Hash concurrent foreign key names similar to Rails
This was initially not implemented simply because I forgot about the size limit of constraint names in PostgreSQL (63 bytes). Using the old technique we can't add foreign keys for certain tables. For example, adding a foreign key on protected_branch_merge_access_levels.protected_branch_id would lead to the following key name: fk_protected_branch_merge_access_levels_protected_branches_protected_branch_id This key is 78 bytes long, thus violating the PostgreSQL size requirements. The hashing strategy is copied from Rails' foreign_key_name() method, which unfortunately is private and subject to change without notice.
This commit is contained in:
parent
459a97d468
commit
79696f5b7a
|
@ -54,7 +54,7 @@ module Gitlab
|
|||
|
||||
disable_statement_timeout
|
||||
|
||||
key_name = "fk_#{source}_#{target}_#{column}"
|
||||
key_name = concurrent_foreign_key_name(source, column)
|
||||
|
||||
# Using NOT VALID allows us to create a key without immediately
|
||||
# validating it. This means we keep the ALTER TABLE lock only for a
|
||||
|
@ -74,6 +74,15 @@ module Gitlab
|
|||
execute("ALTER TABLE #{source} VALIDATE CONSTRAINT #{key_name};")
|
||||
end
|
||||
|
||||
# Returns the name for a concurrent foreign key.
|
||||
#
|
||||
# PostgreSQL constraint names have a limit of 63 bytes. The logic used
|
||||
# here is based on Rails' foreign_key_name() method, which unfortunately
|
||||
# is private so we can't rely on it directly.
|
||||
def concurrent_foreign_key_name(table, column)
|
||||
"fk_#{Digest::SHA256.hexdigest("#{table}_#{column}_fk").first(10)}"
|
||||
end
|
||||
|
||||
# Long-running migrations may take more than the timeout allowed by
|
||||
# the database. Disable the session's statement timeout to ensure
|
||||
# migrations don't get killed prematurely. (PostgreSQL only)
|
||||
|
|
|
@ -101,6 +101,16 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#concurrent_foreign_key_name' do
|
||||
it 'returns the name for a foreign key' do
|
||||
name = model.concurrent_foreign_key_name(:this_is_a_very_long_table_name,
|
||||
:with_a_very_long_column_name)
|
||||
|
||||
expect(name).to be_an_instance_of(String)
|
||||
expect(name.length).to eq(13)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#disable_statement_timeout' do
|
||||
context 'using PostgreSQL' do
|
||||
it 'disables statement timeouts' do
|
||||
|
|
Loading…
Reference in New Issue