Skip to main content

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)]
119pub enum Value {
120    /// Numeric literal
121    #[cfg(not(feature = "bigdecimal"))]
122    Number(String, bool),
123    #[cfg(feature = "bigdecimal")]
124    // HINT: use `test_utils::number` to make an instance of
125    // Value::Number This might help if you your tests pass locally
126    // but fail on CI with the `--all-features` flag enabled
127    Number(BigDecimal, bool),
128    /// 'string value'
129    SingleQuotedString(String),
130    // $<tag_name>$string value$<tag_name>$ (postgres syntax)
131    DollarQuotedString(DollarQuotedString),
132    /// Triple single quoted strings: Example '''abc'''
133    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
134    TripleSingleQuotedString(String),
135    /// Triple double quoted strings: Example """abc"""
136    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
137    TripleDoubleQuotedString(String),
138    /// e'string value' (postgres extension)
139    /// See [Postgres docs](https://www.postgresql.org/docs/8.3/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS)
140    /// for more details.
141    EscapedStringLiteral(String),
142    /// u&'string value' (postgres extension)
143    /// See [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
144    /// for more details.
145    UnicodeStringLiteral(String),
146    /// B'string value'
147    SingleQuotedByteStringLiteral(String),
148    /// B"string value"
149    DoubleQuotedByteStringLiteral(String),
150    /// Triple single quoted literal with byte string prefix. Example `B'''abc'''`
151    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
152    TripleSingleQuotedByteStringLiteral(String),
153    /// Triple double quoted literal with byte string prefix. Example `B"""abc"""`
154    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
155    TripleDoubleQuotedByteStringLiteral(String),
156    /// Single quoted literal with raw string prefix. Example `R'abc'`
157    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
158    SingleQuotedRawStringLiteral(String),
159    /// Double quoted literal with raw string prefix. Example `R"abc"`
160    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
161    DoubleQuotedRawStringLiteral(String),
162    /// Triple single quoted literal with raw string prefix. Example `R'''abc'''`
163    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
164    TripleSingleQuotedRawStringLiteral(String),
165    /// Triple double quoted literal with raw string prefix. Example `R"""abc"""`
166    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
167    TripleDoubleQuotedRawStringLiteral(String),
168    /// N'string value'
169    NationalStringLiteral(String),
170    /// Quote delimited literal. Examples `Q'{ab'c}'`, `Q'|ab'c|'`, `Q'|ab|c|'`
171    /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Literals.html#GUID-1824CBAA-6E16-4921-B2A6-112FB02248DA)
172    QuoteDelimitedStringLiteral(QuoteDelimitedString),
173    /// "National" quote delimited literal. Examples `Q'{ab'c}'`, `Q'|ab'c|'`, `Q'|ab|c|'`
174    /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Literals.html#GUID-1824CBAA-6E16-4921-B2A6-112FB02248DA)
175    NationalQuoteDelimitedStringLiteral(QuoteDelimitedString),
176    /// X'hex value'
177    HexStringLiteral(String),
178
179    DoubleQuotedString(String),
180    /// Boolean value true or false
181    Boolean(bool),
182    /// `NULL` value
183    Null,
184    /// `?` or `$` Prepared statement arg placeholder
185    Placeholder(String),
186}
187
188impl ValueWithSpan {
189    /// If the underlying literal is a string, regardless of quote style, returns the associated string value
190    pub fn into_string(self) -> Option<String> {
191        self.value.into_string()
192    }
193}
194
195impl Value {
196    /// If the underlying literal is a string, regardless of quote style, returns the associated string value
197    pub fn into_string(self) -> Option<String> {
198        match self {
199            Value::SingleQuotedString(s)
200            | Value::DoubleQuotedString(s)
201            | Value::TripleSingleQuotedString(s)
202            | Value::TripleDoubleQuotedString(s)
203            | Value::SingleQuotedByteStringLiteral(s)
204            | Value::DoubleQuotedByteStringLiteral(s)
205            | Value::TripleSingleQuotedByteStringLiteral(s)
206            | Value::TripleDoubleQuotedByteStringLiteral(s)
207            | Value::SingleQuotedRawStringLiteral(s)
208            | Value::DoubleQuotedRawStringLiteral(s)
209            | Value::TripleSingleQuotedRawStringLiteral(s)
210            | Value::TripleDoubleQuotedRawStringLiteral(s)
211            | Value::EscapedStringLiteral(s)
212            | Value::UnicodeStringLiteral(s)
213            | Value::NationalStringLiteral(s)
214            | Value::HexStringLiteral(s) => Some(s),
215            Value::DollarQuotedString(s) => Some(s.value),
216            Value::QuoteDelimitedStringLiteral(s) => Some(s.value),
217            Value::NationalQuoteDelimitedStringLiteral(s) => Some(s.value),
218            _ => None,
219        }
220    }
221
222    pub fn with_span(self, span: Span) -> ValueWithSpan {
223        ValueWithSpan { value: self, span }
224    }
225
226    pub fn with_empty_span(self) -> ValueWithSpan {
227        self.with_span(Span::empty())
228    }
229}
230
231impl fmt::Display for ValueWithSpan {
232    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
233        write!(f, "{}", self.value)
234    }
235}
236
237impl fmt::Display for Value {
238    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
239        match self {
240            Value::Number(v, l) => write!(f, "{}{long}", v, long = if *l { "L" } else { "" }),
241            Value::DoubleQuotedString(v) => write!(f, "\"{}\"", escape_double_quote_string(v)),
242            Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
243            Value::TripleSingleQuotedString(v) => {
244                write!(f, "'''{v}'''")
245            }
246            Value::TripleDoubleQuotedString(v) => {
247                write!(f, r#""""{v}""""#)
248            }
249            Value::DollarQuotedString(v) => write!(f, "{v}"),
250            Value::EscapedStringLiteral(v) => write!(f, "E'{}'", escape_escaped_string(v)),
251            Value::UnicodeStringLiteral(v) => write!(f, "U&'{}'", escape_unicode_string(v)),
252            Value::NationalStringLiteral(v) => write!(f, "N'{v}'"),
253            Value::QuoteDelimitedStringLiteral(v) => v.fmt(f),
254            Value::NationalQuoteDelimitedStringLiteral(v) => write!(f, "N{v}"),
255            Value::HexStringLiteral(v) => write!(f, "X'{v}'"),
256            Value::Boolean(v) => write!(f, "{v}"),
257            Value::SingleQuotedByteStringLiteral(v) => write!(f, "B'{v}'"),
258            Value::DoubleQuotedByteStringLiteral(v) => write!(f, "B\"{v}\""),
259            Value::TripleSingleQuotedByteStringLiteral(v) => write!(f, "B'''{v}'''"),
260            Value::TripleDoubleQuotedByteStringLiteral(v) => write!(f, r#"B"""{v}""""#),
261            Value::SingleQuotedRawStringLiteral(v) => write!(f, "R'{v}'"),
262            Value::DoubleQuotedRawStringLiteral(v) => write!(f, "R\"{v}\""),
263            Value::TripleSingleQuotedRawStringLiteral(v) => write!(f, "R'''{v}'''"),
264            Value::TripleDoubleQuotedRawStringLiteral(v) => write!(f, r#"R"""{v}""""#),
265            Value::Null => write!(f, "NULL"),
266            Value::Placeholder(v) => write!(f, "{v}"),
267        }
268    }
269}
270
271#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
272#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
273#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
274pub struct DollarQuotedString {
275    pub value: String,
276    pub tag: Option<String>,
277}
278
279impl fmt::Display for DollarQuotedString {
280    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
281        match &self.tag {
282            Some(tag) => {
283                write!(f, "${}${}${}$", tag, self.value, tag)
284            }
285            None => {
286                write!(f, "$${}$$", self.value)
287            }
288        }
289    }
290}
291
292/// A quote delimited string literal, e.g. `Q'_abc_'`.
293///
294/// See [Value::QuoteDelimitedStringLiteral] and/or
295/// [Value::NationalQuoteDelimitedStringLiteral].
296#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
297#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
298#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
299pub struct QuoteDelimitedString {
300    /// the quote start character; i.e. the character _after_ the opening `Q'`
301    pub start_quote: char,
302    /// the string literal value itself
303    pub value: String,
304    /// the quote end character; i.e. the character _before_ the closing `'`
305    pub end_quote: char,
306}
307
308impl fmt::Display for QuoteDelimitedString {
309    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310        write!(f, "Q'{}{}{}'", self.start_quote, self.value, self.end_quote)
311    }
312}
313
314#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
315#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
316#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
317pub enum DateTimeField {
318    Year,
319    Years,
320    Month,
321    Months,
322    /// Week optionally followed by a WEEKDAY.
323    ///
324    /// ```sql
325    /// WEEK(MONDAY)
326    /// ```
327    ///
328    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions#extract)
329    Week(Option<Ident>),
330    Weeks,
331    Day,
332    DayOfWeek,
333    DayOfYear,
334    Days,
335    Date,
336    Datetime,
337    Hour,
338    Hours,
339    Minute,
340    Minutes,
341    Second,
342    Seconds,
343    Century,
344    Decade,
345    Dow,
346    Doy,
347    Epoch,
348    Isodow,
349    IsoWeek,
350    Isoyear,
351    Julian,
352    Microsecond,
353    Microseconds,
354    Millenium,
355    Millennium,
356    Millisecond,
357    Milliseconds,
358    Nanosecond,
359    Nanoseconds,
360    Quarter,
361    Time,
362    Timezone,
363    TimezoneAbbr,
364    TimezoneHour,
365    TimezoneMinute,
366    TimezoneRegion,
367    NoDateTime,
368    /// Arbitrary abbreviation or custom date-time part.
369    ///
370    /// ```sql
371    /// EXTRACT(q FROM CURRENT_TIMESTAMP)
372    /// ```
373    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/functions-date-time#supported-date-and-time-parts)
374    Custom(Ident),
375}
376
377impl fmt::Display for DateTimeField {
378    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
379        match self {
380            DateTimeField::Year => write!(f, "YEAR"),
381            DateTimeField::Years => write!(f, "YEARS"),
382            DateTimeField::Month => write!(f, "MONTH"),
383            DateTimeField::Months => write!(f, "MONTHS"),
384            DateTimeField::Week(week_day) => {
385                write!(f, "WEEK")?;
386                if let Some(week_day) = week_day {
387                    write!(f, "({week_day})")?
388                }
389                Ok(())
390            }
391            DateTimeField::Weeks => write!(f, "WEEKS"),
392            DateTimeField::Day => write!(f, "DAY"),
393            DateTimeField::DayOfWeek => write!(f, "DAYOFWEEK"),
394            DateTimeField::DayOfYear => write!(f, "DAYOFYEAR"),
395            DateTimeField::Days => write!(f, "DAYS"),
396            DateTimeField::Date => write!(f, "DATE"),
397            DateTimeField::Datetime => write!(f, "DATETIME"),
398            DateTimeField::Hour => write!(f, "HOUR"),
399            DateTimeField::Hours => write!(f, "HOURS"),
400            DateTimeField::Minute => write!(f, "MINUTE"),
401            DateTimeField::Minutes => write!(f, "MINUTES"),
402            DateTimeField::Second => write!(f, "SECOND"),
403            DateTimeField::Seconds => write!(f, "SECONDS"),
404            DateTimeField::Century => write!(f, "CENTURY"),
405            DateTimeField::Decade => write!(f, "DECADE"),
406            DateTimeField::Dow => write!(f, "DOW"),
407            DateTimeField::Doy => write!(f, "DOY"),
408            DateTimeField::Epoch => write!(f, "EPOCH"),
409            DateTimeField::Isodow => write!(f, "ISODOW"),
410            DateTimeField::Isoyear => write!(f, "ISOYEAR"),
411            DateTimeField::IsoWeek => write!(f, "ISOWEEK"),
412            DateTimeField::Julian => write!(f, "JULIAN"),
413            DateTimeField::Microsecond => write!(f, "MICROSECOND"),
414            DateTimeField::Microseconds => write!(f, "MICROSECONDS"),
415            DateTimeField::Millenium => write!(f, "MILLENIUM"),
416            DateTimeField::Millennium => write!(f, "MILLENNIUM"),
417            DateTimeField::Millisecond => write!(f, "MILLISECOND"),
418            DateTimeField::Milliseconds => write!(f, "MILLISECONDS"),
419            DateTimeField::Nanosecond => write!(f, "NANOSECOND"),
420            DateTimeField::Nanoseconds => write!(f, "NANOSECONDS"),
421            DateTimeField::Quarter => write!(f, "QUARTER"),
422            DateTimeField::Time => write!(f, "TIME"),
423            DateTimeField::Timezone => write!(f, "TIMEZONE"),
424            DateTimeField::TimezoneAbbr => write!(f, "TIMEZONE_ABBR"),
425            DateTimeField::TimezoneHour => write!(f, "TIMEZONE_HOUR"),
426            DateTimeField::TimezoneMinute => write!(f, "TIMEZONE_MINUTE"),
427            DateTimeField::TimezoneRegion => write!(f, "TIMEZONE_REGION"),
428            DateTimeField::NoDateTime => write!(f, "NODATETIME"),
429            DateTimeField::Custom(custom) => write!(f, "{custom}"),
430        }
431    }
432}
433
434#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
435#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
436#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
437/// The Unicode Standard defines four normalization forms, which are intended to eliminate
438/// certain distinctions between visually or functionally identical characters.
439///
440/// See [Unicode Normalization Forms](https://unicode.org/reports/tr15/) for details.
441pub enum NormalizationForm {
442    /// Canonical Decomposition, followed by Canonical Composition.
443    NFC,
444    /// Canonical Decomposition.
445    NFD,
446    /// Compatibility Decomposition, followed by Canonical Composition.
447    NFKC,
448    /// Compatibility Decomposition.
449    NFKD,
450}
451
452impl fmt::Display for NormalizationForm {
453    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
454        match self {
455            NormalizationForm::NFC => write!(f, "NFC"),
456            NormalizationForm::NFD => write!(f, "NFD"),
457            NormalizationForm::NFKC => write!(f, "NFKC"),
458            NormalizationForm::NFKD => write!(f, "NFKD"),
459        }
460    }
461}
462
463pub struct EscapeQuotedString<'a> {
464    string: &'a str,
465    quote: char,
466}
467
468impl fmt::Display for EscapeQuotedString<'_> {
469    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
470        // EscapeQuotedString doesn't know which mode of escape was
471        // chosen by the user. So this code must to correctly display
472        // strings without knowing if the strings are already escaped
473        // or not.
474        //
475        // If the quote symbol in the string is repeated twice, OR, if
476        // the quote symbol is after backslash, display all the chars
477        // without any escape. However, if the quote symbol is used
478        // just between usual chars, `fmt()` should display it twice."
479        //
480        // The following table has examples
481        //
482        // | original query | mode      | AST Node                                           | serialized   |
483        // | -------------  | --------- | -------------------------------------------------- | ------------ |
484        // | `"A""B""A"`    | no-escape | `DoubleQuotedString(String::from("A\"\"B\"\"A"))`  | `"A""B""A"`  |
485        // | `"A""B""A"`    | default   | `DoubleQuotedString(String::from("A\"B\"A"))`      | `"A""B""A"`  |
486        // | `"A\"B\"A"`    | no-escape | `DoubleQuotedString(String::from("A\\\"B\\\"A"))`  | `"A\"B\"A"`  |
487        // | `"A\"B\"A"`    | default   | `DoubleQuotedString(String::from("A\"B\"A"))`      | `"A""B""A"`  |
488        let quote = self.quote;
489        let mut previous_char = char::default();
490        let mut start_idx = 0;
491        let mut peekable_chars = self.string.char_indices().peekable();
492        while let Some(&(idx, ch)) = peekable_chars.peek() {
493            match ch {
494                char if char == quote => {
495                    if previous_char == '\\' {
496                        // the quote is already escaped with a backslash, skip
497                        peekable_chars.next();
498                        continue;
499                    }
500                    peekable_chars.next();
501                    match peekable_chars.peek() {
502                        Some((_, c)) if *c == quote => {
503                            // the quote is already escaped with another quote, skip
504                            peekable_chars.next();
505                        }
506                        _ => {
507                            // The quote is not escaped.
508                            // Including idx in the range, so the quote at idx will be printed twice:
509                            // in this call to write_str() and in the next one.
510                            f.write_str(&self.string[start_idx..=idx])?;
511                            start_idx = idx;
512                        }
513                    }
514                }
515                _ => {
516                    peekable_chars.next();
517                }
518            }
519            previous_char = ch;
520        }
521        f.write_str(&self.string[start_idx..])?;
522        Ok(())
523    }
524}
525
526pub fn escape_quoted_string(string: &str, quote: char) -> EscapeQuotedString<'_> {
527    EscapeQuotedString { string, quote }
528}
529
530pub fn escape_single_quote_string(s: &str) -> EscapeQuotedString<'_> {
531    escape_quoted_string(s, '\'')
532}
533
534pub fn escape_double_quote_string(s: &str) -> EscapeQuotedString<'_> {
535    escape_quoted_string(s, '\"')
536}
537
538pub struct EscapeEscapedStringLiteral<'a>(&'a str);
539
540impl fmt::Display for EscapeEscapedStringLiteral<'_> {
541    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
542        for c in self.0.chars() {
543            match c {
544                '\'' => {
545                    write!(f, r#"\'"#)?;
546                }
547                '\\' => {
548                    write!(f, r#"\\"#)?;
549                }
550                '\n' => {
551                    write!(f, r#"\n"#)?;
552                }
553                '\t' => {
554                    write!(f, r#"\t"#)?;
555                }
556                '\r' => {
557                    write!(f, r#"\r"#)?;
558                }
559                _ => {
560                    write!(f, "{c}")?;
561                }
562            }
563        }
564        Ok(())
565    }
566}
567
568pub fn escape_escaped_string(s: &str) -> EscapeEscapedStringLiteral<'_> {
569    EscapeEscapedStringLiteral(s)
570}
571
572pub struct EscapeUnicodeStringLiteral<'a>(&'a str);
573
574impl fmt::Display for EscapeUnicodeStringLiteral<'_> {
575    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
576        for c in self.0.chars() {
577            match c {
578                '\'' => {
579                    write!(f, "''")?;
580                }
581                '\\' => {
582                    write!(f, r#"\\"#)?;
583                }
584                x if x.is_ascii() => {
585                    write!(f, "{c}")?;
586                }
587                _ => {
588                    let codepoint = c as u32;
589                    // if the character fits in 32 bits, we can use the \XXXX format
590                    // otherwise, we need to use the \+XXXXXX format
591                    if codepoint <= 0xFFFF {
592                        write!(f, "\\{codepoint:04X}")?;
593                    } else {
594                        write!(f, "\\+{codepoint:06X}")?;
595                    }
596                }
597            }
598        }
599        Ok(())
600    }
601}
602
603pub fn escape_unicode_string(s: &str) -> EscapeUnicodeStringLiteral<'_> {
604    EscapeUnicodeStringLiteral(s)
605}
606
607#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
608#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
609#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
610pub enum TrimWhereField {
611    Both,
612    Leading,
613    Trailing,
614}
615
616impl fmt::Display for TrimWhereField {
617    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
618        use TrimWhereField::*;
619        f.write_str(match self {
620            Both => "BOTH",
621            Leading => "LEADING",
622            Trailing => "TRAILING",
623        })
624    }
625}