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::{AsHandle, 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/// * 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        unsafe {
86            sql_set_desc_field(
87                self.as_sys(),
88                rec_number,
89                Desc::Type,
90                c_type as i16 as Pointer,
91                IS_SMALLINT,
92            )
93        }
94        .into_sql_result("SQLSetDescField")
95    }
96
97    /// Data pointer filled with values from the source when fetching data.
98    ///
99    /// # Safety
100    ///
101    /// Pointer must be valid and match the description set using set_type.
102    pub unsafe fn set_data_ptr(&mut self, rec_number: i16, data_ptr: Pointer) -> SqlResult<()> {
103        unsafe {
104            sql_set_desc_field(
105                self.as_sys(),
106                rec_number,
107                Desc::DataPtr,
108                data_ptr,
109                IS_POINTER,
110            )
111        }
112        .into_sql_result("SQLSetDescField")
113    }
114}
115
116unsafe impl AsHandle for Descriptor<'_> {
117    fn as_handle(&self) -> Handle {
118        self.handle as Handle
119    }
120
121    fn handle_type(&self) -> HandleType {
122        HandleType::Desc
123    }
124}