Snowflake: support nested join without parentheses (#1799)

This commit is contained in:
bar sela 2025-04-15 08:57:26 +03:00 committed by GitHub
parent 6566c47593
commit 514d2ecdaf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 440 additions and 2 deletions

View file

@ -3573,3 +3573,413 @@ fn test_alter_session_followed_by_statement() {
_ => panic!("Unexpected statements: {:?}", stmts),
}
}
#[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: Some(TableAlias {
name: Ident {
value: "c".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "p".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "c".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "p".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "c".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "p".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "c".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "p".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "c".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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: Some(TableAlias {
name: Ident {
value: "p".to_string(),
quote_style: None,
span: Span::empty(),
},
columns: vec![],
}),
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())
])),
}))
}],
);
}