odbc_api/handles/statement.rs
1use super::{
2 CData, Descriptor, SqlChar, SqlResult, SqlText,
3 as_handle::AsHandle,
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.
41#[derive(Debug)]
42pub struct StatementImpl<'s> {
43 parent: PhantomData<&'s HDbc>,
44 handle: HStmt,
45}
46
47unsafe impl AsHandle for StatementImpl<'_> {
48 fn as_handle(&self) -> Handle {
49 self.handle as Handle
50 }
51
52 fn handle_type(&self) -> HandleType {
53 HandleType::Stmt
54 }
55}
56
57impl Drop for StatementImpl<'_> {
58 fn drop(&mut self) {
59 unsafe {
60 drop_handle(self.handle as Handle, HandleType::Stmt);
61 }
62 }
63}
64
65impl StatementImpl<'_> {
66 /// # Safety
67 ///
68 /// `handle` must be a valid (successfully allocated) statement handle.
69 pub unsafe fn new(handle: HStmt) -> Self {
70 Self {
71 handle,
72 parent: PhantomData,
73 }
74 }
75
76 /// Transfer ownership of this statement to a raw system handle. It is the users responsibility
77 /// to call [`crate::sys::SQLFreeHandle`].
78 pub fn into_sys(self) -> HStmt {
79 // We do not want to run the drop handler, but transfer ownership instead.
80 ManuallyDrop::new(self).handle
81 }
82
83 /// Special wrapper to a borrowed statement. Acts like a mutable reference to an owned
84 /// statement, but allows the lifetime of the tracked connection to stay covariant.
85 pub fn as_stmt_ref(&mut self) -> StatementRef<'_> {
86 StatementRef {
87 parent: self.parent,
88 handle: self.handle,
89 }
90 }
91}
92
93/// A borrowed valid (i.e. successfully allocated) ODBC statement handle. This can be used instead
94/// of a mutable reference to a [`StatementImpl`]. The main advantage here is that the lifetime
95/// paramater remains covariant, whereas if we would just take a mutable reference to an owned
96/// statement it would become invariant.
97#[derive(Debug)]
98pub struct StatementRef<'s> {
99 parent: PhantomData<&'s HDbc>,
100 handle: HStmt,
101}
102
103impl StatementRef<'_> {
104 pub(crate) unsafe fn new(handle: HStmt) -> Self {
105 Self {
106 handle,
107 parent: PhantomData,
108 }
109 }
110}
111
112impl Statement for StatementRef<'_> {
113 fn as_sys(&self) -> HStmt {
114 self.handle
115 }
116}
117
118unsafe impl AsHandle for StatementRef<'_> {
119 fn as_handle(&self) -> Handle {
120 self.handle as Handle
121 }
122
123 fn handle_type(&self) -> HandleType {
124 HandleType::Stmt
125 }
126}
127
128/// Allows us to be generic over the ownership type (mutably borrowed or owned) of a statement
129pub trait AsStatementRef {
130 /// Get an exclusive reference to the underlying statement handle. This method is used to
131 /// implement other more higher level methods on top of it. It is not intended to be called by
132 /// users of this crate directly, yet it may serve as an escape hatch for low level use cases.
133 fn as_stmt_ref(&mut self) -> StatementRef<'_>;
134}
135
136impl AsStatementRef for StatementImpl<'_> {
137 fn as_stmt_ref(&mut self) -> StatementRef<'_> {
138 self.as_stmt_ref()
139 }
140}
141
142impl AsStatementRef for &mut StatementImpl<'_> {
143 fn as_stmt_ref(&mut self) -> StatementRef<'_> {
144 (*self).as_stmt_ref()
145 }
146}
147
148impl AsStatementRef for StatementRef<'_> {
149 fn as_stmt_ref(&mut self) -> StatementRef<'_> {
150 unsafe { StatementRef::new(self.handle) }
151 }
152}
153
154/// An ODBC statement handle. In this crate it is implemented by [`self::StatementImpl`]. In ODBC
155/// Statements are used to execute statements and retrieve results. Both parameter and result
156/// buffers are bound to the statement and dereferenced during statement execution and fetching
157/// results.
158///
159/// The trait allows us to reason about statements without taking the lifetime of their connection
160/// into account. It also allows for the trait to be implemented by a handle taking ownership of
161/// both, the statement and the connection.
162pub trait Statement: AsHandle {
163 /// Gain access to the underlying statement handle without transferring ownership to it.
164 fn as_sys(&self) -> HStmt;
165
166 /// Binds application data buffers to columns in the result set.
167 ///
168 /// * `column_number`: `0` is the bookmark column. It is not included in some result sets. All
169 /// other columns are numbered starting with `1`. It is an error to bind a higher-numbered
170 /// column than there are columns in the result set. This error cannot be detected until the
171 /// result set has been created, so it is returned by `fetch`, not `bind_col`.
172 /// * `target_type`: The identifier of the C data type of the `value` buffer. When it is
173 /// retrieving data from the data source with `fetch`, the driver converts the data to this
174 /// type. When it sends data to the source, the driver converts the data from this type.
175 /// * `target_value`: Pointer to the data buffer to bind to the column.
176 /// * `target_length`: Length of target value in bytes. (Or for a single element in case of bulk
177 /// aka. block fetching data).
178 /// * `indicator`: Buffer is going to hold length or indicator values.
179 ///
180 /// # Safety
181 ///
182 /// It is the callers responsibility to make sure the bound columns live until they are no
183 /// longer bound.
184 unsafe fn bind_col(&mut self, column_number: u16, target: &mut impl CDataMut) -> SqlResult<()> {
185 unsafe {
186 SQLBindCol(
187 self.as_sys(),
188 column_number,
189 target.cdata_type(),
190 target.mut_value_ptr(),
191 target.buffer_length(),
192 target.mut_indicator_ptr(),
193 )
194 }
195 .into_sql_result("SQLBindCol")
196 }
197
198 /// Returns the next row set in the result set.
199 ///
200 /// It can be called only while a result set exists: I.e., after a call that creates a result
201 /// set and before the cursor over that result set is closed. If any columns are bound, it
202 /// returns the data in those columns. If the application has specified a pointer to a row
203 /// status array or a buffer in which to return the number of rows fetched, `fetch` also returns
204 /// this information. Calls to `fetch` can be mixed with calls to `fetch_scroll`.
205 ///
206 /// # Safety
207 ///
208 /// Fetch dereferences bound column pointers.
209 unsafe fn fetch(&mut self) -> SqlResult<()> {
210 unsafe { SQLFetch(self.as_sys()) }.into_sql_result("SQLFetch")
211 }
212
213 /// Retrieves data for a single column in the result set or for a single parameter.
214 fn get_data(&mut self, col_or_param_num: u16, target: &mut impl CDataMut) -> SqlResult<()> {
215 unsafe {
216 SQLGetData(
217 self.as_sys(),
218 col_or_param_num,
219 target.cdata_type(),
220 target.mut_value_ptr(),
221 target.buffer_length(),
222 target.mut_indicator_ptr(),
223 )
224 }
225 .into_sql_result("SQLGetData")
226 }
227
228 /// Release all column buffers bound by `bind_col`. Except bookmark column.
229 fn unbind_cols(&mut self) -> SqlResult<()> {
230 unsafe { SQLFreeStmt(self.as_sys(), FreeStmtOption::Unbind) }.into_sql_result("SQLFreeStmt")
231 }
232
233 /// Bind an integer to hold the number of rows retrieved with fetch in the current row set.
234 /// Calling [`Self::unset_num_rows_fetched`] is going to unbind the value from the statement.
235 ///
236 /// # Safety
237 ///
238 /// `num_rows` must not be moved and remain valid, as long as it remains bound to the cursor.
239 unsafe fn set_num_rows_fetched(&mut self, num_rows: &mut usize) -> SqlResult<()> {
240 let value = num_rows as *mut usize as Pointer;
241 unsafe {
242 sql_set_stmt_attr(
243 self.as_sys(),
244 StatementAttribute::RowsFetchedPtr,
245 value,
246 IS_POINTER,
247 )
248 }
249 .into_sql_result("SQLSetStmtAttr")
250 }
251
252 /// The number of seconds to wait for an SQL statement to execute before returning to the
253 /// application. If `timeout_sec` is `0` (default), there is no timeout.
254 ///
255 /// Note that the application need not call SQLCloseCursor to reuse the statement if a SELECT
256 /// statement timed out.
257 ///
258 /// This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
259 ///
260 /// See:
261 /// <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function>
262 fn set_query_timeout_sec(&mut self, timeout_sec: usize) -> SqlResult<()> {
263 let value = timeout_sec as *mut usize as Pointer;
264 // This is safe, because `.as_sys` returns a valid statement handle.
265 unsafe { sql_set_stmt_attr(self.as_sys(), StatementAttribute::QueryTimeout, value, 0) }
266 .into_sql_result("SQLSetStmtAttr")
267 }
268
269 /// The number of seconds to wait for an SQL statement to execute before returning to the
270 /// application. If `timeout_sec` is `0` (default), there is no timeout.
271 ///
272 /// This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
273 fn query_timeout_sec(&mut self) -> SqlResult<usize> {
274 let mut out: usize = 0;
275 let value = &mut out as *mut usize as Pointer;
276 unsafe {
277 sql_get_stmt_attr(
278 self.as_sys(),
279 StatementAttribute::QueryTimeout,
280 value,
281 0,
282 null_mut(),
283 )
284 }
285 .into_sql_result("SQLGetStmtAttr")
286 .on_success(|| out)
287 }
288
289 /// Unsets the integer set by [`Self::set_num_rows_fetched`].
290 ///
291 /// This being a seperate method from [`Self::set_num_rows_fetched` allows us to write us
292 /// cleanup code with less `unsafe` statements since this operation is always safe.
293 fn unset_num_rows_fetched(&mut self) -> SqlResult<()> {
294 unsafe {
295 sql_set_stmt_attr(
296 self.as_sys(),
297 StatementAttribute::RowsFetchedPtr,
298 null_mut(),
299 IS_POINTER,
300 )
301 .into_sql_result("SQLSetStmtAttr")
302 }
303 }
304
305 /// Fetch a column description using the column index.
306 ///
307 /// # Parameters
308 ///
309 /// * `column_number`: Column index. `0` is the bookmark column. The other column indices start
310 /// with `1`.
311 /// * `column_description`: Holds the description of the column after the call. This method does
312 /// not provide strong exception safety as the value of this argument is undefined in case of
313 /// an error.
314 fn describe_col(
315 &self,
316 column_number: u16,
317 column_description: &mut ColumnDescription,
318 ) -> SqlResult<()> {
319 let name = &mut column_description.name;
320 // Use maximum available capacity.
321 name.resize(name.capacity(), 0);
322 let mut name_length: i16 = 0;
323 let mut data_type = SqlDataType::UNKNOWN_TYPE;
324 let mut column_size = 0;
325 let mut decimal_digits = 0;
326 let mut nullable = odbc_sys::Nullability::UNKNOWN;
327
328 let res = unsafe {
329 sql_describe_col(
330 self.as_sys(),
331 column_number,
332 mut_buf_ptr(name),
333 clamp_small_int(name.len()),
334 &mut name_length,
335 &mut data_type,
336 &mut column_size,
337 &mut decimal_digits,
338 &mut nullable,
339 )
340 .into_sql_result("SQLDescribeCol")
341 };
342
343 if res.is_err() {
344 return res;
345 }
346
347 column_description.nullability = Nullability::new(nullable);
348
349 if name_length + 1 > clamp_small_int(name.len()) {
350 // Buffer is to small to hold name, retry with larger buffer
351 name.resize(name_length as usize + 1, 0);
352 self.describe_col(column_number, column_description)
353 } else {
354 name.resize(name_length as usize, 0);
355 column_description.data_type = DataType::new(data_type, column_size, decimal_digits);
356 res
357 }
358 }
359
360 /// Executes a statement, using the current values of the parameter marker variables if any
361 /// parameters exist in the statement. SQLExecDirect is the fastest way to submit an SQL
362 /// statement for one-time execution.
363 ///
364 /// # Safety
365 ///
366 /// While `self` as always guaranteed to be a valid allocated handle, this function may
367 /// dereference bound parameters. It is the callers responsibility to ensure these are still
368 /// valid. One strategy is to reset potentially invalid parameters right before the call using
369 /// `reset_parameters`.
370 ///
371 /// # Return
372 ///
373 /// * [`SqlResult::NeedData`] if execution requires additional data from delayed parameters.
374 /// * [`SqlResult::NoData`] if a searched update or delete statement did not affect any rows at
375 /// the data source.
376 unsafe fn exec_direct(&mut self, statement: &SqlText) -> SqlResult<()> {
377 unsafe {
378 sql_exec_direc(
379 self.as_sys(),
380 statement.ptr(),
381 statement.len_char().try_into().unwrap(),
382 )
383 }
384 .into_sql_result("SQLExecDirect")
385 }
386
387 /// Close an open cursor.
388 fn close_cursor(&mut self) -> SqlResult<()> {
389 unsafe { SQLCloseCursor(self.as_sys()) }.into_sql_result("SQLCloseCursor")
390 }
391
392 /// Send an SQL statement to the data source for preparation. The application can include one or
393 /// more parameter markers in the SQL statement. To include a parameter marker, the application
394 /// embeds a question mark (?) into the SQL string at the appropriate position.
395 fn prepare(&mut self, statement: &SqlText) -> SqlResult<()> {
396 unsafe {
397 sql_prepare(
398 self.as_sys(),
399 statement.ptr(),
400 statement.len_char().try_into().unwrap(),
401 )
402 }
403 .into_sql_result("SQLPrepare")
404 }
405
406 /// Executes a statement prepared by `prepare`. After the application processes or discards the
407 /// results from a call to `execute`, the application can call SQLExecute again with new
408 /// parameter values.
409 ///
410 /// # Safety
411 ///
412 /// While `self` as always guaranteed to be a valid allocated handle, this function may
413 /// dereference bound parameters. It is the callers responsibility to ensure these are still
414 /// valid. One strategy is to reset potentially invalid parameters right before the call using
415 /// `reset_parameters`.
416 ///
417 /// # Return
418 ///
419 /// * [`SqlResult::NeedData`] if execution requires additional data from delayed parameters.
420 /// * [`SqlResult::NoData`] if a searched update or delete statement did not affect any rows at
421 /// the data source.
422 unsafe fn execute(&mut self) -> SqlResult<()> {
423 unsafe { SQLExecute(self.as_sys()) }.into_sql_result("SQLExecute")
424 }
425
426 /// Number of columns in result set.
427 ///
428 /// Can also be used to check, whether or not a result set has been created at all.
429 fn num_result_cols(&self) -> SqlResult<i16> {
430 let mut out: i16 = 0;
431 unsafe { SQLNumResultCols(self.as_sys(), &mut out) }
432 .into_sql_result("SQLNumResultCols")
433 .on_success(|| out)
434 }
435
436 /// Number of placeholders of a prepared query.
437 fn num_params(&self) -> SqlResult<u16> {
438 let mut out: i16 = 0;
439 unsafe { SQLNumParams(self.as_sys(), &mut out) }
440 .into_sql_result("SQLNumParams")
441 .on_success(|| out.try_into().unwrap())
442 }
443
444 /// Sets the batch size for bulk cursors, if retrieving many rows at once.
445 ///
446 /// # Safety
447 ///
448 /// It is the callers responsibility to ensure that buffers bound using `bind_col` can hold the
449 /// specified amount of rows.
450 unsafe fn set_row_array_size(&mut self, size: usize) -> SqlResult<()> {
451 assert!(size > 0);
452 unsafe {
453 sql_set_stmt_attr(
454 self.as_sys(),
455 StatementAttribute::RowArraySize,
456 size as Pointer,
457 0,
458 )
459 }
460 .into_sql_result("SQLSetStmtAttr")
461 }
462
463 /// Sets the batch size for bulk cursors, if retrieving many rows at once.
464 ///
465 /// # Safety
466 ///
467 /// It is the callers responsibility to ensure that buffers bound using `bind_col` can hold the
468 /// specified amount of rows.
469 unsafe 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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&self, attribute: Desc, column_number: u16) -> SqlResult<Len> {
811 let mut out: Len = 0;
812 unsafe {
813 sql_col_attribute(
814 self.as_sys(),
815 column_number,
816 attribute,
817 null_mut(),
818 0,
819 null_mut(),
820 &mut out as *mut Len,
821 )
822 }
823 .into_sql_result("SQLColAttribute")
824 .on_success(|| {
825 debug!(
826 "SQLColAttribute called with attribute '{attribute:?}' for column \
827 '{column_number}' reported {out}."
828 );
829 out
830 })
831 }
832
833 /// Sets the SQL_DESC_COUNT field of the APD to 0, releasing all parameter buffers set for the
834 /// given StatementHandle.
835 fn reset_parameters(&mut self) -> SqlResult<()> {
836 unsafe {
837 SQLFreeStmt(self.as_sys(), FreeStmtOption::ResetParams).into_sql_result("SQLFreeStmt")
838 }
839 }
840
841 /// Describes parameter marker associated with a prepared SQL statement.
842 ///
843 /// # Parameters
844 ///
845 /// * `parameter_number`: Parameter marker number ordered sequentially in increasing parameter
846 /// order, starting at 1.
847 fn describe_param(&self, parameter_number: u16) -> SqlResult<ParameterDescription> {
848 let mut data_type = SqlDataType::UNKNOWN_TYPE;
849 let mut parameter_size = 0;
850 let mut decimal_digits = 0;
851 let mut nullable = odbc_sys::Nullability::UNKNOWN;
852 unsafe {
853 SQLDescribeParam(
854 self.as_sys(),
855 parameter_number,
856 &mut data_type,
857 &mut parameter_size,
858 &mut decimal_digits,
859 &mut nullable,
860 )
861 }
862 .into_sql_result("SQLDescribeParam")
863 .on_success(|| ParameterDescription {
864 data_type: DataType::new(data_type, parameter_size, decimal_digits),
865 nullability: Nullability::new(nullable),
866 })
867 }
868
869 /// Use to check if which additional parameters need data. Should be called after binding
870 /// parameters with an indicator set to [`crate::sys::DATA_AT_EXEC`] or a value created with
871 /// [`crate::sys::len_data_at_exec`].
872 ///
873 /// Return value contains a parameter identifier passed to bind parameter as a value pointer.
874 fn param_data(&mut self) -> SqlResult<Option<Pointer>> {
875 unsafe {
876 let mut param_id: Pointer = null_mut();
877 // Use cases for `PARAM_DATA_AVAILABLE` and `NO_DATA` not implemented yet.
878 match SQLParamData(self.as_sys(), &mut param_id as *mut Pointer) {
879 SqlReturn::NEED_DATA => SqlResult::Success(Some(param_id)),
880 other => other.into_sql_result("SQLParamData").on_success(|| None),
881 }
882 }
883 }
884
885 /// Executes a columns query using this statement handle.
886 fn columns(
887 &mut self,
888 catalog_name: &SqlText,
889 schema_name: &SqlText,
890 table_name: &SqlText,
891 column_name: &SqlText,
892 ) -> SqlResult<()> {
893 unsafe {
894 sql_columns(
895 self.as_sys(),
896 catalog_name.ptr(),
897 catalog_name.len_char().try_into().unwrap(),
898 schema_name.ptr(),
899 schema_name.len_char().try_into().unwrap(),
900 table_name.ptr(),
901 table_name.len_char().try_into().unwrap(),
902 column_name.ptr(),
903 column_name.len_char().try_into().unwrap(),
904 )
905 .into_sql_result("SQLColumns")
906 }
907 }
908
909 /// Returns the list of table, catalog, or schema names, and table types, stored in a specific
910 /// data source. The driver returns the information as a result set.
911 ///
912 /// The catalog, schema and table parameters are search patterns by default unless
913 /// [`Self::set_metadata_id`] is called with `true`. In that case they must also not be `None`
914 /// since otherwise a NulPointer error is emitted.
915 fn tables(
916 &mut self,
917 catalog_name: &SqlText,
918 schema_name: &SqlText,
919 table_name: &SqlText,
920 table_type: &SqlText,
921 ) -> SqlResult<()> {
922 unsafe {
923 sql_tables(
924 self.as_sys(),
925 catalog_name.ptr(),
926 catalog_name.len_char().try_into().unwrap(),
927 schema_name.ptr(),
928 schema_name.len_char().try_into().unwrap(),
929 table_name.ptr(),
930 table_name.len_char().try_into().unwrap(),
931 table_type.ptr(),
932 table_type.len_char().try_into().unwrap(),
933 )
934 .into_sql_result("SQLTables")
935 }
936 }
937
938 /// This can be used to retrieve either a list of foreign keys in the specified table or a list
939 /// of foreign keys in other table that refer to the primary key of the specified table.
940 ///
941 /// Like [`Self::tables`] this changes the statement to a cursor over the result set.
942 fn foreign_keys(
943 &mut self,
944 pk_catalog_name: &SqlText,
945 pk_schema_name: &SqlText,
946 pk_table_name: &SqlText,
947 fk_catalog_name: &SqlText,
948 fk_schema_name: &SqlText,
949 fk_table_name: &SqlText,
950 ) -> SqlResult<()> {
951 unsafe {
952 sql_foreign_keys(
953 self.as_sys(),
954 pk_catalog_name.ptr(),
955 pk_catalog_name.len_char().try_into().unwrap(),
956 pk_schema_name.ptr(),
957 pk_schema_name.len_char().try_into().unwrap(),
958 pk_table_name.ptr(),
959 pk_table_name.len_char().try_into().unwrap(),
960 fk_catalog_name.ptr(),
961 fk_catalog_name.len_char().try_into().unwrap(),
962 fk_schema_name.ptr(),
963 fk_schema_name.len_char().try_into().unwrap(),
964 fk_table_name.ptr(),
965 fk_table_name.len_char().try_into().unwrap(),
966 )
967 .into_sql_result("SQLForeignKeys")
968 }
969 }
970
971 /// To put a batch of binary data into the data source at statement execution time. May return
972 /// [`SqlResult::NeedData`]
973 ///
974 /// Panics if batch is empty.
975 fn put_binary_batch(&mut self, batch: &[u8]) -> SqlResult<()> {
976 // Probably not strictly necessary. MSSQL returns an error than inserting empty batches.
977 // Still strikes me as a programming error. Maybe we could also do nothing instead.
978 if batch.is_empty() {
979 panic!("Attempt to put empty batch into data source.")
980 }
981
982 unsafe {
983 SQLPutData(
984 self.as_sys(),
985 batch.as_ptr() as Pointer,
986 batch.len().try_into().unwrap(),
987 )
988 .into_sql_result("SQLPutData")
989 }
990 }
991
992 /// Number of rows affected by an `UPDATE`, `INSERT`, or `DELETE` statement.
993 ///
994 /// See:
995 ///
996 /// <https://docs.microsoft.com/en-us/sql/relational-databases/native-client-odbc-api/sqlrowcount>
997 /// <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlrowcount-function>
998 fn row_count(&mut self) -> SqlResult<isize> {
999 let mut ret = 0isize;
1000 unsafe {
1001 SQLRowCount(self.as_sys(), &mut ret as *mut isize)
1002 .into_sql_result("SQLRowCount")
1003 .on_success(|| ret)
1004 }
1005 }
1006
1007 /// In polling mode can be used instead of repeating the function call. In notification mode
1008 /// this completes the asynchronous operation. This method panics, in case asynchronous mode is
1009 /// not enabled. [`SqlResult::NoData`] if no asynchronous operation is in progress, or (specific
1010 /// to notification mode) the driver manager has not notified the application.
1011 ///
1012 /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlcompleteasync-function>
1013 #[cfg(feature = "odbc_version_3_80")]
1014 fn complete_async(&mut self, function_name: &'static str) -> SqlResult<SqlResult<()>> {
1015 let mut ret = SqlReturn::ERROR;
1016 unsafe {
1017 // Possible return codes are (according to MS ODBC docs):
1018 // * INVALID_HANDLE: The handle indicated by HandleType and Handle is not a valid
1019 // handle. => Must not happen due self always being a valid statement handle.
1020 // * ERROR: ret is NULL or asynchronous processing is not enabled on the handle. => ret
1021 // is never NULL. User may choose not to enable asynchronous processing though.
1022 // * NO_DATA: In notification mode, an asynchronous operation is not in progress or the
1023 // Driver Manager has not notified the application. In polling mode, an asynchronous
1024 // operation is not in progress.
1025 SQLCompleteAsync(self.handle_type(), self.as_handle(), &mut ret.0 as *mut _)
1026 .into_sql_result("SQLCompleteAsync")
1027 }
1028 .on_success(|| ret.into_sql_result(function_name))
1029 }
1030
1031 /// Determines whether more results are available on a statement containing SELECT, UPDATE,
1032 /// INSERT, or DELETE statements and, if so, initializes processing for those results.
1033 /// [`SqlResult::NoData`] is returned to indicate that there are no more result sets.
1034 ///
1035 /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlmoreresults-function>
1036 ///
1037 /// # Safety
1038 ///
1039 /// Since a different result set might have a different schema, care needs to be taken that
1040 /// bound buffers are used correctly.
1041 unsafe fn more_results(&mut self) -> SqlResult<()> {
1042 unsafe { SQLMoreResults(self.as_sys()).into_sql_result("SQLMoreResults") }
1043 }
1044
1045 /// Application Row Descriptor (ARD) associated with the statement handle. It describes the row
1046 /// afte the conversions for the application have been applied. It can be used to query
1047 /// information as well as to set specific desired conversions. E.g. precision and scale for
1048 /// numeric structs. Usually applications have no need to interact directly with the ARD
1049 /// though.
1050 fn application_row_descriptor(&mut self) -> SqlResult<Descriptor<'_>> {
1051 unsafe {
1052 let mut hdesc: odbc_sys::HDesc = null_mut();
1053 let hdesc_out = &mut hdesc as *mut odbc_sys::HDesc as Pointer;
1054 odbc_sys::SQLGetStmtAttr(
1055 self.as_sys(),
1056 odbc_sys::StatementAttribute::AppRowDesc,
1057 hdesc_out,
1058 0,
1059 null_mut(),
1060 )
1061 .into_sql_result("SQLGetStmtAttr")
1062 .on_success(|| Descriptor::new(hdesc))
1063 }
1064 }
1065}
1066
1067impl Statement for StatementImpl<'_> {
1068 /// Gain access to the underlying statement handle without transferring ownership to it.
1069 fn as_sys(&self) -> HStmt {
1070 self.handle
1071 }
1072}
1073
1074/// Description of a parameter associated with a parameter marker in a prepared statement. Returned
1075/// by [`crate::Prepared::describe_param`].
1076#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1077pub struct ParameterDescription {
1078 /// Indicates whether the parameter may be NULL not.
1079 pub nullability: Nullability,
1080 /// The SQL Type associated with that parameter.
1081 pub data_type: DataType,
1082}