Rebind issues work item transitions trigger after bigint swap

What does this MR do and why?

trigger_sync_work_item_transitions_from_issues fires on UPDATE OF a specific list of columns. PostgreSQL stores that list as attribute numbers, not column names, so the column renames performed by the batch one bigint swap (20260916090001) left the trigger bound to the old integer columns, which are now named *_convert_to_bigint.

The effect is that UPDATEs which set moved_to_id, duplicated_to_id or promoted_to_epic_id no longer fire the trigger, so those values stop syncing to work_item_transitions. Inserts are unaffected, as is any update that also changes namespace_id, since that column was not swapped.

This matters because EE reads the promotion state from that table: Issue#promoted_to_epic is delegated to work_item_transition, the "can be promoted" check reads it, and the work item presenter builds the promoted-epic URL from it. An issue promoted after the swap can appear unpromoted and could be promoted a second time.

Observed on GitLab.com after the swap deployed:

CREATE TRIGGER trigger_sync_work_item_transitions_from_issues
  AFTER INSERT OR UPDATE OF moved_to_id_convert_to_bigint,
    duplicated_to_id_convert_to_bigint, promoted_to_epic_id_convert_to_bigint,
    namespace_id
  ON public.issues FOR EACH ROW
  EXECUTE FUNCTION sync_work_item_transitions_from_issues()

Why this is urgent

The batch one swap is a 19.5 migration and 19.5 has not been released, so no self-managed instance has run it yet. Fixing the swap migration itself means they never encounter the defect.

What this MR changes

  1. 20260916090001 (the batch one swap) now recreates the trigger by name inside the existing swap transaction. The same swap method runs for both up and down, and the canonical column names always refer to the live columns once the renames complete, so the binding is correct in both directions. On GitLab.com this is a no-op because the migration has already run.
  2. 20261005130000 repairs instances where the swap already ran, which is GitLab.com and any instance tracking pre-release builds.

Recreating the trigger is idempotent. On an instance that never had the conversion columns, the resulting definition is identical to the existing one, so db/structure.sql is unchanged. The generated statement is character for character the same as the definition already committed there.

Both call sites are guarded by trigger_exists?, so an instance without this trigger is untouched.

Is this a gap in the bigint conversion helpers?

Yes. swap_columns is three rename_column calls, and reset_all_trigger_functions only runs ALTER FUNCTION ... RESET ALL, which clears cached plans in pg_proc and never touches pg_trigger. Neither handles a column-specific trigger, and the conversion docs do not mention them.

Earlier conversions did not hit this because none of those tables had an UPDATE OF trigger on a converted column. Every UPDATE OF trigger in db/structure.sql was cross-checked against db/integer_ids_not_yet_initialized_to_bigint.yml, and no other pending conversion is affected today. A follow-up issue will cover teaching the swap helper to recreate affected triggers.

Migration output

db/structure.sql is unchanged, as described above. Danger flags "new migrations added but db/structure.sql wasn't updated", which is expected here.

Follow-up

The work_item_transitions rows that drifted on GitLab.com between the swap deploying and this fix still need a backfill. That is tracked separately so this MR can merge quickly. Some rows will have self-repaired, since an update touching namespace_id still fires the trigger and the function copies all three columns.

MR acceptance checklist

  • Database review requested — recreates a trigger on issues, no schema change.

Merge request reports

Loading
Loading