diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 8ecb3cefde302210090de17107c534315774e1b2..73e3afe1d57b32e68c8d72d673eec8d9f9c9d6ac 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -120,7 +120,8 @@ def clear def initialize(connection, logger, connection_options, config) super - @statements = StatementPool.new(@connection) + @statements = StatementPool.new(@connection, + config.fetch(:statement_limit) { 1000 }) @client_encoding = nil connect end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index ba4a6c7a781fea5267f33b909401b1a24a85c1cd..a09bf9c73f5faa2abc1a0cf86db4d1abfafd220f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -1,5 +1,6 @@ require 'active_record/connection_adapters/abstract_adapter' require 'active_support/core_ext/object/blank' +require 'active_record/connection_adapters/statement_pool' # Make sure we're using pg high enough for PGResult#values gem 'pg', '~> 0.11' @@ -246,6 +247,43 @@ def supports_statement_cache? true end + class StatementPool < ConnectionAdapters::StatementPool + def initialize(connection, max) + super + @counter = 0 + @cache = {} + end + + def each(&block); @cache.each(&block); end + def key?(key); @cache.key?(key); end + def [](key); @cache[key]; end + def length; @cache.length; end + + def next_key + "a#{@counter + 1}" + end + + def []=(sql, key) + while @max <= @cache.size + dealloc(@cache.shift.last) + end + @counter += 1 + @cache[sql] = key + end + + def clear + @cache.each_value do |stmt_key| + dealloc stmt_key + end + @cache.clear + end + + private + def dealloc(key) + @connection.query "DEALLOCATE #{key}" + end + end + # Initializes and connects a PostgreSQL adapter. def initialize(connection, logger, connection_parameters, config) super(connection, logger) @@ -254,9 +292,10 @@ def initialize(connection, logger, connection_parameters, config) # @local_tz is initialized as nil to avoid warnings when connect tries to use it @local_tz = nil @table_alias_length = nil - @statements = {} connect + @statements = StatementPool.new @connection, + config.fetch(:statement_limit) { 1000 } if postgresql_version < 80200 raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!" @@ -271,9 +310,6 @@ def self.visitor_for(pool) # :nodoc: # Clears the prepared statements cache. def clear_cache! - @statements.each_value do |value| - @connection.query "DEALLOCATE #{value}" - end @statements.clear end @@ -996,7 +1032,7 @@ def exec_no_cache(sql, binds) def exec_cache(sql, binds) unless @statements.key? sql - nextkey = "a#{@statements.length + 1}" + nextkey = @statements.next_key @connection.prepare nextkey, sql @statements[sql] = nextkey end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index a4e21b714bf6ffe90c47ebba34c90411bbaceea3..7c7e762c1994ff5cd23f82acff532c9fe51b5737 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -50,7 +50,7 @@ def <=>(version_string) end class StatementPool < ConnectionAdapters::StatementPool - def initialize(connection, max = 1000) + def initialize(connection, max) super @cache = {} end @@ -82,7 +82,8 @@ def dealloc(stmt) def initialize(connection, logger, config) super(connection, logger) - @statements = StatementPool.new(@connection) + @statements = StatementPool.new(@connection, + config.fetch(:statement_limit) { 1000 }) @config = config end