odbc_api/handles/descriptor.rs
1use std::marker::PhantomData;
2
3use odbc_sys::{
4 CDataType, Desc, HDesc, HStmt, Handle, HandleType, Pointer, IS_POINTER, IS_SMALLINT,
5};
6
7use super::{sql_result::ExtSqlReturn, AsHandle, SqlResult};
8
9#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
10use odbc_sys::SQLSetDescField as sql_set_desc_field;
11
12#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
13use odbc_sys::SQLSetDescFieldW as sql_set_desc_field;
14
15/// A descriptor associated with a statement. This wrapper does not wrap explicitly allocated
16/// descriptors which have the connection as parent, but usually implicitly allocated ones
17/// associated with the statement. It could also represent an explicitly allocated one, but ony in
18/// the context there it is associated with a statement and currently borrowed from it.
19///
20/// * IPD Implementation parameter descriptor
21/// * APD Application parameter descriptor
22/// * IRD Implemenation row descriptor
23/// * ARD Application row descriptor
24pub struct Descriptor<'stmt> {
25 handle: HDesc,
26 parent: PhantomData<&'stmt HStmt>,
27}
28
29impl Descriptor<'_> {
30 /// # Safety
31 ///
32 /// Call this method only with a valid (successfully allocated) ODBC descriptor handle.
33 pub unsafe fn new(handle: HDesc) -> Self {
34 Self {
35 handle,
36 parent: PhantomData,
37 }
38 }
39
40 /// Directly acces the underlying ODBC handle.
41 pub fn as_sys(&self) -> HDesc {
42 self.handle
43 }
44
45 /// Number of digits for an exact numeric type, the number of bits in the mantissa (binary
46 /// precision) for an approximate numeric type, or the numbers of digits in the fractional
47 /// seconds component for the SQL_TYPE_TIME, SQL_TYPE_TIMESTAMP, or SQL_INTERVAL_SECOND data
48 /// type. This field is undefined for all other data types.
49 /// See: <https://learn.microsoft.com/sql/odbc/reference/syntax/sqlsetdescfield-function>
50 pub fn set_precision(&mut self, rec_number: i16, precision: i16) -> SqlResult<()> {
51 unsafe {
52 sql_set_desc_field(
53 self.as_sys(),
54 rec_number,
55 Desc::Precision,
56 precision as Pointer,
57 IS_SMALLINT,
58 )
59 .into_sql_result("SQLSetDescField")
60 }
61 }
62
63 /// The defined scale for decimal and numeric data types. The field is undefined for all other
64 /// data types.
65 pub fn set_scale(&mut self, rec_number: i16, scale: i16) -> SqlResult<()> {
66 unsafe {
67 sql_set_desc_field(
68 self.as_sys(),
69 rec_number,
70 Desc::Scale,
71 scale as Pointer,
72 IS_SMALLINT,
73 )
74 .into_sql_result("SQLSetDescField")
75 }
76 }
77
78 /// C-Type bound to the data pointer.
79 ///
80 /// # Safety
81 ///
82 /// The buffer bound to the data pointer in ARD must match, otherwise calls to fetch might e.g.
83 /// write beyond the bounds of these types, if e.g. a larger type is bound
84 pub unsafe fn set_type(&mut self, rec_number: i16, c_type: CDataType) -> SqlResult<()> {
85 sql_set_desc_field(
86 self.as_sys(),
87 rec_number,
88 Desc::Type,
89 c_type as i16 as Pointer,
90 IS_SMALLINT,
91 )
92 .into_sql_result("SQLSetDescField")
93 }
94
95 /// Data pointer filled with values from the source when fetching data.
96 ///
97 /// # Safety
98 ///
99 /// Pointer must be valid and match the description set using set_type.
100 pub unsafe fn set_data_ptr(&mut self, rec_number: i16, data_ptr: Pointer) -> SqlResult<()> {
101 sql_set_desc_field(
102 self.as_sys(),
103 rec_number,
104 Desc::DataPtr,
105 data_ptr,
106 IS_POINTER,
107 )
108 .into_sql_result("SQLSetDescField")
109 }
110}
111
112unsafe impl AsHandle for Descriptor<'_> {
113 fn as_handle(&self) -> Handle {
114 self.handle as Handle
115 }
116
117 fn handle_type(&self) -> HandleType {
118 HandleType::Desc
119 }
120}