class ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter - activerecord-4.2.5.2 Documentation

# class ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter

### Constants

INDEX_TYPES
INDEX_USINGS
LOST_CONNECTION_ERROR_MESSAGES
NATIVE_DATABASE_TYPES
QUOTED_FALSE

### Public Class Methods

emulate_booleans() click to toggle source

By default, the MysqlAdapter will consider all columns of type `tinyint(1)` as boolean. If you wish to disable this emulation (which was the default behavior in versions 0.13.1 and earlier) you can add the following line to your application.rb file:

    ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 139
    class_attribute :emulate_booleans

new(connection, logger, connection_options, config) click to toggle source

FIXME: Make the first parameter more similar for the two adapters

Calls superclass method ActiveRecord::ConnectionAdapters::QueryCache.new

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 168
    def initialize(connection, logger, connection_options, config)
      super(connection, logger)
      @connection_options, @config = connection_options, config
      @quoted_column_names, @quoted_table_names = {}, {}

      @visitor = Arel::Visitors::MySQL.new self

      if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
        @prepared_statements = true
      else
        @prepared_statements = false
      end
    end

### Public Instance Methods

begin_db_transaction() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 320
    def begin_db_transaction
      execute "BEGIN"
    end

begin_isolated_db_transaction(isolation) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 324
    def begin_isolated_db_transaction(isolation)
      execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
      begin_db_transaction
    end

case_insensitive_comparison(table, attribute, column, value) click to toggle source
Calls superclass method ActiveRecord::ConnectionAdapters::AbstractAdapter#case_insensitive_comparison

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 643
    def case_insensitive_comparison(table, attribute, column, value)
      if column.case_sensitive?
        super
      else
        table[attribute].eq(value)
      end
    end

case_sensitive_comparison(table, attribute, column, value) click to toggle source
Calls superclass method ActiveRecord::ConnectionAdapters::AbstractAdapter#case_sensitive_comparison

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 635
    def case_sensitive_comparison(table, attribute, column, value)
      if column.case_sensitive?
        table[attribute].eq(value)
      else
        super
      end
    end

case_sensitive_modifier(node, table_attribute) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 630
    def case_sensitive_modifier(node, table_attribute)
      node = Arel::Nodes.build_quoted node, table_attribute
      Arel::Nodes::Bin.new(node)
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 514
    def change_column_null(table_name, column_name, null, default = nil)
      column = column_for(table_name, column_name)

      unless null || default.nil?
        execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
      end

      change_column table_name, column_name, column.sql_type, :null => null
    end

charset() click to toggle source

Returns the database character set.

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 392
    def charset
      show_variable 'character_set_database'
    end

clear_cache!() click to toggle source
Calls superclass method ActiveRecord::ConnectionAdapters::AbstractAdapter#clear_cache!

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 298
    def clear_cache!
      super
      reload_type_map
    end

collation() click to toggle source

Returns the database collation strategy.

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 397
    def collation
      show_variable 'collation_database'
    end

create_database(name, options = {}) click to toggle source

Create a new MySQL database with optional `:charset` and `:collation`. Charset defaults to utf8.

Example:

    create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
    create_database 'matt_development'
    create_database 'matt_development', charset: :big5

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 371
    def create_database(name, options = {})
      if options[:collation]
        execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
      else
        execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
      end
    end

current_database() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 387
    def current_database
      select_value 'SELECT DATABASE() as db'
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 495
    def drop_table(table_name, options = {})
      execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
    end

empty_insert_statement_value() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 349
    def empty_insert_statement_value
      "VALUES ()"
    end

execute(sql, name = nil) click to toggle source

Executes the SQL statement in the context of this connection.

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 304
    def execute(sql, name = nil)
      log(sql, name) { @connection.query(sql) }
    end

foreign_keys(table_name) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 538
          def foreign_keys(table_name)
            fk_info = select_all "          SELECT fk.referenced_table_name as 'to_table'
                    ,fk.referenced_column_name as 'primary_key'
                    ,fk.column_name as 'column'
                    ,fk.constraint_name as 'name'
              FROM information_schema.key_column_usage fk
              WHERE fk.referenced_column_name is not null
                AND fk.table_schema = '#{@config[:database]}'
                AND fk.table_name = '#{table_name}'
    ".strip_heredoc

            create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]

            fk_info.map do |row|
              options = {
                column: row['column'],
                name: row['name'],
                primary_key: row['primary_key']
              }

              options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE")
              options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE")

              ForeignKeyDefinition.new(table_name, row['to_table'], options)
            end
          end

index_algorithms() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 225
    def index_algorithms
      { default: 'ALGORITHM = DEFAULT', copy: 'ALGORITHM = COPY', inplace: 'ALGORITHM = INPLACE' }
    end

native_database_types() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 221
    def native_database_types
      NATIVE_DATABASE_TYPES
    end

pk_and_sequence_for(table) click to toggle source

