diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb | 35 | ||||
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb | 90 |
2 files changed, 117 insertions, 8 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index effb36faf1..4303d66451 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -10,14 +10,15 @@ module ActiveRecord # Returns a record hash with the column names as keys and column values # as values. def select_one(sql, name = nil) - result = select(sql, name) + result = select_all(sql, name) result.first if result end # Returns a single value from a record def select_value(sql, name = nil) - result = select_one(sql, name) - result.nil? ? nil : result.values.first + if result = select_one(sql, name) + result.values.first + end end # Returns an array of the values of the first column in a select: @@ -29,7 +30,9 @@ module ActiveRecord # Returns an array of arrays containing the field values. # Order is the same as that returned by #columns. - def select_rows(sql, name = nil) end + def select_rows(sql, name = nil) + raise NotImplementedError, "select_rows is an abstract method" + end # Executes the SQL statement in the context of this connection. def execute(sql, name = nil) @@ -38,17 +41,17 @@ module ActiveRecord # Returns the last auto-generated ID from the affected table. def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) - raise NotImplementedError, "insert is an abstract method" + insert_sql(sql, name, pk, id_value, sequence_name) end # Executes the update statement and returns the number of rows affected. def update(sql, name = nil) - execute(sql, name) + update_sql(sql, name) end # Executes the delete statement and returns the number of rows affected. def delete(sql, name = nil) - update(sql, name) + delete_sql(sql, name) end # Wrap a block in a transaction. Returns result of block. @@ -133,7 +136,7 @@ module ActiveRecord # Inserts the given fixture into the table. Overriden in adapters that require # something beyond a simple insert (eg. Oracle). def insert_fixture(fixture, table_name) - execute "INSERT INTO #{table_name} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert' + insert "INSERT INTO #{table_name} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert' end protected @@ -142,6 +145,22 @@ module ActiveRecord def select(sql, name = nil) raise NotImplementedError, "select is an abstract method" end + + # Returns the last auto-generated ID from the affected table. + def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) + execute(sql, name) + id_value + end + + # Executes the update statement and returns the number of rows affected. + def update_sql(sql, name = nil) + execute(sql, name) + end + + # Executes the delete statement and returns the number of rows affected. + def delete_sql(sql, name = nil) + update_sql(sql, name) + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb new file mode 100644 index 0000000000..42ff1d7d54 --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -0,0 +1,90 @@ +module ActiveRecord + module ConnectionAdapters # :nodoc: + module QueryCache + class << self + def included(base) + base.class_eval do + attr_accessor :query_cache_enabled + alias_method_chain :columns, :query_cache + alias_method_chain :select_all, :query_cache + end + + dirties_query_cache base, :insert, :update, :delete + end + + def dirties_query_cache(base, *method_names) + method_names.each do |method_name| + base.class_eval <<-end_code, __FILE__, __LINE__ + def #{method_name}_with_query_dirty(*args) + clear_query_cache if @query_cache_enabled + #{method_name}_without_query_dirty(*args) + end + + alias_method_chain :#{method_name}, :query_dirty + end_code + end + end + end + + # Enable the query cache within the block. + def cache + old, @query_cache_enabled = @query_cache_enabled, true + @query_cache ||= {} + yield + ensure + clear_query_cache + @query_cache_enabled = old + end + + # Disable the query cache within the block. + def uncached + old, @query_cache_enabled = @query_cache_enabled, false + yield + ensure + @query_cache_enabled = old + end + + def clear_query_cache + @query_cache.clear if @query_cache + end + + def select_all_with_query_cache(*args) + if @query_cache_enabled + cache_sql(args.first) { select_all_without_query_cache(*args) } + else + select_all_without_query_cache(*args) + end + end + + def columns_with_query_cache(*args) + if @query_cache_enabled + @query_cache["SHOW FIELDS FROM #{args.first}"] ||= columns_without_query_cache(*args) + else + columns_without_query_cache(*args) + end + end + + private + def cache_sql(sql) + result = + if @query_cache.has_key?(sql) + log_info(sql, "CACHE", 0.0) + @query_cache[sql] + else + @query_cache[sql] = yield + end + + case result + when Array + result.collect { |row| row.dup } + when nil, Fixnum, Float, true, false + result + else + result.dup + end + rescue TypeError + result + end + end + end +end |