Skip to content

Commit 8b3278b

Browse files
committed
bigquery: CAST AS x FORMAT support
1 parent db19d83 commit 8b3278b

File tree

6 files changed

+94
-4
lines changed

6 files changed

+94
-4
lines changed

src/ast/mod.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,19 +507,22 @@ pub enum Expr {
507507
Cast {
508508
expr: Box<Expr>,
509509
data_type: DataType,
510+
format: Option<Value>,
510511
},
511512
/// TRY_CAST an expression to a different data type e.g. `TRY_CAST(foo AS VARCHAR(123))`
512513
// this differs from CAST in the choice of how to implement invalid conversions
513514
TryCast {
514515
expr: Box<Expr>,
515516
data_type: DataType,
517+
format: Option<Value>,
516518
},
517519
/// SAFE_CAST an expression to a different data type e.g. `SAFE_CAST(foo AS FLOAT64)`
518520
// only available for BigQuery: https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#safe_casting
519521
// this works the same as `TRY_CAST`
520522
SafeCast {
521523
expr: Box<Expr>,
522524
data_type: DataType,
525+
format: Option<Value>,
523526
},
524527
/// AT a timestamp to a different timezone e.g. `FROM_UNIXTIME(0) AT TIME ZONE 'UTC-06:00'`
525528
AtTimeZone {
@@ -809,9 +812,27 @@ impl fmt::Display for Expr {
809812
write!(f, "{op}{expr}")
810813
}
811814
}
812-
Expr::Cast { expr, data_type } => write!(f, "CAST({expr} AS {data_type})"),
813-
Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({expr} AS {data_type})"),
814-
Expr::SafeCast { expr, data_type } => write!(f, "SAFE_CAST({expr} AS {data_type})"),
815+
Expr::Cast { expr, data_type, format } => {
816+
if let Some(format) = format {
817+
write!(f, "CAST({expr} AS {data_type} FORMAT {format})")
818+
} else {
819+
write!(f, "CAST({expr} AS {data_type})")
820+
}
821+
},
822+
Expr::TryCast { expr, data_type, format } => {
823+
if let Some(format) = format {
824+
write!(f, "TRY_CAST({expr} AS {data_type} FORMAT {format})")
825+
} else {
826+
write!(f, "TRY_CAST({expr} AS {data_type})")
827+
}
828+
},
829+
Expr::SafeCast { expr, data_type, format } => {
830+
if let Some(format) = format {
831+
write!(f, "SAFE_CAST({expr} AS {data_type} FORMAT {format})")
832+
} else {
833+
write!(f, "SAFE_CAST({expr} AS {data_type})")
834+
}
835+
},
815836
Expr::Extract { field, expr } => write!(f, "EXTRACT({field} FROM {expr})"),
816837
Expr::Ceil { expr, field } => {
817838
if field == &DateTimeField::NoDateTime {

src/parser.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,10 +1085,18 @@ impl<'a> Parser<'a> {
10851085
let expr = self.parse_expr()?;
10861086
self.expect_keyword(Keyword::AS)?;
10871087
let data_type = self.parse_data_type()?;
1088+
1089+
let format = if dialect_of!(self is BigQueryDialect) && self.parse_keyword(Keyword::FORMAT) {
1090+
Some(self.parse_value()?)
1091+
} else {
1092+
None
1093+
};
1094+
10881095
self.expect_token(&Token::RParen)?;
10891096
Ok(Expr::Cast {
10901097
expr: Box::new(expr),
10911098
data_type,
1099+
format,
10921100
})
10931101
}
10941102

@@ -1098,10 +1106,18 @@ impl<'a> Parser<'a> {
10981106
let expr = self.parse_expr()?;
10991107
self.expect_keyword(Keyword::AS)?;
11001108
let data_type = self.parse_data_type()?;
1109+
1110+
let format = if dialect_of!(self is BigQueryDialect) && self.parse_keyword(Keyword::FORMAT) {
1111+
Some(self.parse_value()?)
1112+
} else {
1113+
None
1114+
};
1115+
11011116
self.expect_token(&Token::RParen)?;
11021117
Ok(Expr::TryCast {
11031118
expr: Box::new(expr),
11041119
data_type,
1120+
format,
11051121
})
11061122
}
11071123

@@ -1111,10 +1127,18 @@ impl<'a> Parser<'a> {
11111127
let expr = self.parse_expr()?;
11121128
self.expect_keyword(Keyword::AS)?;
11131129
let data_type = self.parse_data_type()?;
1130+
1131+
let format = if dialect_of!(self is BigQueryDialect) && self.parse_keyword(Keyword::FORMAT) {
1132+
Some(self.parse_value()?)
1133+
} else {
1134+
None
1135+
};
1136+
11141137
self.expect_token(&Token::RParen)?;
11151138
Ok(Expr::SafeCast {
11161139
expr: Box::new(expr),
11171140
data_type,
1141+
format,
11181142
})
11191143
}
11201144

@@ -1990,6 +2014,7 @@ impl<'a> Parser<'a> {
19902014
Ok(Expr::Cast {
19912015
expr: Box::new(expr),
19922016
data_type: self.parse_data_type()?,
2017+
format: None,
19932018
})
19942019
}
19952020

tests/sqlparser_bigquery.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,37 @@ fn parse_cast_type() {
203203
bigquery().verified_only_select(sql);
204204
}
205205

206+
#[test]
207+
fn parse_cast_date_format() {
208+
let sql = r#"SELECT CAST(date_valid_from AS DATE FORMAT 'YYYY-MM-DD') AS date_valid_from FROM foo"#;
209+
bigquery().verified_only_select(sql);
210+
}
211+
212+
#[test]
213+
fn parse_cast_time_format() {
214+
let sql = r#"SELECT CAST(TIME '21:30:00' AS STRING FORMAT 'PM') AS date_time_to_string"#;
215+
bigquery().verified_only_select(sql);
216+
}
217+
218+
#[test]
219+
#[ignore]
220+
fn parse_cast_timestamp_format_tz() {
221+
let sql = r#"SELECT CAST(TIMESTAMP '2008-12-25 00:00:00+00:00' AS STRING FORMAT 'TZH' AT TIME ZONE 'Asia/Kolkata') AS date_time_to_string"#;
222+
bigquery().verified_only_select(sql);
223+
}
224+
225+
#[test]
226+
fn parse_cast_string_to_bytes_format() {
227+
let sql = r#"SELECT CAST('Hello' AS BYTES FORMAT 'ASCII') AS string_to_bytes"#;
228+
bigquery().verified_only_select(sql);
229+
}
230+
231+
#[test]
232+
fn parse_cast_bytes_to_string_format() {
233+
let sql = r#"SELECT CAST(B'\x48\x65\x6c\x6c\x6f' AS STRING FORMAT 'ASCII') AS bytes_to_string"#;
234+
bigquery().verified_only_select(sql);
235+
}
236+
206237
#[test]
207238
fn parse_like() {
208239
fn chk(negated: bool) {

tests/sqlparser_common.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,7 @@ fn parse_cast() {
17891789
&Expr::Cast {
17901790
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
17911791
data_type: DataType::BigInt(None),
1792+
format: None,
17921793
},
17931794
expr_from_projection(only(&select.projection))
17941795
);
@@ -1799,6 +1800,7 @@ fn parse_cast() {
17991800
&Expr::Cast {
18001801
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18011802
data_type: DataType::TinyInt(None),
1803+
format: None,
18021804
},
18031805
expr_from_projection(only(&select.projection))
18041806
);
@@ -1825,6 +1827,7 @@ fn parse_cast() {
18251827
&Expr::Cast {
18261828
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18271829
data_type: DataType::Nvarchar(Some(50)),
1830+
format: None,
18281831
},
18291832
expr_from_projection(only(&select.projection))
18301833
);
@@ -1835,6 +1838,7 @@ fn parse_cast() {
18351838
&Expr::Cast {
18361839
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18371840
data_type: DataType::Clob(None),
1841+
format: None,
18381842
},
18391843
expr_from_projection(only(&select.projection))
18401844
);
@@ -1845,6 +1849,7 @@ fn parse_cast() {
18451849
&Expr::Cast {
18461850
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18471851
data_type: DataType::Clob(Some(50)),
1852+
format: None,
18481853
},
18491854
expr_from_projection(only(&select.projection))
18501855
);
@@ -1855,6 +1860,7 @@ fn parse_cast() {
18551860
&Expr::Cast {
18561861
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18571862
data_type: DataType::Binary(Some(50)),
1863+
format: None,
18581864
},
18591865
expr_from_projection(only(&select.projection))
18601866
);
@@ -1865,6 +1871,7 @@ fn parse_cast() {
18651871
&Expr::Cast {
18661872
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18671873
data_type: DataType::Varbinary(Some(50)),
1874+
format: None,
18681875
},
18691876
expr_from_projection(only(&select.projection))
18701877
);
@@ -1875,6 +1882,7 @@ fn parse_cast() {
18751882
&Expr::Cast {
18761883
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18771884
data_type: DataType::Blob(None),
1885+
format: None,
18781886
},
18791887
expr_from_projection(only(&select.projection))
18801888
);
@@ -1885,6 +1893,7 @@ fn parse_cast() {
18851893
&Expr::Cast {
18861894
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
18871895
data_type: DataType::Blob(Some(50)),
1896+
format: None,
18881897
},
18891898
expr_from_projection(only(&select.projection))
18901899
);
@@ -1898,6 +1907,7 @@ fn parse_try_cast() {
18981907
&Expr::TryCast {
18991908
expr: Box::new(Expr::Identifier(Ident::new("id").empty_span())),
19001909
data_type: DataType::BigInt(None),
1910+
format: None,
19011911
},
19021912
expr_from_projection(only(&select.projection))
19031913
);

tests/sqlparser_postgres.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1775,7 +1775,9 @@ fn parse_array_index_expr() {
17751775
})),
17761776
data_type: DataType::Array(Some(Box::new(DataType::Array(Some(Box::new(
17771777
DataType::Int(None)
1778-
))))))
1778+
)))))),
1779+
format: None,
1780+
17791781
}))),
17801782
indexes: vec![num[1].clone(), num[2].clone()],
17811783
},

tests/sqlparser_snowflake.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ fn parse_array() {
169169
&Expr::Cast {
170170
expr: Box::new(Expr::Identifier(Ident::new("a").empty_span())),
171171
data_type: DataType::Array(None),
172+
format: None,
172173
},
173174
expr_from_projection(only(&select.projection))
174175
);

0 commit comments

Comments
 (0)