diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
16 files changed, 90 insertions, 28 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 9b3f5260f7..36001efdd5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -426,7 +426,7 @@ module ActiveRecord # #connection can be called any number of times; the connection is # held in a cache keyed by a thread. def connection - @thread_cached_conns[connection_cache_key(@lock_thread || Thread.current)] ||= checkout + @thread_cached_conns[connection_cache_key(current_thread)] ||= checkout end # Returns true if there is an open connection being used for the current thread. @@ -435,7 +435,7 @@ module ActiveRecord # #connection or #with_connection methods. Connections obtained through # #checkout will not be detected by #active_connection? def active_connection? - @thread_cached_conns[connection_cache_key(Thread.current)] + @thread_cached_conns[connection_cache_key(current_thread)] end # Signal that the thread is finished with the current connection. @@ -730,6 +730,10 @@ module ActiveRecord thread end + def current_thread + @lock_thread || Thread.current + end + # Take control of all existing connections so a "group" action such as # reload/disconnect can be performed safely. It is no longer enough to # wrap it in +synchronize+ because some pool's actions are allowed diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb index 75e959045e..d932f068f2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "active_support/deprecation" - module ActiveRecord module ConnectionAdapters # :nodoc: module DatabaseLimits diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 6fec4dbd81..768122b4d2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -33,17 +33,17 @@ module ActiveRecord end def enable_query_cache! - @query_cache_enabled[connection_cache_key(Thread.current)] = true + @query_cache_enabled[connection_cache_key(current_thread)] = true connection.enable_query_cache! if active_connection? end def disable_query_cache! - @query_cache_enabled.delete connection_cache_key(Thread.current) + @query_cache_enabled.delete connection_cache_key(current_thread) connection.disable_query_cache! if active_connection? end def query_cache_enabled - @query_cache_enabled[connection_cache_key(Thread.current)] + @query_cache_enabled[connection_cache_key(current_thread)] end 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 79dc98607a..13f94a4722 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -2,7 +2,6 @@ require "active_record/migration/join_table" require "active_support/core_ext/string/access" -require "active_support/deprecation" require "digest/sha2" module ActiveRecord diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index c0ead17b3b..dc970c384b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -6,7 +6,6 @@ require "active_record/connection_adapters/sql_type_metadata" require "active_record/connection_adapters/abstract/schema_dumper" require "active_record/connection_adapters/abstract/schema_creation" require "active_support/concurrency/load_interlock_aware_monitor" -require "active_support/deprecation" require "arel/collectors/bind" require "arel/collectors/composite" require "arel/collectors/sql_string" @@ -106,6 +105,14 @@ module ActiveRecord Regexp.union(*parts) end + def self.quoted_column_names # :nodoc: + @quoted_column_names ||= {} + end + + def self.quoted_table_names # :nodoc: + @quoted_table_names ||= {} + end + def initialize(connection, logger = nil, config = {}) # :nodoc: super() @@ -116,7 +123,6 @@ module ActiveRecord @config = config @pool = ActiveRecord::ConnectionAdapters::NullPool.new @idle_since = Concurrent.monotonic_time - @quoted_column_names, @quoted_table_names = {}, {} @visitor = arel_visitor @statements = build_statement_pool @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new @@ -264,6 +270,11 @@ module ActiveRecord self.class::ADAPTER_NAME end + # Does the database for this adapter exist? + def self.database_exists?(config) + raise NotImplementedError + end + # Does this adapter support DDL rollbacks in transactions? That is, would # CREATE TABLE or ALTER TABLE get rolled back by a transaction? def supports_ddl_transactions? 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 70292e6d63..405fecb603 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -619,7 +619,11 @@ module ActiveRecord when ER_QUERY_INTERRUPTED QueryCanceled.new(message, sql: sql, binds: binds) else - super + if exception.is_a?(Mysql2::Error::TimeoutError) + ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds) + else + super + end end end @@ -737,7 +741,7 @@ module ActiveRecord end.compact.join(", ") # ...and send them all in one query - execute "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}" + execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA") end def column_definitions(table_name) # :nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb index dfed5471f4..0069f5871c 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb @@ -5,11 +5,11 @@ module ActiveRecord module MySQL module Quoting # :nodoc: def quote_column_name(name) - @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`" + self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`" end def quote_table_name(name) - @quoted_table_names[name] ||= super.gsub(".", "`.`").freeze + self.class.quoted_table_names[name] ||= super.gsub(".", "`.`").freeze end def unquoted_true 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 234fb25fdf..bcd300f3db 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb @@ -41,13 +41,15 @@ module ActiveRecord case column.sql_type when /\Atimestamp\b/ :timestamp + when /\A(?:enum|set)\b/ + column.sql_type else super end end def schema_limit(column) - super unless /\A(?:tiny|medium|long)?(?:text|blob)/.match?(column.sql_type) + super unless /\A(?:enum|set|(?:tiny|medium|long)?(?:text|blob))\b/.match?(column.sql_type) end def schema_precision(column) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 53510c62c2..1df9ac32c9 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -8,6 +8,8 @@ require "mysql2" module ActiveRecord module ConnectionHandling # :nodoc: + ER_BAD_DB_ERROR = 1049 + # Establishes a connection to the database that's used by all Active Record objects. def mysql2_connection(config) config = config.symbolize_keys @@ -22,7 +24,7 @@ module ActiveRecord client = Mysql2::Client.new(config) ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config) rescue Mysql2::Error => error - if error.message.include?("Unknown database") + if error.error_number == ER_BAD_DB_ERROR raise ActiveRecord::NoDatabaseError else raise @@ -42,6 +44,12 @@ module ActiveRecord configure_connection end + def self.database_exists?(config) + !!ActiveRecord::Base.mysql2_connection(config) + rescue ActiveRecord::NoDatabaseError + false + end + def supports_json? !mariadb? && database_version >= "5.7.8" end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb index b4ea6c42d3..f1ecf6df30 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb @@ -24,6 +24,16 @@ module ActiveRecord super.sub(/\[\]\z/, "") end + def init_with(coder) + @serial = coder["serial"] + super + end + + def encode_with(coder) + coder["serial"] = @serial + super + end + def ==(other) other.is_a?(Column) && super && diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb index 6434377b57..357493dfc0 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb @@ -26,9 +26,9 @@ module ActiveRecord value = value.sub(/^\((.+)\)$/, '-\1') # (4) case value - when /^-?\D+[\d,]+\.\d{2}$/ # (1) + when /^-?\D*[\d,]+\.\d{2}$/ # (1) value.gsub!(/[^-\d.]/, "") - when /^-?\D+[\d.]+,\d{2}$/ # (2) + when /^-?\D*[\d.]+,\d{2}$/ # (2) value.gsub!(/[^-\d,]/, "").sub!(/,/, ".") end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 0c800dca83..07b66de366 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -30,7 +30,7 @@ module ActiveRecord # - "schema.name".table_name # - "schema.name"."table.name" def quote_table_name(name) # :nodoc: - @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze + self.class.quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze end # Quotes schema names for use in SQL queries. @@ -44,7 +44,7 @@ module ActiveRecord # Quotes column names for use in SQL queries. def quote_column_name(name) # :nodoc: - @quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze + self.class.quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze end # Quote date/time values for use in SQL input. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 6b18a12bce..0a7c6d8ac4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -46,7 +46,7 @@ module ActiveRecord conn = PG.connect(conn_params) ConnectionAdapters::PostgreSQLAdapter.new(conn, logger, conn_params, config) rescue ::PG::Error => error - if error.message.include?("does not exist") + if error.message.include?(conn_params[:dbname]) raise ActiveRecord::NoDatabaseError else raise @@ -259,6 +259,12 @@ module ActiveRecord @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true end + def self.database_exists?(config) + !!ActiveRecord::Base.postgresql_connection(config) + rescue ActiveRecord::NoDatabaseError + false + end + # Is this connection alive and ready for queries? def active? @lock.synchronize do diff --git a/activerecord/lib/active_record/connection_adapters/schema_cache.rb b/activerecord/lib/active_record/connection_adapters/schema_cache.rb index 7d54fcf9a0..5e30304864 100644 --- a/activerecord/lib/active_record/connection_adapters/schema_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/schema_cache.rb @@ -46,7 +46,11 @@ module ActiveRecord end def primary_keys(table_name) - @primary_keys[table_name] ||= data_source_exists?(table_name) ? connection.primary_key(table_name) : nil + @primary_keys.fetch(table_name) do + if data_source_exists?(table_name) + @primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name)) + end + end end # A cached lookup for table existence. @@ -54,7 +58,7 @@ module ActiveRecord prepare_data_sources if @data_sources.empty? return @data_sources[name] if @data_sources.key? name - @data_sources[name] = connection.data_source_exists?(name) + @data_sources[deep_deduplicate(name)] = connection.data_source_exists?(name) end # Add internal cache for table with +table_name+. @@ -73,13 +77,17 @@ module ActiveRecord # Get the columns for a table def columns(table_name) - @columns[table_name] ||= connection.columns(table_name) + @columns.fetch(table_name) do + @columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name)) + end end # Get the columns for a table as a hash, key is the column name # value is the column object. def columns_hash(table_name) - @columns_hash[table_name] ||= columns(table_name).index_by(&:name) + @columns_hash.fetch(table_name) do + @columns_hash[deep_deduplicate(table_name)] = columns(table_name).index_by(&:name) + end end # Checks whether the columns hash is already cached for a table. @@ -88,7 +96,9 @@ module ActiveRecord end def indexes(table_name) - @indexes[table_name] ||= connection.indexes(table_name) + @indexes.fetch(table_name) do + @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name)) + end end def database_version # :nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb index 58787cf9db..9b74a774e5 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb @@ -13,11 +13,11 @@ module ActiveRecord end def quote_table_name(name) - @quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze + self.class.quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze end def quote_column_name(name) - @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}") + self.class.quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}") end def quoted_time(value) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index da971fdba7..f4847eb6c0 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -98,6 +98,16 @@ module ActiveRecord configure_connection end + def self.database_exists?(config) + config = config.symbolize_keys + if config[:database] == ":memory:" + return true + else + database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database] + File.exist?(database_file) + end + end + def supports_ddl_transactions? true end |