# module ActiveRecord::ConnectionAdapters::SchemaStatements

### Public Instance Methods

add_belongs_to(table_name, ref_name, **options)
Alias for: add_reference
add_column(table_name, column_name, type, options = {}) click to toggle source

Add a new `type` column named `column_name` to `table_name`.

The `type` parameter is normally one of the migrations native types, which is one of the following: `:primary_key`, `:string`, `:text`, `:integer`, `:bigint`, `:float`, `:decimal`, `:numeric`, `:datetime`, `:time`, `:date`, `:binary`, `:boolean`.

You may use a type not in this list as long as it is supported by your database (for example, “polygon” in MySQL), but this will not be database agnostic and should usually be avoided.

Available options are (none of these exists by default):

- `:limit` - Requests a maximum column length. This is the number of characters for a `:string` column and number of bytes for `:text`, `:binary` and `:integer` columns.

- `:default` - The column's default value. Use `nil` for `NULL`.

- `:null` - Allows or disallows `NULL` values in the column. This option could have been named `:null_allowed`.

- `:precision` - Specifies the precision for the `:decimal` and `:numeric` columns.

- `:scale` - Specifies the scale for the `:decimal` and `:numeric` columns.

Note: The precision is the total number of significant digits, and the scale is the number of digits that can be stored following the decimal point. For example, the number 123.45 has a precision of 5 and a scale of 2. A decimal with a precision of 5 and a scale of 2 can range from -999.99 to 999.99.

Please be aware of different RDBMS implementations behavior with `:decimal` columns:

- The SQL standard says the default scale should be 0, `:scale` <= `:precision`, and makes no comments about the requirements of `:precision`.

- MySQL: `:precision` [1..63], `:scale` [0..30]. Default is (10,0).

- PostgreSQL: `:precision` [1..infinity], `:scale` [0..infinity]. No default.

- SQLite3: No restrictions on `:precision` and `:scale`, but the maximum supported `:precision` is 16. No default.

- Oracle: `:precision` [1..38], `:scale` [-84..127]. Default is (38,0).

- DB2: `:precision` [1..63], `:scale` [0..62]. Default unknown.

- SqlServer: `:precision` [1..38], `:scale` [0..38]. Default (38,0).

## Examples¶ ↑

    add_column(:users, :picture, :binary, limit: 2.megabytes)
    # ALTER TABLE "users" ADD "picture" blob(2097152)

    add_column(:articles, :status, :string, limit: 20, default: 'draft', null: false)
    # ALTER TABLE "articles" ADD "status" varchar(20) DEFAULT 'draft' NOT NULL

    add_column(:answers, :bill_gates_money, :decimal, precision: 15, scale: 2)
    # ALTER TABLE "answers" ADD "bill_gates_money" decimal(15,2)

    add_column(:measurements, :sensor_reading, :decimal, precision: 30, scale: 20)
    # ALTER TABLE "measurements" ADD "sensor_reading" decimal(30,20)

    # While :scale defaults to zero on most databases, it
    # probably wouldn't hurt to include it.
    add_column(:measurements, :huge_integer, :decimal, precision: 30)
    # ALTER TABLE "measurements" ADD "huge_integer" decimal(30)

    # Defines a column that stores an array of a type.
    add_column(:users, :skills, :text, array: true)
    # ALTER TABLE "users" ADD "skills" text[]

    # Defines a column with a database-specific type.
    add_column(:shapes, :triangle, 'polygon')
    # ALTER TABLE "shapes" ADD "triangle" polygon

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 551
    def add_column(table_name, column_name, type, options = {})
      at = create_alter_table table_name
      at.add_column(column_name, type, options)
      execute schema_creation.accept at
    end

add_foreign_key(from_table, to_table, options = {}) click to toggle source

Adds a new foreign key. `from_table` is the table with the key column, `to_table` contains the referenced primary key.

The foreign key will be named after the following pattern: `fk_rails_<identifier>`. `identifier` is a 10 character long string which is deterministically generated from the `from_table` and `column`. A custom name can be specified with the `:name` option.

###### Creating a simple foreign key¶ ↑

    add_foreign_key :articles, :authors

generates:

    ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")

###### Creating a foreign key on a specific column¶ ↑

    add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"

generates:

    ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id")

###### Creating a cascading foreign key¶ ↑

    add_foreign_key :articles, :authors, on_delete: :cascade

generates:

    ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE

The `options` hash can include the following keys:

