Skip to content

Commit 993919d

Browse files
authored
fix(snowflake): Properly transpile ARRAY_AGG, IGNORE/RESPECT NULLS (#5137)
* fix(snowflake): Properly transpile ARRAY_AGG, IGNORE/RESPECT NULLS * Refactor into generator flag * Switch to type(expr).key
1 parent bb4f428 commit 993919d

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

sqlglot/dialects/snowflake.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,8 @@ class Generator(generator.Generator):
11541154
exp.VarMap,
11551155
}
11561156

1157+
RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS = (exp.ArrayAgg,)
1158+
11571159
def with_properties(self, properties: exp.Properties) -> str:
11581160
return self.properties(properties, wrapped=False, prefix=self.sep(""), sep=" ")
11591161

@@ -1402,3 +1404,19 @@ def createable_sql(self, expression: exp.Create, locations: t.DefaultDict) -> st
14021404
return f"{this_name}{self.sep()}{copy_grants}{this_schema}"
14031405

14041406
return super().createable_sql(expression, locations)
1407+
1408+
def arrayagg_sql(self, expression: exp.ArrayAgg) -> str:
1409+
this = expression.this
1410+
1411+
# If an ORDER BY clause is present, we need to remove it from ARRAY_AGG
1412+
# and add it later as part of the WITHIN GROUP clause
1413+
order = this if isinstance(this, exp.Order) else None
1414+
if order:
1415+
expression.set("this", order.this.pop())
1416+
1417+
expr_sql = super().arrayagg_sql(expression)
1418+
1419+
if order:
1420+
expr_sql = self.sql(exp.WithinGroup(this=expr_sql, expression=order))
1421+
1422+
return expr_sql

sqlglot/generator.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,8 @@ class Generator(metaclass=_Generator):
667667
# Expressions that need to have all CTEs under them bubbled up to them
668668
EXPRESSIONS_WITHOUT_NESTED_CTES: t.Set[t.Type[exp.Expression]] = set()
669669

670+
RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS: t.Tuple[t.Type[exp.Expression], ...] = ()
671+
670672
SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
671673

672674
__slots__ = (
@@ -4268,6 +4270,13 @@ def _simplify_unless_literal(self, expression: E) -> E:
42684270
return expression
42694271

42704272
def _embed_ignore_nulls(self, expression: exp.IgnoreNulls | exp.RespectNulls, text: str) -> str:
4273+
this = expression.this
4274+
if isinstance(this, self.RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS):
4275+
self.unsupported(
4276+
f"RESPECT/IGNORE NULLS is not supported for {type(this).key} in {self.dialect.__class__.__name__}"
4277+
)
4278+
return self.sql(this)
4279+
42714280
if self.IGNORE_NULLS_IN_FUNC and not expression.meta.get("inline"):
42724281
# The first modifier here will be the one closest to the AggFunc's arg
42734282
mods = sorted(

tests/dialects/test_bigquery.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,3 +2560,22 @@ def test_override_normalization_strategy(self):
25602560
self.assertEqual(qualified.sql("bigquery"), "SELECT * FROM `P`.`D`.`T` AS `T`")
25612561
finally:
25622562
BigQuery.NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
2563+
2564+
def test_array_agg(self):
2565+
for distinct in ("", "DISTINCT "):
2566+
self.validate_all(
2567+
f"SELECT ARRAY_AGG({distinct}x ORDER BY x)",
2568+
write={
2569+
"bigquery": f"SELECT ARRAY_AGG({distinct}x ORDER BY x)",
2570+
"snowflake": f"SELECT ARRAY_AGG({distinct}x) WITHIN GROUP (ORDER BY x NULLS FIRST)",
2571+
},
2572+
)
2573+
2574+
for nulls in ("", " IGNORE NULLS", " RESPECT NULLS"):
2575+
self.validate_all(
2576+
f"SELECT ARRAY_AGG(x{nulls} ORDER BY col1 ASC, col2 DESC)",
2577+
write={
2578+
"bigquery": f"SELECT ARRAY_AGG(x{nulls} ORDER BY col1 ASC, col2 DESC)",
2579+
"snowflake": "SELECT ARRAY_AGG(x) WITHIN GROUP (ORDER BY col1 ASC NULLS FIRST, col2 DESC NULLS LAST)",
2580+
},
2581+
)

0 commit comments

Comments
 (0)