Skip to content
Snippets Groups Projects
Commit 429e98e8 authored by euko's avatar euko :palm_tree:
Browse files

Swap system_note_metadata.id to bigint

See #424114

Changelog: other
parent fe972a2f
No related branches found
No related tags found
No related merge requests found
# frozen_string_literal: true
class SwapColumnsForSystemNoteMetadataId < Gitlab::Database::Migration[2.2]
include Gitlab::Database::MigrationHelpers::ConvertToBigint
disable_ddl_transaction!
milestone '16.9'
TABLE_NAME = 'system_note_metadata'
PRIMARY_KEY_CONSTRAINT_NAME = 'system_note_metadata_pkey'
PRIMARY_KEY_INDEX_NAME = 'index_system_note_metadata_pkey'
NEW_PRIMARY_KEY_INDEX_NAME = 'index_system_note_metadata_pkey_on_id_convert_to_bigint'
# For the FK from 'resource_link_events' table referencing 'system_note_metadata'.
FK_SOURCE_TABLE_NAME = :resource_link_events
FK_COLUMN_NAME = :system_note_metadata_id
FK_NAME = 'fk_2a039c40f4'
TEMP_FK_NAME = 'fk_system_note_metadata_id_convert_to_bigint'
def up
swap
end
def down
swap
end
def swap
# This will replace the existing system_note_metadata_pkey index for the primary key
add_concurrent_index TABLE_NAME, :id_convert_to_bigint, unique: true, name: NEW_PRIMARY_KEY_INDEX_NAME
# This will replace the existing fk_2a039c40f4
add_concurrent_foreign_key FK_SOURCE_TABLE_NAME, TABLE_NAME,
name: TEMP_FK_NAME,
column: FK_COLUMN_NAME,
target_column: :id_convert_to_bigint,
on_delete: :cascade
with_lock_retries(raise_on_exhaustion: true) do
execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
# Swap columns
temp_column_name = quote_column_name(:id_tmp)
id_column_name = quote_column_name(:id)
id_convert_to_bigint_name = quote_column_name(:id_convert_to_bigint)
execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{id_column_name} TO #{temp_column_name}"
execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{id_convert_to_bigint_name} TO #{id_column_name}"
execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{temp_column_name} TO #{id_convert_to_bigint_name}"
# Reset trigger
function_name = Gitlab::Database::UnidirectionalCopyTrigger
.on_table(TABLE_NAME, connection: connection)
.name(:id, :id_convert_to_bigint)
execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
# Swap defaults
seq_name = "system_note_metadata_id_seq"
execute "ALTER SEQUENCE #{seq_name} OWNED BY #{TABLE_NAME}.id"
change_column_default TABLE_NAME, :id, -> { "nextval('#{seq_name}'::regclass)" }
change_column_default TABLE_NAME, :id_convert_to_bigint, 0
# Swap pkey constraint
# This will drop fk_2a039c40f4 ("resource_link_events" REFERENCES system_note_metadata(id) ON DELETE CASCADE)
execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT #{PRIMARY_KEY_CONSTRAINT_NAME} CASCADE"
rename_index TABLE_NAME, NEW_PRIMARY_KEY_INDEX_NAME, PRIMARY_KEY_INDEX_NAME
execute "ALTER TABLE #{TABLE_NAME} ADD CONSTRAINT #{PRIMARY_KEY_CONSTRAINT_NAME} PRIMARY KEY USING INDEX #{PRIMARY_KEY_INDEX_NAME}" # rubocop:disable Layout/LineLength -- for readability
# Rename the new FK
rename_constraint FK_SOURCE_TABLE_NAME, TEMP_FK_NAME, FK_NAME
end
end
end
c579e5722d58bb422a82f52706e37e1e89ee18c90772ce1da20ae94f670618ab
\ No newline at end of file
...@@ -24480,14 +24480,14 @@ CREATE SEQUENCE system_access_microsoft_graph_access_tokens_id_seq ...@@ -24480,14 +24480,14 @@ CREATE SEQUENCE system_access_microsoft_graph_access_tokens_id_seq
ALTER SEQUENCE system_access_microsoft_graph_access_tokens_id_seq OWNED BY system_access_microsoft_graph_access_tokens.id; ALTER SEQUENCE system_access_microsoft_graph_access_tokens_id_seq OWNED BY system_access_microsoft_graph_access_tokens.id;
   
CREATE TABLE system_note_metadata ( CREATE TABLE system_note_metadata (
id integer NOT NULL, id_convert_to_bigint integer DEFAULT 0 NOT NULL,
commit_count integer, commit_count integer,
action character varying, action character varying,
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
description_version_id bigint, description_version_id bigint,
note_id bigint NOT NULL, note_id bigint NOT NULL,
id_convert_to_bigint bigint DEFAULT 0 NOT NULL id bigint NOT NULL
); );
   
CREATE SEQUENCE system_note_metadata_id_seq CREATE SEQUENCE system_note_metadata_id_seq
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe SwapColumnsForSystemNoteMetadataId, feature_category: :team_planning do
describe '#up' do
let(:pk_name) { "system_note_metadata_pkey" }
let(:fk_name) { "fk_2a039c40f4" } # FK on 'resource_link_events'
before do
# A we call `schema_migrate_down!` before each example, and for this migration
# `#down` is same as `#up`, we need to ensure we start from the expected state.
connection = described_class.new.connection
connection.execute('ALTER TABLE system_note_metadata ALTER COLUMN id TYPE integer')
connection.execute('ALTER TABLE system_note_metadata ALTER COLUMN id_convert_to_bigint TYPE bigint')
end
it 'swaps the integer and bigint columns with correct constraint names' do
table = table(:system_note_metadata)
disable_migrations_output do
reversible_migration do |migration|
migration.before -> {
table.reset_column_information
primary_key_naming_check = query_constraint_by_name(:system_note_metadata, pk_name).first
foreign_key_naming_check = query_constraint_by_name(:resource_link_events, fk_name).first
expect(primary_key_naming_check).to match("bool" => true)
expect(foreign_key_naming_check).to match("bool" => true)
expect(table.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer')
expect(table.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint')
}
migration.after -> {
table.reset_column_information
primary_key_naming_check = query_constraint_by_name(:system_note_metadata, pk_name).first
foreign_key_naming_check = query_constraint_by_name(:resource_link_events, fk_name).first
expect(primary_key_naming_check).to match("bool" => true)
expect(foreign_key_naming_check).to match("bool" => true)
expect(table.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
expect(table.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('integer')
}
end
end
end
def query_constraint_by_name(table_name, conname)
described_class.new.connection.execute <<~SQL
SELECT true FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid
WHERE t.relname = \'#{table_name}\' AND c.conname = \'#{conname}\';
SQL
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment