You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/09/22 16:21:41 UTC
(datafusion-sqlparser-rs) 01/01: Fix `TABLE` command identifier quoting and token consumption (#2540)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-2540-5d9de3617123e8a633f5dc35ef39fb5a045dd3eb
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 2a9ab6cbcc4dc383ed0590a38ed7d44637d4e651
Author: Luca Cappelletti <ca...@gmail.com>
AuthorDate: Tue Sep 22 16:21:15 2026 +0000
Fix `TABLE` command identifier quoting and token consumption (#2540)
---
src/ast/query.rs | 7 +++----
src/parser/mod.rs | 40 ++++++----------------------------------
tests/sqlparser_common.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 53 insertions(+), 41 deletions(-)
diff --git a/src/ast/query.rs b/src/ast/query.rs
index 296e4e8ca..98a9c84ae 100644
--- a/src/ast/query.rs
+++ b/src/ast/query.rs
@@ -295,14 +295,13 @@ impl fmt::Display for SetQuantifier {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-/// A [`TABLE` command]( https://www.postgresql.org/docs/current/sql-select.html#SQL-TABLE)
+/// A [`TABLE` command](https://www.postgresql.org/docs/current/sql-select.html#SQL-TABLE)
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
-/// A (possibly schema-qualified) table reference used in `FROM` clauses.
pub struct Table {
/// Optional table name (absent for e.g. `TABLE` command without argument).
- pub table_name: Option<String>,
+ pub table_name: Option<Ident>,
/// Optional schema/catalog name qualifying the table.
- pub schema_name: Option<String>,
+ pub schema_name: Option<Ident>,
}
impl fmt::Display for Table {
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 74d97a085..e1e397fcc 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -15625,44 +15625,16 @@ impl<'a> Parser<'a> {
/// Parse `CREATE TABLE x AS TABLE y`
pub fn parse_as_table(&mut self) -> Result<Table, ParserError> {
- let token1 = self.next_token();
- let token2 = self.next_token();
- let token3 = self.next_token();
-
- let table_name;
- let schema_name;
- if token2 == Token::Period {
- match token1.token {
- Token::Word(w) => {
- schema_name = w.value;
- }
- _ => {
- return self.expected("Schema name", token1);
- }
- }
- match token3.token {
- Token::Word(w) => {
- table_name = w.value;
- }
- _ => {
- return self.expected("Table name", token3);
- }
- }
+ let first_name = self.parse_identifier()?;
+ if self.consume_token(&Token::Period) {
+ let second_name = self.parse_identifier()?;
Ok(Table {
- table_name: Some(table_name),
- schema_name: Some(schema_name),
+ table_name: Some(second_name),
+ schema_name: Some(first_name),
})
} else {
- match token1.token {
- Token::Word(w) => {
- table_name = w.value;
- }
- _ => {
- return self.expected("Table name", token1);
- }
- }
Ok(Table {
- table_name: Some(table_name),
+ table_name: Some(first_name),
schema_name: None,
})
}
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index c4aa607d8..4343e652b 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -4848,7 +4848,7 @@ fn parse_create_table_as_table() {
let expected_query1 = Box::new(Query {
with: None,
body: Box::new(SetExpr::Table(Box::new(Table {
- table_name: Some("old_table".to_string()),
+ table_name: Some(Ident::new("old_table")),
schema_name: None,
}))),
order_by: None,
@@ -4874,8 +4874,8 @@ fn parse_create_table_as_table() {
let expected_query2 = Box::new(Query {
with: None,
body: Box::new(SetExpr::Table(Box::new(Table {
- table_name: Some("old_table".to_string()),
- schema_name: Some("schema_name".to_string()),
+ table_name: Some(Ident::new("old_table")),
+ schema_name: Some(Ident::new("schema_name")),
}))),
order_by: None,
limit_clause: None,
@@ -20080,3 +20080,44 @@ fn parse_unary_minus_never_renders_line_comment() {
all_dialects().verified_stmt("SELECT -1");
all_dialects().verified_stmt("SELECT -x");
}
+
+#[test]
+fn parse_table_preserves_quotes_and_trailing_tokens() {
+ let dialects = TestedDialects::new(vec![
+ Box::new(AnsiDialect {}),
+ Box::new(GenericDialect {}),
+ Box::new(PostgreSqlDialect {}),
+ Box::new(DuckDbDialect {}),
+ Box::new(SnowflakeDialect {}),
+ ]);
+ dialects.verified_stmt(r#"CREATE TABLE new_table AS TABLE "old_table""#);
+ dialects.verified_stmt(r#"CREATE TABLE new_table AS TABLE "schema_name"."old_table""#);
+ dialects.verified_stmt("CREATE TABLE new_table AS TABLE old_table ORDER BY x");
+ dialects.verified_stmt("CREATE TABLE new_table AS TABLE old_table LIMIT 10");
+ dialects.verified_stmt("SELECT * FROM (TABLE old_table ORDER BY x)");
+
+ let backtick_dialects = TestedDialects::new(vec![
+ Box::new(AnsiDialect {}),
+ Box::new(GenericDialect {}),
+ Box::new(MySqlDialect {}),
+ ]);
+ backtick_dialects.verified_stmt("CREATE TABLE new_table AS TABLE `old_table`");
+ backtick_dialects.verified_stmt("CREATE TABLE new_table AS TABLE `%mpty`");
+ backtick_dialects.verified_stmt("INSERT INTO t TABLE `%mpty`");
+
+ let err = dialects
+ .parse_sql_statements("CREATE TABLE new_table AS TABLE %mpty")
+ .unwrap_err();
+ assert_eq!(
+ ParserError::ParserError("Expected: identifier, found: %".to_string()),
+ err
+ );
+
+ let err = backtick_dialects
+ .parse_sql_statements("CREATE TABLE new_table AS TABLE `x` ORE")
+ .unwrap_err();
+ assert_eq!(
+ ParserError::ParserError("Expected: end of statement, found: ORE".to_string()),
+ err
+ );
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org