Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitccfc3cb

Browse files
Fix pg_dump for disabled triggers on partitioned tables
pg_dump failed to preserve the 'enabled' flag (which can be not onlydisabled, but also REPLICA or ALWAYS) for partitions which had itchanged from their respective parents. Attempt to handle that byincluding a definition for such triggers in the dump, but replace thestandard CREATE TRIGGER line with an ALTER TRIGGER line.Backpatch to 11, where these triggers can exist. In branches 11 and 12,pick up a few test lines from commitb9b408c to verify thatpg_upgrade is okay with these arrangements.Co-authored-by: Justin Pryzby <pryzby@telsasoft.com>Co-authored-by: Álvaro Herrera <alvherre@alvh.no-ip.org>Discussion:https://postgr.es/m/20200930223450.GA14848@telsasoft.com
1 parentfed35bd commitccfc3cb

File tree

6 files changed

+189
-13
lines changed

6 files changed

+189
-13
lines changed

‎src/bin/pg_dump/pg_dump.c

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7570,6 +7570,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
75707570
i_tgconstrrelid,
75717571
i_tgconstrrelname,
75727572
i_tgenabled,
7573+
i_tgisinternal,
75737574
i_tgdeferrable,
75747575
i_tginitdeferred,
75757576
i_tgdef;
@@ -7589,18 +7590,63 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
75897590
tbinfo->dobj.name);
75907591

