Skip to main content

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