summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/pg_dump/pg_dump.c94
-rw-r--r--src/bin/pg_dump/pg_dump.h1
-rw-r--r--src/bin/pg_dump/t/002_pg_dump.pl73
-rw-r--r--src/test/regress/expected/sanity_check.out2
-rw-r--r--src/test/regress/expected/triggers.out5
-rw-r--r--src/test/regress/sql/triggers.sql5
6 files changed, 167 insertions, 13 deletions
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 912144c43e3..34b91bb226c 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -7998,6 +7998,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
i_tgconstrrelid,
i_tgconstrrelname,
i_tgenabled,
+ i_tgisinternal,
i_tgdeferrable,
i_tginitdeferred,
i_tgdef;
@@ -8016,18 +8017,63 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
tbinfo->dobj.name);
resetPQExpBuffer(query);
- if (fout->remoteVersion >= 90000)
+ if (fout->remoteVersion >= 130000)
{
/*
* NB: think not to use pretty=true in pg_get_triggerdef. It
* could result in non-forward-compatible dumps of WHEN clauses
* due to under-parenthesization.
+ *
+ * NB: We need to see tgisinternal triggers in partitions, in case
+ * the tgenabled flag has been changed from the parent.
*/
appendPQExpBuffer(query,
- "SELECT tgname, "
- "tgfoid::pg_catalog.regproc AS tgfname, "
- "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
- "tgenabled, tableoid, oid "
+ "SELECT t.tgname, "
+ "t.tgfoid::pg_catalog.regproc AS tgfname, "
+ "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
+ "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
+ "FROM pg_catalog.pg_trigger t "
+ "LEFT JOIN pg_catalog.pg_trigger u ON u.oid = t.tgparentid "
+ "WHERE t.tgrelid = '%u'::pg_catalog.oid "
+ "AND (NOT t.tgisinternal OR t.tgenabled != u.tgenabled)",
+ tbinfo->dobj.catId.oid);
+ }
+ else if (fout->remoteVersion >= 110000)
+ {
+ /*
+ * NB: We need to see tgisinternal triggers in partitions, in case
+ * the tgenabled flag has been changed from the parent. No
+ * tgparentid in version 11-12, so we have to match them via
+ * pg_depend.
+ *
+ * See above about pretty=true in pg_get_triggerdef.
+ */
+ appendPQExpBuffer(query,
+ "SELECT t.tgname, "
+ "t.tgfoid::pg_catalog.regproc AS tgfname, "
+ "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
+ "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
+ "FROM pg_catalog.pg_trigger t "
+ "LEFT JOIN pg_catalog.pg_depend AS d ON "
+ " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
+ " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
+ " d.objid = t.oid "
+ "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
+ "WHERE t.tgrelid = '%u'::pg_catalog.oid "
+ "AND (NOT t.tgisinternal%s)",
+ tbinfo->dobj.catId.oid,
+ tbinfo->ispartition ?
+ " OR t.tgenabled != pt.tgenabled" : "");
+ }
+ else if (fout->remoteVersion >= 90000)
+ {
+ /* See above about pretty=true in pg_get_triggerdef */
+ appendPQExpBuffer(query,
+ "SELECT t.tgname, "
+ "t.tgfoid::pg_catalog.regproc AS tgfname, "
+ "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
+ "t.tgenabled, false as tgisinternal, "
+ "t.tableoid, t.oid "
"FROM pg_catalog.pg_trigger t "
"WHERE tgrelid = '%u'::pg_catalog.oid "
"AND NOT tgisinternal",
@@ -8042,6 +8088,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
"SELECT tgname, "
"tgfoid::pg_catalog.regproc AS tgfname, "
"tgtype, tgnargs, tgargs, tgenabled, "
+ "false as tgisinternal, "
"tgisconstraint, tgconstrname, tgdeferrable, "
"tgconstrrelid, tginitdeferred, tableoid, oid, "
"tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
@@ -8090,6 +8137,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
i_tgenabled = PQfnumber(res, "tgenabled");
+ i_tgisinternal = PQfnumber(res, "tgisinternal");
i_tgdeferrable = PQfnumber(res, "tgdeferrable");
i_tginitdeferred = PQfnumber(res, "tginitdeferred");
i_tgdef = PQfnumber(res, "tgdef");
@@ -8109,6 +8157,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
tginfo[j].tgtable = tbinfo;
tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
+ tginfo[j].tgisinternal = *(PQgetvalue(res, j, i_tgisinternal)) == 't';
if (i_tgdef >= 0)
{
tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
@@ -17799,7 +17848,40 @@ dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
"pg_catalog.pg_trigger", "TRIGGER",
trigidentity->data);
- if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
+ if (tginfo->tgisinternal)
+ {
+ /*
+ * Triggers marked internal only appear here because their 'tgenabled'
+ * flag differs from its parent's. The trigger is created already, so
+ * remove the CREATE and replace it with an ALTER. (Clear out the
+ * DROP query too, so that pg_dump --create does not cause errors.)
+ */
+ resetPQExpBuffer(query);
+ resetPQExpBuffer(delqry);
+ appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
+ tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
+ fmtQualifiedDumpable(tbinfo));
+ switch (tginfo->tgenabled)
+ {
+ case 'f':
+ case 'D':
+ appendPQExpBufferStr(query, "DISABLE");
+ break;
+ case 't':
+ case 'O':
+ appendPQExpBufferStr(query, "ENABLE");
+ break;
+ case 'R':
+ appendPQExpBufferStr(query, "ENABLE REPLICA");
+ break;
+ case 'A':
+ appendPQExpBufferStr(query, "ENABLE ALWAYS");
+ break;
+ }
+ appendPQExpBuffer(query, " TRIGGER %s;\n",
+ fmtId(tginfo->dobj.name));
+ }
+ else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
{
appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index efb8c30e719..f5e170e0dbc 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -425,6 +425,7 @@ typedef struct _triggerInfo
Oid tgconstrrelid;
char *tgconstrrelname;
char tgenabled;
+ bool tgisinternal;
bool tgdeferrable;
bool tginitdeferred;
char *tgdef;
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 448b1be26ce..c5d8915be85 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -2519,12 +2519,68 @@ my %tests = (
},
},
- # this shouldn't ever get emitted
- 'Creation of row-level trigger in partition' => {
+ 'Disabled trigger on partition is altered' => {
+ create_order => 93,
+ create_sql =>
+ 'CREATE TABLE dump_test_second_schema.measurement_y2006m3
+ PARTITION OF dump_test.measurement
+ FOR VALUES FROM (\'2006-03-01\') TO (\'2006-04-01\');
+ ALTER TABLE dump_test_second_schema.measurement_y2006m3 DISABLE TRIGGER test_trigger;
+ CREATE TABLE dump_test_second_schema.measurement_y2006m4
+ PARTITION OF dump_test.measurement
+ FOR VALUES FROM (\'2006-04-01\') TO (\'2006-05-01\');
+ ALTER TABLE dump_test_second_schema.measurement_y2006m4 ENABLE REPLICA TRIGGER test_trigger;
+ CREATE TABLE dump_test_second_schema.measurement_y2006m5
+ PARTITION OF dump_test.measurement
+ FOR VALUES FROM (\'2006-05-01\') TO (\'2006-06-01\');
+ ALTER TABLE dump_test_second_schema.measurement_y2006m5 ENABLE ALWAYS TRIGGER test_trigger;
+ ',
+ regexp => qr/^
+ \QALTER TABLE dump_test_second_schema.measurement_y2006m3 DISABLE TRIGGER test_trigger;\E
+ /xm,
+ like => {
+ %full_runs,
+ section_post_data => 1,
+ role => 1,
+ binary_upgrade => 1,
+ },
+ },
+
+ 'Replica trigger on partition is altered' => {
regexp => qr/^
- \QCREATE TRIGGER test_trigger AFTER INSERT ON dump_test_second_schema.measurement\E
+ \QALTER TABLE dump_test_second_schema.measurement_y2006m4 ENABLE REPLICA TRIGGER test_trigger;\E
/xm,
- like => {},
+ like => {
+ %full_runs,
+ section_post_data => 1,
+ role => 1,
+ binary_upgrade => 1,
+ },
+ },
+
+ 'Always trigger on partition is altered' => {
+ regexp => qr/^
+ \QALTER TABLE dump_test_second_schema.measurement_y2006m5 ENABLE ALWAYS TRIGGER test_trigger;\E
+ /xm,
+ like => {
+ %full_runs,
+ section_post_data => 1,
+ role => 1,
+ binary_upgrade => 1,
+ },
+ },
+
+ # We should never see the creation of a trigger on a partition
+ 'Disabled trigger on partition is not created' => {
+ regexp => qr/CREATE TRIGGER test_trigger.*ON dump_test_second_schema/,
+ like => {},
+ unlike => { %full_runs, %dump_test_schema_runs },
+ },
+
+ # Triggers on partitions should not be dropped individually
+ 'Triggers on partitions are not dropped' => {
+ regexp => qr/DROP TRIGGER test_trigger.*ON dump_test_second_schema/,
+ like => {}
},
'CREATE TABLE test_fourth_table_zero_col' => {
@@ -3177,9 +3233,12 @@ my %tests = (
},
'GRANT SELECT ON TABLE measurement_y2006m2' => {
- create_order => 92,
- create_sql => 'GRANT SELECT ON
- TABLE dump_test_second_schema.measurement_y2006m2
+ create_order => 94,
+ create_sql => 'GRANT SELECT ON TABLE
+ dump_test_second_schema.measurement_y2006m2,
+ dump_test_second_schema.measurement_y2006m3,
+ dump_test_second_schema.measurement_y2006m4,
+ dump_test_second_schema.measurement_y2006m5
TO regress_dump_test_role;',
regexp =>
qr/^\QGRANT SELECT ON TABLE dump_test_second_schema.measurement_y2006m2 TO regress_dump_test_role;\E/m,
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index d9ce961be2b..a64f96e102c 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -213,6 +213,8 @@ tmp|f
trigger_parted|t
trigger_parted_p1|t
trigger_parted_p1_1|t
+trigger_parted_p2|t
+trigger_parted_p2_2|t
varchar_tbl|f
view_base_table|t
-- restore normal output mode
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 42392f8f41d..5254447cf8e 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -3346,6 +3346,11 @@ create trigger aft_row after insert or update on trigger_parted
create table trigger_parted_p1 partition of trigger_parted for values in (1)
partition by list (a);
create table trigger_parted_p1_1 partition of trigger_parted_p1 for values in (1);
+create table trigger_parted_p2 partition of trigger_parted for values in (2)
+ partition by list (a);
+create table trigger_parted_p2_2 partition of trigger_parted_p2 for values in (2);
+alter table only trigger_parted_p2 disable trigger aft_row;
+alter table trigger_parted_p2_2 enable always trigger aft_row;
-- verify transition table conversion slot's lifetime
-- https://postgr.es/m/[email protected]
create table convslot_test_parent (col1 text primary key);
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 0777c4f50f4..7b73ee20a1b 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -2502,6 +2502,11 @@ create trigger aft_row after insert or update on trigger_parted
create table trigger_parted_p1 partition of trigger_parted for values in (1)
partition by list (a);
create table trigger_parted_p1_1 partition of trigger_parted_p1 for values in (1);
+create table trigger_parted_p2 partition of trigger_parted for values in (2)
+ partition by list (a);
+create table trigger_parted_p2_2 partition of trigger_parted_p2 for values in (2);
+alter table only trigger_parted_p2 disable trigger aft_row;
+alter table trigger_parted_p2_2 enable always trigger aft_row;
-- verify transition table conversion slot's lifetime
-- https://postgr.es/m/[email protected]