rs-odbc 0.2.0

Minimal safe Rust implementation of ODBC
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
use crate::c_types::{CScalar, StrLenOrInd};
use crate::convert::{AsMutPtr, AsMutSQLPOINTER, IntoSQLPOINTER};
use crate::desc::AppDesc;
use crate::env::OdbcVersion;
use crate::handle::{RefSQLHDESC, RefUnsafeSQLHDESC, UnsafeSQLHDESC, SQLHDESC};
use crate::str::{OdbcChar, OdbcStr};
use crate::{
    slice_len, Def, DriverDefined, Ident, OdbcDefined, Scalar, SQLCHAR, SQLINTEGER, SQLLEN,
    SQLSMALLINT, SQLUINTEGER, SQLULEN, SQLUSMALLINT, SQLWCHAR,
};
use core::{cell::UnsafeCell, fmt::Debug, mem::MaybeUninit};

pub unsafe trait Attr<A: Ident> {
    type DefinedBy: Def;
}
pub unsafe trait AttrGet<A: Ident>: Attr<A> + AsMutSQLPOINTER + AttrZeroAssert {}
pub unsafe trait AttrSet<A: Ident>: IntoSQLPOINTER + Sized {}

// TODO: https://github.com/rust-lang/rust/issues/35121
// Use never type ! when it is available on stable
#[derive(Debug, Clone, Copy)]
pub enum Void {}

/// Same as [`AsMutPtr`] except that it's intended to be used to designate [`AttrLen::StrLen`] types.
pub unsafe trait StrLen<T: Scalar> {
    fn as_mut_ptr(&mut self) -> *mut T;
}

// TODO: https://github.com/rust-lang/rust/issues/20400
// Once this problem is resolved, it would be possible to modify AttrLen<AD, LEN>
// into AttrLen<A, LEN> and do more precise blanket implementations like
// impl<T: Attr<A>, LEN> AttrLen<A, LEN> for T {}
pub unsafe trait AttrLen<AD: Def, LEN: Scalar> {
    /// Invariant: StrLen can only be LEN(for slices) or uninhabited type(for scalar types)
    /// It is assumed that ODBC driver will never write to StrLen pointer for scalar types
    type StrLen: StrLen<LEN>;

    fn len(&self) -> LEN;
}

pub trait AttrZeroAssert {
    fn assert_zeroed(&self) {}
}

// TODO: Implement and use for binary strings AttrLen
//pub const fn SQL_LEN_BINARY_ATTR<LEN: OdbcInt>(length: LEN) {
//    let SQL_LEN_BINARY_ATTR_OFFSET: LEN::new(-100);
//    (-length).checked_add(SQL_LEN_BINARY_ATTR_OFFSET).expect()
//}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

unsafe impl<A: Ident, T: Scalar> Attr<A> for MaybeUninit<T>
where
    T: Attr<A> + AttrGet<A>,
{
    type DefinedBy = T::DefinedBy;
}
unsafe impl<A: Ident, T> Attr<A> for [MaybeUninit<T>]
where
    [T]: Attr<A> + AttrGet<A>,
{
    type DefinedBy = <[T] as Attr<A>>::DefinedBy;
}
unsafe impl<A: Ident> Attr<A> for OdbcStr<MaybeUninit<SQLCHAR>>
where
    OdbcStr<SQLCHAR>: Attr<A> + AttrGet<A>,
{
    type DefinedBy = <OdbcStr<SQLCHAR> as Attr<A>>::DefinedBy;
}
unsafe impl<A: Ident> Attr<A> for OdbcStr<MaybeUninit<SQLWCHAR>>
where
    OdbcStr<SQLWCHAR>: Attr<A> + AttrGet<A>,
{
    type DefinedBy = <OdbcStr<SQLWCHAR> as Attr<A>>::DefinedBy;
}
unsafe impl<A: Ident, T> Attr<A> for &[T]
where
    [T]: Attr<A>,
{
    type DefinedBy = <[T] as Attr<A>>::DefinedBy;
}
unsafe impl<A: Ident, CH: OdbcChar> Attr<A> for &OdbcStr<CH>
where
    OdbcStr<CH>: Attr<A>,
{
    type DefinedBy = <OdbcStr<CH> as Attr<A>>::DefinedBy;
}

