odbc_api/handles/
statement.rs

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