diff --git a/src/dialect/mysql.rs b/src/dialect/mysql.rs index da92e1411..f73219e8b 100644 --- a/src/dialect/mysql.rs +++ b/src/dialect/mysql.rs @@ -221,6 +221,10 @@ impl Dialect for MySqlDialect { fn supports_group_by_with_modifier(&self) -> bool { true } + + fn supports_left_associative_joins_without_parens(&self) -> bool { + false + } } /// `LOCK TABLES` diff --git a/src/dialect/redshift.rs b/src/dialect/redshift.rs index db5bc53a0..25c2e9235 100644 --- a/src/dialect/redshift.rs +++ b/src/dialect/redshift.rs @@ -147,6 +147,10 @@ impl Dialect for RedshiftSqlDialect { true } + fn supports_left_associative_joins_without_parens(&self) -> bool { + false + } + fn supports_select_exclude(&self) -> bool { true } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index cbd315e92..54b25abfc 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -15994,6 +15994,7 @@ impl<'a> Parser<'a> { if !self .dialect .supports_left_associative_joins_without_parens() + && !natural && self.peek_parens_less_nested_join() { let joins = self.parse_joins()?; diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index f470b93ca..e6586fc9d 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -10672,6 +10672,10 @@ fn one_statement_parses_to(sql: &str, canonical: &str) -> Statement { all_dialects().one_statement_parses_to(sql, canonical) } +fn non_left_associative_dialects() -> TestedDialects { + all_dialects_where(|d| !d.supports_left_associative_joins_without_parens()) +} + fn verified_stmt(query: &str) -> Statement { all_dialects().verified_stmt(query) } @@ -17439,8 +17443,7 @@ fn column_check_enforced() { #[test] fn join_precedence() { - all_dialects_except(|d| !d.supports_left_associative_joins_without_parens()) - .verified_query_with_canonical( + all_dialects().verified_query_with_canonical( "SELECT * FROM t1 NATURAL JOIN t5 @@ -17449,14 +17452,345 @@ fn join_precedence() { // canonical string without parentheses "SELECT * FROM t1 NATURAL JOIN t5 INNER JOIN t0 ON (t0.v1 + t5.v0) > 0 WHERE t0.v1 = t1.v0", ); - all_dialects_except(|d| d.supports_left_associative_joins_without_parens()).verified_query_with_canonical( - "SELECT * - FROM t1 - NATURAL JOIN t5 - INNER JOIN t0 ON (t0.v1 + t5.v0) > 0 - WHERE t0.v1 = t1.v0", - // canonical string with parentheses - "SELECT * FROM t1 NATURAL JOIN (t5 INNER JOIN t0 ON (t0.v1 + t5.v0) > 0) WHERE t0.v1 = t1.v0", +} + +#[test] +fn test_nested_join_without_parentheses() { + let query = "SELECT DISTINCT p.product_id FROM orders AS o INNER JOIN customers AS c INNER JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; + assert_eq!( + only( + non_left_associative_dialects() + .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o INNER JOIN (customers AS c INNER JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") + .from + ) + .joins, + vec![Join { + relation: TableFactor::NestedJoin { + table_with_joins: Box::new(TableWithJoins { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("customers".to_string())]), + alias: table_alias(true, "c"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + joins: vec![Join { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("products".to_string())]), + alias: table_alias(true, "p"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + global: false, + join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("p".to_string()), + Ident::new("customer_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("customer_id".to_string()) + ])), + })), + }] + }), + alias: None + }, + global: false, + join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("order_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("o".to_string()), + Ident::new("order_id".to_string()) + ])), + })) + }], + ); + + let query = "SELECT DISTINCT p.product_id FROM orders AS o JOIN customers AS c JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; + assert_eq!( + only( + non_left_associative_dialects() + .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o JOIN (customers AS c JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") + .from + ) + .joins, + vec![Join { + relation: TableFactor::NestedJoin { + table_with_joins: Box::new(TableWithJoins { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("customers".to_string())]), + alias: table_alias(true, "c"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + joins: vec![Join { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("products".to_string())]), + alias: table_alias(true, "p"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + global: false, + join_operator: JoinOperator::Join(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("p".to_string()), + Ident::new("customer_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("customer_id".to_string()) + ])), + })), + }] + }), + alias: None + }, + global: false, + join_operator: JoinOperator::Join(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("order_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("o".to_string()), + Ident::new("order_id".to_string()) + ])), + })) + }], + ); + + let query = "SELECT DISTINCT p.product_id FROM orders AS o LEFT JOIN customers AS c LEFT JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; + assert_eq!( + only( + non_left_associative_dialects() + .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o LEFT JOIN (customers AS c LEFT JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") + .from + ) + .joins, + vec![Join { + relation: TableFactor::NestedJoin { + table_with_joins: Box::new(TableWithJoins { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("customers".to_string())]), + alias: table_alias(true, "c"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + joins: vec![Join { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("products".to_string())]), + alias: table_alias(true, "p"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + global: false, + join_operator: JoinOperator::Left(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("p".to_string()), + Ident::new("customer_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("customer_id".to_string()) + ])), + })), + }] + }), + alias: None + }, + global: false, + join_operator: JoinOperator::Left(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("order_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("o".to_string()), + Ident::new("order_id".to_string()) + ])), + })) + }], + ); + + let query = "SELECT DISTINCT p.product_id FROM orders AS o RIGHT JOIN customers AS c RIGHT JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; + assert_eq!( + only( + non_left_associative_dialects() + .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o RIGHT JOIN (customers AS c RIGHT JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") + .from + ) + .joins, + vec![Join { + relation: TableFactor::NestedJoin { + table_with_joins: Box::new(TableWithJoins { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("customers".to_string())]), + alias: table_alias(true, "c"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + joins: vec![Join { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("products".to_string())]), + alias: table_alias(true, "p"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + global: false, + join_operator: JoinOperator::Right(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("p".to_string()), + Ident::new("customer_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("customer_id".to_string()) + ])), + })), + }] + }), + alias: None + }, + global: false, + join_operator: JoinOperator::Right(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("order_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("o".to_string()), + Ident::new("order_id".to_string()) + ])), + })) + }], + ); + + let query = "SELECT DISTINCT p.product_id FROM orders AS o FULL JOIN customers AS c FULL JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; + assert_eq!( + only( + non_left_associative_dialects() + .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o FULL JOIN (customers AS c FULL JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") + .from + ) + .joins, + vec![Join { + relation: TableFactor::NestedJoin { + table_with_joins: Box::new(TableWithJoins { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("customers".to_string())]), + alias: table_alias(true, "c"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + joins: vec![Join { + relation: TableFactor::Table { + name: ObjectName::from(vec![Ident::new("products".to_string())]), + alias: table_alias(true, "p"), + args: None, + with_hints: vec![], + version: None, + partitions: vec![], + with_ordinality: false, + json_path: None, + sample: None, + index_hints: vec![], + }, + global: false, + join_operator: JoinOperator::FullOuter(JoinConstraint::On( + Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("p".to_string()), + Ident::new("customer_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("customer_id".to_string()) + ])), + } + )), + }] + }), + alias: None + }, + global: false, + join_operator: JoinOperator::FullOuter(JoinConstraint::On(Expr::BinaryOp { + left: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("c".to_string()), + Ident::new("order_id".to_string()) + ])), + op: BinaryOperator::Eq, + right: Box::new(Expr::CompoundIdentifier(vec![ + Ident::new("o".to_string()), + Ident::new("order_id".to_string()) + ])), + })) + }], ); } diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 14eb5d9f1..9cf6e49e1 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -4333,346 +4333,6 @@ fn test_alter_session_followed_by_statement() { } } -#[test] -fn test_nested_join_without_parentheses() { - let query = "SELECT DISTINCT p.product_id FROM orders AS o INNER JOIN customers AS c INNER JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; - assert_eq!( - only( - snowflake() - .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o INNER JOIN (customers AS c INNER JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") - .from - ) - .joins, - vec![Join { - relation: TableFactor::NestedJoin { - table_with_joins: Box::new(TableWithJoins { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("customers".to_string())]), - alias: table_alias(true, "c"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - joins: vec![Join { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("products".to_string())]), - alias: table_alias(true, "p"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - global: false, - join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("p".to_string()), - Ident::new("customer_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("customer_id".to_string()) - ])), - })), - }] - }), - alias: None - }, - global: false, - join_operator: JoinOperator::Inner(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("order_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("o".to_string()), - Ident::new("order_id".to_string()) - ])), - })) - }], - ); - - let query = "SELECT DISTINCT p.product_id FROM orders AS o JOIN customers AS c JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; - assert_eq!( - only( - snowflake() - .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o JOIN (customers AS c JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") - .from - ) - .joins, - vec![Join { - relation: TableFactor::NestedJoin { - table_with_joins: Box::new(TableWithJoins { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("customers".to_string())]), - alias: table_alias(true, "c"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - joins: vec![Join { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("products".to_string())]), - alias: table_alias(true, "p"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - global: false, - join_operator: JoinOperator::Join(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("p".to_string()), - Ident::new("customer_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("customer_id".to_string()) - ])), - })), - }] - }), - alias: None - }, - global: false, - join_operator: JoinOperator::Join(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("order_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("o".to_string()), - Ident::new("order_id".to_string()) - ])), - })) - }], - ); - - let query = "SELECT DISTINCT p.product_id FROM orders AS o LEFT JOIN customers AS c LEFT JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; - assert_eq!( - only( - snowflake() - .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o LEFT JOIN (customers AS c LEFT JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") - .from - ) - .joins, - vec![Join { - relation: TableFactor::NestedJoin { - table_with_joins: Box::new(TableWithJoins { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("customers".to_string())]), - alias: table_alias(true, "c"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - joins: vec![Join { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("products".to_string())]), - alias: table_alias(true, "p"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - global: false, - join_operator: JoinOperator::Left(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("p".to_string()), - Ident::new("customer_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("customer_id".to_string()) - ])), - })), - }] - }), - alias: None - }, - global: false, - join_operator: JoinOperator::Left(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("order_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("o".to_string()), - Ident::new("order_id".to_string()) - ])), - })) - }], - ); - - let query = "SELECT DISTINCT p.product_id FROM orders AS o RIGHT JOIN customers AS c RIGHT JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; - assert_eq!( - only( - snowflake() - .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o RIGHT JOIN (customers AS c RIGHT JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") - .from - ) - .joins, - vec![Join { - relation: TableFactor::NestedJoin { - table_with_joins: Box::new(TableWithJoins { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("customers".to_string())]), - alias: table_alias(true, "c"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - joins: vec![Join { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("products".to_string())]), - alias: table_alias(true, "p"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - global: false, - join_operator: JoinOperator::Right(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("p".to_string()), - Ident::new("customer_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("customer_id".to_string()) - ])), - })), - }] - }), - alias: None - }, - global: false, - join_operator: JoinOperator::Right(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("order_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("o".to_string()), - Ident::new("order_id".to_string()) - ])), - })) - }], - ); - - let query = "SELECT DISTINCT p.product_id FROM orders AS o FULL JOIN customers AS c FULL JOIN products AS p ON p.customer_id = c.customer_id ON c.order_id = o.order_id"; - assert_eq!( - only( - snowflake() - .verified_only_select_with_canonical(query, "SELECT DISTINCT p.product_id FROM orders AS o FULL JOIN (customers AS c FULL JOIN products AS p ON p.customer_id = c.customer_id) ON c.order_id = o.order_id") - .from - ) - .joins, - vec![Join { - relation: TableFactor::NestedJoin { - table_with_joins: Box::new(TableWithJoins { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("customers".to_string())]), - alias: table_alias(true, "c"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - joins: vec![Join { - relation: TableFactor::Table { - name: ObjectName::from(vec![Ident::new("products".to_string())]), - alias: table_alias(true, "p"), - args: None, - with_hints: vec![], - version: None, - partitions: vec![], - with_ordinality: false, - json_path: None, - sample: None, - index_hints: vec![], - }, - global: false, - join_operator: JoinOperator::FullOuter(JoinConstraint::On( - Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("p".to_string()), - Ident::new("customer_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("customer_id".to_string()) - ])), - } - )), - }] - }), - alias: None - }, - global: false, - join_operator: JoinOperator::FullOuter(JoinConstraint::On(Expr::BinaryOp { - left: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("c".to_string()), - Ident::new("order_id".to_string()) - ])), - op: BinaryOperator::Eq, - right: Box::new(Expr::CompoundIdentifier(vec![ - Ident::new("o".to_string()), - Ident::new("order_id".to_string()) - ])), - })) - }], - ); -} - #[test] fn parse_connect_by_root_operator() { let sql = "SELECT CONNECT_BY_ROOT name AS root_name FROM Tbl1";