module ArJdbc::MySQL

Constants

ADAPTER_NAME
ActiveRecordError

@private

ColumnExtensions

Column behavior based on (abstract) MySQL adapter in Rails. @see ActiveRecord::ConnectionAdapters::JdbcColumn

ForeignKeyDefinition

@private

INDEX_TYPES
INDEX_USINGS
IndexDefinition

@private

NATIVE_DATABASE_TYPES
Type

@private

Public Class Methods

arel_visitor_type(config = nil) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 136
def self.arel_visitor_type(config = nil)
  ::Arel::Visitors::MySQL
end
column_selector() click to toggle source

@see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types

# File lib/arjdbc/mysql/column.rb, line 5
def self.column_selector
  [ /mysql/i, lambda { |config, column| column.extend(Column) } ]
end
emulate_booleans() click to toggle source

@deprecated Use {#emulate_booleans?} instead.

# File lib/arjdbc/mysql/adapter.rb, line 96
def self.emulate_booleans; @@emulate_booleans; end
emulate_booleans=(emulate) click to toggle source

@see emulate_booleans?

# File lib/arjdbc/mysql/adapter.rb, line 98
def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
emulate_booleans?() click to toggle source

Boolean emulation can be disabled using (or using the adapter method) :

ArJdbc::MySQL.emulate_booleans = false

@see #emulate_booleans

# File lib/arjdbc/mysql/adapter.rb, line 94
def self.emulate_booleans?; @@emulate_booleans; end
jdbc_connection_class() click to toggle source

@see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class

# File lib/arjdbc/mysql/adapter.rb, line 20
def self.jdbc_connection_class
  ::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
end

Public Instance Methods

_quote(value) click to toggle source

@private since AR 4.2

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 222
def _quote(value)
  if value.is_a?(Type::Binary::Data)
    "x'#{value.hex}'"
  else
    super
  end
end
adapter_name() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 132
def adapter_name
  ADAPTER_NAME
end
add_column(table_name, column_name, type, options = {}) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 594
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)
  add_column_position!(add_column_sql, options)
  execute(add_column_sql)
end
add_column_position!(sql, options) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 660
def add_column_position!(sql, options)
  if options[:first]
    sql << " FIRST"
  elsif options[:after]
    sql << " AFTER #{quote_column_name(options[:after])}"
  end
end
add_limit_offset!(sql, options) click to toggle source

@note Only used with (non-AREL) ActiveRecord *2.3*. @see Arel::Visitors::MySQL

# File lib/arjdbc/mysql/adapter.rb, line 670
def add_limit_offset!(sql, options)
  limit, offset = options[:limit], options[:offset]
  if limit && offset
    sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}"
  elsif limit
    sql << " LIMIT #{sanitize_limit(limit)}"
  elsif offset
    sql << " OFFSET #{offset.to_i}"
  end
  sql
end
case_insensitive_comparison(table, attribute, column, value) click to toggle source
Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 167
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
# File lib/arjdbc/mysql/adapter.rb, line 159
def case_sensitive_comparison(table, attribute, column, value)
  if column.case_sensitive?
    table[attribute].eq(value)
  else
    super
  end
end
case_sensitive_equality_operator() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 146
def case_sensitive_equality_operator
  "= BINARY"
end
case_sensitive_modifier(node) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 150
def case_sensitive_modifier(node)
  Arel::Nodes::Bin.new(node)
end
change_column(table_name, column_name, type, options = {}) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 617
def change_column(table_name, column_name, type, options = {})
  column = column_for(table_name, column_name)

  unless options_include_default?(options)
    # NOTE: no defaults for BLOB/TEXT columns with MySQL
    options[:default] = column.default if type != :text && type != :binary
  end

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

  change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  add_column_options!(change_column_sql, options)
  add_column_position!(change_column_sql, options)
  execute(change_column_sql)
end
change_column_default(table_name, column_name, default) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 601
def change_column_default(table_name, column_name, default)
  column = column_for(table_name, column_name)
  change_column table_name, column_name, column.sql_type, :default => default
end
change_column_null(table_name, column_name, null, default = nil) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 606
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
# File lib/arjdbc/mysql/adapter.rb, line 710
def charset
  show_variable("character_set_database")
end
clear_cache!() click to toggle source
Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 767
def clear_cache!
  super
  reload_type_map
end
collation() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 714
def collation
  show_variable("collation_database")
end
columns(table_name, name = nil) click to toggle source

Returns an array of `Column` objects for the table specified. @override

