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!, #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
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 319

def add_limit_offset!(sql, options) #:nodoc:
  if limit = options[:limit]
    unless offset = options[:offset]
      sql << " LIMIT #{limit}"
    else
      sql << " LIMIT #{offset}, #{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:



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

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:



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

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.



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

def charset
  show_variable 'character_set_database'
end

#collationObject

Returns the database collation strategy.



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

def collation
  show_variable 'collation_database'
end

#columns(table_name, name = nil) ⇒ Object

:nodoc:



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

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


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

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:



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

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

#current_databaseObject



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

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:



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

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

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



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

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:



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

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.



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

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:



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

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

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:



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

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



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

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’



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

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

#structure_dumpObject

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



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

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:



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

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