`:column`

  The foreign key column name on `from_table`. Defaults to `to_table.singularize + "_id"`

`:primary_key`

  The primary key column name on `to_table`. Defaults to `id`.

`:name`

  The constraint name. Defaults to `fk_rails_<identifier>`.

`:on_delete`

  Action that happens `ON DELETE`. Valid values are `:nullify`, `:cascade` and `:restrict`

`:on_update`

  Action that happens `ON UPDATE`. Valid values are `:nullify`, `:cascade` and `:restrict`

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 923
    def add_foreign_key(from_table, to_table, options = {})
      return unless supports_foreign_keys?

      options = foreign_key_options(from_table, to_table, options)
      at = create_alter_table from_table
      at.add_foreign_key to_table, options

      execute schema_creation.accept(at)
    end

add_index(table_name, column_name, options = {}) click to toggle source

Adds a new index to the table. `column_name` can be a single Symbol, or an Array of Symbols.

The index will be named after the table and the column name(s), unless you pass `:name` as an option.

###### Creating a simple index¶ ↑

    add_index(:suppliers, :name)

generates:

    CREATE INDEX suppliers_name_index ON suppliers(name)

###### Creating a unique index¶ ↑

    add_index(:accounts, [:branch_id, :party_id], unique: true)

generates:

    CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)

###### Creating a named index¶ ↑

    add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')

generates:

    CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)

###### Creating an index with specific key length¶ ↑

    add_index(:accounts, :name, name: 'by_name', length: 10)

generates:

    CREATE INDEX by_name ON accounts(name(10))

###### Creating an index with specific key lengths for multiple keys¶ ↑

    add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})

generates:

    CREATE INDEX by_name_surname ON accounts(name(10), surname(15))

Note: SQLite doesn't support index length.

###### Creating an index with a sort order (desc or asc, asc is the default)¶ ↑

    add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})

generates:

    CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)

Note: MySQL doesn't yet support index order (it accepts the syntax but ignores it).

###### Creating a partial index¶ ↑

    add_index(:accounts, [:branch_id, :party_id], unique: true, where: "active")

generates:

    CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active

Note: Partial indexes are only supported for PostgreSQL and SQLite 3.8.0+.

###### Creating an index with a specific method¶ ↑

    add_index(:developers, :name, using: 'btree')

generates:

    CREATE INDEX index_developers_on_name ON developers USING btree (name) -- PostgreSQL
    CREATE INDEX index_developers_on_name USING btree ON developers (name) -- MySQL

Note: only supported by PostgreSQL and MySQL

###### Creating an index with a specific type¶ ↑

    add_index(:developers, :name, type: :fulltext)

generates:

    CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL

Note: only supported by MySQL.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 723
    def add_index(table_name, column_name, options = {})
      index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
      execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
    end

add_reference(table_name, ref_name, **options) click to toggle source

Adds a reference. The reference column is an integer by default, the `:type` option can be used to specify a different type. Optionally adds a `_type` column, if `:polymorphic` option is provided. add_reference and add_belongs_to are acceptable.

The `options` hash can include the following keys:

`:type`

  The reference column type. Defaults to `:integer`.

`:index`

  Add an appropriate index. Defaults to true. See add_index for usage of this option.

`:foreign_key`

  Add an appropriate foreign key constraint. Defaults to false.

`:polymorphic`

  Whether an additional `_type` column should be added. Defaults to false.

`:null`

  Whether the column allows nulls. Defaults to true.

###### Create a user_id integer column¶ ↑

    add_reference(:products, :user)

###### Create a user_id string column¶ ↑

    add_reference(:products, :user, type: :string)

###### Create supplier_id, supplier_type columns and appropriate index¶ ↑

    add_reference(:products, :supplier, polymorphic: true, index: true)

###### Create a supplier_id column with a unique index¶ ↑

    add_reference(:products, :supplier, index: { unique: true })

###### Create a supplier_id column with a named index¶ ↑

    add_reference(:products, :supplier, index: { name: "my_supplier_index" })

###### Create a supplier_id column and appropriate foreign key¶ ↑

    add_reference(:products, :supplier, foreign_key: true)

###### Create a supplier_id column and a foreign key to the firms table¶ ↑

    add_reference(:products, :supplier, foreign_key: {to_table: :firms})

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 838
    def add_reference(table_name, ref_name, **options)
      ReferenceDefinition.new(ref_name, options).add_to(update_table_definition(table_name, self))
    end

