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