1use std::borrow::Cow;
16use std::collections::HashMap;
17use std::fmt;
18use std::mem;
19use std::pin::Pin;
20use std::sync::Mutex;
21
22use chrono::prelude::*;
23use chrono_tz::Tz;
24use hostname::get;
25use once_cell::sync::Lazy;
26
27pub use self::block::decompress_buffer;
28pub use self::block::Block;
29pub use self::block::RCons;
30pub use self::block::RNil;
31pub use self::block::Row;
32pub use self::block::RowBuilder;
33pub use self::block::Rows;
34pub use self::column::Column;
35pub use self::column::ColumnType;
36pub use self::column::Complex;
37pub use self::column::Either;
38pub use self::column::Simple;
39pub use self::column::StringPool;
40pub use self::date_converter::DateConverter;
41pub use self::date_converter::UNIX_EPOCH_DAY;
42pub use self::decimal::decimal2str;
43pub use self::decimal::Decimal;
44pub use self::decimal::NoBits;
45pub use self::enums::Enum16;
46pub use self::enums::Enum8;
47pub use self::from_sql::FromSql;
48pub use self::from_sql::FromSqlResult;
49pub use self::options::*;
50pub use self::query::Query;
51pub use self::stat_buffer::StatBuffer;
52pub use self::value::Value;
53pub use self::value_ref::ValueRef;
54use crate::binary::Encoder;
55use crate::protocols::DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO;
56use crate::protocols::SERVER_PROGRESS;
57
58pub mod column;
59mod stat_buffer;
60
61mod from_sql;
62mod value;
63mod value_ref;
64
65pub mod block;
66
67mod date_converter;
68mod query;
69
70mod decimal;
71mod enums;
72mod options;
73
74#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
75pub struct Progress {
76 pub rows: u64,
77 pub bytes: u64,
78 pub total_rows: u64,
79}
80
81impl Progress {
82 pub fn write(&self, encoder: &mut Encoder, client_revision: u64) {
83 encoder.uvarint(SERVER_PROGRESS);
84 encoder.uvarint(self.rows);
85 encoder.uvarint(self.bytes);
86 encoder.uvarint(self.total_rows);
87
88 if client_revision >= DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO {
89 encoder.uvarint(0);
90 encoder.uvarint(0);
91 }
92 }
93}
94
95#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
96pub(crate) struct ProfileInfo {
97 pub rows: u64,
98 pub bytes: u64,
99 pub blocks: u64,
100 pub applied_limit: bool,
101 pub rows_before_limit: u64,
102 pub calculated_rows_before_limit: bool,
103}
104
105#[derive(Clone, PartialEq, Eq)]
106pub(crate) struct ServerInfo {
107 pub name: String,
108 pub revision: u64,
109 pub minor_version: u64,
110 pub major_version: u64,
111 pub timezone: Tz,
112}
113
114impl fmt::Debug for ServerInfo {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 write!(
117 f,
118 "{} {}.{}.{} ({:?})",
119 self.name, self.major_version, self.minor_version, self.revision, self.timezone
120 )
121 }
122}
123
124#[allow(dead_code)]
125#[derive(Clone)]
126pub(crate) struct Context {
127 pub(crate) server_info: ServerInfo,
128 pub(crate) hostname: String,
129 pub(crate) options: OptionsSource,
130}
131
132impl Default for ServerInfo {
133 fn default() -> Self {
134 Self {
135 name: String::new(),
136 revision: 0,
137 minor_version: 0,
138 major_version: 0,
139 timezone: Tz::Zulu,
140 }
141 }
142}
143
144impl fmt::Debug for Context {
145 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146 f.debug_struct("Context")
147 .field("options", &self.options)
148 .field("hostname", &self.hostname)
149 .finish()
150 }
151}
152
153impl Default for Context {
154 fn default() -> Self {
155 Self {
156 server_info: ServerInfo::default(),
157 hostname: get().unwrap().into_string().unwrap(),
158 options: OptionsSource::default(),
159 }
160 }
161}
162
163pub trait HasSqlType {
164 fn get_sql_type() -> SqlType;
165}
166
167macro_rules! has_sql_type {
168 ( $( $t:ty : $k:expr ),* ) => {
169 $(
170 impl HasSqlType for $t {
171 fn get_sql_type() -> SqlType {
172 $k
173 }
174 }
175 )*
176 };
177}
178
179has_sql_type! {
180 u8: SqlType::UInt8,
181 u16: SqlType::UInt16,
182 u32: SqlType::UInt32,
183 u64: SqlType::UInt64,
184 i8: SqlType::Int8,
185 i16: SqlType::Int16,
186 i32: SqlType::Int32,
187 i64: SqlType::Int64,
188 &str: SqlType::String,
189 String: SqlType::String,
190 f32: SqlType::Float32,
191 f64: SqlType::Float64,
192 NaiveDate: SqlType::Date,
193 DateTime<Tz>: SqlType::DateTime(DateTimeType::DateTime32)
194}
195
196#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
197pub enum DateTimeType {
198 DateTime32,
199 DateTime64(u32, Tz),
200 Chrono,
201}
202
203#[derive(Clone, Debug, Eq, PartialEq, Hash)]
204pub enum SqlType {
205 UInt8,
206 UInt16,
207 UInt32,
208 UInt64,
209 Int8,
210 Int16,
211 Int32,
212 Int64,
213 String,
214 FixedString(usize),
215 Float32,
216 Float64,
217 Date,
218 DateTime(DateTimeType),
219 Ipv4,
220 Ipv6,
221 Uuid,
222 Nullable(&'static SqlType),
223 Array(&'static SqlType),
224 Decimal(u8, u8),
225 Enum8(Vec<(String, i8)>),
226 Enum16(Vec<(String, i16)>),
227 Tuple(Vec<&'static SqlType>),
228}
229
230static TYPES_CACHE: Lazy<Mutex<HashMap<SqlType, Pin<Box<SqlType>>>>> =
231 Lazy::new(|| Mutex::new(HashMap::new()));
232
233impl From<SqlType> for &'static SqlType {
234 fn from(value: SqlType) -> Self {
235 match value {
236 SqlType::UInt8 => &SqlType::UInt8,
237 SqlType::UInt16 => &SqlType::UInt16,
238 SqlType::UInt32 => &SqlType::UInt32,
239 SqlType::UInt64 => &SqlType::UInt64,
240 SqlType::Int8 => &SqlType::Int8,
241 SqlType::Int16 => &SqlType::Int16,
242 SqlType::Int32 => &SqlType::Int32,
243 SqlType::Int64 => &SqlType::Int64,
244 SqlType::String => &SqlType::String,
245 SqlType::Float32 => &SqlType::Float32,
246 SqlType::Float64 => &SqlType::Float64,
247 SqlType::Date => &SqlType::Date,
248 _ => {
249 let mut guard = TYPES_CACHE.lock().unwrap();
250 loop {
251 if let Some(value_ref) = guard.get(&value.clone()) {
252 return unsafe { mem::transmute(value_ref.as_ref()) };
253 }
254 guard.insert(value.clone(), Box::pin(value.clone()));
255 }
256 }
257 }
258 }
259}
260
261impl SqlType {
262 pub(crate) fn is_datetime(&self) -> bool {
263 matches!(self, SqlType::DateTime(_))
264 }
265
266 pub fn to_string(&self) -> Cow<'static, str> {
267 match self.clone() {
268 SqlType::UInt8 => "UInt8".into(),
269 SqlType::UInt16 => "UInt16".into(),
270 SqlType::UInt32 => "UInt32".into(),
271 SqlType::UInt64 => "UInt64".into(),
272 SqlType::Int8 => "Int8".into(),
273 SqlType::Int16 => "Int16".into(),
274 SqlType::Int32 => "Int32".into(),
275 SqlType::Int64 => "Int64".into(),
276 SqlType::String => "String".into(),
277 SqlType::FixedString(str_len) => format!("FixedString({})", str_len).into(),
278 SqlType::Float32 => "Float32".into(),
279 SqlType::Float64 => "Float64".into(),
280 SqlType::Date => "Date".into(),
281 SqlType::DateTime(DateTimeType::DateTime64(precision, tz)) => {
282 format!("DateTime64({}, '{:?}')", precision, tz).into()
283 }
284 SqlType::DateTime(_) => "DateTime".into(),
285 SqlType::Ipv4 => "IPv4".into(),
286 SqlType::Ipv6 => "IPv6".into(),
287 SqlType::Uuid => "UUID".into(),
288 SqlType::Nullable(nested) => format!("Nullable({})", &nested).into(),
289 SqlType::Array(nested) => format!("Array({})", &nested).into(),
290 SqlType::Decimal(precision, scale) => {
291 format!("Decimal({}, {})", precision, scale).into()
292 }
293 SqlType::Enum8(values) => {
294 let a: Vec<String> = values
295 .iter()
296 .map(|(name, value)| format!("'{}' = {}", name, value))
297 .collect();
298 format!("Enum8({})", a.join(",")).into()
299 }
300 SqlType::Enum16(values) => {
301 let a: Vec<String> = values
302 .iter()
303 .map(|(name, value)| format!("'{}' = {}", name, value))
304 .collect();
305 format!("Enum16({})", a.join(",")).into()
306 }
307 SqlType::Tuple(types) => {
308 let a: Vec<String> = types.iter().map(|t| t.to_string()).collect();
309 format!("Tuple({})", a.join(",")).into()
310 }
311 }
312 }
313
314 pub(crate) fn level(&self) -> u8 {
315 match self {
316 SqlType::Nullable(inner) => 1 + inner.level(),
317 SqlType::Array(inner) => 1 + inner.level(),
318 SqlType::Tuple(types) => types.iter().map(|t| t.level()).max().unwrap_or(0) + 1,
319 _ => 0,
320 }
321 }
322}
323
324impl fmt::Display for SqlType {
325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326 write!(f, "{}", Self::to_string(self))
327 }
328}
329
330#[test]
331fn test_display() {
332 let expected = "UInt8".to_string();
333 let actual = format!("{}", SqlType::UInt8);
334 assert_eq!(expected, actual);
335}
336
337#[test]
338fn test_to_string() {
339 let expected: Cow<'static, str> = "Nullable(UInt8)".into();
340 let actual = SqlType::Nullable(&SqlType::UInt8).to_string();
341 assert_eq!(expected, actual)
342}