sqlparser/ast/
value.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#[cfg(not(feature = "std"))]
19use alloc::string::String;
20
21use core::fmt;
22
23#[cfg(feature = "bigdecimal")]
24use bigdecimal::BigDecimal;
25
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Serialize};
28
29use crate::{ast::Ident, tokenizer::Span};
30#[cfg(feature = "visitor")]
31use sqlparser_derive::{Visit, VisitMut};
32
33/// Wraps a primitive SQL [`Value`]  with its [`Span`] location
34///
35/// # Example: create a `ValueWithSpan` from a `Value`
36/// ```
37/// # use sqlparser::ast::{Value, ValueWithSpan};
38/// # use sqlparser::tokenizer::{Location, Span};
39/// let value = Value::SingleQuotedString(String::from("endpoint"));
40/// // from line 1, column 1 to line 1, column 7
41/// let span = Span::new(Location::new(1, 1), Location::new(1, 7));
42/// let value_with_span = value.with_span(span);
43/// ```
44///
45/// # Example: create a `ValueWithSpan` from a `Value` with an empty span
46///
47/// You can call [`Value::with_empty_span`] to create a `ValueWithSpan` with an empty span
48/// ```
49/// # use sqlparser::ast::{Value, ValueWithSpan};
50/// # use sqlparser::tokenizer::{Location, Span};
51/// let value = Value::SingleQuotedString(String::from("endpoint"));
52/// let value_with_span = value.with_empty_span();
53/// assert_eq!(value_with_span.span, Span::empty());
54/// ```
55///
56/// You can also use the [`From`] trait to convert  `ValueWithSpan` to/from `Value`s
57/// ```
58/// # use sqlparser::ast::{Value, ValueWithSpan};
59/// # use sqlparser::tokenizer::{Location, Span};
60/// let value = Value::SingleQuotedString(String::from("endpoint"));
61/// // converting `Value` to `ValueWithSpan` results in an empty span
62/// let value_with_span: ValueWithSpan = value.into();
63/// assert_eq!(value_with_span.span, Span::empty());
64/// // convert back to `Value`
65/// let value: Value = value_with_span.into();
66/// ```
67#[derive(Debug, Clone, Eq)]
68#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
69#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
70pub struct ValueWithSpan {
71    pub value: Value,
72    pub span: Span,
73}
74
75impl PartialEq for ValueWithSpan {
76    fn eq(&self, other: &Self) -> bool {
77        self.value == other.value
78    }
79}
80
81impl Ord for ValueWithSpan {
82    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
83        self.value.cmp(&other.value)
84    }
85}
86
87impl PartialOrd for ValueWithSpan {
88    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
89        Some(Ord::cmp(self, other))
90    }
91}
92
93impl core::hash::Hash for ValueWithSpan {
94    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
95        self.value.hash(state);
96    }
97}
98
99impl From<Value> for ValueWithSpan {
100    fn from(value: Value) -> Self {
101        value.with_empty_span()
102    }
103}
104
105impl From<ValueWithSpan> for Value {
106    fn from(value: ValueWithSpan) -> Self {
107        value.value
108    }
109}
110
111/// Primitive SQL values such as number and string
112#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
114#[cfg_attr(
115    feature = "visitor",
116    derive(Visit, VisitMut),
117    visit(with = "visit_value")
118)]
119
120pub enum Value {
121    /// Numeric literal
122    #[cfg(not(feature = "bigdecimal"))]
123    Number(String, bool),
124    #[cfg(feature = "bigdecimal")]
125    // HINT: use `test_utils::number` to make an instance of
126    // Value::Number This might help if you your tests pass locally
127    // but fail on CI with the `--all-features` flag enabled
128    Number(BigDecimal, bool),
129    /// 'string value'
130    SingleQuotedString(String),
131    // $<tag_name>$string value$<tag_name>$ (postgres syntax)
132    DollarQuotedString(DollarQuotedString),
133    /// Triple single quoted strings: Example '''abc'''
134    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
135    TripleSingleQuotedString(String),
136    /// Triple double quoted strings: Example """abc"""
137    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
138    TripleDoubleQuotedString(String),
139    /// e'string value' (postgres extension)
140    /// See [Postgres docs](https://www.postgresql.org/docs/8.3/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS)
141    /// for more details.
142    EscapedStringLiteral(String),
143    /// u&'string value' (postgres extension)
144    /// See [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
145    /// for more details.
146    UnicodeStringLiteral(String),
147    /// B'string value'
148    SingleQuotedByteStringLiteral(String),
149    /// B"string value"
150    DoubleQuotedByteStringLiteral(String),
151    /// Triple single quoted literal with byte string prefix. Example `B'''abc'''`
152    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
153    TripleSingleQuotedByteStringLiteral(String),
154    /// Triple double quoted literal with byte string prefix. Example `B"""abc"""`
155    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
156    TripleDoubleQuotedByteStringLiteral(String),
157    /// Single quoted literal with raw string prefix. Example `R'abc'`
158    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
159    SingleQuotedRawStringLiteral(String),
160    /// Double quoted literal with raw string prefix. Example `R"abc"`
161    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
162    DoubleQuotedRawStringLiteral(String),
163    /// Triple single quoted literal with raw string prefix. Example `R'''abc'''`
164    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
165    TripleSingleQuotedRawStringLiteral(String),
166    /// Triple double quoted literal with raw string prefix. Example `R"""abc"""`
167    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
168    TripleDoubleQuotedRawStringLiteral(String),
169    /// N'string value'
170    NationalStringLiteral(String),
171    /// X'hex value'
172    HexStringLiteral(String),
173
174    DoubleQuotedString(String),
175    /// Boolean value true or false
176    Boolean(bool),
177    /// `NULL` value
178    Null,
179    /// `?` or `$` Prepared statement arg placeholder
180    Placeholder(String),
181}
182
183impl ValueWithSpan {
184    /// If the underlying literal is a string, regardless of quote style, returns the associated string value
185    pub fn into_string(self) -> Option<String> {
186        self.value.into_string()
187    }
188}
189
190impl Value {
191    /// If the underlying literal is a string, regardless of quote style, returns the associated string value
192    pub fn into_string(self) -> Option<String> {
193        match self {
194            Value::SingleQuotedString(s)
195            | Value::DoubleQuotedString(s)
196            | Value::TripleSingleQuotedString(s)
197            | Value::TripleDoubleQuotedString(s)
198            | Value::SingleQuotedByteStringLiteral(s)
199            | Value::DoubleQuotedByteStringLiteral(s)
200            | Value::TripleSingleQuotedByteStringLiteral(s)
201            | Value::TripleDoubleQuotedByteStringLiteral(s)
202            | Value::SingleQuotedRawStringLiteral(s)
203            | Value::DoubleQuotedRawStringLiteral(s)
204            | Value::TripleSingleQuotedRawStringLiteral(s)
205            | Value::TripleDoubleQuotedRawStringLiteral(s)
206            | Value::EscapedStringLiteral(s)
207            | Value::UnicodeStringLiteral(s)
208            | Value::NationalStringLiteral(s)
209            | Value::HexStringLiteral(s) => Some(s),
210            Value::DollarQuotedString(s) => Some(s.value),
211            _ => None,
212        }
213    }
214
215    pub fn with_span(self, span: Span) -> ValueWithSpan {
216        ValueWithSpan { value: self, span }
217    }
218
219    pub fn with_empty_span(self) -> ValueWithSpan {
220        self.with_span(Span::empty())
221    }
222}
223
224impl fmt::Display for ValueWithSpan {
225    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226        write!(f, "{}", self.value)
227    }
228}
229
230impl fmt::Display for Value {
231    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232        match self {
233            Value::Number(v, l) => write!(f, "{}{long}", v, long = if *l { "L" } else { "" }),
234            Value::DoubleQuotedString(v) => write!(f, "\"{}\"", escape_double_quote_string(v)),
235            Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
236            Value::TripleSingleQuotedString(v) => {
237                write!(f, "'''{v}'''")
238            }
239            Value::TripleDoubleQuotedString(v) => {
240                write!(f, r#""""{v}""""#)
241            }
242            Value::DollarQuotedString(v) => write!(f, "{v}"),
243            Value::EscapedStringLiteral(v) => write!(f, "E'{}'", escape_escaped_string(v)),
244            Value::UnicodeStringLiteral(v) => write!(f, "U&'{}'", escape_unicode_string(v)),
245            Value::NationalStringLiteral(v) => write!(f, "N'{v}'"),
246            Value::HexStringLiteral(v) => write!(f, "X'{v}'"),
247            Value::Boolean(v) => write!(f, "{v}"),
248            Value::SingleQuotedByteStringLiteral(v) => write!(f, "B'{v}'"),
249            Value::DoubleQuotedByteStringLiteral(v) => write!(f, "B\"{v}\""),
250            Value::TripleSingleQuotedByteStringLiteral(v) => write!(f, "B'''{v}'''"),
251            Value::TripleDoubleQuotedByteStringLiteral(v) => write!(f, r#"B"""{v}""""#),
252            Value::SingleQuotedRawStringLiteral(v) => write!(f, "R'{v}'"),
253            Value::DoubleQuotedRawStringLiteral(v) => write!(f, "R\"{v}\""),
254            Value::TripleSingleQuotedRawStringLiteral(v) => write!(f, "R'''{v}'''"),
255            Value::TripleDoubleQuotedRawStringLiteral(v) => write!(f, r#"R"""{v}""""#),
256            Value::Null => write!(f, "NULL"),
257            Value::Placeholder(v) => write!(f, "{v}"),
258        }
259    }
260}
261
262#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
263#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
264#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
265pub struct DollarQuotedString {
266    pub value: String,
267    pub tag: Option<String>,
268}
269
270impl fmt::Display for DollarQuotedString {
271    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272        match &self.tag {
273            Some(tag) => {
274                write!(f, "${}${}${}$", tag, self.value, tag)
275            }
276            None => {
277                write!(f, "$${}$$", self.value)
278            }
279        }
280    }
281}
282
283#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
284#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
285#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
286pub enum DateTimeField {
287    Year,
288    Years,
289    Month,
290    Months,
291    /// Week optionally followed by a WEEKDAY.
292    ///
293    /// ```sql
294    /// WEEK(MONDAY)
295    /// ```
296    ///
297    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions#extract)
298    Week(Option<Ident>),
299    Weeks,
300    Day,
301    DayOfWeek,
302    DayOfYear,
303    Days,
304    Date,
305    Datetime,
306    Hour,
307    Hours,
308    Minute,
309    Minutes,
310    Second,
311    Seconds,
312    Century,
313    Decade,
314    Dow,
315    Doy,
316    Epoch,
317    Isodow,
318    IsoWeek,
319    Isoyear,
320    Julian,
321    Microsecond,
322    Microseconds,
323    Millenium,
324    Millennium,
325    Millisecond,
326    Milliseconds,
327    Nanosecond,
328    Nanoseconds,
329    Quarter,
330    Time,
331    Timezone,
332    TimezoneAbbr,
333    TimezoneHour,
334    TimezoneMinute,
335    TimezoneRegion,
336    NoDateTime,
337    /// Arbitrary abbreviation or custom date-time part.
338    ///
339    /// ```sql
340    /// EXTRACT(q FROM CURRENT_TIMESTAMP)
341    /// ```
342    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/functions-date-time#supported-date-and-time-parts)
343    Custom(Ident),
344}
345
346impl fmt::Display for DateTimeField {
347    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348        match self {
349            DateTimeField::Year => write!(f, "YEAR"),
350            DateTimeField::Years => write!(f, "YEARS"),
351            DateTimeField::Month => write!(f, "MONTH"),
352            DateTimeField::Months => write!(f, "MONTHS"),
353            DateTimeField::Week(week_day) => {
354                write!(f, "WEEK")?;
355                if let Some(week_day) = week_day {
356                    write!(f, "({week_day})")?
357                }
358                Ok(())
359            }
360            DateTimeField::Weeks => write!(f, "WEEKS"),
361            DateTimeField::Day => write!(f, "DAY"),
362            DateTimeField::DayOfWeek => write!(f, "DAYOFWEEK"),
363            DateTimeField::DayOfYear => write!(f, "DAYOFYEAR"),
364            DateTimeField::Days => write!(f, "DAYS"),
365            DateTimeField::Date => write!(f, "DATE"),
366            DateTimeField::Datetime => write!(f, "DATETIME"),
367            DateTimeField::Hour => write!(f, "HOUR"),
368            DateTimeField::Hours => write!(f, "HOURS"),
369            DateTimeField::Minute => write!(f, "MINUTE"),
370            DateTimeField::Minutes => write!(f, "MINUTES"),
371            DateTimeField::Second => write!(f, "SECOND"),
372            DateTimeField::Seconds => write!(f, "SECONDS"),
373            DateTimeField::Century => write!(f, "CENTURY"),
374            DateTimeField::Decade => write!(f, "DECADE"),
375            DateTimeField::Dow => write!(f, "DOW"),
376            DateTimeField::Doy => write!(f, "DOY"),
377            DateTimeField::Epoch => write!(f, "EPOCH"),
378            DateTimeField::Isodow => write!(f, "ISODOW"),
379            DateTimeField::Isoyear => write!(f, "ISOYEAR"),
380            DateTimeField::IsoWeek => write!(f, "ISOWEEK"),
381            DateTimeField::Julian => write!(f, "JULIAN"),
382            DateTimeField::Microsecond => write!(f, "MICROSECOND"),
383            DateTimeField::Microseconds => write!(f, "MICROSECONDS"),
384            DateTimeField::Millenium => write!(f, "MILLENIUM"),
385            DateTimeField::Millennium => write!(f, "MILLENNIUM"),
386            DateTimeField::Millisecond => write!(f, "MILLISECOND"),
387            DateTimeField::Milliseconds => write!(f, "MILLISECONDS"),
388            DateTimeField::Nanosecond => write!(f, "NANOSECOND"),
389            DateTimeField::Nanoseconds => write!(f, "NANOSECONDS"),
390            DateTimeField::Quarter => write!(f, "QUARTER"),
391            DateTimeField::Time => write!(f, "TIME"),
392            DateTimeField::Timezone => write!(f, "TIMEZONE"),
393            DateTimeField::TimezoneAbbr => write!(f, "TIMEZONE_ABBR"),
394            DateTimeField::TimezoneHour => write!(f, "TIMEZONE_HOUR"),
395            DateTimeField::TimezoneMinute => write!(f, "TIMEZONE_MINUTE"),
396            DateTimeField::TimezoneRegion => write!(f, "TIMEZONE_REGION"),
397            DateTimeField::NoDateTime => write!(f, "NODATETIME"),
398            DateTimeField::Custom(custom) => write!(f, "{custom}"),
399        }
400    }
401}
402
403#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
404#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
405#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
406/// The Unicode Standard defines four normalization forms, which are intended to eliminate
407/// certain distinctions between visually or functionally identical characters.
408///
409/// See [Unicode Normalization Forms](https://unicode.org/reports/tr15/) for details.
410pub enum NormalizationForm {
411    /// Canonical Decomposition, followed by Canonical Composition.
412    NFC,
413    /// Canonical Decomposition.
414    NFD,
415    /// Compatibility Decomposition, followed by Canonical Composition.
416    NFKC,
417    /// Compatibility Decomposition.
418    NFKD,
419}
420
421impl fmt::Display for NormalizationForm {
422    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
423        match self {
424            NormalizationForm::NFC => write!(f, "NFC"),
425            NormalizationForm::NFD => write!(f, "NFD"),
426            NormalizationForm::NFKC => write!(f, "NFKC"),
427            NormalizationForm::NFKD => write!(f, "NFKD"),
428        }
429    }
430}
431
432pub struct EscapeQuotedString<'a> {
433    string: &'a str,
434    quote: char,
435}
436
437impl fmt::Display for EscapeQuotedString<'_> {
438    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
439        // EscapeQuotedString doesn't know which mode of escape was
440        // chosen by the user. So this code must to correctly display
441        // strings without knowing if the strings are already escaped
442        // or not.
443        //
444        // If the quote symbol in the string is repeated twice, OR, if
445        // the quote symbol is after backslash, display all the chars
446        // without any escape. However, if the quote symbol is used
447        // just between usual chars, `fmt()` should display it twice."
448        //
449        // The following table has examples
450        //
451        // | original query | mode      | AST Node                                           | serialized   |
452        // | -------------  | --------- | -------------------------------------------------- | ------------ |
453        // | `"A""B""A"`    | no-escape | `DoubleQuotedString(String::from("A\"\"B\"\"A"))`  | `"A""B""A"`  |
454        // | `"A""B""A"`    | default   | `DoubleQuotedString(String::from("A\"B\"A"))`      | `"A""B""A"`  |
455        // | `"A\"B\"A"`    | no-escape | `DoubleQuotedString(String::from("A\\\"B\\\"A"))`  | `"A\"B\"A"`  |
456        // | `"A\"B\"A"`    | default   | `DoubleQuotedString(String::from("A\"B\"A"))`      | `"A""B""A"`  |
457        let quote = self.quote;
458        let mut previous_char = char::default();
459        let mut peekable_chars = self.string.chars().peekable();
460        while let Some(&ch) = peekable_chars.peek() {
461            match ch {
462                char if char == quote => {
463                    if previous_char == '\\' {
464                        write!(f, "{char}")?;
465                        peekable_chars.next();
466                        continue;
467                    }
468                    peekable_chars.next();
469                    if peekable_chars.peek().map(|c| *c == quote).unwrap_or(false) {
470                        write!(f, "{char}{char}")?;
471                        peekable_chars.next();
472                    } else {
473                        write!(f, "{char}{char}")?;
474                    }
475                }
476                _ => {
477                    write!(f, "{ch}")?;
478                    peekable_chars.next();
479                }
480            }
481            previous_char = ch;
482        }
483        Ok(())
484    }
485}
486
487pub fn escape_quoted_string(string: &str, quote: char) -> EscapeQuotedString<'_> {
488    EscapeQuotedString { string, quote }
489}
490
491pub fn escape_single_quote_string(s: &str) -> EscapeQuotedString<'_> {
492    escape_quoted_string(s, '\'')
493}
494
495pub fn escape_double_quote_string(s: &str) -> EscapeQuotedString<'_> {
496    escape_quoted_string(s, '\"')
497}
498
499pub struct EscapeEscapedStringLiteral<'a>(&'a str);
500
501impl fmt::Display for EscapeEscapedStringLiteral<'_> {
502    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503        for c in self.0.chars() {
504            match c {
505                '\'' => {
506                    write!(f, r#"\'"#)?;
507                }
508                '\\' => {
509                    write!(f, r#"\\"#)?;
510                }
511                '\n' => {
512                    write!(f, r#"\n"#)?;
513                }
514                '\t' => {
515                    write!(f, r#"\t"#)?;
516                }
517                '\r' => {
518                    write!(f, r#"\r"#)?;
519                }
520                _ => {
521                    write!(f, "{c}")?;
522                }
523            }
524        }
525        Ok(())
526    }
527}
528
529pub fn escape_escaped_string(s: &str) -> EscapeEscapedStringLiteral<'_> {
530    EscapeEscapedStringLiteral(s)
531}
532
533pub struct EscapeUnicodeStringLiteral<'a>(&'a str);
534
535impl fmt::Display for EscapeUnicodeStringLiteral<'_> {
536    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
537        for c in self.0.chars() {
538            match c {
539                '\'' => {
540                    write!(f, "''")?;
541                }
542                '\\' => {
543                    write!(f, r#"\\"#)?;
544                }
545                x if x.is_ascii() => {
546                    write!(f, "{}", c)?;
547                }
548                _ => {
549                    let codepoint = c as u32;
550                    // if the character fits in 32 bits, we can use the \XXXX format
551                    // otherwise, we need to use the \+XXXXXX format
552                    if codepoint <= 0xFFFF {
553                        write!(f, "\\{:04X}", codepoint)?;
554                    } else {
555                        write!(f, "\\+{:06X}", codepoint)?;
556                    }
557                }
558            }
559        }
560        Ok(())
561    }
562}
563
564pub fn escape_unicode_string(s: &str) -> EscapeUnicodeStringLiteral<'_> {
565    EscapeUnicodeStringLiteral(s)
566}
567
568#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
569#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
570#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
571pub enum TrimWhereField {
572    Both,
573    Leading,
574    Trailing,
575}
576
577impl fmt::Display for TrimWhereField {
578    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
579        use TrimWhereField::*;
580        f.write_str(match self {
581            Both => "BOTH",
582            Leading => "LEADING",
583            Trailing => "TRAILING",
584        })
585    }
586}