Repository navigation
fix(driver-sql): an Oracle RAW(16) uuid column is filtered and written by the uuid it reads as - #31642
Conversation
…gh HEXTORAW The catalog says which federated columns are RAW(16); those fields bind uuid text as HEXTORAW(?) over its hex digits, as comparands, written values and by-id keys. Text that is not a uuid is refused before the statement is built. Every other column and dialect binds as before. Claude-Session: https://claude.ai/code/session_01ADHkmQ9H84XNocJ8waPS1P Co-authored-by: Claude <noreply@anthropic.com>
…ects' unchanged statements Claude-Session: https://claude.ai/code/session_01ADHkmQ9H84XNocJ8waPS1P Co-authored-by: Claude <noreply@anthropic.com>
… form, and pin the Oracle live cell Claude-Session: https://claude.ai/code/session_01ADHkmQ9H84XNocJ8waPS1P Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADHkmQ9H84XNocJ8waPS1P Co-authored-by: Claude <noreply@anthropic.com>
…ites, through the seam with its subtree The refusal carries the filter subtree it was raised from, so the provenance mark decides what the wire names, as for every other compile refusal. Pattern operators on the column are not judged. Claude-Session: https://claude.ai/code/session_01ADHkmQ9H84XNocJ8waPS1P Co-authored-by: Claude <noreply@anthropic.com>
…he oracle uuid bind The RAW(16) catalog priming now runs at the top of each door facet body (find, create, update, delete, bulk, aggregate, distinct, window functions, analyze), the catalog read and the uuid binding live in FieldMappingFacet and FilterHelpersFacet, and registerExternalObject forgets a stale reading in its schema-sync body. SqlDriver keeps one-line forwards only. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ADHkmQ9H84XNocJ8waPS1P
The find and count calls pass a plain where bag that the driver's query type already accepts, so the any-casts only grew the query-options erasure test surface. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ADHkmQ9H84XNocJ8waPS1P
📓 Docs Drift CheckThis PR changes 1 package(s): 20 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 9 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 14 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 2bd010e8db3def7961ff5bb55f14a00e29061414 && git checkout 2bd010e8db3def7961ff5bb55f14a00e29061414
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 06060c61c572f833f19497a6e84838c52a923166 ee1c0183fa49234f4617984d219614a811b05878 && git checkout -B drift-repro 06060c61c572f833f19497a6e84838c52a923166 && git merge --no-ff ee1c0183fa49234f4617984d219614a811b05878
node scripts/docs-audit/affected-docs.mjs --json 06060c61c572f833f19497a6e84838c52a923166
|
|
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX Contract-review-claim: session_01ADHkmP8JJo4zF2sjTBRwnX · head a535d01 · 2026-11-08T18:17Z |
|
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX Contract reviewServed-tier: Face: Check-runs on ① Derived judgmentsThe surface is The accept set on an Oracle column the catalog reports as
② Semver level
③ Boundary flags
④ Design judgmentContract read sentence by sentence against the tree (card items 1, 2, 4; the seat's claim's file surface). "A comparand or written value for a "The read side stays "The column type must be known at bind time; read it from the introspected/declared column type, never guess it from the value." "Malformed uuid text is refused with a typed "Catalog read once per object; failure modes." Other dialects byte-identical. Judged in ①; the four pins run with the registry deliberately poisoned so only the dialect guard keeps the arm out, and they pass on Facade. Tests. Findings, graded:
No must-fix, no should-fix. Nits alone end the round. Implemented-by: VERDICT: PASS |
…-py8ur5 # Conflicts: # packages/drivers/driver-sql/src/sql-driver-aggregation.ts # packages/drivers/driver-sql/src/sql-driver-bulk-operations.ts # packages/drivers/driver-sql/src/sql-driver-crud.ts # packages/drivers/driver-sql/src/sql-driver-distinct.ts # packages/drivers/driver-sql/src/sql-driver-filter-helpers.ts # packages/drivers/driver-sql/src/sql-driver-query-plan.ts # packages/drivers/driver-sql/src/sql-driver-window-functions.ts # packages/drivers/driver-sql/src/sql-driver.ts
|
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX Contract-review-claim: session_01ADHkmP8JJo4zF2sjTBRwnX · head ee1c018 · 2026-11-08T21:04Z |
|
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX Contract reviewServed-tier: Round 2. The head is the merge of Check-runs on ① Derived judgmentsWhat the merge changed, judged from the remerge diff and from a line-level comparison of the two net diffs ( Door tops, read in the tree: each of the nine shared doors now runs Hosts, read in Interaction between the two features: none. The accept-set judgment of round 1 carries forward unchanged: the only inputs whose requests completed on ② Semver levelUnchanged from round 1 and re-read: ③ Boundary flags
④ Design judgmentThe contract is agreed sentence by sentence as in round 1 — HEXTORAW bind over the stripped digits for comparands, written values and by-id keys; the read side untouched; the column type from Findings, graded — the seven round-1 nits re-read on this head; no new finding:
No must-fix, no should-fix. Nits alone end the round. Implemented-by: VERDICT: PASS |
|
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX ACCEPT · PR #31642 · #31390 · 2026-11-08T21:10ZHead-sha:
|
Fixes #31390
Card items 1, 2 and 4 are in this pull request. Item 3, the type-compat pairing for an Oracle
RAW(16)column, is carried by #31592 in the spec lane, which waits on this one; nothing underpackages/specis touched here.Clause-②: yes (widening)
Metadata-protocol: none
维护者速读
RAW(16)的 uuid 列(SYS_GUID()主键及指向它的 lookup),过滤比较值、写入值和按 id 定位的键现在经HEXTORAW(?)绑定;读侧不变,仍读成带横线的小写 uuid。ALL_TAB_COLUMNS),读失败就照旧按文本绑定;非 uuid 文本在发库前被拒(过滤INVALID_FILTER,写入VALIDATION_ERROR)。其它方言编译输出逐字节不变,有 pin。回滚即 revert 本 PR。sql-driver-filter-helpers.ts(比较值绑定与三处编译拒绝点)、sql-driver-sqlite-serialisation.ts(formatInput 写入分支,所有方言共用)、sql-driver-field-mapping.ts(目录读取与缓存)。pnpm --filter @objectstack/driver-sql exec vitest run src/sql-driver-oracle-dialect.test.ts,预期 71 个测试全绿。What changes
RAW(16), once per object, fromALL_TAB_COLUMNS. The owner is the declared remote schema, then theOWNER.prefix of the remote name, thenCURRENT_SCHEMA. The reading is cached per object and dropped when the object is registered again. The column type decides; the value is never the evidence, so aVARCHAR2column that holds uuids still binds text.=,$eq,$ne,$in,$nin,$gt,$gte,$lt,$lte,$between) against such a column binds asHEXTORAW(?)over the uuid's 32 hex digits, upper case. Pattern operators ($contains,$likeand the rest) compile exactly as before, because their comparand is a text pattern and is never bound to the column.update,delete,bulkDeleteand the post-insert read-back bind the same way. The read-back matches the inserted rows by the read form of the id, so an id written upper case or undashed is found again.INVALID_FILTER/ 400, through the existing withheld-filter seam, so the field is withheld unless the subtree is author-marked. A written value that is not uuid text is refused with the existingVALIDATION_ERROR/ 400.RAW(16)column) is recorded and binds text.FieldMappingFacet, the binding inFilterHelpersFacet, andSqlDriverkeeps one-line forwards only.Error codes reused, none new:
INVALID_FILTER(filter comparands, throughwithheldFilterError),VALIDATION_ERROR(written values).Why
The driver already reads a
RAW(16)column as a dashed lowercase uuid (RAWTOHEXplus dashes in the fetch type handler), but bound the same text back as a string, which Oracle refuses againstRAW. A lookup keyed by aSYS_GUID()column therefore displayed correctly and could not be filtered, written, updated or deleted by its value. Step 0 on main (6b83ec2d, Oracle client compile) showed every uuid comparand and written value bound as dashed text, malformed values sent as they were, and noHEXTORAWanywhere. The declared field type cannot tell aRAW(16)column from a text one, so the column type has to come from the remote catalog.Tests
sql-driver-oracle-dialect.test.ts, 30 new tests (71 in the file, 41 on main):$eqon the key,$inwith mixed case, undashed 32-hex,$nenull-safe, null asIS NULL.VARCHAR2uuid column binds text (seat pin b),$containsis not judged, a uuid in a text column stays text.INVALID_FILTERwith nothing sent: equality, 8 hex digits,$inwith one bad member,$newith a number, 31 hex digits, and through the find door.VALIDATION_ERRORwith nothing sent, the update, delete and bulkDelete door SQL, and the create read-back for upper-case and undashed ids.coerceFilterValueandformatInputwith a poisoned column map, and a sqlite door-level pin capturing the exact statements and bindings of find, create, update, delete, bulkDelete and the read-back.sql-driver-oracle-federation-conformance.test.ts: a live Oracle cell, "RAW(16) uuid keys: filtered, written and looked up by the uuid they read as", covering the SYS_GUID read form, create with an upper-case id, eq and$in, the key, theVARCHAR2control, a lookup round trip, update and delete by key,INVALID_FILTERandVALIDATION_ERROR. It runs only withOS_TEST_ORACLE_URL.sql-driver-compile-refusal-seam.test.tsgains one DOORS row forassertOracleUuidComparand. That file enumerates every builder that raises through the withheld-filter seam and is red until each has a row; the row proves the policy, author, unmarked and merged-$andprovenance cases for the new refusal.Acceptance notes
OS_TEST_ORACLE_URLis not set in this environment and no CI workflow provides it. The live cell skips through the existing testkit.create()mints a nanoid when no id is given. On an object whose key is aRAW(16)column this is nowVALIDATION_ERROR/ 400 instead of an Oracle error. A database-default id (DEFAULT SYS_GUID()) is not used by this pull request.textMatchPredicateis not edited; the bind lives in the comparand and write path.Verification
Head
a535d018, merged withorigin/mainat133f75aec0. The suites and gates below ran onaed364b6; the one commit after it (a535d018) types the query bags in the new test file, and the oracle dialect file, eslint and the query-options erasure gate were re-run on it.eslint --no-inline-config packages/drivers/driver-sqlexit 0.pnpm --filter @objectstack/dogfood test): 440 files passed, 3 skipped; 3633 tests passed, 41 skipped; VERDICT command-exit 0.dispatch-gatesderives for this diff ran and exit 0;--ranreconciliation: 71 derived, 71 run, 0 NOT-MEASURED, 0 UNRUN. Two first runs exited 3 on a missing prerequisite (the teardown fixture commit absent from the shallow clone, and type-check-debt not getting the verify lock while dogfood held it) and passed on re-run.check:query-options-erasurefirst went red on 9 newas anyquery bags in the new test; they are typed ina535d018and the test surface is back at its 236 ceiling.Ablations (every negative pin), run with scripts/ablation-replace.mjs, each restored to blob == HEAD
INVALID_FILTERcases, the find door, and the four seam provenance rowsVALIDATION_ERRORwith nothing sentformatInputOracle guard and the binding's Oracle guard removedVARCHAR2column, uuid in a text column)The other-dialect pins were also run against the base source: they pass on main, so they pin unchanged behaviour.
Human Minimum
packages/specholds no runtime logic. (packages/specnot touched.)pnpm lintpasses.main, one pull request.packages/spectouched: not applicable.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code