Skip to content

Commit 553536b

Browse files
authored
Merge pull request rsim#2735 from yahonda/mirror-pk-fallback-in-sql-for-insert
Mirror AbstractAdapter PK inference fallback in sql_for_insert
2 parents 7a729a9 + ed64959 commit 553536b

2 files changed

Lines changed: 20 additions & 2 deletions

File tree

lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,20 @@ def affected_rows(result)
275275
end
276276

277277
def sql_for_insert(sql, pk, binds, returning) # :nodoc:
278+
table_ref = extract_table_ref_from_insert_sql(sql)
279+
# Mirror AbstractAdapter#sql_for_insert: when caller passes pk: nil,
280+
# infer the primary key from the SQL via the schema cache so that
281+
# generic `connection.exec_insert(sql, name, binds)` callers also
282+
# benefit from RETURNING auto-fetch.
283+
pk = schema_cache.primary_keys(table_ref) if pk.nil? && table_ref
278284
cols = columns_for_returning_clause(sql, pk, binds, returning)
279285
unless cols.empty?
280-
table_name = extract_table_ref_from_insert_sql(sql)
281286
quoted_cols = cols.map { |c| quote_column_name(c) }.join(", ")
282287
placeholders = cols.map { |c| ":returning_#{c}" }.join(", ")
283288
sql = "#{sql} RETURNING #{quoted_cols} INTO #{placeholders}"
284289
binds = binds.dup
285290
cols.each do |col|
286-
column = table_name ? columns(table_name).find { |c| c.name == col } : nil
291+
column = table_ref ? columns(table_ref).find { |c| c.name == col } : nil
287292
type = column&.cast_type || Type::OracleEnhanced::Integer.new
288293
binds << ActiveRecord::Relation::QueryAttribute.new("returning_#{col}", nil, type)
289294
end

spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ class ::TestReturningIdentityItem < ActiveRecord::Base
165165
expect(insert_log).to match(/RETURNING\s+"ID"\s+INTO\s+:returning_id/i)
166166
expect(insert_log).not_to match(/RETURNING\s+"ID"\s*\)?\s*\z/i)
167167
end
168+
169+
# AbstractAdapter#sql_for_insert infers the primary key from the SQL when
170+
# the caller passes pk: nil. Generic callers that go through this path
171+
# without an explicit `pk` used to miss out on RETURNING auto-fetch on
172+
# Oracle because the fallback was not mirrored locally; this spec locks
173+
# in the parity introduced for issue #2732.
174+
it "infers the primary key from the SQL when pk: nil (parity with AbstractAdapter)" do
175+
conn = ActiveRecord::Base.lease_connection
176+
insert_sql = "INSERT INTO #{conn.quote_table_name('test_returning_identity_items')} (#{conn.quote_column_name('name')}) VALUES ('direct-call')"
177+
out_sql, out_binds = conn.send(:sql_for_insert, insert_sql, nil, [], nil)
178+
expect(out_sql).to match(/RETURNING\s+"ID"\s+INTO\s+:returning_id/i)
179+
expect(out_binds.last.name).to eq("returning_id")
180+
end
168181
end
169182

170183
# Sequence-prefetched path: oracle-enhanced's default for `create_table` (no

0 commit comments

Comments
 (0)