Repository: mabel-dev/opteryx

Issue:
🪲 [ClickBench] GROUP BY literal fails
~~~sql
SELECT 1, URL, COUNT(*) AS c FROM hits GROUP BY 1, URL ORDER BY c DESC LIMIT 10;
~~~

> AttributeError: 'NoneType' object has no attribute 'identity'

believe it is the `GROUP BY 1` that is the error


Discussion:
I wonder if GROUP BY True also fails or if this is a remnant of the ordinal GROUP and ORDER clauses.

Resolving patch:
diff --git a/opteryx/__version__.py b/opteryx/__version__.py
--- a/opteryx/__version__.py
+++ b/opteryx/__version__.py
@@ -1,4 +1,4 @@
-__build__ = 566
+__build__ = 569
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/opteryx/planner/binder/binder_visitor.py b/opteryx/planner/binder/binder_visitor.py
--- a/opteryx/planner/binder/binder_visitor.py
+++ b/opteryx/planner/binder/binder_visitor.py
@@ -291,6 +291,8 @@ def visit_aggregate_and_group(
         if node.groups:
             tmp_groups, _ = zip(*(inner_binder(group, context) for group in node.groups))
             columns_to_keep = {col.schema_column.identity for col in tmp_groups}
+        # remove literals in the GROUP BY clause, they form one group
+        node.groups = [g for g in node.groups if g.node_type != NodeType.LITERAL]
         # 2) the columns referenced in the SELECT
         node.columns = get_all_nodes_of_type(
             node.aggregates + node.groups, select_nodes=(NodeType.IDENTIFIER,)
@@ -308,6 +310,10 @@ def visit_aggregate_and_group(
                 context.schemas.pop(name)
 
         for array_agg in [agg for agg in tmp_aggregates if agg.value == "ARRAY_AGG"]:
+            if not node.groups:
+                raise UnsupportedSyntaxError(
+                    "ARRAY_AGG requires a GROUP BY clause, and cannot GROUP BY a literal value."
+                )
             if array_agg.order:
                 if len(array_agg.order) > 1:
                     raise UnsupportedSyntaxError(
diff --git a/opteryx/planner/cost_based_optimizer/strategies/predicate_pushdown.py b/opteryx/planner/cost_based_optimizer/strategies/predicate_pushdown.py
--- a/opteryx/planner/cost_based_optimizer/strategies/predicate_pushdown.py
+++ b/opteryx/planner/cost_based_optimizer/strategies/predicate_pushdown.py
@@ -206,6 +206,15 @@ def visit(self, node: LogicalPlanNode, context: OptimizerContext) -> OptimizerCo
             if context.last_nid:
                 context.optimized_plan.add_edge(context.node_id, context.last_nid)
 
+        elif node.node_type == LogicalPlanStepType.Limit:
+            # don't push filters past limits
+
+            for predicate in context.collected_predicates:
+                context.optimized_plan.insert_node_after(
+                    random_string(), predicate, context.node_id
+                )
+            context.collected_predicates = []
+
         elif node.node_type == LogicalPlanStepType.Filter:
             # collect predicates we can probably push
             if (


Test patch:
diff --git a/tests/sql_battery/test_shapes_and_errors_battery.py b/tests/sql_battery/test_shapes_and_errors_battery.py
--- a/tests/sql_battery/test_shapes_and_errors_battery.py
+++ b/tests/sql_battery/test_shapes_and_errors_battery.py
@@ -1108,7 +1108,7 @@
 
         ("SELECT ARRAY_AGG(name) from $satellites GROUP BY planetId", 7, 1, None),
         ("SELECT ARRAY_AGG(DISTINCT name) from $satellites GROUP BY planetId", 7, 1, None),
-        ("SELECT ARRAY_AGG(name ORDER BY name) from $satellites GROUP BY TRUE", 1, 1, None),
+        ("SELECT ARRAY_AGG(name ORDER BY name) from $satellites GROUP BY TRUE", 1, 1, UnsupportedSyntaxError),
         ("SELECT ARRAY_AGG(name LIMIT 1) from $satellites GROUP BY planetId", 7, 1, None),
         ("SELECT ARRAY_AGG(DISTINCT name LIMIT 1) from $satellites GROUP BY planetId", 7, 1, None),
         ("SELECT COUNT(*), ARRAY_AGG(name) from $satellites GROUP BY planetId", 7, 2, None),
@@ -1580,6 +1580,8 @@
         ("SELECT birth_place->>'town', birth_place->>'state' FROM $astronauts;", 357, 2, None),
         # 1622
         ("SELECT * FROM (SELECT p.Price AS pri, s.escapeVelocity FROM $missions AS p INNER JOIN $planets AS s ON p.Price = s.escapeVelocity) AS SV WHERE IFNULL(null, pri) = pri", 5, 2, None),
+        # 1696
+        ("SELECT name FROM (SELECT * FROM $planets LIMIT 5) AS S WHERE name != 'Mars'", 4, 1, None),
 ]
 # fmt:on
 
diff --git a/tests/sql_battery/tests/regression.run_tests b/tests/sql_battery/tests/regression.run_tests
--- a/tests/sql_battery/tests/regression.run_tests
+++ b/tests/sql_battery/tests/regression.run_tests
@@ -89,10 +89,6 @@ SELECT TRUE XOR FALSE;
 SELECT NOT TRUE;
 SELECT NOT FALSE;
 
-SELECT LIST(id) FROM $planets GROUP BY TRUE;
-SELECT GREATEST(LIST(id)) FROM $planets GROUP BY TRUE;
-SELECT LEAST(LIST(id)) FROM $planets GROUP BY TRUE;
-SELECT ANY_VALUE(id) FROM $planets GROUP BY TRUE;
 SELECT APPROXIMATE_MEDIAN(id) FROM $planets GROUP BY TRUE;
 SELECT AVG(id) FROM $planets GROUP BY TRUE;
 SELECT COUNT(id) FROM $planets GROUP BY TRUE;
@@ -100,7 +96,6 @@ SELECT COUNT_DISTINCT(id) FROM $planets GROUP BY TRUE;
 SELECT MAX(id) FROM $planets GROUP BY TRUE;
 SELECT MIN(id) FROM $planets GROUP BY TRUE;
 SELECT MIN_MAX(id) FROM $planets GROUP BY TRUE;
-SELECT ONE(id) FROM $planets GROUP BY TRUE;
 SELECT PRODUCT(id) FROM $planets GROUP BY TRUE;
 SELECT STDDEV(id) FROM $planets GROUP BY TRUE;
 SELECT SUM(id) FROM $planets GROUP BY TRUE;
diff --git a/tests/sql_battery/tests/types.run_tests b/tests/sql_battery/tests/types.run_tests
--- a/tests/sql_battery/tests/types.run_tests
+++ b/tests/sql_battery/tests/types.run_tests
@@ -2,4 +2,14 @@ SELECT BLOB('apple') = 'apple';
 SELECT 'apple' = BLOB('apple');
 SELECT BLOB('apple') > 'banana';
 SELECT 'banana' > BLOB('apple');
-SELECT BLOB('apple') LIKE 'a%ple';
\ No newline at end of file
+SELECT BLOB('apple') LIKE 'a%ple';
+SELECT b'apple' = 'apple';
+SELECT 'apple' = b'apple'b;
+SELECT b'apple' > 'banana';
+SELECT 'banana' > b'apple';
+SELECT b'apple' LIKE 'a%ple';
+SELECT BLOB('apple') = b'apple';
+SELECT b'apple' = BLOB('apple');
+SELECT BLOB('apple') > b'banana';
+SELECT b'banana' > BLOB('apple');
+SELECT BLOB('apple') LIKE b'a%ple';
\ No newline at end of file