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