Returns a table's primary key and belonging sequence.

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 612
    def pk_and_sequence_for(table)
      execute_and_free("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA') do |result|
        create_table = each_hash(result).first[:"Create Table"]
        if create_table.to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
          keys = $1.split(",").map { |key| key.delete('`"') }
          keys.length == 1 ? [keys.first, nil] : nil
        else
          nil
        end
      end
    end

primary_key(table) click to toggle source

Returns just a table's primary key

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 625
    def primary_key(table)
      pk_and_sequence = pk_and_sequence_for(table)
      pk_and_sequence && pk_and_sequence.first
    end

quoted_false() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 273
    def quoted_false
      QUOTED_FALSE
    end

quoted_true() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 265
    def quoted_true
      QUOTED_TRUE
    end

recreate_database(name, options = {}) click to toggle source

Drops the database specified on the `name` attribute and creates it again using the provided `options`.

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 357
    def recreate_database(name, options = {})
      drop_database(name)
      sql = create_database(name, options)
      reconnect!
      sql
    end

rename_index(table_name, old_name, new_name) click to toggle source
Calls superclass method ActiveRecord::ConnectionAdapters::SchemaStatements#rename_index

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 499
    def rename_index(table_name, old_name, new_name)
      if supports_rename_index?
        validate_index_length!(table_name, new_name)

        execute "ALTER TABLE #{quote_table_name(table_name)} RENAME INDEX #{quote_table_name(old_name)} TO #{quote_table_name(new_name)}"
      else
        super
      end
    end

rename_table(table_name, new_name) click to toggle source

Renames a table.

Example:

    rename_table('octopuses', 'octopi')

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 490
    def rename_table(table_name, new_name)
      execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
      rename_table_indexes(table_name, new_name)
    end

schema_creation() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 57
    def schema_creation
      SchemaCreation.new self
    end

show_variable(name) click to toggle source

SHOW VARIABLES LIKE 'name'

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 606
    def show_variable(name)
      variables = select_all("SHOW VARIABLES LIKE '#{name}'", 'SCHEMA')
      variables.first['Value'] unless variables.empty?
    end

strict_mode?() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 651
    def strict_mode?
      self.class.type_cast_config_to_boolean(@config.fetch(:strict, true))
    end

supports_foreign_keys?() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 213
    def supports_foreign_keys?
      true
    end

supports_index_sort_order?() click to toggle source

Technically MySQL allows to create indexes with the sort order syntax but at the moment (5.5) it doesn't yet implement them

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 197
    def supports_index_sort_order?
      true
    end

supports_indexes_in_create?() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 209
    def supports_indexes_in_create?
      true
    end

supports_migrations?() click to toggle source

Returns true, since this connection adapter supports migrations.

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 183
    def supports_migrations?
      true
    end

supports_primary_key?() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 187
    def supports_primary_key?
      true
    end

supports_transaction_isolation?() click to toggle source

MySQL 4 technically support transaction isolation, but it is affected by a bug where the transaction level gets persisted for the whole session:

bugs.mysql.com/bug.php?id=39170

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 205
    def supports_transaction_isolation?
      version[0] >= 5
    end

supports_views?() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 217
    def supports_views?
      version[0] >= 5
    end

table_exists?(name) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 415
    def table_exists?(name)
      return false unless name.present?
      return true if tables(nil, nil, name).any?

      name          = name.to_s
      schema, table = name.split('.', 2)

      unless table # A table was provided without a schema
        table  = schema
        schema = nil
      end

      tables(nil, schema, table).any?
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 411
    def truncate(table_name, name = nil)
      execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
    end

type_to_sql(type, limit = nil, precision = nil, scale = nil) click to toggle source

Maps logical Rails types to MySQL-specific data types.

Calls superclass method

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 567
    def type_to_sql(type, limit = nil, precision = nil, scale = nil)
      case type.to_s
      when 'binary'
        case limit
        when 0..0xfff;           "varbinary(#{limit})"
        when nil;                "blob"
        when 0x1000..0xffffffff; "blob(#{limit})"
        else raise(ActiveRecordError, "No binary type has character length #{limit}")
        end
      when 'integer'
        case limit
        when 1; 'tinyint'
        when 2; 'smallint'
        when 3; 'mediumint'
        when nil, 4, 11; 'int(11)'  # compatibility with MySQL default
        when 5..8; 'bigint'
        else raise(ActiveRecordError, "No integer type has byte size #{limit}")
        end
      when 'text'
        case limit
        when 0..0xff;               'tinytext'
        when nil, 0x100..0xffff;    'text'
        when 0x10000..0xffffff;     'mediumtext'
        when 0x1000000..0xffffffff; 'longtext'
        else raise(ActiveRecordError, "No text type has character length #{limit}")
        end
      when 'datetime'
        return super unless precision

        case precision
          when 0..6; "datetime(#{precision})"
          else raise(ActiveRecordError, "No datetime type has precision of #{precision}. The allowed range of precision is from 0 to 6.")
        end
      else
        super
      end
    end

unquoted_false() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 277
    def unquoted_false
      0
    end

unquoted_true() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 269
    def unquoted_true
      1
    end

valid_type?(type) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 655
    def valid_type?(type)
      !native_database_types[type].nil?
    end

### Protected Instance Methods

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 757
    def add_column_sql(table_name, column_name, type, options = {})
      td = create_table_definition table_name, options[:temporary], options[:options]
      cd = td.new_column_definition(column_name, type, options)
      schema_creation.visit_AddColumn cd
    end

add_index_length(option_strings, column_names, options = {}) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 721
    def add_index_length(option_strings, column_names, options = {})
      if options.is_a?(Hash) && length = options[:length]
        case length
        when Hash
          column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
        when Fixnum
          column_names.each {|name| option_strings[name] += "(#{length})"}
        end
      end

      return option_strings
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 799
    def add_index_sql(table_name, column_name, options = {})
      index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
      "ADD #{index_type} INDEX #{index_name} (#{index_columns})"
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 809
    def add_timestamps_sql(table_name, options = {})
      [add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)]
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 763
    def change_column_sql(table_name, column_name, type, options = {})
      column = column_for(table_name, column_name)

      unless options_include_default?(options)
        options[:default] = column.default
      end

      unless options.has_key?(:null)
        options[:null] = column.null
      end

      options[:name] = column.name
      schema_creation.accept ChangeColumnDefinition.new column, type, options
    end

