module ActiveRecord::ConnectionAdapters::SchemaStatements

def add_column(table_name, column_name, type, options = {})

See TableDefinition#column for details of the options you can use.
Adds a new column to the named table.
def add_column(table_name, column_name, type, options = {})
  add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  add_column_options!(add_column_sql, options)
  execute(add_column_sql)
end

def add_column_options!(sql, options) #:nodoc:

:nodoc:
def add_column_options!(sql, options) #:nodoc:
  sql << " DEFAULT #{quote(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
end

def add_index(table_name, column_name, options = {})

Note: SQLite doesn't support index length

CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
generates
add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15})

CREATE INDEX by_name ON accounts(name(10))
generates
add_index(:accounts, :name, :name => 'by_name', :length => 10)
====== Creating an index with specific key length

CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
generates
add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
====== Creating a named index

CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
generates
add_index(:accounts, [:branch_id, :party_id], :unique => true)
====== Creating a unique index

CREATE INDEX suppliers_name_index ON suppliers(name)
generates
add_index(:suppliers, :name)
====== Creating a simple index

===== Examples

name.
makes sense, because you will never have to create a singular index with this
index for the first column :first. Using just the first name for this index
[:first, :last], the DBMS creates an index for both columns as well as an
for the index. For example, when you specify an index on two columns
When creating an index on multiple columns, the first column is used as a name

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

an Array of Symbols.
Adds a new index to the table. +column_name+ can be a single Symbol, or
def add_index(table_name, column_name, options = {})
  column_names = Array(column_name)
  index_name   = index_name(table_name, :column => column_names)
  if Hash === options # legacy support, since this param was a string
    index_type = options[:unique] ? "UNIQUE" : ""
    index_name = options[:name].to_s if options[:name]
  else
    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})"
end

def add_order_by_for_association_limiting!(sql, options)

PostgreSQL overrides this due to its stricter standards compliance.
ORDER BY clause for the passed order option.
def add_order_by_for_association_limiting!(sql, options)
  sql << " ORDER BY #{options[:order]}"
end

def add_timestamps(table_name)

add_timestamps(:suppliers)
===== Examples
Adds timestamps (created_at and updated_at) columns to the named table.
def add_timestamps(table_name)
  add_column table_name, :created_at, :datetime
  add_column table_name, :updated_at, :datetime
end

def assume_migrated_upto_version(version, migrations_path = ActiveRecord::Migrator.migrations_path)

def assume_migrated_upto_version(version, migrations_path = ActiveRecord::Migrator.migrations_path)
  version = version.to_i
  sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
  migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
  versions = Dir["#{migrations_path}/[0-9]*_*.rb"].map do |filename|
    filename.split('/').last.split('_').first.to_i
  end
  unless migrated.include?(version)
    execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
  end
  inserted = Set.new
  (versions - migrated).each do |v|
    if inserted.include?(v)
      raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict."
    elsif v < version
      execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
      inserted << v
    end
  end
end

def change_column(table_name, column_name, type, options = {})

change_column(:accounts, :description, :text)
change_column(:suppliers, :name, :string, :limit => 80)
===== Examples
See TableDefinition#column for details of the options you can use.
Changes the column's definition according to the new options.
def change_column(table_name, column_name, type, options = {})
  raise NotImplementedError, "change_column is not implemented"
end

def change_column_default(table_name, column_name, default)

change_column_default(:accounts, :authorized, 1)
change_column_default(:suppliers, :qualification, 'new')
===== Examples
DatabaseStatements#execute the appropriate SQL statement yourself.
value to +NULL+, you are out of luck. You need to
Sets a new default value for a column. If you want to set the default
def change_column_default(table_name, column_name, default)
  raise NotImplementedError, "change_column_default is not implemented"
end

def change_table(table_name)

all of the various column transformation
See also Table for details on

end
t.remove_index :company_id
change_table(:suppliers) do |t|
====== Remove an index

end
t.remove :width, :height
t.remove :company_id
change_table(:suppliers) do |t|
====== Remove several columns

end
t.remove :company
change_table(:suppliers) do |t|
====== Remove a column

