diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
14 files changed, 92 insertions, 58 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 9b74c3a10f..dc5b305843 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -849,6 +849,21 @@ module ActiveRecord remove_connection(spec.name) owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec) + + message_bus = ActiveSupport::Notifications.instrumenter + payload = { + connection_id: object_id + } + if spec + payload[:spec_name] = spec.name + payload[:config] = spec.config + end + + message_bus.instrument('!connection.active_record', payload) do + owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec) + end + + owner_to_pool[spec.name] end # Returns true if there are any active connections among the connection @@ -881,7 +896,7 @@ module ActiveRecord # for (not necessarily the current class). def retrieve_connection(spec_name) #:nodoc: pool = retrieve_connection_pool(spec_name) - raise ConnectionNotEstablished, "No connection pool with id '#{spec_name}' found." unless pool + raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool conn = pool.connection raise ConnectionNotEstablished, "No connection for '#{spec_name}' in connection pool" unless conn conn 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 507a925d32..e667e16964 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -10,7 +10,7 @@ module ActiveRecord def to_sql(arel, binds = []) if arel.respond_to?(:ast) collected = visitor.accept(arel.ast, collector) - collected.compile(binds.dup, self) + collected.compile(binds, self) else arel end @@ -18,11 +18,12 @@ module ActiveRecord # This is used in the StatementCache object. It returns an object that # can be used to query the database repeatedly. - def cacheable_query(arel) # :nodoc: + def cacheable_query(klass, arel) # :nodoc: + collected = visitor.accept(arel.ast, collector) if prepared_statements - ActiveRecord::StatementCache.query visitor, arel.ast + klass.query(collected.value) else - ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector + klass.partial_query(collected.value) end end @@ -315,7 +316,7 @@ module ActiveRecord end end key_list = fixture.keys.map { |name| quote_column_name(name) } - value_list = prepare_binds_for_database(binds).map do |value| + value_list = binds.map(&:value_for_database).map do |value| begin quote(value) rescue TypeError diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 860ef17dca..eda6af08e3 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -112,19 +112,19 @@ module ActiveRecord end def quoted_true - "'t'" + "'t'".freeze end def unquoted_true - 't' + 't'.freeze end def quoted_false - "'f'" + "'f'".freeze end def unquoted_false - 'f' + 'f'.freeze end # Quote date/time values for use in SQL input. Includes microseconds @@ -150,12 +150,12 @@ module ActiveRecord quoted_date(value).sub(/\A2000-01-01 /, '') end - def prepare_binds_for_database(binds) # :nodoc: - binds.map(&:value_for_database) - end - private + def type_casted_binds(binds) + binds.map { |attr| type_cast(attr.value_for_database) } + end + def types_which_need_no_typecasting [nil, Numeric, String] 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 cffd7e8e81..19c265db6e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -129,14 +129,9 @@ module ActiveRecord # Returns just a table's primary key def primary_key(table_name) - pks = primary_keys(table_name) - warn <<-WARNING.strip_heredoc if pks.count > 1 - WARNING: Rails does not support composite primary key. - - #{table_name} has composite primary key. Composite primary key is ignored. - WARNING - - pks.first if pks.one? + pk = primary_keys(table_name) + pk = pk.first unless pk.size > 1 + pk end # Creates a new table with the name +table_name+. +table_name+ may either @@ -998,8 +993,8 @@ module ActiveRecord sm_table = ActiveRecord::Migrator.schema_migrations_table_name if supports_multi_insert? - sql = "INSERT INTO #{sm_table} (version) VALUES " - sql << versions.map {|v| "('#{v}')" }.join(', ') + sql = "INSERT INTO #{sm_table} (version) VALUES\n" + sql << versions.map {|v| "('#{v}')" }.join(",\n") sql << ";\n\n" sql else diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 5747e4d1ee..0b8bacff4e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -130,7 +130,7 @@ module ActiveRecord class BindCollector < Arel::Collectors::Bind def compile(bvs, conn) - casted_binds = conn.prepare_binds_for_database(bvs) + casted_binds = bvs.map(&:value_for_database) super(casted_binds.map { |value| conn.quote(value) }) end end @@ -579,14 +579,15 @@ module ActiveRecord exception end - def log(sql, name = "SQL", binds = [], statement_name = nil) + def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) @instrumenter.instrument( "sql.active_record", - :sql => sql, - :name => name, - :connection_id => object_id, - :statement_name => statement_name, - :binds => binds) { yield } + sql: sql, + name: name, + binds: binds, + type_casted_binds: type_casted_binds, + statement_name: statement_name, + connection_id: object_id) { yield } rescue => e raise translate_exception_class(e, sql) 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 3e77b92141..610d78245f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -9,6 +9,7 @@ require 'active_record/connection_adapters/mysql/schema_dumper' require 'active_record/connection_adapters/mysql/type_metadata' require 'active_support/core_ext/string/strip' +require 'active_support/core_ext/regexp' module ActiveRecord module ConnectionAdapters @@ -85,7 +86,7 @@ module ActiveRecord end def mariadb? # :nodoc: - full_version =~ /mariadb/i + /mariadb/i.match?(full_version) end # Returns true, since this connection adapter supports migrations. @@ -409,10 +410,13 @@ module ActiveRecord end def table_comment(table_name) # :nodoc: + schema, name = extract_schema_qualified_name(table_name) + select_value(<<-SQL.strip_heredoc, 'SCHEMA') SELECT table_comment FROM information_schema.tables - WHERE table_name=#{quote(table_name)} + WHERE table_schema = #{quote(schema)} + AND table_name = #{quote(name)} SQL end @@ -543,7 +547,9 @@ module ActiveRecord end end - def table_options(table_name) + def table_options(table_name) # :nodoc: + table_options = {} + create_table_info = create_table_info(table_name) # strip create_definitions and partition_options @@ -552,10 +558,14 @@ module ActiveRecord # strip AUTO_INCREMENT raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1') + table_options[:options] = raw_table_options + # strip COMMENT - raw_table_options.sub!(/ COMMENT='.+'/, '') + if raw_table_options.sub!(/ COMMENT='.+'/, '') + table_options[:comment] = table_comment(table_name) + end - raw_table_options + table_options end # Maps logical Rails types to MySQL-specific data types. 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 87f0ff7d85..6d1215df2a 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb @@ -77,9 +77,9 @@ module ActiveRecord @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone end - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } + type_casted_binds = type_casted_binds(binds) - log(sql, name, binds) do + log(sql, name, binds, type_casted_binds) do if cache_stmt cache = @statements[sql] ||= { stmt: @connection.prepare(sql) diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb index fbab654112..af1db30047 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb @@ -2,14 +2,14 @@ module ActiveRecord module ConnectionAdapters module MySQL module Quoting # :nodoc: - QUOTED_TRUE, QUOTED_FALSE = '1', '0' + QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze def quote_column_name(name) - @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`" + @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze end def quote_table_name(name) - @quoted_table_names[name] ||= super.gsub('.', '`.`') + @quoted_table_names[name] ||= super.gsub('.', '`.`').freeze end def quoted_true diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb index 6f2e03b370..f5232127c4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb @@ -124,6 +124,8 @@ module ActiveRecord pk = primary_key(table_ref) if table_ref end + pk = suppress_composite_primary_key(pk) + if pk && use_insert_returning? sql = "#{sql} RETURNING #{quote_column_name(pk)}" end @@ -164,6 +166,12 @@ module ActiveRecord def exec_rollback_db_transaction execute "ROLLBACK" end + + private + + def suppress_composite_primary_key(pk) + pk unless pk.is_a?(Array) + end 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 6414459cd1..9fcf8dbb95 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -28,7 +28,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 + @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze end # Quotes schema names for use in SQL queries. @@ -42,7 +42,7 @@ module ActiveRecord # Quotes column names for use in SQL queries. def quote_column_name(name) # :nodoc: - @quoted_column_names[name] ||= PGconn.quote_ident(super) + @quoted_column_names[name] ||= PGconn.quote_ident(super).freeze end # Quote date/time values for use in SQL input. @@ -58,7 +58,7 @@ module ActiveRecord def quote_default_expression(value, column) # :nodoc: if value.is_a?(Proc) value.call - elsif column.type == :uuid && value =~ /\(\)/ + elsif column.type == :uuid && value.include?('()') value # Does not quote function default values for UUID columns elsif column.respond_to?(:array?) value = type_cast_from_column(column, 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 45507e206a..4cf6d4b14a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -238,6 +238,10 @@ module ActiveRecord PostgreSQLColumn.new(*args) end + def table_options(table_name) # :nodoc: + { comment: table_comment(table_name) } + end + # Returns a comment stored in database for given table def table_comment(table_name) # :nodoc: name = Utils.extract_schema_qualified_name(table_name.to_s) @@ -327,12 +331,12 @@ module ActiveRecord end # Returns the sequence name for a table's primary key or some other specified key. - def default_sequence_name(table_name, pk = nil) #:nodoc: - result = serial_sequence(table_name, pk || 'id') + def default_sequence_name(table_name, pk = 'id') #:nodoc: + result = serial_sequence(table_name, pk) return nil unless result Utils.extract_schema_qualified_name(result).to_s rescue ActiveRecord::StatementInvalid - PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s + PostgreSQL::Name.new(nil, "#{table_name}_#{pk}_seq").to_s end def serial_sequence(table, column) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index ddfc560747..61a980fda9 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -597,15 +597,15 @@ module ActiveRecord end def exec_no_cache(sql, name, binds) - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } - log(sql, name, binds) { @connection.async_exec(sql, type_casted_binds) } + type_casted_binds = type_casted_binds(binds) + log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) } end def exec_cache(sql, name, binds) stmt_key = prepare_statement(sql) - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } + type_casted_binds = type_casted_binds(binds) - log(sql, name, binds, stmt_key) do + log(sql, name, binds, type_casted_binds, stmt_key) do @connection.exec_prepared(stmt_key, type_casted_binds) end rescue ActiveRecord::StatementInvalid => e diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb index d5a181d3e2..fa20175b0e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb @@ -11,7 +11,7 @@ module ActiveRecord end def quote_column_name(name) - @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}") + @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}").freeze 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 eb2268157b..41ed784d2e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -159,7 +159,7 @@ module ActiveRecord end # Returns 62. SQLite supports index names up to 64 - # characters. The rest is used by rails internally to perform + # characters. The rest is used by Rails internally to perform # temporary rename operations def allowed_index_name_length index_name_length - 2 @@ -188,9 +188,9 @@ module ActiveRecord end def exec_query(sql, name = nil, binds = [], prepare: false) - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } + type_casted_binds = type_casted_binds(binds) - log(sql, name, binds) do + log(sql, name, binds, type_casted_binds) do # Don't cache statements if they are not prepared unless prepare stmt = @connection.prepare(sql) @@ -203,7 +203,6 @@ module ActiveRecord ensure stmt.close end - stmt = records else cache = @statements[sql] ||= { :stmt => @connection.prepare(sql) @@ -212,9 +211,10 @@ module ActiveRecord cols = cache[:cols] ||= stmt.columns stmt.reset! stmt.bind_params(type_casted_binds) + records = stmt.to_a end - ActiveRecord::Result.new(cols, stmt.to_a) + ActiveRecord::Result.new(cols, records) end end @@ -548,7 +548,7 @@ module ActiveRecord columns_string.split(',').each do |column_string| # This regex will match the column name and collation type and will save # the value in $1 and $2 respectively. - collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string) + collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string end basic_structure.map! do |column| |