Merge 'Unify resolution of aggregate functions' from Piotr Rżysko
Some checks are pending
Build and push limbo-sim image / deploy (push) Waiting to run
Dart/Flutter / test (blacksmith-4vcpu-ubuntu-2404) (push) Waiting to run
Dart/Flutter / test (macos-latest) (push) Waiting to run
Dart/Flutter / test (windows-latest) (push) Waiting to run
Dart/Flutter / precompile (blacksmith-4vcpu-ubuntu-2404) (push) Waiting to run
Dart/Flutter / precompile (macOS-latest) (push) Waiting to run
Dart/Flutter / precompile (windows-latest) (push) Waiting to run
Dart/Flutter / publish (push) Waiting to run
Java Tests / test (push) Waiting to run
Build & publish @tursodatabase/sync / stable - wasm32-wasip1-threads - node@20 (push) Waiting to run
Build & publish @tursodatabase/sync / stable - aarch64-apple-darwin - node@20 (push) Waiting to run
Build & publish @tursodatabase/sync / stable - aarch64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/sync / stable - x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/sync / stable - x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/sync / Test turso-sync-js on Linux-x64-gnu - node@20 (push) Blocked by required conditions
Build & publish @tursodatabase/sync / Publish (push) Blocked by required conditions
Build & publish @tursodatabase/database / stable - x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / stable - wasm32-wasip1-threads - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / stable - aarch64-apple-darwin - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / stable - aarch64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / stable - x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / Test bindings on Linux-x64-gnu - node@20 (push) Blocked by required conditions
Build & publish @tursodatabase/database / Publish (push) Blocked by required conditions
Python / linux (x86_64) (push) Waiting to run
Python / macos-arm64 (aarch64) (push) Waiting to run
Python / sdist (push) Waiting to run
Python / Release (push) Blocked by required conditions
Python / configure-strategy (push) Waiting to run
Python / test (push) Blocked by required conditions
Python / lint (push) Waiting to run
Rust / cargo-fmt-check (push) Waiting to run
Rust / build-native (blacksmith-4vcpu-ubuntu-2404) (push) Waiting to run
Rust / build-native (macos-latest) (push) Waiting to run
Rust / build-native (windows-latest) (push) Waiting to run
Rust / clippy (push) Waiting to run
Rust / simulator (push) Waiting to run
Rust / test-limbo (push) Waiting to run
Rust / test-sqlite (push) Waiting to run
Rust Benchmarks+Nyrkiö / bench (push) Waiting to run
Rust Benchmarks+Nyrkiö / clickbench (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h-criterion (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h (push) Waiting to run
Rust Benchmarks+Nyrkiö / vfs-bench-compile (push) Waiting to run

This PR unifies the logic for resolving aggregate functions. Previously,
bare aggregates (e.g. `SELECT max(a) FROM t1`) and aggregates wrapped in
expressions (e.g. `SELECT max(a) + 1 FROM t1`) were handled differently,
which led to duplicated code. Now both cases are resolved consistently.
The added benchmark shows a small improvement:
```
Prepare `SELECT first_name, last_name, state, city, age + 10, LENGTH(email), UPPER(first_name), LOWE...
                        time:   [59.791 µs 59.898 µs 60.006 µs]
                        change: [-7.7090% -7.2760% -6.8242%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  8 (8.00%) high mild
  2 (2.00%) high severe
```
For an existing benchmark, no change:
```
Prepare `SELECT first_name, count(1) FROM users GROUP BY first_name HAVING count(1) > 1 ORDER BY cou...
                        time:   [11.895 µs 11.913 µs 11.931 µs]
                        change: [-0.2545% +0.2426% +0.6960%] (p = 0.34 > 0.05)
                        No change in performance detected.
Found 8 outliers among 100 measurements (8.00%)
  1 (1.00%) low severe
  2 (2.00%) high mild
  5 (5.00%) high severe
```

Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Reviewed-by: Preston Thorpe <preston@turso.tech>

Closes #2884
This commit is contained in:
Preston Thorpe 2025-09-03 19:46:04 -04:00 committed by GitHub
commit caaf60a7ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 147 additions and 200 deletions

View file

@ -175,3 +175,27 @@ do_execsql_test select-json-group-object-no-sorting-required {
3|{"3437":"Amanda"}
5|{"2378":"Amy","3227":"Amy","5605":"Amanda"}
7|{"2454":"Amber"}}
do_execsql_test_error_content select-max-star {
SELECT max(*) FROM users;
} {"wrong number of arguments to function"}
do_execsql_test_error_content select-max-star-in-expression {
SELECT CASE WHEN max(*) > 0 THEN 1 ELSE 0 END FROM users;
} {"wrong number of arguments to function"}
do_execsql_test_error select-scalar-func-star {
SELECT abs(*) FROM users;
} {.*(Invalid aggregate function|wrong number of arguments to function).*}
do_execsql_test_error select-scalar-func-star-in-expression {
SELECT CASE WHEN abs(*) > 0 THEN 1 ELSE 0 END FROM users;
} {.*(Invalid aggregate function|wrong number of arguments to function).*}
do_execsql_test_error_content select-nested-agg-func {
SELECT max(abs(sum(age))), sum(age) FROM users;
} {"misuse of aggregate function"}
do_execsql_test_error_content select-nested-agg-func-in-expression {
SELECT CASE WHEN max(abs(sum(age))) > 0 THEN 1 ELSE 0 END, sum(age) FROM users;
} {"misuse of aggregate function"}

View file

@ -153,6 +153,11 @@ def test_aggregates():
validate_median,
"median agg function works",
)
limbo.run_test_fn(
"select CASE WHEN median(value) > 0 THEN median(value) ELSE 0 END from numbers;",
validate_median,
"median agg function wrapped in expression works",
)
limbo.execute_dot("INSERT INTO numbers (value) VALUES (8.0);\n")
limbo.run_test_fn(
"select median(value) from numbers;",
@ -184,6 +189,11 @@ def test_grouped_aggregates():
lambda res: "2.0\n5.5" == res,
"median aggregate function works",
)
limbo.run_test_fn(
"select CASE WHEN median(value) > 0 THEN median(value) ELSE 0 END from numbers GROUP BY category;",
lambda res: "2.0\n5.5" == res,
"median aggregate function wrapped in expression works",
)
limbo.run_test_fn(
"SELECT percentile(value, percent) FROM test GROUP BY category;",
lambda res: "12.5\n30.0\n45.0\n70.0" == res,