From 648d6ac8db1b71f5a945f7a7521d1048f5793793 Mon Sep 17 00:00:00 2001 From: Devadathan M B Date: Sat, 11 Apr 2026 19:31:53 +0530 Subject: [PATCH 1/4] fix: correctly separate disabled triggers in \d table output --- pgspecial/dbcommands.py | 5 +++-- tests/dbutils.py | 10 ++++++++++ tests/test_specials.py | 30 ++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/pgspecial/dbcommands.py b/pgspecial/dbcommands.py index 7f02e6c..f46c8cc 100644 --- a/pgspecial/dbcommands.py +++ b/pgspecial/dbcommands.py @@ -1670,10 +1670,11 @@ def describe_one_table_details(cur, schema_name, relation_name, oid, verbose): # * disabled triggers and the two special ALWAYS and REPLICA # * configurations. # */ + rows = cur.fetchall() for category in range(4): have_heading = False - list_trigger = False - for row in cur: + for row in rows: + list_trigger = False # /* # * Check if this trigger falls into the current category # */ diff --git a/tests/dbutils.py b/tests/dbutils.py index 3f73f6b..79dd2c7 100644 --- a/tests/dbutils.py +++ b/tests/dbutils.py @@ -105,6 +105,16 @@ def setup_db(conn): cur.execute("create domain schema1.bigint_t bigint") cur.execute("comment on domain schema1.bigint_t is 'a really large integer'") + # triggers + cur.execute("create table tbl_with_triggers(id integer)") + cur.execute( + """create function trigger_noop() returns trigger language plpgsql as + $$ begin return new; end $$""" + ) + cur.execute("create trigger trig_enabled after insert on tbl_with_triggers for each row execute function trigger_noop()") + cur.execute("create trigger trig_disabled after insert on tbl_with_triggers for each row execute function trigger_noop()") + cur.execute("alter table tbl_with_triggers disable trigger trig_disabled") + # privileges cur.execute("CREATE ROLE test_role;") cur.execute("ALTER DEFAULT PRIVILEGES IN SCHEMA schema1 GRANT SELECT ON TABLES TO test_role;") diff --git a/tests/test_specials.py b/tests/test_specials.py index 6ce5a03..dfd0643 100755 --- a/tests/test_specials.py +++ b/tests/test_specials.py @@ -126,10 +126,11 @@ def test_slash_d(executor): ("public", "tbl2", "table", POSTGRES_USER), ("public", "tbl2_id2_seq", "sequence", POSTGRES_USER), ("public", "tbl3", "table", POSTGRES_USER), + ("public", "tbl_with_triggers", "table", POSTGRES_USER), ("public", "vw1", "view", POSTGRES_USER), ] headers = objects_listing_headers[:-2] - status = "SELECT 8" + status = "SELECT 9" expected = [title, rows, headers, status] assert results == expected @@ -147,10 +148,11 @@ def test_slash_d_verbose(executor): ("public", "tbl2", "table", POSTGRES_USER, "8192 bytes", None), ("public", "tbl2_id2_seq", "sequence", POSTGRES_USER, "8192 bytes", None), ("public", "tbl3", "table", POSTGRES_USER, "0 bytes", None), + ("public", "tbl_with_triggers", "table", POSTGRES_USER, "0 bytes", None), ("public", "vw1", "view", POSTGRES_USER, "0 bytes", None), ] headers = objects_listing_headers - status = "SELECT 8" + status = "SELECT 9" expected = [title, rows, headers, status] assert results == expected @@ -197,6 +199,7 @@ def test_slash_d_wildcard(executor): 'Sequence "public.tbl2_id2_seq"', 'Table "public.tbl3"', 'Index "public.tbl3_c3_excl"', + 'Table "public.tbl_with_triggers"', ] @@ -327,6 +330,19 @@ def test_slash_d_table_2_in_schema(executor): assert results == expected +@dbtest +def test_slash_d_table_with_triggers(executor): + results = executor(r"\d tbl_with_triggers") + status = results[3] + assert "Triggers:" in status + assert "trig_enabled" in status + assert "Disabled triggers:" in status + assert "trig_disabled" in status + # trig_disabled must not appear in the enabled section + enabled_section = status[: status.index("Disabled triggers:")] + assert "trig_disabled" not in enabled_section + + @dbtest def test_slash_dn(executor): """List all schemas.""" @@ -366,6 +382,7 @@ def test_slash_dp(executor): ("public", "tbl2", "table", None, "", ""), ("public", "tbl2_id2_seq", "sequence", None, "", ""), ("public", "tbl3", "table", None, "", ""), + ("public", "tbl_with_triggers", "table", None, "", ""), ("public", "vw1", "view", None, "", ""), ] @@ -491,6 +508,7 @@ def test_slash_dt(executor): ("public", "tbl1", "table", POSTGRES_USER), ("public", "tbl2", "table", POSTGRES_USER), ("public", "tbl3", "table", POSTGRES_USER), + ("public", "tbl_with_triggers", "table", POSTGRES_USER), ] headers = objects_listing_headers[:-2] status = "SELECT %s" % len(rows) @@ -509,6 +527,7 @@ def test_slash_dt_verbose(executor): ("public", "tbl1", "table", POSTGRES_USER, "8192 bytes", None), ("public", "tbl2", "table", POSTGRES_USER, "8192 bytes", None), ("public", "tbl3", "table", POSTGRES_USER, "0 bytes", None), + ("public", "tbl_with_triggers", "table", POSTGRES_USER, "0 bytes", None), ] headers = objects_listing_headers status = "SELECT %s" % len(rows) @@ -778,9 +797,12 @@ def test_slash_db_name(executor): def test_slash_df(executor): results = executor(r"\df") title = None - rows = [("public", "func1", "integer", "", "normal")] + rows = [ + ("public", "func1", "integer", "", "normal"), + ("public", "trigger_noop", "trigger", "", "trigger"), + ] headers = ["Schema", "Name", "Result data type", "Argument data types", "Type"] - status = "SELECT 1" + status = "SELECT 2" expected = [title, rows, headers, status] assert results == expected From df744e881e9414483abddb68a45eff9303b1ea73 Mon Sep 17 00:00:00 2001 From: Devadathan M B Date: Sat, 11 Apr 2026 20:11:35 +0530 Subject: [PATCH 2/4] chore: add changelog entry for disabled triggers fix --- changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.rst b/changelog.rst index bbdcfb0..aad249a 100644 --- a/changelog.rst +++ b/changelog.rst @@ -5,6 +5,7 @@ Unreleased Bug fixes: ---------- * Include relation type/name titles in `\d` and `\d+` describe output so wildcard describe results retain per-relation context. +* Fix `\d table` not showing disabled triggers under a separate "Disabled triggers:" section. 2.2.1 (2025-04-27) ================== From 686ed994cf8b734bbdda21ddb47c21a4132a3045 Mon Sep 17 00:00:00 2001 From: Devadathan M B Date: Sat, 11 Apr 2026 20:21:28 +0530 Subject: [PATCH 3/4] fix: use EXECUTE PROCEDURE for trigger creation to support PG10 --- tests/dbutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/dbutils.py b/tests/dbutils.py index 79dd2c7..0e16647 100644 --- a/tests/dbutils.py +++ b/tests/dbutils.py @@ -111,8 +111,8 @@ def setup_db(conn): """create function trigger_noop() returns trigger language plpgsql as $$ begin return new; end $$""" ) - cur.execute("create trigger trig_enabled after insert on tbl_with_triggers for each row execute function trigger_noop()") - cur.execute("create trigger trig_disabled after insert on tbl_with_triggers for each row execute function trigger_noop()") + cur.execute("create trigger trig_enabled after insert on tbl_with_triggers for each row execute procedure trigger_noop()") + cur.execute("create trigger trig_disabled after insert on tbl_with_triggers for each row execute procedure trigger_noop()") cur.execute("alter table tbl_with_triggers disable trigger trig_disabled") # privileges From 4e2222a6b32aa87d3ad066aa364db641f237087f Mon Sep 17 00:00:00 2001 From: Devadathan M B Date: Sat, 11 Apr 2026 20:39:22 +0530 Subject: [PATCH 4/4] test: assert trig_disabled appears within disabled section explicitly --- tests/test_specials.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_specials.py b/tests/test_specials.py index dfd0643..a9a5d55 100755 --- a/tests/test_specials.py +++ b/tests/test_specials.py @@ -338,9 +338,13 @@ def test_slash_d_table_with_triggers(executor): assert "trig_enabled" in status assert "Disabled triggers:" in status assert "trig_disabled" in status - # trig_disabled must not appear in the enabled section + # trig_enabled must appear in the enabled section, trig_disabled must not enabled_section = status[: status.index("Disabled triggers:")] + assert "trig_enabled" in enabled_section assert "trig_disabled" not in enabled_section + # trig_disabled must appear in the disabled section + disabled_section = status[status.index("Disabled triggers:") :] + assert "trig_disabled" in disabled_section @dbtest