Support the ARRAY type of Snowflake (#699)

* Snowflake Array

* Use the array data type

* Try to fix build

* Try to fix build

* Change Array to option

* Remove unused import
This commit is contained in:
yuval-illumex 2022-11-04 16:25:25 +02:00 committed by GitHub
parent bbf32a9e81
commit 0f7e144890
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 21 deletions

View file

@ -141,7 +141,7 @@ pub enum DataType {
/// Custom type such as enums
Custom(ObjectName, Vec<String>),
/// Arrays
Array(Box<DataType>),
Array(Option<Box<DataType>>),
/// Enums
Enum(Vec<String>),
/// Set
@ -232,7 +232,13 @@ impl fmt::Display for DataType {
DataType::Text => write!(f, "TEXT"),
DataType::String => write!(f, "STRING"),
DataType::Bytea => write!(f, "BYTEA"),
DataType::Array(ty) => write!(f, "{}[]", ty),
DataType::Array(ty) => {
if let Some(t) = &ty {
write!(f, "{}[]", t)
} else {
write!(f, "ARRAY")
}
}
DataType::Custom(ty, modifiers) => {
if modifiers.is_empty() {
write!(f, "{}", ty)

View file

@ -3672,13 +3672,17 @@ impl<'a> Parser<'a> {
Keyword::ENUM => Ok(DataType::Enum(self.parse_string_values()?)),
Keyword::SET => Ok(DataType::Set(self.parse_string_values()?)),
Keyword::ARRAY => {
// Hive array syntax. Note that nesting arrays - or other Hive syntax
// that ends with > will fail due to "C++" problem - >> is parsed as
// Token::ShiftRight
self.expect_token(&Token::Lt)?;
let inside_type = self.parse_data_type()?;
self.expect_token(&Token::Gt)?;
Ok(DataType::Array(Box::new(inside_type)))
if dialect_of!(self is SnowflakeDialect) {
Ok(DataType::Array(None))
} else {
// Hive array syntax. Note that nesting arrays - or other Hive syntax
// that ends with > will fail due to "C++" problem - >> is parsed as
// Token::ShiftRight
self.expect_token(&Token::Lt)?;
let inside_type = self.parse_data_type()?;
self.expect_token(&Token::Gt)?;
Ok(DataType::Array(Some(Box::new(inside_type))))
}
}
_ => {
self.prev_token();
@ -3697,7 +3701,7 @@ impl<'a> Parser<'a> {
// Keyword::ARRAY syntax from above
while self.consume_token(&Token::LBracket) {
self.expect_token(&Token::RBracket)?;
data = DataType::Array(Box::new(data))
data = DataType::Array(Some(Box::new(data)))
}
Ok(data)
}

View file

@ -24,7 +24,7 @@ use sqlparser::ast::SelectItem::UnnamedExpr;
use sqlparser::ast::*;
use sqlparser::dialect::{
AnsiDialect, BigQueryDialect, ClickHouseDialect, GenericDialect, HiveDialect, MsSqlDialect,
PostgreSqlDialect, SQLiteDialect, SnowflakeDialect,
MySqlDialect, PostgreSqlDialect, SQLiteDialect, SnowflakeDialect,
};
use sqlparser::keywords::ALL_KEYWORDS;
use sqlparser::parser::{Parser, ParserError};
@ -2099,7 +2099,7 @@ fn parse_create_table_hive_array() {
},
ColumnDef {
name: Ident::new("val"),
data_type: DataType::Array(Box::new(DataType::Int(None))),
data_type: DataType::Array(Some(Box::new(DataType::Int(None)))),
collation: None,
options: vec![],
},
@ -2109,12 +2109,20 @@ fn parse_create_table_hive_array() {
_ => unreachable!(),
}
let res =
parse_sql_statements("CREATE TABLE IF NOT EXISTS something (name int, val array<int)");
assert!(res
.unwrap_err()
.to_string()
.contains("Expected >, found: )"));
// SnowflakeDialect using array diffrent
let dialects = TestedDialects {
dialects: vec![
Box::new(PostgreSqlDialect {}),
Box::new(HiveDialect {}),
Box::new(MySqlDialect {}),
],
};
let sql = "CREATE TABLE IF NOT EXISTS something (name int, val array<int)";
assert_eq!(
dialects.parse_sql_statements(sql).unwrap_err(),
ParserError::ParserError("Expected >, found: )".to_string())
);
}
#[test]

View file

@ -1324,9 +1324,9 @@ fn parse_array_index_expr() {
})],
named: true,
})),
data_type: DataType::Array(Box::new(DataType::Array(Box::new(DataType::Int(
None
)))))
data_type: DataType::Array(Some(Box::new(DataType::Array(Some(Box::new(
DataType::Int(None)
))))))
}))),
indexes: vec![num[1].clone(), num[2].clone()],
},

View file

@ -143,6 +143,19 @@ fn test_single_table_in_parenthesis_with_alias() {
);
}
#[test]
fn parse_array() {
let sql = "SELECT CAST(a AS ARRAY) FROM customer";
let select = snowflake().verified_only_select(sql);
assert_eq!(
&Expr::Cast {
expr: Box::new(Expr::Identifier(Ident::new("a"))),
data_type: DataType::Array(None),
},
expr_from_projection(only(&select.projection))
);
}
#[test]
fn parse_json_using_colon() {
let sql = "SELECT a:b FROM t";