mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-15 16:29:02 +00:00
157 lines
5.5 KiB
Rust
157 lines
5.5 KiB
Rust
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use ordered_float::OrderedFloat;
|
|
use std::fmt;
|
|
|
|
/// Primitive SQL values such as number and string
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum Value {
|
|
/// Unsigned integer value
|
|
Long(u64),
|
|
/// Unsigned floating point value
|
|
Double(OrderedFloat<f64>),
|
|
/// 'string value'
|
|
SingleQuotedString(String),
|
|
/// N'string value'
|
|
NationalStringLiteral(String),
|
|
/// X'hex value'
|
|
HexStringLiteral(String),
|
|
/// Boolean value true or false
|
|
Boolean(bool),
|
|
/// `DATE '...'` literals
|
|
Date(String),
|
|
/// `TIME '...'` literals
|
|
Time(String),
|
|
/// `TIMESTAMP '...'` literals
|
|
Timestamp(String),
|
|
/// INTERVAL literals, roughly in the following format:
|
|
/// `INTERVAL '<value>' <leading_field> [ (<leading_precision>) ]
|
|
/// [ TO <last_field> [ (<fractional_seconds_precision>) ] ]`,
|
|
/// e.g. `INTERVAL '123:45.67' MINUTE(3) TO SECOND(2)`.
|
|
///
|
|
/// The parser does not validate the `<value>`, nor does it ensure
|
|
/// that the `<leading_field>` units >= the units in `<last_field>`,
|
|
/// so the user will have to reject intervals like `HOUR TO YEAR`.
|
|
Interval {
|
|
value: String,
|
|
leading_field: DateTimeField,
|
|
leading_precision: Option<u64>,
|
|
last_field: Option<DateTimeField>,
|
|
/// The seconds precision can be specified in SQL source as
|
|
/// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field`
|
|
/// will be `Second` and the `last_field` will be `None`),
|
|
/// or as `__ TO SECOND(x)`.
|
|
fractional_seconds_precision: Option<u64>,
|
|
},
|
|
/// `NULL` value
|
|
Null,
|
|
}
|
|
|
|
impl fmt::Display for Value {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Value::Long(v) => write!(f, "{}", v),
|
|
Value::Double(v) => write!(f, "{}", v),
|
|
Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
|
|
Value::NationalStringLiteral(v) => write!(f, "N'{}'", v),
|
|
Value::HexStringLiteral(v) => write!(f, "X'{}'", v),
|
|
Value::Boolean(v) => write!(f, "{}", v),
|
|
Value::Date(v) => write!(f, "DATE '{}'", escape_single_quote_string(v)),
|
|
Value::Time(v) => write!(f, "TIME '{}'", escape_single_quote_string(v)),
|
|
Value::Timestamp(v) => write!(f, "TIMESTAMP '{}'", escape_single_quote_string(v)),
|
|
Value::Interval {
|
|
value,
|
|
leading_field: DateTimeField::Second,
|
|
leading_precision: Some(leading_precision),
|
|
last_field,
|
|
fractional_seconds_precision: Some(fractional_seconds_precision),
|
|
} => {
|
|
// When the leading field is SECOND, the parser guarantees that
|
|
// the last field is None.
|
|
assert!(last_field.is_none());
|
|
write!(
|
|
f,
|
|
"INTERVAL '{}' SECOND ({}, {})",
|
|
escape_single_quote_string(value),
|
|
leading_precision,
|
|
fractional_seconds_precision
|
|
)
|
|
}
|
|
Value::Interval {
|
|
value,
|
|
leading_field,
|
|
leading_precision,
|
|
last_field,
|
|
fractional_seconds_precision,
|
|
} => {
|
|
write!(
|
|
f,
|
|
"INTERVAL '{}' {}",
|
|
escape_single_quote_string(value),
|
|
leading_field
|
|
)?;
|
|
if let Some(leading_precision) = leading_precision {
|
|
write!(f, " ({})", leading_precision)?;
|
|
}
|
|
if let Some(last_field) = last_field {
|
|
write!(f, " TO {}", last_field)?;
|
|
}
|
|
if let Some(fractional_seconds_precision) = fractional_seconds_precision {
|
|
write!(f, " ({})", fractional_seconds_precision)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
Value::Null => write!(f, "NULL"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum DateTimeField {
|
|
Year,
|
|
Month,
|
|
Day,
|
|
Hour,
|
|
Minute,
|
|
Second,
|
|
}
|
|
|
|
impl fmt::Display for DateTimeField {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.write_str(match self {
|
|
DateTimeField::Year => "YEAR",
|
|
DateTimeField::Month => "MONTH",
|
|
DateTimeField::Day => "DAY",
|
|
DateTimeField::Hour => "HOUR",
|
|
DateTimeField::Minute => "MINUTE",
|
|
DateTimeField::Second => "SECOND",
|
|
})
|
|
}
|
|
}
|
|
|
|
struct EscapeSingleQuoteString<'a>(&'a str);
|
|
impl<'a> fmt::Display for EscapeSingleQuoteString<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
for c in self.0.chars() {
|
|
if c == '\'' {
|
|
write!(f, "\'\'")?;
|
|
} else {
|
|
write!(f, "{}", c)?;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> {
|
|
EscapeSingleQuoteString(s)
|
|
}
|