opensrv_clickhouse/types/
mod.rs

1// Copyright 2021 Datafuse Labs.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}