unsafe impl<A: Ident, T: Scalar> AttrGet<A> for MaybeUninit<T>
where
    T: AttrGet<A>,
    Self: AsMutSQLPOINTER,
{
}
unsafe impl<A: Ident> AttrGet<A> for OdbcStr<MaybeUninit<SQLCHAR>> where OdbcStr<SQLCHAR>: AttrGet<A>
{}
unsafe impl<A: Ident> AttrGet<A> for OdbcStr<MaybeUninit<SQLWCHAR>> where
    OdbcStr<SQLWCHAR>: AttrGet<A>
{
}

unsafe impl<A: Ident, T: Scalar> AttrSet<A> for MaybeUninit<T>
where
    Self: IntoSQLPOINTER,
    T: AttrSet<A>,
{
}

unsafe impl<AD: Def, T: Ident, LEN: Scalar> AttrLen<AD, LEN> for T
where
    MaybeUninit<T>: AttrLen<AD, LEN>,
    LEN: From<SQLSMALLINT>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        // Transmute is safe because MaybeUninit<T> has the same size and alignment as T
        <MaybeUninit<_> as AttrLen<AD, LEN>>::len(unsafe { core::mem::transmute(self) })
    }
}
unsafe impl<T: Ident, LEN: Scalar> AttrLen<OdbcDefined, LEN> for MaybeUninit<T>
where
    LEN: From<SQLSMALLINT>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        LEN::from(0)
    }
}
unsafe impl<T: Ident, LEN: Scalar> AttrLen<DriverDefined, LEN> for MaybeUninit<T>
where
    LEN: From<T::Type>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        LEN::from(T::IDENTIFIER)
    }
}
unsafe impl<AD: Def, CH: OdbcChar, LEN: Scalar> AttrLen<AD, LEN> for OdbcStr<CH>
where
    LEN: TryFrom<usize>,
    LEN::Error: Debug,
    OdbcStr<MaybeUninit<CH>>: AttrLen<AD, LEN>,
{
    type StrLen = <OdbcStr<MaybeUninit<CH>> as AttrLen<AD, LEN>>::StrLen;

    fn len(&self) -> LEN {
        // Transmute is safe because MaybeUninit<T> has the same size and alignment as T
        <OdbcStr<MaybeUninit<CH>> as AttrLen<AD, LEN>>::len(unsafe { core::mem::transmute(self) })
    }
}
unsafe impl<AD: Def, CH: OdbcChar, LEN: Scalar> AttrLen<AD, LEN> for OdbcStr<MaybeUninit<CH>>
where
    LEN: TryFrom<usize> + core::ops::Mul<Output = LEN>,
    LEN::Error: Debug,
{
    type StrLen = LEN;

    fn len(&self) -> LEN {
        // TODO: Check for multiplication overflow with checked_mul
        slice_len::<_, LEN>(self) * LEN::try_from(core::mem::size_of::<CH>()).unwrap()
    }
}
// TODO: If this is a deferred buffer, then I believe len should be 0
// This can be resolved with specialization by having special implementation for SQL_DESC_DATA_PTR
// and alike if there are other attributes that correspond to deferred buffers
unsafe impl<LEN: Scalar> AttrLen<OdbcDefined, LEN> for [MaybeUninit<SQLCHAR>]
where
    LEN: TryFrom<usize>,
    LEN::Error: Debug,
{
    type StrLen = LEN;

    fn len(&self) -> LEN {
        slice_len(self)
    }
}
// TODO: What if this is a deferred buffer, then I believe len should be 0
// This can be resolved with specialization by having special implementation for SQL_DESC_DATA_PTR
// and alike if there are other attributes that correspond to deferred buffers
unsafe impl<LEN: Scalar> AttrLen<DriverDefined, LEN> for [MaybeUninit<SQLCHAR>] {
    type StrLen = LEN;

