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) ================== 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..0e16647 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 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 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..a9a5d55 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,23 @@ 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_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 def test_slash_dn(executor): """List all schemas.""" @@ -366,6 +386,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 +512,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 +531,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 +801,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