Skip to content

Commit

Permalink
Change execute_batch to take array of statements
Browse files Browse the repository at this point in the history
Adapters don't necessarily have the ability to execute a batch of
statements.

Previously execute_batch took a single string of statements separated by
';', this meant that the adapter had to have the ability to execute
batch statements.

Instead, this commit changes the method to take an array of statements.
Adapters which support batched queries can do the join there. For
adapters which don't we provide a fallback implementation: executing
each statement one at a time.

This also improves the implementation for the mysql2 adapter, which
understands that there is a maximium query length. Previously the caller
needed to split the statements before passing them to execute_batch, now
execute_batch itself is responsible for splitting the queries.
  • Loading branch information
jhawthorn committed Nov 18, 2019
1 parent a67a2f6 commit 22513cf
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def delete(arel, name = nil, binds = [])

# Executes the truncate statement.
def truncate(table_name, name = nil)
execute(build_truncate_statements(table_name), name)
execute(build_truncate_statement(table_name), name)
end

def truncate_tables(*table_names) # :nodoc:
Expand All @@ -194,9 +194,8 @@ def truncate_tables(*table_names) # :nodoc:

with_multi_statements do
disable_referential_integrity do
Array(build_truncate_statements(*table_names)).each do |sql|
execute_batch(sql, "Truncate Tables")
end
statements = build_truncate_statements(table_names)
execute_batch(statements, "Truncate Tables")
end
end
end
Expand Down Expand Up @@ -365,14 +364,12 @@ def insert_fixture(fixture, table_name)
def insert_fixtures_set(fixture_set, tables_to_delete = [])
fixture_inserts = build_fixture_statements(fixture_set)
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
total_sql = Array(combine_multi_statements(table_deletes + fixture_inserts))
statements = table_deletes + fixture_inserts

with_multi_statements do
disable_referential_integrity do
transaction(requires_new: true) do
total_sql.each do |sql|
execute_batch(sql, "Fixtures Load")
end
execute_batch(statements, "Fixtures Load")
end
end
end
Expand Down Expand Up @@ -408,8 +405,10 @@ def with_yaml_fallback(value) # :nodoc:
end

private
def execute_batch(sql, name = nil)
execute(sql, name)
def execute_batch(statements, name = nil)
statements.each do |statement|
execute(statement, name)
end
end

DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
Expand Down Expand Up @@ -469,11 +468,14 @@ def build_fixture_statements(fixture_set)
end.compact
end

def build_truncate_statements(*table_names)
truncate_tables = table_names.map do |table_name|
"TRUNCATE TABLE #{quote_table_name(table_name)}"
def build_truncate_statement(table_name)
"TRUNCATE TABLE #{quote_table_name(table_name)}"
end

def build_truncate_statements(table_names)
table_names.map do |table_name|
build_truncate_statement(table_name)
end
combine_multi_statements(truncate_tables)
end

def with_multi_statements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,10 @@ def exec_delete(sql, name = nil, binds = [])
alias :exec_update :exec_delete

private
def execute_batch(sql, name = nil)
super
def execute_batch(statements, name = nil)
combine_multi_statements(statements).each do |statement|
execute(statement, name)
end
@connection.abandon_results!
end

Expand All @@ -99,14 +101,6 @@ def supports_set_server_option?
@connection.respond_to?(:set_server_option)
end

def build_truncate_statements(*table_names)
if table_names.size == 1
super.first
else
super
end
end

def multi_statements_enabled?(flags)
if flags.is_a?(Array)
flags.include?("MULTI_STATEMENTS")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,12 @@ def exec_rollback_db_transaction
end

private
def build_truncate_statements(*table_names)
"TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"
def execute_batch(statements, name = nil)
execute(combine_multi_statements(statements))
end

def build_truncate_statements(table_names)
["TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"]
end

# Returns the current ID of a table's sequence.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def exec_rollback_db_transaction #:nodoc:
end

private
def execute_batch(sql, name = nil)
def execute_batch(statements, name = nil)
sql = combine_multi_statements(statements)

if preventing_writes? && write_query?(sql)
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
end
Expand All @@ -112,11 +114,8 @@ def build_fixture_statements(fixture_set)
end.compact
end

def build_truncate_statements(*table_names)
truncate_tables = table_names.map do |table_name|
"DELETE FROM #{quote_table_name(table_name)}"
end
combine_multi_statements(truncate_tables)
def build_truncate_statement(table_name)
"DELETE FROM #{quote_table_name(table_name)}"
end
end
end
Expand Down

0 comments on commit 22513cf

Please sign in to comment.