odbc_api/handles/statement.rs
1use super::{
2 CData, Descriptor, SqlChar, SqlResult, SqlText,
3 any_handle::AnyHandle,
4 bind::{CDataMut, DelayedInput, HasDataType},
5 buffer::{clamp_small_int, mut_buf_ptr},
6 column_description::{ColumnDescription, Nullability},
7 data_type::DataType,
8 drop_handle,
9 sql_char::{binary_length, is_truncated_bin, resize_to_fit_without_tz},
10 sql_result::ExtSqlReturn,
11};
12use log::debug;
13use odbc_sys::{
14 Desc, FreeStmtOption, HDbc, HDesc, HStmt, Handle, HandleType, IS_POINTER, Len, ParamType,
15 Pointer, SQLBindCol, SQLBindParameter, SQLCloseCursor, SQLDescribeParam, SQLExecute, SQLFetch,
16 SQLFreeStmt, SQLGetData, SQLMoreResults, SQLNumParams, SQLNumResultCols, SQLParamData,
17 SQLPutData, SQLRowCount, SqlDataType, SqlReturn, StatementAttribute,
18};
19use std::{
20 ffi::c_void,
21 marker::PhantomData,
22 mem::ManuallyDrop,
23 num::NonZeroUsize,
24 ptr::{null, null_mut},
25};
26
27#[cfg(feature = "odbc_version_3_80")]
28use odbc_sys::SQLCompleteAsync;
29
30#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
31use odbc_sys::{
32 SQLColAttribute as sql_col_attribute, SQLColumns as sql_columns,
33 SQLDescribeCol as sql_describe_col, SQLExecDirect as sql_exec_direc,
34 SQLForeignKeys as sql_foreign_keys, SQLGetStmtAttr as sql_get_stmt_attr,
35 SQLPrepare as sql_prepare, SQLPrimaryKeys as sql_primary_keys,
36 SQLSetStmtAttr as sql_set_stmt_attr, SQLTables as sql_tables,
37};
38
39#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
40use odbc_sys::{
41 SQLColAttributeW as sql_col_attribute, SQLColumnsW as sql_columns,
42 SQLDescribeColW as sql_describe_col, SQLExecDirectW as sql_exec_direc,
43 SQLForeignKeysW as sql_foreign_keys, SQLGetStmtAttrW as sql_get_stmt_attr,
44 SQLPrepareW as sql_prepare, SQLPrimaryKeysW as sql_primary_keys,
45 SQLSetStmtAttrW as sql_set_stmt_attr, SQLTablesW as sql_tables,
46};
47
48/// An owned valid (i.e. successfully allocated) ODBC statement handle. [`StatementImpl`] borrows
49/// the parent connection used to create the handle in order to ensure the Parent is alive and valid
50/// during the lifetime of the statement.
51///
52/// If you want a handle to the statement that instead of borrowing the parent connection does own
53/// it, you should use [`super::StatementConnection`] instead.
54#[derive(Debug)]
55pub struct StatementImpl<'s> {
56 parent: PhantomData<&'s HDbc>,
57 handle: HStmt,
58}
59
60unsafe impl AnyHandle for StatementImpl<'_> {
61 fn as_handle(&self) -> Handle {
62 self.handle.as_handle()
63 }
64
65 fn handle_type(&self) -> HandleType {
66 HandleType::Stmt
67 }
68}
69
70impl Drop for StatementImpl<'_> {
71 fn drop(&mut self) {
72 unsafe {
73 drop_handle(self.handle.as_handle(), HandleType::Stmt);
74 }
75 }
76}
77
78impl StatementImpl<'_> {
79 /// # Safety
80 ///
81 /// `handle` must be a valid (successfully allocated) statement handle.
82 pub unsafe fn new(handle: HStmt) -> Self {
83 Self {
84 handle,
85 parent: PhantomData,
86 }
87 }
88
89 /// Transfer ownership of this statement to a raw system handle. It is the users responsibility
90 /// to call [`crate::sys::SQLFreeHandle`].
91 pub fn into_sys(self) -> HStmt {
92 // We do not want to run the drop handler, but transfer ownership instead.
93 ManuallyDrop::new(self).handle
94 }
95
96 /// Special wrapper to a borrowed statement. Acts like a mutable reference to an owned
97 /// statement, but allows the lifetime of the tracked connection to stay covariant.
98 pub fn as_stmt_ref(&mut self) -> StatementRef<'_> {
99 StatementRef {
100 parent: self.parent,
101 handle: self.handle,
102 }
103 }
104}
105
106/// According to the ODBC documentation this is safe. See:
107/// <https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/multithreading>
108///
109/// We maybe could consider a statement to be `Sync` as well, since all operations on it currently
110/// require `&mut self`. Yet maybe we get forced to allow some of these operations to take `&self`
111/// in the future, like we do for [`crate::Connection`] to allow for shared ownership of
112/// connections by multiple statements.
113///
114/// A non obvious implication of implementing `Send` for `StatementImpl` is that we must demand all
115/// parameters bound to the statement are also `Send`. There might be room for a statement handle
116/// which is not `Send`, but could therefore bind also parameters which are not `Send`. So far it is
117/// not clear in what use-case we would need this. Yet there are multithreaded programs out there
118/// which want to make use of ODBC.
119unsafe impl Send for StatementImpl<'_> {}
120
121/// A borrowed valid (i.e. successfully allocated) ODBC statement handle. This can be used instead
122/// of a mutable reference to a [`StatementImpl`]. The main advantage here is that the lifetime
123/// paramater remains covariant, whereas if we would just take a mutable reference to an owned
124/// statement it would become invariant.
125#[derive(Debug)]
126pub struct StatementRef<'s> {
127 parent: PhantomData<&'s HDbc>,
128 handle: HStmt,
129}
130
131impl StatementRef<'_> {
132 pub(crate) unsafe fn new(handle: HStmt) -> Self {
133 Self {
134 handle,
135 parent: PhantomData,
136 }
137 }
138}
139
140impl Statement for StatementRef<'_> {
141 fn as_sys(&self) -> HStmt {
142 self.handle
143 }
144}
145
146unsafe impl AnyHandle for StatementRef<'_> {
147 fn as_handle(&self) -> Handle {
148 self.handle.as_handle()
149 }
150
151 fn handle_type(&self) -> HandleType {
152 HandleType::Stmt
153 }
154}
155
156/// According to the ODBC documentation this is safe. See:
157/// <https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/multithreading>
158///
159/// We maybe could consider a statement to be `Sync` as well, since all operations on it currently
160/// require `&mut self`. Yet maybe we get forced to allow some of these operations to take `&self`
161/// in the future, like we do for [`crate::Connection`] to allow for shared ownership of
162/// connections by multiple statements.
163unsafe impl Send for StatementRef<'_> {}
164
165/// Allows us to be generic over the ownership type (mutably borrowed or owned) of a statement
166pub trait AsStatementRef {
167 /// Get an exclusive reference to the underlying statement handle. This method is used to
168 /// implement other more higher level methods on top of it. It is not intended to be called by
169 /// users of this crate directly, yet it may serve as an escape hatch for low level use cases.
170 fn as_stmt_ref(&mut self) -> StatementRef<'_>;
171}
172
173impl AsStatementRef for StatementImpl<'_> {
174 fn as_stmt_ref(&mut self) -> StatementRef<'_> {
175 self.as_stmt_ref()
176 }
177}
178
179impl AsStatementRef for &mut StatementImpl<'_> {
180 fn as_stmt_ref(&mut self) -> StatementRef<'_> {
181 (*self).as_stmt_ref()
182 }
183}
184
185impl AsStatementRef for StatementRef<'_> {
186 fn as_stmt_ref(&mut self) -> StatementRef<'_> {
187 unsafe { StatementRef::new(self.handle) }
188 }
189}
190
191/// An ODBC statement handle. In this crate it is implemented by [`self::StatementImpl`]. In ODBC
192/// Statements are used to execute statements and retrieve results. Both parameter and result
193/// buffers are bound to the statement and dereferenced during statement execution and fetching
194/// results.
195///
196/// The trait allows us to reason about statements without taking the lifetime of their connection
197/// into account. It also allows for the trait to be implemented by a handle taking ownership of
198/// both, the statement and the connection.
199pub trait Statement: AnyHandle {
200 /// Gain access to the underlying statement handle without transferring ownership to it.
201 fn as_sys(&self) -> HStmt;
202
203 /// Binds application data buffers to columns in the result set.
204 ///
205 /// * `column_number`: `0` is the bookmark column. It is not included in some result sets. All
206 /// other columns are numbered starting with `1`. It is an error to bind a higher-numbered
207 /// column than there are columns in the result set. This error cannot be detected until the
208 /// result set has been created, so it is returned by `fetch`, not `bind_col`.
209 /// * `target_type`: The identifier of the C data type of the `value` buffer. When it is
210 /// retrieving data from the data source with `fetch`, the driver converts the data to this
211 /// type. When it sends data to the source, the driver converts the data from this type.
212 /// * `target_value`: Pointer to the data buffer to bind to the column.
213 /// * `target_length`: Length of target value in bytes. (Or for a single element in case of bulk
214 /// aka. block fetching data).
215 /// * `indicator`: Buffer is going to hold length or indicator values.
216 ///
217 /// # Safety
218 ///
219 /// It is the callers responsibility to make sure the bound columns live until they are no
220 /// longer bound.
221 unsafe fn bind_col(&mut self, column_number: u16, target: &mut impl CDataMut) -> SqlResult<()> {
222 unsafe {
223 SQLBindCol(
224 self.as_sys(),
225 column_number,
226 target.cdata_type(),
227 target.mut_value_ptr(),
228 target.buffer_length(),
229 target.mut_indicator_ptr(),
230 )
231 }
232 .into_sql_result("SQLBindCol")
233 }
234
235 /// Returns the next row set in the result set.
236 ///
237 /// It can be called only while a result set exists: I.e., after a call that creates a result
238 /// set and before the cursor over that result set is closed. If any columns are bound, it
239 /// returns the data in those columns. If the application has specified a pointer to a row
240 /// status array or a buffer in which to return the number of rows fetched, `fetch` also returns
241 /// this information. Calls to `fetch` can be mixed with calls to `fetch_scroll`.
242 ///
243 /// # Safety
244 ///
245 /// Fetch dereferences bound column pointers.
246 unsafe fn fetch(&mut self) -> SqlResult<()> {
247 unsafe { SQLFetch(self.as_sys()) }.into_sql_result("SQLFetch")
248 }
249
250 /// Retrieves data for a single column in the result set or for a single parameter.
251 fn get_data(&mut self, col_or_param_num: u16, target: &mut impl CDataMut) -> SqlResult<()> {
252 unsafe {
253 SQLGetData(
254 self.as_sys(),
255 col_or_param_num,
256 target.cdata_type(),
257 target.mut_value_ptr(),
258 target.buffer_length(),
259 target.mut_indicator_ptr(),
260 )
261 }
262 .into_sql_result("SQLGetData")
263 }
264
265 /// Release all column buffers bound by `bind_col`. Except bookmark column.
266 fn unbind_cols(&mut self) -> SqlResult<()> {
267 unsafe { SQLFreeStmt(self.as_sys(), FreeStmtOption::Unbind) }.into_sql_result("SQLFreeStmt")
268 }
269
270 /// Bind an integer to hold the number of rows retrieved with fetch in the current row set.
271 /// Calling [`Self::unset_num_rows_fetched`] is going to unbind the value from the statement.
272 ///
273 /// # Safety
274 ///
275 /// `num_rows` must not be moved and remain valid, as long as it remains bound to the cursor.
276 unsafe fn set_num_rows_fetched(&mut self, num_rows: &mut usize) -> SqlResult<()> {
277 let value = num_rows as *mut usize as Pointer;
278 unsafe {
279 sql_set_stmt_attr(
280 self.as_sys(),
281 StatementAttribute::RowsFetchedPtr,
282 value,
283 IS_POINTER,
284 )
285 }
286 .into_sql_result("SQLSetStmtAttr")
287 }
288
289 /// The number of seconds to wait for an SQL statement to execute before returning to the
290 /// application. If `timeout_sec` is `0` (default), there is no timeout.
291 ///
292 /// Note that the application need not call SQLCloseCursor to reuse the statement if a SELECT
293 /// statement timed out.
294 ///
295 /// This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
296 ///
297 /// See:
298 /// <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function>
299 fn set_query_timeout_sec(&mut self, timeout_sec: usize) -> SqlResult<()> {
300 let value = timeout_sec as *mut usize as Pointer;
301 // This is safe, because `.as_sys` returns a valid statement handle.
302 unsafe { sql_set_stmt_attr(self.as_sys(), StatementAttribute::QueryTimeout, value, 0) }
303 .into_sql_result("SQLSetStmtAttr")
304 }
305
306 /// The number of seconds to wait for an SQL statement to execute before returning to the
307 /// application. If `timeout_sec` is `0` (default), there is no timeout.
308 ///
309 /// This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
310 fn query_timeout_sec(&mut self) -> SqlResult<usize> {
311 let mut out: usize = 0;
312 let value = &mut out as *mut usize as Pointer;
313 unsafe {
314 sql_get_stmt_attr(
315 self.as_sys(),
316 StatementAttribute::QueryTimeout,
317 value,
318 0,
319 null_mut(),
320 )
321 }
322 .into_sql_result("SQLGetStmtAttr")
323 .on_success(|| out)
324 }
325
326 /// Unsets the integer set by [`Self::set_num_rows_fetched`].
327 ///
328 /// This being a seperate method from [`Self::set_num_rows_fetched` allows us to write us
329 /// cleanup code with less `unsafe` statements since this operation is always safe.
330 fn unset_num_rows_fetched(&mut self) -> SqlResult<()> {
331 unsafe {
332 sql_set_stmt_attr(
333 self.as_sys(),
334 StatementAttribute::RowsFetchedPtr,
335 null_mut(),
336 IS_POINTER,
337 )
338 .into_sql_result("SQLSetStmtAttr")
339 }
340 }
341
342 /// Fetch a column description using the column index.
343 ///
344 /// # Parameters
345 ///
346 /// * `column_number`: Column index. `0` is the bookmark column. The other column indices start
347 /// with `1`.
348 /// * `column_description`: Holds the description of the column after the call. This method does
349 /// not provide strong exception safety as the value of this argument is undefined in case of
350 /// an error.
351 fn describe_col(
352 &mut self,
353 column_number: u16,
354 column_description: &mut ColumnDescription,
355 ) -> SqlResult<()> {
356 let name = &mut column_description.name;
357 // Use maximum available capacity.
358 name.resize(name.capacity(), 0);
359 let mut name_length: i16 = 0;
360 let mut data_type = SqlDataType::UNKNOWN_TYPE;
361 let mut column_size = 0;
362 let mut decimal_digits = 0;
363 let mut nullable = odbc_sys::Nullability::UNKNOWN;
364
365 let res = unsafe {
366 sql_describe_col(
367 self.as_sys(),
368 column_number,
369 mut_buf_ptr(name),
370 clamp_small_int(name.len()),
371 &mut name_length,
372 &mut data_type,
373 &mut column_size,
374 &mut decimal_digits,
375 &mut nullable,
376 )
377 .into_sql_result("SQLDescribeCol")
378 };
379
380 if res.is_err() {
381 return res;
382 }
383
384 column_description.nullability = Nullability::new(nullable);
385
386 if name_length + 1 > clamp_small_int(name.len()) {
387 // Buffer is to small to hold name, retry with larger buffer
388 name.resize(name_length as usize + 1, 0);
389 self.describe_col(column_number, column_description)
390 } else {
391 name.resize(name_length as usize, 0);
392 column_description.data_type = DataType::new(data_type, column_size, decimal_digits);
393 res
394 }
395 }
396
397 /// Executes a statement, using the current values of the parameter marker variables if any
398 /// parameters exist in the statement. SQLExecDirect is the fastest way to submit an SQL
399 /// statement for one-time execution.
400 ///
401 /// # Safety
402 ///
403 /// While `self` as always guaranteed to be a valid allocated handle, this function may
404 /// dereference bound parameters. It is the callers responsibility to ensure these are still
405 /// valid. One strategy is to reset potentially invalid parameters right before the call using
406 /// `reset_parameters`.
407 ///
408 /// # Return
409 ///
410 /// * [`SqlResult::NeedData`] if execution requires additional data from delayed parameters.
411 /// * [`SqlResult::NoData`] if a searched update or delete statement did not affect any rows at
412 /// the data source.
413 unsafe fn exec_direct(&mut self, statement: &SqlText) -> SqlResult<()> {
414 unsafe {
415 sql_exec_direc(
416 self.as_sys(),
417 statement.ptr(),
418 statement.len_char().try_into().unwrap(),
419 )
420 }
421 .into_sql_result("SQLExecDirect")
422 }
423
424 /// Close an open cursor.
425 fn close_cursor(&mut self) -> SqlResult<()> {
426 unsafe { SQLCloseCursor(self.as_sys()) }.into_sql_result("SQLCloseCursor")
427 }
428
429 /// Send an SQL statement to the data source for preparation. The application can include one or
430 /// more parameter markers in the SQL statement. To include a parameter marker, the application
431 /// embeds a question mark (?) into the SQL string at the appropriate position.
432 fn prepare(&mut self, statement: &SqlText) -> SqlResult<()> {
433 unsafe {
434 sql_prepare(
435 self.as_sys(),
436 statement.ptr(),
437 statement.len_char().try_into().unwrap(),
438 )
439 }
440 .into_sql_result("SQLPrepare")
441 }
442
443 /// Executes a statement prepared by `prepare`. After the application processes or discards the
444 /// results from a call to `execute`, the application can call SQLExecute again with new
445 /// parameter values.
446 ///
447 /// # Safety
448 ///
449 /// While `self` as always guaranteed to be a valid allocated handle, this function may
450 /// dereference bound parameters. It is the callers responsibility to ensure these are still
451 /// valid. One strategy is to reset potentially invalid parameters right before the call using
452 /// `reset_parameters`.
453 ///
454 /// # Return
455 ///
456 /// * [`SqlResult::NeedData`] if execution requires additional data from delayed parameters.
457 /// * [`SqlResult::NoData`] if a searched update or delete statement did not affect any rows at
458 /// the data source.
459 unsafe fn execute(&mut self) -> SqlResult<()> {
460 unsafe { SQLExecute(self.as_sys()) }.into_sql_result("SQLExecute")
461 }
462
463 /// Number of columns in result set.
464 ///
465 /// Can also be used to check, whether or not a result set has been created at all.
466 fn num_result_cols(&mut self) -> SqlResult<i16> {
467 let mut out: i16 = 0;
468 unsafe { SQLNumResultCols(self.as_sys(), &mut out) }
469 .into_sql_result("SQLNumResultCols")
470 .on_success(|| out)
471 }
472
473 /// Number of placeholders of a prepared query.
474 fn num_params(&mut self) -> SqlResult<u16> {
475 let mut out: i16 = 0;
476 unsafe { SQLNumParams(self.as_sys(), &mut out) }
477 .into_sql_result("SQLNumParams")
478 .on_success(|| out.try_into().unwrap())
479 }
480
481 /// Sets the batch size for bulk cursors, if retrieving many rows at once.
482 ///
483 /// # Safety
484 ///
485 /// It is the callers responsibility to ensure that buffers bound using `bind_col` can hold the
486 /// specified amount of rows.
487 unsafe fn set_row_array_size(&mut self, size: usize) -> SqlResult<()> {
488 assert!(size > 0);
489 unsafe {
490 sql_set_stmt_attr(
491 self.as_sys(),
492 StatementAttribute::RowArraySize,
493 size as Pointer,
494 0,
495 )
496 }
497 .into_sql_result("SQLSetStmtAttr")
498 }
499
500 /// Gets the batch size for bulk cursors, if retrieving many rows at once.
501 fn row_array_size(&mut self) -> SqlResult<usize> {
502 let mut out: usize = 0;
503 let value = &mut out as *mut usize as Pointer;
504 unsafe {
505 sql_get_stmt_attr(
506 self.as_sys(),
507 StatementAttribute::RowArraySize,
508 value,
509 0,
510 null_mut(),
511 )
512 }
513 .into_sql_result("SQLGetStmtAttr")
514 .on_success(|| out)
515 }
516
517 /// Specifies the number of values for each parameter. If it is greater than 1, the data and
518 /// indicator buffers of the statement point to arrays. The cardinality of each array is equal
519 /// to the value of this field.
520 ///
521 /// # Safety
522 ///
523 /// The bound buffers must at least hold the number of elements specified in this call then the
524 /// statement is executed.
525 unsafe fn set_paramset_size(&mut self, size: usize) -> SqlResult<()> {
526 assert!(size > 0);
527 unsafe {
528 sql_set_stmt_attr(
529 self.as_sys(),
530 StatementAttribute::ParamsetSize,
531 size as Pointer,
532 0,
533 )
534 }
535 .into_sql_result("SQLSetStmtAttr")
536 }
537
538 /// Sets the binding type to columnar binding for batch cursors.
539 ///
540 /// Any Positive number indicates a row wise binding with that row length. `0` indicates a
541 /// columnar binding.
542 ///
543 /// # Safety
544 ///
545 /// It is the callers responsibility to ensure that the bound buffers match the memory layout
546 /// specified by this function.
547 unsafe fn set_row_bind_type(&mut self, row_size: usize) -> SqlResult<()> {
548 unsafe {
549 sql_set_stmt_attr(
550 self.as_sys(),
551 StatementAttribute::RowBindType,
552 row_size as Pointer,
553 0,
554 )
555 }
556 .into_sql_result("SQLSetStmtAttr")
557 }
558
559 fn set_metadata_id(&mut self, metadata_id: bool) -> SqlResult<()> {
560 unsafe {
561 sql_set_stmt_attr(
562 self.as_sys(),
563 StatementAttribute::MetadataId,
564 metadata_id as usize as Pointer,
565 0,
566 )
567 .into_sql_result("SQLSetStmtAttr")
568 }
569 }
570
571 /// Enables or disables asynchronous execution for this statement handle. If asynchronous
572 /// execution is not enabled on connection level it is disabled by default and everything is
573 /// executed synchronously.
574 ///
575 /// This is equivalent to stetting `SQL_ATTR_ASYNC_ENABLE` in the bare C API.
576 ///
577 /// See
578 /// <https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/executing-statements-odbc>
579 fn set_async_enable(&mut self, on: bool) -> SqlResult<()> {
580 unsafe {
581 sql_set_stmt_attr(
582 self.as_sys(),
583 StatementAttribute::AsyncEnable,
584 on as usize as Pointer,
585 0,
586 )
587 .into_sql_result("SQLSetStmtAttr")
588 }
589 }
590
591 /// Binds a buffer holding an input parameter to a parameter marker in an SQL statement. This
592 /// specialized version takes a constant reference to parameter, but is therefore limited to
593 /// binding input parameters. See [`Statement::bind_parameter`] for the version which can bind
594 /// input and output parameters.
595 ///
596 /// See <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function>.
597 ///
598 /// # Safety
599 ///
600 /// * It is up to the caller to ensure the lifetimes of the bound parameters.
601 /// * Calling this function may influence other statements that share the APD.
602 /// * `parameter` must be complete, i.e not be truncated.
603 unsafe fn bind_input_parameter(
604 &mut self,
605 parameter_number: u16,
606 parameter: &(impl HasDataType + CData + ?Sized + Send),
607 ) -> SqlResult<()> {
608 let parameter_type = parameter.data_type();
609 unsafe {
610 SQLBindParameter(
611 self.as_sys(),
612 parameter_number,
613 ParamType::Input,
614 parameter.cdata_type(),
615 parameter_type.data_type(),
616 parameter_type
617 .column_size()
618 .map(NonZeroUsize::get)
619 .unwrap_or_default(),
620 parameter_type.decimal_digits(),
621 // We cast const to mut here, but we specify the input_output_type as input.
622 parameter.value_ptr() as *mut c_void,
623 parameter.buffer_length(),
624 // We cast const to mut here, but we specify the input_output_type as input.
625 parameter.indicator_ptr() as *mut isize,
626 )
627 }
628 .into_sql_result("SQLBindParameter")
629 }
630
631 /// Binds a buffer holding a single parameter to a parameter marker in an SQL statement. To bind
632 /// input parameters using constant references see [`Statement::bind_input_parameter`].
633 ///
634 /// See <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function>.
635 ///
636 /// # Safety
637 ///
638 /// * It is up to the caller to ensure the lifetimes of the bound parameters.
639 /// * Calling this function may influence other statements that share the APD.
640 /// * `parameter` must be complete, i.e not be truncated. If `input_output_type` indicates
641 /// [`ParamType::Input`] or [`ParamType::InputOutput`].
642 unsafe fn bind_parameter(
643 &mut self,
644 parameter_number: u16,
645 input_output_type: ParamType,
646 parameter: &mut (impl CDataMut + HasDataType + Send),
647 ) -> SqlResult<()> {
648 let parameter_type = parameter.data_type();
649 unsafe {
650 SQLBindParameter(
651 self.as_sys(),
652 parameter_number,
653 input_output_type,
654 parameter.cdata_type(),
655 parameter_type.data_type(),
656 parameter_type
657 .column_size()
658 .map(NonZeroUsize::get)
659 .unwrap_or_default(),
660 parameter_type.decimal_digits(),
661 parameter.value_ptr() as *mut c_void,
662 parameter.buffer_length(),
663 parameter.mut_indicator_ptr(),
664 )
665 }
666 .into_sql_result("SQLBindParameter")
667 }
668
669 /// Binds an input stream to a parameter marker in an SQL statement. Use this to stream large
670 /// values at statement execution time. To bind preallocated constant buffers see
671 /// [`Statement::bind_input_parameter`].
672 ///
673 /// See <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function>.
674 ///
675 /// # Safety
676 ///
677 /// * It is up to the caller to ensure the lifetimes of the bound parameters.
678 /// * Calling this function may influence other statements that share the APD.
679 unsafe fn bind_delayed_input_parameter(
680 &mut self,
681 parameter_number: u16,
682 parameter: &mut (impl DelayedInput + HasDataType),
683 ) -> SqlResult<()> {
684 let paramater_type = parameter.data_type();
685 unsafe {
686 SQLBindParameter(
687 self.as_sys(),
688 parameter_number,
689 ParamType::Input,
690 parameter.cdata_type(),
691 paramater_type.data_type(),
692 paramater_type
693 .column_size()
694 .map(NonZeroUsize::get)
695 .unwrap_or_default(),
696 paramater_type.decimal_digits(),
697 parameter.stream_ptr(),
698 0,
699 // We cast const to mut here, but we specify the input_output_type as input.
700 parameter.indicator_ptr() as *mut isize,
701 )
702 }
703 .into_sql_result("SQLBindParameter")
704 }
705
706 /// `true` if a given column in a result set is unsigned or not a numeric type, `false`
707 /// otherwise.
708 ///
709 /// `column_number`: Index of the column, starting at 1.
710 fn is_unsigned_column(&mut self, column_number: u16) -> SqlResult<bool> {
711 unsafe { self.numeric_col_attribute(Desc::Unsigned, column_number) }.map(|out| match out {
712 0 => false,
713 1 => true,
714 _ => panic!("Unsigned column attribute must be either 0 or 1."),
715 })
716 }
717
718 /// Returns a number identifying the SQL type of the column in the result set.
719 ///
720 /// `column_number`: Index of the column, starting at 1.
721 fn col_type(&mut self, column_number: u16) -> SqlResult<SqlDataType> {
722 unsafe { self.numeric_col_attribute(Desc::Type, column_number) }.map(|ret| {
723 SqlDataType(ret.try_into().expect(
724 "Failed to retrieve data type from ODBC driver. The SQLLEN could not be converted to
725 a 16 Bit integer. If you are on a 64Bit Platform, this may be because your \
726 database driver being compiled against a SQLLEN with 32Bit size instead of 64Bit. \
727 E.g. IBM offers libdb2o.* and libdb2.*. With libdb2o.* being the one with the \
728 correct size.",
729 ))
730 })
731 }
732
733 /// The concise data type. For the datetime and interval data types, this field returns the
734 /// concise data type; for example, `TIME` or `INTERVAL_YEAR`.
735 ///
736 /// `column_number`: Index of the column, starting at 1.
737 fn col_concise_type(&mut self, column_number: u16) -> SqlResult<SqlDataType> {
738 unsafe { self.numeric_col_attribute(Desc::ConciseType, column_number) }.map(|ret| {
739 SqlDataType(ret.try_into().expect(
740 "Failed to retrieve data type from ODBC driver. The SQLLEN could not be \
741 converted to a 16 Bit integer. If you are on a 64Bit Platform, this may be \
742 because your database driver being compiled against a SQLLEN with 32Bit size \
743 instead of 64Bit. E.g. IBM offers libdb2o.* and libdb2.*. With libdb2o.* being \
744 the one with the correct size.",
745 ))
746 })
747 }
748
749 /// Returns the size in bytes of the columns. For variable sized types the maximum size is
750 /// returned, excluding a terminating zero.
751 ///
752 /// `column_number`: Index of the column, starting at 1.
753 fn col_octet_length(&mut self, column_number: u16) -> SqlResult<isize> {
754 unsafe { self.numeric_col_attribute(Desc::OctetLength, column_number) }
755 }
756
757 /// Maximum number of characters required to display data from the column.
758 ///
759 /// `column_number`: Index of the column, starting at 1.
760 fn col_display_size(&mut self, column_number: u16) -> SqlResult<isize> {
761 unsafe { self.numeric_col_attribute(Desc::DisplaySize, column_number) }
762 }
763
764 /// Precision of the column.
765 ///
766 /// Denotes the applicable precision. For data types SQL_TYPE_TIME, SQL_TYPE_TIMESTAMP, and all
767 /// the interval data types that represent a time interval, its value is the applicable
768 /// precision of the fractional seconds component.
769 fn col_precision(&mut self, column_number: u16) -> SqlResult<isize> {
770 unsafe { self.numeric_col_attribute(Desc::Precision, column_number) }
771 }
772
773 /// The applicable scale for a numeric data type. For DECIMAL and NUMERIC data types, this is
774 /// the defined scale. It is undefined for all other data types.
775 fn col_scale(&mut self, column_number: u16) -> SqlResult<isize> {
776 unsafe { self.numeric_col_attribute(Desc::Scale, column_number) }
777 }
778
779 /// Nullability of the column.
780 ///
781 /// `column_number`: Index of the column, starting at 1.
782 ///
783 /// See `SQL_DESC_NULLABLE ` in the ODBC reference:
784 /// <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlcolattribute-function>
785 fn col_nullability(&mut self, column_number: u16) -> SqlResult<Nullability> {
786 unsafe { self.numeric_col_attribute(Desc::Nullable, column_number) }
787 .map(|nullability| Nullability::new(odbc_sys::Nullability(nullability as i16)))
788 }
789
790 /// The column alias, if it applies. If the column alias does not apply, the column name is
791 /// returned. If there is no column name or a column alias, an empty string is returned.
792 fn col_name(&mut self, column_number: u16, buffer: &mut Vec<SqlChar>) -> SqlResult<()> {
793 // String length in bytes, not characters. Terminating zero is excluded.
794 let mut string_length_in_bytes: i16 = 0;
795 // Let's utilize all of `buf`s capacity.
796 buffer.resize(buffer.capacity(), 0);
797 unsafe {
798 let mut res = sql_col_attribute(
799 self.as_sys(),
800 column_number,
801 Desc::Name,
802 mut_buf_ptr(buffer) as Pointer,
803 binary_length(buffer).try_into().unwrap(),
804 &mut string_length_in_bytes as *mut i16,
805 null_mut(),
806 )
807 .into_sql_result("SQLColAttribute");
808
809 if res.is_err() {
810 return res;
811 }
812
813 if is_truncated_bin(buffer, string_length_in_bytes.try_into().unwrap()) {
814 // If we could rely on every ODBC driver sticking to the specifcation it would
815 // probably best to resize by `string_length_in_bytes / 2 + 1`. Yet e.g. SQLite
816 // seems to report the length in characters, so to work with a wide range of DB
817 // systems, and since buffers for names are not expected to become super large we
818 // omit the division by two here.
819 buffer.resize((string_length_in_bytes + 1).try_into().unwrap(), 0);
820
821 res = sql_col_attribute(
822 self.as_sys(),
823 column_number,
824 Desc::Name,
825 mut_buf_ptr(buffer) as Pointer,
826 binary_length(buffer).try_into().unwrap(),
827 &mut string_length_in_bytes as *mut i16,
828 null_mut(),
829 )
830 .into_sql_result("SQLColAttribute");
831 }
832 // Resize buffer to exact string length without terminal zero
833 resize_to_fit_without_tz(buffer, string_length_in_bytes.try_into().unwrap());
834
835 res
836 }
837 }
838
839 /// # Safety
840 ///
841 /// It is the callers responsibility to ensure that `attribute` refers to a numeric attribute.
842 unsafe fn numeric_col_attribute(
843 &mut self,
844 attribute: Desc,
845 column_number: u16,
846 ) -> SqlResult<Len> {
847 let mut out: Len = 0;
848 unsafe {
849 sql_col_attribute(
850 self.as_sys(),
851 column_number,
852 attribute,
853 null_mut(),
854 0,
855 null_mut(),
856 &mut out as *mut Len,
857 )
858 }
859 .into_sql_result("SQLColAttribute")
860 .on_success(|| {
861 debug!(
862 "SQLColAttribute called with attribute '{attribute:?}' for column \
863 '{column_number}' reported {out}."
864 );
865 out
866 })
867 }
868
869 /// Sets the SQL_DESC_COUNT field of the APD to 0, releasing all parameter buffers set for the
870 /// given StatementHandle.
871 fn reset_parameters(&mut self) -> SqlResult<()> {
872 unsafe {
873 SQLFreeStmt(self.as_sys(), FreeStmtOption::ResetParams).into_sql_result("SQLFreeStmt")
874 }
875 }
876
877 /// Describes parameter marker associated with a prepared SQL statement.
878 ///
879 /// # Parameters
880 ///
881 /// * `parameter_number`: Parameter marker number ordered sequentially in increasing parameter
882 /// order, starting at 1.
883 fn describe_param(&mut self, parameter_number: u16) -> SqlResult<ParameterDescription> {
884 let mut data_type = SqlDataType::UNKNOWN_TYPE;
885 let mut parameter_size = 0;
886 let mut decimal_digits = 0;
887 let mut nullable = odbc_sys::Nullability::UNKNOWN;
888 unsafe {
889 SQLDescribeParam(
890 self.as_sys(),
891 parameter_number,
892 &mut data_type,
893 &mut parameter_size,
894 &mut decimal_digits,
895 &mut nullable,
896 )
897 }
898 .into_sql_result("SQLDescribeParam")
899 .on_success(|| ParameterDescription {
900 data_type: DataType::new(data_type, parameter_size, decimal_digits),
901 nullability: Nullability::new(nullable),
902 })
903 }
904
905 /// Use to check if which additional parameters need data. Should be called after binding
906 /// parameters with an indicator set to [`crate::sys::DATA_AT_EXEC`] or a value created with
907 /// [`crate::sys::len_data_at_exec`].
908 ///
909 /// Return value contains a parameter identifier passed to bind parameter as a value pointer.
910 fn param_data(&mut self) -> SqlResult<Option<Pointer>> {
911 unsafe {
912 let mut param_id: Pointer = null_mut();
913 // Use cases for `PARAM_DATA_AVAILABLE` and `NO_DATA` not implemented yet.
914 match SQLParamData(self.as_sys(), &mut param_id as *mut Pointer) {
915 SqlReturn::NEED_DATA => SqlResult::Success(Some(param_id)),
916 other => other.into_sql_result("SQLParamData").on_success(|| None),
917 }
918 }
919 }
920
921 /// Executes a columns query using this statement handle.
922 fn columns(
923 &mut self,
924 catalog_name: &SqlText,
925 schema_name: &SqlText,
926 table_name: &SqlText,
927 column_name: &SqlText,
928 ) -> SqlResult<()> {
929 unsafe {
930 sql_columns(
931 self.as_sys(),
932 catalog_name.ptr(),
933 catalog_name.len_char().try_into().unwrap(),
934 schema_name.ptr(),
935 schema_name.len_char().try_into().unwrap(),
936 table_name.ptr(),
937 table_name.len_char().try_into().unwrap(),
938 column_name.ptr(),
939 column_name.len_char().try_into().unwrap(),
940 )
941 .into_sql_result("SQLColumns")
942 }
943 }
944
945 /// Returns the list of table, catalog, or schema names, and table types, stored in a specific
946 /// data source. The driver returns the information as a result set.
947 ///
948 /// The catalog, schema and table parameters are search patterns by default unless
949 /// [`Self::set_metadata_id`] is called with `true`. In that case they must also not be `None`
950 /// since otherwise a NulPointer error is emitted.
951 fn tables(
952 &mut self,
953 catalog_name: &SqlText,
954 schema_name: &SqlText,
955 table_name: &SqlText,
956 table_type: &SqlText,
957 ) -> SqlResult<()> {
958 unsafe {
959 sql_tables(
960 self.as_sys(),
961 catalog_name.ptr(),
962 catalog_name.len_char().try_into().unwrap(),
963 schema_name.ptr(),
964 schema_name.len_char().try_into().unwrap(),
965 table_name.ptr(),
966 table_name.len_char().try_into().unwrap(),
967 table_type.ptr(),
968 table_type.len_char().try_into().unwrap(),
969 )
970 .into_sql_result("SQLTables")
971 }
972 }
973
974 /// Create a result set which contains the column names that make up the primary key for the
975 /// table.
976 ///
977 /// # Parameters
978 ///
979 /// * `catalog_name`: Catalog name. If a driver supports catalogs for some tables but not for
980 /// others, such as when the driver retrieves data from different DBMSs, an empty string ("")
981 /// denotes those tables that do not have catalogs. `catalog_name` must not contain a string
982 /// search pattern.
983 /// * `schema_name`: Schema name. If a driver supports schemas for some tables but not for
984 /// others, such as when the driver retrieves data from different DBMSs, an empty string ("")
985 /// denotes those tables that do not have schemas. `schema_name` must not contain a string
986 /// search pattern.
987 /// * `table_name`: Table name. `table_name` must not contain a string search pattern.
988 ///
989 /// The resulting result set contains the following columns:
990 ///
991 /// * `TABLE_CAT`: Primary key table catalog name. NULL if not applicable to the data source. If
992 /// a driver supports catalogs for some tables but not for others, such as when the driver
993 /// retrieves data from different DBMSs, it returns an empty string ("") for those tables that
994 /// do not have catalogs. `VARCHAR`
995 /// * `TABLE_SCHEM`: Primary key table schema name; NULL if not applicable to the data source.
996 /// If a driver supports schemas for some tables but not for others, such as when the driver
997 /// retrieves data from different DBMSs, it returns an empty string ("") for those tables that
998 /// do not have schemas. `VARCHAR`
999 /// * `TABLE_NAME`: Primary key table name. `VARCHAR NOT NULL`
1000 /// * `COLUMN_NAME`: Primary key column name. The driver returns an empty string for a column
1001 /// that does not have a name. `VARCHAR NOT NULL`
1002 /// * `KEY_SEQ`: Column sequence number in key (starting with 1). `SMALLINT NOT NULL`
1003 /// * `PK_NAME`: Primary key name. NULL if not applicable to the data source. `VARCHAR`
1004 ///
1005 /// The maximum length of the VARCHAR columns is driver specific.
1006 ///
1007 /// If [`StatementAttribute::MetadataId`] statement attribute is set to true, catalog, schema
1008 /// and table name parameters are treated as an identifiers and their case is not significant.
1009 /// If it is false, they are ordinary arguments. As such they treated literally and their case
1010 /// is significant.
1011 ///
1012 /// See: <https://learn.microsoft.com/sql/odbc/reference/syntax/sqlprimarykeys-function>
1013 fn primary_keys(
1014 &mut self,
1015 catalog_name: Option<&SqlText>,
1016 schema_name: Option<&SqlText>,
1017 table_name: &SqlText,
1018 ) -> SqlResult<()> {
1019 unsafe {
1020 sql_primary_keys(
1021 self.as_sys(),
1022 catalog_name.map_or(null(), |c| c.ptr()),
1023 catalog_name.map_or(0, |c| c.len_char().try_into().unwrap()),
1024 schema_name.map_or(null(), |s| s.ptr()),
1025 schema_name.map_or(0, |s| s.len_char().try_into().unwrap()),
1026 table_name.ptr(),
1027 table_name.len_char().try_into().unwrap(),
1028 )
1029 .into_sql_result("SQLPrimaryKeys")
1030 }
1031 }
1032
1033 /// This can be used to retrieve either a list of foreign keys in the specified table or a list
1034 /// of foreign keys in other table that refer to the primary key of the specified table.
1035 ///
1036 /// Like [`Self::tables`] this changes the statement to a cursor over the result set.
1037 fn foreign_keys(
1038 &mut self,
1039 pk_catalog_name: &SqlText,
1040 pk_schema_name: &SqlText,
1041 pk_table_name: &SqlText,
1042 fk_catalog_name: &SqlText,
1043 fk_schema_name: &SqlText,
1044 fk_table_name: &SqlText,
1045 ) -> SqlResult<()> {
1046 unsafe {
1047 sql_foreign_keys(
1048 self.as_sys(),
1049 pk_catalog_name.ptr(),
1050 pk_catalog_name.len_char().try_into().unwrap(),
1051 pk_schema_name.ptr(),
1052 pk_schema_name.len_char().try_into().unwrap(),
1053 pk_table_name.ptr(),
1054 pk_table_name.len_char().try_into().unwrap(),
1055 fk_catalog_name.ptr(),
1056 fk_catalog_name.len_char().try_into().unwrap(),
1057 fk_schema_name.ptr(),
1058 fk_schema_name.len_char().try_into().unwrap(),
1059 fk_table_name.ptr(),
1060 fk_table_name.len_char().try_into().unwrap(),
1061 )
1062 .into_sql_result("SQLForeignKeys")
1063 }
1064 }
1065
1066 /// To put a batch of binary data into the data source at statement execution time. May return
1067 /// [`SqlResult::NeedData`]
1068 ///
1069 /// Panics if batch is empty.
1070 fn put_binary_batch(&mut self, batch: &[u8]) -> SqlResult<()> {
1071 // Probably not strictly necessary. MSSQL returns an error than inserting empty batches.
1072 // Still strikes me as a programming error. Maybe we could also do nothing instead.
1073 if batch.is_empty() {
1074 panic!("Attempt to put empty batch into data source.")
1075 }
1076
1077 unsafe {
1078 SQLPutData(
1079 self.as_sys(),
1080 batch.as_ptr() as Pointer,
1081 batch.len().try_into().unwrap(),
1082 )
1083 .into_sql_result("SQLPutData")
1084 }
1085 }
1086
1087 /// Number of rows affected by an `UPDATE`, `INSERT`, or `DELETE` statement.
1088 ///
1089 /// See:
1090 ///
1091 /// <https://docs.microsoft.com/en-us/sql/relational-databases/native-client-odbc-api/sqlrowcount>
1092 /// <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlrowcount-function>
1093 fn row_count(&mut self) -> SqlResult<isize> {
1094 let mut ret = 0isize;
1095 unsafe {
1096 SQLRowCount(self.as_sys(), &mut ret as *mut isize)
1097 .into_sql_result("SQLRowCount")
1098 .on_success(|| ret)
1099 }
1100 }
1101
1102 /// In polling mode can be used instead of repeating the function call. In notification mode
1103 /// this completes the asynchronous operation. This method panics, in case asynchronous mode is
1104 /// not enabled. [`SqlResult::NoData`] if no asynchronous operation is in progress, or (specific
1105 /// to notification mode) the driver manager has not notified the application.
1106 ///
1107 /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlcompleteasync-function>
1108 #[cfg(feature = "odbc_version_3_80")]
1109 fn complete_async(&mut self, function_name: &'static str) -> SqlResult<SqlResult<()>> {
1110 let mut ret = SqlReturn::ERROR;
1111 unsafe {
1112 // Possible return codes are (according to MS ODBC docs):
1113 // * INVALID_HANDLE: The handle indicated by HandleType and Handle is not a valid
1114 // handle. => Must not happen due self always being a valid statement handle.
1115 // * ERROR: ret is NULL or asynchronous processing is not enabled on the handle. => ret
1116 // is never NULL. User may choose not to enable asynchronous processing though.
1117 // * NO_DATA: In notification mode, an asynchronous operation is not in progress or the
1118 // Driver Manager has not notified the application. In polling mode, an asynchronous
1119 // operation is not in progress.
1120 SQLCompleteAsync(self.handle_type(), self.as_handle(), &mut ret.0 as *mut _)
1121 .into_sql_result("SQLCompleteAsync")
1122 }
1123 .on_success(|| ret.into_sql_result(function_name))
1124 }
1125
1126 /// Determines whether more results are available on a statement containing SELECT, UPDATE,
1127 /// INSERT, or DELETE statements and, if so, initializes processing for those results.
1128 /// [`SqlResult::NoData`] is returned to indicate that there are no more result sets.
1129 ///
1130 /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlmoreresults-function>
1131 ///
1132 /// # Safety
1133 ///
1134 /// Since a different result set might have a different schema, care needs to be taken that
1135 /// bound buffers are used correctly.
1136 unsafe fn more_results(&mut self) -> SqlResult<()> {
1137 unsafe { SQLMoreResults(self.as_sys()).into_sql_result("SQLMoreResults") }
1138 }
1139
1140 /// Application Row Descriptor (ARD) associated with the statement handle. It describes the row
1141 /// afte the conversions for the application have been applied. It can be used to query
1142 /// information as well as to set specific desired conversions. E.g. precision and scale for
1143 /// numeric structs. Usually applications have no need to interact directly with the ARD
1144 /// though.
1145 fn application_row_descriptor(&mut self) -> SqlResult<Descriptor<'_>> {
1146 unsafe {
1147 let mut hdesc = HDesc::null();
1148 let hdesc_out = &mut hdesc as *mut HDesc as Pointer;
1149 odbc_sys::SQLGetStmtAttr(
1150 self.as_sys(),
1151 odbc_sys::StatementAttribute::AppRowDesc,
1152 hdesc_out,
1153 0,
1154 null_mut(),
1155 )
1156 .into_sql_result("SQLGetStmtAttr")
1157 .on_success(|| Descriptor::new(hdesc))
1158 }
1159 }
1160
1161 /// Application Parameter Descriptor (APD) associated with the statement handle. Describes the
1162 /// parameter buffers bound to an SQL statement. Usually there is no need for an application to
1163 /// directly interact with the APD. It may be required though to set precision and scale for
1164 /// numeric parameters.
1165 fn application_parameter_descriptor(&mut self) -> SqlResult<Descriptor<'_>> {
1166 unsafe {
1167 let mut hdesc = HDesc::null();
1168 let hdesc_out = &mut hdesc as *mut HDesc as Pointer;
1169 odbc_sys::SQLGetStmtAttr(
1170 self.as_sys(),
1171 odbc_sys::StatementAttribute::AppParamDesc,
1172 hdesc_out,
1173 0,
1174 null_mut(),
1175 )
1176 .into_sql_result("SQLGetStmtAttr")
1177 .on_success(|| Descriptor::new(hdesc))
1178 }
1179 }
1180}
1181
1182impl Statement for StatementImpl<'_> {
1183 /// Gain access to the underlying statement handle without transferring ownership to it.
1184 fn as_sys(&self) -> HStmt {
1185 self.handle
1186 }
1187}
1188
1189/// Description of a parameter associated with a parameter marker in a prepared statement. Returned
1190/// by [`crate::Prepared::describe_param`].
1191#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1192pub struct ParameterDescription {
1193 /// Indicates whether the parameter may be NULL not.
1194 pub nullability: Nullability,
1195 /// The SQL Type associated with that parameter.
1196 pub data_type: DataType,
1197}