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.

  • :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

#clear_query_cache

Constructor Details

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

Returns a new instance of MysqlAdapter.



148
149
150
151
152
153
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 148

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)


213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 213

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:



155
156
157
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 155

def adapter_name #:nodoc:
  'MySQL'
end

#add_limit_offset!(sql, options) ⇒ Object

:nodoc:



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

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:



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

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

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

:nodoc:



366
367
368
369
370
371
372
373
374
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 366

def change_column(table_name, column_name, type, options = {}) #:nodoc:
  unless options_include_default?(options)
    options[:default] = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["Default"]
  end

  change_column_sql = "ALTER TABLE #{table_name} CHANGE #{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:



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

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

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

#columns(table_name, name = nil) ⇒ Object

:nodoc:



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

def columns(table_name, name = nil)#:nodoc:
  sql = "SHOW FIELDS FROM #{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:



268
269
270
271
272
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 268

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

#create_database(name) ⇒ Object

:nodoc:



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

def create_database(name) #:nodoc:
  execute "CREATE DATABASE `#{name}`"
end

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

:nodoc:



352
353
354
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 352

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

#current_databaseObject



320
321
322
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 320

def current_database
  select_one("SELECT DATABASE() as db")["db"]
end

#disconnect!Object



235
236
237
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 235

def disconnect!
  @connection.close rescue nil
end

#drop_database(name) ⇒ Object

:nodoc:



316
317
318
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 316

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

#execute(sql, name = nil) ⇒ Object

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



242
243
244
245
246
247
248
249
250
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 242

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:



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

def indexes(table_name, name = nil)#:nodoc:
  indexes = []
  current_index = nil
  execute("SHOW KEYS FROM #{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, name = nil, pk = nil, id_value = nil, sequence_name = nil) ⇒ Object

:nodoc:



252
253
254
255
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 252

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

#native_database_typesObject

:nodoc:



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 163

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

#quote(value, column = nil) ⇒ Object

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



183
184
185
186
187
188
189
190
191
192
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 183

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:



194
195
196
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 194

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

#quote_string(string) ⇒ Object

:nodoc:



198
199
200
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 198

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

#quoted_falseObject



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

def quoted_false
  "0"
end

#quoted_trueObject



202
203
204
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 202

def quoted_true
  "1"
end

#reconnect!Object



230
231
232
233
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 230

def reconnect!
  disconnect!
  connect
end

#recreate_database(name) ⇒ Object

:nodoc:



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

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

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:



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

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

#rename_table(name, new_name) ⇒ Object



356
357
358
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 356

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

#rollback_db_transactionObject

:nodoc:



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

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

#structure_dumpObject

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



294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 294

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 #{table.to_a.first.last}")["Create Table"] + ";\n\n"
  end
end

#supports_migrations?Boolean

:nodoc:

Returns:

  • (Boolean)


159
160
161
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 159

def supports_migrations? #:nodoc:
  true
end

#tables(name = nil) ⇒ Object

:nodoc:



324
325
326
327
328
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 324

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

#update(sql, name = nil) ⇒ Object

:nodoc:



257
258
259
260
# File 'lib/active_record/connection_adapters/mysql_adapter.rb', line 257

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