v1-0001-Add-pretty-formatting-to-pg_get_triggerdef.patch
application/octet-stream
Filename: v1-0001-Add-pretty-formatting-to-pg_get_triggerdef.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v1-0001
Subject: Add pretty formatting to pg_get_triggerdef
| File | + | − |
|---|---|---|
| src/backend/utils/adt/ruleutils.c | 60 | 9 |
| src/bin/psql/describe.c | 1 | 1 |
| src/include/catalog/pg_proc.dat | 3 | 0 |
| src/test/regress/expected/triggers.out | 14 | 6 |
From 8fb727b4849845fa1bbf733e2a5d015e56820095 Mon Sep 17 00:00:00 2001
From: Phil Alger <paalger0@gmail.com>
Date: Mon, 3 Nov 2025 17:49:10 -0600
Subject: [PATCH v1] Add pretty formatting to pg_get_triggerdef
This patch adds pretty formatting to the pg_get_triggerdef function. Currently,
when the function is called with the pretty flag, it will not display the schema
and the format is displayed as a single line. This patch modifies this function to
be consistent with functions like pg_get_viewdef, pg_get_ruledef, and pg_get_indexdef,
which display their output as pretty printed SQL. This is an example of the new format:
1. pg_get_triggerdef(oid, true) - New Pretty Format**
postgres=# select pg_get_triggerdef(12345, true);
pg_get_triggerdef
--------------------------------------------------
CREATE TRIGGER some_trig_foobar AFTER UPDATE +
ON some_t +
FOR EACH ROW +
WHEN (NOT new.some_col) +
EXECUTE FUNCTION dummy_update_func('foobar')
(1 row)
2. pg_get_triggerdef(oid, false) - Existing Compact Format
When pretty printing is false, the output is unchanged from the original function:
postgres=# select pg_get_triggerdef(47901, false);
pg_get_triggerdef
---------------------------------------------------------------------------------------------------------------------------------------------------
CREATE TRIGGER some_trig_foobar AFTER UPDATE ON public.some_t FOR EACH ROW WHEN ((NOT new.some_col)) EXECUTE FUNCTION dummy_update_func('foobar')
(1 row)
3. New Function: pg_get_triggerdef_compact(oid)
This patch also adds a new function, pg_get_triggerdef_compact, which returns trigger definitions
in a compact, single-line format without schema qualification. This is specifically designed
for the psql \d command.
postgres=# select pg_get_triggerdef_compact(47901);
pg_get_triggerdef_compact
--------------------------------------------------------------------------------------------------------------------------------------------
CREATE TRIGGER some_trig_foobar AFTER UPDATE ON some_t FOR EACH ROW WHEN ((NOT new.some_col)) EXECUTE FUNCTION dummy_update_func('foobar')
(1 row)
This change is due to the \d command's behavior, which shows a table's triggers without schema
qualification. Prior to this patch, pg_get_triggerdef(oid, true) was used because its current
behavior removed the schema name, but at the cost of being un-pretty. The new function allows \d
to use a single-line output that lacks the schema name, while allowing the original function's
'pretty' output to correctly include the schema name and formatting. Here's an example:
postgres=# \d main_table
Table "public.main_table"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
b | integer | | |
Indexes:
"main_table_a_key" UNIQUE CONSTRAINT, btree (a)
Triggers:
foofoo AFTER INSERT ON main_table FOR EACH STATEMENT EXECUTE FUNCTION trigger_func('foo_bar')
foo_bar BEFORE INSERT ON main_table FOR EACH STATEMENT EXECUTE FUNCTION trigger_func('foo_bar')
bar_fooAFTER DELETE ON main_table FOR EACH ROW WHEN ((old.a = 123)) EXECUTE FUNCTION trigger_func('foo_bar')
Author: Phil Alger <paalger0@gmail.com>
---
src/backend/utils/adt/ruleutils.c | 69 ++++++++++++++++++++++----
src/bin/psql/describe.c | 2 +-
src/include/catalog/pg_proc.dat | 3 ++
src/test/regress/expected/triggers.out | 20 +++++---
4 files changed, 78 insertions(+), 16 deletions(-)
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 79ec136231..afbca150d5 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -352,7 +352,7 @@ static char *deparse_expression_pretty(Node *expr, List *dpcontext,
int prettyFlags, int startIndent);
static char *pg_get_viewdef_worker(Oid viewoid,
int prettyFlags, int wrapColumn);
-static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
+static char *pg_get_triggerdef_worker(Oid trigid, int prettyFlags);
static int decompile_column_index_array(Datum column_index_array, Oid relId,
bool withPeriod, StringInfo buf);
static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
@@ -886,9 +886,31 @@ pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
{
Oid trigid = PG_GETARG_OID(0);
bool pretty = PG_GETARG_BOOL(1);
+ int prettyFlags;
char *res;
- res = pg_get_triggerdef_worker(trigid, pretty);
+ prettyFlags = pretty ? GET_PRETTY_FLAGS(pretty) : 0;
+
+ res = pg_get_triggerdef_worker(trigid, prettyFlags);
+
+ if (res == NULL)
+ PG_RETURN_NULL();
+
+ PG_RETURN_TEXT_P(string_to_text(res));
+}
+
+/*
+ * pg_get_triggerdef_compact
+ * Returns trigger definition in a compact, single-line format without
+ * schema qualification designed for the psql \d command.
+ */
+Datum
+pg_get_triggerdef_compact(PG_FUNCTION_ARGS)
+{
+ Oid trigid = PG_GETARG_OID(0);
+ char *res;
+
+ res = pg_get_triggerdef_worker(trigid, PRETTYFLAG_SCHEMA);
if (res == NULL)
PG_RETURN_NULL();
@@ -897,7 +919,7 @@ pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
}
static char *
-pg_get_triggerdef_worker(Oid trigid, bool pretty)
+pg_get_triggerdef_worker(Oid trigid, int prettyFlags)
{
HeapTuple ht_trig;
Form_pg_trigger trigrec;
@@ -1007,11 +1029,21 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
* In non-pretty mode, always schema-qualify the target table name for
* safety. In pretty mode, schema-qualify only if not visible.
*/
- appendStringInfo(&buf, " ON %s ",
- pretty ?
+ if (prettyFlags & PRETTYFLAG_INDENT)
+ appendStringInfoString(&buf, "\n ");
+ else
+ appendStringInfoString(&buf, " ");
+
+ appendStringInfo(&buf, "ON %s",
+ (prettyFlags & PRETTYFLAG_SCHEMA) ?
generate_relation_name(trigrec->tgrelid, NIL) :
generate_qualified_relation_name(trigrec->tgrelid));
+ if (prettyFlags & PRETTYFLAG_INDENT)
+ appendStringInfoChar(&buf, '\n');
+ else
+ appendStringInfoString(&buf, " ");
+
if (OidIsValid(trigrec->tgconstraint))
{
if (OidIsValid(trigrec->tgconstrrelid))
@@ -1049,10 +1081,18 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
quote_identifier(tgnewtable));
}
+ if (prettyFlags & PRETTYFLAG_INDENT)
+ appendStringInfoString(&buf, " ");
+
if (TRIGGER_FOR_ROW(trigrec->tgtype))
- appendStringInfoString(&buf, "FOR EACH ROW ");
+ appendStringInfoString(&buf, "FOR EACH ROW");
+ else
+ appendStringInfoString(&buf, "FOR EACH STATEMENT");
+
+ if (prettyFlags & PRETTYFLAG_INDENT)
+ appendStringInfoChar(&buf, '\n');
else
- appendStringInfoString(&buf, "FOR EACH STATEMENT ");
+ appendStringInfoChar(&buf, ' ');
/* If the trigger has a WHEN qualification, add that */
value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
@@ -1066,6 +1106,9 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
RangeTblEntry *oldrte;
RangeTblEntry *newrte;
+ if (prettyFlags & PRETTYFLAG_INDENT)
+ appendStringInfoString(&buf, " ");
+
appendStringInfoString(&buf, "WHEN (");
qual = stringToNode(TextDatumGetCString(value));
@@ -1111,7 +1154,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
context.targetList = NIL;
context.windowClause = NIL;
context.varprefix = true;
- context.prettyFlags = GET_PRETTY_FLAGS(pretty);
+ context.prettyFlags = prettyFlags;
context.wrapColumn = WRAP_COLUMN_DEFAULT;
context.indentLevel = PRETTYINDENT_STD;
context.colNamesVisible = true;
@@ -1121,9 +1164,17 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
get_rule_expr(qual, &context, false);
- appendStringInfoString(&buf, ") ");
+ appendStringInfoChar(&buf, ')');
+
+ if (prettyFlags & PRETTYFLAG_INDENT)
+ appendStringInfoChar(&buf, '\n');
+ else
+ appendStringInfoString(&buf, " ");
}
+ if (prettyFlags & PRETTYFLAG_INDENT)
+ appendStringInfoString(&buf, " ");
+
appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
generate_function_name(trigrec->tgfoid, 0,
NIL, NULL,
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 36f2450284..dffaeecc50 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3251,7 +3251,7 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf,
"SELECT t.tgname, "
- "pg_catalog.pg_get_triggerdef(t.oid, true), "
+ "pg_catalog.pg_get_triggerdef_compact(t.oid), "
"t.tgenabled, t.tgisinternal,\n");
/*
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 9121a382f7..1c91c18edd 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -8555,6 +8555,9 @@
{ oid => '2730', descr => 'trigger description with pretty-print option',
proname => 'pg_get_triggerdef', provolatile => 's', prorettype => 'text',
proargtypes => 'oid bool', prosrc => 'pg_get_triggerdef_ext' },
+{ oid => '9750', descr => 'trigger description in compact single-line format',
+ proname => 'pg_get_triggerdef_compact', provolatile => 's', prorettype => 'text',
+ proargtypes => 'oid', prosrc => 'pg_get_triggerdef_compact' },
# asynchronous notifications
{ oid => '3035',
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 1eb8fba095..7b57394bb3 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -299,9 +299,13 @@ SELECT * FROM main_table ORDER BY a, b;
(8 rows)
SELECT pg_get_triggerdef(oid, true) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'modified_a';
- pg_get_triggerdef
--------------------------------------------------------------------------------------------------------------------------------------------
- CREATE TRIGGER modified_a BEFORE UPDATE OF a ON main_table FOR EACH ROW WHEN (old.a <> new.a) EXECUTE FUNCTION trigger_func('modified_a')
+ pg_get_triggerdef
+-------------------------------------------------
+ CREATE TRIGGER modified_a BEFORE UPDATE OF a +
+ ON main_table +
+ FOR EACH ROW +
+ WHEN (old.a <> new.a) +
+ EXECUTE FUNCTION trigger_func('modified_a')
(1 row)
SELECT pg_get_triggerdef(oid, false) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'modified_a';
@@ -311,9 +315,13 @@ SELECT pg_get_triggerdef(oid, false) FROM pg_trigger WHERE tgrelid = 'main_table
(1 row)
SELECT pg_get_triggerdef(oid, true) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'modified_any';
- pg_get_triggerdef
--------------------------------------------------------------------------------------------------------------------------------------------------------------
- CREATE TRIGGER modified_any BEFORE UPDATE OF a ON main_table FOR EACH ROW WHEN (old.* IS DISTINCT FROM new.*) EXECUTE FUNCTION trigger_func('modified_any')
+ pg_get_triggerdef
+---------------------------------------------------
+ CREATE TRIGGER modified_any BEFORE UPDATE OF a +
+ ON main_table +
+ FOR EACH ROW +
+ WHEN (old.* IS DISTINCT FROM new.*) +
+ EXECUTE FUNCTION trigger_func('modified_any')
(1 row)
-- Test RENAME TRIGGER
--
2.50.1 (Apple Git-155)