75917592
resetPQExpBuffer(query);
7592-
if (fout->remoteVersion >=90000)
7593+
if (fout->remoteVersion >=130000)
75937594
{
75947595
/*
75957596
* NB: think not to use pretty=true in pg_get_triggerdef. It
75967597
* could result in non-forward-compatible dumps of WHEN clauses
75977598
* due to under-parenthesization.
7599+
*
7600+
* NB: We need to see tgisinternal triggers in partitions, in case
7601+
* the tgenabled flag has been changed from the parent.
75987602
*/
75997603
appendPQExpBuffer(query,
7600-
"SELECT tgname, "
7601-
"tgfoid::pg_catalog.regproc AS tgfname, "
7602-
"pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7603-
"tgenabled, tableoid, oid "
7604+
"SELECT t.tgname, "
7605+
"t.tgfoid::pg_catalog.regproc AS tgfname, "
7606+
"pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7607+
"t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
7608+
"FROM pg_catalog.pg_trigger t "
7609+
"LEFT JOIN pg_catalog.pg_trigger u ON u.oid = t.tgparentid "
7610+
"WHERE t.tgrelid = '%u'::pg_catalog.oid "
7611+
"AND (NOT t.tgisinternal OR t.tgenabled != u.tgenabled)",
7612+
tbinfo->dobj.catId.oid);
7613+
}
7614+
else if (fout->remoteVersion >= 110000)
7615+
{
7616+
/*
7617+
* NB: We need to see tgisinternal triggers in partitions, in case
7618+
* the tgenabled flag has been changed from the parent. No
7619+
* tgparentid in version 11-12, so we have to match them via
7620+
* pg_depend.
7621+
*
7622+
* See above about pretty=true in pg_get_triggerdef.
7623+
*/
7624+
appendPQExpBuffer(query,
7625+
"SELECT t.tgname, "
7626+
"t.tgfoid::pg_catalog.regproc AS tgfname, "
7627+
"pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7628+
"t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
7629+
"FROM pg_catalog.pg_trigger t "
7630+
"LEFT JOIN pg_catalog.pg_depend AS d ON "
7631+
" d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
7632+
" d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
7633+
" d.objid = t.oid "
7634+
"LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
7635+
"WHERE t.tgrelid = '%u'::pg_catalog.oid "
7636+
"AND (NOT t.tgisinternal%s)",
7637+
tbinfo->dobj.catId.oid,
7638+
tbinfo->ispartition ?
7639+
" OR t.tgenabled != pt.tgenabled" : "");
7640+
}
7641+
else if (fout->remoteVersion >= 90000)
7642+
{
7643+
/* See above about pretty=true in pg_get_triggerdef */
7644+
appendPQExpBuffer(query,
7645+
"SELECT t.tgname, "
7646+
"t.tgfoid::pg_catalog.regproc AS tgfname, "
7647+
"pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7648+
"t.tgenabled, false as tgisinternal, "
7649+
"t.tableoid, t.oid "
76047650
"FROM pg_catalog.pg_trigger t "
76057651
"WHERE tgrelid = '%u'::pg_catalog.oid "
76067652
"AND NOT tgisinternal",
@@ -7615,6 +7661,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
76157661
"SELECT tgname, "
76167662
"tgfoid::pg_catalog.regproc AS tgfname, "
76177663
"tgtype, tgnargs, tgargs, tgenabled, "
7664+
"false as tgisinternal, "
76187665
"tgisconstraint, tgconstrname, tgdeferrable, "
76197666
"tgconstrrelid, tginitdeferred, tableoid, oid, "
76207667
"tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
@@ -7663,6 +7710,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
76637710
i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
76647711
i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
76657712
i_tgenabled = PQfnumber(res, "tgenabled");
7713+
i_tgisinternal = PQfnumber(res, "tgisinternal");
76667714
i_tgdeferrable = PQfnumber(res, "tgdeferrable");
76677715
i_tginitdeferred = PQfnumber(res, "tginitdeferred");
76687716
i_tgdef = PQfnumber(res, "tgdef");
@@ -7682,6 +7730,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
76827730
tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
76837731
tginfo[j].tgtable = tbinfo;
76847732
tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7733+
tginfo[j].tgisinternal = *(PQgetvalue(res, j, i_tgisinternal)) == 't';
76857734
if (i_tgdef >= 0)
76867735
{
76877736
tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
@@ -17419,7 +17468,40 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
1741917468
"pg_catalog.pg_trigger", "TRIGGER",
1742017469
trigidentity->data);
1742117470

17422-
if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17471+
if (tginfo->tgisinternal)
17472+
{
17473+
/*
17474+
* Triggers marked internal only appear here because their 'tgenabled'
17475+
* flag differs from its parent's. The trigger is created already, so
17476+
* remove the CREATE and replace it with an ALTER. (Clear out the
17477+
* DROP query too, so that pg_dump --create does not cause errors.)
17478+
*/
17479+
resetPQExpBuffer(query);
17480+
resetPQExpBuffer(delqry);
17481+
appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17482+
tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17483+
fmtQualifiedDumpable(tbinfo));
17484+
switch (tginfo->tgenabled)
17485+
{
17486+
case 'f':
17487+
case 'D':
17488+
appendPQExpBufferStr(query, "DISABLE");
17489+
break;
17490+
case 't':
17491+
case 'O':
17492+
appendPQExpBufferStr(query, "ENABLE");
17493+
break;
17494+
case 'R':
17495+
appendPQExpBufferStr(query, "ENABLE REPLICA");
17496+
break;
17497+
case 'A':
17498+
appendPQExpBufferStr(query, "ENABLE ALWAYS");
17499+
break;
17500+
}
17501+
appendPQExpBuffer(query, " TRIGGER %s;\n",
17502+
fmtId(tginfo->dobj.name));
17503+
}
17504+
else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
1742317505
{
1742417506
appendPQExpBuffer(query, "\nALTER TABLE %s ",
1742517507
fmtQualifiedDumpable(tbinfo));

‎src/bin/pg_dump/pg_dump.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ typedef struct _triggerInfo
413413
Oidtgconstrrelid;
414414
char*tgconstrrelname;
415415
chartgenabled;
416+
booltgisinternal;
416417
booltgdeferrable;
417418
booltginitdeferred;
418419
char*tgdef;

‎src/bin/pg_dump/t/002_pg_dump.pl

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,12 +2388,68 @@
23882388
},
23892389
},
23902390
2391-
# this shouldn't ever get emitted
2392-
'Creation of row-level trigger in partition' => {
2391+
'Disabled trigger on partition is altered' => {
2392+
create_order => 93,
2393+
create_sql =>
2394+
'CREATE TABLE dump_test_second_schema.measurement_y2006m3
2395+
PARTITION OF dump_test.measurement
2396+
FOR VALUES FROM (\'2006-03-01\') TO (\'2006-04-01\');
2397+
ALTER TABLE dump_test_second_schema.measurement_y2006m3 DISABLE TRIGGER test_trigger;
2398+
CREATE TABLE dump_test_second_schema.measurement_y2006m4
2399+
PARTITION OF dump_test.measurement
2400+
FOR VALUES FROM (\'2006-04-01\') TO (\'2006-05-01\');
2401+
ALTER TABLE dump_test_second_schema.measurement_y2006m4 ENABLE REPLICA TRIGGER test_trigger;
2402+
CREATE TABLE dump_test_second_schema.measurement_y2006m5
2403+
PARTITION OF dump_test.measurement
2404+
FOR VALUES FROM (\'2006-05-01\') TO (\'2006-06-01\');
2405+
ALTER TABLE dump_test_second_schema.measurement_y2006m5 ENABLE ALWAYS TRIGGER test_trigger;
2406+
',
2407+
regexp => qr/^
2408+
\QALTER TABLE dump_test_second_schema.measurement_y2006m3 DISABLE TRIGGER test_trigger;\E
2409+
/xm,
2410+
like => {
2411+
%full_runs,
2412+
section_post_data => 1,
2413+
role => 1,
2414+
binary_upgrade => 1,
2415+
},
2416+
},
2417+
2418+
'Replica trigger on partition is altered' => {
23932419
regexp => qr/^
2394-
\QCREATE TRIGGER test_trigger AFTER INSERT ON dump_test_second_schema.measurement\E
2420+
\QALTER TABLE dump_test_second_schema.measurement_y2006m4 ENABLE REPLICA TRIGGER test_trigger;\E
23952421
/xm,
2396-
like => {},
2422+
like => {
2423+
%full_runs,
2424+
section_post_data => 1,
2425+
role => 1,
2426+
binary_upgrade => 1,
2427+
},
2428+
},
2429+
2430+
'Always trigger on partition is altered' => {
2431+
regexp => qr/^
2432+
\QALTER TABLE dump_test_second_schema.measurement_y2006m5 ENABLE ALWAYS TRIGGER test_trigger;\E
2433+
/xm,
2434+
like => {
2435+
%full_runs,
2436+
section_post_data => 1,
2437+
role => 1,
2438+
binary_upgrade => 1,
2439+
},
2440+
},
2441+
2442+
# We should never see the creation of a trigger on a partition
2443+
'Disabled trigger on partition is not created' => {
2444+
regexp => qr/CREATE TRIGGER test_trigger.*ON dump_test_second_schema/,
2445+
like => {},
2446+
unlike => {%full_runs,%dump_test_schema_runs },
2447+
},
2448+
2449+
# Triggers on partitions should not be dropped individually
2450+
'Triggers on partitions are not dropped' => {
2451+
regexp => qr/DROP TRIGGER test_trigger.*ON dump_test_second_schema/,
2452+
like => {}
23972453
},
23982454
23992455
'CREATE TABLE test_fourth_table_zero_col' => {
@@ -3032,9 +3088,12 @@
30323088
},
30333089
30343090
'GRANT SELECT ON TABLE measurement_y2006m2' => {
3035-
create_order => 92,
3036-
create_sql => 'GRANT SELECT ON
3037-
TABLE dump_test_second_schema.measurement_y2006m2
3091+
create_order => 94,
3092+
create_sql => 'GRANT SELECT ON TABLE
3093+
dump_test_second_schema.measurement_y2006m2,
3094+
dump_test_second_schema.measurement_y2006m3,
3095+
dump_test_second_schema.measurement_y2006m4,
3096+
dump_test_second_schema.measurement_y2006m5
30383097
TO regress_dump_test_role;',
30393098
regexp =>
30403099
qr/^GRANT SELECT ON TABLE dump_test_second_schema.measurement_y2006m2 TO regress_dump_test_role;/m,

‎src/test/regress/expected/sanity_check.out

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ time_tbl|f
206206
timestamp_tbl|f
207207
timestamptz_tbl|f
208208
timetz_tbl|f
209+
trigger_parted|t
210+
trigger_parted_p1|t
211+
trigger_parted_p1_1|t
212+
trigger_parted_p2|t
213+
trigger_parted_p2_2|t
209214
varchar_tbl|f
210215
view_base_table|t
211216
-- restore normal output mode

‎src/test/regress/expected/triggers.out

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3083,6 +3083,20 @@ drop table self_ref;
30833083
drop function dump_insert();
30843084
drop function dump_update();
30853085
drop function dump_delete();
3086+
-- Leave around some objects for other tests
3087+
create table trigger_parted (a int primary key) partition by list (a);
3088+
create function trigger_parted_trigfunc() returns trigger language plpgsql as
3089+
$$ begin end; $$;
3090+
create trigger aft_row after insert or update on trigger_parted
3091+
for each row execute function trigger_parted_trigfunc();
3092+
create table trigger_parted_p1 partition of trigger_parted for values in (1)
3093+
partition by list (a);
3094+
create table trigger_parted_p1_1 partition of trigger_parted_p1 for values in (1);
3095+
create table trigger_parted_p2 partition of trigger_parted for values in (2)
3096+
partition by list (a);
3097+
create table trigger_parted_p2_2 partition of trigger_parted_p2 for values in (2);
3098+
alter table only trigger_parted_p2 disable trigger aft_row;
3099+
alter table trigger_parted_p2_2 enable always trigger aft_row;
30863100
-- verify transition table conversion slot's lifetime
30873101
-- https://postgr.es/m/39a71864-b120-5a5c-8cc5-c632b6f16761@amazon.com
30883102
create table convslot_test_parent (col1 text primary key);

‎src/test/regress/sql/triggers.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,21 @@ drop function dump_insert();
23072307
dropfunction dump_update();
23082308
dropfunction dump_delete();
23092309

2310+
-- Leave around some objects for other tests
2311+
createtabletrigger_parted (aintprimary key) partition by list (a);
2312+
createfunctiontrigger_parted_trigfunc() returns trigger language plpgsqlas
2313+
$$begin end; $$;
2314+
createtriggeraft_row after insertorupdateon trigger_parted
2315+
for each row execute function trigger_parted_trigfunc();
2316+
createtabletrigger_parted_p1 partition of trigger_parted forvaluesin (1)
2317+
partition by list (a);
2318+
createtabletrigger_parted_p1_1 partition of trigger_parted_p1 forvaluesin (1);
2319+
createtabletrigger_parted_p2 partition of trigger_parted forvaluesin (2)
2320+
partition by list (a);
2321+
createtabletrigger_parted_p2_2 partition of trigger_parted_p2 forvaluesin (2);
2322+
altertable only trigger_parted_p2 disable trigger aft_row;
2323+
altertable trigger_parted_p2_2 enable always trigger aft_row;
2324+
23102325
-- verify transition table conversion slot's lifetime
23112326
-- https://postgr.es/m/39a71864-b120-5a5c-8cc5-c632b6f16761@amazon.com
23122327
createtableconvslot_test_parent (col1textprimary key);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp