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