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
PR #2693 added composite primary key (CPK) support across the adapter, but OracleEnhanced::DatabaseStatements#write_lobs (lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb) still encodes a single-column primary-key assumption. A TODO comment was added there in the same PR; this issue tracks the actual fix.
Current code
defwrite_lobs(table_name,klass,attributes,columns)# :nodoc:id=quote(attributes[klass.primary_key])columns.eachdo |col|
...
SELECT#{quote_column_name(col.name)} FROM #{quote_table_name(table_name)}WHERE#{quote_column_name(klass.primary_key)} = #{id} FOR UPDATE
...
endend
For a CPK model:
klass.primary_key is an Array (e.g. ["author_id", "id"]).
attributes[Array] returns nil.
quote_column_name(Array) produces a malformed SQL fragment such as "[\"author_id\", \"id\"]".
Both the id lookup and the WHERE clause are wrong, so any CPK model that has a CLOB / BLOB column will fail in:
insert_fixture (which calls write_lobs after super)
The post-save LOB rewrite path used when prepared_statements: false (or for any LOB column that wasn't sent via the regular bind path)
Repro sketch
ActiveRecord::Schema.definedocreate_table:cpk_docs,primary_key: [:author_id,:id],force: truedo |t|
t.integer:author_idt.integer:idt.text:body# CLOBendendclassCpkDoc < ActiveRecord::Baseself.primary_key=[:author_id,:id]endCpkDoc.create!(id: [1,1],body: "x" * 5000)# => fails when write_lobs runs, because attributes[[:author_id, :id]] is nil# and the WHERE clause becomes WHERE "["author_id", "id"]" = ...
Fix sketch
Build the lookup key and the WHERE clause from the primary-key components:
defwrite_lobs(table_name,klass,attributes,columns)# :nodoc:pk_cols=Array(klass.primary_key)pk_pairs=pk_cols.map{ |col| [col,attributes[col]]}where_clause=pk_pairs.map{ |col,val| "#{quote_column_name(col)} = #{quote(val)}"}.join(" AND ")columns.eachdo |col|
...
SELECT#{quote_column_name(col.name)} FROM #{quote_table_name(table_name)}WHERE#{where_clause} FOR UPDATE
...
endend
Specs should cover:
CPK + CLOB column, value above the varchar2 inline limit so the LOB rewrite path is exercised.
CPK + BLOB column.
The prepared_statements: false connection variant for the same scenarios.
insert_fixture against a CPK + LOB table (covers the insert_fixture call site).
Background
PR #2693 added composite primary key (CPK) support across the adapter, but
OracleEnhanced::DatabaseStatements#write_lobs(lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb) still encodes a single-column primary-key assumption. ATODOcomment was added there in the same PR; this issue tracks the actual fix.Current code
For a CPK model:
klass.primary_keyis anArray(e.g.["author_id", "id"]).attributes[Array]returnsnil.quote_column_name(Array)produces a malformed SQL fragment such as"[\"author_id\", \"id\"]".Both the
idlookup and theWHEREclause are wrong, so any CPK model that has a CLOB / BLOB column will fail in:insert_fixture(which callswrite_lobsaftersuper)prepared_statements: false(or for any LOB column that wasn't sent via the regular bind path)Repro sketch
Fix sketch
Build the lookup key and the
WHEREclause from the primary-key components:Specs should cover:
varchar2inline limit so the LOB rewrite path is exercised.prepared_statements: falseconnection variant for the same scenarios.insert_fixtureagainst a CPK + LOB table (covers theinsert_fixturecall site).Out of scope
Related
TODOcomment this issue tracks)