# lots of folks doing something like this now - take a look for other good ideas
# https://github.com/jsuchal/activerecord-fast-import/blob/master/lib/activerecord-fast-import.rb
# https://github.com/EmmanuelOga/load_data_infile/blob/master/lib/load_data_infile.rb
# Source code for the MysqlAdapter extensions.
module ActiveRecord #:nodoc:
module ConnectionAdapters #:nodoc:
# Adds new functionality to ActiveRecord MysqlAdapter.
class MysqlAdapter < AbstractAdapter
def support_select_into_table?
true
end
# Inserts an INTO table_name clause to the sql_query.
def add_select_into_table(new_table_name, sql_query)
"CREATE TABLE #{new_table_name} " + sql_query
end
# Copy the specified table.
def copy_table(old_table_name, new_table_name)
transaction do
execute "CREATE TABLE #{new_table_name} LIKE #{old_table_name}"
execute "INSERT INTO #{new_table_name} SELECT * FROM #{old_table_name}"
end
end
def disable_keys(table)
execute("ALTER TABLE #{table} DISABLE KEYS")
end
def enable_keys(table)
execute("ALTER TABLE #{table} ENABLE KEYS")
end
def with_keys_disabled(table)
disable_keys(table)
yield
ensure
enable_keys(table)
end
protected
# Call +bulk_load+, as that method wraps this method.
#
# Bulk load the data in the specified file. This implementation always uses the LOCAL keyword
# so the file must be found locally, not on the remote server, to be loaded.
#
# Options:
# * :ignore -- Ignore the specified number of lines from the source file
# * :columns -- Array of column names defining the source file column order
# * :fields -- Hash of options for fields:
# * :delimited_by -- The field delimiter
# * :enclosed_by -- The field enclosure
# * :replace -- Add in REPLACE to LOAD DATA INFILE command
# * :disable_keys -- if set to true, disable keys, loads, then enables again
def do_bulk_load(file, table_name, options={})
return if File.size(file) == 0
# an unfortunate hack - setting the bulk load option after the connection has been
# established does not seem to have any effect, and since the connection is made when
# active-record is loaded, there's no chance for us to sneak it in earlier. So we
# disconnect, set the option, then reconnect - fortunately, this only needs to happen once.
unless @bulk_load_enabled
disconnect!
@connection.options(Mysql::OPT_LOCAL_INFILE, true)
connect
@bulk_load_enabled = true
end
q = "LOAD DATA LOCAL INFILE '#{file}' #{options[:replace] ? 'REPLACE' : ''} INTO TABLE #{table_name}"
if options[:fields]
q << " FIELDS"
q << " TERMINATED BY '#{options[:fields][:delimited_by]}'" if options[:fields][:delimited_by]
q << " ENCLOSED BY '#{options[:fields][:enclosed_by]}'" if options[:fields][:enclosed_by]
end
q << " IGNORE #{options[:ignore]} LINES" if options[:ignore]
q << " (#{options[:columns].map { |c| quote_column_name(c.to_s) }.join(',')})" if options[:columns]
if options[:disable_keys]
with_keys_disabled(table_name) { execute(q) }
else
execute(q)
end
end
end
end
end