Skip to main content

mz_sql_parser/ast/defs/
value.rs

1// Copyright 2018 sqlparser-rs contributors. All rights reserved.
2// Copyright Materialize, Inc. and contributors. All rights reserved.
3//
4// This file is derived from the sqlparser-rs project, available at
5// https://github.com/andygrove/sqlparser-rs. It was incorporated
6// directly into Materialize on December 21, 2019.
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License in the LICENSE file at the
11// root of this repository, or online at
12//
13//     http://www.apache.org/licenses/LICENSE-2.0
14//
15// Unless required by applicable law or agreed to in writing, software
16// distributed under the License is distributed on an "AS IS" BASIS,
17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18// See the License for the specific language governing permissions and
19// limitations under the License.
20
21use std::fmt;
22use std::str::FromStr;
23
24use serde::{Deserialize, Serialize};
25
26use crate::ast::Ident;
27use crate::ast::display::{self, AstDisplay, AstFormatter};
28
29#[derive(Debug)]
30pub struct ValueError(pub(crate) String);
31
32impl std::error::Error for ValueError {}
33
34impl fmt::Display for ValueError {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        write!(f, "{}", self.0)
37    }
38}
39
40/// Primitive SQL values.
41#[derive(
42    Debug,
43    Clone,
44    PartialEq,
45    Eq,
46    Hash,
47    PartialOrd,
48    Ord,
49    Serialize,
50    Deserialize
51)]
52pub enum Value {
53    /// Numeric value.
54    Number(String),
55    /// String value.
56    String(String),
57    /// Hex string value.
58    HexString(String),
59    /// Boolean value.
60    Boolean(bool),
61    /// INTERVAL literals, roughly in the following format:
62    ///
63    /// ```text
64    /// INTERVAL '<value>' <leading_field> [ TO <last_field>
65    ///     [ (<fractional_seconds_precision>) ] ]
66    /// ```
67    /// e.g. `INTERVAL '123:45.678' MINUTE TO SECOND(2)`.
68    Interval(IntervalValue),
69    /// `NULL` value.
70    Null,
71}
72
73impl AstDisplay for Value {
74    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
75        if f.redacted() {
76            // When adding branches to this match statement, think about whether it is OK for us to collect
77            // the value as part of our telemetry. Check the data management policy to be sure!
78            match self {
79                Value::Number(_) | Value::String(_) | Value::HexString(_) => {
80                    f.write_str("'<REDACTED>'");
81                    return;
82                }
83                Value::Interval(_) => {
84                    f.write_str("INTERVAL '<REDACTED>'");
85                    return;
86                }
87                Value::Boolean(_) | Value::Null => {
88                    // These are fine to log, so just fall through.
89                }
90            }
91        }
92        match self {
93            Value::Number(v) => f.write_str(v),
94            Value::String(v) => {
95                f.write_str("'");
96                f.write_node(&display::escape_single_quote_string(v));
97                f.write_str("'");
98            }
99            Value::HexString(v) => {
100                // The lexer accepts arbitrary bytes inside `X'...'` and treats
101                // `''` as an escaped single quote. We must escape `'` on the
102                // way out so a value containing `'` round-trips through the
103                // lexer instead of closing the literal prematurely.
104                f.write_str("X'");
105                f.write_node(&display::escape_single_quote_string(v));
106                f.write_str("'");
107            }
108            Value::Boolean(v) => f.write_str(v),
109            Value::Interval(interval_value) => {
110                f.write_str("INTERVAL '");
111                f.write_node(interval_value);
112            }
113            Value::Null => f.write_str("NULL"),
114        }
115    }
116}
117impl_display!(Value);
118
119impl AstDisplay for IntervalValue {
120    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
121        if f.redacted() {
122            f.write_str("<REDACTED>'");
123        } else {
124            let IntervalValue {
125                value,
126                precision_high,
127                precision_low,
128                fsec_max_precision,
129            } = self;
130            f.write_node(&display::escape_single_quote_string(value));
131            f.write_str("'");
132            match (precision_high, precision_low, fsec_max_precision) {
133                (DateTimeField::Year, DateTimeField::Second, None) => {}
134                (DateTimeField::Year, DateTimeField::Second, Some(ns)) => {
135                    f.write_str(" SECOND(");
136                    f.write_str(ns);
137                    f.write_str(")");
138                }
139                (DateTimeField::Year, low, None) => {
140                    f.write_str(" ");
141                    f.write_str(low);
142                }
143                (high, low, None) => {
144                    f.write_str(" ");
145                    f.write_str(high);
146                    f.write_str(" TO ");
147                    f.write_str(low);
148                }
149                (high, low, Some(ns)) => {
150                    f.write_str(" ");
151                    f.write_str(high);
152                    f.write_str(" TO ");
153                    f.write_str(low);
154                    f.write_str("(");
155                    f.write_str(ns);
156                    f.write_str(")");
157                }
158            }
159        }
160    }
161}
162
163impl From<Ident> for Value {
164    fn from(ident: Ident) -> Self {
165        Self::String(ident.0)
166    }
167}
168
169#[derive(
170    Debug,
171    Clone,
172    Copy,
173    PartialOrd,
174    Ord,
175    PartialEq,
176    Eq,
177    Hash,
178    Serialize,
179    Deserialize
180)]
181pub enum DateTimeField {
182    Millennium,
183    Century,
184    Decade,
185    Year,
186    Month,
187    Day,
188    Hour,
189    Minute,
190    Second,
191    Milliseconds,
192    Microseconds,
193}
194
195impl fmt::Display for DateTimeField {
196    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197        f.write_str(match self {
198            DateTimeField::Millennium => "MILLENNIUM",
199            DateTimeField::Century => "CENTURY",
200            DateTimeField::Decade => "DECADE",
201            DateTimeField::Year => "YEAR",
202            DateTimeField::Month => "MONTH",
203            DateTimeField::Day => "DAY",
204            DateTimeField::Hour => "HOUR",
205            DateTimeField::Minute => "MINUTE",
206            DateTimeField::Second => "SECOND",
207            DateTimeField::Milliseconds => "MILLISECONDS",
208            DateTimeField::Microseconds => "MICROSECONDS",
209        })
210    }
211}
212
213impl FromStr for DateTimeField {
214    type Err = String;
215
216    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
217        match s.to_uppercase().as_ref() {
218            "MILLENNIUM" | "MILLENNIA" | "MIL" | "MILS" => Ok(Self::Millennium),
219            "CENTURY" | "CENTURIES" | "CENT" | "C" => Ok(Self::Century),
220            "DECADE" | "DECADES" | "DEC" | "DECS" => Ok(Self::Decade),
221            "YEAR" | "YEARS" | "YR" | "YRS" | "Y" => Ok(Self::Year),
222            "MONTH" | "MONTHS" | "MON" | "MONS" => Ok(Self::Month),
223            "DAY" | "DAYS" | "D" => Ok(Self::Day),
224            "HOUR" | "HOURS" | "HR" | "HRS" | "H" => Ok(Self::Hour),
225            "MINUTE" | "MINUTES" | "MIN" | "MINS" | "M" => Ok(Self::Minute),
226            "SECOND" | "SECONDS" | "SEC" | "SECS" | "S" => Ok(Self::Second),
227            "MILLISECOND" | "MILLISECONDS" | "MILLISECON" | "MILLISECONS" | "MSECOND"
228            | "MSECONDS" | "MSEC" | "MSECS" | "MS" => Ok(Self::Milliseconds),
229            "MICROSECOND" | "MICROSECONDS" | "MICROSECON" | "MICROSECONS" | "USECOND"
230            | "USECONDS" | "USEC" | "USECS" | "US" => Ok(Self::Microseconds),
231            _ => Err(format!("invalid DateTimeField: {}", s)),
232        }
233    }
234}
235
236/// An intermediate value for Intervals, which tracks all data from
237/// the user, as well as the computed ParsedDateTime.
238#[derive(
239    Debug,
240    Clone,
241    PartialEq,
242    Eq,
243    Hash,
244    PartialOrd,
245    Ord,
246    Serialize,
247    Deserialize
248)]
249pub struct IntervalValue {
250    /// The raw `[value]` that was present in `INTERVAL '[value]'`
251    pub value: String,
252    /// The most significant DateTimeField to propagate to Interval in
253    /// compute_interval.
254    pub precision_high: DateTimeField,
255    /// The least significant DateTimeField to propagate to Interval in
256    /// compute_interval.
257    /// precision_low is also used to provide a TimeUnit if the final
258    /// part of `value` is ambiguous, e.g. INTERVAL '1-2 3' DAY uses
259    /// 'day' as the TimeUnit for 3.
260    pub precision_low: DateTimeField,
261    /// Maximum nanosecond precision can be specified in SQL source as
262    /// `INTERVAL '__' SECOND(_)`.
263    pub fsec_max_precision: Option<u64>,
264}
265
266impl Default for IntervalValue {
267    fn default() -> Self {
268        Self {
269            value: String::default(),
270            precision_high: DateTimeField::Year,
271            precision_low: DateTimeField::Second,
272            fsec_max_precision: None,
273        }
274    }
275}
276
277#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
278pub struct Version(pub(crate) u64);
279
280impl Version {
281    pub fn new(val: u64) -> Self {
282        Version(val)
283    }
284
285    pub fn into_inner(self) -> u64 {
286        self.0
287    }
288}
289
290impl AstDisplay for Version {
291    fn fmt<W>(&self, f: &mut AstFormatter<W>)
292    where
293        W: fmt::Write,
294    {
295        f.write_node(&self.0);
296    }
297}
298impl_display!(Version);