Skip to content

Read a grouping key in an order term over an aggregate as the GROUP BY reads it, so Oracle sorts by me.age + count(you.age) - #283

Open
jasperblues wants to merge 1 commit into
mainfrom
fix/256-oracle-grouped-order
Open

jasperblues wants to merge 1 commit into
mainfrom
fix/256-oracle-grouped-order

Conversation

@jasperblues

Copy link
Copy Markdown
Member

Fixes #256

Port of liberation-data/drivine4j#429 (merged as bc69834e), the fix for liberation-data/drivine4j#413.

On Oracle, an order term over an aggregate that reads a grouping key failed with ORA-00979:

MATCH (me:Person)--(you:Person)
RETURN me.age AS age, count(you.age) AS cnt
ORDER BY me.age + count(you.age)

It failed here

I ran the new test on Oracle (gvenzl/oracle-free:23-faststart) at main (ac0c979). Each of the first 7 statements failed with ORA-00979: "N1"."PROPS": must appear in the GROUP BY clause or be used in an aggregate function, except the 2 that already worked (ORDER BY age + count(you.age) and the node key). The 5 that failed were the issue's RETURN form, its WITH form, DISTINCT, SKIP/LIMIT with a WHERE after it, and an aggregate in the term that is no item. The run then stalled on the 8th, the comprehension case covered below. Offline, main's SQL for the issue's statement read the key 47 times as JSON_VALUE(n1.props, '$.age…'), beside a GROUP BY on its text.

Fix

In _project, as in drivine4j's project:

  • Where rows are grouped, an order term whose every aggregate and key is an item, each part read by its item's name (_over_items), is sorted over the items' columns after the query.
  • Any other order term over an aggregate reads each key item (an item that doesn't aggregate and names a variable) as its column value, the same expression the GROUP BY holds (_keys_read).

The issue's statement compiles to 14 KB, down from 16 KB. Its SQL is drivine4j's byte for byte, except for the NO_JSON_TABLE_TRANSFORM hint (#275) and the outer KEEP '$'. The temporal case (me.born + duration({days: 10 * count(*)})) compiled to 210 MB on Oracle on main. It is 52 KB now.

SQL

Every statement of the spec (v0.6.19, all four files) compiles to the same SQL on Oracle and Postgres before and after: 2,060 compiles, 0 changed. No spec statement has this shape.

Tests

  • test_an_order_term_over_an_aggregate_that_reads_a_grouping_key_is_sorted_by_the_key_as_it_is_grouped_by (async, plus the sync copy from unasync), on Neo4j, Postgres and Oracle. It is drivine4j's CypherQueryContract test, with Neo4j's rows. It covers the issue's statement in RETURN, WITH and DISTINCT forms, an order term made of items (age + count(you.age)), SKIP and LIMIT with a WHERE after the ordered WITH, a node key, an aggregate that is no item, a key in a function, two keys, a key that is an expression, several keys, a variable-length walk and a temporal key.
  • test_oracle_item_property: the issue's statement reads the key through its text twice (once for the item, once for the GROUP BY) and never as JSON_VALUE(n1.props, '$.age…').

Differences from drivine4j

Gate

scripts/check_cypher_spec.py, ruff check, ruff format --check, pyright, scripts/unasync.py --check, then ORACLE_TESTS=true uv run pytest -q: 5200 passed, 298 skipped.

…Y reads it, so Oracle sorts by me.age + count(you.age)

On Oracle, ORDER BY me.age + count(you.age) beside me.age AS age failed
with ORA-00979. The projection groups by the key read through its text
(item_property), and the order term read me.age again from the properties.

Where rows are grouped, an order term whose every aggregate and key is an
item is now sorted over the items' columns, after the query. Any other
term over an aggregate reads each key item as its column value, the same
expression the GROUP BY holds (_keys_read). Port of drivine4j#429.

Fixes #256

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cypher on Oracle: ORDER BY me.age + count(you.age) beside the grouping key fails with ORA-00979

1 participant