wing_sqlparser/ast/
value.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13#[cfg(not(feature = "std"))]
14use alloc::string::String;
15use core::fmt;
16
17#[cfg(feature = "bigdecimal")]
18use bigdecimal::BigDecimal;
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21
22/// Primitive SQL values such as number and string
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub enum Value {
26    /// Numeric literal
27    #[cfg(not(feature = "bigdecimal"))]
28    Number(String, bool),
29    #[cfg(feature = "bigdecimal")]
30    Number(BigDecimal, bool),
31    /// 'string value'
32    SingleQuotedString(String),
33    /// N'string value'
34    NationalStringLiteral(String),
35    /// X'hex value'
36    HexStringLiteral(String),
37
38    DoubleQuotedString(String),
39    /// Boolean value true or false
40    Boolean(bool),
41    /// INTERVAL literals, roughly in the following format:
42    /// `INTERVAL '<value>' [ <leading_field> [ (<leading_precision>) ] ]
43    /// [ TO <last_field> [ (<fractional_seconds_precision>) ] ]`,
44    /// e.g. `INTERVAL '123:45.67' MINUTE(3) TO SECOND(2)`.
45    ///
46    /// The parser does not validate the `<value>`, nor does it ensure
47    /// that the `<leading_field>` units >= the units in `<last_field>`,
48    /// so the user will have to reject intervals like `HOUR TO YEAR`.
49    Interval {
50        value: String,
51        leading_field: Option<DateTimeField>,
52        leading_precision: Option<u64>,
53        last_field: Option<DateTimeField>,
54        /// The seconds precision can be specified in SQL source as
55        /// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field`
56        /// will be `Second` and the `last_field` will be `None`),
57        /// or as `__ TO SECOND(x)`.
58        fractional_seconds_precision: Option<u64>,
59    },
60    /// `NULL` value
61    Null,
62    /// `?` or `$` Prepared statement arg placeholder
63    Placeholder(String),
64}
65
66impl fmt::Display for Value {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        match self {
69            Value::Number(v, l) => write!(f, "{}{long}", v, long = if *l { "L" } else { "" }),
70            Value::DoubleQuotedString(v) => write!(f, "\"{}\"", v),
71            Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
72            Value::NationalStringLiteral(v) => write!(f, "N'{}'", v),
73            Value::HexStringLiteral(v) => write!(f, "X'{}'", v),
74            Value::Boolean(v) => write!(f, "{}", v),
75            Value::Interval {
76                value,
77                leading_field: Some(DateTimeField::Second),
78                leading_precision: Some(leading_precision),
79                last_field,
80                fractional_seconds_precision: Some(fractional_seconds_precision),
81            } => {
82                // When the leading field is SECOND, the parser guarantees that
83                // the last field is None.
84                assert!(last_field.is_none());
85                write!(
86                    f,
87                    "INTERVAL '{}' SECOND ({}, {})",
88                    escape_single_quote_string(value),
89                    leading_precision,
90                    fractional_seconds_precision
91                )
92            }
93            Value::Interval {
94                value,
95                leading_field,
96                leading_precision,
97                last_field,
98                fractional_seconds_precision,
99            } => {
100                write!(f, "INTERVAL '{}'", escape_single_quote_string(value))?;
101                if let Some(leading_field) = leading_field {
102                    write!(f, " {}", leading_field)?;
103                }
104                if let Some(leading_precision) = leading_precision {
105                    write!(f, " ({})", leading_precision)?;
106                }
107                if let Some(last_field) = last_field {
108                    write!(f, " TO {}", last_field)?;
109                }
110                if let Some(fractional_seconds_precision) = fractional_seconds_precision {
111                    write!(f, " ({})", fractional_seconds_precision)?;
112                }
113                Ok(())
114            }
115            Value::Null => write!(f, "NULL"),
116            Value::Placeholder(v) => write!(f, "{}", v),
117        }
118    }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Hash)]
122#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
123pub enum DateTimeField {
124    Year,
125    Month,
126    Day,
127    Hour,
128    Minute,
129    Second,
130}
131
132impl fmt::Display for DateTimeField {
133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134        f.write_str(match self {
135            DateTimeField::Year => "YEAR",
136            DateTimeField::Month => "MONTH",
137            DateTimeField::Day => "DAY",
138            DateTimeField::Hour => "HOUR",
139            DateTimeField::Minute => "MINUTE",
140            DateTimeField::Second => "SECOND",
141        })
142    }
143}
144
145pub struct EscapeSingleQuoteString<'a>(&'a str);
146
147impl<'a> fmt::Display for EscapeSingleQuoteString<'a> {
148    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149        for c in self.0.chars() {
150            if c == '\'' {
151                write!(f, "\'\'")?;
152            } else {
153                write!(f, "{}", c)?;
154            }
155        }
156        Ok(())
157    }
158}
159
160pub fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> {
161    EscapeSingleQuoteString(s)
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, Hash)]
165#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
166pub enum TrimWhereField {
167    Both,
168    Leading,
169    Trailing,
170}
171
172impl fmt::Display for TrimWhereField {
173    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174        use TrimWhereField::*;
175        f.write_str(match self {
176            Both => "BOTH",
177            Leading => "LEADING",
178            Trailing => "TRAILING",
179        })
180    }
181}