Also aliased as: add_belongs_to
add_timestamps(table_name, options = {}) click to toggle source

Adds timestamps (`created_at` and `updated_at`) columns to `table_name`. Additional options (like `:null`) are forwarded to add_column.

    add_timestamps(:suppliers, null: true)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1111
    def add_timestamps(table_name, options = {})
      options[:null] = false if options[:null].nil?

      add_column table_name, :created_at, :datetime, options
      add_column table_name, :updated_at, :datetime, options
    end

assume_migrated_upto_version(version, migrations_paths) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1033
    def assume_migrated_upto_version(version, migrations_paths)
      migrations_paths = Array(migrations_paths)
      version = version.to_i
      sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)

      migrated = ActiveRecord::SchemaMigration.all_versions.map(&:to_i)
      versions = ActiveRecord::Migrator.migration_files(migrations_paths).map do |file|
        ActiveRecord::Migrator.parse_migration_filename(file).first.to_i
      end

      unless migrated.include?(version)
        execute "INSERT INTO #{sm_table} (version) VALUES (#{quote(version)})"
      end

      inserting = (versions - migrated).select { |v| v < version }
      if inserting.any?
        if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
          raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
        end
        if supports_multi_insert?
          execute insert_versions_sql(inserting)
        else
          inserting.each do |v|
            execute insert_versions_sql(v)
          end
        end
      end
    end

change_column(table_name, column_name, type, options = {}) click to toggle source

Changes the column's definition according to the new options. See ActiveRecord::ConnectionAdapters::TableDefinition#column for details of the options you can use.

    change_column(:suppliers, :name, :string, limit: 80)
    change_column(:accounts, :description, :text)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 585
    def change_column(table_name, column_name, type, options = {})
      raise NotImplementedError, "change_column is not implemented"
    end

change_column_default(table_name, column_name, default_or_changes) click to toggle source

Sets a new default value for a column:

    change_column_default(:suppliers, :qualification, 'new')
    change_column_default(:accounts, :authorized, 1)

Setting the default to `nil` effectively drops the default:

    change_column_default(:users, :email, nil)

Passing a hash containing `:from` and `:to` will make this change reversible in migration:

    change_column_default(:posts, :state, from: nil, to: "draft")

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 603
    def change_column_default(table_name, column_name, default_or_changes)
      raise NotImplementedError, "change_column_default is not implemented"
    end

change_column_null(table_name, column_name, null, default = nil) click to toggle source

Sets or removes a `NOT NULL` constraint on a column. The `null` flag indicates whether the value can be `NULL`. For example

    change_column_null(:users, :nickname, false)

says nicknames cannot be `NULL` (adds the constraint), whereas

    change_column_null(:users, :nickname, true)

allows them to be `NULL` (drops the constraint).

The method accepts an optional fourth argument to replace existing `NULL`s with some other value. Use that one when enabling the constraint if needed, since otherwise those rows would not be valid.

Please note the fourth argument does not set a column's default.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 623
    def change_column_null(table_name, column_name, null, default = nil)
      raise NotImplementedError, "change_column_null is not implemented"
    end

change_table(table_name, options = {}) { |update_table_definition(table_name, recorder)| ... } click to toggle source

A block for changing columns in `table`.

    # change_table() yields a Table instance
    change_table(:suppliers) do |t|
      t.column :name, :string, limit: 60
      # Other column alterations here
    end

The `options` hash can include the following keys:

`:bulk`

  Set this to true to make this a bulk alter query, such as

      ALTER TABLE `users` ADD COLUMN age INT, ADD COLUMN birthdate DATETIME ...

  Defaults to false.

###### Add a column¶ ↑

    change_table(:suppliers) do |t|
      t.column :name, :string, limit: 60
    end

###### Add 2 integer columns¶ ↑

    change_table(:suppliers) do |t|
      t.integer :width, :height, null: false, default: 0
    end

###### Add created_at/updated_at columns¶ ↑

    change_table(:suppliers) do |t|
      t.timestamps
    end

###### Add a foreign key column¶ ↑

    change_table(:suppliers) do |t|
      t.references :company
    end

Creates a `company_id(integer)` column.

###### Add a polymorphic foreign key column¶ ↑

    change_table(:suppliers) do |t|
      t.belongs_to :company, polymorphic: true
    end

Creates `company_type(varchar)` and `company_id(integer)` columns.

###### Remove a column¶ ↑

    change_table(:suppliers) do |t|
      t.remove :company
    end