# File lib/arjdbc/mysql/adapter.rb, line 405
def columns(table_name, name = nil)
  sql = "SHOW FULL #{AR40 ? 'FIELDS' : 'COLUMNS'} FROM #{quote_table_name(table_name)}"
  columns = execute(sql, name || 'SCHEMA')
  strict = strict_mode?
  pass_cast_type = respond_to?(:lookup_cast_type)
  columns.map! do |field|
    sql_type = field['Type']
    null = field['Null'] == "YES"
    if pass_cast_type
      cast_type = lookup_cast_type(sql_type)
      jdbc_column_class.new(field['Field'], field['Default'], cast_type, sql_type, null, field['Collation'], strict, field['Extra'])
    else
      jdbc_column_class.new(field['Field'], field['Default'], sql_type, null, field['Collation'], strict, field['Extra'])
    end
  end
  columns
end
configure_connection() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 44
def configure_connection
  variables = config[:variables] || {}
  # By default, MySQL 'where id is null' selects the last inserted id. Turn this off.
  variables[:sql_auto_is_null] = 0 # execute "SET SQL_AUTO_IS_NULL=0"

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

  # 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.
  if strict_mode? && ! variables.has_key?(:sql_mode)
    variables[:sql_mode] = 'STRICT_ALL_TABLES' # SET SQL_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)
  encoding = "NAMES #{config[:encoding]}, " if config[:encoding]

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

  # ...and send them all in one query
  execute("SET #{encoding} #{variable_assignments}", :skip_logging)
end
create_database(name, options = {}) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 501
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
create_savepoint(name = current_savepoint_name(true)) click to toggle source

@override

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 297
def create_savepoint(name = current_savepoint_name(true))
  log("SAVEPOINT #{name}", 'Savepoint') { super }
end
create_table(name, options = {}) click to toggle source

@override

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 523
def create_table(name, options = {})
  super(name, { :options => "ENGINE=InnoDB" }.merge(options))
end
current_database() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 514
def current_database
  select_one("SELECT DATABASE() as db")['db']
end
disable_referential_integrity() { || ... } click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 311
def disable_referential_integrity
  fk_checks = select_value("SELECT @@FOREIGN_KEY_CHECKS")
  begin
    update("SET FOREIGN_KEY_CHECKS = 0")
    yield
  ensure
    update("SET FOREIGN_KEY_CHECKS = #{fk_checks}")
  end
end
drop_database(name) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 510
def drop_database(name)
  execute "DROP DATABASE IF EXISTS `#{name}`"
end
drop_table(table_name, options = {}) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 527
def drop_table(table_name, options = {})
  execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}"
end
empty_insert_statement_value() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 758
def empty_insert_statement_value
  "VALUES ()"
end
emulate_booleans() click to toggle source

@private

# File lib/arjdbc/mysql/adapter.rb, line 912
def emulate_booleans; ::ArJdbc::MySQL.emulate_booleans?; end
error_number(exception) click to toggle source

@private Only for Rails core compatibility.

# File lib/arjdbc/mysql/adapter.rb, line 200
def error_number(exception)
  exception.error_code if exception.respond_to?(:error_code)
end
foreign_keys(table_name) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 559
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 = '#{current_database}' " <<
      "AND fk.table_name = '#{table_name}'"

  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/arjdbc/mysql/adapter.rb, line 280
def index_algorithms
  { :default => 'ALGORITHM = DEFAULT', :copy => 'ALGORITHM = COPY', :inplace => 'ALGORITHM = INPLACE' }
end
indexes(table_name, name = nil) click to toggle source

Returns an array of indexes for the given table. @override

# File lib/arjdbc/mysql/adapter.rb, line 377
def indexes(table_name, name = nil)
  indexes = []
  current_index = nil
  result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name || 'SCHEMA')
  result.each do |row|
    key_name = row['Key_name']
    if current_index != key_name
      next if key_name == 'PRIMARY' # skip the primary key
      current_index = key_name
      indexes <<
        if self.class.const_defined?(:INDEX_TYPES) # AR 4.0
          mysql_index_type = row['Index_type'].downcase.to_sym
          index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
          index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
          IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [], nil, nil, index_type, index_using)
        else
          IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [])
        end
    end

    indexes.last.columns << row["Column_name"]
    indexes.last.lengths << row["Sub_part"]
  end
  indexes
end
init_connection(jdbc_connection) click to toggle source

@private

