mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
Enum to handle exact number precisios (#654)
This commit is contained in:
parent
a3194ddd52
commit
a9939b0a4f
3 changed files with 83 additions and 12 deletions
|
@ -60,7 +60,7 @@ pub enum DataType {
|
|||
/// [Oracle]: https://docs.oracle.com/javadb/10.8.3.0/ref/rrefblob.html
|
||||
Blob(Option<u64>),
|
||||
/// Decimal type with optional precision and scale e.g. DECIMAL(10,2)
|
||||
Decimal(Option<u64>, Option<u64>),
|
||||
Decimal(ExactNumberInfo),
|
||||
/// Floating point with optional precision e.g. FLOAT(8)
|
||||
Float(Option<u64>),
|
||||
/// Tiny integer with optional display width e.g. TINYINT or TINYINT(3)
|
||||
|
@ -154,12 +154,8 @@ impl fmt::Display for DataType {
|
|||
format_type_with_optional_length(f, "VARBINARY", size, false)
|
||||
}
|
||||
DataType::Blob(size) => format_type_with_optional_length(f, "BLOB", size, false),
|
||||
DataType::Decimal(precision, scale) => {
|
||||
if let Some(scale) = scale {
|
||||
write!(f, "NUMERIC({},{})", precision.unwrap(), scale)
|
||||
} else {
|
||||
format_type_with_optional_length(f, "NUMERIC", precision, false)
|
||||
}
|
||||
DataType::Decimal(info) => {
|
||||
write!(f, "NUMERIC{}", info)
|
||||
}
|
||||
DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false),
|
||||
DataType::TinyInt(zerofill) => {
|
||||
|
@ -297,3 +293,34 @@ impl fmt::Display for TimezoneInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional information for `NUMERIC`, `DECIMAL`, and `DEC` data types
|
||||
/// following the 2016 [standard].
|
||||
///
|
||||
/// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum ExactNumberInfo {
|
||||
/// No additional information e.g. `DECIMAL`
|
||||
None,
|
||||
/// Only precision information e.g. `DECIMAL(10)`
|
||||
Precision(u64),
|
||||
/// Precision and scale information e.g. `DECIMAL(10,2)`
|
||||
PrecisionAndScale(u64, u64),
|
||||
}
|
||||
|
||||
impl fmt::Display for ExactNumberInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ExactNumberInfo::None => {
|
||||
write!(f, "")
|
||||
}
|
||||
ExactNumberInfo::Precision(p) => {
|
||||
write!(f, "({p})")
|
||||
}
|
||||
ExactNumberInfo::PrecisionAndScale(p, s) => {
|
||||
write!(f, "({p},{s})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use core::fmt;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use self::data_type::DataType;
|
||||
pub use self::data_type::ExactNumberInfo;
|
||||
pub use self::data_type::TimezoneInfo;
|
||||
pub use self::ddl::{
|
||||
AlterColumnOperation, AlterTableOperation, ColumnDef, ColumnOption, ColumnOptionDef,
|
||||
|
|
|
@ -3481,10 +3481,9 @@ impl<'a> Parser<'a> {
|
|||
Keyword::STRING => Ok(DataType::String),
|
||||
Keyword::TEXT => Ok(DataType::Text),
|
||||
Keyword::BYTEA => Ok(DataType::Bytea),
|
||||
Keyword::NUMERIC | Keyword::DECIMAL | Keyword::DEC => {
|
||||
let (precision, scale) = self.parse_optional_precision_scale()?;
|
||||
Ok(DataType::Decimal(precision, scale))
|
||||
}
|
||||
Keyword::NUMERIC | Keyword::DECIMAL | Keyword::DEC => Ok(DataType::Decimal(
|
||||
self.parse_exact_number_optional_precision_scale()?,
|
||||
)),
|
||||
Keyword::ENUM => Ok(DataType::Enum(self.parse_string_values()?)),
|
||||
Keyword::SET => Ok(DataType::Set(self.parse_string_values()?)),
|
||||
Keyword::ARRAY => {
|
||||
|
@ -3698,6 +3697,28 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_exact_number_optional_precision_scale(
|
||||
&mut self,
|
||||
) -> Result<ExactNumberInfo, ParserError> {
|
||||
if self.consume_token(&Token::LParen) {
|
||||
let precision = self.parse_literal_uint()?;
|
||||
let scale = if self.consume_token(&Token::Comma) {
|
||||
Some(self.parse_literal_uint()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.expect_token(&Token::RParen)?;
|
||||
|
||||
match scale {
|
||||
None => Ok(ExactNumberInfo::Precision(precision)),
|
||||
Some(scale) => Ok(ExactNumberInfo::PrecisionAndScale(precision, scale)),
|
||||
}
|
||||
} else {
|
||||
Ok(ExactNumberInfo::None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_delete(&mut self) -> Result<Statement, ParserError> {
|
||||
self.expect_keyword(Keyword::FROM)?;
|
||||
let table_name = self.parse_table_factor()?;
|
||||
|
@ -5311,7 +5332,7 @@ mod tests {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test_parse_data_type {
|
||||
use crate::ast::{DataType, TimezoneInfo};
|
||||
use crate::ast::{DataType, ExactNumberInfo, TimezoneInfo};
|
||||
use crate::dialect::{AnsiDialect, GenericDialect};
|
||||
use crate::test_utils::TestedDialects;
|
||||
|
||||
|
@ -5351,6 +5372,28 @@ mod tests {
|
|||
test_parse_data_type!(dialect, "VARCHAR(20)", DataType::Varchar(Some(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ansii_exact_numeric_types() {
|
||||
// Exact numeric types: <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type>
|
||||
let dialect = TestedDialects {
|
||||
dialects: vec![Box::new(GenericDialect {}), Box::new(AnsiDialect {})],
|
||||
};
|
||||
|
||||
test_parse_data_type!(dialect, "NUMERIC", DataType::Decimal(ExactNumberInfo::None));
|
||||
|
||||
test_parse_data_type!(
|
||||
dialect,
|
||||
"NUMERIC(2)",
|
||||
DataType::Decimal(ExactNumberInfo::Precision(2))
|
||||
);
|
||||
|
||||
test_parse_data_type!(
|
||||
dialect,
|
||||
"NUMERIC(2,10)",
|
||||
DataType::Decimal(ExactNumberInfo::PrecisionAndScale(2, 10))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ansii_datetime_types() {
|
||||
// Datetime types: <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue