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 /// Specifies the number of values for each parameter. If it is greater than 1, the data and
464 /// indicator buffers of the statement point to arrays. The cardinality of each array is equal
465 /// to the value of this field.
466 ///
467 /// # Safety
468 ///
469 /// The bound buffers must at least hold the number of elements specified in this call then the
470 /// statement is executed.
471 unsafe fn set_paramset_size(&mut self, size: usize) -> SqlResult<()> {
472 assert!(size > 0);
473 unsafe {
474 sql_set_stmt_attr(
475 self.as_sys(),
476 StatementAttribute::ParamsetSize,
477 size as Pointer,
478 0,
479 )
480 }
481 .into_sql_result("SQLSetStmtAttr")
482 }
483
484 /// Sets the binding type to columnar binding for batch cursors.
485 ///
486 /// Any Positive number indicates a row wise binding with that row length. `0` indicates a
487 /// columnar binding.
488 ///
489 /// # Safety
490 ///
491 /// It is the callers responsibility to ensure that the bound buffers match the memory layout
492 /// specified by this function.
493 unsafe fn set_row_bind_type(&mut self, row_size: usize) -> SqlResult<()> {
494 unsafe {
495 sql_set_stmt_attr(
496 self.as_sys(),
497 StatementAttribute::RowBindType,
498 row_size as Pointer,
499 0,
500 )
501 }
502 .into_sql_result("SQLSetStmtAttr")
503 }
504
505 fn set_metadata_id(&mut self, metadata_id: bool) -> SqlResult<()> {
506 unsafe {
507 sql_set_stmt_attr(
508 self.as_sys(),
509 StatementAttribute::MetadataId,
510 metadata_id as usize as Pointer,
511 0,
512 )
513 .into_sql_result("SQLSetStmtAttr")
514 }
515 }
516
517 /// Enables or disables asynchronous execution for this statement handle. If asynchronous
518 /// execution is not enabled on connection level it is disabled by default and everything is
519 /// executed synchronously.
520 ///
521 /// This is equivalent to stetting `SQL_ATTR_ASYNC_ENABLE` in the bare C API.
522 ///
523 /// See
524 /// <https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/executing-statements-odbc>
525 fn set_async_enable(&mut self, on: bool) -> SqlResult<()> {
526 unsafe {
527 sql_set_stmt_attr(
528 self.as_sys(),
529 StatementAttribute::AsyncEnable,
530 on as usize as Pointer,
531 0,
532 )
533 .into_sql_result("SQLSetStmtAttr")
534 }
535 }
536
537 /// Binds a buffer holding an input parameter to a parameter marker in an SQL statement. This
538 /// specialized version takes a constant reference to parameter, but is therefore limited to
539 /// binding input parameters. See [`Statement::bind_parameter`] for the version which can bind
540 /// input and output parameters.
541 ///
542 /// See <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function>.
543 ///
544 /// # Safety
545 ///
546 /// * It is up to the caller to ensure the lifetimes of the bound parameters.
547 /// * Calling this function may influence other statements that share the APD.
548 /// * `parameter` must be complete, i.e not be truncated.
549 unsafe fn bind_input_parameter(
550 &mut self,
551 parameter_number: u16,
552 parameter: &(impl HasDataType + CData + ?Sized),
553 ) -> SqlResult<()> {
554 let parameter_type = parameter.data_type();
555 unsafe {
556 SQLBindParameter(
557 self.as_sys(),
558 parameter_number,
559 ParamType::Input,
560 parameter.cdata_type(),
561 parameter_type.data_type(),
562 parameter_type
563 .column_size()
564 .map(NonZeroUsize::get)
565 .unwrap_or_default(),
566 parameter_type.decimal_digits(),
567 // We cast const to mut here, but we specify the input_output_type as input.
568 parameter.value_ptr() as *mut c_void,
569 parameter.buffer_length(),
570 // We cast const to mut here, but we specify the input_output_type as input.
571 parameter.indicator_ptr() as *mut isize,
572 )
573 }
574 .into_sql_result("SQLBindParameter")
575 }
576
577 /// Binds a buffer holding a single parameter to a parameter marker in an SQL statement. To bind
578 /// input parameters using constant references see [`Statement::bind_input_parameter`].
579 ///
580 /// See <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function>.
581 ///
582 /// # Safety
583 ///
584 /// * It is up to the caller to ensure the lifetimes of the bound parameters.
585 /// * Calling this function may influence other statements that share the APD.
586 /// * `parameter` must be complete, i.e not be truncated. If `input_output_type` indicates
587 /// [`ParamType::Input`] or [`ParamType::InputOutput`].
588 unsafe fn bind_parameter(
589 &mut self,
590 parameter_number: u16,
591 input_output_type: ParamType,
592 parameter: &mut (impl CDataMut + HasDataType),
593 ) -> SqlResult<()> {
594 let parameter_type = parameter.data_type();
595 unsafe {
596 SQLBindParameter(
597 self.as_sys(),
598 parameter_number,
599 input_output_type,
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 parameter.value_ptr() as *mut c_void,
608 parameter.buffer_length(),
609 parameter.mut_indicator_ptr(),
610 )
611 }
612 .into_sql_result("SQLBindParameter")
613 }
614
615 /// Binds an input stream to a parameter marker in an SQL statement. Use this to stream large
616 /// values at statement execution time. To bind preallocated constant buffers see
617 /// [`Statement::bind_input_parameter`].
618 ///
619 /// See <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function>.
620 ///
621 /// # Safety
622 ///
623 /// * It is up to the caller to ensure the lifetimes of the bound parameters.
624 /// * Calling this function may influence other statements that share the APD.
625 unsafe fn bind_delayed_input_parameter(
626 &mut self,
627 parameter_number: u16,
628 parameter: &mut (impl DelayedInput + HasDataType),
629 ) -> SqlResult<()> {
630 let paramater_type = parameter.data_type();
631 unsafe {
632 SQLBindParameter(
633 self.as_sys(),
634 parameter_number,
635 ParamType::Input,
636 parameter.cdata_type(),
637 paramater_type.data_type(),
638 paramater_type
639 .column_size()
640 .map(NonZeroUsize::get)
641 .unwrap_or_default(),
642 paramater_type.decimal_digits(),
643 parameter.stream_ptr(),
644 0,
645 // We cast const to mut here, but we specify the input_output_type as input.
646 parameter.indicator_ptr() as *mut isize,
647 )
648 }
649 .into_sql_result("SQLBindParameter")
650 }
651
652 /// `true` if a given column in a result set is unsigned or not a numeric type, `false`
653 /// otherwise.
654 ///
655 /// `column_number`: Index of the column, starting at 1.
656 fn is_unsigned_column(&self, column_number: u16) -> SqlResult<bool> {
657 unsafe { self.numeric_col_attribute(Desc::Unsigned, column_number) }.map(|out| match out {
658 0 => false,
659 1 => true,
660 _ => panic!("Unsigned column attribute must be either 0 or 1."),
661 })
662 }
663
664 /// Returns a number identifying the SQL type of the column in the result set.
665 ///
666 /// `column_number`: Index of the column, starting at 1.
667 fn col_type(&self, column_number: u16) -> SqlResult<SqlDataType> {
668 unsafe { self.numeric_col_attribute(Desc::Type, column_number) }.map(|ret| {
669 SqlDataType(ret.try_into().expect(
670 "Failed to retrieve data type from ODBC driver. The SQLLEN could not be converted to
671 a 16 Bit integer. If you are on a 64Bit Platform, this may be because your \
672 database driver being compiled against a SQLLEN with 32Bit size instead of 64Bit. \
673 E.g. IBM offers libdb2o.* and libdb2.*. With libdb2o.* being the one with the \
674 correct size.",
675 ))
676 })
677 }
678
679 /// The concise data type. For the datetime and interval data types, this field returns the
680 /// concise data type; for example, `TIME` or `INTERVAL_YEAR`.
681 ///
682 /// `column_number`: Index of the column, starting at 1.
683 fn col_concise_type(&self, column_number: u16) -> SqlResult<SqlDataType> {
684 unsafe { self.numeric_col_attribute(Desc::ConciseType, column_number) }.map(|ret| {
685 SqlDataType(ret.try_into().expect(
686 "Failed to retrieve data type from ODBC driver. The SQLLEN could not be \
687 converted to a 16 Bit integer. If you are on a 64Bit Platform, this may be \
688 because your database driver being compiled against a SQLLEN with 32Bit size \
689 instead of 64Bit. E.g. IBM offers libdb2o.* and libdb2.*. With libdb2o.* being \
690 the one with the correct size.",
691 ))
692 })
693 }
694
695 /// Returns the size in bytes of the columns. For variable sized types the maximum size is
696 /// returned, excluding a terminating zero.
697 ///
698 /// `column_number`: Index of the column, starting at 1.
699 fn col_octet_length(&self, column_number: u16) -> SqlResult<isize> {
700 unsafe { self.numeric_col_attribute(Desc::OctetLength, column_number) }
701 }
702
703 /// Maximum number of characters required to display data from the column.
704 ///
705 /// `column_number`: Index of the column, starting at 1.
706 fn col_display_size(&self, column_number: u16) -> SqlResult<isize> {
707 unsafe { self.numeric_col_attribute(Desc::DisplaySize, column_number) }
708 }
709
710 /// Precision of the column.
711 ///
712 /// Denotes the applicable precision. For data types SQL_TYPE_TIME, SQL_TYPE_TIMESTAMP, and all
713 /// the interval data types that represent a time interval, its value is the applicable
714 /// precision of the fractional seconds component.
715 fn col_precision(&self, column_number: u16) -> SqlResult<isize> {
716 unsafe { self.numeric_col_attribute(Desc::Precision, column_number) }
717 }
718
719 /// The applicable scale for a numeric data type. For DECIMAL and NUMERIC data types, this is
720 /// the defined scale. It is undefined for all other data types.
721 fn col_scale(&self, column_number: u16) -> SqlResult<Len> {
722 unsafe { self.numeric_col_attribute(Desc::Scale, column_number) }
723 }
724
725 /// The column alias, if it applies. If the column alias does not apply, the column name is
726 /// returned. If there is no column name or a column alias, an empty string is returned.
727 fn col_name(&self, column_number: u16, buffer: &mut Vec<SqlChar>) -> SqlResult<()> {
728 // String length in bytes, not characters. Terminating zero is excluded.
729 let mut string_length_in_bytes: i16 = 0;
730 // Let's utilize all of `buf`s capacity.
731 buffer.resize(buffer.capacity(), 0);
732 unsafe {
733 let mut res = sql_col_attribute(
734 self.as_sys(),
735 column_number,
736 Desc::Name,
737 mut_buf_ptr(buffer) as Pointer,
738 binary_length(buffer).try_into().unwrap(),
739 &mut string_length_in_bytes as *mut i16,
740 null_mut(),
741 )
742 .into_sql_result("SQLColAttribute");
743
744 if res.is_err() {
745 return res;
746 }
747
748 if is_truncated_bin(buffer, string_length_in_bytes.try_into().unwrap()) {
749 // If we could rely on every ODBC driver sticking to the specifcation it would
750 // probably best to resize by `string_length_in_bytes / 2 + 1`. Yet e.g. SQLite
751 // seems to report the length in characters, so to work with a wide range of DB
752 // systems, and since buffers for names are not expected to become super large we
753 // omit the division by two here.
754 buffer.resize((string_length_in_bytes + 1).try_into().unwrap(), 0);
755
756 res = sql_col_attribute(
757 self.as_sys(),
758 column_number,
759 Desc::Name,
760 mut_buf_ptr(buffer) as Pointer,
761 binary_length(buffer).try_into().unwrap(),
762 &mut string_length_in_bytes as *mut i16,
763 null_mut(),
764 )
765 .into_sql_result("SQLColAttribute");
766 }
767 // Resize buffer to exact string length without terminal zero
768 resize_to_fit_without_tz(buffer, string_length_in_bytes.try_into().unwrap());
769
770 res
771 }
772 }
773
774 /// # Safety
775 ///
776 /// It is the callers responsibility to ensure that `attribute` refers to a numeric attribute.
777 unsafe fn numeric_col_attribute(&self, attribute: Desc, column_number: u16) -> SqlResult<Len> {
778 let mut out: Len = 0;
779 unsafe {
780 sql_col_attribute(
781 self.as_sys(),
782 column_number,
783 attribute,
784 null_mut(),
785 0,
786 null_mut(),
787 &mut out as *mut Len,
788 )
789 }
790 .into_sql_result("SQLColAttribute")
791 .on_success(|| {
792 debug!(
793 "SQLColAttribute called with attribute '{attribute:?}' for column \
794 '{column_number}' reported {out}."
795 );
796 out
797 })
798 }
799
800 /// Sets the SQL_DESC_COUNT field of the APD to 0, releasing all parameter buffers set for the
801 /// given StatementHandle.
802 fn reset_parameters(&mut self) -> SqlResult<()> {
803 unsafe {
804 SQLFreeStmt(self.as_sys(), FreeStmtOption::ResetParams).into_sql_result("SQLFreeStmt")
805 }
806 }
807
808 /// Describes parameter marker associated with a prepared SQL statement.
809 ///
810 /// # Parameters
811 ///
812 /// * `parameter_number`: Parameter marker number ordered sequentially in increasing parameter
813 /// order, starting at 1.
814 fn describe_param(&self, parameter_number: u16) -> SqlResult<ParameterDescription> {
815 let mut data_type = SqlDataType::UNKNOWN_TYPE;
816 let mut parameter_size = 0;
817 let mut decimal_digits = 0;
818 let mut nullable = odbc_sys::Nullability::UNKNOWN;
819 unsafe {
820 SQLDescribeParam(
821 self.as_sys(),
822 parameter_number,
823 &mut data_type,
824 &mut parameter_size,
825 &mut decimal_digits,
826 &mut nullable,
827 )
828 }
829 .into_sql_result("SQLDescribeParam")
830 .on_success(|| ParameterDescription {
831 data_type: DataType::new(data_type, parameter_size, decimal_digits),
832 nullability: Nullability::new(nullable),
833 })
834 }
835
836 /// Use to check if which additional parameters need data. Should be called after binding
837 /// parameters with an indicator set to [`crate::sys::DATA_AT_EXEC`] or a value created with
838 /// [`crate::sys::len_data_at_exec`].
839 ///
840 /// Return value contains a parameter identifier passed to bind parameter as a value pointer.
841 fn param_data(&mut self) -> SqlResult<Option<Pointer>> {
842 unsafe {
843 let mut param_id: Pointer = null_mut();
844 // Use cases for `PARAM_DATA_AVAILABLE` and `NO_DATA` not implemented yet.
845 match SQLParamData(self.as_sys(), &mut param_id as *mut Pointer) {
846 SqlReturn::NEED_DATA => SqlResult::Success(Some(param_id)),
847 other => other.into_sql_result("SQLParamData").on_success(|| None),
848 }
849 }
850 }
851
852 /// Executes a columns query using this statement handle.
853 fn columns(
854 &mut self,
855 catalog_name: &SqlText,
856 schema_name: &SqlText,
857 table_name: &SqlText,
858 column_name: &SqlText,
859 ) -> SqlResult<()> {
860 unsafe {
861 sql_columns(
862 self.as_sys(),
863 catalog_name.ptr(),
864 catalog_name.len_char().try_into().unwrap(),
865 schema_name.ptr(),
866 schema_name.len_char().try_into().unwrap(),
867 table_name.ptr(),
868 table_name.len_char().try_into().unwrap(),
869 column_name.ptr(),
870 column_name.len_char().try_into().unwrap(),
871 )
872 .into_sql_result("SQLColumns")
873 }
874 }
875
876 /// Returns the list of table, catalog, or schema names, and table types, stored in a specific
877 /// data source. The driver returns the information as a result set.
878 ///
879 /// The catalog, schema and table parameters are search patterns by default unless
880 /// [`Self::set_metadata_id`] is called with `true`. In that case they must also not be `None`
881 /// since otherwise a NulPointer error is emitted.
882 fn tables(
883 &mut self,
884 catalog_name: &SqlText,
885 schema_name: &SqlText,
886 table_name: &SqlText,
887 table_type: &SqlText,
888 ) -> SqlResult<()> {
889 unsafe {
890 sql_tables(
891 self.as_sys(),
892 catalog_name.ptr(),
893 catalog_name.len_char().try_into().unwrap(),
894 schema_name.ptr(),
895 schema_name.len_char().try_into().unwrap(),
896 table_name.ptr(),
897 table_name.len_char().try_into().unwrap(),
898 table_type.ptr(),
899 table_type.len_char().try_into().unwrap(),
900 )
901 .into_sql_result("SQLTables")
902 }
903 }
904
905 /// This can be used to retrieve either a list of foreign keys in the specified table or a list
906 /// of foreign keys in other table that refer to the primary key of the specified table.
907 ///
908 /// Like [`Self::tables`] this changes the statement to a cursor over the result set.
909 fn foreign_keys(
910 &mut self,
911 pk_catalog_name: &SqlText,
912 pk_schema_name: &SqlText,
913 pk_table_name: &SqlText,
914 fk_catalog_name: &SqlText,
915 fk_schema_name: &SqlText,
916 fk_table_name: &SqlText,
917 ) -> SqlResult<()> {
918 unsafe {
919 sql_foreign_keys(
920 self.as_sys(),
921 pk_catalog_name.ptr(),
922 pk_catalog_name.len_char().try_into().unwrap(),
923 pk_schema_name.ptr(),
924 pk_schema_name.len_char().try_into().unwrap(),
925 pk_table_name.ptr(),
926 pk_table_name.len_char().try_into().unwrap(),
927 fk_catalog_name.ptr(),
928 fk_catalog_name.len_char().try_into().unwrap(),
929 fk_schema_name.ptr(),
930 fk_schema_name.len_char().try_into().unwrap(),
931 fk_table_name.ptr(),
932 fk_table_name.len_char().try_into().unwrap(),
933 )
934 .into_sql_result("SQLForeignKeys")
935 }
936 }
937
938 /// To put a batch of binary data into the data source at statement execution time. May return
939 /// [`SqlResult::NeedData`]
940 ///
941 /// Panics if batch is empty.
942 fn put_binary_batch(&mut self, batch: &[u8]) -> SqlResult<()> {
943 // Probably not strictly necessary. MSSQL returns an error than inserting empty batches.
944 // Still strikes me as a programming error. Maybe we could also do nothing instead.
945 if batch.is_empty() {
946 panic!("Attempt to put empty batch into data source.")
947 }
948
949 unsafe {
950 SQLPutData(
951 self.as_sys(),
952 batch.as_ptr() as Pointer,
953 batch.len().try_into().unwrap(),
954 )
955 .into_sql_result("SQLPutData")
956 }
957 }
958
959 /// Number of rows affected by an `UPDATE`, `INSERT`, or `DELETE` statement.
960 ///
961 /// See:
962 ///
963 /// <https://docs.microsoft.com/en-us/sql/relational-databases/native-client-odbc-api/sqlrowcount>
964 /// <https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlrowcount-function>
965 fn row_count(&mut self) -> SqlResult<isize> {
966 let mut ret = 0isize;
967 unsafe {
968 SQLRowCount(self.as_sys(), &mut ret as *mut isize)
969 .into_sql_result("SQLRowCount")
970 .on_success(|| ret)
971 }
972 }
973
974 /// In polling mode can be used instead of repeating the function call. In notification mode
975 /// this completes the asynchronous operation. This method panics, in case asynchronous mode is
976 /// not enabled. [`SqlResult::NoData`] if no asynchronous operation is in progress, or (specific
977 /// to notification mode) the driver manager has not notified the application.
978 ///
979 /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlcompleteasync-function>
980 #[cfg(feature = "odbc_version_3_80")]
981 fn complete_async(&mut self, function_name: &'static str) -> SqlResult<SqlResult<()>> {
982 let mut ret = SqlReturn::ERROR;
983 unsafe {
984 // Possible return codes are (according to MS ODBC docs):
985 // * INVALID_HANDLE: The handle indicated by HandleType and Handle is not a valid
986 // handle. => Must not happen due self always being a valid statement handle.
987 // * ERROR: ret is NULL or asynchronous processing is not enabled on the handle. => ret
988 // is never NULL. User may choose not to enable asynchronous processing though.
989 // * NO_DATA: In notification mode, an asynchronous operation is not in progress or the
990 // Driver Manager has not notified the application. In polling mode, an asynchronous
991 // operation is not in progress.
992 SQLCompleteAsync(self.handle_type(), self.as_handle(), &mut ret.0 as *mut _)
993 .into_sql_result("SQLCompleteAsync")
994 }
995 .on_success(|| ret.into_sql_result(function_name))
996 }
997
998 /// Determines whether more results are available on a statement containing SELECT, UPDATE,
999 /// INSERT, or DELETE statements and, if so, initializes processing for those results.
1000 /// [`SqlResult::NoData`] is returned to indicate that there are no more result sets.
1001 ///
1002 /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlmoreresults-function>
1003 ///
1004 /// # Safety
1005 ///
1006 /// Since a different result set might have a different schema, care needs to be taken that
1007 /// bound buffers are used correctly.
1008 unsafe fn more_results(&mut self) -> SqlResult<()> {
1009 unsafe { SQLMoreResults(self.as_sys()).into_sql_result("SQLMoreResults") }
1010 }
1011
1012 /// Application Row Descriptor (ARD) associated with the statement handle. It describes the row
1013 /// afte the conversions for the application have been applied. It can be used to query
1014 /// information as well as to set specific desired conversions. E.g. precision and scale for
1015 /// numeric structs. Usually applications have no need to interact directly with the ARD
1016 /// though.
1017 fn application_row_descriptor(&mut self) -> SqlResult<Descriptor<'_>> {
1018 unsafe {
1019 let mut hdesc: odbc_sys::HDesc = null_mut();
1020 let hdesc_out = &mut hdesc as *mut odbc_sys::HDesc as Pointer;
1021 odbc_sys::SQLGetStmtAttr(
1022 self.as_sys(),
1023 odbc_sys::StatementAttribute::AppRowDesc,
1024 hdesc_out,
1025 0,
1026 null_mut(),
1027 )
1028 .into_sql_result("SQLGetStmtAttr")
1029 .on_success(|| Descriptor::new(hdesc))
1030 }
1031 }
1032}
1033
1034impl Statement for StatementImpl<'_> {
1035 /// Gain access to the underlying statement handle without transferring ownership to it.
1036 fn as_sys(&self) -> HStmt {
1037 self.handle
1038 }
1039}
1040
1041/// Description of a parameter associated with a parameter marker in a prepared statement. Returned
1042/// by [`crate::Prepared::describe_param`].
1043#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1044pub struct ParameterDescription {
1045 /// Indicates whether the parameter may be NULL not.
1046 pub nullability: Nullability,
1047 /// The SQL Type associated with that parameter.
1048 pub data_type: DataType,
1049}