Disable supports_left_associative_joins_without_parens for MySQL and Redshift#2357
Disable supports_left_associative_joins_without_parens for MySQL and Redshift#2357revitalkr wants to merge 3 commits into
supports_left_associative_joins_without_parens for MySQL and Redshift#2357Conversation
…h INNER JOIN in Snowflake dialect produces non-equivalent query
| ); | ||
| } | ||
|
|
||
| #[test] |
There was a problem hiding this comment.
does this test fail without the changes in this PR? if not it looks like we can skip it entirely, it looks similar to https://github.com/SatoriCyber/datafusion-sqlparser-rs/blob/00e1d917d439ff40e0c6a10829c491b0735b8818/tests/sqlparser_common.rs#L17445-L17465
There was a problem hiding this comment.
yes, it fails without this PR.
These are different cases which behave differently. Natural join behaves different than the other joins because it can't have a condition after it.
| fn non_left_associative_dialects() -> TestedDialects { | ||
| all_dialects_where(|d| !d.supports_left_associative_joins_without_parens()) | ||
| } |
There was a problem hiding this comment.
can we inline this into the function that uses it?
supports_left_associative_joins_without_parens for MySQL and Redshift
…ntly applied to Snowflake) to MySQL and Redshift.
00e1d91 to
d60c9a3
Compare
|
Rebased this PR on top of #2355 since it depends on those changes. |
| comment: Option<String>, | ||
| }, | ||
| /// ```sql | ||
| /// CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY | VOLATILE } ] FILE FORMAT [ IF NOT EXISTS ] <name> |
There was a problem hiding this comment.
the diff seems to contain unrelated (unintentional ?) changes
…ntly applied to Snowflake) to MySQL and Redshift.
Summary
This PR extends the existing
supports_left_associative_joins_without_parens = falsebehavior (currently applied to Snowflake) to MySQL and Redshift.Problem
The following query is currently accepted only for Snowflake and rejected for other dialects:
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;
However, this query executes successfully in both MySQL and Redshift.
Solution
Set
supports_left_associative_joins_without_parens = falsefor MySQL and Redshift, enabling them to accept the same class of queries already supported for Snowflake.Validation
Attached scripts demonstrate that:
Tests
The existing Snowflake test has been moved to the main test suite and is now applied to all dialects where
supports_left_associative_joins_without_parens = false.scripts
-- =========================================================
-- MySQL validation script
-- 1. Acceptance of deferred ON query
-- 2. Behavior consistent with Snowflake parsing mode
-- =========================================================
-- PART A: REAL QUERY
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS customers;
DROP TABLE IF EXISTS products;
CREATE TABLE orders (
order_id INT
);
CREATE TABLE customers (
customer_id INT,
order_id INT
);
CREATE TABLE products (
product_id INT,
customer_id INT
);
INSERT INTO orders VALUES (1), (2), (3);
INSERT INTO customers VALUES
(10,1),
(20,2),
(30,3);
INSERT INTO products VALUES
(100,10),
(200,20),
(300,30);
-- ORIGINAL
SELECT 'PART_A_ORIGINAL' AS src, 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
ORDER BY p.product_id;
-- CANONICAL (Snowflake-style)
SELECT 'PART_A_CANONICAL' AS src, 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
ORDER BY p.product_id;
-- PART B: WITNESS QUERY
-- Demonstrates observable associativity difference
DROP TABLE IF EXISTS w_orders;
DROP TABLE IF EXISTS w_customers;
DROP TABLE IF EXISTS w_products;
CREATE TABLE w_orders (
order_id INT
);
CREATE TABLE w_customers (
customer_id INT,
order_id INT
);
CREATE TABLE w_products (
product_id INT,
customer_id INT
);
INSERT INTO w_orders VALUES (1), (2);
INSERT INTO w_customers VALUES
(10,1),
(20,2);
INSERT INTO w_products VALUES
(100,10);
-- ORIGINAL
SELECT 'PART_B_ORIGINAL' AS src, o.order_id, c.customer_id, p.product_id
FROM w_orders AS o
LEFT JOIN w_customers AS c
INNER JOIN w_products AS p ON p.customer_id = c.customer_id
ON c.order_id = o.order_id
ORDER BY o.order_id, c.customer_id, p.product_id;
-- CANONICAL
SELECT 'PART_B_CANONICAL' AS src, o.order_id, c.customer_id, p.product_id
FROM w_orders AS o
LEFT JOIN (
w_customers AS c
INNER JOIN w_products AS p ON p.customer_id = c.customer_id
)
ON c.order_id = o.order_id
ORDER BY o.order_id, c.customer_id, p.product_id;
-- ALTERNATIVE (left-deep)
SELECT 'PART_B_LEFT_DEEP' AS src, o.order_id, c.customer_id, p.product_id
FROM (
w_orders AS o
LEFT JOIN w_customers AS c ON c.order_id = o.order_id
)
INNER JOIN w_products AS p ON p.customer_id = c.customer_id
ORDER BY o.order_id, c.customer_id, p.product_id;
-- =========================================================
-- Redshift validation script
-- 1. Acceptance of deferred ON query
-- 2. Behavior consistent with Snowflake parsing mode
-- =========================================================
-- PART A: REAL QUERY
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS customers;
DROP TABLE IF EXISTS products;
CREATE TEMP TABLE orders (
order_id INT
);
CREATE TEMP TABLE customers (
customer_id INT,
order_id INT
);
CREATE TEMP TABLE products (
product_id INT,
customer_id INT
);
INSERT INTO orders VALUES (1), (2), (3);
INSERT INTO customers VALUES
(10,1),
(20,2),
(30,3);
INSERT INTO products VALUES
(100,10),
(200,20),
(300,30);
-- ORIGINAL
SELECT 'PART_A_ORIGINAL' AS src, 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
ORDER BY p.product_id;
-- CANONICAL (Snowflake-style)
SELECT 'PART_A_CANONICAL' AS src, 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
ORDER BY p.product_id;
-- PART B: WITNESS QUERY
DROP TABLE IF EXISTS w_orders;
DROP TABLE IF EXISTS w_customers;
DROP TABLE IF EXISTS w_products;
CREATE TEMP TABLE w_orders (
order_id INT
);
CREATE TEMP TABLE w_customers (
customer_id INT,
order_id INT
);
CREATE TEMP TABLE w_products (
product_id INT,
customer_id INT
);
INSERT INTO w_orders VALUES (1), (2);
INSERT INTO w_customers VALUES
(10,1),
(20,2);
INSERT INTO w_products VALUES
(100,10);
-- ORIGINAL
SELECT 'PART_B_ORIGINAL' AS src, o.order_id, c.customer_id, p.product_id
FROM w_orders AS o
LEFT JOIN w_customers AS c
INNER JOIN w_products AS p ON p.customer_id = c.customer_id
ON c.order_id = o.order_id
ORDER BY o.order_id, c.customer_id, p.product_id;
-- CANONICAL
SELECT 'PART_B_CANONICAL' AS src, o.order_id, c.customer_id, p.product_id
FROM w_orders AS o
LEFT JOIN (
w_customers AS c
INNER JOIN w_products AS p ON p.customer_id = c.customer_id
)
ON c.order_id = o.order_id
ORDER BY o.order_id, c.customer_id, p.product_id;
-- ALTERNATIVE (left-deep)
SELECT 'PART_B_LEFT_DEEP' AS src, o.order_id, c.customer_id, p.product_id
FROM (
w_orders AS o
LEFT JOIN w_customers AS c ON c.order_id = o.order_id
)
INNER JOIN w_products AS p ON p.customer_id = c.customer_id
ORDER BY o.order_id, c.customer_id, p.product_id;
``