activerecord-import 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +49 -0
- data/.rubocop_todo.yml +36 -0
- data/.travis.yml +31 -7
- data/CHANGELOG.md +19 -0
- data/Gemfile +5 -2
- data/README.markdown +6 -1
- data/Rakefile +5 -2
- data/activerecord-import.gemspec +1 -1
- data/benchmarks/benchmark.rb +67 -68
- data/benchmarks/lib/base.rb +136 -137
- data/benchmarks/lib/cli_parser.rb +106 -107
- data/benchmarks/lib/mysql2_benchmark.rb +19 -21
- data/benchmarks/lib/output_to_csv.rb +2 -1
- data/benchmarks/lib/output_to_html.rb +8 -13
- data/benchmarks/schema/mysql_schema.rb +8 -8
- data/gemfiles/4.0.gemfile +1 -1
- data/gemfiles/4.1.gemfile +1 -1
- data/gemfiles/4.2.gemfile +1 -1
- data/gemfiles/5.0.gemfile +1 -1
- data/lib/activerecord-import.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +0 -1
- data/lib/activerecord-import/adapters/abstract_adapter.rb +9 -9
- data/lib/activerecord-import/adapters/mysql_adapter.rb +17 -17
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +20 -22
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +9 -9
- data/lib/activerecord-import/base.rb +3 -3
- data/lib/activerecord-import/import.rb +152 -131
- data/lib/activerecord-import/synchronize.rb +20 -20
- data/lib/activerecord-import/value_sets_parser.rb +7 -6
- data/lib/activerecord-import/version.rb +1 -1
- data/test/adapters/mysql2spatial.rb +1 -1
- data/test/adapters/postgis.rb +1 -1
- data/test/adapters/postgresql.rb +1 -1
- data/test/adapters/spatialite.rb +1 -1
- data/test/adapters/sqlite3.rb +1 -1
- data/test/import_test.rb +121 -70
- data/test/models/book.rb +5 -6
- data/test/models/chapter.rb +2 -2
- data/test/models/discount.rb +3 -0
- data/test/models/end_note.rb +2 -2
- data/test/models/promotion.rb +1 -1
- data/test/models/question.rb +1 -1
- data/test/models/rule.rb +2 -2
- data/test/models/topic.rb +3 -3
- data/test/models/widget.rb +1 -1
- data/test/postgis/import_test.rb +1 -1
- data/test/schema/generic_schema.rb +100 -96
- data/test/schema/mysql_schema.rb +5 -7
- data/test/sqlite3/import_test.rb +0 -2
- data/test/support/active_support/test_case_extensions.rb +12 -15
- data/test/support/assertions.rb +1 -1
- data/test/support/factories.rb +15 -16
- data/test/support/generate.rb +4 -4
- data/test/support/mysql/import_examples.rb +21 -21
- data/test/support/postgresql/import_examples.rb +83 -55
- data/test/support/shared_examples/on_duplicate_key_update.rb +23 -23
- data/test/synchronize_test.rb +2 -2
- data/test/test_helper.rb +6 -8
- data/test/value_sets_bytes_parser_test.rb +14 -17
- data/test/value_sets_records_parser_test.rb +6 -6
- metadata +7 -4
- data/test/travis/build.sh +0 -34
@@ -1,107 +1,106 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
require 'ostruct'
|
3
|
-
|
4
|
-
#
|
5
|
-
# == PARAMETERS
|
6
|
-
# * a - database adapter. ie: mysql, postgresql, oracle, etc.
|
7
|
-
# * n - number of objects to test with. ie: 1, 100, 1000, etc.
|
8
|
-
# * t - the table types to test. ie: myisam, innodb, memory, temporary, etc.
|
9
|
-
#
|
10
|
-
module BenchmarkOptionParser
|
11
|
-
BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options."
|
12
|
-
|
13
|
-
def self.print_banner
|
14
|
-
puts BANNER
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.print_banner!
|
18
|
-
print_banner
|
19
|
-
exit
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.print_options( options )
|
23
|
-
puts "Benchmarking the following options:"
|
24
|
-
puts " Database adapter: #{options.adapter}"
|
25
|
-
puts " Number of objects: #{options.number_of_objects}"
|
26
|
-
puts " Table types:"
|
27
|
-
print_valid_table_types( options, :
|
28
|
-
end
|
29
|
-
|
30
|
-
# TODO IMPLEMENT THIS
|
31
|
-
def self.print_valid_table_types( options, hsh={:
|
32
|
-
if options.table_types.keys.
|
33
|
-
options.table_types.keys.sort.each{ |type| puts hsh[:prefix].to_s + type.to_s }
|
34
|
-
else
|
35
|
-
puts 'No table types defined.'
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.parse( args )
|
40
|
-
options = OpenStruct.new(
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:
|
46
|
-
|
47
|
-
|
48
|
-
opts.banner = BANNER
|
49
|
-
|
50
|
-
# parse the database adapter
|
51
|
-
opts.on( "a", "--adapter [String]",
|
52
|
-
"The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
|
53
|
-
options.adapter = arg
|
54
|
-
end
|
55
|
-
|
56
|
-
# parse do_not_delete flag
|
57
|
-
opts.on( "d", "--do-not-delete",
|
58
|
-
"By default all records in the benchmark tables will be deleted at the end of the benchmark. "
|
59
|
-
"This flag indicates not to delete the benchmark data." ) do |
|
60
|
-
options.delete_on_finish = false
|
61
|
-
end
|
62
|
-
|
63
|
-
# parse the number of row objects to test
|
64
|
-
opts.on( "n", "--num [Integer]",
|
65
|
-
"The number of objects to benchmark." ) do |arg|
|
66
|
-
options.number_of_objects << arg.to_i
|
67
|
-
end
|
68
|
-
|
69
|
-
# parse the table types to test
|
70
|
-
opts.on( "t", "--table-type [String]",
|
71
|
-
"The table type to test. This can be used multiple times." ) do |arg|
|
72
|
-
if arg =~ /^all$/
|
73
|
-
options.table_types['all'] = options.benchmark_all_types = true
|
74
|
-
else
|
75
|
-
options.table_types[arg] = true
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# print results in CSV format
|
80
|
-
opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
|
81
|
-
options.outputs << OpenStruct.new( :
|
82
|
-
end
|
83
|
-
|
84
|
-
# print results in HTML format
|
85
|
-
opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
|
86
|
-
options.outputs << OpenStruct.new( :
|
87
|
-
end
|
88
|
-
end #end opt.parse!
|
89
|
-
|
90
|
-
begin
|
91
|
-
|
92
|
-
if options.table_types.
|
93
|
-
options.table_types['all'] = options.benchmark_all_types = true
|
94
|
-
end
|
95
|
-
rescue Exception
|
96
|
-
print_banner!
|
97
|
-
end
|
98
|
-
|
99
|
-
options.number_of_objects = [1000] if options.number_of_objects.empty?
|
100
|
-
options.outputs = [
|
101
|
-
|
102
|
-
print_options( options )
|
103
|
-
|
104
|
-
options
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
#
|
5
|
+
# == PARAMETERS
|
6
|
+
# * a - database adapter. ie: mysql, postgresql, oracle, etc.
|
7
|
+
# * n - number of objects to test with. ie: 1, 100, 1000, etc.
|
8
|
+
# * t - the table types to test. ie: myisam, innodb, memory, temporary, etc.
|
9
|
+
#
|
10
|
+
module BenchmarkOptionParser
|
11
|
+
BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options.".freeze
|
12
|
+
|
13
|
+
def self.print_banner
|
14
|
+
puts BANNER
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.print_banner!
|
18
|
+
print_banner
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.print_options( options )
|
23
|
+
puts "Benchmarking the following options:"
|
24
|
+
puts " Database adapter: #{options.adapter}"
|
25
|
+
puts " Number of objects: #{options.number_of_objects}"
|
26
|
+
puts " Table types:"
|
27
|
+
print_valid_table_types( options, prefix: " " )
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO IMPLEMENT THIS
|
31
|
+
def self.print_valid_table_types( options, hsh = { prefix: '' } )
|
32
|
+
if !options.table_types.keys.empty?
|
33
|
+
options.table_types.keys.sort.each { |type| puts hsh[:prefix].to_s + type.to_s }
|
34
|
+
else
|
35
|
+
puts 'No table types defined.'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.parse( args )
|
40
|
+
options = OpenStruct.new(
|
41
|
+
adapter: 'mysql2',
|
42
|
+
table_types: {},
|
43
|
+
delete_on_finish: true,
|
44
|
+
number_of_objects: [],
|
45
|
+
outputs: [] )
|
46
|
+
|
47
|
+
opt_parser = OptionParser.new do |opts|
|
48
|
+
opts.banner = BANNER
|
49
|
+
|
50
|
+
# parse the database adapter
|
51
|
+
opts.on( "a", "--adapter [String]",
|
52
|
+
"The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
|
53
|
+
options.adapter = arg
|
54
|
+
end
|
55
|
+
|
56
|
+
# parse do_not_delete flag
|
57
|
+
opts.on( "d", "--do-not-delete",
|
58
|
+
"By default all records in the benchmark tables will be deleted at the end of the benchmark. " \
|
59
|
+
"This flag indicates not to delete the benchmark data." ) do |_|
|
60
|
+
options.delete_on_finish = false
|
61
|
+
end
|
62
|
+
|
63
|
+
# parse the number of row objects to test
|
64
|
+
opts.on( "n", "--num [Integer]",
|
65
|
+
"The number of objects to benchmark." ) do |arg|
|
66
|
+
options.number_of_objects << arg.to_i
|
67
|
+
end
|
68
|
+
|
69
|
+
# parse the table types to test
|
70
|
+
opts.on( "t", "--table-type [String]",
|
71
|
+
"The table type to test. This can be used multiple times." ) do |arg|
|
72
|
+
if arg =~ /^all$/
|
73
|
+
options.table_types['all'] = options.benchmark_all_types = true
|
74
|
+
else
|
75
|
+
options.table_types[arg] = true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# print results in CSV format
|
80
|
+
opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
|
81
|
+
options.outputs << OpenStruct.new( format: 'csv', filename: filename)
|
82
|
+
end
|
83
|
+
|
84
|
+
# print results in HTML format
|
85
|
+
opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
|
86
|
+
options.outputs << OpenStruct.new( format: 'html', filename: filename )
|
87
|
+
end
|
88
|
+
end # end opt.parse!
|
89
|
+
|
90
|
+
begin
|
91
|
+
opt_parser.parse!( args )
|
92
|
+
if options.table_types.empty?
|
93
|
+
options.table_types['all'] = options.benchmark_all_types = true
|
94
|
+
end
|
95
|
+
rescue Exception
|
96
|
+
print_banner!
|
97
|
+
end
|
98
|
+
|
99
|
+
options.number_of_objects = [1000] if options.number_of_objects.empty?
|
100
|
+
options.outputs = [OpenStruct.new( format: 'html', filename: 'benchmark.html')] if options.outputs.empty?
|
101
|
+
|
102
|
+
print_options( options )
|
103
|
+
|
104
|
+
options
|
105
|
+
end
|
106
|
+
end
|
@@ -1,21 +1,19 @@
|
|
1
|
-
class Mysql2Benchmark < BenchmarkBase
|
2
|
-
|
3
|
-
|
4
|
-
methods
|
5
|
-
methods.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
1
|
+
class Mysql2Benchmark < BenchmarkBase
|
2
|
+
def benchmark_all( array_of_cols_and_vals )
|
3
|
+
methods = self.methods.find_all { |m| m =~ /benchmark_/ }
|
4
|
+
methods.delete_if { |m| m =~ /benchmark_(all|model)/ }
|
5
|
+
methods.each { |method| send( method, array_of_cols_and_vals ) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def benchmark_myisam( array_of_cols_and_vals )
|
9
|
+
bm_model( TestMyISAM, array_of_cols_and_vals )
|
10
|
+
end
|
11
|
+
|
12
|
+
def benchmark_innodb( array_of_cols_and_vals )
|
13
|
+
bm_model( TestInnoDb, array_of_cols_and_vals )
|
14
|
+
end
|
15
|
+
|
16
|
+
def benchmark_memory( array_of_cols_and_vals )
|
17
|
+
bm_model( TestMemory, array_of_cols_and_vals )
|
18
|
+
end
|
19
|
+
end
|
@@ -5,7 +5,8 @@ module OutputToCSV
|
|
5
5
|
CSV.open( filename, 'w' ) do |csv|
|
6
6
|
# Iterate over each result set, which contains many results
|
7
7
|
results.each do |result_set|
|
8
|
-
columns
|
8
|
+
columns = []
|
9
|
+
times = []
|
9
10
|
result_set.each do |result|
|
10
11
|
columns << result.description
|
11
12
|
times << result.tms.real
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'erb'
|
2
2
|
|
3
3
|
module OutputToHTML
|
4
|
-
|
5
|
-
TEMPLATE_HEADER =<<"EOT"
|
4
|
+
TEMPLATE_HEADER = <<"EOT".freeze
|
6
5
|
<div>
|
7
6
|
All times are rounded to the nearest thousandth for display purposes. Speedups next to each time are computed
|
8
7
|
before any rounding occurs. Also, all speedup calculations are computed by comparing a given time against
|
@@ -10,7 +9,7 @@ TEMPLATE_HEADER =<<"EOT"
|
|
10
9
|
</div>
|
11
10
|
EOT
|
12
11
|
|
13
|
-
TEMPLATE
|
12
|
+
TEMPLATE = <<"EOT".freeze
|
14
13
|
<style>
|
15
14
|
td#benchmarkTitle {
|
16
15
|
border: 1px solid black;
|
@@ -43,27 +42,23 @@ EOT
|
|
43
42
|
def self.output_results( filename, results )
|
44
43
|
html = ''
|
45
44
|
results.each do |result_set|
|
46
|
-
columns
|
45
|
+
columns = []
|
46
|
+
times = []
|
47
47
|
result_set.each do |result|
|
48
48
|
columns << result.description
|
49
49
|
if result.failed
|
50
50
|
times << "failed"
|
51
51
|
else
|
52
52
|
time = result.tms.real.round_to( 3 )
|
53
|
-
speedup = ( result_set.first.tms.real / result.tms.real ).round
|
54
|
-
|
55
|
-
if result == result_set.first
|
56
|
-
times << "#{time}"
|
57
|
-
else
|
58
|
-
times << "#{time} (#{speedup}x speedup)"
|
59
|
-
end
|
53
|
+
speedup = ( result_set.first.tms.real / result.tms.real ).round
|
54
|
+
times << result == result_set.first ? time.to_s : "#{time} (#{speedup}x speedup)"
|
60
55
|
end
|
61
56
|
end
|
62
57
|
|
63
58
|
template = ERB.new( TEMPLATE, 0, "%<>")
|
64
59
|
html << template.result( binding )
|
65
60
|
end
|
66
|
-
|
67
|
-
File.open( filename, 'w' ){ |file| file.write( TEMPLATE_HEADER + html ) }
|
61
|
+
|
62
|
+
File.open( filename, 'w' ) { |file| file.write( TEMPLATE_HEADER + html ) }
|
68
63
|
end
|
69
64
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
ActiveRecord::Schema.define do
|
2
|
-
create_table :test_myisam, :
|
3
|
-
t.column :my_name, :string, :
|
2
|
+
create_table :test_myisam, options: 'ENGINE=MyISAM', force: true do |t|
|
3
|
+
t.column :my_name, :string, null: false
|
4
4
|
t.column :description, :string
|
5
5
|
end
|
6
|
-
|
7
|
-
create_table :test_innodb, :
|
8
|
-
t.column :my_name, :string, :
|
6
|
+
|
7
|
+
create_table :test_innodb, options: 'ENGINE=InnoDb', force: true do |t|
|
8
|
+
t.column :my_name, :string, null: false
|
9
9
|
t.column :description, :string
|
10
10
|
end
|
11
11
|
|
12
|
-
create_table :test_memory, :
|
13
|
-
t.column :my_name, :string, :
|
12
|
+
create_table :test_memory, options: 'ENGINE=Memory', force: true do |t|
|
13
|
+
t.column :my_name, :string, null: false
|
14
14
|
t.column :description, :string
|
15
15
|
end
|
16
|
-
end
|
16
|
+
end
|
data/gemfiles/4.0.gemfile
CHANGED
data/gemfiles/4.1.gemfile
CHANGED
data/gemfiles/4.2.gemfile
CHANGED
data/gemfiles/5.0.gemfile
CHANGED
data/lib/activerecord-import.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
module ActiveRecord::Import::AbstractAdapter
|
2
2
|
module InstanceMethods
|
3
3
|
def next_value_for_sequence(sequence_name)
|
4
|
-
%
|
4
|
+
%(#{sequence_name}.nextval)
|
5
5
|
end
|
6
6
|
|
7
7
|
def insert_many( sql, values, *args ) # :nodoc:
|
8
8
|
number_of_inserts = 1
|
9
9
|
|
10
|
-
base_sql,post_sql = if sql.is_a?( String )
|
11
|
-
[
|
10
|
+
base_sql, post_sql = if sql.is_a?( String )
|
11
|
+
[sql, '']
|
12
12
|
elsif sql.is_a?( Array )
|
13
|
-
[
|
13
|
+
[sql.shift, sql.join( ' ' )]
|
14
14
|
end
|
15
15
|
|
16
16
|
sql2insert = base_sql + values.join( ',' ) + post_sql
|
17
17
|
insert( sql2insert, *args )
|
18
18
|
|
19
|
-
[number_of_inserts,[]]
|
19
|
+
[number_of_inserts, []]
|
20
20
|
end
|
21
21
|
|
22
22
|
def pre_sql_statements(options)
|
@@ -25,7 +25,7 @@ module ActiveRecord::Import::AbstractAdapter
|
|
25
25
|
sql << options[:command] if options[:command]
|
26
26
|
sql << "IGNORE" if options[:ignore]
|
27
27
|
|
28
|
-
#add keywords like IGNORE or DELAYED
|
28
|
+
# add keywords like IGNORE or DELAYED
|
29
29
|
if options[:keywords].is_a?(Array)
|
30
30
|
sql.concat(options[:keywords])
|
31
31
|
elsif options[:keywords]
|
@@ -38,7 +38,7 @@ module ActiveRecord::Import::AbstractAdapter
|
|
38
38
|
# Synchronizes the passed in ActiveRecord instances with the records in
|
39
39
|
# the database by calling +reload+ on each instance.
|
40
40
|
def after_import_synchronize( instances )
|
41
|
-
instances.each
|
41
|
+
instances.each(&:reload)
|
42
42
|
end
|
43
43
|
|
44
44
|
# Returns an array of post SQL statements given the passed in options.
|
@@ -53,10 +53,10 @@ module ActiveRecord::Import::AbstractAdapter
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
#custom user post_sql
|
56
|
+
# custom user post_sql
|
57
57
|
post_sql_statements << options[:post_sql] if options[:post_sql]
|
58
58
|
|
59
|
-
#with rollup
|
59
|
+
# with rollup
|
60
60
|
post_sql_statements << rollup_sql if options[:rollup]
|
61
61
|
|
62
62
|
post_sql_statements
|
@@ -3,7 +3,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
3
3
|
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
4
4
|
|
5
5
|
NO_MAX_PACKET = 0
|
6
|
-
QUERY_OVERHEAD = 8 #This was shown to be true for MySQL, but it's not clear where the overhead is from.
|
6
|
+
QUERY_OVERHEAD = 8 # This was shown to be true for MySQL, but it's not clear where the overhead is from.
|
7
7
|
|
8
8
|
# +sql+ can be a single string or an array. If it is an array all
|
9
9
|
# elements that are in position >= 1 will be appended to the final SQL.
|
@@ -11,19 +11,19 @@ module ActiveRecord::Import::MysqlAdapter
|
|
11
11
|
# the number of inserts default
|
12
12
|
number_of_inserts = 0
|
13
13
|
|
14
|
-
base_sql,post_sql = if sql.is_a?( String )
|
15
|
-
[
|
14
|
+
base_sql, post_sql = if sql.is_a?( String )
|
15
|
+
[sql, '']
|
16
16
|
elsif sql.is_a?( Array )
|
17
|
-
[
|
17
|
+
[sql.shift, sql.join( ' ' )]
|
18
18
|
end
|
19
19
|
|
20
20
|
sql_size = QUERY_OVERHEAD + base_sql.size + post_sql.size
|
21
21
|
|
22
22
|
# the number of bytes the requested insert statement values will take up
|
23
|
-
values_in_bytes = values.sum
|
23
|
+
values_in_bytes = values.sum(&:bytesize)
|
24
24
|
|
25
25
|
# the number of bytes (commas) it will take to comma separate our values
|
26
|
-
comma_separated_bytes = values.size-1
|
26
|
+
comma_separated_bytes = values.size - 1
|
27
27
|
|
28
28
|
# the total number of bytes required if this statement is one statement
|
29
29
|
total_bytes = sql_size + values_in_bytes + comma_separated_bytes
|
@@ -31,22 +31,22 @@ module ActiveRecord::Import::MysqlAdapter
|
|
31
31
|
max = max_allowed_packet
|
32
32
|
|
33
33
|
# if we can insert it all as one statement
|
34
|
-
if NO_MAX_PACKET == max
|
34
|
+
if NO_MAX_PACKET == max || total_bytes < max
|
35
35
|
number_of_inserts += 1
|
36
36
|
sql2insert = base_sql + values.join( ',' ) + post_sql
|
37
37
|
insert( sql2insert, *args )
|
38
38
|
else
|
39
39
|
value_sets = ::ActiveRecord::Import::ValueSetsBytesParser.parse(values,
|
40
|
-
:
|
41
|
-
:
|
42
|
-
value_sets.each do |
|
40
|
+
reserved_bytes: sql_size,
|
41
|
+
max_bytes: max)
|
42
|
+
value_sets.each do |value_set|
|
43
43
|
number_of_inserts += 1
|
44
|
-
sql2insert = base_sql +
|
44
|
+
sql2insert = base_sql + value_set.join( ',' ) + post_sql
|
45
45
|
insert( sql2insert, *args )
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
[number_of_inserts,[]]
|
49
|
+
[number_of_inserts, []]
|
50
50
|
end
|
51
51
|
|
52
52
|
# Returns the maximum number of bytes that the server will allow
|
@@ -61,7 +61,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
61
61
|
end
|
62
62
|
|
63
63
|
# Add a column to be updated on duplicate key update
|
64
|
-
def add_column_for_on_duplicate_key_update( column, options={} ) # :nodoc:
|
64
|
+
def add_column_for_on_duplicate_key_update( column, options = {} ) # :nodoc:
|
65
65
|
if options.include?(:on_duplicate_key_update)
|
66
66
|
columns = options[:on_duplicate_key_update]
|
67
67
|
case columns
|
@@ -69,7 +69,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
69
69
|
when Hash then columns[column.to_sym] = column.to_sym
|
70
70
|
end
|
71
71
|
else
|
72
|
-
options[:on_duplicate_key_update] = [
|
72
|
+
options[:on_duplicate_key_update] = [column.to_sym]
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -85,12 +85,12 @@ module ActiveRecord::Import::MysqlAdapter
|
|
85
85
|
elsif arg.is_a?( String )
|
86
86
|
sql << arg
|
87
87
|
else
|
88
|
-
raise ArgumentError
|
88
|
+
raise ArgumentError, "Expected Array or Hash"
|
89
89
|
end
|
90
90
|
sql
|
91
91
|
end
|
92
92
|
|
93
|
-
def sql_for_on_duplicate_key_update_as_array( table_name, arr )
|
93
|
+
def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
|
94
94
|
results = arr.map do |column|
|
95
95
|
qc = quote_column_name( column )
|
96
96
|
"#{table_name}.#{qc}=VALUES(#{qc})"
|
@@ -108,7 +108,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
108
108
|
end
|
109
109
|
|
110
110
|
# Return true if the statement is a duplicate key record error
|
111
|
-
def duplicate_key_update_error?(exception)# :nodoc:
|
111
|
+
def duplicate_key_update_error?(exception) # :nodoc:
|
112
112
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
|
113
113
|
end
|
114
114
|
end
|