odbc_safe/handles/
hstmt.rs

1use super::*;
2use sys::*;
3use std::marker::PhantomData;
4use std::ptr::{null, null_mut};
5use std::thread::panicking;
6
7#[derive(Debug)]
8pub struct HStmt<'con> {
9    /// Statement may not outlive the connection used to allocate it.
10    parent: PhantomData<&'con HDbc<'con>>,
11    /// Invariant: Connection handle is always valid.
12    handle: SQLHSTMT,
13}
14
15impl<'con, 'param> Drop for HStmt<'con> {
16    fn drop(&mut self) {
17        unsafe {
18            match SQLFreeHandle(SQL_HANDLE_STMT, self.handle as SQLHANDLE) {
19                SQL_SUCCESS => (),
20                other => {
21                    if !panicking() {
22                        panic!("Unexepected return value of SQLFreeHandle: {:?}.", other)
23                    }
24                }
25            }
26        }
27    }
28}
29
30unsafe impl<'env, 'param> Handle for HStmt<'env> {
31    const HANDLE_TYPE: HandleType = SQL_HANDLE_STMT;
32
33    fn handle(&self) -> SQLHANDLE {
34        self.handle as SQLHANDLE
35    }
36}
37
38impl<'env, 'param> HStmt<'env> {
39    pub fn as_raw(&self) -> SQLHSTMT {
40        self.handle
41    }
42
43    /// Allocates a new Statement Handle
44    pub fn allocate(parent: &HDbc) -> Return<Self> {
45        let mut out = null_mut();
46        unsafe {
47            let result: Return<()> = SQLAllocHandle(SQL_HANDLE_STMT, parent.handle(), &mut out)
48                .into();
49            result.map(|()| {
50                HStmt {
51                    parent: PhantomData,
52                    handle: out as SQLHSTMT,
53                }
54            })
55        }
56    }
57
58    pub fn exec_direct<T>(&mut self, statement_text: &T) -> ReturnOption<()>
59    where
60        T: SqlStr + ?Sized,
61    {
62        unsafe {
63            SQLExecDirect(
64                self.handle,
65                statement_text.as_text_ptr(),
66                statement_text.text_length_int(),
67            ).into()
68        }
69    }
70
71    pub fn num_result_cols(&self) -> Return<SQLSMALLINT> {
72        let mut out: SQLSMALLINT = 0;
73        let ret = unsafe { SQLNumResultCols(self.handle, &mut out) };
74        let ret: Return<()> = ret.into();
75        ret.map(|()| out)
76    }
77
78    pub fn affected_row_count(&self) -> Return<SQLLEN> {
79        let mut out: SQLLEN = 0;
80        let ret = unsafe { SQLRowCount(self.handle, &mut out) };
81        let ret: Return<()> = ret.into();
82        ret.map(|()| out)
83    }
84
85    pub fn fetch(&mut self) -> ReturnOption<()> {
86        unsafe { SQLFetch(self.handle).into() }
87    }
88
89    pub fn get_data<T>(
90        &mut self,
91        col_or_param_num: SQLUSMALLINT,
92        target: &mut T,
93    ) -> ReturnOption<Indicator>
94    where
95        T: CDataType + ?Sized,
96    {
97        let mut str_len_or_ind = 0;
98        let ret: ReturnOption<()> = unsafe {
99            SQLGetData(
100                self.handle,
101                col_or_param_num,
102                T::c_data_type(),
103                target.mut_sql_ptr(),
104                target.buffer_len(),
105                &mut str_len_or_ind,
106            ).into()
107        };
108        ret.map(|()| str_len_or_ind.into())
109    }
110
111    pub fn close_cursor(&mut self) -> Return<()> {
112        unsafe { SQLCloseCursor(self.handle).into() }
113    }
114
115    /// Binds a parameter to a parameter marker in an SQL Statement
116    ///
117    /// It is the callers responsibility to make sure the bound parameters live long enough.
118    pub unsafe fn bind_input_parameter<T>(
119        &mut self,
120        parameter_number: SQLUSMALLINT,
121        parameter_type: DataType,
122        value: &T,
123        indicator: Option<&SQLLEN>
124    ) -> Return<()>
125    where
126        T: CDataType + ?Sized,
127    {
128        let indicator: *const SQLLEN = match indicator {
129            Some(indicator) => {
130                assert!(*indicator <= value.buffer_len(), "Indicator cannot be larger than buffer length.");
131                indicator
132            }
133            None => null(),
134        };
135        SQLBindParameter(
136            self.handle,
137            parameter_number,
138            SQL_PARAM_INPUT,
139            T::c_data_type(),
140            parameter_type.sql_data_type(),
141            parameter_type.column_size(),
142            parameter_type.decimal_digits(),
143            value.sql_ptr() as SQLPOINTER,
144            0,
145            indicator as *mut SQLLEN,
146        ).into()
147    }
148
149    pub fn prepare<T>(&mut self, statement_text: &T) -> Return<()>
150    where
151        T: SqlStr + ?Sized,
152    {
153        unsafe {
154            SQLPrepare(
155                self.handle,
156                statement_text.as_text_ptr(),
157                statement_text.text_length_int(),
158            ).into()
159        }
160    }
161
162    pub fn reset_parameters(&mut self) -> Return<()> {
163        unsafe { SQLFreeStmt(self.handle, SQL_RESET_PARAMS).into() }
164    }
165
166    pub fn execute(&mut self) -> ReturnOption<()> {
167        unsafe { SQLExecute(self.handle).into() }
168    }
169
170    /// Release all columen buffers bound by `bind_col`. Except bookmark column.
171    pub fn reset_columns(&mut self) -> Return<()> {
172        unsafe { SQLFreeStmt(self.handle, SQL_UNBIND).into() }
173    }
174
175    /// Binds application data buffers to columns in the result set
176    ///
177    /// It is the callers responsibility to make sure the bound columns live long enough.
178    pub unsafe fn bind_col<T>(
179        &mut self,
180        column_number: SQLUSMALLINT,
181        value: &mut T,
182        indicator: Option<&mut SQLLEN>,
183    ) -> Return<()>
184    where
185        T: CDataType + ?Sized,
186    {
187        let indicator: *mut SQLLEN = match indicator {
188            Some(indicator) => indicator,
189            None => null_mut(),
190        };
191        SQLBindCol(
192            self.handle,
193            column_number,
194            T::c_data_type(),
195            value.mut_sql_ptr(),
196            value.buffer_len(),
197            indicator,
198        ).into()
199    }
200
201    pub fn describe_col<T>(
202        &mut self,
203        column_number: SQLUSMALLINT,
204        column_name: &mut T,
205        column_name_indicator: &mut SQLSMALLINT,
206        data_type: &mut SqlDataType,
207        column_size: &mut SQLULEN,
208        decimal_digits: &mut SQLSMALLINT,
209        nullable: &mut Nullable,
210    ) -> Return<()>
211    where
212        T: OutputBuffer + ?Sized,
213    {
214        unsafe {
215            SQLDescribeCol(
216                self.handle,
217                column_number,
218                column_name.mut_buf_ptr(),
219                column_name.buf_len(),
220                column_name_indicator,
221                data_type,
222                column_size,
223                decimal_digits,
224                nullable,
225            ).into()
226        }
227    }
228}