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