odbc_api/handles/
statement.rs

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