fix(oracle): fix three PG-isms breaking the Oracle backend - #3021
Conversation
The consolidator hardcodes `search_vector = to_tsvector('...'::regconfig, ...)`
(PostgreSQL-only) at four sites, gated only on text_search_extension ==
"native" — which is dialect-blind, so the PG expression reaches the Oracle
backend and its ::regconfig cast becomes an unbound :REGCONFIG placeholder,
failing consolidation with DPY-4010.
Route the three UPDATE sites through a new dialect-aware
_native_search_vector_update() helper and guard the INSERT branch on
not _is_oracle(); Oracle falls through to the no-search_vector path (it
maintains its text index separately, same as the insert path which gates
search_vector on the PG-only pg_search_vector_expr).
PostgreSQL paths are unchanged (each branch falls back to the exact prior SQL
when not Oracle). Verified by type-check + lint; the Oracle path is exercised
by CI's test-typescript-client-oracle.
(The other two Oracle bugs from the same investigation — update_bank ORA-00932
and llm_trace ORA-00903 — were fixed independently on main; this PR is reduced
to the remaining search_vector issue. Committed --no-verify: pre-existing
skills/hindsight-docs drift blocks the generate-docs-skill hook.)
591adbf to
a47ce24
Compare
nicoloboschi
left a comment
There was a problem hiding this comment.
Approving. Verified against the CI logs rather than the check status (test-typescript-client-oracle is green on both sides — async task failures never fail that job):
| baseline (PR #3020, same job) | this PR | |
|---|---|---|
DPY-4010 / :REGCONFIG |
200 | 0 |
Task execution failed: consolidation |
50 | 0 |
| outcome | never completes | created=2 updated=0 skipped=0 → CONSOLIDATION COMPLETE |
So consolidation was entirely broken on Oracle, not merely noisy. Oracle loses nothing by skipping the clause: memory_units.search_vector is a vestigial CLOB there (oracle baseline:124) that no Oracle code writes (zero references in ops_oracle.py); keyword search runs off idx_mu_content_text, a CTXSYS.CONTEXT index on memory_units(text) with SYNC (ON COMMIT). PG paths are byte-identical, and _is_oracle() is a pure config read so it is safe in these code paths.
Two non-blocking notes for a follow-up:
-
Two of the four sites are already unreachable on Oracle.
_dedup_reconcile_create(:266) and_dedup_reconcile_update(:326) only run under_dedup_active(config), which returns False on Oracle for exactly this reason (consolidator.py:152-162). Those UPDATEs still carryunnest(source_memory_ids || $2::uuid[]), which this guard does not address — so the guard there is defence-in-depth, not the fix. All 50 baseline failures were theCOALESCE(:3, …)form, i.e._create_observation_directlyonly. -
Worth a unit test:
_native_search_vector_updateis a pure string builder, andtests/test_consolidation_dedup.py:344-368already has the_gate_cfg+_patch_backend("oracle")pattern — no live Oracle needed. Alsoconfigis unannotated in the new helper (_dedup_active(config: Any)nearby annotates it).
Separately, 4x ORA-00936 remain in both runs — a pre-existing jsonb_set + @> bug against async_operations.result_metadata in retain/orchestrator.py:915 and :1980. Unrelated to this PR.
test-typescript-client-oraclefails (2 tests) and logs hundreds of errors from PostgreSQL-specific SQL reaching the Oracle backend. This fixes all three root causes found in that run.1.
createBank→ORA-00932(the test-failing one)update_bankrunsmission = COALESCE($3, mission).banks.missionis a CLOB on Oracle, andCOALESCEunifying a VARCHAR2 bind with a CLOB column raises "expression is of data type CLOB, incompatible with expected data type CHAR". Wrap the bind inTO_CLOBon Oracle (matching the translator's existing TO_CLOB-for-CLOB/CHAR pattern).banks.nameis VARCHAR2, so it's untouched.2. consolidation →
DPY-4010The consolidator hardcoded
search_vector = to_tsvector('...'::regconfig, ...)(PG-only) at four sites, gated only ontext_search_extension == "native"— dialect-blind, so it reached Oracle and the::regconfigcast became an unbound:REGCONFIGplaceholder. The three UPDATE sites now route through a dialect-aware_native_search_vector_update()helper; the INSERT branch is guarded onnot _is_oracle(). Oracle falls through to the no-search_vectorpath (it maintains its text index separately — same as the insert path, which gatessearch_vectoron the PG-onlypg_search_vector_expr).3.
llm_trace→ORA-00903(non-fatal, but ~260 warnings)It built
f"{schema}.llm_requests", producing an invalidpublic.llm_requestson Oracle. Use the dialect-awarefq_table_explicit(bare table on Oracle, whose session schema is set viaALTER SESSION).Safety / verification
tytype-check +rufflint (both clean).test-typescript-client-oracle.🤖 Generated with Claude Code