Skip to content

Commit de8903f

Browse files
fix(sqlparser): typed string must be single quoted (#17482)
Signed-off-by: Runji Wang <wangrunji0408@163.com> Co-authored-by: Runji Wang <wangrunji0408@163.com>
1 parent ed09372 commit de8903f

File tree

7 files changed

+47
-24
lines changed

7 files changed

+47
-24
lines changed

e2e_test/ddl/show.slt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ show tables from public;
102102
t3
103103

104104
query T
105-
show tables from public like "t_";
105+
show tables from public like 't_';
106106
----
107107
t3
108108

109109
query T
110-
show tables from public like "_t";
110+
show tables from public like '_t';
111111
----
112112

113113
query T

src/frontend/src/handler/create_sql_function.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ pub async fn handle_create_sql_function(
150150
let body = match &params.as_ {
151151
Some(FunctionDefinition::SingleQuotedDef(s)) => s.clone(),
152152
Some(FunctionDefinition::DoubleDollarDef(s)) => s.clone(),
153+
Some(FunctionDefinition::Identifier(_)) => {
154+
return Err(ErrorCode::InvalidParameterValue("expect quoted string".to_string()).into())
155+
}
153156
None => {
154157
if params.return_.is_none() {
155158
return Err(ErrorCode::InvalidParameterValue(

src/sqlparser/src/ast/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2885,13 +2885,15 @@ impl fmt::Display for FunctionBehavior {
28852885
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
28862886
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28872887
pub enum FunctionDefinition {
2888+
Identifier(String),
28882889
SingleQuotedDef(String),
28892890
DoubleDollarDef(String),
28902891
}
28912892

28922893
impl fmt::Display for FunctionDefinition {
28932894
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28942895
match self {
2896+
FunctionDefinition::Identifier(s) => write!(f, "{s}")?,
28952897
FunctionDefinition::SingleQuotedDef(s) => write!(f, "'{s}'")?,
28962898
FunctionDefinition::DoubleDollarDef(s) => write!(f, "$${s}$$")?,
28972899
}
@@ -2903,6 +2905,7 @@ impl FunctionDefinition {
29032905
/// Returns the function definition as a string slice.
29042906
pub fn as_str(&self) -> &str {
29052907
match self {
2908+
FunctionDefinition::Identifier(s) => s,
29062909
FunctionDefinition::SingleQuotedDef(s) => s,
29072910
FunctionDefinition::DoubleDollarDef(s) => s,
29082911
}
@@ -2911,6 +2914,7 @@ impl FunctionDefinition {
29112914
/// Returns the function definition as a string.
29122915
pub fn into_string(self) -> String {
29132916
match self {
2917+
FunctionDefinition::Identifier(s) => s,
29142918
FunctionDefinition::SingleQuotedDef(s) => s,
29152919
FunctionDefinition::DoubleDollarDef(s) => s,
29162920
}

src/sqlparser/src/parser.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ use winnow::{PResult, Parser as _};
3030
use crate::ast::*;
3131
use crate::keywords::{self, Keyword};
3232
use crate::parser_v2;
33-
use crate::parser_v2::{keyword, literal_i64, literal_uint, single_quoted_string, ParserExt as _};
33+
use crate::parser_v2::{
34+
dollar_quoted_string, keyword, literal_i64, literal_uint, single_quoted_string, ParserExt as _,
35+
};
3436
use crate::tokenizer::*;
3537

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

35523554
pub fn parse_function_definition(&mut self) -> PResult<FunctionDefinition> {
3553-
let peek_token = self.peek_token();
3554-
match peek_token.token {
3555-
Token::DollarQuotedString(value) => {
3556-
self.next_token();
3557-
Ok(FunctionDefinition::DoubleDollarDef(value.value))
3558-
}
3559-
_ => Ok(FunctionDefinition::SingleQuotedDef(
3560-
self.parse_literal_string()?,
3561-
)),
3562-
}
3555+
alt((
3556+
single_quoted_string.map(FunctionDefinition::SingleQuotedDef),
3557+
dollar_quoted_string.map(FunctionDefinition::DoubleDollarDef),
3558+
Self::parse_identifier.map(|i| FunctionDefinition::Identifier(i.value)),
3559+
fail.expect("function definition"),
3560+
))
3561+
.parse_next(self)
35633562
}
35643563

35653564
/// Parse a literal string
35663565
pub fn parse_literal_string(&mut self) -> PResult<String> {
35673566
let checkpoint = *self;
35683567
let token = self.next_token();
35693568
match token.token {
3570-
Token::Word(Word {
3571-
value,
3572-
keyword: Keyword::NoKeyword,
3573-
..
3574-
}) => Ok(value),
35753569
Token::SingleQuotedString(s) => Ok(s),
35763570
_ => self.expected_at(checkpoint, "literal string"),
35773571
}

src/sqlparser/src/parser_v2/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ where
129129
.parse_next(input)
130130
}
131131

132+
/// Consume an $$ dollar-quoted string $$.
133+
pub fn dollar_quoted_string<S>(input: &mut S) -> PResult<String>
134+
where
135+
S: TokenStream,
136+
{
137+
token
138+
.verify_map(|t| match &t.token {
139+
Token::DollarQuotedString(s) => Some(s.value.clone()),
140+
_ => None,
141+
})
142+
.parse_next(input)
143+
}
144+
132145
/// Consume an object name.
133146
///
134147
/// FIXME: Object name is extremely complex, we only handle a subset here.

src/sqlparser/tests/testdata/select.yaml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,10 @@
9797
- input: SELECT timestamp with time zone '2022-10-01 12:00:00Z' AT TIME ZONE zone
9898
formatted_sql: SELECT TIMESTAMP WITH TIME ZONE '2022-10-01 12:00:00Z' AT TIME ZONE zone
9999
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 })'
100-
# https://www.postgresql.org/message-id/CADT4RqBPdbsZW7HS1jJP319TMRHs1hzUiP=iRJYR6UqgHCrgNQ@mail.gmail.com
101-
- input: SELECT now() + INTERVAL '14 days' AT TIME ZONE 'UTC';
100+
- input: SELECT now() + INTERVAL '14 days' AT TIME ZONE 'UTC'; -- https://www.postgresql.org/message-id/CADT4RqBPdbsZW7HS1jJP319TMRHs1hzUiP=iRJYR6UqgHCrgNQ@mail.gmail.com
102101
formatted_sql: SELECT now() + INTERVAL '14 days' AT TIME ZONE 'UTC'
103102
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 })'
104-
# https://github.com/sqlparser-rs/sqlparser-rs/issues/1266
105-
- input: SELECT c FROM t WHERE c >= '2019-03-27T22:00:00.000Z'::timestamp AT TIME ZONE 'Europe/Brussels';
103+
- 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
106104
formatted_sql: SELECT c FROM t WHERE c >= CAST('2019-03-27T22:00:00.000Z' AS TIMESTAMP) AT TIME ZONE 'Europe/Brussels'
107105
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 })'
108106
- input: SELECT 0c6
@@ -222,3 +220,14 @@
222220
sql parser error: expected statement, found: selet
223221
LINE 1: selet 1;
224222
^
223+
- input: select date t::date; -- https://github.com/risingwavelabs/risingwave/issues/17461
224+
error_msg: |-
225+
sql parser error: expected end of statement, found: ::
226+
LINE 1: select date t::date; -- https://github.com/risingwavelabs/risingwave/issues/17461
227+
^
228+
- input: select date 't'::date; -- TypedString higher precedence than Cast
229+
formatted_sql: SELECT CAST(DATE 't' AS DATE)
230+
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 })'
231+
- input: select date t; -- A column "date" aliased to "t"
232+
formatted_sql: SELECT date AS t
233+
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 })'

src/sqlparser/tests/testdata/show.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
- input: SHOW TABLES FROM t
1212
formatted_sql: SHOW TABLES FROM t
1313
formatted_ast: 'ShowObjects { object: Table { schema: Some(Ident { value: "t", quote_style: None }) }, filter: None }'
14-
- input: SHOW TABLES FROM t LIKE "t%"
14+
- input: SHOW TABLES FROM t LIKE 't%'
1515
formatted_sql: SHOW TABLES FROM t LIKE 't%'
1616
formatted_ast: 'ShowObjects { object: Table { schema: Some(Ident { value: "t", quote_style: None }) }, filter: Some(Like("t%")) }'
1717
- input: SHOW VIEWS
@@ -29,7 +29,7 @@
2929
- input: SHOW INTERNAL TABLES FROM t
3030
formatted_sql: SHOW INTERNAL TABLES FROM t
3131
formatted_ast: 'ShowObjects { object: InternalTable { schema: Some(Ident { value: "t", quote_style: None }) }, filter: None }'
32-
- input: SHOW INTERNAL TABLES LIKE "%mv1%"
32+
- input: SHOW INTERNAL TABLES LIKE '%mv1%'
3333
formatted_sql: SHOW INTERNAL TABLES LIKE '%mv1%'
3434
formatted_ast: 'ShowObjects { object: InternalTable { schema: None }, filter: Some(Like("%mv1%")) }'
3535
- input: SHOW MATERIALIZED VIEWS FROM t

0 commit comments

Comments
 (0)