1use std::fmt;
4
5pub use odbc::{ffi, OdbcType};
7
8#[cfg(feature = "chrono")]
9mod sql_timestamp {
10 use super::*;
11 use chrono::naive::{NaiveDate, NaiveDateTime};
12 use chrono::{Datelike, Timelike};
13 use odbc::SqlTimestamp;
14
15 #[derive(Debug)]
17 pub struct UnixTimestamp(SqlTimestamp);
18
19 impl UnixTimestamp {
20 pub fn as_naive_date_time(&self) -> NaiveDateTime {
21 NaiveDate::from_ymd(
22 i32::from(self.0.year),
23 u32::from(self.0.month),
24 u32::from(self.0.day),
25 )
26 .and_hms_nano(
27 u32::from(self.0.hour),
28 u32::from(self.0.minute),
29 u32::from(self.0.second),
30 self.0.fraction,
31 )
32 }
33
34 pub fn into_inner(self) -> SqlTimestamp {
35 self.0
36 }
37 }
38
39 impl From<f64> for UnixTimestamp {
40 fn from(ts: f64) -> UnixTimestamp {
41 let ts =
42 NaiveDateTime::from_timestamp(ts as i64, (ts.fract() * 1_000_000_000.0) as u32);
43 ts.into()
44 }
45 }
46
47 impl From<NaiveDateTime> for UnixTimestamp {
48 fn from(value: NaiveDateTime) -> UnixTimestamp {
49 UnixTimestamp(SqlTimestamp {
50 day: value.day() as u16,
51 month: value.month() as u16,
52 year: value.year() as i16,
53 hour: value.hour() as u16,
54 minute: value.minute() as u16,
55 second: value.second() as u16,
56 fraction: value.nanosecond(),
57 })
58 }
59 }
60
61 unsafe impl<'a> OdbcType<'a> for UnixTimestamp {
62 fn sql_data_type() -> ffi::SqlDataType {
63 SqlTimestamp::sql_data_type()
64 }
65 fn c_data_type() -> ffi::SqlCDataType {
66 SqlTimestamp::c_data_type()
67 }
68
69 fn convert(buffer: &'a [u8]) -> Self {
70 UnixTimestamp(SqlTimestamp::convert(buffer))
71 }
72
73 fn column_size(&self) -> ffi::SQLULEN {
74 self.0.column_size()
75 }
76 fn value_ptr(&self) -> ffi::SQLPOINTER {
77 self.0.value_ptr()
78 }
79 }
80
81 #[cfg(test)]
82 mod tests {
83 pub use super::*;
84
85 #[test]
86 fn test_timestamp() {
87 let ts: UnixTimestamp = 1547115460.2291234.into();
88
89 assert_eq!(ts.0.year, 2019);
90 assert_eq!(ts.0.month, 1);
91 assert_eq!(ts.0.day, 10);
92 assert_eq!(ts.0.hour, 10);
93 assert_eq!(ts.0.minute, 17);
94 assert_eq!(ts.0.second, 40);
95 assert_eq!(ts.0.fraction / 1000, 229123); }
97
98 #[test]
99 fn test_timestamp_as_date_time() {
100 let ts: UnixTimestamp = 1547115460.2291234.into();
101 assert_eq!(ts.as_naive_date_time().timestamp_millis(), 1547115460229);
102 }
103 }
104}
105
106#[cfg(feature = "chrono")]
107pub use sql_timestamp::*;
108
109use std::borrow::Cow;
110
111#[derive(PartialEq, Eq, Debug)]
113pub struct CowString<'s>(pub Cow<'s, str>);
114
115impl<'s> From<String> for CowString<'s> {
116 fn from(s: String) -> CowString<'static> {
117 CowString(Cow::Owned(s))
118 }
119}
120
121impl<'s> From<&'s str> for CowString<'s> {
122 fn from(s: &'s str) -> CowString<'s> {
123 CowString(Cow::Borrowed(s))
124 }
125}
126
127impl<'s> From<Cow<'s, str>> for CowString<'s> {
128 fn from(s: Cow<'s, str>) -> CowString<'s> {
129 CowString(s)
130 }
131}
132
133unsafe impl<'s> OdbcType<'s> for CowString<'s> {
134 fn sql_data_type() -> ffi::SqlDataType {
135 String::sql_data_type()
136 }
137 fn c_data_type() -> ffi::SqlCDataType {
138 String::c_data_type()
139 }
140
141 fn convert(buffer: &'s [u8]) -> Self {
142 CowString(Cow::Owned(String::convert(buffer)))
143 }
144
145 fn column_size(&self) -> ffi::SQLULEN {
146 self.0.as_ref().column_size()
147 }
148
149 fn value_ptr(&self) -> ffi::SQLPOINTER {
150 self.0.as_ref().value_ptr()
151 }
152}
153
154#[derive(PartialEq, Eq)]
156pub struct StringUtf16(pub Vec<u16>);
157
158impl fmt::Debug for StringUtf16 {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 write!(f, "N{:?}", String::from_utf16(&self.0).expect("StringUtf16 is not valid UTF-16 encoded string"))
161 }
162}
163
164impl From<String> for StringUtf16 {
165 fn from(s: String) -> StringUtf16 {
166 s.as_str().into()
167 }
168}
169
170impl From<&str> for StringUtf16 {
171 fn from(s: &str) -> StringUtf16 {
172 StringUtf16(s.encode_utf16().collect())
173 }
174}
175
176unsafe impl<'a> OdbcType<'a> for StringUtf16 {
177 fn sql_data_type() -> ffi::SqlDataType {
178 <&[u16]>::sql_data_type()
179 }
180 fn c_data_type() -> ffi::SqlCDataType {
181 <&[u16]>::c_data_type()
182 }
183
184 fn convert(buffer: &[u8]) -> Self {
185 StringUtf16(<&[u16]>::convert(buffer).to_owned())
186 }
187
188 fn column_size(&self) -> ffi::SQLULEN {
189 <&[u16]>::column_size(&self.0.as_slice())
190 }
191
192 fn value_ptr(&self) -> ffi::SQLPOINTER {
193 self.0.as_ptr() as *const &[u16] as ffi::SQLPOINTER
194 }
195}
196
197#[cfg(feature = "serde")]
198impl<'de> serde::de::Deserialize<'de> for StringUtf16 {
199 fn deserialize<D>(deserializer: D) -> std::result::Result<StringUtf16, D::Error>
200 where
201 D: serde::de::Deserializer<'de>,
202 {
203 String::deserialize(deserializer)
204 .map(From::from)
205 }
206}