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
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
use crate::convert::AsSQLPOINTER;
use crate::env::{OdbcVersion, SQL_OV_ODBC3_80, SQL_OV_ODBC4};
use crate::handle::{RefSQLHDESC, RefUnsafeSQLHDESC};
use crate::sql_types::*;
use crate::str::{OdbcChar, OdbcStr};
use crate::Ident;
use crate::SQLPOINTER;
use crate::{
    SQLBIGINT, SQLCHAR, SQLDOUBLE, SQLINTEGER, SQLLEN, SQLREAL, SQLSCHAR, SQLSMALLINT, SQLUBIGINT,
    SQLUINTEGER, SQLUSMALLINT, SQLWCHAR,
};
use core::{cell::UnsafeCell, mem::MaybeUninit};

pub trait CData<TT: Ident, V: OdbcVersion>: CDataLen {}

/// Care must be taken because references to DeferredBuf might be written to
// TODO: Do I need to disambiguate between BindCol and BindParameters deferred buffers
// TODO: add bound D: Descriptor
pub unsafe trait DeferredBuf<D, TT: Ident, V: OdbcVersion>: CDataLen + AsSQLPOINTER {}

impl<TT: Ident, T: CScalar, V: OdbcVersion> CData<TT, V> for MaybeUninit<T> where T: CData<TT, V> {}

impl<TT: Ident, T, V: OdbcVersion> CData<TT, V> for [MaybeUninit<T>] where [T]: CData<TT, V> {}

impl<TT: Ident, T: OdbcChar, V: OdbcVersion> CData<TT, V> for OdbcStr<MaybeUninit<T>> where
    OdbcStr<T>: CData<TT, V>
{
}

unsafe impl<DT, TT: Ident, T: CScalar, V: OdbcVersion> DeferredBuf<RefSQLHDESC<'_, DT, V>, TT, V>
    for UnsafeCell<T>
where
    T: CData<TT, V>,
{
}
unsafe impl<DT, TT: Ident, CH: OdbcChar, V: OdbcVersion> DeferredBuf<RefSQLHDESC<'_, DT, V>, TT, V>
    for OdbcStr<UnsafeCell<CH>>
where
    OdbcStr<CH>: CData<TT, V>,
{
}

unsafe impl<'conn, DT, TT: Ident, T: CScalar, V: OdbcVersion>
    DeferredBuf<RefUnsafeSQLHDESC<'conn, DT, V>, TT, V> for UnsafeCell<T>
where
    T: DeferredBuf<RefSQLHDESC<'conn, DT, V>, TT, V>,
{
}
unsafe impl<'conn, DT, TT: Ident, T: CScalar, V: OdbcVersion>
    DeferredBuf<RefUnsafeSQLHDESC<'conn, DT, V>, TT, V> for [UnsafeCell<T>]
where
    [T]: DeferredBuf<RefSQLHDESC<'conn, DT, V>, TT, V>,
{
}
unsafe impl<'conn, DT, TT: Ident, CH: OdbcChar, V: OdbcVersion>
    DeferredBuf<RefUnsafeSQLHDESC<'conn, DT, V>, TT, V> for OdbcStr<UnsafeCell<CH>>
where
    OdbcStr<CH>: DeferredBuf<RefSQLHDESC<'conn, DT, V>, TT, V>,
{
}
unsafe impl<DT, TT: Ident, V: OdbcVersion> DeferredBuf<RefUnsafeSQLHDESC<'_, DT, V>, TT, V>
    for (SQLPOINTER, SQLLEN)
{
}

#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct StrLenOrInd(pub(crate) SQLLEN);
impl StrLenOrInd {
    pub unsafe fn set_len(&mut self, len: SQLLEN) {
        if len < 0 {
            panic!("len must be non-negative: {}", len);
        }

        self.0 = len;
    }
}
pub const SQL_NULL_DATA: StrLenOrInd = StrLenOrInd(-1);
// Output constants
pub const SQL_NO_TOTAL: StrLenOrInd = StrLenOrInd(-4);
// Input constants
pub const SQL_NTS: StrLenOrInd = StrLenOrInd(-3);
pub const SQL_DATA_AT_EXEC: StrLenOrInd = StrLenOrInd(-2);
pub const SQL_COLUMN_IGNORE: StrLenOrInd = StrLenOrInd(-6);

// TODO: Do something
// pub fn SQL_LEN_DATA_AT_EXEC(length: LEN) -> LEN {
//    const SQL_LEN_DATA_AT_EXEC_OFFSET: LEN = -100;
//    (-length).checked_add(SQL_LEN_DATA_AT_EXEC_OFFSET).expect()
//}

// SQLBindParameter only
pub const SQL_DEFAULT_PARAM: StrLenOrInd = StrLenOrInd(-5);

const SQL_UNSIGNED_OFFSET: SQLSMALLINT = -22;
const SQL_SIGNED_OFFSET: SQLSMALLINT = -20;
const SQL_C_SHORT: SQLSMALLINT = SqlTypeV3::identifier(&SQL_SMALLINT);
const SQL_C_LONG: SQLSMALLINT = SqlTypeV3::identifier(&SQL_INTEGER);
const SQL_C_TINYINT: SQLSMALLINT = SqlTypeV3::identifier(&SQL_TINYINT);

// TODO: This value is discouraged from being used
//#[derive(Ident)]
//#[identifier(SQLSMALLINT, 99)]
//#[allow(non_camel_case_types)]
//struct SQL_C_DEFAULT;

#[allow(non_camel_case_types)]
pub struct SQL_C_CHAR;
impl Ident for SQL_C_CHAR {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_CHAR);
}
impl<V: OdbcVersion> CData<SQL_C_CHAR, V> for OdbcStr<SQLCHAR> {}

#[allow(non_camel_case_types)]
pub struct SQL_C_WCHAR;
impl Ident for SQL_C_WCHAR {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_WCHAR);
}
impl<V: OdbcVersion> CData<SQL_C_WCHAR, V> for OdbcStr<SQLWCHAR> {}

#[allow(non_camel_case_types)]
pub struct SQL_C_SSHORT;
impl Ident for SQL_C_SSHORT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SQL_C_SHORT + SQL_SIGNED_OFFSET;
}
impl<V: OdbcVersion> CData<SQL_C_SSHORT, V> for SQLSMALLINT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_USHORT;
impl Ident for SQL_C_USHORT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SQL_C_SHORT + SQL_UNSIGNED_OFFSET;
}
impl<V: OdbcVersion> CData<SQL_C_USHORT, V> for SQLUSMALLINT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_SLONG;
impl Ident for SQL_C_SLONG {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SQL_C_LONG + SQL_SIGNED_OFFSET;
}
impl<V: OdbcVersion> CData<SQL_C_SLONG, V> for SQLINTEGER {}

#[allow(non_camel_case_types)]
pub struct SQL_C_ULONG;
impl Ident for SQL_C_ULONG {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SQL_C_LONG + SQL_UNSIGNED_OFFSET;
}
impl<V: OdbcVersion> CData<SQL_C_ULONG, V> for SQLUINTEGER {}

#[allow(non_camel_case_types)]
pub struct SQL_C_FLOAT;
impl Ident for SQL_C_FLOAT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_REAL);
}
impl<V: OdbcVersion> CData<SQL_C_FLOAT, V> for SQLREAL {}

#[allow(non_camel_case_types)]
pub struct SQL_C_DOUBLE;
impl Ident for SQL_C_DOUBLE {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_DOUBLE);
}
impl<V: OdbcVersion> CData<SQL_C_DOUBLE, V> for SQLDOUBLE {}

#[allow(non_camel_case_types)]
pub struct SQL_C_BIT;
impl Ident for SQL_C_BIT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_BIT);
}
impl<V: OdbcVersion> CData<SQL_C_BIT, V> for SQLCHAR {}

#[allow(non_camel_case_types)]
pub struct SQL_C_STINYINT;
impl Ident for SQL_C_STINYINT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SQL_C_TINYINT + SQL_SIGNED_OFFSET;
}
impl<V: OdbcVersion> CData<SQL_C_STINYINT, V> for SQLSCHAR {}

#[allow(non_camel_case_types)]
pub struct SQL_C_UTINYINT;
impl Ident for SQL_C_UTINYINT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SQL_C_TINYINT + SQL_UNSIGNED_OFFSET;
}
impl<V: OdbcVersion> CData<SQL_C_UTINYINT, V> for SQLCHAR {}

#[allow(non_camel_case_types)]
pub struct SQL_C_SBIGINT;
impl Ident for SQL_C_SBIGINT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_BIGINT);
}
impl<V: OdbcVersion> CData<SQL_C_SBIGINT, V> for SQLBIGINT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_UBIGINT;
impl Ident for SQL_C_UBIGINT {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_BIGINT);
}
impl<V: OdbcVersion> CData<SQL_C_UBIGINT, V> for SQLUBIGINT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_BINARY;
impl Ident for SQL_C_BINARY {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_BINARY);
}
impl<V: OdbcVersion> CData<SQL_C_BINARY, V> for OdbcStr<SQLCHAR> {}

// TODO: Weird?
pub use SQL_C_BINARY as SQL_C_VARBOOKMARK;

#[allow(non_camel_case_types)]
pub struct SQL_C_NUMERIC;
impl Ident for SQL_C_NUMERIC {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_NUMERIC);
}
impl<V: OdbcVersion> CData<SQL_C_NUMERIC, V> for SQL_NUMERIC_STRUCT {}

// TODO: This is 3.5
#[allow(non_camel_case_types)]
pub struct SQL_C_GUID;
impl Ident for SQL_C_GUID {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3_8::identifier(&SQL_GUID);
}
impl CData<SQL_C_GUID, SQL_OV_ODBC3_80> for SQLGUID {}

#[allow(non_camel_case_types)]
pub struct SQL_C_TYPE_DATE;
impl Ident for SQL_C_TYPE_DATE {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_TYPE_DATE);
}
impl<V: OdbcVersion> CData<SQL_C_TYPE_DATE, V> for SQL_DATE_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_TYPE_TIME;
impl Ident for SQL_C_TYPE_TIME {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_TYPE_TIME);
}
impl<V: OdbcVersion> CData<SQL_C_TYPE_TIME, V> for SQL_TIME_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_TYPE_TIMESTAMP;
impl Ident for SQL_C_TYPE_TIMESTAMP {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_TYPE_TIMESTAMP);
}
impl<V: OdbcVersion> CData<SQL_C_TYPE_TIMESTAMP, V> for SQL_TIMESTAMP_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_TYPE_TIME_WITH_TIMEZONE;
impl Ident for SQL_C_TYPE_TIME_WITH_TIMEZONE {
    type Type = SQLSMALLINT;
    const IDENTIFIER: SQLSMALLINT = SqlTypeV4::identifier(&SQL_TYPE_TIME_WITH_TIMEZONE);
}
impl CData<SQL_C_TYPE_TIME_WITH_TIMEZONE, SQL_OV_ODBC4> for SQL_TIME_WITH_TIMEZONE_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_TYPE_TIMESTAMP_WITH_TIMEZONE;
impl Ident for SQL_C_TYPE_TIMESTAMP_WITH_TIMEZONE {
    type Type = SQLSMALLINT;
    const IDENTIFIER: SQLSMALLINT = SqlTypeV4::identifier(&SQL_TYPE_TIMESTAMP_WITH_TIMEZONE);
}
impl CData<SQL_C_TYPE_TIMESTAMP_WITH_TIMEZONE, SQL_OV_ODBC4>
    for SQL_TIMESTAMP_WITH_TIMEZONE_STRUCT
{
}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_YEAR;
impl Ident for SQL_C_INTERVAL_YEAR {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_YEAR);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_YEAR, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_MONTH;
impl Ident for SQL_C_INTERVAL_MONTH {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_MONTH);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_MONTH, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_DAY;
impl Ident for SQL_C_INTERVAL_DAY {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_DAY);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_DAY, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_HOUR;
impl Ident for SQL_C_INTERVAL_HOUR {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_HOUR);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_HOUR, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_MINUTE;
impl Ident for SQL_C_INTERVAL_MINUTE {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_MINUTE);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_MINUTE, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_SECOND;
impl Ident for SQL_C_INTERVAL_SECOND {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_SECOND);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_SECOND, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_YEAR_TO_MONTH;
impl Ident for SQL_C_INTERVAL_YEAR_TO_MONTH {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_YEAR_TO_MONTH);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_YEAR_TO_MONTH, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_DAY_TO_HOUR;
impl Ident for SQL_C_INTERVAL_DAY_TO_HOUR {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_DAY_TO_HOUR);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_DAY_TO_HOUR, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_DAY_TO_MINUTE;
impl Ident for SQL_C_INTERVAL_DAY_TO_MINUTE {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_DAY_TO_MINUTE);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_DAY_TO_MINUTE, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_DAY_TO_SECOND;
impl Ident for SQL_C_INTERVAL_DAY_TO_SECOND {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_DAY_TO_SECOND);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_DAY_TO_SECOND, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_HOUR_TO_MINUTE;
impl Ident for SQL_C_INTERVAL_HOUR_TO_MINUTE {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_HOUR_TO_MINUTE);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_HOUR_TO_MINUTE, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_HOUR_TO_SECOND;
impl Ident for SQL_C_INTERVAL_HOUR_TO_SECOND {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_HOUR_TO_SECOND);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_HOUR_TO_SECOND, V> for SQL_INTERVAL_STRUCT {}

#[allow(non_camel_case_types)]
pub struct SQL_C_INTERVAL_MINUTE_TO_SECOND;
impl Ident for SQL_C_INTERVAL_MINUTE_TO_SECOND {
    type Type = SQLSMALLINT;
    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_INTERVAL_MINUTE_TO_SECOND);
}
impl<V: OdbcVersion> CData<SQL_C_INTERVAL_MINUTE_TO_SECOND, V> for SQL_INTERVAL_STRUCT {}

// TODO: Test if these types are required or user can achieve the same goal via some other way
// If SQL_ARD_TYPE and SQL_APD_TYPE are allowed, SQLGetData would have to be unsafe
// Also, these types can only be used for SQLGetData so be careful to implement only for CData<TT>
// because it'll get imeplemented for DeferredBuf automatically. In this case some restructuring
// would be required but it would be transparent to the users of the library
//#[allow(non_camel_case_types)]
//pub struct SQL_ARD_TYPE;
//impl Ident for SQL_ARD_TYPE {
//    type Type = SQLSMALLINT;
//    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_ARD_TYPE);
//}
//
//#[allow(non_camel_case_types)]
//pub struct SQL_APD_TYPE;
//impl Ident for SQL_APD_TYPE {
//    type Type = SQLSMALLINT;
//    const IDENTIFIER: Self::Type = SqlTypeV3::identifier(&SQL_APD_TYPE);
//}

// =================================================================================== //

pub const SQL_MAX_NUMERIC_LEN: usize = 16;

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SQL_NUMERIC_STRUCT {
    pub precision: SQLCHAR,
    pub scale: SQLSCHAR,
    /// The sign field is 1 if positive, 0 if negative.
    pub sign: SQLCHAR,
    pub val: [SQLCHAR; SQL_MAX_NUMERIC_LEN],
}

