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