Creates company_type(varchar) and company_id(integer) columns

end
t.belongs_to :company, :polymorphic => true
change_table(:suppliers) do |t|
====== Add a polymorphic foreign key column

Creates a company_id(integer) column

end
t.references :company
change_table(:suppliers) do |t|
====== Add a foreign key column

end
t.timestamps
change_table(:suppliers) do |t|
====== Add created_at/updated_at columns

end
t.integer :width, :height, :null => false, :default => 0
change_table(:suppliers) do |t|
====== Add 2 integer columns

end
t.column :name, :string, :limit => 60
change_table(:suppliers) do |t|
====== Add a column
===== Examples

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

A block for changing columns in +table+.
def change_table(table_name)
  yield Table.new(table_name, self)
end

def columns(table_name, name = nil) end

See the concrete implementation for details on the expected parameter values.
Returns an array of Column objects for the table specified by +table_name+.
def columns(table_name, name = nil) end

def create_table(table_name, options = {})

See also TableDefinition#column for details on how to create columns.

)
supplier_id int
category_id int,
CREATE TABLE categories_suppliers (
generates:
end
t.column :supplier_id, :integer
t.column :category_id, :integer
create_table(:categories_suppliers, :id => false) do |t|
====== Do not add a primary key column

)
name varchar(80)
guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
CREATE TABLE objects (
generates:
end
t.column :name, :string, :limit => 80
create_table(:objects, :primary_key => 'guid') do |t|
====== Rename the primary key column

) ENGINE=InnoDB DEFAULT CHARSET=utf8
id int(11) DEFAULT NULL auto_increment PRIMARY KEY
CREATE TABLE suppliers (
generates:
create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
====== Add a backend specific option to the generated SQL (MySQL)
===== Examples

Defaults to false.
Set to true to drop the table before creating it.
[:force]
Make a temporary table.
[:temporary]
Any extra options you want appended to the table definition.
[:options]
Defaults to +id+.
The name of the primary key, if one is to be added automatically.
[:primary_key]
Join tables for +has_and_belongs_to_many+ should set :id => false.
Whether to automatically add a primary key column. Defaults to true.
[:id]
The +options+ hash can include the following keys:

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

end
# Other fields here
t.column :name, :string, :limit => 60
create_table(:suppliers) do |t|
# table.
# This form will not only create the table, but also columns for the
# create_table() passes a TableDefinition object to the block.
=== Block form

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

be a String or a Symbol.
Creates a new table with the name +table_name+. +table_name+ may either
def create_table(table_name, options = {})
  table_definition = TableDefinition.new(self)
  table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
  yield table_definition if block_given?
  if options[:force] && table_exists?(table_name)
    drop_table(table_name, options)
  end
  create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
  create_sql << "#{quote_table_name(table_name)} ("
  create_sql << table_definition.to_sql
  create_sql << ") #{options[:options]}"
  execute create_sql
end

def distinct(columns, order_by)

distinct("posts.id", "posts.created_at desc")

Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.
SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
def distinct(columns, order_by)
  "DISTINCT #{columns}"
end

def drop_table(table_name, options = {})

Drops a table from the database.
def drop_table(table_name, options = {})
  execute "DROP TABLE #{quote_table_name(table_name)}"
end

def dump_schema_information #:nodoc:

:nodoc:
def dump_schema_information #:nodoc:
  sm_table = ActiveRecord::Migrator.schema_migrations_table_name
  migrated = select_values("SELECT version FROM #{sm_table}")
  migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n")
end

def index_exists?(table_name, index_name, default)

as there's no way to determine the correct answer in that case.
The default argument is returned if the underlying implementation does not define the indexes method,

Verify the existence of an index.
def index_exists?(table_name, index_name, default)
  return default unless respond_to?(:indexes)
  index_name = index_name.to_s
  indexes(table_name).detect { |i| i.name == index_name }
end

def index_name(table_name, options) #:nodoc:

:nodoc:
def index_name(table_name, options) #:nodoc:
  if Hash === options # legacy support
    if options[:column]
      "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
    elsif options[:name]
      options[:name]
    else
      raise ArgumentError, "You must specify the index name"
    end
  else
    index_name(table_name, :column => options)
  end
end

def initialize_schema_migrations_table

The migrations module handles this automatically.
Should not be called normally, but this operation is non-destructive.
def initialize_schema_migrations_table
  sm_table = ActiveRecord::Migrator.schema_migrations_table_name
  unless tables.detect { |t| t == sm_table }
    create_table(sm_table, :id => false) do |schema_migrations_table|
      schema_migrations_table.column :version, :string, :null => false
    end
    add_index sm_table, :version, :unique => true,
      :name => "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
    # Backwards-compatibility: if we find schema_info, assume we've
    # migrated up to that point:
    si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
    if tables.detect { |t| t == si_table }
      old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
      assume_migrated_upto_version(old_version)
      drop_table(si_table)
    end
  end
end

def native_database_types

abstract data types.
database types. See TableDefinition#column for details on the recognized
Returns a Hash of mappings from the abstract data types to the native
def native_database_types
  {}
end

def options_include_default?(options)

def options_include_default?(options)
  options.include?(:default) && !(options[:null] == false && options[:default].nil?)
end

def quoted_columns_for_index(column_names, options = {})

Overridden by the mysql adapter for supporting index lengths
def quoted_columns_for_index(column_names, options = {})
  column_names.map {|name| quote_column_name(name) }
end

def remove_column(table_name, *column_names)

remove_columns(:suppliers, :qualification, :experience)
remove_column(:suppliers, :qualification)
===== Examples
Removes the column(s) from the table definition.
def remove_column(table_name, *column_names)
  raise ArgumentError.new("You must specify at least one column name.  Example: remove_column(:people, :first_name)") if column_names.empty?
  column_names.flatten.each do |column_name|
    execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
  end
end

def remove_index(table_name, options = {})

remove_index :accounts, :name => :by_branch_party
Remove the index named by_branch_party in the accounts table.
remove_index :accounts, :column => [:branch_id, :party_id]
Remove the index named accounts_branch_id_party_id_index in the accounts table.
remove_index :accounts, :column => :branch_id
Remove the index named accounts_branch_id_index in the accounts table.
remove_index :suppliers, :name
Remove the suppliers_name_index in the suppliers table.

Remove the given index from the table.
def remove_index(table_name, options = {})
  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:

:nodoc:
def remove_index!(table_name, index_name) #:nodoc:
  execute "DROP INDEX #{quote_column_name(index_name)} ON #{table_name}"
end

def remove_timestamps(table_name)

remove_timestamps(:suppliers)
===== Examples
Removes the timestamp columns (created_at and updated_at) from the table definition.
def remove_timestamps(table_name)
  remove_column table_name, :updated_at
  remove_column table_name, :created_at
end

def rename_column(table_name, column_name, new_column_name)

rename_column(:suppliers, :description, :name)
===== Example
Renames a column.
def rename_column(table_name, column_name, new_column_name)
  raise NotImplementedError, "rename_column is not implemented"
end

def rename_index(table_name, old_name, new_name)

rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
Rename the index_people_on_last_name index to index_users_on_last_name

Rename an index.
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 rename_table(table_name, new_name)

rename_table('octopuses', 'octopi')
===== Example
Renames a table.
def rename_table(table_name, new_name)
  raise NotImplementedError, "rename_table is not implemented"
end

def structure_dump

entire structure of the database.
Returns a string of CREATE TABLE SQL statement(s) for recreating the
def structure_dump
end

def table_alias_for(table_name)

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(/\./, '_')
end

def table_exists?(table_name)

def table_exists?(table_name)
  tables.include?(table_name.to_s)
end

def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:

:nodoc:
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
  if native = native_database_types[type]
    column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
    if type == :decimal # ignore limit, use precision and scale
      scale ||= native[:scale]
      if precision ||= native[:precision]
        if scale
          column_type_sql << "(#{precision},#{scale})"
        else
          column_type_sql << "(#{precision})"
        end
      elsif scale
        raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
      end
    elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
      column_type_sql << "(#{limit})"
    end
    column_type_sql
  else
    type
  end
end