You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] $startsWith / $icontains on a multi-valued lookup answer 500 on PostgreSQL and a wrong count on SQLite: the text operators other than $contains reach a JSON column unrefused and unruled #21009
Filing gate: ① a defect with a named landing site: packages/drivers/driver-sql/src/sql-driver.ts, the JSON-column operator gate (JSON_COLUMN_INCOMPATIBLE_OPERATORS and the arms that emit LIKE / GLOB over a JSON column). Finding class (a). reach:POST /api/v1/data/:object/query on SQLite and a live PostgreSQL 16.14, at origin/main212d613c and at PR #21004's head 90ba78d9, measured by #20873's dev (os-dev-report 5922812043 on #20873, out_of_scope_findings[3]).
Filed by the domain:engine execution seat 2 (seat post #20966, session_01Ujdtvqs7ree7WyQmEDwEnG, os-litant). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.
What happens
A multi-valued lookup owners; one row holds ['u10'].
where
PostgreSQL 16
SQLite
in-memory
{ owners: { $startsWith: 'u1' } }
500 DATABASE_ERROR
200, n: 0 (the serialized text starts with a bracket)
3, per element
{ owners: { $icontains: 'U1' } }
500
200, n: 3: it counts ['u10'], a substring across the serialization
The SQL family does not refuse them either: $startsWith is not in JSON_COLUMN_INCOMPATIBLE_OPERATORS, so it reaches applyLike over the JSON text, which PostgreSQL cannot do for a json column.
One filter, three answers, one of them a 500.
Scope for whoever takes it (⛔ not a ruling)
Decide the text operators' reading over a JSON-stored field (refuse them like the equality family, with the $or-of-$contains prescription; or give them a per-element ruling). That is a contract decision, so the operator set's semantics may need the maintainer. The open fact is that the platform answers it three ways today, one of them 500.
Whatever is ruled, every driver gives one answer, and the having / per-aggregation evaluator follows where.
Pins on memory, SQLite and PostgreSQL: $startsWith, $endsWith, $icontains (and $like / $ilike if they reach the column) over a multi-valued lookup.
Reader: triage first (the reading may be a contract question); then the domain:engine seat for driver-sql / driver-memory, or the domain:spec seat if the docblock's ruling changes.
Dedupe
mcp__github__search_issues, repo-scoped, open and closed, in the act that filed this card:
Filing gate: ① a defect with a named landing site:
packages/drivers/driver-sql/src/sql-driver.ts, the JSON-column operator gate (JSON_COLUMN_INCOMPATIBLE_OPERATORSand the arms that emitLIKE/GLOBover a JSON column). Finding class (a).reach:POST /api/v1/data/:object/queryon SQLite and a live PostgreSQL 16.14, atorigin/main212d613cand at PR #21004's head90ba78d9, measured by #20873's dev (os-dev-report5922812043 on #20873,out_of_scope_findings[3]).Filed by the
domain:engineexecution seat 2 (seat post #20966,session_01Ujdtvqs7ree7WyQmEDwEnG,os-litant). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.What happens
A multi-valued lookup
owners; one row holds['u10'].where{ owners: { $startsWith: 'u1' } }DATABASE_ERRORn: 0(the serialized text starts with a bracket){ owners: { $icontains: 'U1' } }n: 3: it counts['u10'], a substring across the serialization$containsdocblock (FILTER_OPERATORS,@objectstack/spec) rules$contains/$notContainson a JSON-stored field as membership. After PR fix(driver-memory): $contains on a multi-valued or JSON-stored field is membership, on every face #20984 it says the other text operators over a stored array are NOT ruled by that section.$startsWithis not inJSON_COLUMN_INCOMPATIBLE_OPERATORS, so it reachesapplyLikeover the JSON text, which PostgreSQL cannot do for ajsoncolumn.Scope for whoever takes it (⛔ not a ruling)
$or-of-$containsprescription; or give them a per-element ruling). That is a contract decision, so the operator set's semantics may need the maintainer. The open fact is that the platform answers it three ways today, one of them 500.having/ per-aggregation evaluator followswhere.$startsWith,$endsWith,$icontains(and$like/$ilikeif they reach the column) over a multi-valued lookup.Reader: triage first (the reading may be a contract question); then the
domain:engineseat fordriver-sql/driver-memory, or thedomain:specseat if the docblock's ruling changes.Dedupe
mcp__github__search_issues, repo-scoped, open and closed, in the act that filed this card:$contains/$notContainson a declared multi-valued or JSON-stored field still answer SUBSTRING on five faces, the analytics RLS read scope among them (u1admits a row storingu10) #20987 ($containsmembership on five faces) and analytics: on the ObjectQL strategy a$notover a multi-valued lookup ($contains) is refused 400, because the NULL-safe guard reaches driver-sql as$ne: nullon a JSON column, where the engine answers the rows #20918 (an analytics$notguard). Closed: service-analytics:$icontainswith an empty comparand answers every non-NULL row on the analytics where and read-scope compilers, where FILTER_TEXT_CASES declares it refused (INVALID_FILTER) and driver-sql refuses it #20068, service-analytics (SQLite): the shared text-match arm emitsGLOB, so a$contains/$endsWith/$startsWithcomparand holding U+0000 is cut at the NUL; on the read scope a leading U+0000 widens$contains/$endsWithto every row #20025, driver-sql (SQLite faces): a$contains/$startsWith/$endsWithcomparand holding U+0000 is cut at the NUL byglob(), so the filter answers wrongly; one that starts with U+0000 makes$contains/$endsWithmatch every row #19999,$icontainsstill compilestranslate()on theunknowndialect arm, so a SQLite datasource whose dialect is unanswered still fails to parse — PR #16020's measured residue #16028, service-analytics: the three SQL compilers emittranslate()for$icontains, a function SQLite does not have — the statement fails to parse instead of answering wrong rows #15780, service-analytics: all three SQL compilers emit a plain LIKE for the case-sensitive $contains family, which folds ASCII case on SQLite — the read scope and the native where admit rows the #4706 contract excludes #15684,$icontainshas no counterpart inVIEW_FILTER_OPERATORSorVALID_AST_OPERATORS, so it is authorable only in the MongoDB-style dialect #8934, [finding]$icontainsis absent from analyticsTEXT_PATTERN_OPERATORS, so the #5234 comparand fence never covered it on thewheredoor — one operator, two answers inside one package #7693, objectqlhavinghas no$icontainscomparand-shape gate — an empty comparand matches EVERY row (2 of 5FILTER_TEXT_CASESrejection rows unenrollable) #7158, drivers(sql family): 文本算子的大小写折叠是「方言的」而非「契约的」——$contains在 SQLite 过折叠、$icontains在 PG/MySQL 过折叠 #6518 and objectui: FilterConditionField cannot author spec’s $icontains — the case-insensitive contains is unreachable from the filter UI #6337, which are empty comparands, U+0000,translate(), case folding and authoring. None covers a text operator other than$containsover a JSON column.Dedupe words:
startsWith multiple lookup postgres 500·icontains json column serialization substring·text operators stored array unruled