gitlab-org--gitlab-foss/db/migrate/20170516153305_migrate_assignee_to_separate_table.rb
Yorick Peterse cb4ee4b131
Check if OLD is set when migrating issue assignees
The procedure for migrating issue assignees is invoked on both an INSERT
and UPDATE. This means it will fail for INSERTs because OLD is set to
NULL in this case.
2017-05-17 22:56:23 +02:00

83 lines
2.8 KiB
Ruby

# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class MigrateAssigneeToSeparateTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# When a migration requires downtime you **must** uncomment the following
# constant and define a short and easy to understand explanation as to why the
# migration requires downtime.
# DOWNTIME_REASON = ''
# When using the methods "add_concurrent_index", "remove_concurrent_index" or
# "add_column_with_default" you must disable the use of transactions
# as these methods can not run in an existing transaction.
# When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
# that either of them is the _only_ method called in the migration,
# any other changes should go in a separate migration.
# This ensures that upon failure _only_ the index creation or removing fails
# and can be retried or reverted easily.
#
# To disable transactions uncomment the following line and remove these
# comments:
# disable_ddl_transaction!
def up
drop_table(:issue_assignees) if table_exists?(:issue_assignees)
if Gitlab::Database.mysql?
execute <<-EOF
CREATE TABLE issue_assignees AS
SELECT assignee_id AS user_id, id AS issue_id FROM issues WHERE assignee_id IS NOT NULL
EOF
else
ActiveRecord::Base.transaction do
execute('LOCK TABLE issues IN EXCLUSIVE MODE')
execute <<-EOF
CREATE TABLE issue_assignees AS
SELECT assignee_id AS user_id, id AS issue_id FROM issues WHERE assignee_id IS NOT NULL
EOF
execute <<-EOF
CREATE OR REPLACE FUNCTION replicate_assignee_id()
RETURNS trigger AS
$BODY$
BEGIN
if OLD IS NOT NULL AND OLD.assignee_id IS NOT NULL THEN
DELETE FROM issue_assignees WHERE issue_id = OLD.id;
END IF;
if NEW.assignee_id IS NOT NULL THEN
INSERT INTO issue_assignees (user_id, issue_id) VALUES (NEW.assignee_id, NEW.id);
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql'
VOLATILE;
CREATE TRIGGER replicate_assignee_id
BEFORE INSERT OR UPDATE OF assignee_id
ON issues
FOR EACH ROW EXECUTE PROCEDURE replicate_assignee_id();
EOF
end
end
end
def down
drop_table(:issue_assignees) if table_exists?(:issue_assignees)
if Gitlab::Database.postgresql?
execute <<-EOF
DROP TRIGGER IF EXISTS replicate_assignee_id ON issues;
DROP FUNCTION IF EXISTS replicate_assignee_id();
EOF
end
end
end