diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2017-06-30 06:36:33 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2017-06-30 14:47:27 +0900 |
commit | 21d040f97d539fb292bd79453692dc02b19c23f0 (patch) | |
tree | 0ee689509ec3413683db614148f23f7fc06b3533 /activerecord | |
parent | b9120d1f8cdfe8c6c88559a8029ba60452c9e5ca (diff) | |
download | rails-21d040f97d539fb292bd79453692dc02b19c23f0.tar.gz rails-21d040f97d539fb292bd79453692dc02b19c23f0.tar.bz2 rails-21d040f97d539fb292bd79453692dc02b19c23f0.zip |
Don't cache queries for schema statements
`test_middleware_caches` is sometimes failed since #29454.
The failure is due to schema statements are affected by query caching.
Bypassing query caching for schema statements to avoid the issue.
Diffstat (limited to 'activerecord')
10 files changed, 70 insertions, 55 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 af5314c1d6..879626b72a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -51,9 +51,7 @@ module ActiveRecord # Returns a single value from a record def select_value(arel, name = nil, binds = []) - if result = select_rows(arel, name, binds).first - result.first - end + single_value_from_rows(select_rows(arel, name, binds)) end # Returns an array of the values of the first column in a select: @@ -68,6 +66,18 @@ module ActiveRecord select_all(arel, name, binds).rows end + def query_value(sql, name = nil) # :nodoc: + single_value_from_rows(query(sql, name)) + end + + def query_values(sql, name = nil) # :nodoc: + query(sql, name).map(&:first) + end + + def query(sql, name = nil) # :nodoc: + exec_query(sql, name).rows + end + # Executes the SQL statement in the context of this connection and returns # the raw result from the connection adapter. # Note: depending on your database connector, the result returned by this @@ -410,7 +420,11 @@ module ActiveRecord end def last_inserted_id(result) - row = result.rows.first + single_value_from_rows(result.rows) + end + + def single_value_from_rows(rows) + row = rows.first row && row.first end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 22d7791dec..41d900733a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -31,7 +31,7 @@ module ActiveRecord # Returns the relation names useable to back Active Record models. # For most adapters this means all #tables and #views. def data_sources - select_values(data_source_sql, "SCHEMA") + query_values(data_source_sql, "SCHEMA") rescue NotImplementedError tables | views end @@ -41,14 +41,14 @@ module ActiveRecord # data_source_exists?(:ebooks) # def data_source_exists?(name) - select_values(data_source_sql(name), "SCHEMA").any? if name.present? + query_values(data_source_sql(name), "SCHEMA").any? if name.present? rescue NotImplementedError data_sources.include?(name.to_s) end # Returns an array of table names defined in the database. def tables - select_values(data_source_sql(type: "BASE TABLE"), "SCHEMA") + query_values(data_source_sql(type: "BASE TABLE"), "SCHEMA") end # Checks to see if the table +table_name+ exists on the database. @@ -56,14 +56,14 @@ module ActiveRecord # table_exists?(:developers) # def table_exists?(table_name) - select_values(data_source_sql(table_name, type: "BASE TABLE"), "SCHEMA").any? if table_name.present? + query_values(data_source_sql(table_name, type: "BASE TABLE"), "SCHEMA").any? if table_name.present? rescue NotImplementedError tables.include?(table_name.to_s) end # Returns an array of view names defined in the database. def views - select_values(data_source_sql(type: "VIEW"), "SCHEMA") + query_values(data_source_sql(type: "VIEW"), "SCHEMA") end # Checks to see if the view +view_name+ exists on the database. @@ -71,7 +71,7 @@ module ActiveRecord # view_exists?(:ebooks) # def view_exists?(view_name) - select_values(data_source_sql(view_name, type: "VIEW"), "SCHEMA").any? if view_name.present? + query_values(data_source_sql(view_name, type: "VIEW"), "SCHEMA").any? if view_name.present? rescue NotImplementedError views.include?(view_name.to_s) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 183f0f3c1b..6a907699e9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -120,11 +120,11 @@ module ActiveRecord end def get_advisory_lock(lock_name, timeout = 0) # :nodoc: - select_value("SELECT GET_LOCK(#{quote(lock_name)}, #{timeout})") == 1 + query_value("SELECT GET_LOCK(#{quote(lock_name)}, #{timeout})") == 1 end def release_advisory_lock(lock_name) # :nodoc: - select_value("SELECT RELEASE_LOCK(#{quote(lock_name)})") == 1 + query_value("SELECT RELEASE_LOCK(#{quote(lock_name)})") == 1 end def native_database_types @@ -152,7 +152,7 @@ module ActiveRecord # REFERENTIAL INTEGRITY ==================================== def disable_referential_integrity #:nodoc: - old = select_value("SELECT @@FOREIGN_KEY_CHECKS") + old = query_value("SELECT @@FOREIGN_KEY_CHECKS") begin update("SET FOREIGN_KEY_CHECKS = 0") @@ -267,7 +267,7 @@ module ActiveRecord end def current_database - select_value "SELECT DATABASE() as db" + query_value("SELECT database()", "SCHEMA") end # Returns the database character set. @@ -287,7 +287,7 @@ module ActiveRecord def table_comment(table_name) # :nodoc: scope = quoted_scope(table_name) - select_value(<<-SQL.strip_heredoc, "SCHEMA") + query_value(<<-SQL.strip_heredoc, "SCHEMA") SELECT table_comment FROM information_schema.tables WHERE table_schema = #{scope[:schema]} @@ -393,7 +393,7 @@ module ActiveRecord scope = quoted_scope(table_name) - fk_info = select_all(<<-SQL.strip_heredoc, "SCHEMA") + fk_info = exec_query(<<-SQL.strip_heredoc, "SCHEMA") SELECT fk.referenced_table_name AS 'to_table', fk.referenced_column_name AS 'primary_key', fk.column_name AS 'column', @@ -470,7 +470,7 @@ module ActiveRecord # SHOW VARIABLES LIKE 'name' def show_variable(name) - select_value("SELECT @@#{name}", "SCHEMA") + query_value("SELECT @@#{name}", "SCHEMA") rescue ActiveRecord::StatementInvalid nil end @@ -480,7 +480,7 @@ module ActiveRecord scope = quoted_scope(table_name) - select_values(<<-SQL.strip_heredoc, "SCHEMA") + query_values(<<-SQL.strip_heredoc, "SCHEMA") SELECT column_name FROM information_schema.key_column_usage WHERE constraint_name = 'PRIMARY' @@ -694,7 +694,7 @@ module ActiveRecord auto_increment: column.auto_increment? } - current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA")["Type"] + current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"] td = create_table_definition(table_name) cd = td.new_column_definition(new_column_name, current_type, options) schema_creation.accept(ChangeColumnDefinition.new(cd, column.name)) @@ -804,7 +804,7 @@ module ActiveRecord end def create_table_info(table_name) # :nodoc: - select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"] + exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"] end def arel_visitor diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb index 9f1021456b..bda482a00f 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb @@ -13,6 +13,10 @@ module ActiveRecord result end + def query(sql, name = nil) # :nodoc: + execute(sql, name).to_a + end + # Executes the SQL statement in the context of this connection. def execute(sql, name = nil) # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb index f21b2546de..eff96e329f 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb @@ -47,7 +47,7 @@ module ActiveRecord def schema_collation(column) if column.collation && table_name = column.table_name @table_collation_cache ||= {} - @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE #{quote(table_name)}")["Collation"] + @table_collation_cache[table_name] ||= exec_query("SHOW TABLE STATUS LIKE #{quote(table_name)}", "SCHEMA").first["Collation"] column.collation.inspect if column.collation != @table_collation_cache[table_name] end end @@ -64,7 +64,7 @@ module ActiveRecord " WHERE table_schema = #{scope[:schema]}" \ " AND table_name = #{scope[:name]}" \ " AND column_name = #{quote(column.name)}" - select_value(sql, "SCHEMA").inspect + query_value(sql, "SCHEMA").inspect end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 44eb666965..ee4230c6f2 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -78,7 +78,7 @@ module ActiveRecord private def lookup_cast_type(sql_type) - super(select_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i) + super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i) end def _quote(value) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 7aa034f901..8a999a8429 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -60,7 +60,7 @@ module ActiveRecord # Returns true if schema exists. def schema_exists?(name) - select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = #{quote(name)}", "SCHEMA").to_i > 0 + query_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = #{quote(name)}", "SCHEMA").to_i > 0 end # Verifies existence of an index with a given name. @@ -73,7 +73,7 @@ module ActiveRecord table = quoted_scope(table_name) index = quoted_scope(index_name) - select_value(<<-SQL, "SCHEMA").to_i > 0 + query_value(<<-SQL, "SCHEMA").to_i > 0 SELECT COUNT(*) FROM pg_class t INNER JOIN pg_index d ON t.oid = d.indrelid @@ -163,7 +163,7 @@ module ActiveRecord def table_comment(table_name) # :nodoc: scope = quoted_scope(table_name, type: "BASE TABLE") if scope[:name] - select_value(<<-SQL.strip_heredoc, "SCHEMA") + query_value(<<-SQL.strip_heredoc, "SCHEMA") SELECT pg_catalog.obj_description(c.oid, 'pg_class') FROM pg_catalog.pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace @@ -176,32 +176,32 @@ module ActiveRecord # Returns the current database name. def current_database - select_value("SELECT current_database()", "SCHEMA") + query_value("SELECT current_database()", "SCHEMA") end # Returns the current schema name. def current_schema - select_value("SELECT current_schema", "SCHEMA") + query_value("SELECT current_schema", "SCHEMA") end # Returns the current database encoding format. def encoding - select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = current_database()", "SCHEMA") + query_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = current_database()", "SCHEMA") end # Returns the current database collation. def collation - select_value("SELECT datcollate FROM pg_database WHERE datname = current_database()", "SCHEMA") + query_value("SELECT datcollate FROM pg_database WHERE datname = current_database()", "SCHEMA") end # Returns the current database ctype. def ctype - select_value("SELECT datctype FROM pg_database WHERE datname = current_database()", "SCHEMA") + query_value("SELECT datctype FROM pg_database WHERE datname = current_database()", "SCHEMA") end # Returns an array of schema names. def schema_names - select_values(<<-SQL, "SCHEMA") + query_values(<<-SQL, "SCHEMA") SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' @@ -234,12 +234,12 @@ module ActiveRecord # Returns the active schema search path. def schema_search_path - @schema_search_path ||= select_value("SHOW search_path", "SCHEMA") + @schema_search_path ||= query_value("SHOW search_path", "SCHEMA") end # Returns the current client message level. def client_min_messages - select_value("SHOW client_min_messages", "SCHEMA") + query_value("SHOW client_min_messages", "SCHEMA") end # Set the client message level. @@ -257,7 +257,7 @@ module ActiveRecord end def serial_sequence(table, column) - select_value("SELECT pg_get_serial_sequence(#{quote(table)}, #{quote(column)})", "SCHEMA") + query_value("SELECT pg_get_serial_sequence(#{quote(table)}, #{quote(column)})", "SCHEMA") end # Sets the sequence of a table's primary key to the specified value. @@ -268,7 +268,7 @@ module ActiveRecord if sequence quoted_sequence = quote_table_name(sequence) - select_value("SELECT setval(#{quote(quoted_sequence)}, #{value})", "SCHEMA") + query_value("SELECT setval(#{quote(quoted_sequence)}, #{value})", "SCHEMA") else @logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger end @@ -290,18 +290,16 @@ module ActiveRecord if pk && sequence quoted_sequence = quote_table_name(sequence) - max_pk = select_value("select MAX(#{quote_column_name pk}) from #{quote_table_name(table)}") + max_pk = query_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}", "SCHEMA") if max_pk.nil? if postgresql_version >= 100000 - minvalue = select_value("SELECT seqmin from pg_sequence where seqrelid = #{quote(quoted_sequence)}::regclass") + minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA") else - minvalue = select_value("SELECT min_value FROM #{quoted_sequence}") + minvalue = query_value("SELECT min_value FROM #{quoted_sequence}", "SCHEMA") end end - select_value(<<-end_sql, "SCHEMA") - SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false}) - end_sql + query_value("SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})", "SCHEMA") end end @@ -360,7 +358,7 @@ module ActiveRecord end def primary_keys(table_name) # :nodoc: - select_values(<<-SQL.strip_heredoc, "SCHEMA") + query_values(<<-SQL.strip_heredoc, "SCHEMA") SELECT a.attname FROM ( SELECT indrelid, indkey, generate_subscripts(indkey, 1) idx @@ -511,7 +509,7 @@ module ActiveRecord def foreign_keys(table_name) scope = quoted_scope(table_name) - fk_info = select_all(<<-SQL.strip_heredoc, "SCHEMA") + fk_info = exec_query(<<-SQL.strip_heredoc, "SCHEMA") SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete FROM pg_constraint c JOIN pg_class t1 ON c.conrelid = t1.oid diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 99edbe486f..e63563afc4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -312,14 +312,14 @@ module ActiveRecord unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63 raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer") end - select_value("SELECT pg_try_advisory_lock(#{lock_id});") + query_value("SELECT pg_try_advisory_lock(#{lock_id})") end def release_advisory_lock(lock_id) # :nodoc: unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63 raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer") end - select_value("SELECT pg_advisory_unlock(#{lock_id})") + query_value("SELECT pg_advisory_unlock(#{lock_id})") end def enable_extension(name) @@ -336,15 +336,14 @@ module ActiveRecord def extension_enabled?(name) if supports_extensions? - res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled", - "SCHEMA" + res = exec_query("SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled", "SCHEMA") res.cast_values.first end end def extensions if supports_extensions? - exec_query("SELECT extname from pg_extension", "SCHEMA").cast_values + exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values else super end @@ -352,14 +351,14 @@ module ActiveRecord # Returns the configured supported identifier length supported by PostgreSQL def table_alias_length - @max_identifier_length ||= select_value("SHOW max_identifier_length", "SCHEMA").to_i + @max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i end alias index_name_length table_alias_length # Set the authorized user for this session def session_auth=(user) clear_cache! - exec_query "SET SESSION AUTHORIZATION #{user}" + execute("SET SESSION AUTHORIZATION #{user}") end def use_insert_returning? diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb index e02491edb6..00ff804e80 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb @@ -11,7 +11,7 @@ module ActiveRecord end exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row| - index_sql = select_value(<<-SQL, "SCHEMA") + index_sql = query_value(<<-SQL, "SCHEMA") SELECT sql FROM sqlite_master WHERE name = #{quote(row['name'])} AND type = 'index' diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index ee2faf43b5..17c63d4b5f 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -169,7 +169,7 @@ module ActiveRecord # REFERENTIAL INTEGRITY ==================================== def disable_referential_integrity # :nodoc: - old = select_value("PRAGMA foreign_keys") + old = query_value("PRAGMA foreign_keys") begin execute("PRAGMA foreign_keys = OFF") @@ -337,7 +337,7 @@ module ActiveRecord alias :add_belongs_to :add_reference def foreign_keys(table_name) - fk_info = select_all("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA") + fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA") fk_info.map do |row| options = { column: row["from"], @@ -443,7 +443,7 @@ module ActiveRecord end def sqlite_version - @sqlite_version ||= SQLite3Adapter::Version.new(select_value("SELECT sqlite_version(*)")) + @sqlite_version ||= SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)")) end def translate_exception(exception, message) |