Skip to main content

arrow_flight/sql/
server.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5//! Helper trait [`FlightSqlService`] for implementing a [`FlightService`] that implements FlightSQL.
6
7use std::fmt::{Display, Formatter};
8use std::pin::Pin;
9
10use super::{
11    ActionBeginSavepointRequest, ActionBeginSavepointResult, ActionBeginTransactionRequest,
12    ActionBeginTransactionResult, ActionCancelQueryRequest, ActionCancelQueryResult,
13    ActionClosePreparedStatementRequest, ActionCreatePreparedStatementRequest,
14    ActionCreatePreparedStatementResult, ActionCreatePreparedSubstraitPlanRequest,
15    ActionEndSavepointRequest, ActionEndTransactionRequest, Any, Command, CommandGetCatalogs,
16    CommandGetCrossReference, CommandGetDbSchemas, CommandGetExportedKeys, CommandGetImportedKeys,
17    CommandGetPrimaryKeys, CommandGetSqlInfo, CommandGetTableTypes, CommandGetTables,
18    CommandGetXdbcTypeInfo, CommandPreparedStatementQuery, CommandPreparedStatementUpdate,
19    CommandStatementIngest, CommandStatementQuery, CommandStatementSubstraitPlan,
20    CommandStatementUpdate, DoPutPreparedStatementResult, DoPutUpdateResult, ProstMessageExt,
21    SqlInfo, TicketStatementQuery,
22};
23use crate::{
24    Action, ActionType, Criteria, Empty, FlightData, FlightDescriptor, FlightInfo,
25    HandshakeRequest, HandshakeResponse, PutResult, SchemaResult, Ticket,
26    flight_service_server::FlightService, r#gen::PollInfo,
27};
28use futures::{Stream, StreamExt, stream::Peekable};
29use prost::Message;
30use tonic::{Request, Response, Status, Streaming};
31
32pub(crate) static CREATE_PREPARED_STATEMENT: &str = "CreatePreparedStatement";
33pub(crate) static CLOSE_PREPARED_STATEMENT: &str = "ClosePreparedStatement";
34pub(crate) static CREATE_PREPARED_SUBSTRAIT_PLAN: &str = "CreatePreparedSubstraitPlan";
35pub(crate) static BEGIN_TRANSACTION: &str = "BeginTransaction";
36pub(crate) static END_TRANSACTION: &str = "EndTransaction";
37pub(crate) static BEGIN_SAVEPOINT: &str = "BeginSavepoint";
38pub(crate) static END_SAVEPOINT: &str = "EndSavepoint";
39pub(crate) static CANCEL_QUERY: &str = "CancelQuery";
40
41/// Implements FlightSqlService to handle the flight sql protocol
42// `async_trait` marks the boxed futures returned by provided methods `#[must_use]`
43#[expect(clippy::double_must_use)]
44#[tonic::async_trait]
45pub trait FlightSqlService: Sync + Send + Sized + 'static {
46    /// When impl FlightSqlService, you can always set FlightService to Self
47    type FlightService: FlightService;
48
49    /// Accept authentication and return a token
50    /// <https://arrow.apache.org/docs/format/Flight.html#authentication>
51    async fn do_handshake(
52        &self,
53        _request: Request<Streaming<HandshakeRequest>>,
54    ) -> Result<
55        Response<Pin<Box<dyn Stream<Item = Result<HandshakeResponse, Status>> + Send>>>,
56        Status,
57    > {
58        Err(Status::unimplemented(
59            "Handshake has no default implementation",
60        ))
61    }
62
63    /// Implementors may override to handle additional calls to do_get()
64    async fn do_get_fallback(
65        &self,
66        _request: Request<Ticket>,
67        message: Any,
68    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
69        Err(Status::unimplemented(format!(
70            "do_get: The defined request is invalid: {}",
71            message.type_url
72        )))
73    }
74
75    /// Get a FlightInfo for executing a SQL query.
76    async fn get_flight_info_statement(
77        &self,
78        _query: CommandStatementQuery,
79        _request: Request<FlightDescriptor>,
80    ) -> Result<Response<FlightInfo>, Status> {
81        Err(Status::unimplemented(
82            "get_flight_info_statement has no default implementation",
83        ))
84    }
85
86    /// Get a FlightInfo for executing a substrait plan.
87    async fn get_flight_info_substrait_plan(
88        &self,
89        _query: CommandStatementSubstraitPlan,
90        _request: Request<FlightDescriptor>,
91    ) -> Result<Response<FlightInfo>, Status> {
92        Err(Status::unimplemented(
93            "get_flight_info_substrait_plan has no default implementation",
94        ))
95    }
96
97    /// Get a FlightInfo for executing an already created prepared statement.
98    async fn get_flight_info_prepared_statement(
99        &self,
100        _query: CommandPreparedStatementQuery,
101        _request: Request<FlightDescriptor>,
102    ) -> Result<Response<FlightInfo>, Status> {
103        Err(Status::unimplemented(
104            "get_flight_info_prepared_statement has no default implementation",
105        ))
106    }
107
108    /// Get a FlightInfo for listing catalogs.
109    async fn get_flight_info_catalogs(
110        &self,
111        _query: CommandGetCatalogs,
112        _request: Request<FlightDescriptor>,
113    ) -> Result<Response<FlightInfo>, Status> {
114        Err(Status::unimplemented(
115            "get_flight_info_catalogs has no default implementation",
116        ))
117    }
118
119    /// Get a FlightInfo for listing schemas.
120    async fn get_flight_info_schemas(
121        &self,
122        _query: CommandGetDbSchemas,
123        _request: Request<FlightDescriptor>,
124    ) -> Result<Response<FlightInfo>, Status> {
125        Err(Status::unimplemented(
126            "get_flight_info_schemas has no default implementation",
127        ))
128    }
129
130    /// Get a FlightInfo for listing tables.
131    async fn get_flight_info_tables(
132        &self,
133        _query: CommandGetTables,
134        _request: Request<FlightDescriptor>,
135    ) -> Result<Response<FlightInfo>, Status> {
136        Err(Status::unimplemented(
137            "get_flight_info_tables has no default implementation",
138        ))
139    }
140
141    /// Get a FlightInfo to extract information about the table types.
142    async fn get_flight_info_table_types(
143        &self,
144        _query: CommandGetTableTypes,
145        _request: Request<FlightDescriptor>,
146    ) -> Result<Response<FlightInfo>, Status> {
147        Err(Status::unimplemented(
148            "get_flight_info_table_types has no default implementation",
149        ))
150    }
151
152    /// Get a FlightInfo for retrieving other information (See SqlInfo).
153    async fn get_flight_info_sql_info(
154        &self,
155        _query: CommandGetSqlInfo,
156        _request: Request<FlightDescriptor>,
157    ) -> Result<Response<FlightInfo>, Status> {
158        Err(Status::unimplemented(
159            "get_flight_info_sql_info has no default implementation",
160        ))
161    }
162
163    /// Get a FlightInfo to extract information about primary and foreign keys.
164    async fn get_flight_info_primary_keys(
165        &self,
166        _query: CommandGetPrimaryKeys,
167        _request: Request<FlightDescriptor>,
168    ) -> Result<Response<FlightInfo>, Status> {
169        Err(Status::unimplemented(
170            "get_flight_info_primary_keys has no default implementation",
171        ))
172    }
173
174    /// Get a FlightInfo to extract information about exported keys.
175    async fn get_flight_info_exported_keys(
176        &self,
177        _query: CommandGetExportedKeys,
178        _request: Request<FlightDescriptor>,
179    ) -> Result<Response<FlightInfo>, Status> {
180        Err(Status::unimplemented(
181            "get_flight_info_exported_keys has no default implementation",
182        ))
183    }
184
185    /// Get a FlightInfo to extract information about imported keys.
186    async fn get_flight_info_imported_keys(
187        &self,
188        _query: CommandGetImportedKeys,
189        _request: Request<FlightDescriptor>,
190    ) -> Result<Response<FlightInfo>, Status> {
191        Err(Status::unimplemented(
192            "get_flight_info_imported_keys has no default implementation",
193        ))
194    }
195
196    /// Get a FlightInfo to extract information about cross reference.
197    async fn get_flight_info_cross_reference(
198        &self,
199        _query: CommandGetCrossReference,
200        _request: Request<FlightDescriptor>,
201    ) -> Result<Response<FlightInfo>, Status> {
202        Err(Status::unimplemented(
203            "get_flight_info_cross_reference has no default implementation",
204        ))
205    }
206
207    /// Get a FlightInfo to extract information about the supported XDBC types.
208    async fn get_flight_info_xdbc_type_info(
209        &self,
210        _query: CommandGetXdbcTypeInfo,
211        _request: Request<FlightDescriptor>,
212    ) -> Result<Response<FlightInfo>, Status> {
213        Err(Status::unimplemented(
214            "get_flight_info_xdbc_type_info has no default implementation",
215        ))
216    }
217
218    /// Implementors may override to handle additional calls to get_flight_info()
219    async fn get_flight_info_fallback(
220        &self,
221        cmd: Command,
222        _request: Request<FlightDescriptor>,
223    ) -> Result<Response<FlightInfo>, Status> {
224        Err(Status::unimplemented(format!(
225            "get_flight_info: The defined request is invalid: {}",
226            cmd.type_url()
227        )))
228    }
229
230    // do_get
231
232    /// Get a FlightDataStream containing the query results.
233    async fn do_get_statement(
234        &self,
235        _ticket: TicketStatementQuery,
236        _request: Request<Ticket>,
237    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
238        Err(Status::unimplemented(
239            "do_get_statement has no default implementation",
240        ))
241    }
242
243    /// Get a FlightDataStream containing the prepared statement query results.
244    async fn do_get_prepared_statement(
245        &self,
246        _query: CommandPreparedStatementQuery,
247        _request: Request<Ticket>,
248    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
249        Err(Status::unimplemented(
250            "do_get_prepared_statement has no default implementation",
251        ))
252    }
253
254    /// Get a FlightDataStream containing the list of catalogs.
255    async fn do_get_catalogs(
256        &self,
257        _query: CommandGetCatalogs,
258        _request: Request<Ticket>,
259    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
260        Err(Status::unimplemented(
261            "do_get_catalogs has no default implementation",
262        ))
263    }
264
265    /// Get a FlightDataStream containing the list of schemas.
266    async fn do_get_schemas(
267        &self,
268        _query: CommandGetDbSchemas,
269        _request: Request<Ticket>,
270    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
271        Err(Status::unimplemented(
272            "do_get_schemas has no default implementation",
273        ))
274    }
275
276    /// Get a FlightDataStream containing the list of tables.
277    async fn do_get_tables(
278        &self,
279        _query: CommandGetTables,
280        _request: Request<Ticket>,
281    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
282        Err(Status::unimplemented(
283            "do_get_tables has no default implementation",
284        ))
285    }
286
287    /// Get a FlightDataStream containing the data related to the table types.
288    async fn do_get_table_types(
289        &self,
290        _query: CommandGetTableTypes,
291        _request: Request<Ticket>,
292    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
293        Err(Status::unimplemented(
294            "do_get_table_types has no default implementation",
295        ))
296    }
297
298    /// Get a FlightDataStream containing the list of SqlInfo results.
299    async fn do_get_sql_info(
300        &self,
301        _query: CommandGetSqlInfo,
302        _request: Request<Ticket>,
303    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
304        Err(Status::unimplemented(
305            "do_get_sql_info has no default implementation",
306        ))
307    }
308
309    /// Get a FlightDataStream containing the data related to the primary and foreign keys.
310    async fn do_get_primary_keys(
311        &self,
312        _query: CommandGetPrimaryKeys,
313        _request: Request<Ticket>,
314    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
315        Err(Status::unimplemented(
316            "do_get_primary_keys has no default implementation",
317        ))
318    }
319
320    /// Get a FlightDataStream containing the data related to the exported keys.
321    async fn do_get_exported_keys(
322        &self,
323        _query: CommandGetExportedKeys,
324        _request: Request<Ticket>,
325    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
326        Err(Status::unimplemented(
327            "do_get_exported_keys has no default implementation",
328        ))
329    }
330
331    /// Get a FlightDataStream containing the data related to the imported keys.
332    async fn do_get_imported_keys(
333        &self,
334        _query: CommandGetImportedKeys,
335        _request: Request<Ticket>,
336    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
337        Err(Status::unimplemented(
338            "do_get_imported_keys has no default implementation",
339        ))
340    }
341
342    /// Get a FlightDataStream containing the data related to the cross reference.
343    async fn do_get_cross_reference(
344        &self,
345        _query: CommandGetCrossReference,
346        _request: Request<Ticket>,
347    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
348        Err(Status::unimplemented(
349            "do_get_cross_reference has no default implementation",
350        ))
351    }
352
353    /// Get a FlightDataStream containing the data related to the supported XDBC types.
354    async fn do_get_xdbc_type_info(
355        &self,
356        _query: CommandGetXdbcTypeInfo,
357        _request: Request<Ticket>,
358    ) -> Result<Response<<Self as FlightService>::DoGetStream>, Status> {
359        Err(Status::unimplemented(
360            "do_get_xdbc_type_info has no default implementation",
361        ))
362    }
363
364    // do_put
365
366    /// Implementors may override to handle additional calls to do_put()
367    async fn do_put_fallback(
368        &self,
369        _request: Request<PeekableFlightDataStream>,
370        message: Any,
371    ) -> Result<Response<<Self as FlightService>::DoPutStream>, Status> {
372        Err(Status::unimplemented(format!(
373            "do_put: The defined request is invalid: {}",
374            message.type_url
375        )))
376    }
377
378    /// Implementors may override to handle do_put errors
379    async fn do_put_error_callback(
380        &self,
381        _request: Request<PeekableFlightDataStream>,
382        error: DoPutError,
383    ) -> Result<Response<<Self as FlightService>::DoPutStream>, Status> {
384        Err(Status::unimplemented(format!("Unhandled Error: {error}")))
385    }
386
387    /// Execute an update SQL statement.
388    async fn do_put_statement_update(
389        &self,
390        _ticket: CommandStatementUpdate,
391        _request: Request<PeekableFlightDataStream>,
392    ) -> Result<i64, Status> {
393        Err(Status::unimplemented(
394            "do_put_statement_update has no default implementation",
395        ))
396    }
397
398    /// Execute a bulk ingestion.
399    async fn do_put_statement_ingest(
400        &self,
401        _ticket: CommandStatementIngest,
402        _request: Request<PeekableFlightDataStream>,
403    ) -> Result<i64, Status> {
404        Err(Status::unimplemented(
405            "do_put_statement_ingest has no default implementation",
406        ))
407    }
408
409    /// Bind parameters to given prepared statement.
410    ///
411    /// Returns an opaque handle that the client should pass
412    /// back to the server during subsequent requests with this
413    /// prepared statement.
414    async fn do_put_prepared_statement_query(
415        &self,
416        _query: CommandPreparedStatementQuery,
417        _request: Request<PeekableFlightDataStream>,
418    ) -> Result<DoPutPreparedStatementResult, Status> {
419        Err(Status::unimplemented(
420            "do_put_prepared_statement_query has no default implementation",
421        ))
422    }
423
424    /// Execute an update SQL prepared statement.
425    async fn do_put_prepared_statement_update(
426        &self,
427        _query: CommandPreparedStatementUpdate,
428        _request: Request<PeekableFlightDataStream>,
429    ) -> Result<i64, Status> {
430        Err(Status::unimplemented(
431            "do_put_prepared_statement_update has no default implementation",
432        ))
433    }
434
435    /// Execute a substrait plan
436    async fn do_put_substrait_plan(
437        &self,
438        _query: CommandStatementSubstraitPlan,
439        _request: Request<PeekableFlightDataStream>,
440    ) -> Result<i64, Status> {
441        Err(Status::unimplemented(
442            "do_put_substrait_plan has no default implementation",
443        ))
444    }
445
446    // do_action
447
448    /// Implementors may override to handle additional calls to do_action()
449    async fn do_action_fallback(
450        &self,
451        request: Request<Action>,
452    ) -> Result<Response<<Self as FlightService>::DoActionStream>, Status> {
453        Err(Status::invalid_argument(format!(
454            "do_action: The defined request is invalid: {:?}",
455            request.get_ref().r#type
456        )))
457    }
458
459    /// Add custom actions to list_actions() result
460    async fn list_custom_actions(&self) -> Option<Vec<Result<ActionType, Status>>> {
461        None
462    }
463
464    /// Create a prepared statement from given SQL statement.
465    async fn do_action_create_prepared_statement(
466        &self,
467        _query: ActionCreatePreparedStatementRequest,
468        _request: Request<Action>,
469    ) -> Result<ActionCreatePreparedStatementResult, Status> {
470        Err(Status::unimplemented(
471            "do_action_create_prepared_statement has no default implementation",
472        ))
473    }
474
475    /// Close a prepared statement.
476    async fn do_action_close_prepared_statement(
477        &self,
478        _query: ActionClosePreparedStatementRequest,
479        _request: Request<Action>,
480    ) -> Result<(), Status> {
481        Err(Status::unimplemented(
482            "do_action_close_prepared_statement has no default implementation",
483        ))
484    }
485
486    /// Create a prepared substrait plan.
487    async fn do_action_create_prepared_substrait_plan(
488        &self,
489        _query: ActionCreatePreparedSubstraitPlanRequest,
490        _request: Request<Action>,
491    ) -> Result<ActionCreatePreparedStatementResult, Status> {
492        Err(Status::unimplemented(
493            "do_action_create_prepared_substrait_plan has no default implementation",
494        ))
495    }
496
497    /// Begin a transaction
498    async fn do_action_begin_transaction(
499        &self,
500        _query: ActionBeginTransactionRequest,
501        _request: Request<Action>,
502    ) -> Result<ActionBeginTransactionResult, Status> {
503        Err(Status::unimplemented(
504            "do_action_begin_transaction has no default implementation",
505        ))
506    }
507
508    /// End a transaction
509    async fn do_action_end_transaction(
510        &self,
511        _query: ActionEndTransactionRequest,
512        _request: Request<Action>,
513    ) -> Result<(), Status> {
514        Err(Status::unimplemented(
515            "do_action_end_transaction has no default implementation",
516        ))
517    }
518
519    /// Begin a savepoint
520    async fn do_action_begin_savepoint(
521        &self,
522        _query: ActionBeginSavepointRequest,
523        _request: Request<Action>,
524    ) -> Result<ActionBeginSavepointResult, Status> {
525        Err(Status::unimplemented(
526            "do_action_begin_savepoint has no default implementation",
527        ))
528    }
529
530    /// End a savepoint
531    async fn do_action_end_savepoint(
532        &self,
533        _query: ActionEndSavepointRequest,
534        _request: Request<Action>,
535    ) -> Result<(), Status> {
536        Err(Status::unimplemented(
537            "do_action_end_savepoint has no default implementation",
538        ))
539    }
540
541    /// Cancel a query
542    async fn do_action_cancel_query(
543        &self,
544        _query: ActionCancelQueryRequest,
545        _request: Request<Action>,
546    ) -> Result<ActionCancelQueryResult, Status> {
547        Err(Status::unimplemented(
548            "do_action_cancel_query has no default implementation",
549        ))
550    }
551
552    /// do_exchange
553    /// Implementors may override to handle additional calls to do_exchange()
554    async fn do_exchange_fallback(
555        &self,
556        _request: Request<Streaming<FlightData>>,
557    ) -> Result<Response<<Self as FlightService>::DoExchangeStream>, Status> {
558        Err(Status::unimplemented("Not yet implemented"))
559    }
560
561    /// Register a new SqlInfo result, making it available when calling GetSqlInfo.
562    #[deprecated(
563        since = "60.1.0",
564        note = "Not used in request handling and doesn't accept a value to register. Use `SqlInfoDataBuilder::append` instead"
565    )]
566    async fn register_sql_info(&self, _id: i32, _result: &SqlInfo) {}
567}
568
569/// Implements the lower level interface to handle FlightSQL
570#[tonic::async_trait]
571impl<T: 'static> FlightService for T
572where
573    T: FlightSqlService + Send,
574{
575    type HandshakeStream =
576        Pin<Box<dyn Stream<Item = Result<HandshakeResponse, Status>> + Send + 'static>>;
577    type ListFlightsStream =
578        Pin<Box<dyn Stream<Item = Result<FlightInfo, Status>> + Send + 'static>>;
579    type DoGetStream = Pin<Box<dyn Stream<Item = Result<FlightData, Status>> + Send + 'static>>;
580    type DoPutStream = Pin<Box<dyn Stream<Item = Result<PutResult, Status>> + Send + 'static>>;
581    type DoActionStream =
582        Pin<Box<dyn Stream<Item = Result<super::super::Result, Status>> + Send + 'static>>;
583    type ListActionsStream =
584        Pin<Box<dyn Stream<Item = Result<ActionType, Status>> + Send + 'static>>;
585    type DoExchangeStream =
586        Pin<Box<dyn Stream<Item = Result<FlightData, Status>> + Send + 'static>>;
587
588    async fn handshake(
589        &self,
590        request: Request<Streaming<HandshakeRequest>>,
591    ) -> Result<Response<Self::HandshakeStream>, Status> {
592        let res = self.do_handshake(request).await?;
593        Ok(res)
594    }
595
596    async fn list_flights(
597        &self,
598        _request: Request<Criteria>,
599    ) -> Result<Response<Self::ListFlightsStream>, Status> {
600        Err(Status::unimplemented("Not yet implemented"))
601    }
602
603    async fn get_flight_info(
604        &self,
605        request: Request<FlightDescriptor>,
606    ) -> Result<Response<FlightInfo>, Status> {
607        let message = Any::decode(&*request.get_ref().cmd).map_err(decode_error_to_status)?;
608
609        match Command::try_from(message).map_err(arrow_error_to_status)? {
610            Command::CommandStatementQuery(token) => {
611                self.get_flight_info_statement(token, request).await
612            }
613            Command::CommandPreparedStatementQuery(handle) => {
614                self.get_flight_info_prepared_statement(handle, request)
615                    .await
616            }
617            Command::CommandStatementSubstraitPlan(handle) => {
618                self.get_flight_info_substrait_plan(handle, request).await
619            }
620            Command::CommandGetCatalogs(token) => {
621                self.get_flight_info_catalogs(token, request).await
622            }
623            Command::CommandGetDbSchemas(token) => {
624                return self.get_flight_info_schemas(token, request).await;
625            }
626            Command::CommandGetTables(token) => self.get_flight_info_tables(token, request).await,
627            Command::CommandGetTableTypes(token) => {
628                self.get_flight_info_table_types(token, request).await
629            }
630            Command::CommandGetSqlInfo(token) => {
631                self.get_flight_info_sql_info(token, request).await
632            }
633            Command::CommandGetPrimaryKeys(token) => {
634                self.get_flight_info_primary_keys(token, request).await
635            }
636            Command::CommandGetExportedKeys(token) => {
637                self.get_flight_info_exported_keys(token, request).await
638            }
639            Command::CommandGetImportedKeys(token) => {
640                self.get_flight_info_imported_keys(token, request).await
641            }
642            Command::CommandGetCrossReference(token) => {
643                self.get_flight_info_cross_reference(token, request).await
644            }
645            Command::CommandGetXdbcTypeInfo(token) => {
646                self.get_flight_info_xdbc_type_info(token, request).await
647            }
648            cmd => self.get_flight_info_fallback(cmd, request).await,
649        }
650    }
651
652    async fn poll_flight_info(
653        &self,
654        _request: Request<FlightDescriptor>,
655    ) -> Result<Response<PollInfo>, Status> {
656        Err(Status::unimplemented("Not yet implemented"))
657    }
658
659    async fn get_schema(
660        &self,
661        _request: Request<FlightDescriptor>,
662    ) -> Result<Response<SchemaResult>, Status> {
663        Err(Status::unimplemented("Not yet implemented"))
664    }
665
666    async fn do_get(
667        &self,
668        request: Request<Ticket>,
669    ) -> Result<Response<Self::DoGetStream>, Status> {
670        let msg: Any =
671            Message::decode(&*request.get_ref().ticket).map_err(decode_error_to_status)?;
672
673        match Command::try_from(msg).map_err(arrow_error_to_status)? {
674            Command::TicketStatementQuery(command) => self.do_get_statement(command, request).await,
675            Command::CommandPreparedStatementQuery(command) => {
676                self.do_get_prepared_statement(command, request).await
677            }
678            Command::CommandGetCatalogs(command) => self.do_get_catalogs(command, request).await,
679            Command::CommandGetDbSchemas(command) => self.do_get_schemas(command, request).await,
680            Command::CommandGetTables(command) => self.do_get_tables(command, request).await,
681            Command::CommandGetTableTypes(command) => {
682                self.do_get_table_types(command, request).await
683            }
684            Command::CommandGetSqlInfo(command) => self.do_get_sql_info(command, request).await,
685            Command::CommandGetPrimaryKeys(command) => {
686                self.do_get_primary_keys(command, request).await
687            }
688            Command::CommandGetExportedKeys(command) => {
689                self.do_get_exported_keys(command, request).await
690            }
691            Command::CommandGetImportedKeys(command) => {
692                self.do_get_imported_keys(command, request).await
693            }
694            Command::CommandGetCrossReference(command) => {
695                self.do_get_cross_reference(command, request).await
696            }
697            Command::CommandGetXdbcTypeInfo(command) => {
698                self.do_get_xdbc_type_info(command, request).await
699            }
700            cmd => self.do_get_fallback(request, cmd.into_any()).await,
701        }
702    }
703
704    async fn do_put(
705        &self,
706        request: Request<Streaming<FlightData>>,
707    ) -> Result<Response<Self::DoPutStream>, Status> {
708        // See issue #4658: https://github.com/apache/arrow-rs/issues/4658
709        // To dispatch to the correct `do_put` method, we cannot discard the first message,
710        // as it may contain the Arrow schema, which the `do_put` handler may need.
711        // To allow the first message to be reused by the `do_put` handler,
712        // we wrap this stream in a `Peekable` one, which allows us to peek at
713        // the first message without discarding it.
714        let mut request = request.map(PeekableFlightDataStream::new);
715        let mut stream = Pin::new(request.get_mut());
716
717        let peeked_item = stream.peek().await.cloned();
718        let Some(cmd) = peeked_item else {
719            return self
720                .do_put_error_callback(request, DoPutError::MissingCommand)
721                .await;
722        };
723
724        let Some(flight_descriptor) = cmd?.flight_descriptor else {
725            return self
726                .do_put_error_callback(request, DoPutError::MissingFlightDescriptor)
727                .await;
728        };
729        let message = Any::decode(flight_descriptor.cmd).map_err(decode_error_to_status)?;
730        match Command::try_from(message).map_err(arrow_error_to_status)? {
731            Command::CommandStatementUpdate(command) => {
732                let record_count = self.do_put_statement_update(command, request).await?;
733                let result = DoPutUpdateResult { record_count };
734                let output = futures::stream::iter(vec![Ok(PutResult {
735                    app_metadata: result.encode_to_vec().into(),
736                })]);
737                Ok(Response::new(Box::pin(output)))
738            }
739            Command::CommandStatementIngest(command) => {
740                let record_count = self.do_put_statement_ingest(command, request).await?;
741                let result = DoPutUpdateResult { record_count };
742                let output = futures::stream::iter(vec![Ok(PutResult {
743                    app_metadata: result.encode_to_vec().into(),
744                })]);
745                Ok(Response::new(Box::pin(output)))
746            }
747            Command::CommandPreparedStatementQuery(command) => {
748                let result = self
749                    .do_put_prepared_statement_query(command, request)
750                    .await?;
751                let output = futures::stream::iter(vec![Ok(PutResult {
752                    app_metadata: result.encode_to_vec().into(),
753                })]);
754                Ok(Response::new(Box::pin(output)))
755            }
756            Command::CommandStatementSubstraitPlan(command) => {
757                let record_count = self.do_put_substrait_plan(command, request).await?;
758                let result = DoPutUpdateResult { record_count };
759                let output = futures::stream::iter(vec![Ok(PutResult {
760                    app_metadata: result.encode_to_vec().into(),
761                })]);
762                Ok(Response::new(Box::pin(output)))
763            }
764            Command::CommandPreparedStatementUpdate(command) => {
765                let record_count = self
766                    .do_put_prepared_statement_update(command, request)
767                    .await?;
768                let result = DoPutUpdateResult { record_count };
769                let output = futures::stream::iter(vec![Ok(PutResult {
770                    app_metadata: result.encode_to_vec().into(),
771                })]);
772                Ok(Response::new(Box::pin(output)))
773            }
774            cmd => self.do_put_fallback(request, cmd.into_any()).await,
775        }
776    }
777
778    async fn list_actions(
779        &self,
780        _request: Request<Empty>,
781    ) -> Result<Response<Self::ListActionsStream>, Status> {
782        let create_prepared_statement_action_type = ActionType {
783            r#type: CREATE_PREPARED_STATEMENT.to_string(),
784            description: "Creates a reusable prepared statement resource on the server.\n
785                Request Message: ActionCreatePreparedStatementRequest\n
786                Response Message: ActionCreatePreparedStatementResult"
787                .into(),
788        };
789        let close_prepared_statement_action_type = ActionType {
790            r#type: CLOSE_PREPARED_STATEMENT.to_string(),
791            description: "Closes a reusable prepared statement resource on the server.\n
792                Request Message: ActionClosePreparedStatementRequest\n
793                Response Message: N/A"
794                .into(),
795        };
796        let create_prepared_substrait_plan_action_type = ActionType {
797            r#type: CREATE_PREPARED_SUBSTRAIT_PLAN.to_string(),
798            description: "Creates a reusable prepared substrait plan resource on the server.\n
799                Request Message: ActionCreatePreparedSubstraitPlanRequest\n
800                Response Message: ActionCreatePreparedStatementResult"
801                .into(),
802        };
803        let begin_transaction_action_type = ActionType {
804            r#type: BEGIN_TRANSACTION.to_string(),
805            description: "Begins a transaction.\n
806                Request Message: ActionBeginTransactionRequest\n
807                Response Message: ActionBeginTransactionResult"
808                .into(),
809        };
810        let end_transaction_action_type = ActionType {
811            r#type: END_TRANSACTION.to_string(),
812            description: "Ends a transaction\n
813                Request Message: ActionEndTransactionRequest\n
814                Response Message: N/A"
815                .into(),
816        };
817        let begin_savepoint_action_type = ActionType {
818            r#type: BEGIN_SAVEPOINT.to_string(),
819            description: "Begins a savepoint.\n
820                Request Message: ActionBeginSavepointRequest\n
821                Response Message: ActionBeginSavepointResult"
822                .into(),
823        };
824        let end_savepoint_action_type = ActionType {
825            r#type: END_SAVEPOINT.to_string(),
826            description: "Ends a savepoint\n
827                Request Message: ActionEndSavepointRequest\n
828                Response Message: N/A"
829                .into(),
830        };
831        let cancel_query_action_type = ActionType {
832            r#type: CANCEL_QUERY.to_string(),
833            description: "Cancels a query\n
834                Request Message: ActionCancelQueryRequest\n
835                Response Message: ActionCancelQueryResult"
836                .into(),
837        };
838        let mut actions: Vec<Result<ActionType, Status>> = vec![
839            Ok(create_prepared_statement_action_type),
840            Ok(close_prepared_statement_action_type),
841            Ok(create_prepared_substrait_plan_action_type),
842            Ok(begin_transaction_action_type),
843            Ok(end_transaction_action_type),
844            Ok(begin_savepoint_action_type),
845            Ok(end_savepoint_action_type),
846            Ok(cancel_query_action_type),
847        ];
848
849        if let Some(mut custom_actions) = self.list_custom_actions().await {
850            actions.append(&mut custom_actions);
851        }
852
853        let output = futures::stream::iter(actions);
854        Ok(Response::new(Box::pin(output) as Self::ListActionsStream))
855    }
856
857    async fn do_action(
858        &self,
859        request: Request<Action>,
860    ) -> Result<Response<Self::DoActionStream>, Status> {
861        if request.get_ref().r#type == CREATE_PREPARED_STATEMENT {
862            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
863
864            let cmd: ActionCreatePreparedStatementRequest = any
865                .unpack()
866                .map_err(arrow_error_to_status)?
867                .ok_or_else(|| {
868                    Status::invalid_argument(
869                        "Unable to unpack ActionCreatePreparedStatementRequest.",
870                    )
871                })?;
872            let stmt = self
873                .do_action_create_prepared_statement(cmd, request)
874                .await?;
875            let output = futures::stream::iter(vec![Ok(super::super::r#gen::Result {
876                body: stmt.as_any().encode_to_vec().into(),
877            })]);
878            return Ok(Response::new(Box::pin(output)));
879        } else if request.get_ref().r#type == CLOSE_PREPARED_STATEMENT {
880            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
881
882            let cmd: ActionClosePreparedStatementRequest = any
883                .unpack()
884                .map_err(arrow_error_to_status)?
885                .ok_or_else(|| {
886                    Status::invalid_argument(
887                        "Unable to unpack ActionClosePreparedStatementRequest.",
888                    )
889                })?;
890            self.do_action_close_prepared_statement(cmd, request)
891                .await?;
892            return Ok(Response::new(Box::pin(futures::stream::empty())));
893        } else if request.get_ref().r#type == CREATE_PREPARED_SUBSTRAIT_PLAN {
894            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
895
896            let cmd: ActionCreatePreparedSubstraitPlanRequest = any
897                .unpack()
898                .map_err(arrow_error_to_status)?
899                .ok_or_else(|| {
900                    Status::invalid_argument(
901                        "Unable to unpack ActionCreatePreparedSubstraitPlanRequest.",
902                    )
903                })?;
904            self.do_action_create_prepared_substrait_plan(cmd, request)
905                .await?;
906            return Ok(Response::new(Box::pin(futures::stream::empty())));
907        } else if request.get_ref().r#type == BEGIN_TRANSACTION {
908            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
909
910            let cmd: ActionBeginTransactionRequest = any
911                .unpack()
912                .map_err(arrow_error_to_status)?
913                .ok_or_else(|| {
914                Status::invalid_argument("Unable to unpack ActionBeginTransactionRequest.")
915            })?;
916            let stmt = self.do_action_begin_transaction(cmd, request).await?;
917            let output = futures::stream::iter(vec![Ok(super::super::r#gen::Result {
918                body: stmt.as_any().encode_to_vec().into(),
919            })]);
920            return Ok(Response::new(Box::pin(output)));
921        } else if request.get_ref().r#type == END_TRANSACTION {
922            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
923
924            let cmd: ActionEndTransactionRequest = any
925                .unpack()
926                .map_err(arrow_error_to_status)?
927                .ok_or_else(|| {
928                    Status::invalid_argument("Unable to unpack ActionEndTransactionRequest.")
929                })?;
930            self.do_action_end_transaction(cmd, request).await?;
931            return Ok(Response::new(Box::pin(futures::stream::empty())));
932        } else if request.get_ref().r#type == BEGIN_SAVEPOINT {
933            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
934
935            let cmd: ActionBeginSavepointRequest = any
936                .unpack()
937                .map_err(arrow_error_to_status)?
938                .ok_or_else(|| {
939                    Status::invalid_argument("Unable to unpack ActionBeginSavepointRequest.")
940                })?;
941            let stmt = self.do_action_begin_savepoint(cmd, request).await?;
942            let output = futures::stream::iter(vec![Ok(super::super::r#gen::Result {
943                body: stmt.as_any().encode_to_vec().into(),
944            })]);
945            return Ok(Response::new(Box::pin(output)));
946        } else if request.get_ref().r#type == END_SAVEPOINT {
947            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
948
949            let cmd: ActionEndSavepointRequest = any
950                .unpack()
951                .map_err(arrow_error_to_status)?
952                .ok_or_else(|| {
953                    Status::invalid_argument("Unable to unpack ActionEndSavepointRequest.")
954                })?;
955            self.do_action_end_savepoint(cmd, request).await?;
956            return Ok(Response::new(Box::pin(futures::stream::empty())));
957        } else if request.get_ref().r#type == CANCEL_QUERY {
958            let any = Any::decode(&*request.get_ref().body).map_err(decode_error_to_status)?;
959
960            let cmd: ActionCancelQueryRequest = any
961                .unpack()
962                .map_err(arrow_error_to_status)?
963                .ok_or_else(|| {
964                    Status::invalid_argument("Unable to unpack ActionCancelQueryRequest.")
965                })?;
966            let stmt = self.do_action_cancel_query(cmd, request).await?;
967            let output = futures::stream::iter(vec![Ok(super::super::r#gen::Result {
968                body: stmt.as_any().encode_to_vec().into(),
969            })]);
970            return Ok(Response::new(Box::pin(output)));
971        }
972
973        self.do_action_fallback(request).await
974    }
975
976    async fn do_exchange(
977        &self,
978        request: Request<Streaming<FlightData>>,
979    ) -> Result<Response<Self::DoExchangeStream>, Status> {
980        self.do_exchange_fallback(request).await
981    }
982}
983
984/// Unrecoverable errors associated with `do_put` requests
985pub enum DoPutError {
986    /// The first element in the request stream is missing the command
987    MissingCommand,
988    /// The first element in the request stream is missing the flight descriptor
989    MissingFlightDescriptor,
990}
991impl Display for DoPutError {
992    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
993        match self {
994            DoPutError::MissingCommand => {
995                write!(f, "Command is missing.")
996            }
997            DoPutError::MissingFlightDescriptor => {
998                write!(f, "Flight descriptor is missing.")
999            }
1000        }
1001    }
1002}
1003
1004fn decode_error_to_status(err: prost::DecodeError) -> Status {
1005    Status::invalid_argument(format!("{err:?}"))
1006}
1007
1008fn arrow_error_to_status(err: arrow_schema::ArrowError) -> Status {
1009    Status::internal(format!("{err:?}"))
1010}
1011
1012/// A wrapper around [`Streaming<FlightData>`] that allows "peeking" at the
1013/// message at the front of the stream without consuming it.
1014///
1015/// This is needed because sometimes the first message in the stream will contain
1016/// a [`FlightDescriptor`] in addition to potentially any data, and the dispatch logic
1017/// must inspect this information.
1018///
1019/// # Example
1020///
1021/// [`PeekableFlightDataStream::peek`] can be used to peek at the first message without
1022/// discarding it; otherwise, `PeekableFlightDataStream` can be used as a regular stream.
1023/// See the following example:
1024///
1025/// ```no_run
1026/// use arrow_array::RecordBatch;
1027/// use arrow_flight::decode::FlightRecordBatchStream;
1028/// use arrow_flight::FlightDescriptor;
1029/// use arrow_flight::error::FlightError;
1030/// use arrow_flight::sql::server::PeekableFlightDataStream;
1031/// use tonic::{Request, Status};
1032/// use futures::TryStreamExt;
1033///
1034/// #[tokio::main]
1035/// async fn main() -> Result<(), Status> {
1036///     let request: Request<PeekableFlightDataStream> = todo!();
1037///     let stream: PeekableFlightDataStream = request.into_inner();
1038///
1039///     // The first message contains the flight descriptor and the schema.
1040///     // Read the flight descriptor without discarding the schema:
1041///     let flight_descriptor: FlightDescriptor = stream
1042///         .peek()
1043///         .await
1044///         .cloned()
1045///         .transpose()?
1046///         .and_then(|data| data.flight_descriptor)
1047///         .expect("first message should contain flight descriptor");
1048///
1049///     // Pass the stream through a decoder
1050///     let batches: Vec<RecordBatch> = FlightRecordBatchStream::new_from_flight_data(
1051///         request.into_inner().map_err(|e| e.into()),
1052///     )
1053///     .try_collect()
1054///     .await?;
1055/// }
1056/// ```
1057pub struct PeekableFlightDataStream {
1058    inner: Peekable<Streaming<FlightData>>,
1059}
1060
1061impl PeekableFlightDataStream {
1062    fn new(stream: Streaming<FlightData>) -> Self {
1063        Self {
1064            inner: stream.peekable(),
1065        }
1066    }
1067
1068    /// Convert this stream into a `Streaming<FlightData>`.
1069    /// Any messages observed through [`Self::peek`] will be lost
1070    /// after the conversion.
1071    pub fn into_inner(self) -> Streaming<FlightData> {
1072        self.inner.into_inner()
1073    }
1074
1075    /// Convert this stream into a `Peekable<Streaming<FlightData>>`.
1076    /// Preserves the state of the stream, so that calls to [`Self::peek`]
1077    /// and [`Self::poll_next`] are the same.
1078    pub fn into_peekable(self) -> Peekable<Streaming<FlightData>> {
1079        self.inner
1080    }
1081
1082    /// Peek at the head of this stream without advancing it.
1083    pub async fn peek(&mut self) -> Option<&Result<FlightData, Status>> {
1084        Pin::new(&mut self.inner).peek().await
1085    }
1086}
1087
1088impl Stream for PeekableFlightDataStream {
1089    type Item = Result<FlightData, Status>;
1090
1091    fn poll_next(
1092        mut self: Pin<&mut Self>,
1093        cx: &mut std::task::Context<'_>,
1094    ) -> std::task::Poll<Option<Self::Item>> {
1095        self.inner.poll_next_unpin(cx)
1096    }
1097}