From 3980379b48a263aa684b789d6f7811b1c61eb11e Mon Sep 17 00:00:00 2001 From: "seer-by-sentry[bot]" <157164994+seer-by-sentry[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:10:26 +0000 Subject: [PATCH 1/3] fix(db): Convert owners triggers from BEFORE to AFTER --- .../0011_convert_owners_trigger_to_after.py | 31 +++++++++++++++++++ .../legacy_sql/main/triggers/owners.py | 4 +-- 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py diff --git a/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py b/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py new file mode 100644 index 000000000..6a5548aa7 --- /dev/null +++ b/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py @@ -0,0 +1,31 @@ +# Generated by Django on 2025-12-09 +# Fix for TriggeredDataChangeViolation: convert BEFORE trigger to AFTER trigger +# BEFORE triggers cannot modify the same table they are triggered on + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("legacy_migrations", "0010_fix_owners_trigger_self_modification"), + ] + + operations = [ + migrations.RunSQL( + """ + -- Drop existing BEFORE triggers + drop trigger if exists owners_before_insert on owners; + drop trigger if exists owners_before_update on owners; + + -- Recreate as AFTER triggers + create trigger owners_after_insert after insert on owners + for each row + execute procedure owners_before_insert_or_update(); + + create trigger owners_after_update after update on owners + for each row + when (new.username is not null and new.username is distinct from old.username) + execute procedure owners_before_insert_or_update(); + """ + ), + ] \ No newline at end of file diff --git a/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py b/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py index 7fb1bd0e3..36913a163 100644 --- a/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py +++ b/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py @@ -15,11 +15,11 @@ def run_sql(schema_editor): end; $$ language plpgsql; - create trigger owners_before_insert before insert on owners + create trigger owners_after_insert after insert on owners for each row execute procedure owners_before_insert_or_update(); - create trigger owners_before_update before update on owners + create trigger owners_after_update after update on owners for each row when (new.username is not null and new.username is distinct from old.username) execute procedure owners_before_insert_or_update(); From 56f89ac84666c60390668d793e5b50e7fa7d469d Mon Sep 17 00:00:00 2001 From: Tom Hu Date: Sat, 13 Dec 2025 00:41:26 +0800 Subject: [PATCH 2/3] fix: naming --- .../0011_convert_owners_trigger_to_after.py | 23 +++++++++++++++---- .../legacy_sql/main/triggers/owners.py | 6 ++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py b/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py index 6a5548aa7..7a5b196a5 100644 --- a/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py +++ b/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py @@ -17,15 +17,30 @@ class Migration(migrations.Migration): drop trigger if exists owners_before_insert on owners; drop trigger if exists owners_before_update on owners; - -- Recreate as AFTER triggers + -- Create the renamed function (AFTER instead of BEFORE) + create or replace function owners_after_insert_or_update() returns trigger as $$ + begin + -- user has changed name or deleted and invalidate sessions + with _owners as (update owners + set username = null + where service = new.service + and username = new.username::citext + and ownerid is distinct from new.ownerid + returning ownerid) + delete from sessions where ownerid in (select ownerid from _owners); + return new; + end; + $$ language plpgsql; + + -- Recreate as AFTER triggers using the renamed function create trigger owners_after_insert after insert on owners for each row - execute procedure owners_before_insert_or_update(); + execute procedure owners_after_insert_or_update(); create trigger owners_after_update after update on owners for each row when (new.username is not null and new.username is distinct from old.username) - execute procedure owners_before_insert_or_update(); + execute procedure owners_after_insert_or_update(); """ ), - ] \ No newline at end of file + ] diff --git a/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py b/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py index 36913a163..20eeff0a0 100644 --- a/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py +++ b/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py @@ -1,7 +1,7 @@ def run_sql(schema_editor): schema_editor.execute( """ - create or replace function owners_before_insert_or_update() returns trigger as $$ + create or replace function owners_after_insert_or_update() returns trigger as $$ begin -- user has changed name or deleted and invalidate sessions with _owners as (update owners @@ -17,11 +17,11 @@ def run_sql(schema_editor): create trigger owners_after_insert after insert on owners for each row - execute procedure owners_before_insert_or_update(); + execute procedure owners_after_insert_or_update(); create trigger owners_after_update after update on owners for each row when (new.username is not null and new.username is distinct from old.username) - execute procedure owners_before_insert_or_update(); + execute procedure owners_after_insert_or_update(); """ ) From cfb3f7913afadae49fb22f24e63be526d7726d09 Mon Sep 17 00:00:00 2001 From: Tom Hu Date: Sat, 13 Dec 2025 00:54:25 +0800 Subject: [PATCH 3/3] fix: update naming --- .../0011_convert_owners_trigger_to_after.py | 21 +++---------------- .../legacy_sql/main/triggers/owners.py | 10 ++++----- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py b/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py index 7a5b196a5..482c96f3b 100644 --- a/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py +++ b/libs/shared/shared/django_apps/legacy_migrations/migrations/0011_convert_owners_trigger_to_after.py @@ -17,30 +17,15 @@ class Migration(migrations.Migration): drop trigger if exists owners_before_insert on owners; drop trigger if exists owners_before_update on owners; - -- Create the renamed function (AFTER instead of BEFORE) - create or replace function owners_after_insert_or_update() returns trigger as $$ - begin - -- user has changed name or deleted and invalidate sessions - with _owners as (update owners - set username = null - where service = new.service - and username = new.username::citext - and ownerid is distinct from new.ownerid - returning ownerid) - delete from sessions where ownerid in (select ownerid from _owners); - return new; - end; - $$ language plpgsql; - - -- Recreate as AFTER triggers using the renamed function + -- Recreate as AFTER triggers (function name unchanged, behavior is the same) create trigger owners_after_insert after insert on owners for each row - execute procedure owners_after_insert_or_update(); + execute procedure owners_before_insert_or_update(); create trigger owners_after_update after update on owners for each row when (new.username is not null and new.username is distinct from old.username) - execute procedure owners_after_insert_or_update(); + execute procedure owners_before_insert_or_update(); """ ), ] diff --git a/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py b/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py index 20eeff0a0..7fb1bd0e3 100644 --- a/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py +++ b/libs/shared/shared/django_apps/legacy_migrations/migrations/legacy_sql/main/triggers/owners.py @@ -1,7 +1,7 @@ def run_sql(schema_editor): schema_editor.execute( """ - create or replace function owners_after_insert_or_update() returns trigger as $$ + create or replace function owners_before_insert_or_update() returns trigger as $$ begin -- user has changed name or deleted and invalidate sessions with _owners as (update owners @@ -15,13 +15,13 @@ def run_sql(schema_editor): end; $$ language plpgsql; - create trigger owners_after_insert after insert on owners + create trigger owners_before_insert before insert on owners for each row - execute procedure owners_after_insert_or_update(); + execute procedure owners_before_insert_or_update(); - create trigger owners_after_update after update on owners + create trigger owners_before_update before update on owners for each row when (new.username is not null and new.username is distinct from old.username) - execute procedure owners_after_insert_or_update(); + execute procedure owners_before_insert_or_update(); """ )