mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-27 07:59:11 +00:00
MySQL: Add support for unsigned numeric types (#2031)
This commit is contained in:
parent
f642dd573c
commit
ea7f9026f7
3 changed files with 182 additions and 15 deletions
|
@ -131,6 +131,11 @@ pub enum DataType {
|
||||||
///
|
///
|
||||||
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
|
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
|
||||||
Decimal(ExactNumberInfo),
|
Decimal(ExactNumberInfo),
|
||||||
|
/// [MySQL] unsigned decimal with optional precision and scale, e.g. DECIMAL UNSIGNED or DECIMAL(10,2) UNSIGNED.
|
||||||
|
/// Note: Using UNSIGNED with DECIMAL is deprecated in recent versions of MySQL.
|
||||||
|
///
|
||||||
|
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
|
||||||
|
DecimalUnsigned(ExactNumberInfo),
|
||||||
/// [BigNumeric] type used in BigQuery.
|
/// [BigNumeric] type used in BigQuery.
|
||||||
///
|
///
|
||||||
/// [BigNumeric]: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#bignumeric_literals
|
/// [BigNumeric]: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#bignumeric_literals
|
||||||
|
@ -143,8 +148,19 @@ pub enum DataType {
|
||||||
///
|
///
|
||||||
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
|
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
|
||||||
Dec(ExactNumberInfo),
|
Dec(ExactNumberInfo),
|
||||||
/// Floating point with optional precision, e.g. FLOAT(8).
|
/// [MySQL] unsigned decimal (DEC alias) with optional precision and scale, e.g. DEC UNSIGNED or DEC(10,2) UNSIGNED.
|
||||||
Float(Option<u64>),
|
/// Note: Using UNSIGNED with DEC is deprecated in recent versions of MySQL.
|
||||||
|
///
|
||||||
|
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
|
||||||
|
DecUnsigned(ExactNumberInfo),
|
||||||
|
/// Floating point with optional precision and scale, e.g. FLOAT, FLOAT(8), or FLOAT(8,2).
|
||||||
|
Float(ExactNumberInfo),
|
||||||
|
/// [MySQL] unsigned floating point with optional precision and scale, e.g.
|
||||||
|
/// FLOAT UNSIGNED, FLOAT(10) UNSIGNED or FLOAT(10,2) UNSIGNED.
|
||||||
|
/// Note: Using UNSIGNED with FLOAT is deprecated in recent versions of MySQL.
|
||||||
|
///
|
||||||
|
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
|
||||||
|
FloatUnsigned(ExactNumberInfo),
|
||||||
/// Tiny integer with optional display width, e.g. TINYINT or TINYINT(3).
|
/// Tiny integer with optional display width, e.g. TINYINT or TINYINT(3).
|
||||||
TinyInt(Option<u64>),
|
TinyInt(Option<u64>),
|
||||||
/// Unsigned tiny integer with optional display width,
|
/// Unsigned tiny integer with optional display width,
|
||||||
|
@ -302,17 +318,32 @@ pub enum DataType {
|
||||||
Float64,
|
Float64,
|
||||||
/// Floating point, e.g. REAL.
|
/// Floating point, e.g. REAL.
|
||||||
Real,
|
Real,
|
||||||
|
/// [MySQL] unsigned real, e.g. REAL UNSIGNED.
|
||||||
|
/// Note: Using UNSIGNED with REAL is deprecated in recent versions of MySQL.
|
||||||
|
///
|
||||||
|
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
|
||||||
|
RealUnsigned,
|
||||||
/// Float8 is an alias for Double in [PostgreSQL].
|
/// Float8 is an alias for Double in [PostgreSQL].
|
||||||
///
|
///
|
||||||
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
|
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
|
||||||
Float8,
|
Float8,
|
||||||
/// Double
|
/// Double
|
||||||
Double(ExactNumberInfo),
|
Double(ExactNumberInfo),
|
||||||
|
/// [MySQL] unsigned double precision with optional precision, e.g. DOUBLE UNSIGNED or DOUBLE(10,2) UNSIGNED.
|
||||||
|
/// Note: Using UNSIGNED with DOUBLE is deprecated in recent versions of MySQL.
|
||||||
|
///
|
||||||
|
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
|
||||||
|
DoubleUnsigned(ExactNumberInfo),
|
||||||
/// Double Precision, see [SQL Standard], [PostgreSQL].
|
/// Double Precision, see [SQL Standard], [PostgreSQL].
|
||||||
///
|
///
|
||||||
/// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#approximate-numeric-type
|
/// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#approximate-numeric-type
|
||||||
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-numeric.html
|
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-numeric.html
|
||||||
DoublePrecision,
|
DoublePrecision,
|
||||||
|
/// [MySQL] unsigned double precision, e.g. DOUBLE PRECISION UNSIGNED.
|
||||||
|
/// Note: Using UNSIGNED with DOUBLE PRECISION is deprecated in recent versions of MySQL.
|
||||||
|
///
|
||||||
|
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
|
||||||
|
DoublePrecisionUnsigned,
|
||||||
/// Bool is an alias for Boolean, see [PostgreSQL].
|
/// Bool is an alias for Boolean, see [PostgreSQL].
|
||||||
///
|
///
|
||||||
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
|
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
|
||||||
|
@ -497,12 +528,19 @@ impl fmt::Display for DataType {
|
||||||
DataType::Decimal(info) => {
|
DataType::Decimal(info) => {
|
||||||
write!(f, "DECIMAL{info}")
|
write!(f, "DECIMAL{info}")
|
||||||
}
|
}
|
||||||
|
DataType::DecimalUnsigned(info) => {
|
||||||
|
write!(f, "DECIMAL{info} UNSIGNED")
|
||||||
|
}
|
||||||
DataType::Dec(info) => {
|
DataType::Dec(info) => {
|
||||||
write!(f, "DEC{info}")
|
write!(f, "DEC{info}")
|
||||||
}
|
}
|
||||||
|
DataType::DecUnsigned(info) => {
|
||||||
|
write!(f, "DEC{info} UNSIGNED")
|
||||||
|
}
|
||||||
DataType::BigNumeric(info) => write!(f, "BIGNUMERIC{info}"),
|
DataType::BigNumeric(info) => write!(f, "BIGNUMERIC{info}"),
|
||||||
DataType::BigDecimal(info) => write!(f, "BIGDECIMAL{info}"),
|
DataType::BigDecimal(info) => write!(f, "BIGDECIMAL{info}"),
|
||||||
DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false),
|
DataType::Float(info) => write!(f, "FLOAT{info}"),
|
||||||
|
DataType::FloatUnsigned(info) => write!(f, "FLOAT{info} UNSIGNED"),
|
||||||
DataType::TinyInt(zerofill) => {
|
DataType::TinyInt(zerofill) => {
|
||||||
format_type_with_optional_length(f, "TINYINT", zerofill, false)
|
format_type_with_optional_length(f, "TINYINT", zerofill, false)
|
||||||
}
|
}
|
||||||
|
@ -616,12 +654,15 @@ impl fmt::Display for DataType {
|
||||||
write!(f, "UNSIGNED INTEGER")
|
write!(f, "UNSIGNED INTEGER")
|
||||||
}
|
}
|
||||||
DataType::Real => write!(f, "REAL"),
|
DataType::Real => write!(f, "REAL"),
|
||||||
|
DataType::RealUnsigned => write!(f, "REAL UNSIGNED"),
|
||||||
DataType::Float4 => write!(f, "FLOAT4"),
|
DataType::Float4 => write!(f, "FLOAT4"),
|
||||||
DataType::Float32 => write!(f, "Float32"),
|
DataType::Float32 => write!(f, "Float32"),
|
||||||
DataType::Float64 => write!(f, "FLOAT64"),
|
DataType::Float64 => write!(f, "FLOAT64"),
|
||||||
DataType::Double(info) => write!(f, "DOUBLE{info}"),
|
DataType::Double(info) => write!(f, "DOUBLE{info}"),
|
||||||
|
DataType::DoubleUnsigned(info) => write!(f, "DOUBLE{info} UNSIGNED"),
|
||||||
DataType::Float8 => write!(f, "FLOAT8"),
|
DataType::Float8 => write!(f, "FLOAT8"),
|
||||||
DataType::DoublePrecision => write!(f, "DOUBLE PRECISION"),
|
DataType::DoublePrecision => write!(f, "DOUBLE PRECISION"),
|
||||||
|
DataType::DoublePrecisionUnsigned => write!(f, "DOUBLE PRECISION UNSIGNED"),
|
||||||
DataType::Bool => write!(f, "BOOL"),
|
DataType::Bool => write!(f, "BOOL"),
|
||||||
DataType::Boolean => write!(f, "BOOLEAN"),
|
DataType::Boolean => write!(f, "BOOLEAN"),
|
||||||
DataType::Date => write!(f, "DATE"),
|
DataType::Date => write!(f, "DATE"),
|
||||||
|
|
|
@ -10181,19 +10181,41 @@ impl<'a> Parser<'a> {
|
||||||
Token::Word(w) => match w.keyword {
|
Token::Word(w) => match w.keyword {
|
||||||
Keyword::BOOLEAN => Ok(DataType::Boolean),
|
Keyword::BOOLEAN => Ok(DataType::Boolean),
|
||||||
Keyword::BOOL => Ok(DataType::Bool),
|
Keyword::BOOL => Ok(DataType::Bool),
|
||||||
Keyword::FLOAT => Ok(DataType::Float(self.parse_optional_precision()?)),
|
Keyword::FLOAT => {
|
||||||
Keyword::REAL => Ok(DataType::Real),
|
let precision = self.parse_exact_number_optional_precision_scale()?;
|
||||||
|
|
||||||
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::FloatUnsigned(precision))
|
||||||
|
} else {
|
||||||
|
Ok(DataType::Float(precision))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::REAL => {
|
||||||
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::RealUnsigned)
|
||||||
|
} else {
|
||||||
|
Ok(DataType::Real)
|
||||||
|
}
|
||||||
|
}
|
||||||
Keyword::FLOAT4 => Ok(DataType::Float4),
|
Keyword::FLOAT4 => Ok(DataType::Float4),
|
||||||
Keyword::FLOAT32 => Ok(DataType::Float32),
|
Keyword::FLOAT32 => Ok(DataType::Float32),
|
||||||
Keyword::FLOAT64 => Ok(DataType::Float64),
|
Keyword::FLOAT64 => Ok(DataType::Float64),
|
||||||
Keyword::FLOAT8 => Ok(DataType::Float8),
|
Keyword::FLOAT8 => Ok(DataType::Float8),
|
||||||
Keyword::DOUBLE => {
|
Keyword::DOUBLE => {
|
||||||
if self.parse_keyword(Keyword::PRECISION) {
|
if self.parse_keyword(Keyword::PRECISION) {
|
||||||
Ok(DataType::DoublePrecision)
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::DoublePrecisionUnsigned)
|
||||||
|
} else {
|
||||||
|
Ok(DataType::DoublePrecision)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(DataType::Double(
|
let precision = self.parse_exact_number_optional_precision_scale()?;
|
||||||
self.parse_exact_number_optional_precision_scale()?,
|
|
||||||
))
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::DoubleUnsigned(precision))
|
||||||
|
} else {
|
||||||
|
Ok(DataType::Double(precision))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keyword::TINYINT => {
|
Keyword::TINYINT => {
|
||||||
|
@ -10420,12 +10442,24 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::NUMERIC => Ok(DataType::Numeric(
|
Keyword::NUMERIC => Ok(DataType::Numeric(
|
||||||
self.parse_exact_number_optional_precision_scale()?,
|
self.parse_exact_number_optional_precision_scale()?,
|
||||||
)),
|
)),
|
||||||
Keyword::DECIMAL => Ok(DataType::Decimal(
|
Keyword::DECIMAL => {
|
||||||
self.parse_exact_number_optional_precision_scale()?,
|
let precision = self.parse_exact_number_optional_precision_scale()?;
|
||||||
)),
|
|
||||||
Keyword::DEC => Ok(DataType::Dec(
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
self.parse_exact_number_optional_precision_scale()?,
|
Ok(DataType::DecimalUnsigned(precision))
|
||||||
)),
|
} else {
|
||||||
|
Ok(DataType::Decimal(precision))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::DEC => {
|
||||||
|
let precision = self.parse_exact_number_optional_precision_scale()?;
|
||||||
|
|
||||||
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::DecUnsigned(precision))
|
||||||
|
} else {
|
||||||
|
Ok(DataType::Dec(precision))
|
||||||
|
}
|
||||||
|
}
|
||||||
Keyword::BIGNUMERIC => Ok(DataType::BigNumeric(
|
Keyword::BIGNUMERIC => Ok(DataType::BigNumeric(
|
||||||
self.parse_exact_number_optional_precision_scale()?,
|
self.parse_exact_number_optional_precision_scale()?,
|
||||||
)),
|
)),
|
||||||
|
|
|
@ -1757,6 +1757,98 @@ fn parse_signed_data_types() {
|
||||||
.expect_err("SIGNED suffix should not be allowed");
|
.expect_err("SIGNED suffix should not be allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_deprecated_mysql_unsigned_data_types() {
|
||||||
|
let sql = "CREATE TABLE foo (bar_decimal DECIMAL UNSIGNED, bar_decimal_prec DECIMAL(10) UNSIGNED, bar_decimal_scale DECIMAL(10,2) UNSIGNED, bar_dec DEC UNSIGNED, bar_dec_prec DEC(10) UNSIGNED, bar_dec_scale DEC(10,2) UNSIGNED, bar_float FLOAT UNSIGNED, bar_float_prec FLOAT(10) UNSIGNED, bar_float_scale FLOAT(10,2) UNSIGNED, bar_double DOUBLE UNSIGNED, bar_double_prec DOUBLE(10) UNSIGNED, bar_double_scale DOUBLE(10,2) UNSIGNED, bar_real REAL UNSIGNED, bar_double_precision DOUBLE PRECISION UNSIGNED)";
|
||||||
|
match mysql().verified_stmt(sql) {
|
||||||
|
Statement::CreateTable(CreateTable { name, columns, .. }) => {
|
||||||
|
assert_eq!(name.to_string(), "foo");
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_decimal"),
|
||||||
|
data_type: DataType::DecimalUnsigned(ExactNumberInfo::None),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_decimal_prec"),
|
||||||
|
data_type: DataType::DecimalUnsigned(ExactNumberInfo::Precision(10)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_decimal_scale"),
|
||||||
|
data_type: DataType::DecimalUnsigned(ExactNumberInfo::PrecisionAndScale(
|
||||||
|
10, 2
|
||||||
|
)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_dec"),
|
||||||
|
data_type: DataType::DecUnsigned(ExactNumberInfo::None),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_dec_prec"),
|
||||||
|
data_type: DataType::DecUnsigned(ExactNumberInfo::Precision(10)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_dec_scale"),
|
||||||
|
data_type: DataType::DecUnsigned(ExactNumberInfo::PrecisionAndScale(10, 2)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_float"),
|
||||||
|
data_type: DataType::FloatUnsigned(ExactNumberInfo::None),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_float_prec"),
|
||||||
|
data_type: DataType::FloatUnsigned(ExactNumberInfo::Precision(10)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_float_scale"),
|
||||||
|
data_type: DataType::FloatUnsigned(ExactNumberInfo::PrecisionAndScale(
|
||||||
|
10, 2
|
||||||
|
)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_double"),
|
||||||
|
data_type: DataType::DoubleUnsigned(ExactNumberInfo::None),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_double_prec"),
|
||||||
|
data_type: DataType::DoubleUnsigned(ExactNumberInfo::Precision(10)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_double_scale"),
|
||||||
|
data_type: DataType::DoubleUnsigned(ExactNumberInfo::PrecisionAndScale(
|
||||||
|
10, 2
|
||||||
|
)),
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_real"),
|
||||||
|
data_type: DataType::RealUnsigned,
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_double_precision"),
|
||||||
|
data_type: DataType::DoublePrecisionUnsigned,
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
columns
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_simple_insert() {
|
fn parse_simple_insert() {
|
||||||
let sql = r"INSERT INTO tasks (title, priority) VALUES ('Test Some Inserts', 1), ('Test Entry 2', 2), ('Test Entry 3', 3)";
|
let sql = r"INSERT INTO tasks (title, priority) VALUES ('Test Some Inserts', 1), ('Test Entry 2', 2), ('Test Entry 3', 3)";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue