Skip to content

Commit 6b33591

Browse files
committed
Fix ODBC fixed-size parameter indicators
1 parent e1ae0e9 commit 6b33591

3 files changed

Lines changed: 34 additions & 9 deletions

File tree

sqlx-core/src/odbc/connection/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ impl OdbcConnection {
303303
})
304304
.await?;
305305

306+
if !allow_deferred_result_columns && !metadata_complete {
307+
return Err(Error::Protocol(
308+
"ODBC driver did not provide result-column metadata before execution".into(),
309+
));
310+
}
311+
306312
if store_to_cache && metadata_complete && self.stmt_cache.is_enabled() {
307313
self.stmt_cache
308314
.insert(&sql_owned, Arc::new(Mutex::new(prepared)));

sqlx-core/src/odbc/connection/odbc_bridge.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,34 +131,34 @@ fn to_param(arg: OdbcArgumentValue) -> Box<dyn odbc_api::parameter::InputParamet
131131
use odbc_api::DataType;
132132

133133
match arg {
134-
OdbcArgumentValue::Int(i) => Box::new(i.into_parameter()),
134+
OdbcArgumentValue::Int(i) => Box::new(Some(i).into_parameter()),
135135
OdbcArgumentValue::UInt(u) => Box::new(
136136
WithDataType {
137-
value: u,
137+
value: odbc_api::Nullable::new(u),
138138
data_type: DataType::BigInt,
139139
}
140140
.into_parameter(),
141141
),
142-
OdbcArgumentValue::Float(f) => Box::new(f.into_parameter()),
142+
OdbcArgumentValue::Float(f) => Box::new(Some(f).into_parameter()),
143143
OdbcArgumentValue::Text(s) => Box::new(s.into_parameter()),
144144
OdbcArgumentValue::Bytes(b) => Box::new(b.into_parameter()),
145145
OdbcArgumentValue::Date(d) => Box::new(
146146
WithDataType {
147-
value: d,
147+
value: odbc_api::Nullable::new(d),
148148
data_type: DataType::Date,
149149
}
150150
.into_parameter(),
151151
),
152152
OdbcArgumentValue::Time(t) => Box::new(
153153
WithDataType {
154-
value: t,
154+
value: odbc_api::Nullable::new(t),
155155
data_type: DataType::Time { precision: 0 },
156156
}
157157
.into_parameter(),
158158
),
159159
OdbcArgumentValue::Timestamp(ts) => Box::new(
160160
WithDataType {
161-
value: ts,
161+
value: odbc_api::Nullable::new(ts),
162162
data_type: DataType::Timestamp { precision: 6 },
163163
}
164164
.into_parameter(),
@@ -177,7 +177,7 @@ fn to_param(arg: OdbcArgumentValue) -> Box<dyn odbc_api::parameter::InputParamet
177177
mod tests {
178178
use super::*;
179179
use crate::arguments::Arguments;
180-
use odbc_api::handles::HasDataType;
180+
use odbc_api::handles::{CData, HasDataType};
181181

182182
#[test]
183183
fn typed_none_parameter_preserves_non_string_data_type() {
@@ -189,6 +189,17 @@ mod tests {
189189
assert_eq!(params.len(), 1);
190190
assert_eq!(params[0].data_type(), odbc_api::DataType::Integer);
191191
}
192+
193+
#[test]
194+
fn fixed_sized_parameter_uses_explicit_non_null_indicator() {
195+
let mut args = OdbcArguments::default();
196+
197+
args.add(5_i32);
198+
199+
let params = prepare_parameters(Some(args));
200+
assert_eq!(params.len(), 1);
201+
assert!(!params[0].indicator_ptr().is_null());
202+
}
192203
}
193204

194205
fn handle_result_sets<C: Cursor + ResultSetMetadata>(

tests/odbc/odbc.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,14 @@ where
650650
let mut opts = OdbcConnectOptions::from_str(&database_url)?;
651651
opts.buffer_settings(buf_settings);
652652

653-
let conn = OdbcConnection::connect_with(&opts).await?;
653+
let mut conn = OdbcConnection::connect_with(&opts).await?;
654+
let dbms_name = conn.dbms_name().await?;
655+
if buf_settings.max_column_size.is_some()
656+
&& dbms_name.to_ascii_lowercase().contains("duckdb")
657+
{
658+
// DuckDB's ODBC driver rejects the rowset attributes used by buffered fetching.
659+
continue;
660+
}
654661
test_fn(conn, buf_settings).await?;
655662
}
656663
Ok(())
@@ -1385,7 +1392,8 @@ async fn it_handles_prepared_statement_with_wrong_parameter_count() -> anyhow::R
13851392
assert!(
13861393
err_str.contains("07002")
13871394
|| err_str.contains("parameter count")
1388-
|| err_str.contains("unbound parameter"),
1395+
|| err_str.contains("unbound parameter")
1396+
|| err_str.contains("not all parameters are bound"),
13891397
"{:?} should contain '07002' (COUNT field incorrect)",
13901398
err
13911399
);

0 commit comments

Comments
 (0)