mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-26 15:39:12 +00:00
mysql unsigned datatype (#428)
* support MySQL UNSIGNED * fix: 🐛 `unsigned` is not column option * test: 💍 add `unsigned` test * fix: 🐛 `unsigned` is not column option * feat: 🎸 declare unsigned data_types * feat: 🎸 display unsigned * fix: 🐛 unsigned is not column type option * feat: 🎸 parse_data_type can parse unsigned * feat: 🎸 int or decimal or float is unsigned selectable * fix: 🐛 FLOAT/DOUBLE/DECIMAL + UNSIGNED is not recommended https://dev.mysql.com/doc/refman/8.0/en/numeric-type-attributes.html * test: 💍 add test * style: 💄 fmt
This commit is contained in:
parent
3af3ca07b6
commit
994b86a45c
4 changed files with 109 additions and 14 deletions
|
@ -45,12 +45,20 @@ pub enum DataType {
|
||||||
Float(Option<u64>),
|
Float(Option<u64>),
|
||||||
/// 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 e.g. TINYINT UNSIGNED or TINYINT(3) UNSIGNED
|
||||||
|
UnsignedTinyInt(Option<u64>),
|
||||||
/// Small integer with optional display width e.g. SMALLINT or SMALLINT(5)
|
/// Small integer with optional display width e.g. SMALLINT or SMALLINT(5)
|
||||||
SmallInt(Option<u64>),
|
SmallInt(Option<u64>),
|
||||||
|
/// Unsigned small integer with optional display width e.g. SMALLINT UNSIGNED or SMALLINT(5) UNSIGNED
|
||||||
|
UnsignedSmallInt(Option<u64>),
|
||||||
/// Integer with optional display width e.g. INT or INT(11)
|
/// Integer with optional display width e.g. INT or INT(11)
|
||||||
Int(Option<u64>),
|
Int(Option<u64>),
|
||||||
|
/// Unsigned integer with optional display width e.g. INT UNSIGNED or INT(11) UNSIGNED
|
||||||
|
UnsignedInt(Option<u64>),
|
||||||
/// Big integer with optional display width e.g. BIGINT or BIGINT(20)
|
/// Big integer with optional display width e.g. BIGINT or BIGINT(20)
|
||||||
BigInt(Option<u64>),
|
BigInt(Option<u64>),
|
||||||
|
/// Unsigned big integer with optional display width e.g. BIGINT UNSIGNED or BIGINT(20) UNSIGNED
|
||||||
|
UnsignedBigInt(Option<u64>),
|
||||||
/// Floating point e.g. REAL
|
/// Floating point e.g. REAL
|
||||||
Real,
|
Real,
|
||||||
/// Double e.g. DOUBLE PRECISION
|
/// Double e.g. DOUBLE PRECISION
|
||||||
|
@ -86,9 +94,9 @@ pub enum DataType {
|
||||||
impl fmt::Display for DataType {
|
impl fmt::Display for DataType {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
DataType::Char(size) => format_type_with_optional_length(f, "CHAR", size),
|
DataType::Char(size) => format_type_with_optional_length(f, "CHAR", size, false),
|
||||||
DataType::Varchar(size) => {
|
DataType::Varchar(size) => {
|
||||||
format_type_with_optional_length(f, "CHARACTER VARYING", size)
|
format_type_with_optional_length(f, "CHARACTER VARYING", size, false)
|
||||||
}
|
}
|
||||||
DataType::Uuid => write!(f, "UUID"),
|
DataType::Uuid => write!(f, "UUID"),
|
||||||
DataType::Clob(size) => write!(f, "CLOB({})", size),
|
DataType::Clob(size) => write!(f, "CLOB({})", size),
|
||||||
|
@ -99,16 +107,32 @@ impl fmt::Display for DataType {
|
||||||
if let Some(scale) = scale {
|
if let Some(scale) = scale {
|
||||||
write!(f, "NUMERIC({},{})", precision.unwrap(), scale)
|
write!(f, "NUMERIC({},{})", precision.unwrap(), scale)
|
||||||
} else {
|
} else {
|
||||||
format_type_with_optional_length(f, "NUMERIC", precision)
|
format_type_with_optional_length(f, "NUMERIC", precision, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size),
|
DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false),
|
||||||
DataType::TinyInt(zerofill) => format_type_with_optional_length(f, "TINYINT", zerofill),
|
DataType::TinyInt(zerofill) => {
|
||||||
|
format_type_with_optional_length(f, "TINYINT", zerofill, false)
|
||||||
|
}
|
||||||
|
DataType::UnsignedTinyInt(zerofill) => {
|
||||||
|
format_type_with_optional_length(f, "TINYINT", zerofill, true)
|
||||||
|
}
|
||||||
DataType::SmallInt(zerofill) => {
|
DataType::SmallInt(zerofill) => {
|
||||||
format_type_with_optional_length(f, "SMALLINT", zerofill)
|
format_type_with_optional_length(f, "SMALLINT", zerofill, false)
|
||||||
|
}
|
||||||
|
DataType::UnsignedSmallInt(zerofill) => {
|
||||||
|
format_type_with_optional_length(f, "SMALLINT", zerofill, true)
|
||||||
|
}
|
||||||
|
DataType::Int(zerofill) => format_type_with_optional_length(f, "INT", zerofill, false),
|
||||||
|
DataType::UnsignedInt(zerofill) => {
|
||||||
|
format_type_with_optional_length(f, "INT", zerofill, true)
|
||||||
|
}
|
||||||
|
DataType::BigInt(zerofill) => {
|
||||||
|
format_type_with_optional_length(f, "BIGINT", zerofill, false)
|
||||||
|
}
|
||||||
|
DataType::UnsignedBigInt(zerofill) => {
|
||||||
|
format_type_with_optional_length(f, "BIGINT", zerofill, true)
|
||||||
}
|
}
|
||||||
DataType::Int(zerofill) => format_type_with_optional_length(f, "INT", zerofill),
|
|
||||||
DataType::BigInt(zerofill) => format_type_with_optional_length(f, "BIGINT", zerofill),
|
|
||||||
DataType::Real => write!(f, "REAL"),
|
DataType::Real => write!(f, "REAL"),
|
||||||
DataType::Double => write!(f, "DOUBLE"),
|
DataType::Double => write!(f, "DOUBLE"),
|
||||||
DataType::Boolean => write!(f, "BOOLEAN"),
|
DataType::Boolean => write!(f, "BOOLEAN"),
|
||||||
|
@ -150,10 +174,14 @@ fn format_type_with_optional_length(
|
||||||
f: &mut fmt::Formatter,
|
f: &mut fmt::Formatter,
|
||||||
sql_type: &'static str,
|
sql_type: &'static str,
|
||||||
len: &Option<u64>,
|
len: &Option<u64>,
|
||||||
|
unsigned: bool,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
write!(f, "{}", sql_type)?;
|
write!(f, "{}", sql_type)?;
|
||||||
if let Some(len) = len {
|
if let Some(len) = len {
|
||||||
write!(f, "({})", len)?;
|
write!(f, "({})", len)?;
|
||||||
}
|
}
|
||||||
|
if unsigned {
|
||||||
|
write!(f, " UNSIGNED")?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -499,6 +499,7 @@ define_keywords!(
|
||||||
UNIQUE,
|
UNIQUE,
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
UNNEST,
|
UNNEST,
|
||||||
|
UNSIGNED,
|
||||||
UPDATE,
|
UPDATE,
|
||||||
UPPER,
|
UPPER,
|
||||||
USAGE,
|
USAGE,
|
||||||
|
|
|
@ -2382,12 +2382,38 @@ impl<'a> Parser<'a> {
|
||||||
let _ = self.parse_keyword(Keyword::PRECISION);
|
let _ = self.parse_keyword(Keyword::PRECISION);
|
||||||
Ok(DataType::Double)
|
Ok(DataType::Double)
|
||||||
}
|
}
|
||||||
Keyword::TINYINT => Ok(DataType::TinyInt(self.parse_optional_precision()?)),
|
Keyword::TINYINT => {
|
||||||
Keyword::SMALLINT => Ok(DataType::SmallInt(self.parse_optional_precision()?)),
|
let optional_precision = self.parse_optional_precision();
|
||||||
Keyword::INT | Keyword::INTEGER => {
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
Ok(DataType::Int(self.parse_optional_precision()?))
|
Ok(DataType::UnsignedTinyInt(optional_precision?))
|
||||||
|
} else {
|
||||||
|
Ok(DataType::TinyInt(optional_precision?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::SMALLINT => {
|
||||||
|
let optional_precision = self.parse_optional_precision();
|
||||||
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::UnsignedSmallInt(optional_precision?))
|
||||||
|
} else {
|
||||||
|
Ok(DataType::SmallInt(optional_precision?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::INT | Keyword::INTEGER => {
|
||||||
|
let optional_precision = self.parse_optional_precision();
|
||||||
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::UnsignedInt(optional_precision?))
|
||||||
|
} else {
|
||||||
|
Ok(DataType::Int(optional_precision?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keyword::BIGINT => {
|
||||||
|
let optional_precision = self.parse_optional_precision();
|
||||||
|
if self.parse_keyword(Keyword::UNSIGNED) {
|
||||||
|
Ok(DataType::UnsignedBigInt(optional_precision?))
|
||||||
|
} else {
|
||||||
|
Ok(DataType::BigInt(optional_precision?))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Keyword::BIGINT => Ok(DataType::BigInt(self.parse_optional_precision()?)),
|
|
||||||
Keyword::VARCHAR => Ok(DataType::Varchar(self.parse_optional_precision()?)),
|
Keyword::VARCHAR => Ok(DataType::Varchar(self.parse_optional_precision()?)),
|
||||||
Keyword::CHAR | Keyword::CHARACTER => {
|
Keyword::CHAR | Keyword::CHARACTER => {
|
||||||
if self.parse_keyword(Keyword::VARYING) {
|
if self.parse_keyword(Keyword::VARYING) {
|
||||||
|
|
|
@ -407,6 +407,46 @@ fn parse_create_table_with_minimum_display_width() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_create_table_unsigned() {
|
||||||
|
let sql = "CREATE TABLE foo (bar_tinyint TINYINT(3) UNSIGNED, bar_smallint SMALLINT(5) UNSIGNED, bar_int INT(11) UNSIGNED, bar_bigint BIGINT(20) UNSIGNED)";
|
||||||
|
match mysql().verified_stmt(sql) {
|
||||||
|
Statement::CreateTable { name, columns, .. } => {
|
||||||
|
assert_eq!(name.to_string(), "foo");
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_tinyint"),
|
||||||
|
data_type: DataType::UnsignedTinyInt(Some(3)),
|
||||||
|
collation: None,
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_smallint"),
|
||||||
|
data_type: DataType::UnsignedSmallInt(Some(5)),
|
||||||
|
collation: None,
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_int"),
|
||||||
|
data_type: DataType::UnsignedInt(Some(11)),
|
||||||
|
collation: None,
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
ColumnDef {
|
||||||
|
name: Ident::new("bar_bigint"),
|
||||||
|
data_type: DataType::UnsignedBigInt(Some(20)),
|
||||||
|
collation: None,
|
||||||
|
options: vec![],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
columns
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "bigdecimal"))]
|
#[cfg(not(feature = "bigdecimal"))]
|
||||||
fn parse_simple_insert() {
|
fn parse_simple_insert() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue