Module: ActiveRecord::Import::MysqlAdapter
- Includes:
- ImportSupport, OnDuplicateKeyUpdateSupport
- Included in:
- ConnectionAdapters::SeamlessDatabasePoolAdapter, EMMysql2Adapter, Mysql2Adapter, TrilogyAdapter
- Defined in:
- lib/activerecord-import/adapters/mysql_adapter.rb
Constant Summary collapse
- NO_MAX_PACKET =
0
- QUERY_OVERHEAD =
This was shown to be true for MySQL, but it’s not clear where the overhead is from.
8
Instance Method Summary collapse
-
#add_column_for_on_duplicate_key_update(column, options = {}) ⇒ Object
Add a column to be updated on duplicate key update.
-
#duplicate_key_update_error?(exception) ⇒ Boolean
Return true if the statement is a duplicate key record error.
- #increment_locking_column!(table_name, results, locking_column) ⇒ Object
-
#insert_many(sql, values, options = {}, *args) ⇒ Object
sql
can be a single string or an array. -
#max_allowed_packet ⇒ Object
Returns the maximum number of bytes that the server will allow in a single packet.
- #pre_sql_statements(options) ⇒ Object
-
#sql_for_on_duplicate_key_update(table_name, *args) ⇒ Object
Returns a generated ON DUPLICATE KEY UPDATE statement given the passed in
args
. -
#sql_for_on_duplicate_key_update_as_array(table_name, model, locking_column, arr) ⇒ Object
:nodoc:.
-
#sql_for_on_duplicate_key_update_as_hash(table_name, model, locking_column, hsh) ⇒ Object
:nodoc:.
Methods included from OnDuplicateKeyUpdateSupport
#supports_on_duplicate_key_update?
Methods included from ImportSupport
Instance Method Details
#add_column_for_on_duplicate_key_update(column, options = {}) ⇒ Object
Add a column to be updated on duplicate key update
76 77 78 79 80 81 82 83 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 76 def add_column_for_on_duplicate_key_update( column, = {} ) # :nodoc: if (columns = [:on_duplicate_key_update]) case columns when Array then columns << column.to_sym unless columns.include?(column.to_sym) when Hash then columns[column.to_sym] = column.to_sym end end end |
#duplicate_key_update_error?(exception) ⇒ Boolean
Return true if the statement is a duplicate key record error
128 129 130 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 128 def duplicate_key_update_error?(exception) # :nodoc: exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry') end |
#increment_locking_column!(table_name, results, locking_column) ⇒ Object
132 133 134 135 136 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 132 def increment_locking_column!(table_name, results, locking_column) if locking_column.present? results << "`#{locking_column}`=#{table_name}.`#{locking_column}`+1" end end |
#insert_many(sql, values, options = {}, *args) ⇒ Object
sql
can be a single string or an array. If it is an array all elements that are in position >= 1 will be appended to the final SQL.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 12 def insert_many( sql, values, = {}, *args ) # :nodoc: # the number of inserts default number_of_inserts = 0 base_sql, post_sql = case sql when String [sql, ''] when Array [sql.shift, sql.join( ' ' )] end sql_size = QUERY_OVERHEAD + base_sql.bytesize + post_sql.bytesize # the number of bytes the requested insert statement values will take up values_in_bytes = values.sum(&:bytesize) # the number of bytes (commas) it will take to comma separate our values comma_separated_bytes = values.size - 1 # the total number of bytes required if this statement is one statement total_bytes = sql_size + values_in_bytes + comma_separated_bytes max = max_allowed_packet # if we can insert it all as one statement if max == NO_MAX_PACKET || total_bytes <= max || [:force_single_insert] number_of_inserts += 1 sql2insert = base_sql + values.join( ',' ) + post_sql insert( sql2insert, *args ) else value_sets = ::ActiveRecord::Import::ValueSetsBytesParser.parse(values, reserved_bytes: sql_size, max_bytes: max) transaction(requires_new: true) do value_sets.each do |value_set| number_of_inserts += 1 sql2insert = base_sql + value_set.join( ',' ) + post_sql insert( sql2insert, *args ) end end end ActiveRecord::Import::Result.new([], number_of_inserts, [], []) end |
#max_allowed_packet ⇒ Object
Returns the maximum number of bytes that the server will allow in a single packet
60 61 62 63 64 65 66 67 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 60 def max_allowed_packet # :nodoc: @max_allowed_packet ||= begin result = execute( "SELECT @@max_allowed_packet" ) # original Mysql gem responds to #fetch_row while Mysql2 responds to #first val = result.respond_to?(:fetch_row) ? result.fetch_row[0] : result.first[0] val.to_i end end |
#pre_sql_statements(options) ⇒ Object
69 70 71 72 73 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 69 def pre_sql_statements( ) sql = [] sql << "IGNORE" if [:ignore] || [:on_duplicate_key_ignore] sql + super end |
#sql_for_on_duplicate_key_update(table_name, *args) ⇒ Object
Returns a generated ON DUPLICATE KEY UPDATE statement given the passed in args
.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 87 def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc: sql = ' ON DUPLICATE KEY UPDATE '.dup arg, model, _primary_key, locking_column = args case arg when Array sql << sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, arg ) when Hash sql << sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, arg ) when String sql << arg else raise ArgumentError, "Expected Array or Hash" end sql end |
#sql_for_on_duplicate_key_update_as_array(table_name, model, locking_column, arr) ⇒ Object
:nodoc:
103 104 105 106 107 108 109 110 111 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 103 def sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, arr ) # :nodoc: results = arr.map do |column| original_column_name = model.attribute_alias?( column ) ? model.attribute_alias( column ) : column qc = quote_column_name( original_column_name ) "#{table_name}.#{qc}=VALUES(#{qc})" end increment_locking_column!(table_name, results, locking_column) results.join( ',' ) end |
#sql_for_on_duplicate_key_update_as_hash(table_name, model, locking_column, hsh) ⇒ Object
:nodoc:
113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/activerecord-import/adapters/mysql_adapter.rb', line 113 def sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, hsh ) # :nodoc: results = hsh.map do |column1, column2| original_column1_name = model.attribute_alias?( column1 ) ? model.attribute_alias( column1 ) : column1 qc1 = quote_column_name( original_column1_name ) original_column2_name = model.attribute_alias?( column2 ) ? model.attribute_alias( column2 ) : column2 qc2 = quote_column_name( original_column2_name ) "#{table_name}.#{qc1}=VALUES( #{qc2} )" end increment_locking_column!(table_name, results, locking_column) results.join( ',') end |