###### Remove several columns¶ ↑

    change_table(:suppliers) do |t|
      t.remove :company_id
      t.remove :width, :height
    end

###### Remove an index¶ ↑

    change_table(:suppliers) do |t|
      t.remove_index :company_id
    end

See also Table for details on all of the various column transformations.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 440
    def change_table(table_name, options = {})
      if supports_bulk_alter? && options[:bulk]
        recorder = ActiveRecord::Migration::CommandRecorder.new(self)
        yield update_table_definition(table_name, recorder)
        bulk_change_table(table_name, recorder.commands)
      else
        yield update_table_definition(table_name, self)
      end
    end

change_table_comment(table_name, comment) click to toggle source

Changes the comment for a table or removes it if `nil`.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1168
    def change_table_comment(table_name, comment)
      raise NotImplementedError, "#{self.class} does not support changing table comments"
    end

column_exists?(table_name, column_name, type = nil, options = {}) click to toggle source

Checks to see if a column exists in a given table.

    # Check a column exists
    column_exists?(:suppliers, :name)

    # Check a column exists of a particular type
    column_exists?(:suppliers, :name, :string)

    # Check a column exists with a specific definition
    column_exists?(:suppliers, :name, :string, limit: 100)
    column_exists?(:suppliers, :name, :string, default: 'default')
    column_exists?(:suppliers, :name, :string, null: false)
    column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 128
    def column_exists?(table_name, column_name, type = nil, options = {})
      column_name = column_name.to_s
      checks = []
      checks << lambda { |c| c.name == column_name }
      checks << lambda { |c| c.type == type } if type
      column_options_keys.each do |attr|
        checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
      end

      columns(table_name).any? { |c| checks.all? { |check| check[c] } }
    end

columns(table_name) click to toggle source

Returns an array of Column objects for the table specified by `table_name`. See the concrete implementation for details on the expected parameter values.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 110
    def columns(table_name)
      raise NotImplementedError, "#columns is not implemented"
    end

create_join_table(table_1, table_2, column_options: {}, **options) { |td| ... } click to toggle source

Creates a new join table with the name created using the lexical order of the first two arguments. These arguments can be a String or a Symbol.

    # Creates a table called 'assemblies_parts' with no id.
    create_join_table(:assemblies, :parts)

You can pass an `options` hash which can include the following keys:

`:table_name`

  Sets the table name, overriding the default.

`:column_options`

  Any extra options you want appended to the columns definition.

`:options`

  Any extra options you want appended to the table definition.

`:temporary`

  Make a temporary table.

`:force`

  Set to true to drop the table before creating it. Defaults to false.

Note that create_join_table does not create any indices by default; you can use its block form to do so yourself:

    create_join_table :products, :categories do |t|
      t.index :product_id
      t.index :category_id
    end