    fn len(&self) -> LEN {
        // TODO: Should be a negative value
        unimplemented!();
    }
}
unsafe impl<AD: Def, LEN: Scalar> AttrLen<AD, LEN> for [SQLCHAR]
where
    [MaybeUninit<SQLCHAR>]: AttrLen<AD, LEN>,
{
    type StrLen = <[MaybeUninit<SQLCHAR>] as AttrLen<AD, LEN>>::StrLen;

    fn len(&self) -> LEN {
        // Transmute is safe because MaybeUninit<T> has the same size and alignment as T
        <[MaybeUninit<SQLCHAR>] as AttrLen<AD, LEN>>::len(unsafe { core::mem::transmute(self) })
    }
}
unsafe impl<AD: Def, T: Ident, LEN: Scalar> AttrLen<AD, LEN> for [T]
where
    LEN: From<SQLSMALLINT>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        LEN::from(0)
    }
}
unsafe impl<AD: Def, LEN: Scalar, CH: OdbcChar> AttrLen<AD, LEN> for &OdbcStr<CH>
where
    OdbcStr<CH>: AttrLen<AD, LEN>,
{
    type StrLen = <OdbcStr<CH> as AttrLen<AD, LEN>>::StrLen;

    fn len(&self) -> LEN {
        AttrLen::len(*self)
    }
}
unsafe impl<AD: Def, LEN: Scalar, T> AttrLen<AD, LEN> for &[T]
where
    [T]: AttrLen<AD, LEN>,
{
    type StrLen = <[T] as AttrLen<AD, LEN>>::StrLen;

    fn len(&self) -> LEN {
        AttrLen::len(*self)
    }
}
// Deferred buffers are used only through SQLSetDescAttr and SQLGetDescAttr
unsafe impl<AD: Def, T: CScalar> AttrLen<AD, SQLINTEGER> for UnsafeCell<T> {
    type StrLen = Void;

    fn len(&self) -> SQLINTEGER {
        0
    }
}
// Deferred buffers are used only through SQLSetDescAttr and SQLGetDescAttr
unsafe impl<AD: Def, T> AttrLen<AD, SQLINTEGER> for [UnsafeCell<T>] {
    type StrLen = Void;

    fn len(&self) -> SQLINTEGER {
        0 // Length is not used for deferred buffers
    }
}
unsafe impl<DT, LEN: Scalar, V: OdbcVersion> AttrLen<OdbcDefined, LEN>
    for MaybeUninit<RefUnsafeSQLHDESC<'_, DT, V>>
where
    LEN: From<SQLSMALLINT>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        LEN::from(0)
    }
}
unsafe impl<DT, LEN: Scalar, V: OdbcVersion> AttrLen<DriverDefined, LEN>
    for MaybeUninit<RefUnsafeSQLHDESC<'_, DT, V>>
where
    LEN: From<SQLSMALLINT>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        LEN::from(crate::SQL_IS_POINTER)
    }
}
unsafe impl<'conn, AD: Def, DT, LEN: Scalar, V: OdbcVersion> AttrLen<AD, LEN>
    for MaybeUninit<RefSQLHDESC<'conn, DT, V>>
where
    MaybeUninit<RefUnsafeSQLHDESC<'conn, DT, V>>: AttrLen<AD, LEN>,
    LEN: From<SQLSMALLINT>,
{
    type StrLen = <MaybeUninit<RefUnsafeSQLHDESC<'conn, DT, V>> as AttrLen<AD, LEN>>::StrLen;

    fn len(&self) -> LEN {
        // Transmute is safe because RefSQLHDESC is a transparent wrapper over RefUnsafeSQLHDESC
        unsafe { core::mem::transmute::<_, &MaybeUninit<RefUnsafeSQLHDESC<'conn, DT, V>>>(self) }
            .len()
    }
}
unsafe impl<LEN: Scalar, V: OdbcVersion> AttrLen<OdbcDefined, LEN>
    for Option<&UnsafeSQLHDESC<'_, AppDesc<'_>, V>>
where
    LEN: From<SQLSMALLINT>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        LEN::from(0)
    }
}
unsafe impl<LEN: Scalar, V: OdbcVersion> AttrLen<DriverDefined, LEN>
    for Option<&UnsafeSQLHDESC<'_, AppDesc<'_>, V>>
