Skip to content

Commit 34fb5da

Browse files
authored
fix: handle aggregate operations on empty selections (#2510)
SQL generator output fallbacks (SELECT 1 placeholder). Fixes #<452681068> 🦕
1 parent b589de9 commit 34fb5da

3 files changed

Lines changed: 37 additions & 3 deletions

File tree

‎tests/system/small/test_dataframe.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6296,3 +6296,20 @@ def test_agg_with_dict_containing_non_existing_col_raise_key_error(scalars_dfs):
62966296

62976297
withpytest.raises(KeyError):
62986298
bf_df.agg(agg_funcs)
6299+
6300+
6301+
deftest_empty_agg_projection_succeeds():
6302+
# Tests that the compiler generates a SELECT 1 fallback for empty aggregations,
6303+
# protecting against BigQuery syntax errors when both groups and metrics are empty.
6304+
importimportlib
6305+
6306+
bq=importlib.import_module(
6307+
"bigframes_vendored.ibis.backends.sql.compilers.bigquery"
6308+
)
6309+
sg=importlib.import_module("bigframes_vendored.sqlglot")
6310+
6311+
compiler=bq.BigQueryCompiler()
6312+
res=compiler.visit_Aggregate(
6313+
"op", parent=sg.table("parent_table"), groups=[], metrics=[]
6314+
)
6315+
assert"SELECT 1"inres.sql()

‎third_party/bigframes_vendored/ibis/backends/sql/compilers/base.py‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,9 +1394,17 @@ def _generate_groups(groups):
13941394
returnmap(sge.convert, range(1, len(groups) +1))
13951395

13961396
defvisit_Aggregate(self, op, *, parent, groups, metrics):
1397-
sel=sg.select(
1398-
*self._cleanup_names(groups), *self._cleanup_names(metrics), copy=False
1399-
).from_(parent, copy=False)
1397+
exprs= []
1398+
ifgroups:
1399+
exprs.extend(self._cleanup_names(groups))
1400+
ifmetrics:
1401+
exprs.extend(self._cleanup_names(metrics))
1402+
1403+
ifnotexprs:
1404+
# Empty aggregated projections are invalid in BigQuery
1405+
exprs= [sge.Literal.number(1)]
1406+
1407+
sel=sg.select(*exprs, copy=False).from_(parent, copy=False)
14001408

14011409
ifgroups:
14021410
sel=sel.group_by(*self._generate_groups(groups.values()), copy=False)

‎third_party/bigframes_vendored/ibis/backends/sql/compilers/bigquery/__init__.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,15 @@ def visit_TimestampFromUNIX(self, op, *, arg, unit):
540540

541541
defvisit_Cast(self, op, *, arg, to):
542542
from_=op.arg.dtype
543+
ifto.is_null():
544+
returnsge.Null()
545+
ifargisNULLor (
546+
isinstance(arg, sge.Cast)
547+
andgetattr(arg, "to", None) isnotNone
548+
andstr(arg.to).upper() =="NULL"
549+
):
550+
ifto.is_struct() orto.is_array():
551+
returnsge.Cast(this=NULL, to=self.type_mapper.from_ibis(to))
543552
iffrom_.is_timestamp() andto.is_integer():
544553
returnself.f.unix_micros(arg)
545554
eliffrom_.is_integer() andto.is_timestamp():

0 commit comments

Comments
 (0)