databend_common_ast/ast/
common.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::fmt::Display;
16use std::fmt::Formatter;
17
18use derive_visitor::Drive;
19use derive_visitor::DriveMut;
20use ethnum::i256;
21
22use super::quote::QuotedString;
23use crate::ast::quote::QuotedIdent;
24use crate::ast::WithOptions;
25use crate::Span;
26
27// Identifier of table name or column name.
28#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
29pub struct Identifier {
30    pub span: Span,
31    pub name: String,
32    pub quote: Option<char>,
33    #[drive(skip)]
34    pub ident_type: IdentifierType,
35}
36
37#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
38pub enum IdentifierType {
39    #[default]
40    None,
41    Hole,
42    Variable,
43}
44
45impl Identifier {
46    pub fn is_quoted(&self) -> bool {
47        self.quote.is_some()
48    }
49
50    pub fn is_hole(&self) -> bool {
51        self.ident_type == IdentifierType::Hole
52    }
53
54    pub fn is_variable(&self) -> bool {
55        self.ident_type == IdentifierType::Variable
56    }
57
58    pub fn from_name(span: Span, name: impl Into<String>) -> Self {
59        Self {
60            span,
61            name: name.into(),
62            quote: None,
63            ident_type: IdentifierType::None,
64        }
65    }
66
67    pub fn from_name_with_quoted(span: Span, name: impl Into<String>, quote: Option<char>) -> Self {
68        Self {
69            span,
70            name: name.into(),
71            quote,
72            ident_type: IdentifierType::None,
73        }
74    }
75}
76
77impl Display for Identifier {
78    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
79        if self.is_hole() {
80            write!(f, "IDENTIFIER(:{})", self.name)
81        } else if self.is_variable() {
82            write!(f, "IDENTIFIER(${})", self.name)
83        } else if let Some(quote) = self.quote {
84            write!(f, "{}", QuotedIdent(&self.name, quote))
85        } else {
86            write!(f, "{}", self.name)
87        }
88    }
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
92pub struct ColumnPosition {
93    pub span: Span,
94    pub pos: usize,
95    pub name: String,
96}
97
98impl ColumnPosition {
99    pub fn create(span: Span, pos: usize) -> ColumnPosition {
100        ColumnPosition {
101            pos,
102            name: format!("${}", pos),
103            span,
104        }
105    }
106    pub fn name(&self) -> String {
107        format!("${}", self.pos)
108    }
109}
110
111impl Display for ColumnPosition {
112    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
113        write!(f, "${}", self.pos)
114    }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
118pub enum ColumnID {
119    Name(Identifier),
120    Position(ColumnPosition),
121}
122
123impl ColumnID {
124    pub fn name(&self) -> &str {
125        match self {
126            ColumnID::Name(id) => &id.name,
127            ColumnID::Position(id) => &id.name,
128        }
129    }
130}
131
132impl Display for ColumnID {
133    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
134        match self {
135            ColumnID::Name(id) => write!(f, "{}", id),
136            ColumnID::Position(id) => write!(f, "{}", id),
137        }
138    }
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
142pub struct DatabaseRef {
143    pub catalog: Option<Identifier>,
144    pub database: Identifier,
145}
146
147impl Display for DatabaseRef {
148    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
149        if let Some(catalog) = &self.catalog {
150            write!(f, "{}.", catalog)?;
151        }
152        write!(f, "{}", self.database)?;
153        Ok(())
154    }
155}
156
157#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
158pub struct TableRef {
159    pub catalog: Option<Identifier>,
160    pub database: Option<Identifier>,
161    pub table: Identifier,
162    pub with_options: Option<WithOptions>,
163}
164
165impl Display for TableRef {
166    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
167        assert!(self.catalog.is_none() || (self.catalog.is_some() && self.database.is_some()));
168        if let Some(catalog) = &self.catalog {
169            write!(f, "{}.", catalog)?;
170        }
171        if let Some(database) = &self.database {
172            write!(f, "{}.", database)?;
173        }
174        write!(f, "{}", self.table)?;
175
176        if let Some(with_options) = &self.with_options {
177            write!(f, " {with_options}")?;
178        }
179        Ok(())
180    }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
184pub struct ColumnRef {
185    pub database: Option<Identifier>,
186    pub table: Option<Identifier>,
187    pub column: ColumnID,
188}
189
190impl Display for ColumnRef {
191    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
192        assert!(self.database.is_none() || (self.database.is_some() && self.table.is_some()));
193
194        if f.alternate() {
195            write!(f, "{}", self.column)?;
196            return Ok(());
197        }
198
199        if let Some(database) = &self.database {
200            write!(f, "{}.", database)?;
201        }
202        if let Some(table) = &self.table {
203            write!(f, "{}.", table)?;
204        }
205        write!(f, "{}", self.column)?;
206        Ok(())
207    }
208}
209
210pub(crate) fn write_dot_separated_list(
211    f: &mut Formatter,
212    items: impl IntoIterator<Item = impl Display>,
213) -> std::fmt::Result {
214    for (i, item) in items.into_iter().enumerate() {
215        if i > 0 {
216            write!(f, ".")?;
217        }
218        write!(f, "{}", item)?;
219    }
220    Ok(())
221}
222
223/// Write input items into `a, b, c`
224pub(crate) fn write_comma_separated_list(
225    f: &mut Formatter,
226    items: impl IntoIterator<Item = impl Display>,
227) -> std::fmt::Result {
228    for (i, item) in items.into_iter().enumerate() {
229        if i > 0 {
230            write!(f, ", ")?;
231        }
232        write!(f, "{item}")?;
233    }
234    Ok(())
235}
236
237/// Write input items into `'a', 'b', 'c'`
238pub(crate) fn write_comma_separated_string_list(
239    f: &mut Formatter,
240    items: impl IntoIterator<Item = impl Display>,
241) -> std::fmt::Result {
242    for (i, item) in items.into_iter().enumerate() {
243        if i > 0 {
244            write!(f, ", ")?;
245        }
246        write!(f, "'{item}'")?;
247    }
248    Ok(())
249}
250
251/// Write input map items into `field_a=x, field_b=y`
252pub(crate) fn write_comma_separated_map(
253    f: &mut Formatter,
254    items: impl IntoIterator<Item = (impl Display, impl Display)>,
255) -> std::fmt::Result {
256    for (i, (k, v)) in items.into_iter().enumerate() {
257        if i > 0 {
258            write!(f, ", ")?;
259        }
260        write!(f, "{k} = {v}")?;
261    }
262    Ok(())
263}
264
265/// Write input map items into `field_a='x', field_b='y'`
266pub(crate) fn write_comma_separated_string_map(
267    f: &mut Formatter,
268    items: impl IntoIterator<Item = (impl Display, impl Display)>,
269) -> std::fmt::Result {
270    for (i, (k, v)) in items.into_iter().enumerate() {
271        if i > 0 {
272            write!(f, ", ")?;
273        }
274        write!(f, "{k} = {}", QuotedString(v.to_string(), '\''))?;
275    }
276    Ok(())
277}
278
279/// Write input map items into `field_a='x' field_b='y'`
280pub(crate) fn write_space_separated_string_map(
281    f: &mut Formatter,
282    items: impl IntoIterator<Item = (impl Display, impl Display)>,
283) -> std::fmt::Result {
284    for (i, (k, v)) in items.into_iter().enumerate() {
285        if i > 0 {
286            write!(f, " ")?;
287        }
288        write!(f, "{k} = {}", QuotedString(v.to_string(), '\''))?;
289    }
290    Ok(())
291}
292
293pub(crate) fn display_decimal_256(num: i256, scale: u8) -> impl Display {
294    struct Decimal256 {
295        num: i256,
296        scale: u8,
297    }
298
299    impl Display for Decimal256 {
300        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301            if self.scale == 0 {
302                write!(f, "{}", self.num)
303            } else {
304                let pow_scale = i256::from(10).pow(self.scale as u32);
305                // -1/10 = 0
306                if self.num >= 0 {
307                    write!(
308                        f,
309                        "{}.{:0>width$}",
310                        self.num / pow_scale,
311                        (self.num % pow_scale).abs(),
312                        width = self.scale as usize
313                    )
314                } else {
315                    write!(
316                        f,
317                        "-{}.{:0>width$}",
318                        -self.num / pow_scale,
319                        (self.num % pow_scale).abs(),
320                        width = self.scale as usize
321                    )
322                }
323            }
324        }
325    }
326
327    Decimal256 { num, scale }
328}