feat: support SAFE_CAST for bigquery (#552)

Co-authored-by: togami2864 <yoshiaki.togami@plaid.co.jp>
This commit is contained in:
Yoshi Togami 2022-08-03 22:17:39 +09:00 committed by GitHub
parent 2a04212e56
commit e24951e080
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 0 deletions

View file

@ -285,6 +285,13 @@ pub enum Expr {
expr: Box<Expr>,
data_type: DataType,
},
/// SAFE_CAST an expression to a different data type e.g. `SAFE_CAST(foo AS FLOAT64)`
// only available for BigQuery: https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#safe_casting
// this works the same as `TRY_CAST`
SafeCast {
expr: Box<Expr>,
data_type: DataType,
},
/// AT a timestamp to a different timezone e.g. `FROM_UNIXTIME(0) AT TIME ZONE 'UTC-06:00'`
AtTimeZone {
timestamp: Box<Expr>,
@ -442,6 +449,7 @@ impl fmt::Display for Expr {
}
Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type),
Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({} AS {})", expr, data_type),
Expr::SafeCast { expr, data_type } => write!(f, "SAFE_CAST({} AS {})", expr, data_type),
Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr),
Expr::Position { expr, r#in } => write!(f, "POSITION({} IN {})", expr, r#in),
Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation),

View file

@ -439,6 +439,7 @@ define_keywords!(
ROWID,
ROWS,
ROW_NUMBER,
SAFE_CAST,
SAVEPOINT,
SCHEMA,
SCOPE,

View file

@ -426,6 +426,7 @@ impl<'a> Parser<'a> {
Keyword::CASE => self.parse_case_expr(),
Keyword::CAST => self.parse_cast_expr(),
Keyword::TRY_CAST => self.parse_try_cast_expr(),
Keyword::SAFE_CAST => self.parse_safe_cast_expr(),
Keyword::EXISTS => self.parse_exists_expr(false),
Keyword::EXTRACT => self.parse_extract_expr(),
Keyword::POSITION => self.parse_position_expr(),
@ -780,6 +781,19 @@ impl<'a> Parser<'a> {
})
}
/// Parse a BigQuery SAFE_CAST function e.g. `SAFE_CAST(expr AS FLOAT64)`
pub fn parse_safe_cast_expr(&mut self) -> Result<Expr, ParserError> {
self.expect_token(&Token::LParen)?;
let expr = self.parse_expr()?;
self.expect_keyword(Keyword::AS)?;
let data_type = self.parse_data_type()?;
self.expect_token(&Token::RParen)?;
Ok(Expr::SafeCast {
expr: Box::new(expr),
data_type,
})
}
/// Parse a SQL EXISTS expression e.g. `WHERE EXISTS(SELECT ...)`.
pub fn parse_exists_expr(&mut self, negated: bool) -> Result<Expr, ParserError> {
self.expect_token(&Token::LParen)?;

View file

@ -94,6 +94,12 @@ fn parse_table_identifiers() {
test_table_ident("abc5.GROUP", vec![Ident::new("abc5"), Ident::new("GROUP")]);
}
#[test]
fn parse_cast_type() {
let sql = r#"SELECT SAFE_CAST(1 AS INT64)"#;
bigquery().verified_only_select(sql);
}
fn bigquery() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(BigQueryDialect {})],