diff options
Diffstat (limited to 'activerecord/lib')
10 files changed, 52 insertions, 44 deletions
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 2fbab97133..609c6e8cab 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -172,6 +172,8 @@ module ActiveRecord # If the result is true then check for the select case. # For queries selecting a subset of columns, return false for unselected columns. + # We check defined?(@attributes) not to issue warnings if called on objects that + # have been allocated but not yet initialized. if defined?(@attributes) && @attributes.present? && self.class.column_names.include?(name) return has_attribute?(name) end @@ -340,6 +342,7 @@ module ActiveRecord end def attribute_method?(attr_name) # :nodoc: + # We check defined? because Syck calls respond_to? before actually calling initialize. defined?(@attributes) && @attributes.include?(attr_name) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 1138b10a1b..26586f0974 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -433,7 +433,7 @@ module ActiveRecord def translate_exception(exception, message) # override in derived class - ActiveRecord::StatementInvalid.new(message) + ActiveRecord::StatementInvalid.new(message, exception) end end 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 94d9efe521..76c501dec5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -287,7 +287,7 @@ module ActiveRecord end rescue ActiveRecord::StatementInvalid => exception if exception.message.split(":").first =~ /Packets out of order/ - raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings." + raise ActiveRecord::StatementInvalid.new("'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings.", exception.original_exception) else raise end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 9e45e6e474..ba053700f2 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -352,7 +352,9 @@ module ActiveRecord # Returns the contents of the record as a nicely formatted string. def inspect - inspection = if @attributes + # We check defined?(@attributes) not to issue warnings if the object is + # allocated but not initialized. + inspection = if defined?(@attributes) && @attributes self.class.column_names.collect { |name| if has_attribute?(name) "#{name}: #{attribute_for_inspect(name)}" diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index c615d59725..cd31147414 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -57,24 +57,25 @@ module ActiveRecord class RecordNotDestroyed < ActiveRecordError end - # Raised when SQL statement cannot be executed by the database (for example, it's often the case for - # MySQL when Ruby driver used is too old). + # Superclass for all database execution errors. + # + # Wraps the underlying database error as +original_exception+. class StatementInvalid < ActiveRecordError + attr_reader :original_exception + + def initialize(message, original_exception = nil) + super(message) + @original_exception = original_exception + end end # Raised when SQL statement is invalid and the application gets a blank result. class ThrowResult < ActiveRecordError end - # Parent class for all specific exceptions which wrap database driver exceptions - # provides access to the original exception also. + # Defunct wrapper class kept for compatibility. + # +StatementInvalid+ wraps the original exception now. class WrappedDatabaseException < StatementInvalid - attr_reader :original_exception - - def initialize(message, original_exception) - super(message) - @original_exception = original_exception - end end # Raised when a record cannot be inserted because it would violate a uniqueness constraint. diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 59f8e90e7a..178db07ca1 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -428,23 +428,11 @@ module ActiveRecord # Updates the associated record with values matching those of the instance attributes. # Returns the number of affected rows. def update_record(attribute_names = @attributes.keys) - attributes_with_values = arel_attributes_with_values_for_update(attribute_names) - if attributes_with_values.empty? + attributes_values = arel_attributes_with_values_for_update(attribute_names) + if attributes_values.empty? 0 else - klass = self.class - column_hash = klass.connection.schema_cache.columns_hash klass.table_name - db_columns_with_values = attributes_with_values.map { |attr,value| - real_column = column_hash[attr.name] - [real_column, value] - } - bind_attrs = attributes_with_values.dup - bind_attrs.keys.each_with_index do |column, i| - real_column = db_columns_with_values[i].first - bind_attrs[column] = klass.connection.substitute_at(real_column, i) - end - stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id_was || id)).arel.compile_update(bind_attrs) - klass.connection.update stmt, 'SQL', db_columns_with_values + self.class.unscoped.update_record attributes_values, id, id_was end end diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index 902fd90c54..f78ccb01aa 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -8,7 +8,7 @@ module ActiveRecord delegate :find_each, :find_in_batches, :to => :all delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, - :having, :create_with, :uniq, :distinct, :references, :none, :to => :all + :having, :create_with, :uniq, :distinct, :references, :none, :unscope, :to => :all delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :ids, :to => :all # Executes a custom SQL query against your database and returns all the results. The results will diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 56462d355b..ad33e398be 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -56,16 +56,7 @@ module ActiveRecord im = arel.create_insert im.into @table - conn = @klass.connection - - substitutes = values.sort_by { |arel_attr,_| arel_attr.name } - binds = substitutes.map do |arel_attr, value| - [@klass.columns_hash[arel_attr.name], value] - end - - substitutes.each_with_index do |tuple, i| - tuple[1] = conn.substitute_at(binds[i][0], i) - end + substitutes, binds = substitute_values values if values.empty? # empty insert im.values = Arel.sql(connection.empty_insert_statement_value) @@ -73,7 +64,7 @@ module ActiveRecord im.insert substitutes end - conn.insert( + @klass.connection.insert( im, 'SQL', primary_key, @@ -82,6 +73,29 @@ module ActiveRecord binds) end + def update_record(values, id, id_was) + substitutes, binds = substitute_values values + um = @klass.unscoped.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes) + + @klass.connection.update( + um, + 'SQL', + binds) + end + + def substitute_values(values) + substitutes = values.sort_by { |arel_attr,_| arel_attr.name } + binds = substitutes.map do |arel_attr, value| + [@klass.columns_hash[arel_attr.name], value] + end + + substitutes.each_with_index do |tuple, i| + tuple[1] = @klass.connection.substitute_at(binds[i][0], i) + end + + [substitutes, binds] + end + # Initializes new record from relation while maintaining the current # scope. # diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb index 1b6239eb38..8d6740246c 100644 --- a/activerecord/lib/active_record/relation/delegation.rb +++ b/activerecord/lib/active_record/relation/delegation.rb @@ -14,14 +14,14 @@ module ActiveRecord delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, :connection, :columns_hash, :to => :klass - module ClassSpecificRelation + module ClassSpecificRelation # :nodoc: extend ActiveSupport::Concern included do @delegation_mutex = Mutex.new end - module ClassMethods + module ClassMethods # :nodoc: def name superclass.name end @@ -70,7 +70,7 @@ module ActiveRecord end end - module ClassMethods + module ClassMethods # :nodoc: @@subclasses = ThreadSafe::Cache.new(:initial_capacity => 2) def new(klass, *args) diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index f2b041ad97..de5fd05468 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -1,7 +1,7 @@ module ActiveRecord # Returns the version of the currently loaded ActiveRecord as a Gem::Version def self.version - Gem::Version.new "4.0.0.beta1" + Gem::Version.new "4.1.0.beta" end module VERSION #:nodoc: |