odbc_api/handles/
descriptor.rs

1use std::marker::PhantomData;
2
3use odbc_sys::{
4    CDataType, Desc, HDesc, HStmt, Handle, HandleType, IS_POINTER, IS_SMALLINT, Pointer,
5};
6
7use super::{AnyHandle, SqlResult, sql_result::ExtSqlReturn};
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/// * APD Application parameter descriptor
21/// * ARD Application row descriptor
22pub struct Descriptor<'stmt> {
23    handle: HDesc,
24    parent: PhantomData<&'stmt HStmt>,
25}
26
27impl Descriptor<'_> {
28    /// # Safety
29    ///
30    /// Call this method only with a valid (successfully allocated) ODBC descriptor handle.
31    pub unsafe fn new(handle: HDesc) -> Self {
32        Self {
33            handle,
34            parent: PhantomData,
35        }
36    }
37
38    /// Directly acces the underlying ODBC handle.
39    pub fn as_sys(&self) -> HDesc {
40        self.handle
41    }
42
43    /// Number of digits for an exact numeric type, the number of bits in the mantissa (binary
44    /// precision) for an approximate numeric type, or the numbers of digits in the fractional
45    /// seconds component for the SQL_TYPE_TIME, SQL_TYPE_TIMESTAMP, or SQL_INTERVAL_SECOND data
46    /// type. This field is undefined for all other data types.
47    /// See: <https://learn.microsoft.com/sql/odbc/reference/syntax/sqlsetdescfield-function>
48    pub fn set_precision(&mut self, rec_number: i16, precision: i16) -> SqlResult<()> {
49        unsafe {
50            sql_set_desc_field(
51                self.as_sys(),
52                rec_number,
53                Desc::Precision,
54                precision as Pointer,
55                IS_SMALLINT,
56            )
57            .into_sql_result("SQLSetDescField")
58        }
59    }
60
61    /// The defined scale for decimal and numeric data types. The field is undefined for all other
62    /// data types.
63    pub fn set_scale(&mut self, rec_number: i16, scale: i16) -> SqlResult<()> {
64        unsafe {
65            sql_set_desc_field(
66                self.as_sys(),
67                rec_number,
68                Desc::Scale,
69                scale as Pointer,
70                IS_SMALLINT,
71            )
72            .into_sql_result("SQLSetDescField")
73        }
74    }
75
76    /// C-Type bound to the data pointer.
77    ///
78    /// # Safety
79    ///
80    /// The buffer bound to the data pointer in ARD must match, otherwise calls to fetch might e.g.
81    /// write beyond the bounds of these types, if e.g. a larger type is bound
82    pub unsafe fn set_type(&mut self, rec_number: i16, c_type: CDataType) -> SqlResult<()> {
83        unsafe {
84            sql_set_desc_field(
85                self.as_sys(),
86                rec_number,
87                Desc::Type,
88                c_type as i16 as Pointer,
89                IS_SMALLINT,
90            )
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        unsafe {
102            sql_set_desc_field(
103                self.as_sys(),
104                rec_number,
105                Desc::DataPtr,
106                data_ptr,
107                IS_POINTER,
108            )
109        }
110        .into_sql_result("SQLSetDescField")
111    }
112}
113
114unsafe impl AnyHandle for Descriptor<'_> {
115    fn as_handle(&self) -> Handle {
116        self.handle.as_handle()
117    }
118
119    fn handle_type(&self) -> HandleType {
120        HandleType::Desc
121    }
122}