From 64d3bd5e36094dca440fd9e14f9e9c06b3b6af4e Mon Sep 17 00:00:00 2001 From: Chris Ginter Date: Mon, 24 Oct 2022 14:20:13 -0700 Subject: [PATCH 1/2] only qualify non-alias column references in the having clause --- sqlglot/optimizer/qualify_columns.py | 21 ++++++++++++-------- sqlglot/optimizer/scope.py | 2 +- tests/fixtures/optimizer/qualify_columns.sql | 17 ++++++++++++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/sqlglot/optimizer/qualify_columns.py b/sqlglot/optimizer/qualify_columns.py index 36ba02869f..064ca2f355 100644 --- a/sqlglot/optimizer/qualify_columns.py +++ b/sqlglot/optimizer/qualify_columns.py @@ -211,21 +211,26 @@ def _qualify_columns(scope, resolver): if column_table: column.set("table", exp.to_identifier(column_table)) + other_columns = [] # Determine whether each reference in the order by clause is to a column or an alias. for ordered in scope.find_all(exp.Ordered): for column in ordered.find_all(exp.Column): - column_table = column.table - column_name = column.name + if not column.table and column.parent is not ordered and column.name in resolver.all_columns: + other_columns.append(column) - if column_table or column.parent is ordered or column_name not in resolver.all_columns: - continue + # Determine whether each reference in the having clause is to a column or an alias. + for having in scope.find_all(exp.Having): + for column in having.find_all(exp.Column): + if not column.table and column.find_ancestor(exp.AggFunc) and column.name in resolver.all_columns: + other_columns.append(column) - column_table = resolver.get_table(column_name) + for column in other_columns: + column_table = resolver.get_table(column.name) - if column_table is None: - raise OptimizeError(f"Ambiguous column: {column_name}") + if column_table is None: + raise OptimizeError(f"Ambiguous column: {column.name}") - column.set("table", exp.to_identifier(column_table)) + column.set("table", exp.to_identifier(column_table)) def _expand_stars(scope, resolver): diff --git a/sqlglot/optimizer/scope.py b/sqlglot/optimizer/scope.py index b7eb6c2fb7..5a75ee29a7 100644 --- a/sqlglot/optimizer/scope.py +++ b/sqlglot/optimizer/scope.py @@ -232,7 +232,7 @@ def columns(self): self._columns = [] for column in columns + external_columns: - ancestor = column.find_ancestor(exp.Qualify, exp.Order, exp.Hint) + ancestor = column.find_ancestor(exp.Qualify, exp.Order, exp.Having, exp.Hint) if ( not ancestor or column.table diff --git a/tests/fixtures/optimizer/qualify_columns.sql b/tests/fixtures/optimizer/qualify_columns.sql index 858f23248f..a958c08899 100644 --- a/tests/fixtures/optimizer/qualify_columns.sql +++ b/tests/fixtures/optimizer/qualify_columns.sql @@ -31,6 +31,23 @@ SELECT x.a + x.b AS "_col_0" FROM x AS x; SELECT a, SUM(b) FROM x WHERE a > 1 AND b > 1 GROUP BY a; SELECT x.a AS a, SUM(x.b) AS "_col_1" FROM x AS x WHERE x.a > 1 AND x.b > 1 GROUP BY x.a; +SELECT SUM(a) AS c FROM x HAVING SUM(a) > 3; +SELECT SUM(x.a) AS c FROM x AS x HAVING SUM(x.a) > 3; + +SELECT SUM(a) AS a FROM x HAVING SUM(a) > 3; +SELECT SUM(x.a) AS a FROM x AS x HAVING SUM(x.a) > 3; + +SELECT SUM(a) AS c FROM x HAVING c > 3; +SELECT SUM(x.a) AS c FROM x AS x HAVING c > 3; + +# execute: false +SELECT SUM(a) AS a FROM x HAVING a > 3; +SELECT SUM(x.a) AS a FROM x AS x HAVING a > 3; + +# execute: false +SELECT SUM(a) AS c FROM x HAVING SUM(c) > 3; +SELECT SUM(x.a) AS c FROM x AS x HAVING SUM(c) > 3; + SELECT a AS j, b FROM x ORDER BY j; SELECT x.a AS j, x.b AS b FROM x AS x ORDER BY j; From b229cea4f33a3a41ecb183408a5c6bc8bb15758c Mon Sep 17 00:00:00 2001 From: Chris Ginter Date: Mon, 24 Oct 2022 14:42:54 -0700 Subject: [PATCH 2/2] rename other_columns --- sqlglot/optimizer/qualify_columns.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sqlglot/optimizer/qualify_columns.py b/sqlglot/optimizer/qualify_columns.py index 064ca2f355..ebee92a8a1 100644 --- a/sqlglot/optimizer/qualify_columns.py +++ b/sqlglot/optimizer/qualify_columns.py @@ -211,20 +211,20 @@ def _qualify_columns(scope, resolver): if column_table: column.set("table", exp.to_identifier(column_table)) - other_columns = [] + columns_missing_from_scope = [] # Determine whether each reference in the order by clause is to a column or an alias. for ordered in scope.find_all(exp.Ordered): for column in ordered.find_all(exp.Column): if not column.table and column.parent is not ordered and column.name in resolver.all_columns: - other_columns.append(column) + columns_missing_from_scope.append(column) # Determine whether each reference in the having clause is to a column or an alias. for having in scope.find_all(exp.Having): for column in having.find_all(exp.Column): if not column.table and column.find_ancestor(exp.AggFunc) and column.name in resolver.all_columns: - other_columns.append(column) + columns_missing_from_scope.append(column) - for column in other_columns: + for column in columns_missing_from_scope: column_table = resolver.get_table(column.name) if column_table is None: