From d5994ee48af14d67f0eec7d23863d4b19211b078 Mon Sep 17 00:00:00 2001 From: John Mileham Date: Thu, 3 Mar 2011 23:26:45 -0500 Subject: Change behavior of count(:limit => x, :offset => y) to limit/offset before counting. --- .../lib/active_record/relation/calculations.rb | 40 ++++++++++++++-------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index c1842b1a96..7bfeb20a2b 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -183,10 +183,13 @@ module ActiveRecord end end - def aggregate_column(column_name) + def aggregate_column(column_name, subquery_alias = nil) if @klass.column_names.include?(column_name.to_s) - Arel::Attribute.new(@klass.unscoped.table, column_name) + Arel::Attribute.new(subquery_alias || @klass.unscoped.table, column_name) else + if subquery_alias && (split_name = column_name.to_s.split(".")).length > 1 + column_name = split_name.last + end Arel.sql(column_name == :all ? "*" : column_name.to_s) end end @@ -196,24 +199,22 @@ module ActiveRecord end def execute_simple_calculation(operation, column_name, distinct) #:nodoc: - column = aggregate_column(column_name) - # Postgresql doesn't like ORDER BY when there are no GROUP BY relation = except(:order) - select_value = operation_over_aggregate_column(column, operation, distinct) - relation.select_values = [select_value] + if operation == "count" && (relation.limit_value || relation.offset_value) + # Shortcut when limit is zero. + return 0 if relation.limit_value == 0 - query_builder = relation.arel + query_builder = build_count_subquery(relation, column_name, distinct) + else + column = aggregate_column(column_name) - if operation == "count" - limit = relation.limit_value - offset = relation.offset_value + select_value = operation_over_aggregate_column(column, operation, distinct) - unless limit && offset - query_builder.limit = nil - query_builder.offset = nil - end + relation.select_values = [select_value] + + query_builder = relation.arel end type_cast_calculated_value(@klass.connection.select_value(query_builder.to_sql), column_for(column_name), operation) @@ -312,5 +313,16 @@ module ActiveRecord select if select !~ /(,|\*)/ end end + + def build_count_subquery(relation, column_name, distinct) + # Arel doesn't do subqueries + subquery_alias = arel_table.alias("subquery_for_count") + aliased_column = aggregate_column(column_name, subquery_alias) + select_value = operation_over_aggregate_column(aliased_column, 'count', distinct) + + relation.select_values = [(column_name == :all ? 1 : aggregate_column(column_name))] + subquery_sql = "(#{relation.arel.to_sql}) #{subquery_alias.name}" + subquery_alias.relation.select_manager.project(select_value).from(subquery_sql) + end end end -- cgit v1.2.3 From 5214e73850916de3c9127d35a4ecee0424d364a3 Mon Sep 17 00:00:00 2001 From: Josh Susser Date: Wed, 23 Mar 2011 21:52:53 -0700 Subject: add #first! and #last! to models & relations --- activerecord/lib/active_record/relation/finder_methods.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 426000fde1..25e23a9d55 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -123,6 +123,11 @@ module ActiveRecord end end + # Same as #first! but raises RecordNotFound if no record is returned + def first!(*args) + self.first(*args) or raise RecordNotFound + end + # A convenience wrapper for find(:last, *args). You can pass in all the # same arguments to this method as you can to find(:last). def last(*args) @@ -137,6 +142,11 @@ module ActiveRecord end end + # Same as #last! but raises RecordNotFound if no record is returned + def last!(*args) + self.last(*args) or raise RecordNotFound + end + # A convenience wrapper for find(:all, *args). You can pass in all the # same arguments to this method as you can to find(:all). def all(*args) -- cgit v1.2.3 From 28c73f012328c8386acfc608f0dfb1a459dbf170 Mon Sep 17 00:00:00 2001 From: John Mileham Date: Thu, 24 Mar 2011 15:09:24 -0400 Subject: Use Arel to build subquery. Adapt tests to changed fixtures. --- .../lib/active_record/relation/calculations.rb | 25 +++++++++++----------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 7bfeb20a2b..869eebfa34 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -183,13 +183,10 @@ module ActiveRecord end end - def aggregate_column(column_name, subquery_alias = nil) + def aggregate_column(column_name) if @klass.column_names.include?(column_name.to_s) - Arel::Attribute.new(subquery_alias || @klass.unscoped.table, column_name) + Arel::Attribute.new(@klass.unscoped.table, column_name) else - if subquery_alias && (split_name = column_name.to_s.split(".")).length > 1 - column_name = split_name.last - end Arel.sql(column_name == :all ? "*" : column_name.to_s) end end @@ -315,14 +312,16 @@ module ActiveRecord end def build_count_subquery(relation, column_name, distinct) - # Arel doesn't do subqueries - subquery_alias = arel_table.alias("subquery_for_count") - aliased_column = aggregate_column(column_name, subquery_alias) - select_value = operation_over_aggregate_column(aliased_column, 'count', distinct) - - relation.select_values = [(column_name == :all ? 1 : aggregate_column(column_name))] - subquery_sql = "(#{relation.arel.to_sql}) #{subquery_alias.name}" - subquery_alias.relation.select_manager.project(select_value).from(subquery_sql) + column_alias = Arel.sql('count_column') + subquery_alias = Arel.sql('subquery_for_count') + + aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias) + relation.select_values = [aliased_column] + subquery = relation.arel.as(subquery_alias) + + sm = Arel::SelectManager.new relation.engine + select_value = operation_over_aggregate_column(column_alias, 'count', distinct) + sm.project(select_value).from(subquery) end end end -- cgit v1.2.3 From 65dce01091ec88f3485ccc26f8799c609b91e7cc Mon Sep 17 00:00:00 2001 From: Josh Susser Date: Fri, 25 Mar 2011 09:41:06 -0700 Subject: comment typo fix --- activerecord/lib/active_record/relation/finder_methods.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 25e23a9d55..9d4c6d60f5 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -123,7 +123,7 @@ module ActiveRecord end end - # Same as #first! but raises RecordNotFound if no record is returned + # Same as #first but raises RecordNotFound if no record is returned def first!(*args) self.first(*args) or raise RecordNotFound end @@ -142,7 +142,7 @@ module ActiveRecord end end - # Same as #last! but raises RecordNotFound if no record is returned + # Same as #last but raises RecordNotFound if no record is returned def last!(*args) self.last(*args) or raise RecordNotFound end -- cgit v1.2.3 From 25be204e3c2c46b4eb7738daa0ac622738aa211b Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 25 Mar 2011 22:30:36 +0000 Subject: No arguments for first! and last! --- activerecord/lib/active_record/relation/finder_methods.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 9d4c6d60f5..d41a360821 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -124,8 +124,8 @@ module ActiveRecord end # Same as #first but raises RecordNotFound if no record is returned - def first!(*args) - self.first(*args) or raise RecordNotFound + def first! + self.first or raise RecordNotFound end # A convenience wrapper for find(:last, *args). You can pass in all the @@ -143,8 +143,8 @@ module ActiveRecord end # Same as #last but raises RecordNotFound if no record is returned - def last!(*args) - self.last(*args) or raise RecordNotFound + def last! + self.last or raise RecordNotFound end # A convenience wrapper for find(:all, *args). You can pass in all the -- cgit v1.2.3 From 9d9b873b9501f5fc90c0b6a4a550c5e29fc742a5 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 26 Mar 2011 00:02:40 +0100 Subject: removes unnecessary selfs, and mentions that first! and last! take no arguments in their API docs --- activerecord/lib/active_record/relation/finder_methods.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index d41a360821..563843f3cc 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -123,9 +123,10 @@ module ActiveRecord end end - # Same as #first but raises RecordNotFound if no record is returned + # Same as +first+ but raises ActiveRecord::RecordNotFound if no record + # is found. Note that first! accepts no arguments. def first! - self.first or raise RecordNotFound + first or raise RecordNotFound end # A convenience wrapper for find(:last, *args). You can pass in all the @@ -142,9 +143,10 @@ module ActiveRecord end end - # Same as #last but raises RecordNotFound if no record is returned + # Same as +last+ but raises ActiveRecord::RecordNotFound if no record + # is found. Note that last! accepts no arguments. def last! - self.last or raise RecordNotFound + last or raise RecordNotFound end # A convenience wrapper for find(:all, *args). You can pass in all the -- cgit v1.2.3 From 45c233ef819dc7b67e259dd73f24721fec28b8c8 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Sat, 26 Mar 2011 11:42:26 -0300 Subject: Removed #update_attribute method. New #update_column method. Signed-off-by: Santiago Pastorino --- .../active_record/associations/has_one_association.rb | 3 ++- activerecord/lib/active_record/persistence.rb | 18 ++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 1d2e8667e4..dfcb116392 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -34,7 +34,8 @@ module ActiveRecord when :destroy target.destroy when :nullify - target.update_attribute(reflection.foreign_key, nil) + target.send("#{reflection.foreign_key}=", nil) + target.save(:validations => false) end end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 17a64b6e86..3377a5934b 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -104,19 +104,17 @@ module ActiveRecord became end - # Updates a single attribute and saves the record. - # This is especially useful for boolean flags on existing records. Also note that + # Updates a single attribute of an object, without calling save. # # * Validation is skipped. - # * Callbacks are invoked. - # * updated_at/updated_on column is updated if that column is available. - # * Updates all the attributes that are dirty in this object. + # * Callbacks are skipped. + # * updated_at/updated_on column is not updated in any case. # - def update_attribute(name, value) + def update_column(name, value) name = name.to_s raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name) send("#{name}=", value) - save(:validate => false) + self.class.update_all({ name => value }, self.class.primary_key => id) end # Updates the attributes of the model from the passed-in hash and saves the @@ -156,7 +154,7 @@ module ActiveRecord # Saving is not subjected to validation checks. Returns +true+ if the # record could be saved. def increment!(attribute, by = 1) - increment(attribute, by).update_attribute(attribute, self[attribute]) + increment(attribute, by).update_column(attribute, self[attribute]) end # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1). @@ -173,7 +171,7 @@ module ActiveRecord # Saving is not subjected to validation checks. Returns +true+ if the # record could be saved. def decrement!(attribute, by = 1) - decrement(attribute, by).update_attribute(attribute, self[attribute]) + decrement(attribute, by).update_column(attribute, self[attribute]) end # Assigns to +attribute+ the boolean opposite of attribute?. So @@ -190,7 +188,7 @@ module ActiveRecord # Saving is not subjected to validation checks. Returns +true+ if the # record could be saved. def toggle!(attribute) - toggle(attribute).update_attribute(attribute, self[attribute]) + toggle(attribute).update_column(attribute, self[attribute]) end # Reloads the attributes of this object from the database. -- cgit v1.2.3 From 0e1fed537a7699a7ded02f77b71d222d7207c5ad Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Sun, 27 Mar 2011 18:52:21 -0300 Subject: Revert "Removed #update_attribute method. New #update_column method." This reverts commit 45c233ef819dc7b67e259dd73f24721fec28b8c8. Signed-off-by: Santiago Pastorino --- .../active_record/associations/has_one_association.rb | 3 +-- activerecord/lib/active_record/persistence.rb | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index dfcb116392..1d2e8667e4 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -34,8 +34,7 @@ module ActiveRecord when :destroy target.destroy when :nullify - target.send("#{reflection.foreign_key}=", nil) - target.save(:validations => false) + target.update_attribute(reflection.foreign_key, nil) end end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 3377a5934b..17a64b6e86 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -104,17 +104,19 @@ module ActiveRecord became end - # Updates a single attribute of an object, without calling save. + # Updates a single attribute and saves the record. + # This is especially useful for boolean flags on existing records. Also note that # # * Validation is skipped. - # * Callbacks are skipped. - # * updated_at/updated_on column is not updated in any case. + # * Callbacks are invoked. + # * updated_at/updated_on column is updated if that column is available. + # * Updates all the attributes that are dirty in this object. # - def update_column(name, value) + def update_attribute(name, value) name = name.to_s raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name) send("#{name}=", value) - self.class.update_all({ name => value }, self.class.primary_key => id) + save(:validate => false) end # Updates the attributes of the model from the passed-in hash and saves the @@ -154,7 +156,7 @@ module ActiveRecord # Saving is not subjected to validation checks. Returns +true+ if the # record could be saved. def increment!(attribute, by = 1) - increment(attribute, by).update_column(attribute, self[attribute]) + increment(attribute, by).update_attribute(attribute, self[attribute]) end # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1). @@ -171,7 +173,7 @@ module ActiveRecord # Saving is not subjected to validation checks. Returns +true+ if the # record could be saved. def decrement!(attribute, by = 1) - decrement(attribute, by).update_column(attribute, self[attribute]) + decrement(attribute, by).update_attribute(attribute, self[attribute]) end # Assigns to +attribute+ the boolean opposite of attribute?. So @@ -188,7 +190,7 @@ module ActiveRecord # Saving is not subjected to validation checks. Returns +true+ if the # record could be saved. def toggle!(attribute) - toggle(attribute).update_column(attribute, self[attribute]) + toggle(attribute).update_attribute(attribute, self[attribute]) end # Reloads the attributes of this object from the database. -- cgit v1.2.3 From 245542ea2994961731be105db6c076256a22a7a9 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Sun, 27 Mar 2011 19:12:28 -0300 Subject: Added new #update_column method. Signed-off-by: Santiago Pastorino --- activerecord/lib/active_record/attribute_methods/write.rb | 1 + activerecord/lib/active_record/persistence.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 3c4dab304e..7661676f8c 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -32,6 +32,7 @@ module ActiveRecord @attributes[attr_name] = value end end + alias_method :raw_write_attribute, :write_attribute private # Handle *= for method_missing. diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 17a64b6e86..a916c88348 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -119,6 +119,20 @@ module ActiveRecord save(:validate => false) end + # Updates a single attribute of an object, without calling save. + # + # * Validation is skipped. + # * Callbacks are skipped. + # * updated_at/updated_on column is not updated if that column is available. + # + def update_column(name, value) + name = name.to_s + raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name) + raise ActiveRecordError, "can not update on a new record object" unless persisted? + raw_write_attribute(name, value) + self.class.update_all({ name => value }, self.class.primary_key => id) == 1 + end + # Updates the attributes of the model from the passed-in hash and saves the # record, all wrapped in a transaction. If the object is invalid, the saving # will fail and false will be returned. -- cgit v1.2.3 From fb215110401c70cfc7013c6e2ad5753fa4e374e9 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Mon, 28 Mar 2011 10:19:41 -0300 Subject: Bring #reorder back Signed-off-by: Santiago Pastorino --- activerecord/lib/active_record/base.rb | 2 +- activerecord/lib/active_record/relation/query_methods.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index b778b0c0f0..616b5cc3b4 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -439,7 +439,7 @@ module ActiveRecord #:nodoc: class << self # Class methods delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped delegate :find_each, :find_in_batches, :to => :scoped - delegate :select, :group, :order, :except, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped + delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped # Executes a custom SQL query against your database and returns all the results. The results will diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 9470e7c6c5..02b7056989 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -62,6 +62,10 @@ module ActiveRecord relation end + def reorder(*args) + except(:order).order(args) + end + def joins(*args) return self if args.compact.blank? -- cgit v1.2.3 From e1a5007207b8bd9e91711428acc3104f4c8e8fb8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 28 Mar 2011 15:27:37 -0700 Subject: sql logger ignores schema statements --- activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb | 4 ++-- activerecord/lib/active_record/log_subscriber.rb | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index ae61d6ce94..32229a8410 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -222,7 +222,7 @@ module ActiveRecord # SCHEMA STATEMENTS ======================================== - def tables(name = nil) #:nodoc: + def tables(name = 'SCHEMA') #:nodoc: sql = <<-SQL SELECT name FROM sqlite_master @@ -350,7 +350,7 @@ module ActiveRecord end def table_structure(table_name) - structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})").to_hash + structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty? structure end diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb index afadbf03ef..d31e321440 100644 --- a/activerecord/lib/active_record/log_subscriber.rb +++ b/activerecord/lib/active_record/log_subscriber.rb @@ -23,6 +23,9 @@ module ActiveRecord return unless logger.debug? payload = event.payload + + return if 'SCHEMA' == payload[:name] + name = '%s (%.1fms)' % [payload[:name], event.duration] sql = payload[:sql].squeeze(' ') binds = nil -- cgit v1.2.3 From 4211866b7a1d0abf0c9150fd61ea67a8043b831d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 28 Mar 2011 16:43:34 -0700 Subject: adding active_connection? to the connection pool --- .../active_record/connection_adapters/abstract/connection_pool.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'activerecord/lib/active_record') 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 4297c26413..61e44d09bf 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -151,6 +151,12 @@ module ActiveRecord @reserved_connections[current_connection_id] ||= checkout end + # Check to see if there is an active connection in this connection + # pool. + def active_connection? + @reserved_connections.key? current_connection_id + end + # Signal that the thread is finished with the current connection. # #release_connection releases the connection-thread association # and returns the connection to the pool. -- cgit v1.2.3 From 25f94971abf71fe51089f53b72cc08b636c230b3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 28 Mar 2011 17:29:37 -0700 Subject: adding active_connections? to the connection pool for finding open connections --- .../active_record/connection_adapters/abstract/connection_pool.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'activerecord/lib/active_record') 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 61e44d09bf..7a900055a9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -352,6 +352,12 @@ module ActiveRecord @connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec) end + # Returns true if there are any active connections among the connection + # pools that the ConnectionHandler is managing. + def active_connections? + connection_pools.values.any? { |pool| pool.active_connection? } + end + # Returns any connections in use by the current thread back to the pool, # and also returns connections to the pool cached by threads that are no # longer alive. -- cgit v1.2.3 From aea1477362b640ebe52cf991b915ad32e7bf2571 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 28 Mar 2011 17:47:46 -0700 Subject: make sure we have an active database connection before running each connection management test --- .../connection_adapters/abstract/connection_specification.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index d88720c8bf..bcd3abc08d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -116,7 +116,11 @@ module ActiveRecord connection_handler.remove_connection(klass) end - delegate :clear_active_connections!, :clear_reloadable_connections!, + def clear_active_connections! + connection_handler.clear_active_connections! + end + + delegate :clear_reloadable_connections!, :clear_all_connections!,:verify_active_connections!, :to => :connection_handler end end -- cgit v1.2.3 From b155fdadf334cff32a7e648c86c3c97f2f51257f Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 29 Mar 2011 12:51:58 +0100 Subject: Change exists? so that it doesn't instantiate records [#6127 state:resolved] --- activerecord/lib/active_record/relation/finder_methods.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 563843f3cc..8fa315bdf3 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -183,7 +183,9 @@ module ActiveRecord def exists?(id = nil) id = id.id if ActiveRecord::Base === id - relation = select("1").limit(1) + join_dependency = construct_join_dependency_for_association_find + relation = construct_relation_for_association_find(join_dependency) + relation = relation.except(:select).select("1").limit(1) case id when Array, Hash @@ -192,14 +194,13 @@ module ActiveRecord relation = relation.where(table[primary_key].eq(id)) if id end - relation.first ? true : false + connection.select_value(relation.to_sql) ? true : false end protected def find_with_associations - including = (@eager_load_values + @includes_values).uniq - join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, []) + join_dependency = construct_join_dependency_for_association_find relation = construct_relation_for_association_find(join_dependency) rows = connection.select_all(relation.to_sql, 'SQL', relation.bind_values) join_dependency.instantiate(rows) @@ -207,6 +208,11 @@ module ActiveRecord [] end + def construct_join_dependency_for_association_find + including = (@eager_load_values + @includes_values).uniq + ActiveRecord::Associations::JoinDependency.new(@klass, including, []) + end + def construct_relation_for_association_calculations including = (@eager_load_values + @includes_values).uniq join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first) -- cgit v1.2.3 From a9dafbb28de3e34c31ebf184fbc4e2042c7ff207 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 29 Mar 2011 15:08:40 +0100 Subject: Delegate first!, last!, any? and many? to scoped --- activerecord/lib/active_record/base.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 616b5cc3b4..fe81c7dc2f 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -437,7 +437,8 @@ module ActiveRecord #:nodoc: self._attr_readonly = [] class << self # Class methods - delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped + delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped + delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped delegate :find_each, :find_in_batches, :to => :scoped delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped -- cgit v1.2.3 From 555d0163897601010ab1305f41ed393ec517b61e Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 27 Mar 2011 09:54:38 +0100 Subject: Quote find_in_batches ORDER BY clause [#6620 state:resolved] --- .../lib/active_record/attribute_methods/primary_key.rb | 13 ++++++++++++- activerecord/lib/active_record/relation.rb | 2 +- activerecord/lib/active_record/relation/batches.rb | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index fcdd31ddea..5f06452247 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -17,6 +17,11 @@ module ActiveRecord @primary_key ||= reset_primary_key end + # Returns a quoted version of the primary key name, used to construct SQL statements. + def quoted_primary_key + @quoted_primary_key ||= connection.quote_column_name(primary_key) + end + def reset_primary_key #:nodoc: key = self == base_class ? get_primary_key(base_class.name) : base_class.primary_key @@ -43,7 +48,12 @@ module ActiveRecord end attr_accessor :original_primary_key - attr_writer :primary_key + + # Attribute writer for the primary key column + def primary_key=(value) + @quoted_primary_key = nil + @primary_key = value + end # Sets the name of the primary key column to use to the given value, # or (if the value is nil or false) to the value returned by the given @@ -53,6 +63,7 @@ module ActiveRecord # set_primary_key "sysid" # end def set_primary_key(value = nil, &block) + @quoted_primary_key = nil @primary_key ||= '' self.original_primary_key = @primary_key value &&= value.to_s diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 8e545f9cad..896daf516e 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -12,7 +12,7 @@ module ActiveRecord # These are explicitly delegated to improve performance (avoids method_missing) delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to => :to_a - delegate :table_name, :primary_key, :to => :klass + delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, :to => :klass attr_reader :table, :klass, :loaded attr_accessor :extensions diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index bf5a60f458..d52b84179f 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -83,7 +83,7 @@ module ActiveRecord private def batch_order - "#{table_name}.#{primary_key} ASC" + "#{quoted_table_name}.#{quoted_primary_key} ASC" end end end -- cgit v1.2.3 From e5246092d1ce30961af4f7d9b5ad86071298cf1c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 29 Mar 2011 15:37:07 -0700 Subject: proxy body responses so we close database connections after body is flushed --- .../abstract/connection_pool.rb | 31 +++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'activerecord/lib/active_record') 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 7a900055a9..5e12f80263 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -417,18 +417,35 @@ module ActiveRecord end class ConnectionManagement + class Proxy # :nodoc: + attr_reader :body, :testing + + def initialize(body, testing = false) + @body = body + @testing = testing + end + + def each(&block) + body.each(&block) + end + + def close + body.close if body.respond_to?(:close) + + # Don't return connection (and perform implicit rollback) if + # this request is a part of integration test + ActiveRecord::Base.clear_active_connections! unless testing + end + end + def initialize(app) @app = app end def call(env) - @app.call(env) - ensure - # Don't return connection (and perform implicit rollback) if - # this request is a part of integration test - unless env.key?("rack.test") - ActiveRecord::Base.clear_active_connections! - end + status, headers, body = @app.call(env) + + [status, headers, Proxy.new(body, env.key?('rack.test'))] end end end -- cgit v1.2.3 From 3b2a032677a2261499aa5d2de019f31f1173a858 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 29 Mar 2011 15:42:32 -0700 Subject: clearing active connections in the ConnectionManagement middleware if an exception happens --- .../lib/active_record/connection_adapters/abstract/connection_pool.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'activerecord/lib/active_record') 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 5e12f80263..45900d27dc 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -446,6 +446,9 @@ module ActiveRecord status, headers, body = @app.call(env) [status, headers, Proxy.new(body, env.key?('rack.test'))] + rescue + ActiveRecord::Base.clear_active_connections! + raise end end end -- cgit v1.2.3 From c7b7c6ad1c773102753f1a11b857d0e37ceb6a21 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 29 Mar 2011 15:47:16 -0700 Subject: make sure that active connections are not cleared during test when an exception happens --- .../active_record/connection_adapters/abstract/connection_pool.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') 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 45900d27dc..b4db1eed18 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -443,11 +443,13 @@ module ActiveRecord end def call(env) + testing = env.key?('rack.test') + status, headers, body = @app.call(env) - [status, headers, Proxy.new(body, env.key?('rack.test'))] + [status, headers, Proxy.new(body, testing)] rescue - ActiveRecord::Base.clear_active_connections! + ActiveRecord::Base.clear_active_connections! unless testing raise end end -- cgit v1.2.3 From cfb6f77ac0574d3cd613c99fcc32135016b4284c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 30 Mar 2011 09:54:46 -0700 Subject: TableAlias leg ordering has changed, so change accordingly --- .../lib/active_record/associations/join_dependency/join_part.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb index 3279e56e7d..2b1d888a9a 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb @@ -22,7 +22,7 @@ module ActiveRecord end def aliased_table - Arel::Nodes::TableAlias.new aliased_table_name, table + Arel::Nodes::TableAlias.new table, aliased_table_name end def ==(other) -- cgit v1.2.3