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