Skip to content

fix(find): refuse a cursor along an order with no comparable value - #1031

Merged
abnegate merged 1 commit into
mainfrom
fix/cursor-unorderable
Oct 16, 2026
Merged

abnegate merged 1 commit into
mainfrom
fix/cursor-unorderable

Conversation

@abnegate

Copy link
Copy Markdown
Member

What

Staging bug E: cursor paging over an array or spatial order gave a 500. orderAsc on a string-array (sa), int-array (ia), point (pt) or line (ln) column combined with cursorAfter failed as follows:

  • Arrays: TypeError Query::greaterThan() given an array at SQL.php:5737 (cursorConditions).
  • Spatial columns on MySQL: PDOException 1210 Incorrect arguments to >.

The same orders without a cursor return 200.

A cursor pages along the values of the read's order and compares each row's value with the cursor's. An array, object, spatial or vector attribute has no value an engine can compare that way. 7.4.2 failed here too ("Unknown PDO Type for array"). MongoDB, Memory and Redis did answer such a page, but with comparisons that do not follow the order, so paging along it skipped or repeated rows.

find() now refuses a cursor along an array, object, spatial or vector attribute with Exception\Query on every adapter, including under a join alias. Ordering by such an attribute without a cursor keeps working exactly as on main, and so does a cursor along a scalar order. The refusal is a plain query error, not Exception\Order, because Appwrite reports Exception\Order as database_query_order_null ("had a null value").

Behaviour change to note: on MongoDB, Memory and Redis, a cursor along an array or object order used to return a (mis-ordered) page and is now refused.

Regression tests

Test Adapters origin/main this PR
DocumentTests::testCursorAlongAnOrderWithoutComparableValuesIsAnInvalidQuery: orders by sa, ia, plus pt/ln where spatial, obj where objects and vec where vectors; each with asc+after, desc+after, asc+before, and behind a scalar order; the same orders without a cursor still return every row; a cursor along n still pages MySQL, MariaDB, Postgres, SQLite fail: TypeError: Query::greaterThan(): Argument #2 ($value) must be of type string|int|float|bool, array given at SQL.php:5737 pass
MongoDB, Memory, Redis fail: cursor along sa accepted pass

Run locally against Docker: the full adapter suites for MySQL, MariaDB, Postgres, SQLite, MongoDB, Memory and Redis pass, as do the full unit suite, Pint and PHPStan.

API repro (Appwrite)

GET /v1/tablesdb/{db}/tables/{t}/rows?queries[]={"method":"orderAsc","attribute":"sa"}&queries[]={"method":"cursorAfter","values":["<rowId>"]} → 400 general_query_invalid, message Cannot page with a cursor along the order of 'sa': an array, object, spatial or vector attribute has no value a cursor can compare (was 500). The same holds for ia, pt and ln, and for orderDesc and cursorBefore. Without the cursor query → 200.

🤖 Generated with Claude Code

A cursor pages along the values of the read's order, comparing each row's
value with the cursor's. A read ordered by an array attribute passed the
array the cursor holds to Query::greaterThan(), a TypeError, and one
ordered by a spatial attribute reached MySQL as a geometry comparison it
refuses with error 1210, both server errors. MongoDB, Memory and Redis
answered such a page, but by comparisons that do not follow the order, so
paging along it skipped or repeated rows. 7.4.2 failed the SQL engines the
same way ("Unknown PDO Type for array").

find() refuses a cursor along an array, object, spatial or vector
attribute as an invalid query on every adapter, under a join alias too.
Ordering by such an attribute without a cursor keeps working as it did.
The refusal is a plain query error rather than Exception\Order, which
consumers report as a null order value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 39 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: utopia-php/database/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9ff3ed4e-0970-4713-a7ae-86189823d0f0
📥 Commits

Reviewing files that changed from the base of the PR and between 09a4729 and 2fe76ce.

📒 Files selected for processing: 2
  • src/Database/Trait/Documents.php
  • tests/e2e/Adapter/Scopes/DocumentTests.php
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@abnegate
abnegate merged commit 7beab0c into main Oct 16, 2026
24 checks passed
@abnegate
abnegate deleted the fix/cursor-unorderable branch October 16, 2026 04:36
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.

1 participant