###### Add a backend specific option to the generated SQL (MySQL)¶ ↑

    create_join_table(:assemblies, :parts, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')

generates:

    CREATE TABLE assemblies_parts (
      assembly_id int NOT NULL,
      part_id int NOT NULL,
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 345
    def create_join_table(table_1, table_2, column_options: {}, **options)
      join_table_name = find_join_table_name(table_1, table_2, options)

      column_options.reverse_merge!(null: false, index: false)

      t1_ref, t2_ref = [table_1, table_2].map { |t| t.to_s.singularize }

      create_table(join_table_name, options.merge!(id: false)) do |td|
        td.references t1_ref, column_options
        td.references t2_ref, column_options
        yield td if block_given?
      end
    end

create_table(table_name, comment: nil, **options) { |td| ... } click to toggle source

Creates a new table with the name `table_name`. `table_name` may either be a String or a Symbol.

There are two ways to work with create_table. You can use the block form or the regular form, like this:

### Block form¶ ↑

    # create_table() passes a TableDefinition object to the block.
    # This form will not only create the table, but also columns for the
    # table.

    create_table(:suppliers) do |t|
      t.column :name, :string, limit: 60
      # Other fields here
    end

### Block form, with shorthand¶ ↑

    # You can also use the column types as method calls, rather than calling the column method.
    create_table(:suppliers) do |t|
      t.string :name, limit: 60
      # Other fields here
    end

### Regular form¶ ↑

    # Creates a table called 'suppliers' with no columns.
    create_table(:suppliers)
    # Add a column to 'suppliers'.
    add_column(:suppliers, :name, :string, {limit: 60})

The `options` hash can include the following keys:

`:id`

  Whether to automatically add a primary key column. Defaults to true. Join tables for ActiveRecord::Base.has_and_belongs_to_many should set it to false.

  A Symbol can be used to specify the type of the generated primary key column.

`:primary_key`

  The name of the primary key, if one is to be added automatically. Defaults to `id`. If `:id` is false, then this option is ignored.

  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.

`:options`

  Any extra options you want appended to the table definition.

`:temporary`

  Make a temporary table.

`:force`

  Set to true to drop the table before creating it. Set to `:cascade` to drop dependent objects as well. Defaults to false.

`:as`

  SQL to use to generate the table. When this option is used, the block is ignored, as are the `:id` and `:primary_key` options.

###### Add a backend specific option to the generated SQL (MySQL)¶ ↑

    create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')

generates:

    CREATE TABLE suppliers (
      id int auto_increment PRIMARY KEY
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8

###### Rename the primary key column¶ ↑

    create_table(:objects, primary_key: 'guid') do |t|
      t.column :name, :string, limit: 80
    end

generates:

    CREATE TABLE objects (
      guid int auto_increment PRIMARY KEY,
      name varchar(80)
    )

###### Change the primary key column type¶ ↑

    create_table(:tags, id: :string) do |t|
      t.column :label, :string
    end

generates:

    CREATE TABLE tags (
      id varchar PRIMARY KEY,
      label varchar
    )

###### Do not add a primary key column¶ ↑

    create_table(:categories_suppliers, id: false) do |t|
      t.column :category_id, :integer
      t.column :supplier_id, :integer
    end

generates:

    CREATE TABLE categories_suppliers (
      category_id int,
      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 ActiveRecord::ConnectionAdapters::TableDefinition#column for details on how to create columns.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 267
    def create_table(table_name, comment: nil, **options)
      td = create_table_definition table_name, options[:temporary], options[:options], options[:as], comment: comment

      if options[:id] != false && !options[:as]
        pk = options.fetch(:primary_key) do
          Base.get_primary_key table_name.to_s.singularize
        end

        if pk.is_a?(Array)
          td.primary_keys pk
        else
          td.primary_key pk, options.fetch(:id, :primary_key), options
        end
      end

      yield td if block_given?

      if options[:force]
        drop_table(table_name, **options, if_exists: true)
      end

      result = execute schema_creation.accept td

      unless supports_indexes_in_create?
        td.indexes.each do |column_name, index_options|
          add_index(table_name, column_name, index_options)
        end
      end

      if supports_comments? && !supports_comments_in_create?
        change_table_comment(table_name, comment) if comment.present?

        td.columns.each do |column|
          change_column_comment(table_name, column.name, column.comment) if column.comment.present?
        end
      end

      result
    end

data_source_exists?(name) click to toggle source

Checks to see if the data source `name` exists on the database.

    data_source_exists?(:ebooks)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 43
    def data_source_exists?(name)
      query_values(data_source_sql(name), "SCHEMA").any? if name.present?
    rescue NotImplementedError
      data_sources.include?(name.to_s)
    end

data_sources() click to toggle source

Returns the relation names useable to back Active Record models. For most adapters this means all tables and views.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 33
    def data_sources
      query_values(data_source_sql, "SCHEMA")
    rescue NotImplementedError
      tables | views
    end

drop_join_table(table_1, table_2, options = {}) click to toggle source

Drops the join table specified by the given arguments. See create_join_table for details.

Although this command ignores the block if one is given, it can be helpful to provide one in a migration's `change` method so it can be reverted. In that case, the block will be used by create_join_table.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 365
    def drop_join_table(table_1, table_2, options = {})
      join_table_name = find_join_table_name(table_1, table_2, options)
      drop_table(join_table_name)
    end

drop_table(table_name, options = {}) click to toggle source

Drops a table from the database.

`:force`

  Set to `:cascade` to drop dependent objects as well. Defaults to false.

`:if_exists`

  Set to `true` to only drop the table if it exists. Defaults to false.

Although this command ignores most `options` and the block if one is given, it can be helpful to provide these in a migration's `change` method so it can be reverted. In that case, `options` and the block will be used by create_table.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 470
    def drop_table(table_name, options = {})
      execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
    end

foreign_key_exists?(from_table, options_or_to_table = {}) click to toggle source

Checks to see if a foreign key exists on a table for a given foreign key definition.

    # Checks to see if a foreign key exists.
    foreign_key_exists?(:accounts, :branches)

    # Checks to see if a foreign key on a specified column exists.
    foreign_key_exists?(:accounts, column: :owner_id)

    # Checks to see if a foreign key with a custom name exists.
    foreign_key_exists?(:accounts, name: "special_fk_name")

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 973
    def foreign_key_exists?(from_table, options_or_to_table = {})
      foreign_key_for(from_table, options_or_to_table).present?
    end

foreign_keys(table_name) click to toggle source

Returns an array of foreign keys for the given table. The foreign keys are represented as ForeignKeyDefinition objects.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 877
    def foreign_keys(table_name)
      raise NotImplementedError, "foreign_keys is not implemented"
    end

index_exists?(table_name, column_name, options = {}) click to toggle source

Checks to see if an index exists on a table for a given index definition.

    # Check an index exists
    index_exists?(:suppliers, :company_id)

    # Check an index on multiple columns exists
    index_exists?(:suppliers, [:company_id, :company_type])

    # Check a unique index exists
    index_exists?(:suppliers, :company_id, unique: true)

    # Check an index with a custom name exists
    index_exists?(:suppliers, :company_id, name: "idx_company_id")

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 98
    def index_exists?(table_name, column_name, options = {})
      column_names = Array(column_name).map(&:to_s)
      checks = []
      checks << lambda { |i| i.columns == column_names }
      checks << lambda { |i| i.unique } if options[:unique]
      checks << lambda { |i| i.name == options[:name].to_s } if options[:name]

      indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
    end

index_name_exists?(table_name, index_name, default = nil) click to toggle source

Verifies the existence of an index with a given name.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 782
          def index_name_exists?(table_name, index_name, default = nil)
            unless default.nil?
              ActiveSupport::Deprecation.warn("            Passing default to #index_name_exists? is deprecated without replacement.
    ".squish)
            end
            index_name = index_name.to_s
            indexes(table_name).detect { |i| i.name == index_name }
          end

indexes(table_name, name = nil) click to toggle source

Returns an array of indexes for the given table.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 80
    def indexes(table_name, name = nil)
      raise NotImplementedError, "#indexes is not implemented"
    end

native_database_types() click to toggle source

Returns a hash of mappings from the abstract data types to the native database types. See ActiveRecord::ConnectionAdapters::TableDefinition#column for details on the recognized abstract data types.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 13
    def native_database_types
      {}
    end

options_include_default?(options) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1163
    def options_include_default?(options)
      options.include?(:default) && !(options[:null] == false && options[:default].nil?)
    end

primary_key(table_name) click to toggle source

Returns just a table's primary key

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 141
    def primary_key(table_name)
      pk = primary_keys(table_name)
      pk = pk.first unless pk.size > 1
      pk
    end

remove_belongs_to(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
Alias for: remove_reference
remove_column(table_name, column_name, type = nil, options = {}) click to toggle source

Removes the column from the table definition.

    remove_column(:suppliers, :qualification)

The `type` and `options` parameters will be ignored if present. It can be helpful to provide these in a migration's `change` method so it can be reverted. In that case, `type` and `options` will be used by add_column.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 575
    def remove_column(table_name, column_name, type = nil, options = {})
      execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
    end

remove_columns(table_name, *column_names) click to toggle source

Removes the given columns from the table definition.

    remove_columns(:suppliers, :qualification, :experience)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 561
    def remove_columns(table_name, *column_names)
      raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)") if column_names.empty?
      column_names.each do |column_name|
        remove_column(table_name, column_name)
      end
    end

remove_foreign_key(from_table, options_or_to_table = {}) click to toggle source

Removes the given foreign key from the table. Any option parameters provided will be used to re-add the foreign key in case of a migration rollback. It is recommended that you provide any options used when creating the foreign key so that the migration can be reverted properly.

Removes the foreign key on `accounts.branch_id`.

    remove_foreign_key :accounts, :branches

Removes the foreign key on `accounts.owner_id`.

    remove_foreign_key :accounts, column: :owner_id

Removes the foreign key named `special_fk_name` on the `accounts` table.

    remove_foreign_key :accounts, name: :special_fk_name

The `options` hash accepts the same keys as #add_foreign_key.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 951
    def remove_foreign_key(from_table, options_or_to_table = {})
      return unless supports_foreign_keys?

      fk_name_to_delete = foreign_key_for!(from_table, options_or_to_table).name

      at = create_alter_table from_table
      at.drop_foreign_key fk_name_to_delete

      execute schema_creation.accept(at)
    end

remove_index(table_name, options = {}) click to toggle source

Removes the given index from the table.

Removes the index on `branch_id` in the `accounts` table if exactly one such index exists.

    remove_index :accounts, :branch_id

Removes the index on `branch_id` in the `accounts` table if exactly one such index exists.

    remove_index :accounts, column: :branch_id

Removes the index on `branch_id` and `party_id` in the `accounts` table if exactly one such index exists.

    remove_index :accounts, column: [:branch_id, :party_id]

Removes the index named `by_branch_party` in the `accounts` table.

    remove_index :accounts, name: :by_branch_party

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 746
    def remove_index(table_name, options = {})
      index_name = index_name_for_remove(table_name, options)
      execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
    end

remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options) click to toggle source

Removes the reference(s). Also removes a `type` column if one exists. remove_reference and remove_belongs_to are acceptable.

###### Remove the reference¶ ↑

    remove_reference(:products, :user, index: true)

###### Remove polymorphic reference¶ ↑

    remove_reference(:products, :supplier, polymorphic: true)

###### Remove the reference with a foreign key¶ ↑

    remove_reference(:products, :user, index: true, foreign_key: true)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 858
    def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
      if foreign_key
        reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
        if foreign_key.is_a?(Hash)
          foreign_key_options = foreign_key
        else
          foreign_key_options = { to_table: reference_name }
        end
        foreign_key_options[:column] ||= "#{ref_name}_id"
        remove_foreign_key(table_name, **foreign_key_options)
      end

      remove_column(table_name, "#{ref_name}_id")
      remove_column(table_name, "#{ref_name}_type") if polymorphic
    end

Also aliased as: remove_belongs_to
remove_timestamps(table_name, options = {}) click to toggle source

Removes the timestamp columns (`created_at` and `updated_at`) from the table definition.

    remove_timestamps(:suppliers)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1122
    def remove_timestamps(table_name, options = {})
      remove_column table_name, :updated_at
      remove_column table_name, :created_at
    end

rename_column(table_name, column_name, new_column_name) click to toggle source

Renames a column.

    rename_column(:suppliers, :description, :name)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 631
    def rename_column(table_name, column_name, new_column_name)
      raise NotImplementedError, "rename_column is not implemented"
    end

rename_index(table_name, old_name, new_name) click to toggle source

Renames 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'

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 757
    def rename_index(table_name, old_name, new_name)
      validate_index_length!(table_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
      add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
      remove_index(table_name, name: old_name)
    end

rename_table(table_name, new_name) click to toggle source

Renames a table.

    rename_table('octopuses', 'octopi')

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 454
    def rename_table(table_name, new_name)
      raise NotImplementedError, "rename_table is not implemented"
    end

table_alias_for(table_name) click to toggle source

Truncates a table alias according to the limits of the current adapter.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 27
    def table_alias_for(table_name)
      table_name[0...table_alias_length].tr(".", "_")
    end

table_comment(table_name) click to toggle source

Returns the table comment that's stored in database metadata.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 22
    def table_comment(table_name)
      nil
    end

table_exists?(table_name) click to toggle source

Checks to see if the table `table_name` exists on the database.

    table_exists?(:developers)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 58
    def table_exists?(table_name)
      query_values(data_source_sql(table_name, type: "BASE TABLE"), "SCHEMA").any? if table_name.present?
    rescue NotImplementedError
      tables.include?(table_name.to_s)
    end

table_options(table_name) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 17
    def table_options(table_name)
      nil
    end

tables() click to toggle source

Returns an array of table names defined in the database.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 50
    def tables
      query_values(data_source_sql(type: "BASE TABLE"), "SCHEMA")
    end

view_exists?(view_name) click to toggle source

Checks to see if the view `view_name` exists on the database.

    view_exists?(:ebooks)

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 73
    def view_exists?(view_name)
      query_values(data_source_sql(view_name, type: "VIEW"), "SCHEMA").any? if view_name.present?
    rescue NotImplementedError
      views.include?(view_name.to_s)
    end

views() click to toggle source

Returns an array of view names defined in the database.

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 65
    def views
      query_values(data_source_sql(type: "VIEW"), "SCHEMA")
    end

### Private Instance Methods

add_index_sort_order(quoted_columns, **options) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1182
    def add_index_sort_order(quoted_columns, **options)
      if order = options[:order]
        case order
        when Hash
          order = order.symbolize_keys
          quoted_columns.each { |name, column| column << " #{order[name].upcase}" if order[name].present? }
        when String
          quoted_columns.each { |name, column| column << " #{order.upcase}" if order.present? }
        end
      end

      quoted_columns
    end

add_options_for_index_columns(quoted_columns, **options) click to toggle source

Overridden by the MySQL adapter for supporting index lengths

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1197
    def add_options_for_index_columns(quoted_columns, **options)
      if supports_index_sort_order?
        quoted_columns = add_index_sort_order(quoted_columns, options)
      end

      quoted_columns
    end

can_remove_index_by_name?(options) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1312
    def can_remove_index_by_name?(options)
      options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
    end

column_options_keys() click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1178
    def column_options_keys
      [:limit, :precision, :scale, :default, :null, :collation, :comment]
    end

create_alter_table(name) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1268
    def create_alter_table(name)
      AlterTable.new create_table_definition(name)
    end

create_table_definition(*args) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1264
    def create_table_definition(*args)
      TableDefinition.new(*args)
    end

data_source_sql(name = nil, type: nil) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1316
    def data_source_sql(name = nil, type: nil)
      raise NotImplementedError
    end

extract_new_default_value(default_or_changes) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1304
    def extract_new_default_value(default_or_changes)
      if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
        default_or_changes[:to]
      else
        default_or_changes
      end
    end

foreign_key_name(table_name, options) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1288
    def foreign_key_name(table_name, options)
      identifier = "#{table_name}_#{options.fetch(:column)}_fk"
      hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
      options.fetch(:name) do
        "fk_rails_#{hashed_identifier}"
      end
    end

index_column_names(column_names) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1272
    def index_column_names(column_names)
      if column_names.is_a?(String) && /\W/.match?(column_names)
        column_names
      else
        Array(column_names)
      end
    end

index_name_for_remove(table_name, options = {}) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1212
    def index_name_for_remove(table_name, options = {})
      return options[:name] if can_remove_index_by_name?(options)

      checks = []

      if options.is_a?(Hash)
        checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
        column_names = index_column_names(options[:column])
      else
        column_names = index_column_names(options)
      end

      if column_names.present?
        checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
      end

      raise ArgumentError, "No name or columns specified" if checks.none?

      matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }

      if matching_indexes.count > 1
        raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. "                                   "Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
      elsif matching_indexes.none?
        raise ArgumentError, "No indexes found on #{table_name} with the options provided."
      else
        matching_indexes.first.name
      end
    end

index_name_options(column_names) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1280
    def index_name_options(column_names)
      if column_names.is_a?(String) && /\W/.match?(column_names)
        column_names = column_names.scan(/\w+/).join("_")
      end

      { column: column_names }
    end

quoted_columns_for_index(column_names, **options) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1205
    def quoted_columns_for_index(column_names, **options)
      return [column_names] if column_names.is_a?(String)

      quoted_columns = Hash[column_names.map { |name| [name.to_sym, quote_column_name(name).dup] }]
      add_options_for_index_columns(quoted_columns, options).values
    end

quoted_scope(name = nil, type: nil) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1320
    def quoted_scope(name = nil, type: nil)
      raise NotImplementedError
    end

rename_column_indexes(table_name, column_name, new_column_name) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1251
    def rename_column_indexes(table_name, column_name, new_column_name)
      column_name, new_column_name = column_name.to_s, new_column_name.to_s
      indexes(table_name).each do |index|
        next unless index.columns.include?(new_column_name)
        old_columns = index.columns.dup
        old_columns[old_columns.index(new_column_name)] = column_name
        generated_index_name = index_name(table_name, column: old_columns)
        if generated_index_name == index.name
          rename_index table_name, generated_index_name, index_name(table_name, column: index.columns)
        end
      end
    end

rename_table_indexes(table_name, new_name) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1242
    def rename_table_indexes(table_name, new_name)
      indexes(new_name).each do |index|
        generated_index_name = index_name(table_name, column: index.columns)
        if generated_index_name == index.name
          rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
        end
      end
    end

validate_index_length!(table_name, new_name, internal = false) click to toggle source

    # File lib/active_record/connection_adapters/abstract/schema_statements.rb, line 1296
    def validate_index_length!(table_name, new_name, internal = false)
      max_index_length = internal ? index_name_length : allowed_index_name_length

      if new_name.length > max_index_length
        raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters"
      end
    end