aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2010-05-19 23:29:39 +0200
committerXavier Noria <fxn@hashref.com>2010-05-19 23:29:39 +0200
commit7f07cc364a7ee7ceae21b29b54467fde0db93389 (patch)
tree7c9dd8aaeda68731756ee108a8318239b04c80f0 /activerecord/lib
parentb9fcd8d71f94702463b97545bb70ce4727c5b47e (diff)
parent61001e766de974a8864c0bc2cf915888d277a0ea (diff)
downloadrails-7f07cc364a7ee7ceae21b29b54467fde0db93389.tar.gz
rails-7f07cc364a7ee7ceae21b29b54467fde0db93389.tar.bz2
rails-7f07cc364a7ee7ceae21b29b54467fde0db93389.zip
Merge remote branch 'rails/master'
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/autosave_association.rb23
-rwxr-xr-xactiverecord/lib/active_record/base.rb23
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb57
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb45
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb4
-rw-r--r--activerecord/lib/active_record/session_store.rb2
9 files changed, 143 insertions, 28 deletions
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index fd1082a268..c553e95bad 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -214,6 +214,12 @@ module ActiveRecord
@marked_for_destruction
end
+ # Returns whether or not this record has been changed in any way (including whether
+ # any of its nested autosave associations are likewise changed)
+ def changed_for_autosave?
+ new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
+ end
+
private
# Returns the record for an association collection that should be validated
@@ -223,12 +229,27 @@ module ActiveRecord
if new_record
association
elsif autosave
- association.target.find_all { |record| record.new_record? || record.changed? || record.marked_for_destruction? }
+ association.target.find_all { |record| record.changed_for_autosave? }
else
association.target.find_all { |record| record.new_record? }
end
end
+ # go through nested autosave associations that are loaded in memory (without loading
+ # any new ones), and return true if is changed for autosave
+ def nested_records_changed_for_autosave?
+ self.class.reflect_on_all_autosave_associations.each do |reflection|
+ if association = association_instance_get(reflection.name)
+ if [:belongs_to, :has_one].include?(reflection.macro)
+ return true if association.target && association.target.changed_for_autosave?
+ else
+ association.target.each {|record| return true if record.changed_for_autosave? }
+ end
+ end
+ end
+ false
+ end
+
# Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
# turned on for the association specified by +reflection+.
def validate_single_association(reflection)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index c02af328c1..1b76f357e3 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1193,10 +1193,6 @@ module ActiveRecord #:nodoc:
self.default_scoping << construct_finder_arel(options, default_scoping.pop)
end
- def clear_default_scope
- self.default_scoping.clear
- end
-
def scoped_methods #:nodoc:
key = :"#{self}_scoped_methods"
Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup
@@ -1362,7 +1358,8 @@ module ActiveRecord #:nodoc:
def replace_bind_variables(statement, values) #:nodoc:
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
bound = values.dup
- statement.gsub('?') { quote_bound_value(bound.shift) }
+ c = connection
+ statement.gsub('?') { quote_bound_value(bound.shift, c) }
end
def replace_named_bind_variables(statement, bind_vars) #:nodoc:
@@ -1394,15 +1391,15 @@ module ActiveRecord #:nodoc:
expanded
end
- def quote_bound_value(value) #:nodoc:
+ def quote_bound_value(value, c = connection) #:nodoc:
if value.respond_to?(:map) && !value.acts_like?(:string)
if value.respond_to?(:empty?) && value.empty?
- connection.quote(nil)
+ c.quote(nil)
else
- value.map { |v| connection.quote(v) }.join(',')
+ value.map { |v| c.quote(v) }.join(',')
end
else
- connection.quote(value)
+ c.quote(value)
end
end
@@ -1462,12 +1459,18 @@ module ActiveRecord #:nodoc:
callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
cloned_attributes.delete(self.class.primary_key)
+
@attributes = cloned_attributes
+
+ @changed_attributes = {}
+ attributes_from_column_definition.each do |attr, orig_value|
+ @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr])
+ end
+
clear_aggregation_cache
@attributes_cache = {}
@new_record = true
ensure_proper_type
- @changed_attributes = other.changed_attributes.dup
if scope = self.class.send(:current_scoped_methods)
create_with = scope.scope_for_create
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
new file mode 100644
index 0000000000..4118ea7b31
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
@@ -0,0 +1,57 @@
+module ActiveRecord
+ module ConnectionAdapters # :nodoc:
+ module DatabaseLimits
+
+ # the maximum length of a table alias
+ def table_alias_length
+ 255
+ end
+
+ # the maximum length of a column name
+ def column_name_length
+ 64
+ end
+
+ # the maximum length of a table name
+ def table_name_length
+ 64
+ end
+
+ # the maximum length of an index name
+ def index_name_length
+ 64
+ end
+
+ # the maximum number of columns per table
+ def columns_per_table
+ 1024
+ end
+
+ # the maximum number of indexes per table
+ def indexes_per_table
+ 16
+ end
+
+ # the maximum number of columns in a multicolumn index
+ def columns_per_multicolumn_index
+ 16
+ end
+
+ # the maximum number of elements in an IN (x,y,z) clause
+ def in_clause_length
+ 65535
+ end
+
+ # the maximum length of a SQL query
+ def sql_query_length
+ 1048575
+ end
+
+ # maximum number of joins in a single query
+ def joins_per_query
+ 256
+ end
+
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 1255ef09be..d3499cea72 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -10,11 +10,6 @@ module ActiveRecord
{}
end
- # This is the maximum length a table alias can be
- def table_alias_length
- 255
- end
-
# Truncates a table alias according to the limits of the current adapter.
def table_alias_for(table_name)
table_name[0..table_alias_length-1].gsub(/\./, '_')
@@ -293,6 +288,14 @@ module ActiveRecord
index_type = options
end
+ if index_name.length > index_name_length
+ @logger.warn("Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters. Skipping.")
+ return
+ end
+ if index_exists?(table_name, index_name, false)
+ @logger.warn("Index name '#{index_name}' on table '#{table_name}' already exists. Skipping.")
+ return
+ end
quoted_column_names = quoted_columns_for_index(column_names, options).join(", ")
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
@@ -309,7 +312,28 @@ module ActiveRecord
# Remove the index named by_branch_party in the accounts table.
# remove_index :accounts, :name => :by_branch_party
def remove_index(table_name, options = {})
- execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{quote_table_name(table_name)}"
+ index_name = index_name(table_name, options)
+ unless index_exists?(table_name, index_name, true)
+ @logger.warn("Index name '#{index_name}' on table '#{table_name}' does not exist. Skipping.")
+ return
+ end
+ remove_index!(table_name, index_name)
+ end
+
+ def remove_index!(table_name, index_name) #:nodoc:
+ execute "DROP INDEX #{quote_column_name(index_name)} ON #{table_name}"
+ end
+
+ # Rename an index.
+ #
+ # Rename the index_people_on_last_name index to index_users_on_last_name
+ # rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
+ def rename_index(table_name, old_name, new_name)
+ # this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
+ old_index_def = indexes(table_name).detect { |i| i.name == old_name }
+ return unless old_index_def
+ remove_index(table_name, :name => old_name)
+ add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique)
end
def index_name(table_name, options) #:nodoc:
@@ -326,6 +350,15 @@ module ActiveRecord
end
end
+ # Verify the existence of an index.
+ #
+ # The default argument is returned if the underlying implementation does not define the indexes method,
+ # as there's no way to determine the correct answer in that case.
+ def index_exists?(table_name, index_name, default)
+ return default unless respond_to?(:indexes)
+ indexes(table_name).detect { |i| i.name == index_name }
+ end
+
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
# entire structure of the database.
def structure_dump
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 28a59c1e62..fecd4d590e 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -11,6 +11,7 @@ require 'active_record/connection_adapters/abstract/quoting'
require 'active_record/connection_adapters/abstract/connection_pool'
require 'active_record/connection_adapters/abstract/connection_specification'
require 'active_record/connection_adapters/abstract/query_cache'
+require 'active_record/connection_adapters/abstract/database_limits'
module ActiveRecord
module ConnectionAdapters # :nodoc:
@@ -29,6 +30,7 @@ module ActiveRecord
# notably, the instance methods provided by SchemaStatement are very useful.
class AbstractAdapter
include Quoting, DatabaseStatements, SchemaStatements
+ include DatabaseLimits
include QueryCache
include ActiveSupport::Callbacks
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index e12924e63f..ec25bbf18e 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -513,7 +513,7 @@ module ActiveRecord
def change_column(table_name, column_name, type, options = {}) #:nodoc:
column = column_for(table_name, column_name)
- if has_default?(type) && !options_include_default?(options)
+ unless options_include_default?(options)
options[:default] = column.default
end
@@ -675,10 +675,6 @@ module ActiveRecord
end
column
end
-
- def has_default?(sql_type)
- sql_type =~ :binary || sql_type == :text #mysql forbids defaults on blob and text columns
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 6389094b8a..34aaff2b49 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -819,9 +819,12 @@ module ActiveRecord
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
end
- # Drops an index from a table.
- def remove_index(table_name, options = {})
- execute "DROP INDEX #{quote_table_name(index_name(table_name, options))}"
+ def remove_index!(table_name, index_name) #:nodoc:
+ execute "DROP INDEX #{quote_table_name(index_name)}"
+ end
+
+ def index_name_length
+ 63
end
# Maps logical Rails types to PostgreSQL-specific data types.
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 29225b83c5..e8a45bb3c6 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -217,8 +217,8 @@ module ActiveRecord
column ? column['name'] : nil
end
- def remove_index(table_name, options={}) #:nodoc:
- execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
+ def remove_index!(table_name, index_name) #:nodoc:
+ execute "DROP INDEX #{quote_column_name(index_name)}"
end
def rename_table(name, new_name)
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index 9dda3361d8..931872eded 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -307,7 +307,7 @@ module ActiveRecord
end
end
- return true
+ sid
end
def get_session_model(env, sid)