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