From 5d93d379ff6a7257770969c9a797024f7c47096d Mon Sep 17 00:00:00 2001 From: Xiangjin Date: Mon, 21 Oct 2024 11:52:40 +0800 Subject: [PATCH 1/2] reproduce with sqlparser test --- src/sqlparser/tests/sqlparser_common.rs | 64 ------------------------ src/sqlparser/tests/testdata/select.yaml | 6 +++ 2 files changed, 6 insertions(+), 64 deletions(-) diff --git a/src/sqlparser/tests/sqlparser_common.rs b/src/sqlparser/tests/sqlparser_common.rs index 6fb7bbe5f6f5..e6b29d632fe2 100644 --- a/src/sqlparser/tests/sqlparser_common.rs +++ b/src/sqlparser/tests/sqlparser_common.rs @@ -2836,70 +2836,6 @@ fn parse_ctes() { } } -#[test] -fn parse_changelog_ctes() { - let cte_sqls = vec!["foo", "bar"]; - let with = &format!( - "WITH a AS changelog from {}, b AS changelog from {} SELECT foo + bar FROM a, b", - cte_sqls[0], cte_sqls[1] - ); - - fn assert_changelog_ctes(expected: &[&str], sel: &Query) { - for (i, exp) in expected.iter().enumerate() { - let Cte { alias, cte_inner } = &sel.with.as_ref().unwrap().cte_tables[i]; - if let CteInner::ChangeLog(from) = cte_inner { - assert_eq!(*exp, from.to_string()); - assert_eq!( - if i == 0 { - Ident::new_unchecked("a") - } else { - Ident::new_unchecked("b") - }, - alias.name - ); - assert!(alias.columns.is_empty()); - } else { - panic!("expected CteInner::ChangeLog") - } - } - } - - // Top-level CTE - assert_changelog_ctes(&cte_sqls, &verified_query(with)); - // CTE in a subquery - let sql = &format!("SELECT ({})", with); - let select = verified_only_select(sql); - match expr_from_projection(only(&select.projection)) { - Expr::Subquery(ref subquery) => { - assert_changelog_ctes(&cte_sqls, subquery.as_ref()); - } - _ => panic!("expected subquery"), - } - // CTE in a derived table - let sql = &format!("SELECT * FROM ({})", with); - let select = verified_only_select(sql); - match only(select.from).relation { - TableFactor::Derived { subquery, .. } => { - assert_changelog_ctes(&cte_sqls, subquery.as_ref()) - } - _ => panic!("expected derived table"), - } - // CTE in a view - let sql = &format!("CREATE VIEW v AS {}", with); - match verified_stmt(sql) { - Statement::CreateView { query, .. } => assert_changelog_ctes(&cte_sqls, &query), - _ => panic!("expected CREATE VIEW"), - } - // CTE in a CTE... - let sql = &format!("WITH outer_cte AS ({}) SELECT * FROM outer_cte", with); - let select = verified_query(sql); - if let CteInner::Query(query) = &only(&select.with.unwrap().cte_tables).cte_inner { - assert_changelog_ctes(&cte_sqls, query); - } else { - panic!("expected CteInner::Query") - } -} - #[test] fn parse_cte_renamed_columns() { let sql = "WITH cte (col1, col2) AS (SELECT foo, bar FROM baz) SELECT * FROM cte"; diff --git a/src/sqlparser/tests/testdata/select.yaml b/src/sqlparser/tests/testdata/select.yaml index 606b3d7a0c13..7d5c641e320e 100644 --- a/src/sqlparser/tests/testdata/select.yaml +++ b/src/sqlparser/tests/testdata/select.yaml @@ -231,3 +231,9 @@ - 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 })' +- input: |- + WITH a_log AS changelog from a, + "B_log" AS changelog from public."B" + SELECT a0 + b0 FROM a_log, "B_log" + formatted_sql: WITH a_log AS changelog from a, "B_log" AS changelog from public.B SELECT a0 + b0 FROM a_log, "B_log" + formatted_ast: 'Query(Query { with: Some(With { recursive: false, cte_tables: [Cte { alias: TableAlias { name: Ident { value: "a_log", quote_style: None }, columns: [] }, cte_inner: ChangeLog(ObjectName([Ident { value: "a", quote_style: None }])) }, Cte { alias: TableAlias { name: Ident { value: "B_log", quote_style: Some(''"'') }, columns: [] }, cte_inner: ChangeLog(ObjectName([Ident { value: "public", quote_style: None }, Ident { value: "B", quote_style: Some(''"'') }])) }] }), body: Select(Select { distinct: All, projection: [UnnamedExpr(BinaryOp { left: Identifier(Ident { value: "a0", quote_style: None }), op: Plus, right: Identifier(Ident { value: "b0", quote_style: None }) })], from: [TableWithJoins { relation: Table { name: ObjectName([Ident { value: "a_log", quote_style: None }]), alias: None, as_of: None }, joins: [] }, TableWithJoins { relation: Table { name: ObjectName([Ident { value: "B_log", quote_style: Some(''"'') }]), alias: None, as_of: None }, joins: [] }], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })' From 35b5bdaecf9fd2fe175222e5509784467db66a64 Mon Sep 17 00:00:00 2001 From: Xiangjin Date: Mon, 21 Oct 2024 12:00:17 +0800 Subject: [PATCH 2/2] fix(sqlparser): `Display` changelog with quoted identifiers --- src/sqlparser/src/ast/query.rs | 9 +++------ src/sqlparser/tests/testdata/select.yaml | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/sqlparser/src/ast/query.rs b/src/sqlparser/src/ast/query.rs index 5b6bd469b572..0dd7ab2f626f 100644 --- a/src/sqlparser/src/ast/query.rs +++ b/src/sqlparser/src/ast/query.rs @@ -335,12 +335,9 @@ impl fmt::Display for Cte { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.cte_inner { CteInner::Query(query) => write!(f, "{} AS ({})", self.alias, query)?, - CteInner::ChangeLog(obj_name) => write!( - f, - "{} AS changelog from {}", - self.alias, - obj_name.real_value() - )?, + CteInner::ChangeLog(obj_name) => { + write!(f, "{} AS changelog from {}", self.alias, obj_name)? + } } Ok(()) } diff --git a/src/sqlparser/tests/testdata/select.yaml b/src/sqlparser/tests/testdata/select.yaml index 7d5c641e320e..72de88bd1dfb 100644 --- a/src/sqlparser/tests/testdata/select.yaml +++ b/src/sqlparser/tests/testdata/select.yaml @@ -235,5 +235,5 @@ WITH a_log AS changelog from a, "B_log" AS changelog from public."B" SELECT a0 + b0 FROM a_log, "B_log" - formatted_sql: WITH a_log AS changelog from a, "B_log" AS changelog from public.B SELECT a0 + b0 FROM a_log, "B_log" + formatted_sql: WITH a_log AS changelog from a, "B_log" AS changelog from public."B" SELECT a0 + b0 FROM a_log, "B_log" formatted_ast: 'Query(Query { with: Some(With { recursive: false, cte_tables: [Cte { alias: TableAlias { name: Ident { value: "a_log", quote_style: None }, columns: [] }, cte_inner: ChangeLog(ObjectName([Ident { value: "a", quote_style: None }])) }, Cte { alias: TableAlias { name: Ident { value: "B_log", quote_style: Some(''"'') }, columns: [] }, cte_inner: ChangeLog(ObjectName([Ident { value: "public", quote_style: None }, Ident { value: "B", quote_style: Some(''"'') }])) }] }), body: Select(Select { distinct: All, projection: [UnnamedExpr(BinaryOp { left: Identifier(Ident { value: "a0", quote_style: None }), op: Plus, right: Identifier(Ident { value: "b0", quote_style: None }) })], from: [TableWithJoins { relation: Table { name: ObjectName([Ident { value: "a_log", quote_style: None }]), alias: None, as_of: None }, joins: [] }, TableWithJoins { relation: Table { name: ObjectName([Ident { value: "B_log", quote_style: Some(''"'') }]), alias: None, as_of: None }, joins: [] }], lateral_views: [], selection: None, group_by: [], having: None }), order_by: [], limit: None, offset: None, fetch: None })'