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