# File lib/arjdbc/mysql/adapter.rb, line 29
def init_connection(jdbc_connection)
  meta = jdbc_connection.meta_data
  if meta.driver_major_version == 1 # TODO check in driver code
    # assumes MariaDB 1.x currently
  elsif meta.driver_major_version < 5
    raise ::ActiveRecord::ConnectionNotEstablished,
      "MySQL adapter requires driver >= 5.0 got: '#{meta.driver_version}'"
  elsif meta.driver_major_version == 5 && meta.driver_minor_version < 1
    config[:connection_alive_sql] ||= 'SELECT 1' # need 5.1 for JDBC 4.0
  else
    # NOTE: since the loaded Java driver class can't change :
    MySQL.send(:remove_method, :init_connection) rescue nil
  end
end
initialize_schema_migrations_table() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 179
def initialize_schema_migrations_table
  if @config[:encoding] == 'utf8mb4'
    ActiveRecord::SchemaMigration.create_table(191)
  else
    ActiveRecord::SchemaMigration.create_table
  end
end
jdbc_column_class() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 24
def jdbc_column_class
  ::ActiveRecord::ConnectionAdapters::MysqlAdapter::Column
end
join_to_update(update, select) click to toggle source

In the simple case, MySQL allows us to place JOINs directly into the UPDATE query. However, this does not allow for LIMIT, OFFSET and ORDER. To support these, we must use a subquery. However, MySQL is too stupid to create a temporary table for this automatically, so we have to give it some prompting in the form of a subsubquery. Ugh! @private based on mysql_adapter.rb from 3.1-stable

# File lib/arjdbc/mysql/adapter.rb, line 688
def join_to_update(update, select)
  if select.limit || select.offset || select.orders.any?
    subsubselect = select.clone
    subsubselect.projections = [update.key]

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

    update.where update.key.in(subselect)
  else
    update.table select.source
    update.wheres = select.constraints
  end
end
limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 175
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
  where_sql
end
native_database_types() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 125
def native_database_types
  NATIVE_DATABASE_TYPES
end
new_column(field, default, type, null, collation, extra = "") click to toggle source

@private Only for Rails core compatibility.

# File lib/arjdbc/mysql/adapter.rb, line 190
def new_column(field, default, type, null, collation, extra = "")
  jdbc_column_class.new(field, default, type, null, collation, strict_mode?, extra)
end
pk_and_sequence_for(table) click to toggle source

Returns a table's primary key and belonging sequence. @note Not used, only here for potential compatibility with native adapter. @override

