summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2017-02-21 15:07:02 +0100
committerYorick Peterse <yorickpeterse@gmail.com>2017-02-21 15:07:02 +0100
commit79696f5b7aaf260176355026e91af05d40d92d0c (patch)
treeefee41993f5d006e9c5b717af4789576a09f50d4
parent459a97d46812fecc59c973bad356935422c7f60e (diff)
downloadgitlab-ce-hash-concurrent-foreign-key-names.tar.gz
Hash concurrent foreign key names similar to Railshash-concurrent-foreign-key-names
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.
-rw-r--r--lib/gitlab/database/migration_helpers.rb11
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb10
2 files changed, 20 insertions, 1 deletions
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 4800a509b37..fc445ab9483 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -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)
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index e94ca4fcfd2..e007044868c 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -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