Skip to content

Commit

Permalink
fix(sqlparser): typed string must be single quoted (#17482) (#17495)
Browse files Browse the repository at this point in the history
Signed-off-by: Runji Wang <[email protected]>
Co-authored-by: xiangjinwu <[email protected]>
Co-authored-by: Runji Wang <[email protected]>
  • Loading branch information
3 people authored Jun 28, 2024
1 parent b78272d commit e61b27e
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 24 deletions.
4 changes: 2 additions & 2 deletions e2e_test/ddl/show.slt
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ show tables from public;
t3

query T
show tables from public like "t_";
show tables from public like 't_';
----
t3

query T
show tables from public like "_t";
show tables from public like '_t';
----

query T
Expand Down
3 changes: 3 additions & 0 deletions src/frontend/src/handler/create_sql_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ pub async fn handle_create_sql_function(
let body = match &params.as_ {
Some(FunctionDefinition::SingleQuotedDef(s)) => s.clone(),
Some(FunctionDefinition::DoubleDollarDef(s)) => s.clone(),
Some(FunctionDefinition::Identifier(_)) => {
return Err(ErrorCode::InvalidParameterValue("expect quoted string".to_string()).into())
}
None => {
if params.return_.is_none() {
return Err(ErrorCode::InvalidParameterValue(
Expand Down
4 changes: 4 additions & 0 deletions src/sqlparser/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2885,13 +2885,15 @@ impl fmt::Display for FunctionBehavior {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum FunctionDefinition {
Identifier(String),
SingleQuotedDef(String),
DoubleDollarDef(String),
}

impl fmt::Display for FunctionDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FunctionDefinition::Identifier(s) => write!(f, "{s}")?,
FunctionDefinition::SingleQuotedDef(s) => write!(f, "'{s}'")?,
FunctionDefinition::DoubleDollarDef(s) => write!(f, "$${s}$$")?,
}
Expand All @@ -2903,6 +2905,7 @@ impl FunctionDefinition {
/// Returns the function definition as a string slice.
pub fn as_str(&self) -> &str {
match self {
FunctionDefinition::Identifier(s) => s,
FunctionDefinition::SingleQuotedDef(s) => s,
FunctionDefinition::DoubleDollarDef(s) => s,
}
Expand All @@ -2911,6 +2914,7 @@ impl FunctionDefinition {
/// Returns the function definition as a string.
pub fn into_string(self) -> String {
match self {
FunctionDefinition::Identifier(s) => s,
FunctionDefinition::SingleQuotedDef(s) => s,
FunctionDefinition::DoubleDollarDef(s) => s,
}
Expand Down
26 changes: 10 additions & 16 deletions src/sqlparser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ use winnow::{PResult, Parser as _};
use crate::ast::*;
use crate::keywords::{self, Keyword};
use crate::parser_v2;
use crate::parser_v2::{keyword, literal_i64, literal_uint, single_quoted_string, ParserExt as _};
use crate::parser_v2::{
dollar_quoted_string, keyword, literal_i64, literal_uint, single_quoted_string, ParserExt as _,
};
use crate::tokenizer::*;

pub(crate) const UPSTREAM_SOURCE_KEY: &str = "connector";
Expand Down Expand Up @@ -3550,28 +3552,20 @@ impl Parser<'_> {
}

pub fn parse_function_definition(&mut self) -> PResult<FunctionDefinition> {
let peek_token = self.peek_token();
match peek_token.token {
Token::DollarQuotedString(value) => {
self.next_token();
Ok(FunctionDefinition::DoubleDollarDef(value.value))
}
_ => Ok(FunctionDefinition::SingleQuotedDef(
self.parse_literal_string()?,
)),
}
alt((
single_quoted_string.map(FunctionDefinition::SingleQuotedDef),
dollar_quoted_string.map(FunctionDefinition::DoubleDollarDef),
Self::parse_identifier.map(|i| FunctionDefinition::Identifier(i.value)),
fail.expect("function definition"),
))
.parse_next(self)
}

/// Parse a literal string
pub fn parse_literal_string(&mut self) -> PResult<String> {
let checkpoint = *self;
let token = self.next_token();
match token.token {
Token::Word(Word {
value,
keyword: Keyword::NoKeyword,
..
}) => Ok(value),
Token::SingleQuotedString(s) => Ok(s),
_ => self.expected_at(checkpoint, "literal string"),
}
Expand Down
13 changes: 13 additions & 0 deletions src/sqlparser/src/parser_v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,19 @@ where
.parse_next(input)
}

/// Consume an $$ dollar-quoted string $$.
pub fn dollar_quoted_string<S>(input: &mut S) -> PResult<String>
where
S: TokenStream,
{
token
.verify_map(|t| match &t.token {
Token::DollarQuotedString(s) => Some(s.value.clone()),
_ => None,
})
.parse_next(input)
}

/// Consume an object name.
///
/// FIXME: Object name is extremely complex, we only handle a subset here.
Expand Down
17 changes: 13 additions & 4 deletions src/sqlparser/tests/testdata/select.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,10 @@
- input: SELECT timestamp with time zone '2022-10-01 12:00:00Z' AT TIME ZONE zone
formatted_sql: SELECT TIMESTAMP WITH TIME ZONE '2022-10-01 12:00:00Z' AT TIME ZONE zone
formatted_ast: 'Query(Query { with: None, body: Select(Select { distinct: All, projection: [UnnamedExpr(AtTimeZone { timestamp: TypedString { data_type: Timestamp(true), value: "2022-10-01 12:00:00Z" }, time_zone: Identifier(Ident { value: "zone", quote_style: None }) })], from: [], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'
# https://www.postgresql.org/message-id/CADT4RqBPdbsZW7HS1jJP319TMRHs1hzUiP=iRJYR6UqgHCrgNQ@mail.gmail.com
- input: SELECT now() + INTERVAL '14 days' AT TIME ZONE 'UTC';
- input: SELECT now() + INTERVAL '14 days' AT TIME ZONE 'UTC'; -- https://www.postgresql.org/message-id/CADT4RqBPdbsZW7HS1jJP319TMRHs1hzUiP=iRJYR6UqgHCrgNQ@mail.gmail.com
formatted_sql: SELECT now() + INTERVAL '14 days' AT TIME ZONE 'UTC'
formatted_ast: 'Query(Query { with: None, body: Select(Select { distinct: All, projection: [UnnamedExpr(BinaryOp { left: Function(Function { name: ObjectName([Ident { value: "now", quote_style: None }]), args: [], variadic: false, over: None, distinct: false, order_by: [], filter: None, within_group: None }), op: Plus, right: AtTimeZone { timestamp: Value(Interval { value: "14 days", leading_field: None, leading_precision: None, last_field: None, fractional_seconds_precision: None }), time_zone: Value(SingleQuotedString("UTC")) } })], from: [], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'
# https://github.com/sqlparser-rs/sqlparser-rs/issues/1266
- input: SELECT c FROM t WHERE c >= '2019-03-27T22:00:00.000Z'::timestamp AT TIME ZONE 'Europe/Brussels';
- input: SELECT c FROM t WHERE c >= '2019-03-27T22:00:00.000Z'::timestamp AT TIME ZONE 'Europe/Brussels'; -- https://github.com/sqlparser-rs/sqlparser-rs/issues/1266
formatted_sql: SELECT c FROM t WHERE c >= CAST('2019-03-27T22:00:00.000Z' AS TIMESTAMP) AT TIME ZONE 'Europe/Brussels'
formatted_ast: 'Query(Query { with: None, body: Select(Select { distinct: All, projection: [UnnamedExpr(Identifier(Ident { value: "c", quote_style: None }))], from: [TableWithJoins { relation: Table { name: ObjectName([Ident { value: "t", quote_style: None }]), alias: None, as_of: None }, joins: [] }], lateral_views: [], selection: Some(BinaryOp { left: Identifier(Ident { value: "c", quote_style: None }), op: GtEq, right: AtTimeZone { timestamp: Cast { expr: Value(SingleQuotedString("2019-03-27T22:00:00.000Z")), data_type: Timestamp(false) }, time_zone: Value(SingleQuotedString("Europe/Brussels")) } }), group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'
- input: SELECT 0c6
Expand Down Expand Up @@ -222,3 +220,14 @@
sql parser error: expected statement, found: selet
LINE 1: selet 1;
^
- input: select date t::date; -- https://github.com/risingwavelabs/risingwave/issues/17461
error_msg: |-
sql parser error: expected end of statement, found: ::
LINE 1: select date t::date; -- https://github.com/risingwavelabs/risingwave/issues/17461
^
- input: select date 't'::date; -- TypedString higher precedence than Cast
formatted_sql: SELECT CAST(DATE 't' AS DATE)
formatted_ast: 'Query(Query { with: None, body: Select(Select { distinct: All, projection: [UnnamedExpr(Cast { expr: TypedString { data_type: Date, value: "t" }, data_type: Date })], from: [], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'
- input: select date t; -- A column "date" aliased to "t"
formatted_sql: SELECT date AS t
formatted_ast: 'Query(Query { with: None, body: Select(Select { distinct: All, projection: [ExprWithAlias { expr: Identifier(Ident { value: "date", quote_style: None }), alias: Ident { value: "t", quote_style: None } }], from: [], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'
4 changes: 2 additions & 2 deletions src/sqlparser/tests/testdata/show.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- input: SHOW TABLES FROM t
formatted_sql: SHOW TABLES FROM t
formatted_ast: 'ShowObjects { object: Table { schema: Some(Ident { value: "t", quote_style: None }) }, filter: None }'
- input: SHOW TABLES FROM t LIKE "t%"
- input: SHOW TABLES FROM t LIKE 't%'
formatted_sql: SHOW TABLES FROM t LIKE 't%'
formatted_ast: 'ShowObjects { object: Table { schema: Some(Ident { value: "t", quote_style: None }) }, filter: Some(Like("t%")) }'
- input: SHOW VIEWS
Expand All @@ -29,7 +29,7 @@
- input: SHOW INTERNAL TABLES FROM t
formatted_sql: SHOW INTERNAL TABLES FROM t
formatted_ast: 'ShowObjects { object: InternalTable { schema: Some(Ident { value: "t", quote_style: None }) }, filter: None }'
- input: SHOW INTERNAL TABLES LIKE "%mv1%"
- input: SHOW INTERNAL TABLES LIKE '%mv1%'
formatted_sql: SHOW INTERNAL TABLES LIKE '%mv1%'
formatted_ast: 'ShowObjects { object: InternalTable { schema: None }, filter: Some(Like("%mv1%")) }'
- input: SHOW MATERIALIZED VIEWS FROM t
Expand Down

0 comments on commit e61b27e

Please sign in to comment.