activerecord-import 0.10.0 → 1.0.8

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.
Files changed (118) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +49 -0
  4. data/.rubocop_todo.yml +36 -0
  5. data/.travis.yml +64 -8
  6. data/CHANGELOG.md +475 -0
  7. data/Gemfile +32 -15
  8. data/LICENSE +21 -56
  9. data/README.markdown +564 -35
  10. data/Rakefile +20 -3
  11. data/activerecord-import.gemspec +7 -7
  12. data/benchmarks/README +2 -2
  13. data/benchmarks/benchmark.rb +68 -64
  14. data/benchmarks/lib/base.rb +138 -137
  15. data/benchmarks/lib/cli_parser.rb +107 -103
  16. data/benchmarks/lib/{mysql_benchmark.rb → mysql2_benchmark.rb} +19 -22
  17. data/benchmarks/lib/output_to_csv.rb +5 -4
  18. data/benchmarks/lib/output_to_html.rb +8 -13
  19. data/benchmarks/models/test_innodb.rb +1 -1
  20. data/benchmarks/models/test_memory.rb +1 -1
  21. data/benchmarks/models/test_myisam.rb +1 -1
  22. data/benchmarks/schema/mysql2_schema.rb +16 -0
  23. data/gemfiles/3.2.gemfile +2 -4
  24. data/gemfiles/4.0.gemfile +2 -4
  25. data/gemfiles/4.1.gemfile +2 -4
  26. data/gemfiles/4.2.gemfile +2 -4
  27. data/gemfiles/5.0.gemfile +2 -0
  28. data/gemfiles/5.1.gemfile +2 -0
  29. data/gemfiles/5.2.gemfile +2 -0
  30. data/gemfiles/6.0.gemfile +2 -0
  31. data/gemfiles/6.1.gemfile +1 -0
  32. data/lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb +6 -0
  33. data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +0 -1
  34. data/lib/activerecord-import/adapters/abstract_adapter.rb +23 -17
  35. data/lib/activerecord-import/adapters/mysql_adapter.rb +52 -25
  36. data/lib/activerecord-import/adapters/postgresql_adapter.rb +187 -10
  37. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +148 -17
  38. data/lib/activerecord-import/base.rb +15 -9
  39. data/lib/activerecord-import/import.rb +740 -191
  40. data/lib/activerecord-import/synchronize.rb +21 -21
  41. data/lib/activerecord-import/value_sets_parser.rb +33 -8
  42. data/lib/activerecord-import/version.rb +1 -1
  43. data/lib/activerecord-import.rb +4 -15
  44. data/test/adapters/jdbcsqlite3.rb +1 -0
  45. data/test/adapters/makara_postgis.rb +1 -0
  46. data/test/adapters/mysql2_makara.rb +1 -0
  47. data/test/adapters/mysql2spatial.rb +1 -1
  48. data/test/adapters/postgis.rb +1 -1
  49. data/test/adapters/postgresql.rb +1 -1
  50. data/test/adapters/postgresql_makara.rb +1 -0
  51. data/test/adapters/spatialite.rb +1 -1
  52. data/test/adapters/sqlite3.rb +1 -1
  53. data/test/database.yml.sample +13 -18
  54. data/test/import_test.rb +608 -89
  55. data/test/jdbcmysql/import_test.rb +2 -3
  56. data/test/jdbcpostgresql/import_test.rb +0 -2
  57. data/test/jdbcsqlite3/import_test.rb +4 -0
  58. data/test/makara_postgis/import_test.rb +8 -0
  59. data/test/models/account.rb +3 -0
  60. data/test/models/alarm.rb +2 -0
  61. data/test/models/animal.rb +6 -0
  62. data/test/models/bike_maker.rb +7 -0
  63. data/test/models/book.rb +7 -6
  64. data/test/models/car.rb +3 -0
  65. data/test/models/chapter.rb +2 -2
  66. data/test/models/dictionary.rb +4 -0
  67. data/test/models/discount.rb +3 -0
  68. data/test/models/end_note.rb +2 -2
  69. data/test/models/promotion.rb +3 -0
  70. data/test/models/question.rb +3 -0
  71. data/test/models/rule.rb +3 -0
  72. data/test/models/tag.rb +4 -0
  73. data/test/models/topic.rb +17 -3
  74. data/test/models/user.rb +3 -0
  75. data/test/models/user_token.rb +4 -0
  76. data/test/models/vendor.rb +7 -0
  77. data/test/models/widget.rb +19 -2
  78. data/test/mysql2/import_test.rb +2 -3
  79. data/test/{em_mysql2 → mysql2_makara}/import_test.rb +1 -1
  80. data/test/mysqlspatial2/import_test.rb +2 -2
  81. data/test/postgis/import_test.rb +5 -1
  82. data/test/schema/generic_schema.rb +159 -85
  83. data/test/schema/jdbcpostgresql_schema.rb +1 -0
  84. data/test/schema/mysql2_schema.rb +19 -0
  85. data/test/schema/postgis_schema.rb +1 -0
  86. data/test/schema/postgresql_schema.rb +61 -0
  87. data/test/schema/sqlite3_schema.rb +13 -0
  88. data/test/sqlite3/import_test.rb +2 -50
  89. data/test/support/active_support/test_case_extensions.rb +21 -13
  90. data/test/support/{mysql/assertions.rb → assertions.rb} +20 -2
  91. data/test/support/factories.rb +39 -14
  92. data/test/support/generate.rb +10 -10
  93. data/test/support/mysql/import_examples.rb +49 -98
  94. data/test/support/postgresql/import_examples.rb +535 -57
  95. data/test/support/shared_examples/on_duplicate_key_ignore.rb +43 -0
  96. data/test/support/shared_examples/on_duplicate_key_update.rb +378 -0
  97. data/test/support/shared_examples/recursive_import.rb +225 -0
  98. data/test/support/sqlite3/import_examples.rb +231 -0
  99. data/test/synchronize_test.rb +10 -2
  100. data/test/test_helper.rb +36 -8
  101. data/test/travis/database.yml +26 -17
  102. data/test/value_sets_bytes_parser_test.rb +25 -17
  103. data/test/value_sets_records_parser_test.rb +6 -6
  104. metadata +86 -42
  105. data/benchmarks/boot.rb +0 -18
  106. data/benchmarks/schema/mysql_schema.rb +0 -16
  107. data/gemfiles/3.1.gemfile +0 -4
  108. data/lib/activerecord-import/active_record/adapters/em_mysql2_adapter.rb +0 -8
  109. data/lib/activerecord-import/active_record/adapters/mysql_adapter.rb +0 -6
  110. data/lib/activerecord-import/em_mysql2.rb +0 -7
  111. data/lib/activerecord-import/mysql.rb +0 -7
  112. data/test/adapters/em_mysql2.rb +0 -1
  113. data/test/adapters/mysql.rb +0 -1
  114. data/test/adapters/mysqlspatial.rb +0 -1
  115. data/test/mysql/import_test.rb +0 -6
  116. data/test/mysqlspatial/import_test.rb +0 -6
  117. data/test/schema/mysql_schema.rb +0 -18
  118. data/test/travis/build.sh +0 -30
