diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract')
9 files changed, 274 insertions, 154 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 816b397fcf..db80c0faee 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -58,13 +58,11 @@ module ActiveRecord # * +checkout_timeout+: number of seconds to block and wait for a connection # before giving up and raising a timeout error (default 5 seconds). # * +reaping_frequency+: frequency in seconds to periodically run the - # Reaper, which attempts to find and close dead connections, which can - # occur if a programmer forgets to close a connection at the end of a - # thread or a thread dies unexpectedly. (Default nil, which means don't - # run the Reaper). - # * +dead_connection_timeout+: number of seconds from last checkout - # after which the Reaper will consider a connection reapable. (default - # 5 seconds). + # Reaper, which attempts to find and recover connections from dead + # threads, which can occur if a programmer forgets to close a + # connection at the end of a thread or a thread dies unexpectedly. + # Regardless of this setting, the Reaper will be invoked before every + # blocking wait. (Default nil, which means don't schedule the Reaper). class ConnectionPool # Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool # with which it shares a Monitor. But could be a generic Queue. @@ -86,7 +84,7 @@ module ActiveRecord end end - # Return the number of threads currently waiting on this + # Returns the number of threads currently waiting on this # queue. def num_waiting synchronize do @@ -222,7 +220,7 @@ module ActiveRecord include MonitorMixin - attr_accessor :automatic_reconnect, :checkout_timeout, :dead_connection_timeout + attr_accessor :automatic_reconnect, :checkout_timeout attr_reader :spec, :connections, :size, :reaper # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification @@ -237,7 +235,6 @@ module ActiveRecord @spec = spec @checkout_timeout = spec.config[:checkout_timeout] || 5 - @dead_connection_timeout = spec.config[:dead_connection_timeout] || 5 @reaper = Reaper.new self, spec.config[:reaping_frequency] @reaper.run @@ -332,11 +329,6 @@ module ActiveRecord end end - def clear_stale_cached_connections! # :nodoc: - reap - end - deprecate :clear_stale_cached_connections! => "Please use #reap instead" - # Check-out a database connection from the pool, indicating that you want # to use it. You should call #checkin when you no longer need this. # @@ -366,11 +358,13 @@ module ActiveRecord # calling +checkout+ on this pool. def checkin(conn) synchronize do + owner = conn.owner + conn.run_callbacks :checkin do conn.expire end - release conn + release conn, owner @available.add conn end @@ -383,22 +377,28 @@ module ActiveRecord @connections.delete conn @available.delete conn - # FIXME: we might want to store the key on the connection so that removing - # from the reserved hash will be a little easier. - release conn + release conn, conn.owner @available.add checkout_new_connection if @available.any_waiting? end end - # Removes dead connections from the pool. A dead connection can occur - # if a programmer forgets to close a connection at the end of a thread + # Recover lost connections for the pool. A lost connection can occur if + # a programmer forgets to checkin a connection at the end of a thread # or a thread dies unexpectedly. def reap - synchronize do - stale = Time.now - @dead_connection_timeout - connections.dup.each do |conn| - if conn.in_use? && stale > conn.last_use && !conn.active? + stale_connections = synchronize do + @connections.select do |conn| + conn.in_use? && !conn.owner.alive? + end + end + + stale_connections.each do |conn| + synchronize do + if conn.active? + conn.reset! + checkin conn + else remove conn end end @@ -420,20 +420,15 @@ module ActiveRecord elsif @connections.size < @size checkout_new_connection else + reap @available.poll(@checkout_timeout) end end - def release(conn) - thread_id = if @reserved_connections[current_connection_id] == conn - current_connection_id - else - @reserved_connections.keys.find { |k| - @reserved_connections[k] == conn - } - end + def release(conn, owner) + thread_id = owner.object_id - @reserved_connections.delete thread_id if thread_id + @reserved_connections.delete thread_id end def new_connection @@ -543,7 +538,10 @@ module ActiveRecord # for (not necessarily the current class). def retrieve_connection(klass) #:nodoc: pool = retrieve_connection_pool(klass) - (pool && pool.connection) or raise ConnectionNotEstablished + raise ConnectionNotEstablished, "No connection pool for #{klass}" unless pool + conn = pool.connection + raise ConnectionNotEstablished, "No connection for #{klass} in connection pool" unless conn + conn end # Returns true if a connection that's accessible to this class has @@ -629,7 +627,7 @@ module ActiveRecord end response - rescue + rescue Exception ActiveRecord::Base.clear_active_connections! unless testing raise end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index c64b542286..bc47412405 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -9,26 +9,33 @@ module ActiveRecord # Converts an arel AST to SQL def to_sql(arel, binds = []) if arel.respond_to?(:ast) - binds = binds.dup - visitor.accept(arel.ast) do - quote(*binds.shift.reverse) - end + collected = visitor.accept(arel.ast, collector) + collected.compile(binds.dup, self) else arel end end - # Returns an array of record hashes with the column names as keys and - # column values as values. + # This is used in the StatementCache object. It returns an object that + # can be used to query the database repeatedly. + def cacheable_query(arel) # :nodoc: + if prepared_statements + ActiveRecord::StatementCache.query visitor, arel.ast + else + ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector + end + end + + # Returns an ActiveRecord::Result instance. def select_all(arel, name = nil, binds = []) + arel, binds = binds_from_relation arel, binds select(to_sql(arel, binds), name, binds) end # Returns a record hash with the column names as keys and column values # as values. def select_one(arel, name = nil, binds = []) - result = select_all(arel, name, binds) - result.first if result + select_all(arel, name, binds).first end # Returns a single value from a record @@ -41,13 +48,13 @@ module ActiveRecord # Returns an array of the values of the first column in a select: # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3] def select_values(arel, name = nil) - result = select_rows(to_sql(arel, []), name) - result.map { |v| v[0] } + arel, binds = binds_from_relation arel, [] + select_rows(to_sql(arel, binds), name, binds).map(&:first) end # Returns an array of arrays containing the field values. # Order is the same as that returned by +columns+. - def select_rows(sql, name = nil) + def select_rows(sql, name = nil, binds = []) end undef_method :select_rows @@ -303,10 +310,6 @@ module ActiveRecord "DEFAULT VALUES" end - def case_sensitive_equality_operator - "=" - end - def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})" end @@ -323,7 +326,7 @@ module ActiveRecord def sanitize_limit(limit) if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral) limit - elsif limit.to_s =~ /,/ + elsif limit.to_s.include?(',') Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',') else Integer(limit) @@ -348,15 +351,14 @@ module ActiveRecord protected - # Return a subquery for the given key using the join information. + # Returns a subquery for the given key using the join information. def subquery_for(key, select) subselect = select.clone subselect.projections = [key] subselect end - # Returns an array of record hashes with the column names as keys and - # column values as values. + # Returns an ActiveRecord::Result instance. def select(sql, name = nil, binds = []) end undef_method :select @@ -377,14 +379,21 @@ module ActiveRecord update_sql(sql, name) end - def sql_for_insert(sql, pk, id_value, sequence_name, binds) - [sql, binds] - end + def sql_for_insert(sql, pk, id_value, sequence_name, binds) + [sql, binds] + end - def last_inserted_id(result) - row = result.rows.first - row && row.first - end + def last_inserted_id(result) + row = result.rows.first + row && row.first + end + + def binds_from_relation(relation, binds) + if relation.is_a?(Relation) && binds.empty? + relation, binds = relation.arel, relation.bind_values + end + [relation, binds] + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 41e07fbda9..4a4506c7f5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -9,10 +9,10 @@ module ActiveRecord def dirties_query_cache(base, *method_names) method_names.each do |method_name| base.class_eval <<-end_code, __FILE__, __LINE__ + 1 - def #{method_name}(*) # def update_with_query_dirty(*) - clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled - super # super - end # end + def #{method_name}(*) + clear_query_cache if @query_cache_enabled + super + end end_code end end @@ -20,13 +20,19 @@ module ActiveRecord attr_reader :query_cache, :query_cache_enabled + def initialize(*) + super + @query_cache = Hash.new { |h,sql| h[sql] = {} } + @query_cache_enabled = false + end + # Enable the query cache within the block. def cache old, @query_cache_enabled = @query_cache_enabled, true yield ensure - clear_query_cache @query_cache_enabled = old + clear_query_cache unless @query_cache_enabled end def enable_query_cache! @@ -57,6 +63,7 @@ module ActiveRecord def select_all(arel, name = nil, binds = []) if @query_cache_enabled && !locked?(arel) + arel, binds = binds_from_relation arel, binds sql = to_sql(arel, binds) cache_sql(sql, binds) { super(sql, name, binds) } else @@ -75,14 +82,7 @@ module ActiveRecord else @query_cache[sql][binds] = yield end - - # FIXME: we should guarantee that all cached items are Result - # objects. Then we can avoid this conditional - if ActiveRecord::Result === result - result.dup - else - result.collect { |row| row.dup } - end + result.dup end # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index d18b9c991f..75501852ed 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -15,7 +15,6 @@ module ActiveRecord return "'#{quote_string(value)}'" unless column case column.type - when :binary then "'#{quote_string(column.string_to_binary(value))}'" when :integer then value.to_i.to_s when :float then value.to_f.to_s else @@ -44,7 +43,9 @@ module ActiveRecord # SQLite does not understand dates, so this method will convert a Date # to a String. def type_cast(value, column) - return value.id if value.respond_to?(:quoted_id) + if value.respond_to?(:quoted_id) && value.respond_to?(:id) + return value.id + end case value when String, ActiveSupport::Multibyte::Chars @@ -52,7 +53,6 @@ module ActiveRecord return value unless column case column.type - when :binary then value when :integer then value.to_i when :float then value.to_f else diff --git a/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb b/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb new file mode 100644 index 0000000000..25c17ce971 --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/abstract/savepoints.rb @@ -0,0 +1,21 @@ +module ActiveRecord + module ConnectionAdapters + module Savepoints #:nodoc: + def supports_savepoints? + true + end + + def create_savepoint(name = current_savepoint_name) + execute("SAVEPOINT #{name}") + end + + def rollback_to_savepoint(name = current_savepoint_name) + execute("ROLLBACK TO SAVEPOINT #{name}") + end + + def release_savepoint(name = current_savepoint_name) + execute("RELEASE SAVEPOINT #{name}") + end + end + end +end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb new file mode 100644 index 0000000000..47fe501752 --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -0,0 +1,90 @@ +module ActiveRecord + module ConnectionAdapters + class AbstractAdapter + class SchemaCreation # :nodoc: + def initialize(conn) + @conn = conn + @cache = {} + end + + def accept(o) + m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}" + send m, o + end + + def visit_AddColumn(o) + sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale) + sql = "ADD #{quote_column_name(o.name)} #{sql_type}" + add_column_options!(sql, column_options(o)) + end + + private + + def visit_AlterTable(o) + sql = "ALTER TABLE #{quote_table_name(o.name)} " + sql << o.adds.map { |col| visit_AddColumn col }.join(' ') + end + + def visit_ColumnDefinition(o) + sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale) + column_sql = "#{quote_column_name(o.name)} #{sql_type}" + add_column_options!(column_sql, column_options(o)) unless o.primary_key? + column_sql + end + + def visit_TableDefinition(o) + create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE " + create_sql << "#{quote_table_name(o.name)} " + create_sql << "(#{o.columns.map { |c| accept c }.join(', ')}) " unless o.as + create_sql << "#{o.options}" + create_sql << " AS #{@conn.to_sql(o.as)}" if o.as + create_sql + end + + def column_options(o) + column_options = {} + column_options[:null] = o.null unless o.null.nil? + column_options[:default] = o.default unless o.default.nil? + column_options[:column] = o + column_options[:first] = o.first + column_options[:after] = o.after + column_options + end + + def quote_column_name(name) + @conn.quote_column_name name + end + + def quote_table_name(name) + @conn.quote_table_name name + end + + def type_to_sql(type, limit, precision, scale) + @conn.type_to_sql type.to_sym, limit, precision, scale + end + + def add_column_options!(sql, options) + sql << " DEFAULT #{quote_value(options[:default], options[:column])}" if options_include_default?(options) + # must explicitly check for :null to allow change_column to work on migrations + if options[:null] == false + sql << " NOT NULL" + end + if options[:auto_increment] == true + sql << " AUTO_INCREMENT" + end + sql + end + + def quote_value(value, column) + column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale) + + @conn.quote(value, column) + end + + def options_include_default?(options) + options.include?(:default) && !(options[:null] == false && options[:default].nil?) + end + end + end + end +end 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 0be4b5cb19..71c3a4378b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -15,10 +15,7 @@ module ActiveRecord # are typically created by methods in TableDefinition, and added to the # +columns+ attribute of said TableDefinition object, in order to be used # for generating a number of table creation or table changing SQL statements. - class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key) #:nodoc: - def string_to_binary(value) - value - end + class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type) #:nodoc: def primary_key? primary_key || type.to_sym == :primary_key @@ -52,14 +49,15 @@ module ActiveRecord # An array of ColumnDefinition objects, representing the column changes # that have been defined. attr_accessor :indexes - attr_reader :name, :temporary, :options + attr_reader :name, :temporary, :options, :as - def initialize(types, name, temporary, options) + def initialize(types, name, temporary, options, as = nil) @columns_hash = {} @indexes = {} @native = types @temporary = temporary @options = options + @as = as @name = name 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 9a1923dec5..ffa6af6d99 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -40,7 +40,7 @@ module ActiveRecord # index_exists?(:suppliers, :company_id, unique: true) # # # Check an index with a custom name exists - # index_exists?(:suppliers, :company_id, name: "idx_company_id" + # index_exists?(:suppliers, :company_id, name: "idx_company_id") # def index_exists?(table_name, column_name, options = {}) column_names = Array(column_name) @@ -71,7 +71,8 @@ module ActiveRecord # column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2) # def column_exists?(table_name, column_name, type = nil, options = {}) - columns(table_name).any?{ |c| c.name == column_name.to_s && + column_name = column_name.to_s + columns(table_name).any?{ |c| c.name == column_name && (!type || c.type == type) && (!options.key?(:limit) || c.limit == options[:limit]) && (!options.key?(:precision) || c.precision == options[:precision]) && @@ -120,9 +121,9 @@ module ActiveRecord # The name of the primary key, if one is to be added automatically. # Defaults to +id+. If <tt>:id</tt> is false this option is ignored. # - # Also note that this just sets the primary key in the table. You additionally - # need to configure the primary key in the model via +self.primary_key=+. - # Models do NOT auto-detect the primary key from their table definition. + # Note that Active Record models will automatically detect their + # primary key. This can be avoided by using +self.primary_key=+ on the model + # to define the key explicitly. # # [<tt>:options</tt>] # Any extra options you want appended to the table definition. @@ -131,6 +132,9 @@ module ActiveRecord # [<tt>:force</tt>] # Set to true to drop the table before creating it. # Defaults to false. + # [<tt>:as</tt>] + # SQL to use to generate the table. When this option is used, the block is + # ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options. # # ====== Add a backend specific option to the generated SQL (MySQL) # @@ -169,14 +173,24 @@ module ActiveRecord # supplier_id int # ) # + # ====== Create a temporary table based on a query + # + # create_table(:long_query, temporary: true, + # as: "SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id") + # + # generates: + # + # CREATE TEMPORARY TABLE long_query AS + # SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id + # # See also TableDefinition#column for details on how to create columns. def create_table(table_name, options = {}) - td = create_table_definition table_name, options[:temporary], options[:options] + td = create_table_definition table_name, options[:temporary], options[:options], options[:as] - unless options[:id] == false - pk = options.fetch(:primary_key) { + if options[:id] != false && !options[:as] + pk = options.fetch(:primary_key) do Base.get_primary_key table_name.to_s.singularize - } + end td.primary_key pk, options.fetch(:id, :primary_key), options end @@ -187,8 +201,9 @@ module ActiveRecord drop_table(table_name, options) end - execute schema_creation.accept td - td.indexes.each_pair { |c,o| add_index table_name, c, o } + result = execute schema_creation.accept td + td.indexes.each_pair { |c, o| add_index(table_name, c, o) } unless supports_indexes_in_create? + result end # Creates a new join table with the name created using the lexical order of the first two @@ -558,8 +573,8 @@ module ActiveRecord # 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) + add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique) + remove_index(table_name, name: old_name) end def index_name(table_name, options) #:nodoc: @@ -690,25 +705,16 @@ module ActiveRecord column_type_sql else - type + type.to_s end end - # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. - # - # distinct("posts.id", ["posts.created_at desc"]) - # - def distinct(columns, order_by) - ActiveSupport::Deprecation.warn("#distinct is deprecated and shall be removed from future releases.") - "DISTINCT #{columns_for_distinct(columns, order_by)}" - end - # Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT. # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax - they # require the order columns appear in the SELECT. # # columns_for_distinct("posts.id", ["posts.created_at desc"]) - def columns_for_distinct(columns, orders) # :nodoc: + def columns_for_distinct(columns, orders) #:nodoc: columns end @@ -730,6 +736,44 @@ module ActiveRecord remove_column table_name, :created_at end + def update_table_definition(table_name, base) #:nodoc: + Table.new(table_name, base) + end + + def add_index_options(table_name, column_name, options = {}) #:nodoc: + column_names = Array(column_name) + index_name = index_name(table_name, column: column_names) + + options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type) + + index_type = options[:unique] ? "UNIQUE" : "" + index_type = options[:type].to_s if options.key?(:type) + index_name = options[:name].to_s if options.key?(:name) + max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length + + if options.key?(:algorithm) + algorithm = index_algorithms.fetch(options[:algorithm]) { + raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") + } + end + + using = "USING #{options[:using]}" if options[:using].present? + + if supports_partial_index? + index_options = options[:where] ? " WHERE #{options[:where]}" : "" + end + + if index_name.length > max_index_length + raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters" + end + if table_exists?(table_name) && index_name_exists?(table_name, index_name, false) + raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists" + end + index_columns = quoted_columns_for_index(column_names, options).join(", ") + + [index_name, index_type, index_columns, index_options, algorithm, using] + end + protected def add_index_sort_order(option_strings, column_names, options = {}) if options.is_a?(Hash) && order = options[:order] @@ -760,40 +804,6 @@ module ActiveRecord options.include?(:default) && !(options[:null] == false && options[:default].nil?) end - def add_index_options(table_name, column_name, options = {}) - column_names = Array(column_name) - index_name = index_name(table_name, column: column_names) - - options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type) - - index_type = options[:unique] ? "UNIQUE" : "" - index_type = options[:type].to_s if options.key?(:type) - index_name = options[:name].to_s if options.key?(:name) - max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length - - if options.key?(:algorithm) - algorithm = index_algorithms.fetch(options[:algorithm]) { - raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") - } - end - - using = "USING #{options[:using]}" if options[:using].present? - - if supports_partial_index? - index_options = options[:where] ? " WHERE #{options[:where]}" : "" - end - - if index_name.length > max_index_length - raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters" - end - if index_name_exists?(table_name, index_name, false) - raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists" - end - index_columns = quoted_columns_for_index(column_names, options).join(", ") - - [index_name, index_type, index_columns, index_options, algorithm, using] - end - def index_name_for_remove(table_name, options = {}) index_name = index_name(table_name, options) @@ -812,12 +822,6 @@ module ActiveRecord index_name end - def columns_for_remove(table_name, *column_names) - ActiveSupport::Deprecation.warn("columns_for_remove is deprecated and will be removed in the future") - raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)") if column_names.blank? - column_names.map {|column_name| quote_column_name(column_name) } - end - def rename_table_indexes(table_name, new_name) indexes(new_name).each do |index| generated_index_name = index_name(table_name, column: index.columns) @@ -841,17 +845,13 @@ module ActiveRecord end private - def create_table_definition(name, temporary, options) - TableDefinition.new native_database_types, name, temporary, options + def create_table_definition(name, temporary, options, as = nil) + TableDefinition.new native_database_types, name, temporary, options, as end def create_alter_table(name) AlterTable.new create_table_definition(name, false, {}) end - - def update_table_definition(table_name, base) - Table.new(table_name, base) - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index 2b6685499a..bc4884b538 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -23,6 +23,10 @@ module ActiveRecord @parent = nil end + def finalized? + @state + end + def committed? @state == :committed end |