#[repr(C)]
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SQLGUID {
    pub Data1: u32,
    pub Data2: u16,
    pub Data3: u16,
    pub Data4: [u8; 8],
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SQL_DATE_STRUCT {
    pub year: SQLSMALLINT,
    pub month: SQLUSMALLINT,
    pub day: SQLUSMALLINT,
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SQL_TIME_STRUCT {
    pub hour: SQLUSMALLINT,
    pub minute: SQLUSMALLINT,
    pub second: SQLUSMALLINT,
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SQL_TIMESTAMP_STRUCT {
    pub year: SQLSMALLINT,
    pub month: SQLUSMALLINT,
    pub day: SQLUSMALLINT,
    pub hour: SQLUSMALLINT,
    pub minute: SQLUSMALLINT,
    pub second: SQLUSMALLINT,
    /// Number of billionths of a second and ranges from 0 through 999,999,999
    pub fraction: SQLUINTEGER,
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SQL_TIME_WITH_TIMEZONE_STRUCT {
    pub hour: SQLUSMALLINT,
    pub minute: SQLUSMALLINT,
    pub second: SQLUSMALLINT,
    pub timezone_hours: SQLSMALLINT,
    pub timezone_minutes: SQLUSMALLINT,
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SQL_TIMESTAMP_WITH_TIMEZONE_STRUCT {
    pub year: SQLSMALLINT,
    pub month: SQLUSMALLINT,
    pub day: SQLUSMALLINT,
    pub hour: SQLUSMALLINT,
    pub minute: SQLUSMALLINT,
    pub second: SQLUSMALLINT,
    /// Number of billionths of a second and ranges from 0 through 999,999,999
    pub fraction: SQLUINTEGER,
    pub timezone_hours: SQLSMALLINT,
    pub timezone_minutes: SQLUSMALLINT,
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
pub struct SQL_INTERVAL_STRUCT {
    pub interval_type: SQLINTERVAL,
    pub interval_sign: SQLSMALLINT,
    // TODO: Make public
    interval: IntervalUnion,
}
impl Eq for SQL_INTERVAL_STRUCT {}
impl PartialEq<SQL_INTERVAL_STRUCT> for SQL_INTERVAL_STRUCT {
    fn eq(&self, _: &SQL_INTERVAL_STRUCT) -> bool {
        unimplemented!()
    }
}
impl core::fmt::Debug for SQL_INTERVAL_STRUCT {
    fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
        unimplemented!()
    }
}

// TODO: Probably shouldn't use an enum with C FFI
// But it's literally defined as enum in ODBC
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SQLINTERVAL {
    SQL_IS_YEAR = 1,
    SQL_IS_MONTH = 2,
    SQL_IS_DAY = 3,
    SQL_IS_HOUR = 4,
    SQL_IS_MINUTE = 5,
    SQL_IS_SECOND = 6,
    SQL_IS_YEAR_TO_MONTH = 7,
    SQL_IS_DAY_TO_HOUR = 8,
    SQL_IS_DAY_TO_MINUTE = 9,
    SQL_IS_DAY_TO_SECOND = 10,
    SQL_IS_HOUR_TO_MINUTE = 11,
    SQL_IS_HOUR_TO_SECOND = 12,
    SQL_IS_MINUTE_TO_SECOND = 13,
}

#[repr(C)]
// TODO: Should this be public?
// TODO: Remove Copy
#[derive(Clone, Copy)]
union IntervalUnion {
    pub year_month: SQL_YEAR_MONTH_STRUCT,
    pub day_second: SQL_DAY_SECOND_STRUCT,
}

// TODO: Must be copy because it's used in uinon
// Maybe it would be ok in nightly
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(non_camel_case_types)]
struct SQL_YEAR_MONTH_STRUCT {
    pub year: SQLUINTEGER,
    pub month: SQLUINTEGER,
}

// TODO: Must be copy because it's used in uinon
// Maybe it would be ok in nightly
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(non_camel_case_types)]
struct SQL_DAY_SECOND_STRUCT {
    pub day: SQLUINTEGER,
    pub month: SQLUINTEGER,
    pub minute: SQLUINTEGER,
    pub second: SQLUINTEGER,
    pub fraction: SQLUINTEGER,
}

/// CScalar must be repr(C) and have
/// the same representation as SQLPOINTER
pub unsafe trait CScalar {}

unsafe impl CScalar for SQLSMALLINT {}
unsafe impl CScalar for SQLUSMALLINT {}
unsafe impl CScalar for SQLUINTEGER {}
unsafe impl CScalar for SQLINTEGER {}
unsafe impl CScalar for SQLREAL {}
unsafe impl CScalar for SQLDOUBLE {}
unsafe impl CScalar for SQLCHAR {}
unsafe impl CScalar for SQLSCHAR {}
unsafe impl CScalar for SQLBIGINT {}
unsafe impl CScalar for SQLUBIGINT {}
unsafe impl CScalar for SQLGUID {}
unsafe impl CScalar for SQL_NUMERIC_STRUCT {}
unsafe impl CScalar for SQL_INTERVAL_STRUCT {}
unsafe impl CScalar for SQL_DATE_STRUCT {}
unsafe impl CScalar for SQL_TIME_STRUCT {}
unsafe impl CScalar for SQL_TIMESTAMP_STRUCT {}
unsafe impl CScalar for SQL_TIME_WITH_TIMEZONE_STRUCT {}
unsafe impl CScalar for SQL_TIMESTAMP_WITH_TIMEZONE_STRUCT {}

pub trait CDataLen {
    fn len(&self) -> SQLLEN;
}

impl<T: CScalar> CDataLen for T {
    fn len(&self) -> SQLLEN {
        0
    }
}
impl<T: CScalar> CDataLen for UnsafeCell<T> {
    fn len(&self) -> SQLLEN {
        0
    }
}
impl<T: CScalar> CDataLen for MaybeUninit<T> {
    fn len(&self) -> SQLLEN {
        0
    }
}
// TODO:
//impl<T: CScalar> CDataLen for UnsafeCell<MaybeUninit<T>> {
//    fn len(&self) -> SQLLEN {
//        0
//    }
//}
impl<T> CDataLen for [T] {
    fn len(&self) -> SQLLEN {
        self.len()
            .try_into()
            .expect("Buffer length greater than SQLLEN max")
    }
}
impl<T> CDataLen for OdbcStr<T> {
    fn len(&self) -> SQLLEN {
        <[T] as CDataLen>::len(self)
    }
}
impl CDataLen for (SQLPOINTER, SQLLEN) {
    fn len(&self) -> SQLLEN {
        self.1
    }
}

//impl<T> ParameterDir<SQL_PARAM_INPUT> for [T] where [T]: DeferredBuf {}
//impl<T> ParameterDir<SQL_PARAM_OUTPUT> for [MaybeUninit<T>] where [T]: DeferredBuf {}
//impl<T> ParameterDir<SQL_PARAM_INPUT_OUTPUT> for [MaybeUninit<T>] where
//    [T]: ParameterDir<SQL_PARAM_INPUT> {}