@@ -1,103 +1,107 @@
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, :prefix=>" " )
28
- end
29
-
30
- # TODO IMPLEMENT THIS
31
- def self.print_valid_table_types( options, hsh={:prefix=>''} )
32
- if options.table_types.keys.size > 0
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
- :table_types => {},
42
- :delete_on_finish => true,
43
- :number_of_objects => [],
44
- :outputs => [] )
45
-
46
- opts = OptionParser.new do |opts|
47
- opts.banner = BANNER
48
-
49
- # parse the database adapter
50
- opts.on( "a", "--adapter [String]",
51
- "The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
52
- options.adapter = arg
53
- end
54
-
55
- # parse do_not_delete flag
56
- opts.on( "d", "--do-not-delete",
57
- "By default all records in the benchmark tables will be deleted at the end of the benchmark. " +
58
- "This flag indicates not to delete the benchmark data." ) do |arg|
59
- options.delete_on_finish = false
60
- end
61
-
62
- # parse the number of row objects to test
63
- opts.on( "n", "--num [Integer]",
64
- "The number of objects to benchmark." ) do |arg|
65
- options.number_of_objects << arg.to_i
66
- end
67
-
68
- # parse the table types to test
69
- opts.on( "t", "--table-type [String]",
70
- "The table type to test. This can be used multiple times." ) do |arg|
71
- if arg =~ /^all$/
72
- options.table_types['all'] = options.benchmark_all_types = true
73
- else
74
- options.table_types[arg] = true
75
- end
76
- end
77
-
78
- # print results in CSV format
79
- opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
80
- options.outputs << OpenStruct.new( :format=>'csv', :filename=>filename)
81
- end
82
-
83
- # print results in HTML format
84
- opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
85
- options.outputs << OpenStruct.new( :format=>'html', :filename=>filename )
86
- end
87
- end #end opt.parse!
88
-
89
- begin
90
- opts.parse!( args )
91
- if options.table_types.size == 0
92
- options.table_types['all'] = options.benchmark_all_types = true
93
- end
94
- rescue Exception => ex
95
- print_banner!
96
- end
97
-
98
- print_options( options )
99
-
100
- options
101
- end
102
-
103
- 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
+
48
+ opt_parser = OptionParser.new do |opts|
49
+ opts.banner = BANNER
50
+
51
+ # parse the database adapter
52
+ opts.on( "a", "--adapter [String]",
53
+ "The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
54
+ options.adapter = arg
55
+ end
56
+
57
+ # parse do_not_delete flag
58
+ opts.on( "d", "--do-not-delete",
59
+ "By default all records in the benchmark tables will be deleted at the end of the benchmark. " \
60
+ "This flag indicates not to delete the benchmark data." ) do |_|
61
+ options.delete_on_finish = false
62
+ end
63
+
64
+ # parse the number of row objects to test
65
+ opts.on( "n", "--num [Integer]",
66
+ "The number of objects to benchmark." ) do |arg|
67
+ options.number_of_objects << arg.to_i
68
+ end
69
+
70
+ # parse the table types to test
71
+ opts.on( "t", "--table-type [String]",
72
+ "The table type to test. This can be used multiple times." ) do |arg|
73
+ if arg =~ /^all$/
74
+ options.table_types['all'] = options.benchmark_all_types = true
75
+ else
76
+ options.table_types[arg] = true
77
+ end
78
+ end
79
+
80
+ # print results in CSV format
81
+ opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
82
+ options.outputs << OpenStruct.new( format: 'csv', filename: filename)
83
+ end
84
+
85
+ # print results in HTML format
86
+ opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
87
+ options.outputs << OpenStruct.new( format: 'html', filename: filename )
88
+ end
89
+ end # end opt.parse!
90
+
91
+ begin
92
+ opt_parser.parse!( args )
93
+ if options.table_types.empty?
94
+ options.table_types['all'] = options.benchmark_all_types = true
95
+ end
96
+ rescue Exception
97
+ print_banner!
98
+ end
99
+
100
+ options.number_of_objects = [1000] if options.number_of_objects.empty?
101
+ options.outputs = [OpenStruct.new( format: 'html', filename: 'benchmark.html')] if options.outputs.empty?
102
+
103
+ print_options( options )
104
+
105
+ options
106
+ end
107
+ end
@@ -1,22 +1,19 @@
1
- class MysqlBenchmark < BenchmarkBase
2
-
3
- def benchmark_all( array_of_cols_and_vals )
4
- methods = self.methods.find_all { |m| m =~ /benchmark_/ }
5
- methods.delete_if{ |m| m =~ /benchmark_(all|model)/ }
6
- methods.each { |method| self.send( method, array_of_cols_and_vals ) }
7
- end
8
-
9
- def benchmark_myisam( array_of_cols_and_vals )
10
- bm_model( TestMyISAM, array_of_cols_and_vals )
11
- end
12
-
13
- def benchmark_innodb( array_of_cols_and_vals )
14
- bm_model( TestInnoDb, array_of_cols_and_vals )
15
- end
16
-
17
- def benchmark_memory( array_of_cols_and_vals )
18
- bm_model( TestMemory, array_of_cols_and_vals )
19
- end
20
-
21
- end
22
-
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
@@ -1,12 +1,13 @@
1
- require 'fastercsv'
1
+ require 'csv'
2
2
 
3
3
  module OutputToCSV
4
4
  def self.output_results( filename, results )
5
- FasterCSV.open( filename, 'w' ) do |csv|
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, times = [], []
9
- result_set.each do |result|
8
+ columns = []
9
+ times = []
10
+ result_set.each do |result|
10
11
  columns << result.description
11
12
  times << result.tms.real
12
13
  end
@@ -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 =<<"EOT"
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, times = [], []
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,3 +1,3 @@
1
1
  class TestInnoDb < ActiveRecord::Base
2
- set_table_name 'test_innodb'
2
+ self.table_name = 'test_innodb'
3
3
  end
@@ -1,3 +1,3 @@
1
1
  class TestMemory < ActiveRecord::Base
2
- set_table_name 'test_memory'
2
+ self.table_name = 'test_memory'
3
3
  end
@@ -1,3 +1,3 @@
1
1
  class TestMyISAM < ActiveRecord::Base
2
- set_table_name 'test_myisam'
2
+ self.table_name = 'test_myisam'
3
3
  end
@@ -0,0 +1,16 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :test_myisam, options: 'ENGINE=MyISAM', force: true do |t|
3
+ t.column :my_name, :string, null: false
4
+ t.column :description, :string
5
+ end
6
+
7
+ create_table :test_innodb, options: 'ENGINE=InnoDb', force: true do |t|
8
+ t.column :my_name, :string, null: false
9
+ t.column :description, :string
10
+ end
11
+
12
+ create_table :test_memory, options: 'ENGINE=Memory', force: true do |t|
13
+ t.column :my_name, :string, null: false
14
+ t.column :description, :string
15
+ end
16
+ end
data/gemfiles/3.2.gemfile CHANGED
@@ -1,4 +1,2 @@
1
- platforms :ruby do
2
- gem 'mysql', '>= 2.8.1'
3
- gem 'activerecord', '~> 3.2.0'
4
- end
1
+ gem 'activerecord', '~> 3.2.0'
2
+ gem 'composite_primary_keys', '~> 5.0'
data/gemfiles/4.0.gemfile CHANGED
@@ -1,4 +1,2 @@
1
- platforms :ruby do
2
- gem 'mysql', '~> 2.9'
3
- gem 'activerecord', '~> 4.0.0.rc2'
4
- end
1
+ gem 'activerecord', '~> 4.0.0'
2
+ gem 'composite_primary_keys', '~> 6.0'
data/gemfiles/4.1.gemfile CHANGED
@@ -1,4 +1,2 @@
1
- platforms :ruby do
2
- gem 'mysql', '~> 2.9'
3
- gem 'activerecord', '~> 4.1'
4
- end
1
+ gem 'activerecord', '~> 4.1.0'
2
+ gem 'composite_primary_keys', '~> 7.0'
data/gemfiles/4.2.gemfile CHANGED
@@ -1,4 +1,2 @@
1
- platforms :ruby do
2
- gem 'mysql', '~> 2.9'
3
- gem 'activerecord', '~> 4.2'
4
- end
1
+ gem 'activerecord', '~> 4.2.0'
2
+ gem 'composite_primary_keys', '~> 8.0'
@@ -0,0 +1,2 @@
1
+ gem 'activerecord', '~> 5.0.0'
2
+ gem 'composite_primary_keys', '~> 9.0'
@@ -0,0 +1,2 @@
1
+ gem 'activerecord', '~> 5.1.0'
2
+ gem 'composite_primary_keys', '~> 10.0'
@@ -0,0 +1,2 @@
1
+ gem 'activerecord', '~> 5.2.0'
2
+ gem 'composite_primary_keys', '~> 11.0'
@@ -0,0 +1,2 @@
1
+ gem 'activerecord', '~> 6.0.0'
2
+ gem 'composite_primary_keys', '~> 12.0'
@@ -0,0 +1 @@
1
+ gem 'activerecord', '~> 6.1.0'
@@ -0,0 +1,6 @@
1
+ require "active_record/connection_adapters/sqlite3_adapter"
2
+ require "activerecord-import/adapters/sqlite3_adapter"
3
+
4
+ class ActiveRecord::ConnectionAdapters::SQLite3Adapter
5
+ include ActiveRecord::Import::SQLite3Adapter
6
+ end
@@ -4,4 +4,3 @@ require "activerecord-import/adapters/sqlite3_adapter"
4
4
  class ActiveRecord::ConnectionAdapters::SQLite3Adapter
5
5
  include ActiveRecord::Import::SQLite3Adapter
6
6
  end
7
-
@@ -1,31 +1,30 @@
1
1
  module ActiveRecord::Import::AbstractAdapter
2
2
  module InstanceMethods
3
3
  def next_value_for_sequence(sequence_name)
4
- %{#{sequence_name}.nextval}
4
+ %(#{sequence_name}.nextval)
5
5
  end
6
6
 
7
- def insert_many( sql, values, *args ) # :nodoc:
7
+ def insert_many( sql, values, _options = {}, *args ) # :nodoc:
8
8
  number_of_inserts = 1
9
9
 
10
- base_sql,post_sql = if sql.is_a?( String )
11
- [ sql, '' ]
10
+ base_sql, post_sql = if sql.is_a?( String )
11
+ [sql, '']
12
12
  elsif sql.is_a?( Array )
13
- [ sql.shift, sql.join( ' ' ) ]
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
+ ActiveRecord::Import::Result.new([], number_of_inserts, [], [])
20
20
  end
21
21
 
22
22
  def pre_sql_statements(options)
23
23
  sql = []
24
24
  sql << options[:pre_sql] if options[:pre_sql]
25
25
  sql << options[:command] if options[:command]
26
- sql << "IGNORE" if options[:ignore]
27
26
 
28
- #add keywords like IGNORE or DELAYED
27
+ # add keywords like IGNORE or DELAYED
29
28
  if options[:keywords].is_a?(Array)
30
29
  sql.concat(options[:keywords])
31
30
  elsif options[:keywords]
@@ -38,29 +37,36 @@ module ActiveRecord::Import::AbstractAdapter
38
37
  # Synchronizes the passed in ActiveRecord instances with the records in
39
38
  # the database by calling +reload+ on each instance.
40
39
  def after_import_synchronize( instances )
41
- instances.each { |e| e.reload }
40
+ instances.each(&:reload)
42
41
  end
43
42
 
44
43
  # Returns an array of post SQL statements given the passed in options.
45
44
  def post_sql_statements( table_name, options ) # :nodoc:
46
45
  post_sql_statements = []
47
- if options[:on_duplicate_key_update]
48
- post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update] )
46
+
47
+ if supports_on_duplicate_key_update? && options[:on_duplicate_key_update]
48
+ post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:primary_key], options[:locking_column] )
49
+ elsif logger && options[:on_duplicate_key_update]
50
+ logger.warn "Ignoring on_duplicate_key_update because it is not supported by the database."
49
51
  end
50
52
 
51
- #custom user post_sql
53
+ # custom user post_sql
52
54
  post_sql_statements << options[:post_sql] if options[:post_sql]
53
55
 
54
- #with rollup
56
+ # with rollup
55
57
  post_sql_statements << rollup_sql if options[:rollup]
56
58
 
57
59
  post_sql_statements
58
60
  end
59
61
 
60
- # Returns the maximum number of bytes that the server will allow
61
- # in a single packet
62
- def max_allowed_packet
63
- NO_MAX_PACKET
62
+ def increment_locking_column!(table_name, results, locking_column)
63
+ if locking_column.present?
64
+ results << "\"#{locking_column}\"=#{table_name}.\"#{locking_column}\"+1"
65
+ end
66
+ end
67
+
68
+ def supports_on_duplicate_key_update?
69
+ false
64
70
  end
65
71
  end
66
72
  end