From 6c22fc952601ca25069ba57572c29a66d744dcb3 Mon Sep 17 00:00:00 2001 From: Nnamdi Nwabuokei Date: Tue, 2 Dec 2025 10:55:57 +0100 Subject: [PATCH 1/4] chore(exasol): qualified select list with "LOCAL" --- sqlglot/dialects/exasol.py | 3 +++ tests/dialects/test_exasol.py | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sqlglot/dialects/exasol.py b/sqlglot/dialects/exasol.py index 7848fa5662..018e5bd0c4 100644 --- a/sqlglot/dialects/exasol.py +++ b/sqlglot/dialects/exasol.py @@ -99,6 +99,9 @@ def prefix_local(node): ) return node + expression.set( + "expressions", [sel.transform(prefix_local) for sel in expression.expressions] + ) for key in ("where", "group", "having"): if arg := expression.args.get(key): expression.set(key, arg.transform(prefix_local)) diff --git a/tests/dialects/test_exasol.py b/tests/dialects/test_exasol.py index 1c7c69e2f3..1af9c676a5 100644 --- a/tests/dialects/test_exasol.py +++ b/tests/dialects/test_exasol.py @@ -660,7 +660,14 @@ def test_local_prefix_for_alias(self): self.validate_identity( 'SELECT YEAR(a_date) AS "a_year" FROM MY_SUMMARY_TABLE GROUP BY LOCAL."a_year"', ) - self.validate_identity('SELECT a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year') + self.validate_identity( + 'SELECT a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year', + 'SELECT LOCAL.a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year', + ) + self.validate_identity( + "SELECT YEAR(current_date) AS current_year, current_year + 1 AS next_year", + "SELECT YEAR(CURRENT_DATE) AS current_year, LOCAL.current_year + 1 AS next_year", + ) test_cases = [ ( From 4953a608b62afe8cdb809ed8b9b876d0ce7713a1 Mon Sep 17 00:00:00 2001 From: Nnamdi Nwabuokei Date: Thu, 4 Dec 2025 23:24:40 +0100 Subject: [PATCH 2/4] chore(exasol): implementing alias referencing using local keyword for select list --- sqlglot/dialects/exasol.py | 26 +++++++++++++++++++------- tests/dialects/test_exasol.py | 7 ++++++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/sqlglot/dialects/exasol.py b/sqlglot/dialects/exasol.py index cd92f15740..4f24a1ba1f 100644 --- a/sqlglot/dialects/exasol.py +++ b/sqlglot/dialects/exasol.py @@ -92,21 +92,33 @@ def _add_local_prefix_for_aliases(expression: exp.Expression) -> exp.Expression: ): table_ident.replace(exp.to_identifier(table_ident.name.upper(), quoted=True)) - def prefix_local(node): + def prefix_local(node, visible_aliases: dict[str, bool]) -> exp.Expression: if isinstance(node, exp.Column) and not node.table: - if node.name in aliases: + if node.name in visible_aliases: return exp.Column( - this=exp.to_identifier(node.name, quoted=aliases[node.name]), + this=exp.to_identifier(node.name, quoted=visible_aliases[node.name]), table=exp.to_identifier("LOCAL", quoted=False), ) return node - expression.set( - "expressions", [sel.transform(prefix_local) for sel in expression.expressions] - ) for key in ("where", "group", "having"): if arg := expression.args.get(key): - expression.set(key, arg.transform(prefix_local)) + expression.set(key, arg.transform(lambda node: prefix_local(node, aliases))) + + seen_aliases: dict[str, bool] = {} + new_selects: list[exp.Expression] = [] + for sel in expression.selects: + if isinstance(sel, exp.Alias): + inner = sel.this.transform(lambda node: prefix_local(node, seen_aliases)) + sel.set("this", inner) + + alias_node = sel.args.get("alias") + if alias_node and alias_node.name: + seen_aliases[alias_node.name] = bool(alias_node.args.get("quoted")) + new_selects.append(sel) + else: + new_selects.append(sel.transform(lambda node: prefix_local(node, seen_aliases))) + expression.set("expressions", new_selects) return expression diff --git a/tests/dialects/test_exasol.py b/tests/dialects/test_exasol.py index 6ceb5ad747..79bdab39d6 100644 --- a/tests/dialects/test_exasol.py +++ b/tests/dialects/test_exasol.py @@ -684,7 +684,7 @@ def test_local_prefix_for_alias(self): ) self.validate_identity( 'SELECT a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year', - 'SELECT LOCAL.a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year', + 'SELECT a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year', ) self.validate_identity( "SELECT YEAR(current_date) AS current_year, current_year + 1 AS next_year", @@ -712,6 +712,11 @@ def test_local_prefix_for_alias(self): "SELECT YEAR(a_date) AS a_year, MONTH(a_date) AS a_month FROM my_table WHERE LOCAL.a_year > 2020 AND LOCAL.a_month < 6", "SELECT YEAR(a_date) AS a_year, MONTH(a_date) AS a_month FROM my_table WHERE a_year > 2020 AND a_month < 6", ), + ( + "Select list aliases", + "SELECT YR AS THE_YEAR, ID AS YR, LOCAL.THE_YEAR + 1 AS NEXT_YEAR FROM my_table", + "SELECT YR AS THE_YEAR, ID AS YR, THE_YEAR + 1 AS NEXT_YEAR FROM my_table", + ), ] for title, exasol_sql, dbx_sql in test_cases: with self.subTest(clause=title): From 6c341ac19ce129e71b02330bf2e262aa3c4bbc38 Mon Sep 17 00:00:00 2001 From: Nnamdi Nwabuokei Date: Fri, 5 Dec 2025 17:02:59 +0100 Subject: [PATCH 3/4] chore(exasol): refactored test and simplifying implementation --- sqlglot/dialects/exasol.py | 3 +-- tests/dialects/test_exasol.py | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sqlglot/dialects/exasol.py b/sqlglot/dialects/exasol.py index 4f24a1ba1f..1a52b4f660 100644 --- a/sqlglot/dialects/exasol.py +++ b/sqlglot/dialects/exasol.py @@ -113,8 +113,7 @@ def prefix_local(node, visible_aliases: dict[str, bool]) -> exp.Expression: sel.set("this", inner) alias_node = sel.args.get("alias") - if alias_node and alias_node.name: - seen_aliases[alias_node.name] = bool(alias_node.args.get("quoted")) + seen_aliases[alias_node.name] = bool(alias_node.args.get("quoted")) new_selects.append(sel) else: new_selects.append(sel.transform(lambda node: prefix_local(node, seen_aliases))) diff --git a/tests/dialects/test_exasol.py b/tests/dialects/test_exasol.py index 79bdab39d6..30bde491c4 100644 --- a/tests/dialects/test_exasol.py +++ b/tests/dialects/test_exasol.py @@ -684,11 +684,6 @@ def test_local_prefix_for_alias(self): ) self.validate_identity( 'SELECT a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year', - 'SELECT a_year AS a_year FROM "LOCAL" GROUP BY "LOCAL".a_year', - ) - self.validate_identity( - "SELECT YEAR(current_date) AS current_year, current_year + 1 AS next_year", - "SELECT YEAR(CURRENT_DATE) AS current_year, LOCAL.current_year + 1 AS next_year", ) test_cases = [ @@ -717,6 +712,11 @@ def test_local_prefix_for_alias(self): "SELECT YR AS THE_YEAR, ID AS YR, LOCAL.THE_YEAR + 1 AS NEXT_YEAR FROM my_table", "SELECT YR AS THE_YEAR, ID AS YR, THE_YEAR + 1 AS NEXT_YEAR FROM my_table", ), + ( + "Select list aliases without Local keyword", + "SELECT YEAR(CURRENT_DATE) AS current_year, LOCAL.current_year + 1 AS next_year", + "SELECT YEAR(CURRENT_DATE) AS current_year, current_year + 1 AS next_year", + ) ] for title, exasol_sql, dbx_sql in test_cases: with self.subTest(clause=title): From 6868e7d927e897892ce3b533efdcfdb792a3b99b Mon Sep 17 00:00:00 2001 From: Nnamdi Nwabuokei Date: Sun, 7 Dec 2025 18:26:01 +0100 Subject: [PATCH 4/4] chore(exasol): refactored the test and added safe checking when reading alias.node --- sqlglot/dialects/exasol.py | 3 ++- tests/dialects/test_exasol.py | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sqlglot/dialects/exasol.py b/sqlglot/dialects/exasol.py index 1a52b4f660..f43391acd4 100644 --- a/sqlglot/dialects/exasol.py +++ b/sqlglot/dialects/exasol.py @@ -113,7 +113,8 @@ def prefix_local(node, visible_aliases: dict[str, bool]) -> exp.Expression: sel.set("this", inner) alias_node = sel.args.get("alias") - seen_aliases[alias_node.name] = bool(alias_node.args.get("quoted")) + + seen_aliases[sel.alias] = bool(alias_node and getattr(alias_node, "quoted", False)) new_selects.append(sel) else: new_selects.append(sel.transform(lambda node: prefix_local(node, seen_aliases))) diff --git a/tests/dialects/test_exasol.py b/tests/dialects/test_exasol.py index 30bde491c4..5677b6ad1f 100644 --- a/tests/dialects/test_exasol.py +++ b/tests/dialects/test_exasol.py @@ -713,10 +713,10 @@ def test_local_prefix_for_alias(self): "SELECT YR AS THE_YEAR, ID AS YR, THE_YEAR + 1 AS NEXT_YEAR FROM my_table", ), ( - "Select list aliases without Local keyword", - "SELECT YEAR(CURRENT_DATE) AS current_year, LOCAL.current_year + 1 AS next_year", - "SELECT YEAR(CURRENT_DATE) AS current_year, current_year + 1 AS next_year", - ) + "Select list aliases without Local keyword", + "SELECT YEAR(CURRENT_DATE) AS current_year, LOCAL.current_year + 1 AS next_year", + "SELECT YEAR(CURRENT_DATE) AS current_year, current_year + 1 AS next_year", + ), ] for title, exasol_sql, dbx_sql in test_cases: with self.subTest(clause=title):