1use arrow_schema::ArrowError;
42use bytes::Bytes;
43use prost::Message;
44
45#[allow(clippy::all)]
46mod r#gen {
47 #![allow(missing_docs)]
49 include!("arrow.flight.protocol.sql.rs");
50}
51
52pub use r#gen::ActionBeginSavepointRequest;
53pub use r#gen::ActionBeginSavepointResult;
54pub use r#gen::ActionBeginTransactionRequest;
55pub use r#gen::ActionBeginTransactionResult;
56pub use r#gen::ActionCancelQueryRequest;
57pub use r#gen::ActionCancelQueryResult;
58pub use r#gen::ActionClosePreparedStatementRequest;
59pub use r#gen::ActionCreatePreparedStatementRequest;
60pub use r#gen::ActionCreatePreparedStatementResult;
61pub use r#gen::ActionCreatePreparedSubstraitPlanRequest;
62pub use r#gen::ActionEndSavepointRequest;
63pub use r#gen::ActionEndTransactionRequest;
64pub use r#gen::CommandGetCatalogs;
65pub use r#gen::CommandGetCrossReference;
66pub use r#gen::CommandGetDbSchemas;
67pub use r#gen::CommandGetExportedKeys;
68pub use r#gen::CommandGetImportedKeys;
69pub use r#gen::CommandGetPrimaryKeys;
70pub use r#gen::CommandGetSqlInfo;
71pub use r#gen::CommandGetTableTypes;
72pub use r#gen::CommandGetTables;
73pub use r#gen::CommandGetXdbcTypeInfo;
74pub use r#gen::CommandPreparedStatementQuery;
75pub use r#gen::CommandPreparedStatementUpdate;
76pub use r#gen::CommandStatementIngest;
77pub use r#gen::CommandStatementQuery;
78pub use r#gen::CommandStatementSubstraitPlan;
79pub use r#gen::CommandStatementUpdate;
80pub use r#gen::DoPutPreparedStatementResult;
81pub use r#gen::DoPutUpdateResult;
82pub use r#gen::Nullable;
83pub use r#gen::Searchable;
84pub use r#gen::SqlInfo;
85pub use r#gen::SqlNullOrdering;
86pub use r#gen::SqlOuterJoinsSupportLevel;
87pub use r#gen::SqlSupportedCaseSensitivity;
88pub use r#gen::SqlSupportedElementActions;
89pub use r#gen::SqlSupportedGroupBy;
90pub use r#gen::SqlSupportedPositionedCommands;
91pub use r#gen::SqlSupportedResultSetConcurrency;
92pub use r#gen::SqlSupportedResultSetType;
93pub use r#gen::SqlSupportedSubqueries;
94pub use r#gen::SqlSupportedTransaction;
95pub use r#gen::SqlSupportedTransactions;
96pub use r#gen::SqlSupportedUnions;
97pub use r#gen::SqlSupportsConvert;
98pub use r#gen::SqlTransactionIsolationLevel;
99pub use r#gen::SubstraitPlan;
100pub use r#gen::SupportedSqlGrammar;
101pub use r#gen::TicketStatementQuery;
102pub use r#gen::UpdateDeleteRules;
103pub use r#gen::XdbcDataType;
104pub use r#gen::XdbcDatetimeSubcode;
105pub use r#gen::action_end_transaction_request::EndTransaction;
106pub use r#gen::command_statement_ingest::TableDefinitionOptions;
107pub use r#gen::command_statement_ingest::table_definition_options::{
108 TableExistsOption, TableNotExistOption,
109};
110
111pub mod client;
112pub mod metadata;
113pub mod server;
114
115pub use crate::streams::FallibleRequestStream;
116
117pub trait ProstMessageExt: prost::Message + Default {
119 fn type_url() -> &'static str;
121
122 fn as_any(&self) -> Any;
124}
125
126macro_rules! prost_message_ext {
127 ($($name:tt,)*) => {
128 #[derive(Clone, Debug, PartialEq)]
151 pub enum Command {
152 $(
153 #[doc = concat!(stringify!($name), "variant")]
154 $name($name),)*
155
156 Unknown(Any),
158 }
159
160 impl Command {
161 pub fn into_any(self) -> Any {
163 match self {
164 $(
165 Self::$name(cmd) => cmd.as_any(),
166 )*
167 Self::Unknown(any) => any,
168 }
169 }
170
171 pub fn type_url(&self) -> &str {
173 match self {
174 $(
175 Self::$name(_) => <$name as ProstMessageExt>::type_url(),
176 )*
177 Self::Unknown(any) => any.type_url.as_str(),
178 }
179 }
180 }
181
182 impl TryFrom<Any> for Command {
183 type Error = ArrowError;
184
185 fn try_from(any: Any) -> Result<Self, Self::Error> {
186 match any.type_url.as_str() {
187 $(
188 concat!("type.googleapis.com/arrow.flight.protocol.sql.", stringify!($name))
189 => {
190 let m: $name = Message::decode(&*any.value).map_err(|err| {
191 ArrowError::ParseError(format!("Unable to decode Any value: {err}"))
192 })?;
193 Ok(Self::$name(m))
194 }
195 )*
196 _ => Ok(Self::Unknown(any)),
197 }
198 }
199 }
200
201 $(
202 impl ProstMessageExt for $name {
203 fn type_url() -> &'static str {
204 concat!("type.googleapis.com/arrow.flight.protocol.sql.", stringify!($name))
205 }
206
207 fn as_any(&self) -> Any {
208 Any {
209 type_url: <$name>::type_url().to_string(),
210 value: self.encode_to_vec().into(),
211 }
212 }
213 }
214 )*
215 };
216}
217
218prost_message_ext!(
220 ActionBeginSavepointRequest,
221 ActionBeginSavepointResult,
222 ActionBeginTransactionRequest,
223 ActionBeginTransactionResult,
224 ActionCancelQueryRequest,
225 ActionCancelQueryResult,
226 ActionClosePreparedStatementRequest,
227 ActionCreatePreparedStatementRequest,
228 ActionCreatePreparedStatementResult,
229 ActionCreatePreparedSubstraitPlanRequest,
230 ActionEndSavepointRequest,
231 ActionEndTransactionRequest,
232 CommandGetCatalogs,
233 CommandGetCrossReference,
234 CommandGetDbSchemas,
235 CommandGetExportedKeys,
236 CommandGetImportedKeys,
237 CommandGetPrimaryKeys,
238 CommandGetSqlInfo,
239 CommandGetTableTypes,
240 CommandGetTables,
241 CommandGetXdbcTypeInfo,
242 CommandPreparedStatementQuery,
243 CommandPreparedStatementUpdate,
244 CommandStatementIngest,
245 CommandStatementQuery,
246 CommandStatementSubstraitPlan,
247 CommandStatementUpdate,
248 DoPutPreparedStatementResult,
249 DoPutUpdateResult,
250 TicketStatementQuery,
251);
252
253#[derive(Clone, PartialEq, ::prost::Message)]
271pub struct Any {
272 #[prost(string, tag = "1")]
279 pub type_url: String,
280 #[prost(bytes = "bytes", tag = "2")]
282 pub value: Bytes,
283}
284
285impl Any {
286 pub fn is<M: ProstMessageExt>(&self) -> bool {
288 M::type_url() == self.type_url
289 }
290
291 pub fn unpack<M: ProstMessageExt>(&self) -> Result<Option<M>, ArrowError> {
293 if !self.is::<M>() {
294 return Ok(None);
295 }
296 let m = Message::decode(&*self.value)
297 .map_err(|err| ArrowError::ParseError(format!("Unable to decode Any value: {err}")))?;
298 Ok(Some(m))
299 }
300
301 pub fn pack<M: ProstMessageExt>(message: &M) -> Result<Any, ArrowError> {
303 Ok(message.as_any())
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn test_type_url() {
313 assert_eq!(
314 TicketStatementQuery::type_url(),
315 "type.googleapis.com/arrow.flight.protocol.sql.TicketStatementQuery"
316 );
317 assert_eq!(
318 CommandStatementQuery::type_url(),
319 "type.googleapis.com/arrow.flight.protocol.sql.CommandStatementQuery"
320 );
321 }
322
323 #[test]
324 fn test_prost_any_pack_unpack() {
325 let query = CommandStatementQuery {
326 query: "select 1".to_string(),
327 transaction_id: None,
328 };
329 let any = Any::pack(&query).unwrap();
330 assert!(any.is::<CommandStatementQuery>());
331 let unpack_query: CommandStatementQuery = any.unpack().unwrap().unwrap();
332 assert_eq!(query, unpack_query);
333 }
334
335 #[test]
336 fn test_command() {
337 let query = CommandStatementQuery {
338 query: "select 1".to_string(),
339 transaction_id: None,
340 };
341 let any = Any::pack(&query).unwrap();
342 let cmd: Command = any.try_into().unwrap();
343
344 assert!(matches!(cmd, Command::CommandStatementQuery(_)));
345 assert_eq!(cmd.type_url(), CommandStatementQuery::type_url());
346
347 let any = Any {
350 type_url: "fake_url".to_string(),
351 value: Default::default(),
352 };
353
354 let cmd: Command = any.try_into().unwrap();
355 assert!(matches!(cmd, Command::Unknown(_)));
356 assert_eq!(cmd.type_url(), "fake_url");
357 }
358}