Skip to content

Commit

Permalink
Fix!(optimizer): preserve predecence when merging derived tables (#1857)
Browse files Browse the repository at this point in the history
* Fix!(optimizer): preserve predecence when merging derived tables

* Rephrase comment

* Add another test in simplify

* Formatting

* Fix typo

* Add another test
  • Loading branch information
georgesittas authored Jun 29, 2023
1 parent 146dc34 commit 72aa018
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 1 deletion.
22 changes: 21 additions & 1 deletion sqlglot/optimizer/merge_subqueries.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ def merge_subqueries(expression, leave_tables_isolated=False):
}


# Projections in the outer query that are instances of these types can be replaced
# without getting wrapped in parentheses, because the precedence won't be altered.
SAFE_TO_REPLACE_UNWRAPPED = (
exp.Column,
exp.EQ,
exp.Func,
exp.NEQ,
exp.Paren,
)


def merge_ctes(expression, leave_tables_isolated=False):
scopes = traverse_scope(expression)

Expand Down Expand Up @@ -293,8 +304,17 @@ def _merge_expressions(outer_scope, inner_scope, alias):
if not projection_name:
continue
columns_to_replace = outer_columns.get(projection_name, [])

expression = expression.unalias()
must_wrap_expression = not isinstance(expression, SAFE_TO_REPLACE_UNWRAPPED)

for column in columns_to_replace:
column.replace(expression.unalias().copy())
# Ensures we don't alter the intended operator precedence if there's additional
# context surrounding the outer expression (i.e. it's not a simple projection).
if isinstance(column.parent, (exp.Unary, exp.Binary)) and must_wrap_expression:
expression = exp.paren(expression, copy=False)

column.replace(expression.copy())


def _merge_where(outer_scope, inner_scope, from_or_join):
Expand Down
1 change: 1 addition & 0 deletions sqlglot/optimizer/simplify.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ def simplify_parens(expression):
or not isinstance(this, exp.Binary)
or (isinstance(this, exp.Add) and isinstance(parent, exp.Add))
or (isinstance(this, exp.Mul) and isinstance(parent, exp.Mul))
or (isinstance(this, exp.Mul) and isinstance(parent, (exp.Add, exp.Sub)))
):
return expression.this
return expression
Expand Down
22 changes: 22 additions & 0 deletions tests/fixtures/optimizer/merge_subqueries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@
SELECT a, b FROM (SELECT a, b FROM x);
SELECT x.a AS a, x.b AS b FROM x AS x;

# title: Wrap addition in a multiplication
SELECT c * 2 AS d FROM (SELECT a + b AS c FROM x);
SELECT (x.a + x.b) * 2 AS d FROM x AS x;

# title: Wrap addition in an addition
# note: The "simplify" rule will unwrap this
SELECT c + d AS e FROM (SELECT a + b AS c, a AS d FROM x);
SELECT (x.a + x.b) + x.a AS e FROM x AS x;

# title: Wrap multiplication in an addition
# note: The "simplify" rule will unwrap this
WITH cte AS (SELECT a * b AS c, a AS d FROM x) SELECT c + d AS e FROM cte;
SELECT (x.a * x.b) + x.a AS e FROM x AS x;

# title: Don't wrap function
SELECT 2 * foo AS bar FROM (SELECT CAST(b AS DOUBLE) AS foo FROM x);
SELECT 2 * CAST(x.b AS DOUBLE) AS bar FROM x AS x;

# title: Don't wrap a wrapped expression
SELECT foo * 2 AS bar FROM (SELECT (1 + 2 + 3) AS foo FROM x);
SELECT (1 + 2 + 3) * 2 AS bar FROM x AS x;

# title: Inner table alias is merged
SELECT a, b FROM (SELECT a, b FROM x AS q) AS r;
SELECT q.a AS a, q.b AS b FROM x AS q;
Expand Down
8 changes: 8 additions & 0 deletions tests/fixtures/optimizer/optimizer.sql
Original file line number Diff line number Diff line change
Expand Up @@ -693,3 +693,11 @@ GROUP BY
"x"."a" + 1 + 1
HAVING
"x"."a" + 1 + 1 + 1 + 1 > 1;

# title: replace alias with mult expression without wrapping it
WITH cte AS (SELECT a * b AS c, a AS d, b as e FROM x) SELECT c + d - (c - e) AS f FROM cte;
SELECT
"x"."a" * "x"."b" + "x"."a" - (
"x"."a" * "x"."b" - "x"."b"
) AS "f"
FROM "x" AS "x";
6 changes: 6 additions & 0 deletions tests/fixtures/optimizer/simplify.sql
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,12 @@ a + 4;
a + (1 + 1) + (10);
a + 12;

a + (1 * 1) + (1 - (1 * 1));
a + 1;

a + (b * c) + (d - (e * f));
a + b * c + (d - e * f);

5 + 4 * 3;
17;

Expand Down

0 comments on commit 72aa018

Please sign in to comment.