rs_odbc/
diag.rs

1use crate::api::Handle;
2use crate::attr::{Attr, AttrGet, AttrLen, AttrZeroAssert, Void};
3use crate::convert::AsMutSQLPOINTER;
4use crate::env::OdbcVersion;
5use crate::handle::SQLHSTMT;
6use crate::str::{OdbcChar, OdbcStr};
7use crate::{
8    sqlreturn::SQLRETURN, Def, Ident, OdbcDefined, Scalar, SQLCHAR, SQLINTEGER, SQLLEN, SQLPOINTER,
9    SQLSMALLINT, SQLWCHAR,
10};
11use core::mem::MaybeUninit;
12use rs_odbc_derive::{odbc_type, Ident};
13
14pub trait DiagField<H: Handle, D: Ident>: Attr<D> + AttrLen<Self::DefinedBy, SQLSMALLINT> {
15    // TODO: These could be checked by the type system
16    // SQL_DIAG_CURSOR_ROW_COUNT -> The contents of this field are defined only after SQLExecute, SQLExecDirect, or SQLMoreResults
17    // SQL_DIAG_DYNAMIC_FUNCTION -> The contents of this field are defined only after SQLExecute, SQLExecDirect, or SQLMoreResults
18    // SQL_DIAG_DYNAMIC_FUNCTION_CODE -> The contents of this field are defined only after SQLExecute, SQLExecDirect, or SQLMoreResults
19    // SQL_DIAG_ROW_COUNT -> SQLExecute, SQLExecDirect, SQLBulkOperations, or SQLSetPos
20}
21
22pub const SQLSTATE_SIZE: usize = 5;
23
24#[repr(transparent)]
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct SQLSTATE<C: OdbcChar>([C; SQLSTATE_SIZE + 1]);
27impl SQLSTATE<SQLCHAR> {
28    pub fn new(init: &str) -> SQLSTATE<SQLCHAR> {
29        let bytes = init.as_bytes();
30
31        assert_eq!(
32            SQLSTATE_SIZE,
33            bytes.len(),
34            "SQLSTATE({}) len != {}",
35            init,
36            SQLSTATE_SIZE
37        );
38
39        let mut sqlstate = [SQLCHAR::default(); SQLSTATE_SIZE + 1];
40        for (s, i) in sqlstate.iter_mut().zip(bytes.iter()) {
41            *s = *i;
42        }
43
44        Self(sqlstate)
45    }
46}
47impl SQLSTATE<SQLWCHAR> {
48    pub fn new(init: &str) -> SQLSTATE<SQLWCHAR> {
49        let bytes = init.as_bytes();
50
51        assert_eq!(
52            SQLSTATE_SIZE,
53            bytes.len(),
54            "SQLSTATE({}) len != {}",
55            init,
56            SQLSTATE_SIZE
57        );
58
59        let mut sqlstate = [SQLWCHAR::default(); SQLSTATE_SIZE + 1];
60        for (s, i) in sqlstate.iter_mut().zip(bytes.iter()) {
61            *s = *i as u16;
62        }
63
64        Self(sqlstate)
65    }
66}
67unsafe impl<C: OdbcChar> AsMutSQLPOINTER for SQLSTATE<C> {
68    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
69        (self as *mut Self).cast()
70    }
71}
72unsafe impl<C: OdbcChar> AsMutSQLPOINTER for MaybeUninit<SQLSTATE<C>> {
73    fn as_mut_SQLPOINTER(&mut self) -> SQLPOINTER {
74        self.as_mut_ptr().cast()
75    }
76}
77impl PartialEq<&str> for SQLSTATE<SQLCHAR> {
78    fn eq(&self, other: &&str) -> bool {
79        *self == SQLSTATE::<SQLCHAR>::new(other)
80    }
81}
82impl PartialEq<&str> for SQLSTATE<SQLWCHAR> {
83    fn eq(&self, other: &&str) -> bool {
84        *self == SQLSTATE::<SQLWCHAR>::new(other)
85    }
86}
87impl<'a, C: OdbcChar> PartialEq<SQLSTATE<C>> for &'a str
88where
89    SQLSTATE<C>: PartialEq<&'a str>,
90{
91    fn eq(&self, other: &SQLSTATE<C>) -> bool {
92        other == self
93    }
94}
95impl<C: OdbcChar> AttrZeroAssert for SQLSTATE<C> {
96    // This is character field and doesn't have to be zero checked
97}
98unsafe impl<C: OdbcChar> AttrLen<OdbcDefined, SQLSMALLINT> for SQLSTATE<C>
99where
100    MaybeUninit<SQLSTATE<C>>: AttrLen<OdbcDefined, SQLSMALLINT>,
101{
102    type StrLen = Void;
103
104    fn len(&self) -> SQLSMALLINT {
105        // This is ok because MaybeUninit<T> has the same memory layout as T
106        <MaybeUninit<SQLSTATE<C>>>::len(unsafe { core::mem::transmute(self) })
107    }
108}
109unsafe impl<AD: Def> AttrLen<AD, SQLSMALLINT> for MaybeUninit<SQLSTATE<SQLCHAR>> {
110    type StrLen = Void;
111
112    fn len(&self) -> SQLSMALLINT {
113        (SQLSTATE_SIZE + 1) as SQLSMALLINT
114    }
115}
116unsafe impl<AD: Def> AttrLen<AD, SQLSMALLINT> for MaybeUninit<SQLSTATE<SQLWCHAR>> {
117    type StrLen = Void;
118
119    fn len(&self) -> SQLSMALLINT {
120        (core::mem::size_of::<SQLWCHAR>() * (SQLSTATE_SIZE + 1)) as SQLSMALLINT
121    }
122}
123
124// Implement DiagField for uninitialized diagnostic attributes
125impl<D: Ident, T: Scalar, H: Handle> DiagField<H, D> for MaybeUninit<T>
126where
127    T: DiagField<H, D> + AttrGet<D>,
128    Self: AttrLen<Self::DefinedBy, SQLSMALLINT>,
129{
130}
131
132impl<D: Ident, T: Scalar, H: Handle> DiagField<H, D> for [MaybeUninit<T>]
133where
134    [T]: DiagField<H, D> + AttrGet<D>,
135    Self: AttrLen<Self::DefinedBy, SQLSMALLINT>,
136{
137}
138
139impl<D: Ident, H: Handle> DiagField<H, D> for OdbcStr<MaybeUninit<SQLCHAR>> where
140    OdbcStr<SQLCHAR>: DiagField<H, D> + AttrGet<D>
141{
142}
143impl<D: Ident, H: Handle> DiagField<H, D> for OdbcStr<MaybeUninit<SQLWCHAR>> where
144    OdbcStr<SQLWCHAR>: DiagField<H, D> + AttrGet<D>
145{
146}
147
148//=====================================================================================//
149//-------------------------------------Attributes--------------------------------------//
150
151/////////////////////////////////////////////////////////////////////////////////////////
152////////////////////////////////////// Header fields ////////////////////////////////////
153/////////////////////////////////////////////////////////////////////////////////////////
154
155#[derive(Ident)]
156#[identifier(SQLSMALLINT, -1249)]
157#[allow(non_camel_case_types)]
158pub struct SQL_DIAG_CURSOR_ROW_COUNT;
159unsafe impl Attr<SQL_DIAG_CURSOR_ROW_COUNT> for SQLLEN {
160    type DefinedBy = OdbcDefined;
161}
162impl<V: OdbcVersion> DiagField<SQLHSTMT<'_, '_, '_, V>, SQL_DIAG_CURSOR_ROW_COUNT> for SQLLEN {}
163unsafe impl AttrGet<SQL_DIAG_CURSOR_ROW_COUNT> for SQLLEN {}
164
165#[derive(Ident)]
166#[identifier(SQLSMALLINT, 7)]
167#[allow(non_camel_case_types)]
168pub struct SQL_DIAG_DYNAMIC_FUNCTION;
169unsafe impl Attr<SQL_DIAG_DYNAMIC_FUNCTION> for OdbcStr<SQLCHAR> {
170    type DefinedBy = OdbcDefined;
171}
172impl<V: OdbcVersion> DiagField<SQLHSTMT<'_, '_, '_, V>, SQL_DIAG_DYNAMIC_FUNCTION>
173    for OdbcStr<SQLCHAR>
174{
175}
176unsafe impl AttrGet<SQL_DIAG_DYNAMIC_FUNCTION> for OdbcStr<SQLCHAR> {}
177
178#[derive(Ident)]
179#[identifier(SQLSMALLINT, 12)]
180#[allow(non_camel_case_types)]
181pub struct SQL_DIAG_DYNAMIC_FUNCTION_CODE;
182unsafe impl Attr<SQL_DIAG_DYNAMIC_FUNCTION_CODE> for DiagDynamicFunctionCode {
183    type DefinedBy = OdbcDefined;
184}
185impl<V: OdbcVersion> DiagField<SQLHSTMT<'_, '_, '_, V>, SQL_DIAG_DYNAMIC_FUNCTION_CODE>
186    for DiagDynamicFunctionCode
187{
188}
189unsafe impl AttrGet<SQL_DIAG_DYNAMIC_FUNCTION_CODE> for DiagDynamicFunctionCode {}
190
191#[derive(Ident)]
192#[identifier(SQLSMALLINT, 2)]
193#[allow(non_camel_case_types)]
194pub struct SQL_DIAG_NUMBER;
195unsafe impl Attr<SQL_DIAG_NUMBER> for SQLINTEGER {
196    type DefinedBy = OdbcDefined;
197}
198impl<H: Handle> DiagField<H, SQL_DIAG_NUMBER> for SQLINTEGER {}
199unsafe impl AttrGet<SQL_DIAG_NUMBER> for SQLINTEGER {}
200
201#[derive(Ident)]
202#[identifier(SQLSMALLINT, 1)]
203#[allow(non_camel_case_types)]
204pub struct SQL_DIAG_RETURNCODE;
205unsafe impl Attr<SQL_DIAG_RETURNCODE> for SQLRETURN {
206    type DefinedBy = OdbcDefined;
207}
208impl<H: Handle> DiagField<H, SQL_DIAG_RETURNCODE> for SQLRETURN {}
209unsafe impl AttrGet<SQL_DIAG_RETURNCODE> for SQLRETURN {}
210
211#[derive(Ident)]
212#[identifier(SQLSMALLINT, 3)]
213#[allow(non_camel_case_types)]
214pub struct SQL_DIAG_ROW_COUNT;
215unsafe impl Attr<SQL_DIAG_ROW_COUNT> for SQLLEN {
216    type DefinedBy = OdbcDefined;
217}
218impl<V: OdbcVersion> DiagField<SQLHSTMT<'_, '_, '_, V>, SQL_DIAG_ROW_COUNT> for SQLLEN {}
219unsafe impl AttrGet<SQL_DIAG_ROW_COUNT> for SQLLEN {}
220
221/////////////////////////////////////////////////////////////////////////////////////////
222////////////////////////////////////// Record fields ////////////////////////////////////
223/////////////////////////////////////////////////////////////////////////////////////////
224
225#[derive(Ident)]
226#[identifier(SQLSMALLINT, 8)]
227#[allow(non_camel_case_types)]
228pub struct SQL_DIAG_CLASS_ORIGIN;
229unsafe impl Attr<SQL_DIAG_CLASS_ORIGIN> for OdbcStr<SQLCHAR> {
230    type DefinedBy = OdbcDefined;
231}
232impl<H: Handle> DiagField<H, SQL_DIAG_CLASS_ORIGIN> for OdbcStr<SQLCHAR> {}
233unsafe impl AttrGet<SQL_DIAG_CLASS_ORIGIN> for OdbcStr<SQLCHAR> {}
234
235#[derive(Ident)]
236#[identifier(SQLSMALLINT, -1247)]
237#[allow(non_camel_case_types)]
238pub struct SQL_DIAG_COLUMN_NUMBER;
239unsafe impl Attr<SQL_DIAG_COLUMN_NUMBER> for DiagColumnNumber {
240    type DefinedBy = OdbcDefined;
241}
242impl<V: OdbcVersion> DiagField<SQLHSTMT<'_, '_, '_, V>, SQL_DIAG_COLUMN_NUMBER>
243    for DiagColumnNumber
244{
245}
246unsafe impl AttrGet<SQL_DIAG_COLUMN_NUMBER> for DiagColumnNumber {}
247
248#[derive(Ident)]
249#[identifier(SQLSMALLINT, 10)]
250#[allow(non_camel_case_types)]
251pub struct SQL_DIAG_CONNECTION_NAME;
252unsafe impl Attr<SQL_DIAG_CONNECTION_NAME> for OdbcStr<SQLCHAR> {
253    type DefinedBy = OdbcDefined;
254}
255impl<H: Handle> DiagField<H, SQL_DIAG_CONNECTION_NAME> for OdbcStr<SQLCHAR> {}
256unsafe impl AttrGet<SQL_DIAG_CONNECTION_NAME> for OdbcStr<SQLCHAR> {}
257
258#[derive(Ident)]
259#[identifier(SQLSMALLINT, 6)]
260#[allow(non_camel_case_types)]
261pub struct SQL_DIAG_MESSAGE_TEXT;
262unsafe impl Attr<SQL_DIAG_MESSAGE_TEXT> for OdbcStr<SQLCHAR> {
263    type DefinedBy = OdbcDefined;
264}
265impl<H: Handle> DiagField<H, SQL_DIAG_MESSAGE_TEXT> for OdbcStr<SQLCHAR> {}
266unsafe impl AttrGet<SQL_DIAG_MESSAGE_TEXT> for OdbcStr<SQLCHAR> {}
267
268#[derive(Ident)]
269#[identifier(SQLSMALLINT, 5)]
270#[allow(non_camel_case_types)]
271pub struct SQL_DIAG_NATIVE;
272unsafe impl Attr<SQL_DIAG_NATIVE> for SQLINTEGER {
273    type DefinedBy = OdbcDefined;
274}
275impl<H: Handle> DiagField<H, SQL_DIAG_NATIVE> for SQLINTEGER {}
276unsafe impl AttrGet<SQL_DIAG_NATIVE> for SQLINTEGER {}
277
278#[derive(Ident)]
279#[identifier(SQLSMALLINT, -1248)]
280#[allow(non_camel_case_types)]
281pub struct SQL_DIAG_ROW_NUMBER;
282unsafe impl Attr<SQL_DIAG_ROW_NUMBER> for DiagRowNumber {
283    type DefinedBy = OdbcDefined;
284}
285impl<V: OdbcVersion> DiagField<SQLHSTMT<'_, '_, '_, V>, SQL_DIAG_ROW_NUMBER> for DiagRowNumber {}
286unsafe impl AttrGet<SQL_DIAG_ROW_NUMBER> for DiagRowNumber {}
287
288#[derive(Ident)]
289#[identifier(SQLSMALLINT, 11)]
290#[allow(non_camel_case_types)]
291pub struct SQL_DIAG_SERVER_NAME;
292unsafe impl Attr<SQL_DIAG_SERVER_NAME> for OdbcStr<SQLCHAR> {
293    type DefinedBy = OdbcDefined;
294}
295impl<H: Handle> DiagField<H, SQL_DIAG_SERVER_NAME> for OdbcStr<SQLCHAR> {}
296unsafe impl AttrGet<SQL_DIAG_SERVER_NAME> for OdbcStr<SQLCHAR> {}
297
298#[derive(Ident)]
299#[identifier(SQLSMALLINT, 4)]
300#[allow(non_camel_case_types)]
301pub struct SQL_DIAG_SQLSTATE;
302unsafe impl<C: OdbcChar> Attr<SQL_DIAG_SQLSTATE> for SQLSTATE<C> {
303    type DefinedBy = OdbcDefined;
304}
305impl<H: Handle> DiagField<H, SQL_DIAG_SQLSTATE> for SQLSTATE<SQLCHAR> {}
306impl<H: Handle> DiagField<H, SQL_DIAG_SQLSTATE> for SQLSTATE<SQLWCHAR> {}
307unsafe impl<C: OdbcChar> AttrGet<SQL_DIAG_SQLSTATE> for SQLSTATE<C> {}
308
309#[derive(Ident)]
310#[identifier(SQLSMALLINT, 9)]
311#[allow(non_camel_case_types)]
312pub struct SQL_DIAG_SUBCLASS_ORIGIN;
313unsafe impl Attr<SQL_DIAG_SUBCLASS_ORIGIN> for OdbcStr<SQLCHAR> {
314    type DefinedBy = OdbcDefined;
315}
316impl<H: Handle> DiagField<H, SQL_DIAG_SUBCLASS_ORIGIN> for OdbcStr<SQLCHAR> {}
317unsafe impl AttrGet<SQL_DIAG_SUBCLASS_ORIGIN> for OdbcStr<SQLCHAR> {}
318
319//=====================================================================================//
320
321#[odbc_type(SQLINTEGER)]
322pub struct DiagDynamicFunctionCode;
323pub const SQL_DIAG_ALTER_DOMAIN: DiagDynamicFunctionCode = DiagDynamicFunctionCode(3);
324pub const SQL_DIAG_ALTER_TABLE: DiagDynamicFunctionCode = DiagDynamicFunctionCode(4);
325pub const SQL_DIAG_CREATE_ASSERTION: DiagDynamicFunctionCode = DiagDynamicFunctionCode(6);
326pub const SQL_DIAG_CREATE_CHARACTER_SET: DiagDynamicFunctionCode = DiagDynamicFunctionCode(8);
327pub const SQL_DIAG_CREATE_COLLATION: DiagDynamicFunctionCode = DiagDynamicFunctionCode(10);
328pub const SQL_DIAG_CREATE_DOMAIN: DiagDynamicFunctionCode = DiagDynamicFunctionCode(23);
329pub const SQL_DIAG_CREATE_INDEX: DiagDynamicFunctionCode = DiagDynamicFunctionCode(-1);
330pub const SQL_DIAG_CREATE_TABLE: DiagDynamicFunctionCode = DiagDynamicFunctionCode(77);
331pub const SQL_DIAG_CREATE_VIEW: DiagDynamicFunctionCode = DiagDynamicFunctionCode(84);
332pub const SQL_DIAG_SELECT_CURSOR: DiagDynamicFunctionCode = DiagDynamicFunctionCode(85);
333pub const SQL_DIAG_DYNAMIC_DELETE_CURSOR: DiagDynamicFunctionCode = DiagDynamicFunctionCode(38);
334pub const SQL_DIAG_DELETE_WHERE: DiagDynamicFunctionCode = DiagDynamicFunctionCode(19);
335pub const SQL_DIAG_DROP_ASSERTION: DiagDynamicFunctionCode = DiagDynamicFunctionCode(24);
336pub const SQL_DIAG_DROP_CHARACTER_SET: DiagDynamicFunctionCode = DiagDynamicFunctionCode(25);
337pub const SQL_DIAG_DROP_COLLATION: DiagDynamicFunctionCode = DiagDynamicFunctionCode(26);
338pub const SQL_DIAG_DROP_DOMAIN: DiagDynamicFunctionCode = DiagDynamicFunctionCode(27);
339pub const SQL_DIAG_DROP_INDEX: DiagDynamicFunctionCode = DiagDynamicFunctionCode(-2);
340pub const SQL_DIAG_DROP_SCHEMA: DiagDynamicFunctionCode = DiagDynamicFunctionCode(31);
341pub const SQL_DIAG_DROP_TABLE: DiagDynamicFunctionCode = DiagDynamicFunctionCode(32);
342pub const SQL_DIAG_DROP_TRANSLATION: DiagDynamicFunctionCode = DiagDynamicFunctionCode(33);
343pub const SQL_DIAG_DROP_VIEW: DiagDynamicFunctionCode = DiagDynamicFunctionCode(36);
344pub const SQL_DIAG_GRANT: DiagDynamicFunctionCode = DiagDynamicFunctionCode(48);
345pub const SQL_DIAG_INSERT: DiagDynamicFunctionCode = DiagDynamicFunctionCode(50);
346pub const SQL_DIAG_CALL: DiagDynamicFunctionCode = DiagDynamicFunctionCode(7);
347pub const SQL_DIAG_REVOKE: DiagDynamicFunctionCode = DiagDynamicFunctionCode(59);
348pub const SQL_DIAG_CREATE_SCHEMA: DiagDynamicFunctionCode = DiagDynamicFunctionCode(64);
349pub const SQL_DIAG_CREATE_TRANSLATION: DiagDynamicFunctionCode = DiagDynamicFunctionCode(79);
350pub const SQL_DIAG_DYNAMIC_UPDATE_CURSOR: DiagDynamicFunctionCode = DiagDynamicFunctionCode(81);
351pub const SQL_DIAG_UPDATE_WHERE: DiagDynamicFunctionCode = DiagDynamicFunctionCode(82);
352pub const SQL_DIAG_UNKNOWN_STATEMENT: DiagDynamicFunctionCode = DiagDynamicFunctionCode(0);
353
354#[odbc_type(SQLINTEGER)]
355pub struct DiagColumnNumber;
356pub const SQL_NO_COLUMN_NUMBER: DiagColumnNumber = DiagColumnNumber(-1);
357pub const SQL_COLUMN_NUMBER_UNKNOWN: DiagColumnNumber = DiagColumnNumber(-2);
358
359#[odbc_type(SQLLEN)]
360pub struct DiagRowNumber;
361pub const SQL_NO_ROW_NUMBER: DiagRowNumber = DiagRowNumber(-1);
362pub const SQL_ROW_NUMBER_UNKNOWN: DiagRowNumber = DiagRowNumber(-2);
363
364//=====================================================================================//
365//----------------------------------------Tests----------------------------------------//
366
367#[cfg(test)]
368mod test {
369    #![allow(non_snake_case)]
370
371    use super::*;
372
373    #[test]
374    fn new_sqlstate_SQLCHAR() {
375        let sqlstate = SQLSTATE::<SQLCHAR>::new("12345");
376
377        assert_eq!(6, sqlstate.len());
378        assert_eq!([49, 50, 51, 52, 53, 0].as_ref(), sqlstate.0);
379    }
380
381    #[test]
382    fn new_sqlstate_SQLWCHAR() {
383        let sqlstate = SQLSTATE::<SQLWCHAR>::new("12345");
384
385        assert_eq!(12, sqlstate.len());
386        assert_eq!([49, 50, 51, 52, 53, 0].as_ref(), sqlstate.0);
387    }
388
389    #[test]
390    #[should_panic]
391    fn new_sqlstate_SQLCHAR_size_4() {
392        SQLSTATE::<SQLCHAR>::new("0000");
393    }
394
395    #[test]
396    #[should_panic]
397    fn new_sqlstate_SQLWCHAR_size_4() {
398        SQLSTATE::<SQLWCHAR>::new("0000");
399    }
400
401    #[test]
402    fn sqlstate_SQLCHAR_cmp() {
403        let sqlstate = SQLSTATE::<SQLCHAR>::new("12345");
404
405        assert_eq!("12345", sqlstate);
406        assert_eq!(sqlstate, "12345");
407    }
408
409    #[test]
410    fn sqlstate_SQLWCHAR_cmp() {
411        let sqlstate = SQLSTATE::<SQLWCHAR>::new("12345");
412
413        assert_eq!("12345", sqlstate);
414        assert_eq!(sqlstate, "12345");
415    }
416}