Commit 0c1b8c88 authored by Yorick Peterse's avatar Yorick Peterse

Allow custom names for concurrent foreign keys

This is necessary for backporting the EE schema to ensure backported
foreign keys use the same key names.
parent c803cc90
...@@ -149,7 +149,7 @@ module Gitlab ...@@ -149,7 +149,7 @@ module Gitlab
# column - The name of the column to create the foreign key on. # column - The name of the column to create the foreign key on.
# on_delete - The action to perform when associated data is removed, # on_delete - The action to perform when associated data is removed,
# defaults to "CASCADE". # defaults to "CASCADE".
def add_concurrent_foreign_key(source, target, column:, on_delete: :cascade) def add_concurrent_foreign_key(source, target, column:, on_delete: :cascade, name: nil)
# Transactions would result in ALTER TABLE locks being held for the # Transactions would result in ALTER TABLE locks being held for the
# duration of the transaction, defeating the purpose of this method. # duration of the transaction, defeating the purpose of this method.
if transaction_open? if transaction_open?
...@@ -167,14 +167,18 @@ module Gitlab ...@@ -167,14 +167,18 @@ module Gitlab
return return
end end
return add_foreign_key(source, target, key_options = { column: column, on_delete: on_delete }
column: column,
on_delete: on_delete) # The MySQL adapter tries to create a foreign key without a name when
# `:name` is nil, instead of generating a name for us.
key_options[:name] = name if name
return add_foreign_key(source, target, key_options)
else else
on_delete = 'SET NULL' if on_delete == :nullify on_delete = 'SET NULL' if on_delete == :nullify
end end
key_name = concurrent_foreign_key_name(source, column) key_name = name || concurrent_foreign_key_name(source, column)
unless foreign_key_exists?(source, target, column: column) unless foreign_key_exists?(source, target, column: column)
Rails.logger.warn "Foreign key not created because it exists already " \ Rails.logger.warn "Foreign key not created because it exists already " \
......
...@@ -214,6 +214,23 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -214,6 +214,23 @@ describe Gitlab::Database::MigrationHelpers do
model.add_concurrent_foreign_key(:projects, :users, column: :user_id) model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
end end
it 'allows the use of a custom key name' do
expect(model).to receive(:add_foreign_key).with(
:projects,
:users,
column: :user_id,
on_delete: :cascade,
name: :foo
)
model.add_concurrent_foreign_key(
:projects,
:users,
column: :user_id,
name: :foo
)
end
it 'does not create a foreign key if it exists already' do it 'does not create a foreign key if it exists already' do
expect(model).to receive(:foreign_key_exists?).with(:projects, :users, column: :user_id).and_return(true) expect(model).to receive(:foreign_key_exists?).with(:projects, :users, column: :user_id).and_return(true)
expect(model).not_to receive(:add_foreign_key) expect(model).not_to receive(:add_foreign_key)
...@@ -257,6 +274,16 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -257,6 +274,16 @@ describe Gitlab::Database::MigrationHelpers do
model.add_concurrent_foreign_key(:projects, :users, column: :user_id) model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
end end
it 'allows the use of a custom key name' do
expect(model).to receive(:disable_statement_timeout).and_call_original
expect(model).to receive(:execute).with(/statement_timeout/)
expect(model).to receive(:execute).ordered.with(/NOT VALID/)
expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT.+foo/)
expect(model).to receive(:execute).with(/RESET ALL/)
model.add_concurrent_foreign_key(:projects, :users, column: :user_id, name: :foo)
end
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