Commit e4d42a62 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Raise if updating columns in batches within a transaction

parent 4e8d6507
...@@ -222,6 +222,12 @@ module Gitlab ...@@ -222,6 +222,12 @@ module Gitlab
# #
# rubocop: disable Metrics/AbcSize # rubocop: disable Metrics/AbcSize
def update_column_in_batches(table, column, value) def update_column_in_batches(table, column, value)
if transaction_open?
raise 'update_column_in_batches can not be run inside a transaction, ' \
'you can disable transactions by calling disable_ddl_transaction! ' \
'in the body of your migration class'
end
table = Arel::Table.new(table) table = Arel::Table.new(table)
count_arel = table.project(Arel.star.count.as('count')) count_arel = table.project(Arel.star.count.as('count'))
......
...@@ -262,39 +262,53 @@ describe Gitlab::Database::MigrationHelpers, lib: true do ...@@ -262,39 +262,53 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
end end
describe '#update_column_in_batches' do describe '#update_column_in_batches' do
before do context 'when running outside of a transaction' do
create_list(:empty_project, 5) before do
end expect(model).to receive(:transaction_open?).and_return(false)
it 'updates all the rows in a table' do create_list(:empty_project, 5)
model.update_column_in_batches(:projects, :import_error, 'foo') end
expect(Project.where(import_error: 'foo').count).to eq(5) it 'updates all the rows in a table' do
end model.update_column_in_batches(:projects, :import_error, 'foo')
it 'updates boolean values correctly' do expect(Project.where(import_error: 'foo').count).to eq(5)
model.update_column_in_batches(:projects, :archived, true) end
expect(Project.where(archived: true).count).to eq(5) it 'updates boolean values correctly' do
end model.update_column_in_batches(:projects, :archived, true)
expect(Project.where(archived: true).count).to eq(5)
end
context 'when a block is supplied' do context 'when a block is supplied' do
it 'yields an Arel table and query object to the supplied block' do it 'yields an Arel table and query object to the supplied block' do
first_id = Project.first.id first_id = Project.first.id
model.update_column_in_batches(:projects, :archived, true) do |t, query| model.update_column_in_batches(:projects, :archived, true) do |t, query|
query.where(t[:id].eq(first_id)) query.where(t[:id].eq(first_id))
end
expect(Project.where(archived: true).count).to eq(1)
end end
end
expect(Project.where(archived: true).count).to eq(1) context 'when the value is Arel.sql (Arel::Nodes::SqlLiteral)' do
it 'updates the value as a SQL expression' do
model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1'))
expect(Project.sum(:star_count)).to eq(2 * Project.count)
end
end end
end end
context 'when the value is Arel.sql (Arel::Nodes::SqlLiteral)' do context 'when running inside the transaction' do
it 'updates the value as a SQL expression' do it 'raises RuntimeError' do
model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1')) expect(model).to receive(:transaction_open?).and_return(true)
expect(Project.sum(:star_count)).to eq(2 * Project.count) expect do
model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1'))
end.to raise_error(RuntimeError)
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment