From 917b835a6aa1d10de1e2ffaaa8d6c75b276dd300 Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 23 Jan 2025 11:08:04 +0200 Subject: [PATCH 01/10] wip --- src/parser/mod.rs | 18 +++++++++++++++--- tests/sqlparser_bigquery.rs | 21 +++++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 355e520ab..80d264efe 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8442,12 +8442,24 @@ impl<'a> Parser<'a> { keyword: Keyword::NoKeyword, .. }) => Ok(value), - Token::SingleQuotedString(s) => Ok(s), - Token::DoubleQuotedString(s) => Ok(s), + Token::SingleQuotedString(s) + | Token::DoubleQuotedString(s) + | Token::TripleSingleQuotedString(s) + | Token::TripleDoubleQuotedString(s) + | Token::SingleQuotedByteStringLiteral(s) + | Token::DoubleQuotedByteStringLiteral(s) + | Token::TripleSingleQuotedByteStringLiteral(s) + | Token::TripleDoubleQuotedByteStringLiteral(s) + | Token::SingleQuotedRawStringLiteral(s) + | Token::DoubleQuotedRawStringLiteral(s) + | Token::TripleSingleQuotedRawStringLiteral(s) + | Token::TripleDoubleQuotedRawStringLiteral(s) + | Token::NationalStringLiteral(s) + | Token::HexStringLiteral(s) + | Token::UnicodeStringLiteral(s) => Ok(s), Token::EscapedStringLiteral(s) if dialect_of!(self is PostgreSqlDialect | GenericDialect) => { Ok(s) } - Token::UnicodeStringLiteral(s) => Ok(s), _ => self.expected("literal string", next_token), } } diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index a173a6cc9..a5c7630ac 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -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 {})], @@ -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]) ); @@ -2214,6 +2214,23 @@ fn test_select_as_value() { assert_eq!(Some(ValueTableMode::AsValue), select.value_table_mode); } +#[test] +fn test_typed_strings() { + bigquery().verified_expr(r#"JSON """{"foo":"bar's"}""""#); + bigquery().verified_expr(r#"JSON '''{"foo":"bar's"}'''"#); + bigquery().verified_expr(r#"JSON '{"foo":"bar\'s"}'"#); + bigquery().verified_expr(r#"JSON "{\"foo\":\"bar's\"}""#); + + let select = bigquery().verified_only_select(r#"SELECT JSON """{\"foo\":\"bar\"}""""#); + assert_eq!( + vec![SelectItem::UnnamedExpr(Expr::TypedString { + data_type: DataType::JSON, + value: r#"{"foo":"bar's"}"#.to_string() + }),], + select.projection + ); +} + #[test] fn test_array_agg() { bigquery_and_generic().verified_expr("ARRAY_AGG(state)"); From 78ff17611e5d23e5feacff0eb0b075bfa3210d23 Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 23 Jan 2025 11:44:30 +0200 Subject: [PATCH 02/10] fix --- src/ast/mod.rs | 4 ++-- src/ast/spans.rs | 4 ++-- src/parser/mod.rs | 2 +- tests/sqlparser_bigquery.rs | 43 +++++++++++++++++++++++-------------- tests/sqlparser_common.rs | 28 +++++++++++++----------- tests/sqlparser_postgres.rs | 2 +- 6 files changed, 48 insertions(+), 35 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 2fc89e29b..7d47c55d2 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -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), @@ -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}"), diff --git a/src/ast/spans.rs b/src/ast/spans.rs index acd3987da..f15679f11 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -1265,7 +1265,7 @@ impl Spanned for AssignmentTarget { /// f.e. `IS NULL ` reports as `::span`. /// /// Missing spans: -/// - [Expr::TypedString] +/// - [Expr::TypedString] # missing span for data_type /// - [Expr::MatchAgainst] # MySQL specific /// - [Expr::RLike] # MySQL specific /// - [Expr::Struct] # BigQuery specific @@ -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()))) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 80d264efe..05b21f87c 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -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()?, }), } })?; diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index a5c7630ac..174522960 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -809,7 +809,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -862,7 +862,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"}]}}"#.to_string() + ) },], fields: vec![StructField { field_name: None, @@ -889,7 +891,9 @@ 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".to_string() + ) },], fields: vec![StructField { field_name: None, @@ -903,7 +907,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -920,7 +924,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -933,7 +937,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -1124,7 +1128,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -1177,7 +1181,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"}]}}"#.to_string() + ) },], fields: vec![StructField { field_name: None, @@ -1204,7 +1210,9 @@ 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".to_string() + ) },], fields: vec![StructField { field_name: None, @@ -1218,7 +1226,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -1235,7 +1243,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -1248,7 +1256,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".to_string()) },], fields: vec![StructField { field_name: None, @@ -2218,14 +2226,17 @@ fn test_select_as_value() { fn test_typed_strings() { bigquery().verified_expr(r#"JSON """{"foo":"bar's"}""""#); bigquery().verified_expr(r#"JSON '''{"foo":"bar's"}'''"#); - bigquery().verified_expr(r#"JSON '{"foo":"bar\'s"}'"#); - bigquery().verified_expr(r#"JSON "{\"foo\":\"bar's\"}""#); - let select = bigquery().verified_only_select(r#"SELECT JSON """{\"foo\":\"bar\"}""""#); + // 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\"}""#); + + let select = bigquery().verified_only_select(r#"SELECT JSON """{"foo":"bar's"}""""#); assert_eq!( vec![SelectItem::UnnamedExpr(Expr::TypedString { data_type: DataType::JSON, - value: r#"{"foo":"bar's"}"#.to_string() + value: Value::TripleDoubleQuotedString(r#"{"foo":"bar's"}"#.to_string()) }),], select.projection ); diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index ebd6bef03..3f8bc9021 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -5295,7 +5295,7 @@ fn parse_literal_date() { assert_eq!( &Expr::TypedString { data_type: DataType::Date, - value: "1999-01-01".into(), + value: Value::SingleQuotedString("1999-01-01".into()), }, expr_from_projection(only(&select.projection)), ); @@ -5308,7 +5308,7 @@ fn parse_literal_time() { assert_eq!( &Expr::TypedString { data_type: DataType::Time(None, TimezoneInfo::None), - value: "01:23:34".into(), + value: Value::SingleQuotedString("01:23:34".to_string()), }, expr_from_projection(only(&select.projection)), ); @@ -5321,7 +5321,7 @@ fn parse_literal_datetime() { assert_eq!( &Expr::TypedString { data_type: DataType::Datetime(None), - value: "1999-01-01 01:23:34.45".into(), + value: Value::SingleQuotedString("1999-01-01 01:23:34.45".to_string()), }, expr_from_projection(only(&select.projection)), ); @@ -5334,7 +5334,7 @@ fn parse_literal_timestamp_without_time_zone() { assert_eq!( &Expr::TypedString { data_type: DataType::Timestamp(None, TimezoneInfo::None), - value: "1999-01-01 01:23:34".into(), + value: Value::SingleQuotedString("1999-01-01 01:23:34".to_string()), }, expr_from_projection(only(&select.projection)), ); @@ -5349,7 +5349,7 @@ fn parse_literal_timestamp_with_time_zone() { assert_eq!( &Expr::TypedString { data_type: DataType::Timestamp(None, TimezoneInfo::Tz), - value: "1999-01-01 01:23:34Z".into(), + value: Value::SingleQuotedString("1999-01-01 01:23:34Z".to_string()), }, expr_from_projection(only(&select.projection)), ); @@ -5901,7 +5901,8 @@ fn parse_json_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::JSON, - value: r#"{ + value: Value::SingleQuotedString( + r#"{ "id": 10, "type": "fruit", "name": "apple", @@ -5921,7 +5922,8 @@ fn parse_json_keyword() { ] } }"# - .into() + .to_string() + ) }, expr_from_projection(only(&select.projection)), ); @@ -5934,7 +5936,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: r#"0"#.into() + value: Value::SingleQuotedString(r#"0"#.to_string()) }, expr_from_projection(only(&select.projection)), ); @@ -5945,7 +5947,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: r#"123456"#.into() + value: Value::SingleQuotedString(r#"123456"#.to_string()) }, expr_from_projection(only(&select.projection)), ); @@ -5956,7 +5958,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: r#"-3.14"#.into() + value: Value::SingleQuotedString(r#"-3.14"#.to_string()) }, expr_from_projection(only(&select.projection)), ); @@ -5967,7 +5969,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: r#"-0.54321"#.into() + value: Value::SingleQuotedString(r#"-0.54321"#.to_string()) }, expr_from_projection(only(&select.projection)), ); @@ -5978,7 +5980,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: r#"1.23456e05"#.into() + value: Value::SingleQuotedString(r#"1.23456e05"#.to_string()) }, expr_from_projection(only(&select.projection)), ); @@ -5989,7 +5991,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: r#"-9.876e-3"#.into() + value: Value::SingleQuotedString(r#"-9.876e-3"#.to_string()) }, expr_from_projection(only(&select.projection)), ); diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 0fca4cec1..01be64a5b 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -4618,7 +4618,7 @@ fn parse_at_time_zone() { left: Box::new(Expr::AtTimeZone { timestamp: Box::new(Expr::TypedString { data_type: DataType::Timestamp(None, TimezoneInfo::None), - value: "2001-09-28 01:00".to_owned(), + value: Value::SingleQuotedString("2001-09-28 01:00".to_string()), }), time_zone: Box::new(Expr::Cast { kind: CastKind::DoubleColon, From cb2cd7ca980bef34c0ee6248a355029d37a3487b Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 23 Jan 2025 11:53:44 +0200 Subject: [PATCH 03/10] undo unnecessary change --- src/parser/mod.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 05b21f87c..cb062ce90 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8444,18 +8444,6 @@ impl<'a> Parser<'a> { }) => Ok(value), Token::SingleQuotedString(s) | Token::DoubleQuotedString(s) - | Token::TripleSingleQuotedString(s) - | Token::TripleDoubleQuotedString(s) - | Token::SingleQuotedByteStringLiteral(s) - | Token::DoubleQuotedByteStringLiteral(s) - | Token::TripleSingleQuotedByteStringLiteral(s) - | Token::TripleDoubleQuotedByteStringLiteral(s) - | Token::SingleQuotedRawStringLiteral(s) - | Token::DoubleQuotedRawStringLiteral(s) - | Token::TripleSingleQuotedRawStringLiteral(s) - | Token::TripleDoubleQuotedRawStringLiteral(s) - | Token::NationalStringLiteral(s) - | Token::HexStringLiteral(s) | Token::UnicodeStringLiteral(s) => Ok(s), Token::EscapedStringLiteral(s) if dialect_of!(self is PostgreSqlDialect | GenericDialect) => { Ok(s) From 10790ce799128f442cccdea3c8d3e4af8b9cd735 Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 23 Jan 2025 11:55:16 +0200 Subject: [PATCH 04/10] undo unnecessary change --- src/parser/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index cb062ce90..e4f480ab5 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8442,12 +8442,12 @@ impl<'a> Parser<'a> { keyword: Keyword::NoKeyword, .. }) => Ok(value), - Token::SingleQuotedString(s) - | Token::DoubleQuotedString(s) - | Token::UnicodeStringLiteral(s) => Ok(s), + Token::SingleQuotedString(s) => Ok(s), + Token::DoubleQuotedString(s) => Ok(s), Token::EscapedStringLiteral(s) if dialect_of!(self is PostgreSqlDialect | GenericDialect) => { Ok(s) } + Token::UnicodeStringLiteral(s) => Ok(s), _ => self.expected("literal string", next_token), } } From caf1604522509fff02e2e7877252569d2db978ad Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 23 Jan 2025 16:30:33 +0200 Subject: [PATCH 05/10] Add Into impl --- src/ast/value.rs | 26 ++++++++++ tests/sqlparser_bigquery.rs | 94 ++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 49 deletions(-) diff --git a/src/ast/value.rs b/src/ast/value.rs index 1b16646be..12b75e58c 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -97,6 +97,32 @@ pub enum Value { Placeholder(String), } +impl Into 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 { diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index 174522960..7504ba108 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -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]) ); @@ -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]) @@ -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]) @@ -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") }, ], @@ -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 @@ -809,7 +807,7 @@ fn parse_typed_struct_syntax_bigquery() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::Datetime(None), - value: Value::SingleQuotedString("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, @@ -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, @@ -863,7 +861,7 @@ fn parse_typed_struct_syntax_bigquery() { values: vec![Expr::TypedString { data_type: DataType::JSON, value: Value::SingleQuotedString( - r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.to_string() + r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.into() ) },], fields: vec![StructField { @@ -879,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)) @@ -891,9 +889,7 @@ fn parse_typed_struct_syntax_bigquery() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::Timestamp(None, TimezoneInfo::None), - value: Value::SingleQuotedString( - "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, @@ -907,7 +903,7 @@ fn parse_typed_struct_syntax_bigquery() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::Time(None, TimezoneInfo::None), - value: Value::SingleQuotedString("15:30:00".to_string()) + value: Value::SingleQuotedString("15:30:00".into()) },], fields: vec![StructField { field_name: None, @@ -924,7 +920,7 @@ fn parse_typed_struct_syntax_bigquery() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::Numeric(ExactNumberInfo::None), - value: Value::SingleQuotedString("1".to_string()) + value: Value::SingleQuotedString("1".into()) },], fields: vec![StructField { field_name: None, @@ -937,7 +933,7 @@ fn parse_typed_struct_syntax_bigquery() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString("1".to_string()) + value: Value::SingleQuotedString("1".into()) },], fields: vec![StructField { field_name: None, @@ -1114,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 @@ -1128,7 +1122,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::Datetime(None), - value: Value::SingleQuotedString("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, @@ -1164,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, @@ -1182,7 +1176,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() { values: vec![Expr::TypedString { data_type: DataType::JSON, value: Value::SingleQuotedString( - r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.to_string() + r#"{"class" : {"students" : [{"name" : "Jane"}]}}"#.into() ) },], fields: vec![StructField { @@ -1198,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)) @@ -1210,9 +1204,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::Timestamp(None, TimezoneInfo::None), - value: Value::SingleQuotedString( - "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, @@ -1226,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: Value::SingleQuotedString("15:30:00".to_string()) + value: Value::SingleQuotedString("15:30:00".into()) },], fields: vec![StructField { field_name: None, @@ -1243,7 +1235,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::Numeric(ExactNumberInfo::None), - value: Value::SingleQuotedString("1".to_string()) + value: Value::SingleQuotedString("1".into()) },], fields: vec![StructField { field_name: None, @@ -1256,7 +1248,7 @@ fn parse_typed_struct_syntax_bigquery_and_generic() { &Expr::Struct { values: vec![Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString("1".to_string()) + value: Value::SingleQuotedString("1".into()) },], fields: vec![StructField { field_name: None, @@ -1284,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) @@ -1331,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) @@ -2224,22 +2216,26 @@ fn test_select_as_value() { #[test] fn test_typed_strings() { - bigquery().verified_expr(r#"JSON """{"foo":"bar's"}""""#); - bigquery().verified_expr(r#"JSON '''{"foo":"bar's"}'''"#); + 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\"}""#); - - let select = bigquery().verified_only_select(r#"SELECT JSON """{"foo":"bar's"}""""#); - assert_eq!( - vec![SelectItem::UnnamedExpr(Expr::TypedString { - data_type: DataType::JSON, - value: Value::TripleDoubleQuotedString(r#"{"foo":"bar's"}"#.to_string()) - }),], - select.projection - ); } #[test] From dc7c6adcd4e7148b38e9dd5f41658d27c105d3e8 Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Tue, 28 Jan 2025 20:40:52 +0200 Subject: [PATCH 06/10] Value::as_str --- src/ast/mod.rs | 4 ++++ src/ast/value.rs | 17 +++++++++++------ tests/sqlparser_bigquery.rs | 28 ++++++++++++++++++---------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 5c16d48e5..d7b9416b5 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -898,6 +898,8 @@ pub enum Expr { /// IntroducedString { introducer: String, + /// The value of the constant. + /// Hint: you can unwrap the string value using `value.as_str()`. value: Value, }, /// A constant of form ` 'value'`. @@ -905,6 +907,8 @@ pub enum Expr { /// as well as constants of other types (a non-standard PostgreSQL extension). TypedString { data_type: DataType, + /// The value of the constant. + /// Hint: you can unwrap the string value using `value.as_str()`. value: Value, }, /// Scalar function call e.g. `LEFT(foo, 5)` diff --git a/src/ast/value.rs b/src/ast/value.rs index 12b75e58c..49080a340 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -97,14 +97,19 @@ pub enum Value { Placeholder(String), } -impl Into for Value { - fn into(self) -> String { +impl Value { + /// Get the string value of a `Value` wrapping a string. + /// This includes all quotation styles + /// `{Single,Double,TripleSingle,TripleDouble}{QuotedString,RawString,ByteString}` + /// as well as `EscapedStringLiteral`, `UnicodeStringLiteral`, `NationalStringLiteral`, + /// `HexStringLiteral`, `DollarQuotedString`. + /// This will panic if called on a non-string variant like `Value::Number`` or `Value::Null`. + pub fn as_str(self) -> String { match self { Value::SingleQuotedString(s) => s, + Value::DoubleQuotedString(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, @@ -113,10 +118,10 @@ impl Into for Value { Value::DoubleQuotedRawStringLiteral(s) => s, Value::TripleSingleQuotedRawStringLiteral(s) => s, Value::TripleDoubleQuotedRawStringLiteral(s) => s, + Value::EscapedStringLiteral(s) => s, + Value::UnicodeStringLiteral(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"), } diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index 2e4dc01ea..19019e01c 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -39,14 +39,16 @@ fn parse_literal_string() { r#"'''triple-single'unescaped''', "#, r#""double\"escaped", "#, r#""""triple-double\"escaped""", "#, - r#""""triple-double"un'escaped""""#, + r#""""triple-double"unescaped""", "#, + r#""""triple-double'unescaped""", "#, + r#"'''triple-single"unescaped'''"#, ); let dialect = TestedDialects::new_with_options( vec![Box::new(BigQueryDialect {})], ParserOptions::new().with_unescape(false), ); let select = dialect.verified_only_select(sql); - assert_eq!(10, select.projection.len()); + assert_eq!(12, select.projection.len()); assert_eq!( &Expr::Value(Value::SingleQuotedString("single".into())), expr_from_projection(&select.projection[0]) @@ -91,10 +93,22 @@ fn parse_literal_string() { ); assert_eq!( &Expr::Value(Value::TripleDoubleQuotedString( - r#"triple-double"un'escaped"#.to_string() + r#"triple-double"unescaped"#.to_string() )), expr_from_projection(&select.projection[9]) ); + assert_eq!( + &Expr::Value(Value::TripleDoubleQuotedString( + r#"triple-double'unescaped"#.to_string() + )), + expr_from_projection(&select.projection[10]) + ); + assert_eq!( + &Expr::Value(Value::TripleSingleQuotedString( + r#"triple-single"unescaped"#.to_string() + )), + expr_from_projection(&select.projection[11]) + ); } #[test] @@ -2239,14 +2253,8 @@ fn test_typed_strings() { 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); + assert_eq!(r#"{"foo":"bar's"}"#, value.as_str()); } - - // 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] From eec32234bd74c3d66c699f62f4b2bfbab85c0391 Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 30 Jan 2025 10:49:37 +0200 Subject: [PATCH 07/10] into_string -> Option --- src/ast/value.rs | 45 +++++++++++++++++-------------------- tests/sqlparser_bigquery.rs | 2 +- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/ast/value.rs b/src/ast/value.rs index 49080a340..5798b5404 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -98,32 +98,27 @@ pub enum Value { } impl Value { - /// Get the string value of a `Value` wrapping a string. - /// This includes all quotation styles - /// `{Single,Double,TripleSingle,TripleDouble}{QuotedString,RawString,ByteString}` - /// as well as `EscapedStringLiteral`, `UnicodeStringLiteral`, `NationalStringLiteral`, - /// `HexStringLiteral`, `DollarQuotedString`. - /// This will panic if called on a non-string variant like `Value::Number`` or `Value::Null`. - pub fn as_str(self) -> String { + /// If the underlying literal is a string, regardless of quote style, returns the associated string value + pub fn into_string(self) -> Option { match self { - Value::SingleQuotedString(s) => s, - Value::DoubleQuotedString(s) => s, - Value::TripleSingleQuotedString(s) => s, - Value::TripleDoubleQuotedString(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::EscapedStringLiteral(s) => s, - Value::UnicodeStringLiteral(s) => s, - Value::NationalStringLiteral(s) => s, - Value::HexStringLiteral(s) => s, - Value::DollarQuotedString(s) => s.value, - _ => panic!("not a string value"), + Value::SingleQuotedString(s) + | Value::DoubleQuotedString(s) + | Value::TripleSingleQuotedString(s) + | Value::TripleDoubleQuotedString(s) + | Value::SingleQuotedByteStringLiteral(s) + | Value::DoubleQuotedByteStringLiteral(s) + | Value::TripleSingleQuotedByteStringLiteral(s) + | Value::TripleDoubleQuotedByteStringLiteral(s) + | Value::SingleQuotedRawStringLiteral(s) + | Value::DoubleQuotedRawStringLiteral(s) + | Value::TripleSingleQuotedRawStringLiteral(s) + | Value::TripleDoubleQuotedRawStringLiteral(s) + | Value::EscapedStringLiteral(s) + | Value::UnicodeStringLiteral(s) + | Value::NationalStringLiteral(s) + | Value::HexStringLiteral(s) => Some(s), + Value::DollarQuotedString(s) => Some(s.value), + _ => None, } } } diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index 19019e01c..ec4f1342f 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -2253,7 +2253,7 @@ fn test_typed_strings() { let expr = bigquery().verified_expr(r#"JSON '''{"foo":"bar's"}'''"#); if let Expr::TypedString { data_type, value } = expr { assert_eq!(DataType::JSON, data_type); - assert_eq!(r#"{"foo":"bar's"}"#, value.as_str()); + assert_eq!(r#"{"foo":"bar's"}"#, value.into_string().unwrap()); } } From e79d799ca098f212f0716848d066c497dfdd8fb8 Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 30 Jan 2025 10:57:17 +0200 Subject: [PATCH 08/10] fix docstring --- src/ast/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d7b9416b5..159193b64 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -899,7 +899,7 @@ pub enum Expr { IntroducedString { introducer: String, /// The value of the constant. - /// Hint: you can unwrap the string value using `value.as_str()`. + /// Hint: you can unwrap the string value using `value.into_string()`. value: Value, }, /// A constant of form ` 'value'`. @@ -908,7 +908,7 @@ pub enum Expr { TypedString { data_type: DataType, /// The value of the constant. - /// Hint: you can unwrap the string value using `value.as_str()`. + /// Hint: you can unwrap the string value using `value.into_string()`. value: Value, }, /// Scalar function call e.g. `LEFT(foo, 5)` From 1ead5c985c67c0810b6b5749de04c88a474094cf Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Thu, 30 Jan 2025 11:18:04 +0200 Subject: [PATCH 09/10] move common test --- tests/sqlparser_bigquery.rs | 10 +++------- tests/sqlparser_common.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs index ec4f1342f..af4083c48 100644 --- a/tests/sqlparser_bigquery.rs +++ b/tests/sqlparser_bigquery.rs @@ -2240,7 +2240,9 @@ fn test_select_as_value() { } #[test] -fn test_typed_strings() { +fn test_triple_quote_typed_strings() { + bigquery().verified_expr(r#"JSON '''{"foo":"bar's"}'''"#); + let expr = bigquery().verified_expr(r#"JSON """{"foo":"bar's"}""""#); assert_eq!( Expr::TypedString { @@ -2249,12 +2251,6 @@ fn test_typed_strings() { }, 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); - assert_eq!(r#"{"foo":"bar's"}"#, value.into_string().unwrap()); - } } #[test] diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 59a35a32c..481d7ffc1 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -6020,6 +6020,23 @@ fn parse_json_keyword() { ); } +#[test] +fn parse_typed_strings() { + let expr = verified_expr(r#"JSON '{"foo":"bar"}'"#); + assert_eq!( + Expr::TypedString { + data_type: DataType::JSON, + value: Value::SingleQuotedString(r#"{"foo":"bar"}"#.into()) + }, + expr + ); + + if let Expr::TypedString { data_type, value } = expr { + assert_eq!(DataType::JSON, data_type); + assert_eq!(r#"{"foo":"bar"}"#, value.into_string().unwrap()); + } +} + #[test] fn parse_bignumeric_keyword() { let sql = r#"SELECT BIGNUMERIC '0'"#; From cad6ef0a7e7dac0f4cc7c13e3d2a006c6815885a Mon Sep 17 00:00:00 2001 From: Paul Grau Date: Fri, 31 Jan 2025 01:32:59 +0200 Subject: [PATCH 10/10] undo some unnecessary changes --- tests/sqlparser_common.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 481d7ffc1..9f1deb849 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -5399,7 +5399,7 @@ fn parse_literal_time() { assert_eq!( &Expr::TypedString { data_type: DataType::Time(None, TimezoneInfo::None), - value: Value::SingleQuotedString("01:23:34".to_string()), + value: Value::SingleQuotedString("01:23:34".into()), }, expr_from_projection(only(&select.projection)), ); @@ -5412,7 +5412,7 @@ fn parse_literal_datetime() { assert_eq!( &Expr::TypedString { data_type: DataType::Datetime(None), - value: Value::SingleQuotedString("1999-01-01 01:23:34.45".to_string()), + value: Value::SingleQuotedString("1999-01-01 01:23:34.45".into()), }, expr_from_projection(only(&select.projection)), ); @@ -5425,7 +5425,7 @@ fn parse_literal_timestamp_without_time_zone() { assert_eq!( &Expr::TypedString { data_type: DataType::Timestamp(None, TimezoneInfo::None), - value: Value::SingleQuotedString("1999-01-01 01:23:34".to_string()), + value: Value::SingleQuotedString("1999-01-01 01:23:34".into()), }, expr_from_projection(only(&select.projection)), ); @@ -5440,7 +5440,7 @@ fn parse_literal_timestamp_with_time_zone() { assert_eq!( &Expr::TypedString { data_type: DataType::Timestamp(None, TimezoneInfo::Tz), - value: Value::SingleQuotedString("1999-01-01 01:23:34Z".to_string()), + value: Value::SingleQuotedString("1999-01-01 01:23:34Z".into()), }, expr_from_projection(only(&select.projection)), ); @@ -6044,7 +6044,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString(r#"0"#.to_string()) + value: Value::SingleQuotedString(r#"0"#.into()) }, expr_from_projection(only(&select.projection)), ); @@ -6055,7 +6055,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString(r#"123456"#.to_string()) + value: Value::SingleQuotedString(r#"123456"#.into()) }, expr_from_projection(only(&select.projection)), ); @@ -6066,7 +6066,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString(r#"-3.14"#.to_string()) + value: Value::SingleQuotedString(r#"-3.14"#.into()) }, expr_from_projection(only(&select.projection)), ); @@ -6077,7 +6077,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString(r#"-0.54321"#.to_string()) + value: Value::SingleQuotedString(r#"-0.54321"#.into()) }, expr_from_projection(only(&select.projection)), ); @@ -6088,7 +6088,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString(r#"1.23456e05"#.to_string()) + value: Value::SingleQuotedString(r#"1.23456e05"#.into()) }, expr_from_projection(only(&select.projection)), ); @@ -6099,7 +6099,7 @@ fn parse_bignumeric_keyword() { assert_eq!( &Expr::TypedString { data_type: DataType::BigNumeric(ExactNumberInfo::None), - value: Value::SingleQuotedString(r#"-9.876e-3"#.to_string()) + value: Value::SingleQuotedString(r#"-9.876e-3"#.into()) }, expr_from_projection(only(&select.projection)), );