Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ pub enum Expr {
/// as well as constants of other types (a non-standard PostgreSQL extension).
TypedString {
data_type: DataType,
value: String,
value: Value,
},
/// Scalar function call e.g. `LEFT(foo, 5)`
Function(Function),
Expand Down Expand Up @@ -1589,7 +1589,7 @@ impl fmt::Display for Expr {
Expr::IntroducedString { introducer, value } => write!(f, "{introducer} {value}"),
Expr::TypedString { data_type, value } => {
write!(f, "{data_type}")?;
write!(f, " '{}'", &value::escape_single_quote_string(value))
write!(f, " {value}")
}
Expr::Function(fun) => write!(f, "{fun}"),
Expr::Method(method) => write!(f, "{method}"),
Expand Down
4 changes: 2 additions & 2 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1265,7 +1265,7 @@ impl Spanned for AssignmentTarget {
/// f.e. `IS NULL <expr>` reports as `<expr>::span`.
///
/// Missing spans:
/// - [Expr::TypedString]
/// - [Expr::TypedString] # missing span for data_type
/// - [Expr::MatchAgainst] # MySQL specific
/// - [Expr::RLike] # MySQL specific
/// - [Expr::Struct] # BigQuery specific
Expand Down Expand Up @@ -1361,7 +1361,7 @@ impl Spanned for Expr {
.union(&union_spans(collation.0.iter().map(|i| i.span))),
Expr::Nested(expr) => expr.span(),
Expr::Value(value) => value.span(),
Expr::TypedString { .. } => Span::empty(),
Expr::TypedString { value, .. } => value.span(),
Expr::Function(function) => function.span(),
Expr::GroupingSets(vec) => {
union_spans(vec.iter().flat_map(|i| i.iter().map(|k| k.span())))
Expand Down
26 changes: 26 additions & 0 deletions src/ast/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,32 @@ pub enum Value {
Placeholder(String),
}

impl Into<String> for Value {
fn into(self) -> String {
match self {
Value::SingleQuotedString(s) => s,
Value::TripleSingleQuotedString(s) => s,
Value::TripleDoubleQuotedString(s) => s,
Value::EscapedStringLiteral(s) => s,
Value::UnicodeStringLiteral(s) => s,
Value::SingleQuotedByteStringLiteral(s) => s,
Value::DoubleQuotedByteStringLiteral(s) => s,
Value::TripleSingleQuotedByteStringLiteral(s) => s,
Value::TripleDoubleQuotedByteStringLiteral(s) => s,
Value::SingleQuotedRawStringLiteral(s) => s,
Value::DoubleQuotedRawStringLiteral(s) => s,
Value::TripleSingleQuotedRawStringLiteral(s) => s,
Value::TripleDoubleQuotedRawStringLiteral(s) => s,
Value::NationalStringLiteral(s) => s,
Value::HexStringLiteral(s) => s,
Value::DoubleQuotedString(s) => s,
Value::Placeholder(s) => s,
Value::DollarQuotedString(s) => s.value,
_ => panic!("not a string value"),
}
}
}

impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand Down
2 changes: 1 addition & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,7 +1316,7 @@ impl<'a> Parser<'a> {
DataType::Custom(..) => parser_err!("dummy", loc),
data_type => Ok(Expr::TypedString {
data_type,
value: parser.parse_literal_string()?,
value: parser.parse_value()?,
}),
}
})?;
Expand Down
96 changes: 60 additions & 36 deletions tests/sqlparser_bigquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn parse_literal_string() {
r#"'''triple-single'unescaped''', "#,
r#""double\"escaped", "#,
r#""""triple-double\"escaped""", "#,
r#""""triple-double"unescaped""""#,
r#""""triple-double"un'escaped""""#,
);
let dialect = TestedDialects::new_with_options(
vec![Box::new(BigQueryDialect {})],
Expand All @@ -48,34 +48,34 @@ fn parse_literal_string() {
let select = dialect.verified_only_select(sql);
assert_eq!(10, select.projection.len());
assert_eq!(
&Expr::Value(Value::SingleQuotedString("single".to_string())),
&Expr::Value(Value::SingleQuotedString("single".into())),
expr_from_projection(&select.projection[0])
);
assert_eq!(
&Expr::Value(Value::DoubleQuotedString("double".to_string())),
&Expr::Value(Value::DoubleQuotedString("double".into())),
expr_from_projection(&select.projection[1])
);
assert_eq!(
&Expr::Value(Value::TripleSingleQuotedString("triple-single".to_string())),
&Expr::Value(Value::TripleSingleQuotedString("triple-single".into())),
expr_from_projection(&select.projection[2])
);
assert_eq!(
&Expr::Value(Value::TripleDoubleQuotedString("triple-double".to_string())),
&Expr::Value(Value::TripleDoubleQuotedString("triple-double".into())),
expr_from_projection(&select.projection[3])
);
assert_eq!(
&Expr::Value(Value::SingleQuotedString(r#"single\'escaped"#.to_string())),
&Expr::Value(Value::SingleQuotedString(r#"single\'escaped"#.into())),
expr_from_projection(&select.projection[4])
);
assert_eq!(
&Expr::Value(Value::TripleSingleQuotedString(
r#"triple-single\'escaped"#.to_string()
r#"triple-single\'escaped"#.into()
)),
expr_from_projection(&select.projection[5])
);
assert_eq!(
&Expr::Value(Value::TripleSingleQuotedString(
r#"triple-single'unescaped"#.to_string()
r#"triple-single'unescaped"#.into()
)),
expr_from_projection(&select.projection[6])
);
Expand All @@ -91,7 +91,7 @@ fn parse_literal_string() {
);
assert_eq!(
&Expr::Value(Value::TripleDoubleQuotedString(
r#"triple-double"unescaped"#.to_string()
r#"triple-double"un'escaped"#.to_string()
)),
expr_from_projection(&select.projection[9])
);
Expand Down Expand Up @@ -579,7 +579,7 @@ fn parse_tuple_struct_literal() {
&Expr::Tuple(vec![
Expr::Value(number("1")),
Expr::Value(number("1.0")),
Expr::Value(Value::SingleQuotedString("123".to_string())),
Expr::Value(Value::SingleQuotedString("123".into())),
Expr::Value(Value::Boolean(true))
]),
expr_from_projection(&select.projection[1])
Expand Down Expand Up @@ -607,7 +607,7 @@ fn parse_typeless_struct_syntax() {

assert_eq!(
&Expr::Struct {
values: vec![Expr::Value(Value::SingleQuotedString("abc".to_string())),],
values: vec![Expr::Value(Value::SingleQuotedString("abc".into())),],
fields: Default::default()
},
expr_from_projection(&select.projection[1])
Expand All @@ -630,7 +630,7 @@ fn parse_typeless_struct_syntax() {
name: Ident::from("a")
},
Expr::Named {
expr: Expr::Value(Value::SingleQuotedString("abc".to_string())).into(),
expr: Expr::Value(Value::SingleQuotedString("abc".into())).into(),
name: Ident::from("b")
},
],
Expand Down Expand Up @@ -795,9 +795,7 @@ fn parse_typed_struct_syntax_bigquery() {
assert_eq!(4, select.projection.len());
assert_eq!(
&Expr::Struct {
values: vec![Expr::Value(Value::DoubleQuotedString(
"2011-05-05".to_string()
)),],
values: vec![Expr::Value(Value::DoubleQuotedString("2011-05-05".into())),],
fields: vec![StructField {
field_name: None,
field_type: DataType::Date
Expand All @@ -809,7 +807,7 @@ fn parse_typed_struct_syntax_bigquery() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Datetime(None),
value: "1999-01-01 01:23:34.45".to_string()
value: Value::SingleQuotedString("1999-01-01 01:23:34.45".into())
},],
fields: vec![StructField {
field_name: None,
Expand Down Expand Up @@ -845,7 +843,7 @@ fn parse_typed_struct_syntax_bigquery() {
assert_eq!(
&Expr::Struct {
values: vec![Expr::Interval(Interval {
value: Box::new(Expr::Value(Value::SingleQuotedString("2".to_string()))),
value: Box::new(Expr::Value(Value::SingleQuotedString("2".into()))),
leading_field: Some(DateTimeField::Hour),
leading_precision: None,
last_field: None,
Expand All @@ -862,7 +860,9 @@ fn parse_typed_struct_syntax_bigquery() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::JSON,
value: r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.to_string()
value: Value::SingleQuotedString(
r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.into()
)
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -877,7 +877,7 @@ fn parse_typed_struct_syntax_bigquery() {
assert_eq!(3, select.projection.len());
assert_eq!(
&Expr::Struct {
values: vec![Expr::Value(Value::DoubleQuotedString("foo".to_string())),],
values: vec![Expr::Value(Value::DoubleQuotedString("foo".into())),],
fields: vec![StructField {
field_name: None,
field_type: DataType::String(Some(42))
Expand All @@ -889,7 +889,7 @@ fn parse_typed_struct_syntax_bigquery() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Timestamp(None, TimezoneInfo::None),
value: "2008-12-25 15:30:00 America/Los_Angeles".to_string()
value: Value::SingleQuotedString("2008-12-25 15:30:00 America/Los_Angeles".into())
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -903,7 +903,7 @@ fn parse_typed_struct_syntax_bigquery() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Time(None, TimezoneInfo::None),
value: "15:30:00".to_string()
value: Value::SingleQuotedString("15:30:00".into())
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -920,7 +920,7 @@ fn parse_typed_struct_syntax_bigquery() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Numeric(ExactNumberInfo::None),
value: "1".to_string()
value: Value::SingleQuotedString("1".into())
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -933,7 +933,7 @@ fn parse_typed_struct_syntax_bigquery() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::BigNumeric(ExactNumberInfo::None),
value: "1".to_string()
value: Value::SingleQuotedString("1".into())
},],
fields: vec![StructField {
field_name: None,
Expand Down Expand Up @@ -1110,9 +1110,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
assert_eq!(4, select.projection.len());
assert_eq!(
&Expr::Struct {
values: vec![Expr::Value(Value::SingleQuotedString(
"2011-05-05".to_string()
)),],
values: vec![Expr::Value(Value::SingleQuotedString("2011-05-05".into())),],
fields: vec![StructField {
field_name: None,
field_type: DataType::Date
Expand All @@ -1124,7 +1122,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Datetime(None),
value: "1999-01-01 01:23:34.45".to_string()
value: Value::SingleQuotedString("1999-01-01 01:23:34.45".into())
},],
fields: vec![StructField {
field_name: None,
Expand Down Expand Up @@ -1160,7 +1158,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
assert_eq!(
&Expr::Struct {
values: vec![Expr::Interval(Interval {
value: Box::new(Expr::Value(Value::SingleQuotedString("1".to_string()))),
value: Box::new(Expr::Value(Value::SingleQuotedString("1".into()))),
leading_field: Some(DateTimeField::Month),
leading_precision: None,
last_field: None,
Expand All @@ -1177,7 +1175,9 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::JSON,
value: r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.to_string()
value: Value::SingleQuotedString(
r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.into()
)
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -1192,7 +1192,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
assert_eq!(3, select.projection.len());
assert_eq!(
&Expr::Struct {
values: vec![Expr::Value(Value::SingleQuotedString("foo".to_string())),],
values: vec![Expr::Value(Value::SingleQuotedString("foo".into())),],
fields: vec![StructField {
field_name: None,
field_type: DataType::String(Some(42))
Expand All @@ -1204,7 +1204,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Timestamp(None, TimezoneInfo::None),
value: "2008-12-25 15:30:00 America/Los_Angeles".to_string()
value: Value::SingleQuotedString("2008-12-25 15:30:00 America/Los_Angeles".into())
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -1218,7 +1218,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Time(None, TimezoneInfo::None),
value: "15:30:00".to_string()
value: Value::SingleQuotedString("15:30:00".into())
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -1235,7 +1235,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::Numeric(ExactNumberInfo::None),
value: "1".to_string()
value: Value::SingleQuotedString("1".into())
},],
fields: vec![StructField {
field_name: None,
Expand All @@ -1248,7 +1248,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() {
&Expr::Struct {
values: vec![Expr::TypedString {
data_type: DataType::BigNumeric(ExactNumberInfo::None),
value: "1".to_string()
value: Value::SingleQuotedString("1".into())
},],
fields: vec![StructField {
field_name: None,
Expand Down Expand Up @@ -1276,7 +1276,7 @@ fn parse_typed_struct_with_field_name_bigquery() {
);
assert_eq!(
&Expr::Struct {
values: vec![Expr::Value(Value::DoubleQuotedString("foo".to_string())),],
values: vec![Expr::Value(Value::DoubleQuotedString("foo".into())),],
fields: vec![StructField {
field_name: Some(Ident::from("y")),
field_type: DataType::String(None)
Expand Down Expand Up @@ -1323,7 +1323,7 @@ fn parse_typed_struct_with_field_name_bigquery_and_generic() {
);
assert_eq!(
&Expr::Struct {
values: vec![Expr::Value(Value::SingleQuotedString("foo".to_string())),],
values: vec![Expr::Value(Value::SingleQuotedString("foo".into())),],
fields: vec![StructField {
field_name: Some(Ident::from("y")),
field_type: DataType::String(None)
Expand Down Expand Up @@ -2214,6 +2214,30 @@ fn test_select_as_value() {
assert_eq!(Some(ValueTableMode::AsValue), select.value_table_mode);
}

#[test]
fn test_typed_strings() {
let expr = bigquery().verified_expr(r#"JSON """{"foo":"bar's"}""""#);
assert_eq!(
Expr::TypedString {
data_type: DataType::JSON,
value: Value::TripleDoubleQuotedString(r#"{"foo":"bar's"}"#.into())
},
expr
);

let expr = bigquery().verified_expr(r#"JSON '''{"foo":"bar's"}'''"#);
if let Expr::TypedString { data_type, value } = expr {
assert_eq!(DataType::JSON, data_type);
let string_value: String = value.into();
assert_eq!(r#"{"foo":"bar's"}"#, string_value);
}

// SingleQuotedString and DoubleQuotedString are currently not correctly formatted by `fmt::Display for Value`.
// BigQuery does not support double escaping, should be \' or \" instead.
//bigquery().verified_expr(r#"JSON '{"foo":"bar\'s"}'"#);
//bigquery().verified_expr(r#"JSON "{\"foo\":\"bar's\"}""#);
}

#[test]
fn test_array_agg() {
bigquery_and_generic().verified_expr("ARRAY_AGG(state)");
Expand Down
Loading