Class: ActiveRecord::ConnectionAdapters::MysqlAdapter

Inherits:
AbstractAdapter show all
Defined in:
lib/active_record/connection_adapters/mysql_adapter.rb

Overview

The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with the faster C-based MySQL/Ruby adapter (available both as a gem and from www.tmtm.org/en/mysql/ruby/).

Options:

  • :host – Defaults to localhost

  • :port – Defaults to 3306

  • :socket – Defaults to /tmp/mysql.sock

  • :username – Defaults to root

  • :password – Defaults to nothing

  • :database – The name of the database. No default, must be provided.

  • :encoding – (Optional) Sets the client encoding by executing “SET NAMES <encoding>” after connection

  • :sslkey – Necessary to use MySQL with an SSL connection

  • :sslcert – Necessary to use MySQL with an SSL connection

  • :sslcapath – Necessary to use MySQL with an SSL connection

  • :sslcipher – Necessary to use MySQL with an SSL connection

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 environment.rb file:

ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false

Constant Summary collapse

LOST_CONNECTION_ERROR_MESSAGES =
[
  "Server shutdown in progress",
  "Broken pipe",
  "Lost connection to MySQL server during query",
  "MySQL server has gone away"
]
@@emulate_booleans =
true

Instance Method Summary collapse

Methods inherited from AbstractAdapter

#log_info, #prefetch_primary_key?, #raw_connection, #requires_reloading?, #reset_runtime, #supports_count_distinct?, #verify!

Methods included from QueryCache

#cache, #uncached

Methods included from Quoting

#quoted_date, #quoted_string_prefix

Methods included from DatabaseStatements

#add_limit!, #add_lock!, #default_sequence_name, #delete, #empty_insert_statement, #insert, #insert_fixture, #reset_sequence!, #sanitize_limit, #select_all, #select_one, #select_value, #select_values, #transaction, #update

Methods included from SchemaStatements

#add_column, #add_column_options!, #add_index, #add_order_by_for_association_limiting!, #distinct, #dump_schema_information, #index_name, #initialize_schema_information, #remove_column, #remove_index, #table_alias_for, #table_alias_length, #type_to_sql

Constructor Details

#initialize(connection, logger, connection_options, config) ⇒ MysqlAdapter

Returns a new instance of MysqlAdapter.



161
162
163
164
165
166
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 161

def initialize(connection, logger, connection_options, config)
  super(connection, logger)
  @connection_options, @config = connection_options, config

  connect
end

Instance Method Details

#active?Boolean

CONNECTION MANAGEMENT ====================================

Returns:

  • (Boolean)


242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 242

def active?
  if @connection.respond_to?(:stat)
    @connection.stat
  else
    @connection.query 'select 1'
  end

  # mysql-ruby doesn't raise an exception when stat fails.
  if @connection.respond_to?(:errno)
    @connection.errno.zero?
  else
    true
  end
rescue Mysql::Error
  false
end

#adapter_nameObject

:nodoc:



168
169
170
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 168

def adapter_name #:nodoc:
  'MySQL'
end

#add_limit_offset!(sql, options) ⇒ Object

:nodoc:



319
320
321
322
323
324
325
326
327
328
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 319

def add_limit_offset!(sql, options) #:nodoc:
  if limit = options[:limit]
    limit = sanitize_limit(limit)
    unless offset = options[:offset]
      sql << " LIMIT #{limit}"
    else
      sql << " LIMIT #{offset.to_i}, #{limit}"
    end
  end
end

#begin_db_transactionObject

:nodoc:



300
301
302
303
304
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 300

def begin_db_transaction #:nodoc:
  execute "BEGIN"
rescue Exception
  # Transactions aren't supported
end

#change_column(table_name, column_name, type, options = {}) ⇒ Object

:nodoc:



430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 430

