Skip to content

driver-sql / driver-turso (SQLite faces): GLOB still cuts a STORED value at its first U+0000, so a NUL-free $contains / $notContains / $icontains / $endsWith answers wrongly on it; a $like / $ilike pattern holding U+0000 is cut the same way #20024

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site on the SQLite faces:

  • packages/drivers/driver-sql/src/sql-driver.ts textMatchPredicate (the GLOB arm) and likePatternPredicate (the $like / $ilike SQLite arm), inherited by SqliteWasmDriver and TursoDriver local mode;
  • packages/drivers/driver-turso/src/remote-transport.ts pushLike / pushLikePattern.

Finding class (a).

Filed by the domain:engine execution seat 1 (session_01Bvd69VPa6puiNzzPUroDBx) from the out-of-scope findings of its #19999 dev (os-dev-report on #19999, PR #20019). Its at-tier contract reviewer measured both findings REAL (record 5821310673 on PR #20019). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.

What happens

SQLite's glob() reads both its pattern and the stored value as C strings, so each is cut at its first U+0000. #19999 (PR #20019, in review) moves a comparand that HOLDS U+0000 off GLOB. Two cuts remain:

  1. A stored value holding U+0000, filtered by a comparand without one. GLOB sees only the part before the value's first U+0000. Measured at PR fix(driver-sql, driver-turso): compare a SQLite text comparand holding U+0000 whole instead of cutting it at GLOB #20019's head b60884a47 on better-sqlite3 (SQLite 3.53.4), sql.js (3.49.1) and a real @libsql/client engine (3.45.1), with identical answers on all four faces (SqlDriver, SqliteWasmDriver, TursoDriver local and remote), 22 wrong cases per face in the reviewer's probe:

    • $contains: 'b' misses a value stored as 'a'+U+0000+'b';
    • $endsWith: 'a' returns it;
    • $notContains: 'b' returns it;
    • $icontains: 'B' misses 'A'+U+0000+'B';
    • $contains: 'z' misses U+0000+'z'.

    $startsWith is provably unaffected. A stored U+0000 is reachable today: better-sqlite3 stores it, and so has sqlite-wasm since PR fix(driver-sqlite-wasm): a text value round-trips byte-for-byte — U+0000 no longer truncates it, a leading U+FEFF is no longer dropped on read #19998 (driver-sqlite-wasm: a text value does not round-trip the way driver-sql's does — an embedded NUL truncates the stored value, and a leading BOM is stripped on read #19978).

  2. A $like / $ilike pattern holding U+0000. It is cut at the U+0000. Measured on SqlDriver/better-sqlite3 at the same head, over the values 'a'+U+0000+'b', 'ab'+U+0000, U+0000+'z', 'plain' and '':

    • $like: '%'+U+0000 returned all five rows (JS: 'ab'+U+0000 only);
    • $like: U+0000+'%' returned '' and U+0000+'z' (JS: the latter only);
    • $ilike: '%'+U+0000+'B' returned all five (JS: 'a'+U+0000+'b').

    The remote pushLikePattern shares the arm by reading; it was not executed.

Nothing raises: the filter answers a different question than it names.

Suggested shape (⛔ not a ruling)

Filing-gate answers

Dedupe words: GLOB stored value U+0000 cut contains endsWith · sqlite text value NUL substring missed · $like pattern U+0000 GLOB · likePatternPredicate NUL


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions