diff options
Diffstat (limited to 'activerecord/lib/active_record')
43 files changed, 156 insertions, 157 deletions
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 268b022ab8..ca1f9f1650 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -130,8 +130,8 @@ module ActiveRecord def extensions extensions = klass.default_extensions | reflection.extensions - if scope = reflection.scope - extensions |= klass.unscoped.instance_exec(owner, &scope).extensions + if reflection.scope + extensions |= reflection.scope_for(klass.unscoped, owner).extensions end extensions diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 3d79e540b8..0e849c06ef 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -27,7 +27,7 @@ module ActiveRecord chain_head, chain_tail = get_chain(reflection, association, alias_tracker) scope.extending! reflection.extensions - add_constraints(scope, owner, reflection, chain_head, chain_tail) + add_constraints(scope, owner, chain_head, chain_tail) end def join_type @@ -126,7 +126,7 @@ module ActiveRecord [runtime_reflection, previous_reflection] end - def add_constraints(scope, owner, refl, chain_head, chain_tail) + def add_constraints(scope, owner, chain_head, chain_tail) owner_reflection = chain_tail table = owner_reflection.alias_name scope = last_chain_scope(scope, table, owner_reflection, owner) @@ -146,7 +146,7 @@ module ActiveRecord reflection.constraints.each do |scope_chain_item| item = eval_scope(reflection, table, scope_chain_item, owner) - if scope_chain_item == refl.scope + if scope_chain_item == chain_head.scope scope.merge! item.except(:where, :includes) end @@ -174,7 +174,8 @@ module ActiveRecord end def eval_scope(reflection, table, scope, owner) - reflection.build_scope(table).instance_exec(owner, &scope) + relation = reflection.build_scope(table) + relation.instance_exec(owner, &scope) || relation end end end diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 7a9f5f7937..ba54cd8f49 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module ActiveRecord - # = Active Record Belongs To Association module Associations + # = Active Record Belongs To Association class BelongsToAssociation < SingularAssociation #:nodoc: def handle_dependency target.send(options[:dependent]) if load_target diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index 13b4a084ea..4ce3474bd5 100644 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module ActiveRecord - # = Active Record Belongs To Polymorphic Association module Associations + # = Active Record Belongs To Polymorphic Association class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc: def klass type = owner[reflection.foreign_type] diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 88fe33eef2..07c7f28d2d 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module ActiveRecord - # = Active Record Has Many Association module Associations + # = Active Record Has Many Association # This is the proxy that handles a has many association. # # If the association has a <tt>:through</tt> option further specialization diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 89ce00f98e..adbf52b87c 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module ActiveRecord - # = Active Record Has Many Through Association module Associations + # = Active Record Has Many Through Association class HasManyThroughAssociation < HasManyAssociation #:nodoc: include ThroughAssociation diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 9a88c1af70..7953b89f61 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module ActiveRecord - # = Active Record Has One Association module Associations + # = Active Record Has One Association class HasOneAssociation < SingularAssociation #:nodoc: include ForeignAssociation diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb index eb54977aa0..36746f9115 100644 --- a/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module ActiveRecord - # = Active Record Has One Through Association module Associations + # = Active Record Has One Through Association class HasOneThroughAssociation < HasOneAssociation #:nodoc: include ThroughAssociation diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index dc029c08bd..77b3d11b47 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -119,7 +119,7 @@ module ActiveRecord end def aliases - Aliases.new join_root.each_with_index.map { |join_part, i| + @aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i| columns = join_part.column_names.each_with_index.map { |column_name, j| Aliases::Column.new column_name, "t#{i}_r#{j}" } @@ -127,7 +127,7 @@ module ActiveRecord } end - def instantiate(result_set, aliases) + def instantiate(result_set, &block) primary_key = aliases.column_alias(join_root, join_root.primary_key) seen = Hash.new { |i, object_id| @@ -150,7 +150,7 @@ module ActiveRecord message_bus.instrument("instantiation.active_record", payload) do result_set.each { |row_hash| parent_key = primary_key ? row_hash[primary_key] : row_hash - parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases) + parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block) construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases) } end @@ -256,7 +256,8 @@ module ActiveRecord else model = construct_model(ar_parent, node, row, model_cache, id, aliases) - if node.reflection.scope_for(node.base_klass).readonly_value + if node.reflection.scope && + node.reflection.scope_for(node.base_klass.unscoped).readonly_value model.readonly! end diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 4915a37f06..7bfb85fb32 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -113,7 +113,7 @@ module ActiveRecord end def reflection_scope - @reflection_scope ||= reflection.scope_for(klass) + @reflection_scope ||= reflection.scope ? reflection.scope_for(klass.unscoped) : klass.unscoped end def build_scope @@ -123,7 +123,7 @@ module ActiveRecord scope.where!(reflection.type => model.base_class.sti_name) end - scope.merge!(reflection_scope) + scope.merge!(reflection_scope) if reflection.scope scope.merge!(preload_scope) if preload_scope scope end diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index de4b847a41..8aac00d910 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -81,23 +81,33 @@ module ActiveRecord def through_scope scope = through_reflection.klass.unscoped - values = reflection_scope.values if options[:source_type] scope.where! reflection.foreign_type => options[:source_type] - else - unless reflection_scope.where_clause.empty? - scope.includes_values = Array(values[:includes] || options[:source]) - scope.where_clause = reflection_scope.where_clause - if joins = values[:joins] - scope.joins!(source_reflection.name => joins) - end - if left_outer_joins = values[:left_outer_joins] - scope.left_outer_joins!(source_reflection.name => left_outer_joins) - end + elsif !reflection_scope.where_clause.empty? + scope.where_clause = reflection_scope.where_clause + values = reflection_scope.values + + if includes = values[:includes] + scope.includes!(source_reflection.name => includes) + else + scope.includes!(source_reflection.name) + end + + if values[:references] && !values[:references].empty? + scope.references!(values[:references]) + else + scope.references!(source_reflection.table_name) + end + + if joins = values[:joins] + scope.joins!(source_reflection.name => joins) + end + + if left_outer_joins = values[:left_outer_joins] + scope.left_outer_joins!(source_reflection.name => left_outer_joins) end - scope.references! values[:references] if scope.eager_loading? && order_values = values[:order] scope = scope.order(order_values) end diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index cba565448f..bce2a95ce1 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module ActiveRecord - # = Active Record Through Association module Associations + # = Active Record Through Association module ThroughAssociation #:nodoc: delegate :source_reflection, :through_reflection, to: :reflection diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index c622df132e..4f957ac3ca 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -94,7 +94,7 @@ module ActiveRecord end # Did this attribute change when we last saved? This method can be invoked - # as `saved_change_to_name?` instead of `saved_change_to_attribute?("name")`. + # as +saved_change_to_name?+ instead of <tt>saved_change_to_attribute?("name")</tt>. # Behaves similarly to +attribute_changed?+. This method is useful in # after callbacks to determine if the call to save changed a certain # attribute. @@ -117,8 +117,8 @@ module ActiveRecord # Behaves similarly to +attribute_change+. This method is useful in after # callbacks, to see the change in an attribute that just occurred # - # This method can be invoked as `saved_change_to_name` in instead of - # `saved_change_to_attribute("name")` + # This method can be invoked as +saved_change_to_name+ in instead of + # <tt>saved_change_to_attribute("name")</tt> def saved_change_to_attribute(attr_name) mutations_before_last_save.change_to_attribute(attr_name) end @@ -131,7 +131,7 @@ module ActiveRecord mutations_before_last_save.original_value(attr_name) end - # Did the last call to `save` have any changes to change? + # Did the last call to +save+ have any changes to change? def saved_changes? mutations_before_last_save.any_changes? end @@ -141,37 +141,37 @@ module ActiveRecord mutations_before_last_save.changes end - # Alias for `attribute_changed?` + # Alias for +attribute_changed?+ def will_save_change_to_attribute?(attr_name, **options) mutations_from_database.changed?(attr_name, **options) end - # Alias for `attribute_change` + # Alias for +attribute_change+ def attribute_change_to_be_saved(attr_name) mutations_from_database.change_to_attribute(attr_name) end - # Alias for `attribute_was` + # Alias for +attribute_was+ def attribute_in_database(attr_name) mutations_from_database.original_value(attr_name) end - # Alias for `changed?` + # Alias for +changed?+ def has_changes_to_save? mutations_from_database.any_changes? end - # Alias for `changes` + # Alias for +changes+ def changes_to_save mutations_from_database.changes end - # Alias for `changed` + # Alias for +changed+ def changed_attribute_names_to_save changes_to_save.keys end - # Alias for `changed_attributes` + # Alias for +changed_attributes+ def attributes_in_database changes_to_save.transform_values(&:first) end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 615b2fa701..b070235684 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -5,7 +5,7 @@ module ActiveRecord module Read extend ActiveSupport::Concern - module ClassMethods + module ClassMethods # :nodoc: private # We want to generate the methods via module_eval rather than diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index f12a9f915c..d2b7817b45 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -62,7 +62,7 @@ module ActiveRecord class_attribute :time_zone_aware_types, instance_writer: false, default: [ :datetime, :time ] end - module ClassMethods + module ClassMethods # :nodoc: private def inherited(subclass) diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 62c5ce059b..37891ce2ef 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -9,7 +9,7 @@ module ActiveRecord attribute_method_suffix "=" end - module ClassMethods + module ClassMethods # :nodoc: private def define_method_attribute=(name) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb index 8bf3879a4c..bd05fb8f6e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -62,7 +62,7 @@ module ActiveRecord end def visit_PrimaryKeyDefinition(o) - "PRIMARY KEY (#{o.name.join(', ')})" + "PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})" end def visit_ForeignKeyDefinition(o) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 3b2c51ef94..788a455773 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -148,7 +148,7 @@ module ActiveRecord end def polymorphic_options - as_options(polymorphic).merge(null: options[:null]) + as_options(polymorphic).merge(options.slice(:null, :first, :after)) end def index_options diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb index f17f1d35e2..1926603474 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb @@ -4,31 +4,24 @@ require "active_support/core_ext/hash/compact" module ActiveRecord module ConnectionAdapters # :nodoc: - # The goal of this module is to move Adapter specific column - # definitions to the Adapter instead of having it in the schema - # dumper itself. This code represents the normal case. - # We can then redefine how certain data types may be handled in the schema dumper on the - # Adapter level by over-writing this code inside the database specific adapters - module ColumnDumper - def column_spec(column) - [schema_type_with_virtual(column), prepare_column_options(column)] + class SchemaDumper < SchemaDumper # :nodoc: + def self.create(connection, options) + new(connection, options) end - def column_spec_for_primary_key(column) - return {} if default_primary_key?(column) - spec = { id: schema_type(column).inspect } - spec.merge!(prepare_column_options(column).except!(:null)) - spec[:default] ||= "nil" if explicit_primary_key_default?(column) - spec - end + private + def column_spec(column) + [schema_type_with_virtual(column), prepare_column_options(column)] + end - # Lists the valid migration options - def migration_keys # :nodoc: - column_options_keys - end - deprecate :migration_keys + def column_spec_for_primary_key(column) + return {} if default_primary_key?(column) + spec = { id: schema_type(column).inspect } + spec.merge!(prepare_column_options(column).except!(:null)) + spec[:default] ||= "nil" if explicit_primary_key_default?(column) + spec + end - private def prepare_column_options(column) spec = {} spec[:limit] = schema_limit(column) @@ -51,7 +44,7 @@ module ActiveRecord end def schema_type_with_virtual(column) - if supports_virtual_columns? && column.virtual? + if @connection.supports_virtual_columns? && column.virtual? :virtual else schema_type(column) @@ -68,7 +61,7 @@ module ActiveRecord def schema_limit(column) limit = column.limit unless column.bigint? - limit.inspect if limit && limit != native_database_types[column.type][:limit] + limit.inspect if limit && limit != @connection.native_database_types[column.type][:limit] end def schema_precision(column) @@ -81,7 +74,7 @@ module ActiveRecord def schema_default(column) return unless column.has_default? - type = lookup_cast_type_from_column(column) + type = @connection.lookup_cast_type_from_column(column) default = type.deserialize(column.default) if default.nil? schema_expression(column) 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 3c9b25e411..f57c7a5d4d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -406,6 +406,8 @@ module ActiveRecord # # Defaults to false. # + # Only supported on the MySQL adapter, ignored elsewhere. + # # ====== Add a column # # change_table(:suppliers) do |t| @@ -1174,6 +1176,10 @@ module ActiveRecord raise NotImplementedError, "#{self.class} does not support changing column comments" end + def create_schema_dumper(options) # :nodoc: + SchemaDumper.create(self, options) + end + private def column_options_keys [:limit, :precision, :scale, :default, :null, :collation, :comment] diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 7645cf7825..47881e3305 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -72,7 +72,6 @@ module ActiveRecord include Quoting, DatabaseStatements, SchemaStatements include DatabaseLimits include QueryCache - include ColumnDumper include Savepoints SIMPLE_INT = /\A\d+\z/ 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 e647389514..7cd086084a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -17,7 +17,6 @@ module ActiveRecord module ConnectionAdapters class AbstractMysqlAdapter < AbstractAdapter include MySQL::Quoting - include MySQL::ColumnDumper include MySQL::SchemaStatements ## @@ -34,7 +33,7 @@ module ActiveRecord string: { name: "varchar", limit: 255 }, text: { name: "text", limit: 65535 }, integer: { name: "int", limit: 4 }, - float: { name: "float" }, + float: { name: "float", limit: 24 }, decimal: { name: "decimal" }, datetime: { name: "datetime" }, timestamp: { name: "timestamp" }, @@ -630,6 +629,7 @@ module ActiveRecord ER_LOCK_DEADLOCK = 1213 ER_CANNOT_ADD_FOREIGN = 1215 ER_CANNOT_CREATE_TABLE = 1005 + ER_LOCK_WAIT_TIMEOUT = 1205 def translate_exception(exception, message) case error_number(exception) @@ -653,6 +653,8 @@ module ActiveRecord NotNullViolation.new(message) when ER_LOCK_DEADLOCK Deadlocked.new(message) + when ER_LOCK_WAIT_TIMEOUT + TransactionTimeout.new(message) else super end 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 81f7dce562..95eb77aea4 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb @@ -3,17 +3,13 @@ module ActiveRecord module ConnectionAdapters module MySQL - module ColumnDumper # :nodoc: - def migration_keys - super + [:unsigned] - end - + class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc: private def prepare_column_options(column) spec = super spec[:unsigned] = "true" if column.unsigned? - if supports_virtual_columns? && column.virtual? + if @connection.supports_virtual_columns? && column.virtual? spec[:as] = extract_expression_for_virtual_column(column) spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra) spec = { type: schema_type(column).inspect }.merge!(spec) @@ -48,24 +44,27 @@ module ActiveRecord def schema_collation(column) if column.collation && table_name = column.table_name @table_collation_cache ||= {} - @table_collation_cache[table_name] ||= exec_query("SHOW TABLE STATUS LIKE #{quote(table_name)}", "SCHEMA").first["Collation"] + @table_collation_cache[table_name] ||= + @connection.exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"] column.collation.inspect if column.collation != @table_collation_cache[table_name] end end def extract_expression_for_virtual_column(column) - if mariadb? && version < "10.2.5" - create_table_info = create_table_info(column.table_name) - if %r/#{quote_column_name(column.name)} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info + if @connection.mariadb? && @connection.version < "10.2.5" + create_table_info = @connection.send(:create_table_info, column.table_name) + column_name = @connection.quote_column_name(column.name) + if %r/#{column_name} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info $~[:expression].inspect end else - scope = quoted_scope(column.table_name) + scope = @connection.send(:quoted_scope, column.table_name) + column_name = @connection.quote(column.name) sql = "SELECT generation_expression FROM information_schema.columns" \ " WHERE table_schema = #{scope[:schema]}" \ " AND table_name = #{scope[:name]}" \ - " AND column_name = #{quote(column.name)}" - query_value(sql, "SCHEMA").inspect + " AND column_name = #{column_name}" + @connection.query_value(sql, "SCHEMA").inspect end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb index 7bebe82065..759493e3bd 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb @@ -66,6 +66,10 @@ module ActiveRecord MySQL::Table.new(table_name, base) end + def create_schema_dumper(options) + MySQL::SchemaDumper.create(self, options) + end + private CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"] diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb index 5031605c2a..c0dbb166b7 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb @@ -3,12 +3,7 @@ module ActiveRecord module ConnectionAdapters module PostgreSQL - module ColumnDumper # :nodoc: - # Adds +:array+ as a valid migration key - def migration_keys - super + [:array] - end - + class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc: private def prepare_column_options(column) spec = super 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 f258203a43..9e2f61e6ce 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -590,6 +590,10 @@ module ActiveRecord PostgreSQL::Table.new(table_name, base) end + def create_schema_dumper(options) # :nodoc: + PostgreSQL::SchemaDumper.create(self, options) + end + private def schema_creation PostgreSQL::SchemaCreation.new(self) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 9d92f7ca70..4d37a292d6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -121,7 +121,6 @@ module ActiveRecord include PostgreSQL::ReferentialIntegrity include PostgreSQL::SchemaStatements include PostgreSQL::DatabaseStatements - include PostgreSQL::ColumnDumper def supports_index_sort_order? true diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb index ab057c73f1..621678ec65 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb @@ -3,9 +3,8 @@ module ActiveRecord module ConnectionAdapters module SQLite3 - module ColumnDumper # :nodoc: + class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc: private - def default_primary_key?(column) schema_type(column) == :integer end 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 ee84646214..a512702b7b 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb @@ -43,6 +43,10 @@ module ActiveRecord SQLite3::Table.new(table_name, base) end + def create_schema_dumper(options) + SQLite3::SchemaDumper.create(self, options) + end + private def schema_creation SQLite3::SchemaCreation.new(self) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 107b7a9e1d..6fdd666486 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -57,7 +57,6 @@ module ActiveRecord ADAPTER_NAME = "SQLite".freeze include SQLite3::Quoting - include SQLite3::ColumnDumper include SQLite3::SchemaStatements NATIVE_DATABASE_TYPES = { @@ -77,7 +76,7 @@ module ActiveRecord ## # :singleton-method: # Indicates whether boolean values are stored in sqlite3 databases as 1 - # and 0 or 't' and 'f'. Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer` + # and 0 or 't' and 'f'. Leaving <tt>ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer</tt> # set to false is deprecated. SQLite databases have used 't' and 'f' to # serialize boolean values and must have old data converted to 1 and 0 # (its native boolean serialization) before setting this flag to true. @@ -86,7 +85,7 @@ module ActiveRecord # ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1) # ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0) # for all models and all boolean columns, after which the flag must be set - # to true by adding the following to your application.rb file: + # to true by adding the following to your <tt>application.rb</tt> file: # # Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true class_attribute :represent_boolean_as_integer, default: false diff --git a/activerecord/lib/active_record/define_callbacks.rb b/activerecord/lib/active_record/define_callbacks.rb index 2c8783dcc9..87ecd7cec5 100644 --- a/activerecord/lib/active_record/define_callbacks.rb +++ b/activerecord/lib/active_record/define_callbacks.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module ActiveRecord - # This module exists because `ActiveRecord::AttributeMethods::Dirty` needs to - # define callbacks, but continue to have its version of `save` be the super - # method of `ActiveRecord::Callbacks`. This will be removed when the removal + # This module exists because ActiveRecord::AttributeMethods::Dirty needs to + # define callbacks, but continue to have its version of +save+ be the super + # method of ActiveRecord::Callbacks. This will be removed when the removal # of deprecated code removes this need. module DefineCallbacks extend ActiveSupport::Concern diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index e790760292..9ef3316393 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -334,4 +334,9 @@ module ActiveRecord # +reverse_order+ to automatically reverse. class IrreversibleOrderError < ActiveRecordError end + + # TransactionTimeout will be raised when lock wait timeout expires. + # Wait time value is set by innodb_lock_wait_timeout. + class TransactionTimeout < StatementInvalid + end end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 4940e122f4..12169fffa9 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -147,7 +147,7 @@ module ActiveRecord # unwanted inter-test dependencies. Methods used by multiple fixtures should be defined in a module # that is included in ActiveRecord::FixtureSet.context_class. # - # - define a helper method in `test_helper.rb` + # - define a helper method in <tt>test_helper.rb</tt> # module FixtureFileHelpers # def file_sha(path) # Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path))) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 1864ca5ad2..435c81c153 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "active_support/core_ext/hash/except" +require "active_support/core_ext/module/redefine_method" require "active_support/core_ext/object/try" require "active_support/core_ext/hash/indifferent_access" @@ -355,9 +356,7 @@ module ActiveRecord # associations are just regular associations. def generate_association_writer(association_name, type) generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1 - if method_defined?(:#{association_name}_attributes=) - remove_method(:#{association_name}_attributes=) - end + silence_redefinition_of_method :#{association_name}_attributes= def #{association_name}_attributes=(attributes) assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes) end diff --git a/activerecord/lib/active_record/no_touching.rb b/activerecord/lib/active_record/no_touching.rb index c573deb63a..754c891884 100644 --- a/activerecord/lib/active_record/no_touching.rb +++ b/activerecord/lib/active_record/no_touching.rb @@ -6,7 +6,7 @@ module ActiveRecord extend ActiveSupport::Concern module ClassMethods - # Lets you selectively disable calls to `touch` for the + # Lets you selectively disable calls to +touch+ for the # duration of a block. # # ==== Examples diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 1297e0cde7..fbbf9082cc 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -353,7 +353,7 @@ module ActiveRecord # Wrapper around #increment that writes the update to the database. # Only +attribute+ is updated; the record itself is not saved. # This means that any other modified attributes will still be dirty. - # Validations and callbacks are skipped. Supports the `touch` option from + # Validations and callbacks are skipped. Supports the +touch+ option from # +update_counters+, see that for more. # Returns +self+. def increment!(attribute, by = 1, touch: nil) @@ -374,7 +374,7 @@ module ActiveRecord # Wrapper around #decrement that writes the update to the database. # Only +attribute+ is updated; the record itself is not saved. # This means that any other modified attributes will still be dirty. - # Validations and callbacks are skipped. Supports the `touch` option from + # Validations and callbacks are skipped. Supports the +touch+ option from # +update_counters+, see that for more. # Returns +self+. def decrement!(attribute, by = 1, touch: nil) diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index e35049bb41..49ddcaecdf 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -214,7 +214,7 @@ module ActiveRecord def join_scopes(table, predicate_builder) # :nodoc: if scope - [build_scope(table, predicate_builder).instance_exec(&scope)] + [scope_for(build_scope(table, predicate_builder))] else [] end @@ -391,8 +391,8 @@ module ActiveRecord active_record == other_aggregation.active_record end - def scope_for(klass) - scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped + def scope_for(relation, owner = nil) + relation.instance_exec(owner, &scope) || relation end private @@ -1036,20 +1036,12 @@ module ActiveRecord def scopes scopes = @previous_reflection.scopes - if @previous_reflection.options[:source_type] - scopes + [@previous_reflection.source_type_scope] - else - scopes - end + scopes << @previous_reflection.source_type_scope end def join_scopes(table, predicate_builder) # :nodoc: scopes = @previous_reflection.join_scopes(table, predicate_builder) + super - if @previous_reflection.options[:source_type] - scopes + [@previous_reflection.source_type_scope] - else - scopes - end + scopes << @previous_reflection.source_type_scope end def klass @@ -1100,10 +1092,6 @@ module ActiveRecord @reflection.constraints end - def alias_candidate(name) - "#{plural_name}_#{name}_join" - end - def alias_name Arel::Table.new(table_name, type_caster: klass.type_caster) end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index d319978930..012bc838b1 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -566,7 +566,7 @@ module ActiveRecord relation = self if eager_loading? - find_with_associations { |rel| relation = rel } + find_with_associations { |rel, _| relation = rel } end conn = klass.connection @@ -660,7 +660,19 @@ module ActiveRecord def exec_queries(&block) skip_query_cache_if_necessary do - @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, &block).freeze + @records = + if eager_loading? + find_with_associations do |relation, join_dependency| + if ActiveRecord::NullRelation === relation + [] + else + rows = connection.select_all(relation.arel, "SQL") + join_dependency.instantiate(rows, &block) + end.freeze + end + else + klass.find_by_sql(arel, &block).freeze + end preload = preload_values preload += includes_values unless eager_loading? diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb index 4793f2a49b..c5354bf4e9 100644 --- a/activerecord/lib/active_record/relation/delegation.rb +++ b/activerecord/lib/active_record/relation/delegation.rb @@ -39,9 +39,9 @@ module ActiveRecord # for each different klass, and the delegations are compiled into that subclass only. delegate :to_xml, :encode_with, :length, :each, :uniq, :to_ary, :join, - :[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of, + :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of, :to_sentence, :to_formatted_s, :as_json, - :shuffle, :split, :index, to: :records + :shuffle, :split, :slice, :index, :rindex, to: :records delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, :connection, :columns_hash, to: :klass @@ -75,13 +75,6 @@ module ActiveRecord end end end - - def delegate(method, opts = {}) - @delegation_mutex.synchronize do - return if method_defined?(method) - super - end - end end private @@ -93,7 +86,6 @@ module ActiveRecord elsif arel.respond_to?(method) ActiveSupport::Deprecation.warn \ "Delegating #{method} to arel is deprecated and will be removed in Rails 6.0." - self.class.delegate method, to: :arel arel.public_send(method, *args, &block) else super diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 5da9573052..2aed941916 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -372,16 +372,7 @@ module ActiveRecord relation = select aliases.columns relation = apply_join_dependency(relation, join_dependency) - if block_given? - yield relation - else - if ActiveRecord::NullRelation === relation - [] - else - rows = skip_query_cache_if_necessary { connection.select_all(relation.arel, "SQL") } - join_dependency.instantiate(rows, aliases) - end - end + yield relation, join_dependency end def construct_relation_for_exists(relation, conditions) diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index fd644225ca..8d0311fabd 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -19,7 +19,7 @@ module ActiveRecord class << self def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base) - new(connection, generate_options(config)).dump(stream) + connection.create_schema_dumper(generate_options(config)).dump(stream) stream end @@ -123,7 +123,7 @@ HEADER when String tbl.print ", primary_key: #{pk.inspect}" unless pk == "id" pkcol = columns.detect { |c| c.name == pk } - pkcolspec = @connection.column_spec_for_primary_key(pkcol) + pkcolspec = column_spec_for_primary_key(pkcol) if pkcolspec.present? tbl.print ", #{format_colspec(pkcolspec)}" end @@ -132,20 +132,19 @@ HEADER else tbl.print ", id: false" end - tbl.print ", force: :cascade" table_options = @connection.table_options(table) if table_options.present? tbl.print ", #{format_options(table_options)}" end - tbl.puts " do |t|" + tbl.puts ", force: :cascade do |t|" # then dump all non-primary key columns columns.each do |column| raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type) next if column.name == pk - type, colspec = @connection.column_spec(column) + type, colspec = column_spec(column) tbl.print " t.#{type} #{column.name.inspect}" tbl.print ", #{format_colspec(colspec)}" if colspec.present? tbl.puts @@ -163,8 +162,6 @@ HEADER stream.puts "# #{e.message}" stream.puts end - - stream end # Keep it for indexing materialized views diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb index 5681ccdd23..647e066137 100644 --- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb @@ -117,7 +117,7 @@ module ActiveRecord end def run_cmd_error(cmd, args, action) - msg = "failed to execute:\n" + msg = "failed to execute:\n".dup msg << "#{cmd} #{args.join(' ')}\n\n" msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" msg diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb index abdd6db64a..dfe599c4dd 100644 --- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb @@ -73,7 +73,7 @@ module ActiveRecord end def run_cmd_error(cmd, args) - msg = "failed to execute:\n" + msg = "failed to execute:\n".dup msg << "#{cmd} #{args.join(' ')}\n\n" msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" msg |