def change_column(table_name, column_name, type, options = {}) #:nodoc:
  unless options_include_default?(options)
    if column = columns(table_name).find { |c| c.name == column_name.to_s }
      options[:default] = column.default
    else
      raise "No such column: #{table_name}.#{column_name}"
    end
  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)
  execute(change_column_sql)
end

#change_column_default(table_name, column_name, default) ⇒ Object

:nodoc:



424
425
426
427
428
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 424

def change_column_default(table_name, column_name, default) #:nodoc:
  current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]

  execute("ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{current_type} DEFAULT #{quote(default)}")
end

#charsetObject

Returns the database character set.



375
376
377
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 375

def charset
  show_variable 'character_set_database'
end

#collationObject

Returns the database collation strategy.



380
381
382
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 380

def collation
  show_variable 'collation_database'
end

#columns(table_name, name = nil) ⇒ Object

:nodoc:



409
410
411
412
413
414
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 409

def columns(table_name, name = nil)#:nodoc:
  sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
  columns = []
  execute(sql, name).each { |field| columns << MysqlColumn.new(field[0], field[4], field[1], field[2] == "YES") }
  columns
end

#commit_db_transactionObject

:nodoc:



306
307
308
309
310
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 306

def commit_db_transaction #:nodoc:
  execute "COMMIT"
rescue Exception
  # Transactions aren't supported
end

#create_database(name, options = {}) ⇒ Object

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


358
359
360
361
362
363
364
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 358

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_table(table_name, options = {}) ⇒ Object

:nodoc:



416
417
418
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 416

def create_table(table_name, options = {}) #:nodoc:
  super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB"))
end

#current_databaseObject



370
371
372
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 370

def current_database
  select_value 'SELECT DATABASE() as db'
end

#disable_referential_integrity(&block) ⇒ Object

REFERENTIAL INTEGRITY ====================================



229
230
231
232
233
234
235
236
237
238
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 229

def disable_referential_integrity(&block) #:nodoc:
  old = select_value("SELECT @@FOREIGN_KEY_CHECKS")

  begin
    update("SET FOREIGN_KEY_CHECKS = 0")
    yield
  ensure
    update("SET FOREIGN_KEY_CHECKS = #{old}")
  end
end

#disconnect!Object



264
265
266
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 264

def disconnect!
  @connection.close rescue nil
end

#drop_database(name) ⇒ Object

:nodoc:



366
367
368
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 366

def drop_database(name) #:nodoc:
  execute "DROP DATABASE IF EXISTS `#{name}`"
end

#drop_table(table_name, options = {}) ⇒ Object



390
391
392
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 390

def drop_table(table_name, options = {})
  super(table_name, options)
end

#execute(sql, name = nil) ⇒ Object

:nodoc:



280
281
282
283
284
285
286
287
288
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 280

def execute(sql, name = nil) #:nodoc:
  log(sql, name) { @connection.query(sql) }
rescue ActiveRecord::StatementInvalid => exception
  if exception.message.split(":").first =~ /Packets out of order/
    raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information.  If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
  else
    raise
  end
end

#indexes(table_name, name = nil) ⇒ Object

:nodoc:



394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 394

def indexes(table_name, name = nil)#:nodoc:
  indexes = []
  current_index = nil
  execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name).each do |row|
    if current_index != row[2]
      next if row[2] == "PRIMARY" # skip the primary key
      current_index = row[2]
      indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [])
    end

    indexes.last.columns << row[4]
  end
  indexes
end

#insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) ⇒ Object

:nodoc:



290
291
292
293
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 290

def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
  super sql, name
  id_value || @connection.insert_id
end

#native_database_typesObject

:nodoc:



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 176

def native_database_types #:nodoc:
  {
    :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
    :string      => { :name => "varchar", :limit => 255 },
    :text        => { :name => "text" },
    :integer     => { :name => "int", :limit => 11 },
    :float       => { :name => "float" },
    :decimal     => { :name => "decimal" },
    :datetime    => { :name => "datetime" },
    :timestamp   => { :name => "datetime" },
    :time        => { :name => "time" },
    :date        => { :name => "date" },
    :binary      => { :name => "blob" },
    :boolean     => { :name => "tinyint", :limit => 1 }
  }
end

#pk_and_sequence_for(table) ⇒ Object

Returns a table’s primary key and belonging sequence.



457
458
459
460
461
462
463
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 457

def pk_and_sequence_for(table) #:nodoc:
  keys = []
  execute("describe #{quote_table_name(table)}").each_hash do |h|
    keys << h["Field"]if h["Key"] == "PRI"
  end
  keys.length == 1 ? [keys.first, nil] : nil
end

#quote(value, column = nil) ⇒ Object

QUOTING ==================================================



196
197
198
199
200
201
202
203
204
205
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 196

def quote(value, column = nil)
  if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
    s = column.class.string_to_binary(value).unpack("H*")[0]
    "x'#{s}'"
  elsif value.kind_of?(BigDecimal)
    "'#{value.to_s("F")}'"
  else
    super
  end
end

#quote_column_name(name) ⇒ Object

:nodoc:



207
208
209
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 207

def quote_column_name(name) #:nodoc:
  "`#{name}`"
end

#quote_string(string) ⇒ Object

:nodoc:



215
216
217
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 215

def quote_string(string) #:nodoc:
  @connection.quote(string)
end

#quote_table_name(name) ⇒ Object

:nodoc:



211
212
213
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 211

def quote_table_name(name) #:nodoc:
  quote_column_name(name).gsub('.', '`.`')
end

#quoted_falseObject



223
224
225
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 223

def quoted_false
  "0"
end

#quoted_trueObject



219
220
221
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 219

def quoted_true
  "1"
end

#reconnect!Object



259
260
261
262
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 259

def reconnect!
  disconnect!
  connect
end

#recreate_database(name) ⇒ Object

:nodoc:



346
347
348
349
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 346

def recreate_database(name) #:nodoc:
  drop_database(name)
  create_database(name)
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:



444
445
446
447
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 444

def rename_column(table_name, column_name, new_column_name) #:nodoc:
  current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
  execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
end

#rename_table(table_name, new_name) ⇒ Object



420
421
422
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 420

def rename_table(table_name, new_name)
  execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
end

#rollback_db_transactionObject

:nodoc:



312
313
314
315
316
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 312

def rollback_db_transaction #:nodoc:
  execute "ROLLBACK"
rescue Exception
  # Transactions aren't supported
end

#select_rows(sql, name = nil) ⇒ Object

DATABASE STATEMENTS ======================================



271
272
273
274
275
276
277
278
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 271

def select_rows(sql, name = nil)
  @connection.query_with_result = true
  result = execute(sql, name)
  rows = []
  result.each { |row| rows << row }
  result.free
  rows
end

#show_variable(name) ⇒ Object

SHOW VARIABLES LIKE ‘name’



451
452
453
454
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 451

def show_variable(name)
  variables = select_all("SHOW VARIABLES LIKE '#{name}'")
  variables.first['Value'] unless variables.empty?
end

#structure_dumpObject

SCHEMA STATEMENTS ========================================



333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 333

def structure_dump #:nodoc:
  if supports_views?
    sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
  else
    sql = "SHOW TABLES"
  end

  select_all(sql).inject("") do |structure, table|
    table.delete('Table_type')
    structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n"
  end
end

#supports_migrations?Boolean

:nodoc:

Returns:

  • (Boolean)


172
173
174
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 172

def supports_migrations? #:nodoc:
  true
end

#tables(name = nil) ⇒ Object

:nodoc:



384
385
386
387
388
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 384

def tables(name = nil) #:nodoc:
  tables = []
  execute("SHOW TABLES", name).each { |field| tables << field[0] }
  tables
end

#update_sql(sql, name = nil) ⇒ Object

:nodoc:



295
296
297
298
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 295

def update_sql(sql, name = nil) #:nodoc:
  super
  @connection.affected_rows
end