Skip to content

Commit 6f19dae

Browse files
authored
Merge pull request rsim#2719 from yahonda/evict-stale-prepared-statements-on-ddl
Evict stale prepared statements on DDL via clear_table_columns_cache
2 parents 2347382 + 376c7a2 commit 6f19dae

2 files changed

Lines changed: 65 additions & 2 deletions

File tree

lib/active_record/connection_adapters/oracle_enhanced_adapter.rb

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,9 +902,24 @@ def column_definitions(table_name)
902902
end
903903

904904
def clear_table_columns_cache(table_name)
905-
@columns_cache[table_name.to_s] = nil
906-
@trigger_assigned_pk_cache.delete(table_name.to_s)
905+
table_name = table_name.to_s
906+
@columns_cache[table_name] = nil
907+
@trigger_assigned_pk_cache.delete(table_name)
908+
evict_prepared_statements_for(table_name)
909+
end
910+
911+
def evict_prepared_statements_for(table_name) # :nodoc:
912+
return unless prepared_statements?
913+
return unless @statements
914+
915+
quoted_table_name = quote_table_name(table_name)
916+
keys_to_delete = []
917+
@statements.each do |sql, _stmt|
918+
keys_to_delete << sql if sql.include?(quoted_table_name)
919+
end
920+
keys_to_delete.each { |sql| @statements.delete(sql) }
907921
end
922+
private :evict_prepared_statements_for
908923

909924
# Returns +[pk, sequence]+ for single-column PKs; +nil+ for composite or
910925
# missing PKs (composite PKs are introspected via +primary_keys+).

spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,54 @@ class ::TestPost < ActiveRecord::Base
16281628
end
16291629
end
16301630

1631+
describe "prepared statement cache eviction on DDL" do
1632+
before(:each) do
1633+
schema_define do
1634+
create_table :test_evict, force: true do |t|
1635+
t.string :name
1636+
t.integer :extra
1637+
end
1638+
end
1639+
end
1640+
1641+
after(:each) do
1642+
schema_define do
1643+
drop_table :test_evict, if_exists: true
1644+
end
1645+
ActiveRecord::Base.clear_cache!
1646+
end
1647+
1648+
def cached_prepared_sqls_for(table_name)
1649+
pool = @conn.instance_variable_get(:@statements)
1650+
return [] unless pool
1651+
pool.map { |sql, _| sql }.select { |sql| sql.include?(@conn.send(:quote_table_name, table_name)) }
1652+
end
1653+
1654+
it "removes cached prepared statements after a column is dropped" do
1655+
klass = Class.new(ActiveRecord::Base) { self.table_name = :test_evict }
1656+
klass.create!(name: "before-ddl", extra: 1)
1657+
expect(cached_prepared_sqls_for(:test_evict)).not_to be_empty
1658+
1659+
schema_define do
1660+
remove_column :test_evict, :extra
1661+
end
1662+
1663+
expect(cached_prepared_sqls_for(:test_evict)).to be_empty
1664+
end
1665+
1666+
it "removes cached prepared statements after the table is dropped" do
1667+
klass = Class.new(ActiveRecord::Base) { self.table_name = :test_evict }
1668+
klass.create!(name: "before-drop", extra: 1)
1669+
expect(cached_prepared_sqls_for(:test_evict)).not_to be_empty
1670+
1671+
schema_define do
1672+
drop_table :test_evict, if_exists: true
1673+
end
1674+
1675+
expect(cached_prepared_sqls_for(:test_evict)).to be_empty
1676+
end
1677+
end
1678+
16311679
describe "alter columns with column cache" do
16321680
include LoggerSpecHelper
16331681

0 commit comments

Comments
 (0)