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