odbc_api/handles/
statement.rs

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