# File lib/arjdbc/mysql/adapter.rb, line 359
def pk_and_sequence_for(table)
  result = execute("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA').first
  if result['Create Table'].to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
    keys = $1.split(","); keys.map! { |key| key.gsub(/[`"]/, "") }
    return keys.length == 1 ? [ keys.first, nil ] : nil
  else
    return nil
  end
end
prepare_column_options(column, types) click to toggle source

@private since AR 4.2

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 773
def prepare_column_options(column, types)
  spec = super
  spec.delete(:limit) if column.type == :boolean
  spec
end
primary_key(table) click to toggle source

Returns just a table's primary key. @override

# File lib/arjdbc/mysql/adapter.rb, line 350
def primary_key(table)
  #pk_and_sequence = pk_and_sequence_for(table)
  #pk_and_sequence && pk_and_sequence.first
  @connection.primary_keys(table).first
end
quote(value, column = nil) click to toggle source

@override

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 207
def quote(value, column = nil)
  return value.quoted_id if value.respond_to?(:quoted_id)
  return value if sql_literal?(value)
  return value.to_s if column && column.type == :primary_key

  if value.kind_of?(String) && column && column.type == :binary
    "x'#{value.unpack("H*")[0]}'"
  elsif value.kind_of?(BigDecimal)
    value.to_s("F")
  else
    super
  end
end
quote_column_name(name) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 231
def quote_column_name(name)
  "`#{name.to_s.gsub('`', '``')}`"
end
quote_table_name(name) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 236
def quote_table_name(name)
  quote_column_name(name).gsub('.', '`.`')
end
recreate_database(name, options = {}) click to toggle source

@private

# File lib/arjdbc/mysql/adapter.rb, line 494
def recreate_database(name, options = {})
  drop_database(name)
  create_database(name, options)
  reconnect!
end
release_savepoint(name = current_savepoint_name(false)) click to toggle source

@override

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 307
def release_savepoint(name = current_savepoint_name(false))
  log("RELEASE SAVEPOINT #{name}", 'Savepoint') { super }
end
remove_index!(table_name, index_name) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 538
def remove_index!(table_name, index_name)
  # missing table_name quoting in AR-2.3
  execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
end
rename_column(table_name, column_name, new_column_name) click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 641
def rename_column(table_name, column_name, new_column_name)
  options = {}

  if column = columns(table_name).find { |c| c.name == column_name.to_s }
    type = column.type
    options[:default] = column.default if type != :text && type != :binary
    options[:null] = column.null
  else
    raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
  end

  current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]

  rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
  add_column_options!(rename_column_sql, options)
  execute(rename_column_sql)
  rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
end
rename_index(table_name, old_name, new_name) click to toggle source

@override

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 544
def rename_index(table_name, old_name, new_name)
  if supports_rename_index?
    validate_index_length!(table_name, new_name) if respond_to?(:validate_index_length!)
    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

@override

# File lib/arjdbc/mysql/adapter.rb, line 532
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) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
end
rollback_to_savepoint(name = current_savepoint_name(true)) click to toggle source

@override

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 302
def rollback_to_savepoint(name = current_savepoint_name(true))
  log("ROLLBACK TO SAVEPOINT #{name}", 'Savepoint') { super }
end
schema_creation() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 489
def schema_creation; SchemaCreation.new self end
show_variable(var) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 704
def show_variable(var)
  res = execute("show variables like '#{var}'")
  result_row = res.detect {|row| row["Variable_name"] == var }
  result_row && result_row["Value"]
end
strict_mode?() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 80
def strict_mode?
  config.key?(:strict) ?
    self.class.type_cast_config_to_boolean(config[:strict]) :
      AR40 # strict_mode is default since AR 4.0
end
structure_dump() click to toggle source

@deprecated no longer used - handled with (AR built-in) Rake tasks

# File lib/arjdbc/mysql/adapter.rb, line 329
def structure_dump
  # NOTE: due AR (2.3-3.2) compatibility views are not included
  if supports_views?
    sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
  else
    sql = "SHOW TABLES"
  end

  @connection.execute_query_raw(sql).map do |table|
    # e.g. { "Tables_in_arjdbc_test"=>"big_fields", "Table_type"=>"BASE TABLE" }
    table.delete('Table_type')
    table_name = table.to_a.first.last

    create_table = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")

    "#{create_table['Create Table']};\n\n"
  end.join
end
supports_foreign_keys?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 557
def supports_foreign_keys?; true end
supports_index_sort_order?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 251
def supports_index_sort_order?
  # Technically MySQL allows to create indexes with the sort order syntax
  # but at the moment (5.5) it doesn't yet implement them.
  true
end
supports_indexes_in_create?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 258
def supports_indexes_in_create?
  true
end
supports_migrations?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 241
def supports_migrations?
  true
end
supports_primary_key?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 246
def supports_primary_key?
  true
end
supports_rename_index?() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 275
def supports_rename_index?
  return false if mariadb? || ! version[0]
  (version[0] == 5 && version[1] >= 7) || version[0] >= 6
end
supports_savepoints?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 292
def supports_savepoints?
  true
end
supports_transaction_isolation?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 263
def supports_transaction_isolation?
  # MySQL 4 technically support transaction isolation, but it is affected by
  # a bug where the transaction level gets persisted for the whole session:
  # http://bugs.mysql.com/bug.php?id=39170
  version[0] && version[0] >= 5
end
supports_views?() click to toggle source

@override

# File lib/arjdbc/mysql/adapter.rb, line 271
def supports_views?
  version[0] && version[0] >= 5
end
truncate(table_name, name = nil) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 518
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/arjdbc/mysql/adapter.rb, line 719
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
update_sql(sql, name = nil) click to toggle source

@override make it public just like native MySQL adapter does

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 322
def update_sql(sql, name = nil)
  super
end
valid_type?(type) click to toggle source

@note since AR 4.2

# File lib/arjdbc/mysql/adapter.rb, line 763
def valid_type?(type)
  ! native_database_types[type].nil?
end

Protected Instance Methods

initialize_type_map(m) click to toggle source

@private

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 785
def initialize_type_map(m)
  super

  register_class_with_limit m, %r(char)i, MysqlString

  m.register_type %r(tinytext)i,   Type::Text.new(:limit => 2**8 - 1)
  m.register_type %r(tinyblob)i,   Type::Binary.new(:limit => 2**8 - 1)
  m.register_type %r(text)i,       Type::Text.new(:limit => 2**16 - 1)
  m.register_type %r(blob)i,       Type::Binary.new(:limit => 2**16 - 1)
  m.register_type %r(mediumtext)i, Type::Text.new(:limit => 2**24 - 1)
  m.register_type %r(mediumblob)i, Type::Binary.new(:limit => 2**24 - 1)
  m.register_type %r(longtext)i,   Type::Text.new(:limit => 2**32 - 1)
  m.register_type %r(longblob)i,   Type::Binary.new(:limit => 2**32 - 1)
  m.register_type %r(^float)i,     Type::Float.new(:limit => 24)
  m.register_type %r(^double)i,    Type::Float.new(:limit => 53)

  register_integer_type m, %r(^bigint)i,    :limit => 8
  register_integer_type m, %r(^int)i,       :limit => 4
  register_integer_type m, %r(^mediumint)i, :limit => 3
  register_integer_type m, %r(^smallint)i,  :limit => 2
  register_integer_type m, %r(^tinyint)i,   :limit => 1

  m.alias_type %r(tinyint\(1\))i,  'boolean' if emulate_booleans
  m.alias_type %r(set)i,           'varchar'
  m.alias_type %r(year)i,          'integer'
  m.alias_type %r(bit)i,           'binary'

  m.register_type(%r(datetime)i) do |sql_type|
    precision = extract_precision(sql_type)
    MysqlDateTime.new(:precision => precision)
  end

  m.register_type(%r(enum)i) do |sql_type|
    limit = sql_type[/^enum\((.+)\)/i, 1].split(',').
        map{|enum| enum.strip.length - 2}.max
    MysqlString.new(:limit => limit)
  end
end
quoted_columns_for_index(column_names, options = {}) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 847
def quoted_columns_for_index(column_names, options = {})
  length = options[:length] if options.is_a?(Hash)

  case length
  when Hash
    column_names.map { |name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) }
  when Fixnum
    column_names.map { |name| "#{quote_column_name(name)}(#{length})" }
  else
    column_names.map { |name| quote_column_name(name) }
  end
end
register_integer_type(mapping, key, options) click to toggle source

@private

# File lib/arjdbc/mysql/adapter.rb, line 825
def register_integer_type(mapping, key, options)
  mapping.register_type(key) do |sql_type|
    if /unsigned/i =~ sql_type
      Type::UnsignedInteger.new(options)
    else
      Type::Integer.new(options)
    end
  end
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! @note since AR 4.2

# File lib/arjdbc/mysql/adapter.rb, line 838
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

@override

Calls superclass method
# File lib/arjdbc/mysql/adapter.rb, line 861
def translate_exception(exception, message)
  return super unless exception.respond_to?(:errno)

  case exception.errno
  when 1062
    ::ActiveRecord::RecordNotUnique.new(message, exception)
  when 1452
    ::ActiveRecord::InvalidForeignKey.new(message, exception)
  else
    super
  end
end

Private Instance Methods

column_for(table_name, column_name) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 876
def column_for(table_name, column_name)
  unless column = columns(table_name).find { |c| c.name == column_name.to_s }
    raise "No such column: #{table_name}.#{column_name}"
  end
  column
end
extract_foreign_key_action(structure, name, action) click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 583
def extract_foreign_key_action(structure, name, action)
  if structure =~ /CONSTRAINT #{quote_column_name(name)} FOREIGN KEY .* REFERENCES .* ON #{action} (CASCADE|SET NULL|RESTRICT)/
    case $1
    when 'CASCADE'; :cascade
    when 'SET NULL'; :nullify
    end
  end
end
full_version() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 904
def full_version
  @full_version ||= begin
    result = execute 'SELECT VERSION()', 'SCHEMA'
    result.first.values.first # [{"VERSION()"=>"5.5.37-0ubuntu..."}]
  end
end
mariadb?() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 883
def mariadb?; !! ( full_version =~ /mariadb/i ) end
version() click to toggle source
# File lib/arjdbc/mysql/adapter.rb, line 885
def version
  return @version ||= begin
    version = []
    java_connection = jdbc_connection(true)
    if java_connection.java_class.name == 'com.mysql.jdbc.ConnectionImpl'
      version << jdbc_connection.serverMajorVersion
      version << jdbc_connection.serverMinorVersion
      version << jdbc_connection.serverSubMinorVersion
    else
      if match = full_version.match(/^(\d+)\.(\d+)\.(\d+)/)
        version << match[1].to_i
        version << match[2].to_i
        version << match[3].to_i
      end
    end
    version.freeze
  end
end