| // 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. |
| |
| #[cfg(feature = "bigdecimal")] |
| use bigdecimal::BigDecimal; |
| use std::fmt; |
| |
| /// Primitive SQL values such as number and string |
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
| pub enum Value { |
| /// Numeric literal |
| #[cfg(not(feature = "bigdecimal"))] |
| Number(String), |
| #[cfg(feature = "bigdecimal")] |
| Number(BigDecimal), |
| /// '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::Number(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", |
| }) |
| } |
| } |
| |
| pub 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(()) |
| } |
| } |
| |
| pub fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> { |
| EscapeSingleQuoteString(s) |
| } |