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
use error::{SqlDiagnosticRecord, SqlResult};
use handle::SqlHandle;
use odbc_sys::*;
use std;
use std::string::FromUtf16Error;

pub fn decimal_digits(parameter_type: SqlDataType) -> SQLSMALLINT {
    match parameter_type {
        SQL_TIMESTAMP
        | SQL_SS_TIMESTAMPOFFSET
        | SQL_TIME
        | SQL_DATETIME
        | SQL_SS_TIME2
        | SQL_EXT_TIMESTAMP
        | SQL_EXT_TIME_OR_INTERVAL => 9,
        _ => 0,
    }
}

pub fn from_utf_16_null_terminated(mut slice: &[u16]) -> Result<String, FromUtf16Error> {
    if let Some(&0) = slice.last() {
        slice = &slice[..slice.len() - 1];
    };

    String::from_utf16(slice)
}

pub fn u32_to_bool(x: u32) -> bool {
    match x {
        1 => true,
        0 => false,
        _ => panic!("{} is not a valid boolean value (0/1)", x),
    }
}

pub fn is_string_data_right_truncated<T: SqlHandle>(handle: &T, ret: SQLRETURN) -> SqlResult<bool> {
    match ret {
        SQL_SUCCESS | SQL_NO_DATA => Ok(false),
        SQL_SUCCESS_WITH_INFO => {
            let diagnostics = handle.diagnostics()?;
            Ok(diagnostics
                .iter()
                .any(SqlDiagnosticRecord::is_string_data_right_truncated))
        }
        _ => panic!("Unexpected SQLRETURN: {:?}", ret),
    }
}

pub trait VecCapacityExt {
    fn reserve_capacity(&mut self, capacity: usize);
    unsafe fn set_len_checked(&mut self, len: usize);
    fn capacity_bytes(&self) -> usize;
    fn remaining_capacity(&self) -> usize;
    fn remaining_capacity_bytes(&self) -> usize;
}

impl<T> VecCapacityExt for Vec<T> {
    fn reserve_capacity(&mut self, capacity: usize) {
        let len = self.len();
        if capacity > len {
            self.reserve_exact(capacity - len);
        }
    }
    unsafe fn set_len_checked(&mut self, len: usize) {
        assert!(len <= self.capacity());
        self.set_len(len);
    }
    fn capacity_bytes(&self) -> usize {
        self.capacity() * std::mem::size_of::<T>()
    }
    fn remaining_capacity(&self) -> usize {
        self.capacity() - self.len()
    }
    fn remaining_capacity_bytes(&self) -> usize {
        self.remaining_capacity() * std::mem::size_of::<T>()
    }
}

#[cfg(test)]
mod tests {
    use std::sync::{Arc, RwLock};
    use SqlHandle;

    pub fn print_diagnostics<T: SqlHandle>(handle: &T) {
        let diagnostics = handle.diagnostics().unwrap();

        let mut iter = diagnostics.iter().peekable();
        while let Some(detail) = iter.next() {
            if iter.peek().is_some() {
                println!("{}\n", detail);
            } else {
                println!("{}", detail);
            }
        }
    }

    pub fn print_diagnostics_async<T: SqlHandle>(handle: &Arc<RwLock<T>>) {
        let lock = handle.read().unwrap();

        print_diagnostics(&lock as &T);
    }
}

#[cfg(test)]
pub use self::tests::*;