diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-09 15:10:06 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-09 15:10:06 +0300 |
commit | 963e09aecfb3cdd57babdd9b37c15e34601fdb42 (patch) | |
tree | 2c3067224f4ed5197d9bfc34a1ff63e7003e05dc /lib/gitlab | |
parent | 529d3153bc5823c8326f04649f8362f1a32d8c61 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/gitlab')
-rw-r--r-- | lib/gitlab/database/migration_helpers/convert_to_bigint.rb | 88 |
1 files changed, 82 insertions, 6 deletions
diff --git a/lib/gitlab/database/migration_helpers/convert_to_bigint.rb b/lib/gitlab/database/migration_helpers/convert_to_bigint.rb index 11f1e62e8b9..d1edb739b85 100644 --- a/lib/gitlab/database/migration_helpers/convert_to_bigint.rb +++ b/lib/gitlab/database/migration_helpers/convert_to_bigint.rb @@ -4,12 +4,16 @@ module Gitlab module Database module MigrationHelpers module ConvertToBigint - # This helper is extracted for the purpose of - # https://gitlab.com/gitlab-org/gitlab/-/issues/392815 - # so that we can test all combinations just once, - # and simplify migration tests. - # - # Once we are done with the PK conversions we can remove this. + INDEX_OPTIONS_MAP = { + unique: :unique, + order: :orders, + opclass: :opclasses, + where: :where, + type: :type, + using: :using, + comment: :comment + }.freeze + def com_or_dev_or_test_but_not_jh? return true if Gitlab.dev_or_test_env? @@ -29,6 +33,78 @@ module Gitlab column.sql_type == 'bigint' && temp_column.sql_type == 'integer' end + + def add_bigint_column_indexes(table_name, int_column_name) + bigint_column_name = convert_to_bigint_column(int_column_name) + + unless column_exists?(table_name.to_s, bigint_column_name) + raise "Bigint column '#{bigint_column_name}' does not exist on #{table_name}" + end + + indexes(table_name).each do |i| + next unless Array(i.columns).join(' ').match?(/\b#{int_column_name}\b/) + + create_bigint_index(table_name, i, int_column_name, bigint_column_name) + end + end + + # default 'index_name' method is not used because this method can be reused while swapping/dropping the indexes + def bigint_index_name(int_column_index_name) + # First 20 digits of the hash is chosen to make sure it fits the 63 chars limit + digest = Digest::SHA256.hexdigest(int_column_index_name).first(20) + "bigint_idx_#{digest}" + end + + private + + def create_bigint_index(table_name, index_definition, int_column_name, bigint_column_name) + index_attributes = index_definition.as_json + index_options = INDEX_OPTIONS_MAP + .transform_values { |key| index_attributes[key.to_s] } + .select { |_, v| v.present? } + + bigint_index_options = create_bigint_options( + index_options, + index_definition.name, + int_column_name, + bigint_column_name + ) + + add_concurrent_index( + table_name, + bigint_index_columns(int_column_name, bigint_column_name, index_definition.columns), + name: bigint_index_options.delete(:name), + ** bigint_index_options + ) + end + + def bigint_index_columns(int_column_name, bigint_column_name, int_index_columns) + if int_index_columns.is_a?(String) + int_index_columns.gsub(/\b#{int_column_name}\b/, bigint_column_name) + else + int_index_columns.map do |column| + column == int_column_name.to_s ? bigint_column_name : column + end + end + end + + def create_bigint_options(index_options, int_index_name, int_column_name, bigint_column_name) + index_options[:name] = bigint_index_name(int_index_name) + index_options[:where]&.gsub!(/\b#{int_column_name}\b/, bigint_column_name) + + # ordering on multiple columns will return a Hash instead of string + index_options[:order] = + if index_options[:order].is_a?(Hash) + index_options[:order].to_h do |column, order| + column = bigint_column_name if column == int_column_name + [column, order] + end + else + index_options[:order]&.gsub(/\b#{int_column_name}\b/, bigint_column_name) + end + + index_options.select { |_, v| v.present? } + end end end end |