activerecord-import 1.0.3
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 +7 -0
- data/.gitignore +32 -0
- data/.rubocop.yml +49 -0
- data/.rubocop_todo.yml +36 -0
- data/.travis.yml +74 -0
- data/Brewfile +3 -0
- data/CHANGELOG.md +430 -0
- data/Gemfile +59 -0
- data/LICENSE +56 -0
- data/README.markdown +619 -0
- data/Rakefile +68 -0
- data/activerecord-import.gemspec +23 -0
- data/benchmarks/README +32 -0
- data/benchmarks/benchmark.rb +68 -0
- data/benchmarks/lib/base.rb +138 -0
- data/benchmarks/lib/cli_parser.rb +107 -0
- data/benchmarks/lib/float.rb +15 -0
- data/benchmarks/lib/mysql2_benchmark.rb +19 -0
- data/benchmarks/lib/output_to_csv.rb +19 -0
- data/benchmarks/lib/output_to_html.rb +64 -0
- data/benchmarks/models/test_innodb.rb +3 -0
- data/benchmarks/models/test_memory.rb +3 -0
- data/benchmarks/models/test_myisam.rb +3 -0
- data/benchmarks/schema/mysql_schema.rb +16 -0
- data/gemfiles/3.2.gemfile +2 -0
- data/gemfiles/4.0.gemfile +2 -0
- data/gemfiles/4.1.gemfile +2 -0
- data/gemfiles/4.2.gemfile +2 -0
- data/gemfiles/5.0.gemfile +2 -0
- data/gemfiles/5.1.gemfile +2 -0
- data/gemfiles/5.2.gemfile +2 -0
- data/gemfiles/6.0.gemfile +1 -0
- data/gemfiles/6.1.gemfile +1 -0
- data/lib/activerecord-import.rb +6 -0
- data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +9 -0
- data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +6 -0
- data/lib/activerecord-import/active_record/adapters/jdbcpostgresql_adapter.rb +6 -0
- data/lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb +6 -0
- data/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb +6 -0
- data/lib/activerecord-import/active_record/adapters/postgresql_adapter.rb +6 -0
- data/lib/activerecord-import/active_record/adapters/seamless_database_pool_adapter.rb +7 -0
- data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +6 -0
- data/lib/activerecord-import/adapters/abstract_adapter.rb +66 -0
- data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +5 -0
- data/lib/activerecord-import/adapters/mysql2_adapter.rb +5 -0
- data/lib/activerecord-import/adapters/mysql_adapter.rb +129 -0
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +217 -0
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +180 -0
- data/lib/activerecord-import/base.rb +43 -0
- data/lib/activerecord-import/import.rb +1059 -0
- data/lib/activerecord-import/mysql2.rb +7 -0
- data/lib/activerecord-import/postgresql.rb +7 -0
- data/lib/activerecord-import/sqlite3.rb +7 -0
- data/lib/activerecord-import/synchronize.rb +66 -0
- data/lib/activerecord-import/value_sets_parser.rb +77 -0
- data/lib/activerecord-import/version.rb +5 -0
- data/test/adapters/jdbcmysql.rb +1 -0
- data/test/adapters/jdbcpostgresql.rb +1 -0
- data/test/adapters/jdbcsqlite3.rb +1 -0
- data/test/adapters/makara_postgis.rb +1 -0
- data/test/adapters/mysql2.rb +1 -0
- data/test/adapters/mysql2_makara.rb +1 -0
- data/test/adapters/mysql2spatial.rb +1 -0
- data/test/adapters/postgis.rb +1 -0
- data/test/adapters/postgresql.rb +1 -0
- data/test/adapters/postgresql_makara.rb +1 -0
- data/test/adapters/seamless_database_pool.rb +1 -0
- data/test/adapters/spatialite.rb +1 -0
- data/test/adapters/sqlite3.rb +1 -0
- data/test/database.yml.sample +52 -0
- data/test/import_test.rb +903 -0
- data/test/jdbcmysql/import_test.rb +5 -0
- data/test/jdbcpostgresql/import_test.rb +4 -0
- data/test/jdbcsqlite3/import_test.rb +4 -0
- data/test/makara_postgis/import_test.rb +8 -0
- data/test/models/account.rb +3 -0
- data/test/models/alarm.rb +2 -0
- data/test/models/bike_maker.rb +7 -0
- data/test/models/book.rb +9 -0
- data/test/models/car.rb +3 -0
- data/test/models/chapter.rb +4 -0
- data/test/models/dictionary.rb +4 -0
- data/test/models/discount.rb +3 -0
- data/test/models/end_note.rb +4 -0
- data/test/models/group.rb +3 -0
- data/test/models/promotion.rb +3 -0
- data/test/models/question.rb +3 -0
- data/test/models/rule.rb +3 -0
- data/test/models/tag.rb +4 -0
- data/test/models/topic.rb +23 -0
- data/test/models/user.rb +3 -0
- data/test/models/user_token.rb +4 -0
- data/test/models/vendor.rb +7 -0
- data/test/models/widget.rb +24 -0
- data/test/mysql2/import_test.rb +5 -0
- data/test/mysql2_makara/import_test.rb +6 -0
- data/test/mysqlspatial2/import_test.rb +6 -0
- data/test/postgis/import_test.rb +8 -0
- data/test/postgresql/import_test.rb +4 -0
- data/test/schema/generic_schema.rb +194 -0
- data/test/schema/jdbcpostgresql_schema.rb +1 -0
- data/test/schema/mysql2_schema.rb +19 -0
- data/test/schema/postgis_schema.rb +1 -0
- data/test/schema/postgresql_schema.rb +47 -0
- data/test/schema/sqlite3_schema.rb +13 -0
- data/test/schema/version.rb +10 -0
- data/test/sqlite3/import_test.rb +4 -0
- data/test/support/active_support/test_case_extensions.rb +75 -0
- data/test/support/assertions.rb +73 -0
- data/test/support/factories.rb +64 -0
- data/test/support/generate.rb +29 -0
- data/test/support/mysql/import_examples.rb +98 -0
- data/test/support/postgresql/import_examples.rb +563 -0
- data/test/support/shared_examples/on_duplicate_key_ignore.rb +43 -0
- data/test/support/shared_examples/on_duplicate_key_update.rb +368 -0
- data/test/support/shared_examples/recursive_import.rb +216 -0
- data/test/support/sqlite3/import_examples.rb +231 -0
- data/test/synchronize_test.rb +41 -0
- data/test/test_helper.rb +75 -0
- data/test/travis/database.yml +66 -0
- data/test/value_sets_bytes_parser_test.rb +104 -0
- data/test/value_sets_records_parser_test.rb +32 -0
- metadata +259 -0
|
@@ -0,0 +1,19 @@
|
|
|
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
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'csv'
|
|
2
|
+
|
|
3
|
+
module OutputToCSV
|
|
4
|
+
def self.output_results( filename, results )
|
|
5
|
+
CSV.open( filename, 'w' ) do |csv|
|
|
6
|
+
# Iterate over each result set, which contains many results
|
|
7
|
+
results.each do |result_set|
|
|
8
|
+
columns = []
|
|
9
|
+
times = []
|
|
10
|
+
result_set.each do |result|
|
|
11
|
+
columns << result.description
|
|
12
|
+
times << result.tms.real
|
|
13
|
+
end
|
|
14
|
+
csv << columns
|
|
15
|
+
csv << times
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'erb'
|
|
2
|
+
|
|
3
|
+
module OutputToHTML
|
|
4
|
+
TEMPLATE_HEADER = <<"EOT".freeze
|
|
5
|
+
<div>
|
|
6
|
+
All times are rounded to the nearest thousandth for display purposes. Speedups next to each time are computed
|
|
7
|
+
before any rounding occurs. Also, all speedup calculations are computed by comparing a given time against
|
|
8
|
+
the very first column (which is always the default ActiveRecord::Base.create method.
|
|
9
|
+
</div>
|
|
10
|
+
EOT
|
|
11
|
+
|
|
12
|
+
TEMPLATE = <<"EOT".freeze
|
|
13
|
+
<style>
|
|
14
|
+
td#benchmarkTitle {
|
|
15
|
+
border: 1px solid black;
|
|
16
|
+
padding: 2px;
|
|
17
|
+
font-size: 0.8em;
|
|
18
|
+
background-color: black;
|
|
19
|
+
color: white;
|
|
20
|
+
}
|
|
21
|
+
td#benchmarkCell {
|
|
22
|
+
border: 1px solid black;
|
|
23
|
+
padding: 2px;
|
|
24
|
+
font-size: 0.8em;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
27
|
+
<table>
|
|
28
|
+
<tr>
|
|
29
|
+
<% columns.each do |col| %>
|
|
30
|
+
<td id="benchmarkTitle"><%= col %></td>
|
|
31
|
+
<% end %>
|
|
32
|
+
</tr>
|
|
33
|
+
<tr>
|
|
34
|
+
<% times.each do |time| %>
|
|
35
|
+
<td id="benchmarkCell"><%= time %></td>
|
|
36
|
+
<% end %>
|
|
37
|
+
</tr>
|
|
38
|
+
<tr><td> </td></tr>
|
|
39
|
+
</table>
|
|
40
|
+
EOT
|
|
41
|
+
|
|
42
|
+
def self.output_results( filename, results )
|
|
43
|
+
html = ''
|
|
44
|
+
results.each do |result_set|
|
|
45
|
+
columns = []
|
|
46
|
+
times = []
|
|
47
|
+
result_set.each do |result|
|
|
48
|
+
columns << result.description
|
|
49
|
+
if result.failed
|
|
50
|
+
times << "failed"
|
|
51
|
+
else
|
|
52
|
+
time = result.tms.real.round_to( 3 )
|
|
53
|
+
speedup = ( result_set.first.tms.real / result.tms.real ).round
|
|
54
|
+
times << (result == result_set.first ? time.to_s : "#{time} (#{speedup}x speedup)")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
template = ERB.new( TEMPLATE, 0, "%<>")
|
|
59
|
+
html << template.result( binding )
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
File.open( filename, 'w' ) { |file| file.write( TEMPLATE_HEADER + html ) }
|
|
63
|
+
end
|
|
64
|
+
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gem 'activerecord', '~> 6.0.0'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gem 'activerecord', '~> 6.1.0.alpha', github: "rails/rails"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
require "seamless_database_pool"
|
|
2
|
+
require "active_record/connection_adapters/seamless_database_pool_adapter"
|
|
3
|
+
require "activerecord-import/adapters/mysql_adapter"
|
|
4
|
+
|
|
5
|
+
class ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter
|
|
6
|
+
include ActiveRecord::Import::MysqlAdapter
|
|
7
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module ActiveRecord::Import::AbstractAdapter
|
|
2
|
+
module InstanceMethods
|
|
3
|
+
def next_value_for_sequence(sequence_name)
|
|
4
|
+
%(#{sequence_name}.nextval)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def insert_many( sql, values, _options = {}, *args ) # :nodoc:
|
|
8
|
+
number_of_inserts = 1
|
|
9
|
+
|
|
10
|
+
base_sql, post_sql = if sql.is_a?( String )
|
|
11
|
+
[sql, '']
|
|
12
|
+
elsif sql.is_a?( Array )
|
|
13
|
+
[sql.shift, sql.join( ' ' )]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
sql2insert = base_sql + values.join( ',' ) + post_sql
|
|
17
|
+
insert( sql2insert, *args )
|
|
18
|
+
|
|
19
|
+
ActiveRecord::Import::Result.new([], number_of_inserts, [], [])
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def pre_sql_statements(options)
|
|
23
|
+
sql = []
|
|
24
|
+
sql << options[:pre_sql] if options[:pre_sql]
|
|
25
|
+
sql << options[:command] if options[:command]
|
|
26
|
+
|
|
27
|
+
# add keywords like IGNORE or DELAYED
|
|
28
|
+
if options[:keywords].is_a?(Array)
|
|
29
|
+
sql.concat(options[:keywords])
|
|
30
|
+
elsif options[:keywords]
|
|
31
|
+
sql << options[:keywords].to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
sql
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Synchronizes the passed in ActiveRecord instances with the records in
|
|
38
|
+
# the database by calling +reload+ on each instance.
|
|
39
|
+
def after_import_synchronize( instances )
|
|
40
|
+
instances.each(&:reload)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns an array of post SQL statements given the passed in options.
|
|
44
|
+
def post_sql_statements( table_name, options ) # :nodoc:
|
|
45
|
+
post_sql_statements = []
|
|
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."
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# custom user post_sql
|
|
54
|
+
post_sql_statements << options[:post_sql] if options[:post_sql]
|
|
55
|
+
|
|
56
|
+
# with rollup
|
|
57
|
+
post_sql_statements << rollup_sql if options[:rollup]
|
|
58
|
+
|
|
59
|
+
post_sql_statements
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def supports_on_duplicate_key_update?
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
module ActiveRecord::Import::MysqlAdapter
|
|
2
|
+
include ActiveRecord::Import::ImportSupport
|
|
3
|
+
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
|
4
|
+
|
|
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.
|
|
7
|
+
|
|
8
|
+
# +sql+ can be a single string or an array. If it is an array all
|
|
9
|
+
# elements that are in position >= 1 will be appended to the final SQL.
|
|
10
|
+
def insert_many( sql, values, options = {}, *args ) # :nodoc:
|
|
11
|
+
# the number of inserts default
|
|
12
|
+
number_of_inserts = 0
|
|
13
|
+
|
|
14
|
+
base_sql, post_sql = if sql.is_a?( String )
|
|
15
|
+
[sql, '']
|
|
16
|
+
elsif sql.is_a?( Array )
|
|
17
|
+
[sql.shift, sql.join( ' ' )]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
sql_size = QUERY_OVERHEAD + base_sql.size + post_sql.size
|
|
21
|
+
|
|
22
|
+
# the number of bytes the requested insert statement values will take up
|
|
23
|
+
values_in_bytes = values.sum(&:bytesize)
|
|
24
|
+
|
|
25
|
+
# the number of bytes (commas) it will take to comma separate our values
|
|
26
|
+
comma_separated_bytes = values.size - 1
|
|
27
|
+
|
|
28
|
+
# the total number of bytes required if this statement is one statement
|
|
29
|
+
total_bytes = sql_size + values_in_bytes + comma_separated_bytes
|
|
30
|
+
|
|
31
|
+
max = max_allowed_packet
|
|
32
|
+
|
|
33
|
+
# if we can insert it all as one statement
|
|
34
|
+
if NO_MAX_PACKET == max || total_bytes <= max || options[:force_single_insert]
|
|
35
|
+
number_of_inserts += 1
|
|
36
|
+
sql2insert = base_sql + values.join( ',' ) + post_sql
|
|
37
|
+
insert( sql2insert, *args )
|
|
38
|
+
else
|
|
39
|
+
value_sets = ::ActiveRecord::Import::ValueSetsBytesParser.parse(values,
|
|
40
|
+
reserved_bytes: sql_size,
|
|
41
|
+
max_bytes: max)
|
|
42
|
+
|
|
43
|
+
transaction(requires_new: true) do
|
|
44
|
+
value_sets.each do |value_set|
|
|
45
|
+
number_of_inserts += 1
|
|
46
|
+
sql2insert = base_sql + value_set.join( ',' ) + post_sql
|
|
47
|
+
insert( sql2insert, *args )
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
ActiveRecord::Import::Result.new([], number_of_inserts, [], [])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Returns the maximum number of bytes that the server will allow
|
|
56
|
+
# in a single packet
|
|
57
|
+
def max_allowed_packet # :nodoc:
|
|
58
|
+
@max_allowed_packet ||= begin
|
|
59
|
+
result = execute( "SHOW VARIABLES like 'max_allowed_packet'" )
|
|
60
|
+
# original Mysql gem responds to #fetch_row while Mysql2 responds to #first
|
|
61
|
+
val = result.respond_to?(:fetch_row) ? result.fetch_row[1] : result.first[1]
|
|
62
|
+
val.to_i
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def pre_sql_statements( options)
|
|
67
|
+
sql = []
|
|
68
|
+
sql << "IGNORE" if options[:ignore] || options[:on_duplicate_key_ignore]
|
|
69
|
+
sql + super
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Add a column to be updated on duplicate key update
|
|
73
|
+
def add_column_for_on_duplicate_key_update( column, options = {} ) # :nodoc:
|
|
74
|
+
if (columns = options[:on_duplicate_key_update])
|
|
75
|
+
case columns
|
|
76
|
+
when Array then columns << column.to_sym unless columns.include?(column.to_sym)
|
|
77
|
+
when Hash then columns[column.to_sym] = column.to_sym
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns a generated ON DUPLICATE KEY UPDATE statement given the passed
|
|
83
|
+
# in +args+.
|
|
84
|
+
def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
|
|
85
|
+
sql = ' ON DUPLICATE KEY UPDATE '
|
|
86
|
+
arg = args.first
|
|
87
|
+
locking_column = args.last
|
|
88
|
+
if arg.is_a?( Array )
|
|
89
|
+
sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arg )
|
|
90
|
+
elsif arg.is_a?( Hash )
|
|
91
|
+
sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, arg )
|
|
92
|
+
elsif arg.is_a?( String )
|
|
93
|
+
sql << arg
|
|
94
|
+
else
|
|
95
|
+
raise ArgumentError, "Expected Array or Hash"
|
|
96
|
+
end
|
|
97
|
+
sql
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
|
|
101
|
+
results = arr.map do |column|
|
|
102
|
+
qc = quote_column_name( column )
|
|
103
|
+
"#{table_name}.#{qc}=VALUES(#{qc})"
|
|
104
|
+
end
|
|
105
|
+
increment_locking_column!(results, table_name, locking_column)
|
|
106
|
+
results.join( ',' )
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
|
|
110
|
+
results = hsh.map do |column1, column2|
|
|
111
|
+
qc1 = quote_column_name( column1 )
|
|
112
|
+
qc2 = quote_column_name( column2 )
|
|
113
|
+
"#{table_name}.#{qc1}=VALUES( #{qc2} )"
|
|
114
|
+
end
|
|
115
|
+
increment_locking_column!(results, table_name, locking_column)
|
|
116
|
+
results.join( ',')
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Return true if the statement is a duplicate key record error
|
|
120
|
+
def duplicate_key_update_error?(exception) # :nodoc:
|
|
121
|
+
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def increment_locking_column!(results, table_name, locking_column)
|
|
125
|
+
if locking_column.present?
|
|
126
|
+
results << "#{table_name}.`#{locking_column}`=`#{locking_column}`+1"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|