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