quoted_columns_for_index(column_names, options = {}) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 734
    def quoted_columns_for_index(column_names, options = {})
      option_strings = Hash[column_names.map {|name| [name, '']}]

      # add index length
      option_strings = add_index_length(option_strings, column_names, options)

      # add index sort order
      option_strings = add_index_sort_order(option_strings, column_names, options)

      column_names.map {|name| quote_column_name(name) + option_strings[name]}
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 791
    def remove_column_sql(table_name, column_name, type = nil, options = {})
      "DROP #{quote_column_name(column_name)}"
    end

remove_columns_sql(table_name, *column_names) click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 795
    def remove_columns_sql(table_name, *column_names)
      column_names.map {|column_name| remove_column_sql(table_name, column_name) }
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 804
    def remove_index_sql(table_name, options = {})
      index_name = index_name_for_remove(table_name, options)
      "DROP INDEX #{index_name}"
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 813
    def remove_timestamps_sql(table_name, options = {})
      [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)]
    end

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

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 778
    def rename_column_sql(table_name, column_name, new_column_name)
      column  = column_for(table_name, column_name)
      options = {
        name: new_column_name,
        default: column.default,
        null: column.null,
        auto_increment: column.extra == "auto_increment"
      }

      current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"]
      schema_creation.accept ChangeColumnDefinition.new column, current_type, options
    end

subquery_for(key, select) click to toggle source

MySQL is too stupid to create a temporary table for use subquery, so we have to give it some prompting in the form of a subsubquery. Ugh!

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 712
    def subquery_for(key, select)
      subsubselect = select.clone
      subsubselect.projections = [key]

      subselect = Arel::SelectManager.new(select.engine)
      subselect.project Arel.sql(key.name)
      subselect.from subsubselect.as('__active_record_temp')
    end

translate_exception(exception, message) click to toggle source
Calls superclass method ActiveRecord::ConnectionAdapters::AbstractAdapter#translate_exception

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 746
    def translate_exception(exception, message)
      case error_number(exception)
      when 1062
        RecordNotUnique.new(message, exception)
      when 1452
        InvalidForeignKey.new(message, exception)
      else
        super
      end
    end

### Private Instance Methods

configure_connection() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 831
    def configure_connection
      variables = @config.fetch(:variables, {}).stringify_keys

      # By default, MySQL 'where id is null' selects the last inserted id.
      # Turn this off. http://dev.rubyonrails.org/ticket/6778
      variables['sql_auto_is_null'] = 0

      # Increase timeout so the server doesn't disconnect us.
      wait_timeout = @config[:wait_timeout]
      wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
      variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout)

      # Make MySQL reject illegal values rather than truncating or blanking them, see
      # http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_all_tables
      # If the user has provided another value for sql_mode, don't replace it.
      unless variables.has_key?('sql_mode')
        variables['sql_mode'] = strict_mode? ? 'STRICT_ALL_TABLES' : ''
      end

      # NAMES does not have an equals sign, see
      # http://dev.mysql.com/doc/refman/5.0/en/set-statement.html#id944430
      # (trailing comma because variable_assignments will always have content)
      if @config[:encoding]
        encoding = "NAMES #{@config[:encoding]}"
        encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
        encoding << ", "
      end

      # Gather up all of the SET variables...
      variable_assignments = variables.map do |k, v|
        if v == ':default' || v == :default
          "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
        elsif !v.nil?
          "@@SESSION.#{k} = #{quote(v)}"
        end
        # or else nil; compact to clear nils out
      end.compact.join(', ')

      # ...and send them all in one query
      @connection.query  "SET #{encoding} #{variable_assignments}"
    end

mariadb?() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 823
    def mariadb?
      full_version =~ /mariadb/i
    end

supports_rename_index?() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 827
    def supports_rename_index?
      mariadb? ? false : (version[0] == 5 && version[1] >= 7) || version[0] >= 6
    end

version() click to toggle source

    # File lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 819
    def version
      @version ||= full_version.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
    end