where
    LEN: From<SQLSMALLINT>,
{
    type StrLen = Void;

    fn len(&self) -> LEN {
        LEN::from(crate::SQL_IS_POINTER)
    }
}
unsafe impl<'a, 'conn, 'buf, AD: Def, LEN: Scalar, V: OdbcVersion> AttrLen<AD, LEN>
    for Option<&'a SQLHDESC<'conn, AppDesc<'buf>, V>>
where
    Option<&'a UnsafeSQLHDESC<'conn, AppDesc<'buf>, V>>: AttrLen<AD, LEN>,
    LEN: From<SQLSMALLINT>,
{
    type StrLen = <Option<&'a UnsafeSQLHDESC<'conn, AppDesc<'buf>, V>> as AttrLen<AD, LEN>>::StrLen;

    fn len(&self) -> LEN {
        // Transmute is safe because SQLHDESC is a transparent wrapper over UnsafeSQLHDESC
        unsafe { core::mem::transmute::<_, Option<&UnsafeSQLHDESC<'conn, AppDesc<'buf>, V>>>(self) }
            .len()
    }
}

unsafe impl<T: Scalar> StrLen<T> for T
where
    T: AsMutPtr<T>,
{
    fn as_mut_ptr(&mut self) -> *mut T {
        <Self as AsMutPtr<T>>::as_mut_ptr(self)
    }
}
unsafe impl<T: Scalar> StrLen<T> for MaybeUninit<T>
where
    Self: AsMutPtr<T>,
    T: StrLen<T>,
{
    fn as_mut_ptr(&mut self) -> *mut T {
        <Self as AsMutPtr<T>>::as_mut_ptr(self)
    }
}

impl<T> AttrZeroAssert for MaybeUninit<T> {
    // MaybeUninit must not be read
}
impl<T> AttrZeroAssert for [T] {}
impl<T> AttrZeroAssert for OdbcStr<T> {}
impl<T: CScalar> AttrZeroAssert for UnsafeCell<T> {
    // Deferred buffers don't need to be zeroed
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

// TODO: Why are these needed?
unsafe impl StrLen<SQLLEN> for MaybeUninit<StrLenOrInd> {
    fn as_mut_ptr(&mut self) -> *mut SQLLEN {
        self.as_mut_ptr().cast()
    }
}
unsafe impl StrLen<SQLLEN> for UnsafeCell<StrLenOrInd> {
    fn as_mut_ptr(&mut self) -> *mut SQLLEN {
        self.get().cast()
    }
}
unsafe impl<T: Scalar> StrLen<T> for Void {
    fn as_mut_ptr(&mut self) -> *mut T {
        // Uninhabited type has no memory location
        core::ptr::null_mut()
    }
}
unsafe impl<T: Scalar> StrLen<T> for MaybeUninit<Void> {
    fn as_mut_ptr(&mut self) -> *mut T {
        // Uninhabited type has no memory location
        core::ptr::null_mut()
    }
}

impl AttrZeroAssert for SQLSMALLINT {
    fn assert_zeroed(&self) {
        // TODO: Add custom message
        assert_eq!(0, *self);
    }
}
impl AttrZeroAssert for SQLUSMALLINT {
    fn assert_zeroed(&self) {
        // TODO: Add custom message
        assert_eq!(0, *self);
    }
}
impl AttrZeroAssert for SQLINTEGER {
    fn assert_zeroed(&self) {
        // TODO: Add custom message
        assert_eq!(0, *self);
    }
}
impl AttrZeroAssert for SQLUINTEGER {
    fn assert_zeroed(&self) {
        // TODO: Add custom message
        assert_eq!(0, *self);
    }
}
impl AttrZeroAssert for SQLLEN {
    fn assert_zeroed(&self) {
        // TODO: Add custom message
        assert_eq!(0, *self);
    }
}
impl AttrZeroAssert for SQLULEN {
    fn assert_zeroed(&self) {
        // TODO: Add custom message
        assert_eq!(0, *self);
    }
}