diff --git a/remote-table/src/connection/mdb/mod.rs b/remote-table/src/connection/mdb/mod.rs index 3a4eeb1..9c6011a 100644 --- a/remote-table/src/connection/mdb/mod.rs +++ b/remote-table/src/connection/mdb/mod.rs @@ -190,22 +190,20 @@ impl Connection for MdbConnection { let sql = RemoteDbType::Mdb.limit_1_query_if_possible(source)?; debug!("[remote-table] inferring mdb schema with: {sql}"); let conn = self.conn.lock().await; - let mut prepared = conn.prepare(&sql).map_err(|e| { - DataFusionError::Plan(format!( - "Failed to prepare query for schema inference on mdb: {e:?}, sql: {sql}" - )) - })?; - // mdbtools does not populate result-set metadata (SQLNumResultCols / - // SQLDescribeCol) until after SQLExecute. Prepared::execute(()) is the - // safe wrapper around SQLExecute; we discard the returned cursor since - // column metadata is then available on `prepared` itself. - prepared.execute(()).map_err(|e| { + let cursor_opt = conn.execute(&sql, (), None).map_err(|e| { DataFusionError::Plan(format!( "Failed to execute query for schema inference on mdb: {e:?}, sql: {sql}" )) })?; - let remote_schema = Arc::new(build_remote_schema(&mut prepared)?); - Ok(remote_schema) + match cursor_opt { + None => Err(DataFusionError::Plan( + "No rows returned to infer schema".to_string(), + )), + Some(cursor) => { + let remote_schema = Arc::new(build_remote_schema(cursor)?); + Ok(remote_schema) + } + } } async fn query( diff --git a/remote-table/src/connection/mdb/schema.rs b/remote-table/src/connection/mdb/schema.rs index 1fd3882..8b6b502 100644 --- a/remote-table/src/connection/mdb/schema.rs +++ b/remote-table/src/connection/mdb/schema.rs @@ -4,7 +4,7 @@ use crate::RemoteField; use crate::RemoteSchema; use crate::RemoteType; use datafusion_common::DataFusionError; -use odbc_api::Prepared; +use odbc_api::CursorImpl; use odbc_api::ResultSetMetadata; use odbc_api::handles::{AsStatementRef, ColumnDescription, Statement, StatementImpl}; @@ -26,10 +26,8 @@ fn sql_chars_to_string_lossy(name: &[u16]) -> String { String::from_utf16_lossy(name) } -pub(super) fn build_remote_schema( - prepared: &mut Prepared>, -) -> DFResult { - let col_count = prepared +pub(super) fn build_remote_schema(mut cursor: CursorImpl) -> DFResult { + let col_count = cursor .num_result_cols() .map_err(|e| DataFusionError::External(Box::new(e)))? as u16; let mut remote_fields = vec![]; @@ -39,7 +37,7 @@ pub(super) fn build_remote_schema( // col_nullability return NoDiagnostics), so we go through the // low-level SQLDescribeCol path. let mut col_desc = ColumnDescription::default(); - let describe_result = prepared.as_stmt_ref().describe_col(i, &mut col_desc); + let describe_result = cursor.as_stmt_ref().describe_col(i, &mut col_desc); if describe_result.is_err() { return Err(DataFusionError::Plan(format!( "describe_col failed for column {i} on mdb"