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 type such as enums
Custom(ObjectName, Vec<String>), Custom(ObjectName, Vec<String>),
/// Arrays /// Arrays
Array(Box<DataType>), Array(Option<Box<DataType>>),
/// Enums /// Enums
Enum(Vec<String>), Enum(Vec<String>),
/// Set /// Set
@ -232,7 +232,13 @@ impl fmt::Display for DataType {
DataType::Text => write!(f, "TEXT"), DataType::Text => write!(f, "TEXT"),
DataType::String => write!(f, "STRING"), DataType::String => write!(f, "STRING"),
DataType::Bytea => write!(f, "BYTEA"), 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) => { DataType::Custom(ty, modifiers) => {
if modifiers.is_empty() { if modifiers.is_empty() {
write!(f, "{}", ty) write!(f, "{}", ty)

View file

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

View file

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

View file

@ -1324,9 +1324,9 @@ fn parse_array_index_expr() {
})], })],
named: true, named: true,
})), })),
data_type: DataType::Array(Box::new(DataType::Array(Box::new(DataType::Int( data_type: DataType::Array(Some(Box::new(DataType::Array(Some(Box::new(
None DataType::Int(None)
))))) ))))))
}))), }))),
indexes: vec![num[1].clone(), num[2].clone()], 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] #[test]
fn parse_json_using_colon() { fn parse_json_using_colon() {
let sql = "SELECT a:b FROM t"; let sql = "SELECT a:b FROM t";