Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0161074

Browse files
committed
Fix pg_dump's failure to honor dependencies of SQL functions.
A new-style SQL function can contain a parse-time dependency on a unique index, much as views and matviews can (such cases arise from GROUP BY and ON CONFLICT clauses, for example). To dump and restore such a function successfully, pg_dump must postpone the function until after the unique index is created, which will happen in the post-data part of the dump. Therefore we have to remove the normal constraint that functions are dumped in pre-data. Add code similar to the existing logic that handles this for matviews. I added test cases for both as well, since code coverage tests showed that we weren't testing the matview logic. Per report from Sami Imseih. Back-patch to v14 where new-style SQL functions came in. Discussion: https://postgr.es/m/2C1933AB-C2F8-499B-9D18-4AC1882256A0@amazon.com
1 parent b3f32a6 commit 0161074

File tree

4 files changed

+89
-1
lines changed

4 files changed

+89
-1
lines changed

src/bin/pg_dump/pg_dump.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -6085,6 +6085,7 @@ getAggregates(Archive *fout, int *numAggs)
60856085
agginfo[i].aggfn.argtypes,
60866086
agginfo[i].aggfn.nargs);
60876087
}
6088+
agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
60886089

60896090
/* Decide whether we want to dump it */
60906091
selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
@@ -6283,6 +6284,7 @@ getFuncs(Archive *fout, int *numFuncs)
62836284
parseOidArray(PQgetvalue(res, i, i_proargtypes),
62846285
finfo[i].argtypes, finfo[i].nargs);
62856286
}
6287+
finfo[i].postponed_def = false; /* might get set during sort */
62866288

62876289
/* Decide whether we want to dump it */
62886290
selectDumpableObject(&(finfo[i].dobj), fout);
@@ -12168,7 +12170,8 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
1216812170
.namespace = finfo->dobj.namespace->dobj.name,
1216912171
.owner = finfo->rolname,
1217012172
.description = keyword,
12171-
.section = SECTION_PRE_DATA,
12173+
.section = finfo->postponed_def ?
12174+
SECTION_POST_DATA : SECTION_PRE_DATA,
1217212175
.createStmt = q->data,
1217312176
.dropStmt = delqry->data));
1217412177

src/bin/pg_dump/pg_dump.h

+1
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ typedef struct _funcInfo
227227
int nargs;
228228
Oid *argtypes;
229229
Oid prorettype;
230+
bool postponed_def; /* function must be postponed into post-data */
230231
} FuncInfo;
231232

232233
/* AggInfo is a superset of FuncInfo */

src/bin/pg_dump/pg_dump_sort.c

+44
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,28 @@ repairMatViewBoundaryMultiLoop(DumpableObject *boundaryobj,
868868
}
869869
}
870870

871+
/*
872+
* If a function is involved in a multi-object loop, we can't currently fix
873+
* that by splitting it into two DumpableObjects. As a stopgap, we try to fix
874+
* it by dropping the constraint that the function be dumped in the pre-data
875+
* section. This is sufficient to handle cases where a function depends on
876+
* some unique index, as can happen if it has a GROUP BY for example.
877+
*/
878+
static void
879+
repairFunctionBoundaryMultiLoop(DumpableObject *boundaryobj,
880+
DumpableObject *nextobj)
881+
{
882+
/* remove boundary's dependency on object after it in loop */
883+
removeObjectDependency(boundaryobj, nextobj->dumpId);
884+
/* if that object is a function, mark it as postponed into post-data */
885+
if (nextobj->objType == DO_FUNC)
886+
{
887+
FuncInfo *nextinfo = (FuncInfo *) nextobj;
888+
889+
nextinfo->postponed_def = true;
890+
}
891+
}
892+
871893
/*
872894
* Because we make tables depend on their CHECK constraints, while there
873895
* will be an automatic dependency in the other direction, we need to break
@@ -1062,6 +1084,28 @@ repairDependencyLoop(DumpableObject **loop,
10621084
}
10631085
}
10641086

1087+
/* Indirect loop involving function and data boundary */
1088+
if (nLoop > 2)
1089+
{
1090+
for (i = 0; i < nLoop; i++)
1091+
{
1092+
if (loop[i]->objType == DO_FUNC)
1093+
{
1094+
for (j = 0; j < nLoop; j++)
1095+
{
1096+
if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1097+
{
1098+
DumpableObject *nextobj;
1099+
1100+
nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1101+
repairFunctionBoundaryMultiLoop(loop[j], nextobj);
1102+
return;
1103+
}
1104+
}
1105+
}
1106+
}
1107+
}
1108+
10651109
/* Table and CHECK constraint */
10661110
if (nLoop == 2 &&
10671111
loop[0]->objType == DO_TABLE &&

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

+40
Original file line numberDiff line numberDiff line change
@@ -2490,6 +2490,27 @@
24902490
},
24912491
},
24922492
2493+
'Check ordering of a function that depends on a primary key' => {
2494+
create_order => 41,
2495+
create_sql => '
2496+
CREATE TABLE dump_test.ordering_table (id int primary key, data int);
2497+
CREATE FUNCTION dump_test.ordering_func ()
2498+
RETURNS SETOF dump_test.ordering_table
2499+
LANGUAGE sql BEGIN ATOMIC
2500+
SELECT * FROM dump_test.ordering_table GROUP BY id; END;',
2501+
regexp => qr/^
2502+
\QALTER TABLE ONLY dump_test.ordering_table\E
2503+
\n\s+\QADD CONSTRAINT ordering_table_pkey PRIMARY KEY (id);\E
2504+
.*^
2505+
\QCREATE FUNCTION dump_test.ordering_func\E/xms,
2506+
like =>
2507+
{ %full_runs, %dump_test_schema_runs, section_post_data => 1, },
2508+
unlike => {
2509+
exclude_dump_test_schema => 1,
2510+
only_dump_measurement => 1,
2511+
},
2512+
},
2513+
24932514
'CREATE PROCEDURE dump_test.ptest1' => {
24942515
create_order => 41,
24952516
create_sql => 'CREATE PROCEDURE dump_test.ptest1(a int)
@@ -2732,6 +2753,25 @@
27322753
},
27332754
},
27342755
2756+
'Check ordering of a matview that depends on a primary key' => {
2757+
create_order => 42,
2758+
create_sql => '
2759+
CREATE MATERIALIZED VIEW dump_test.ordering_view AS
2760+
SELECT * FROM dump_test.ordering_table GROUP BY id;',
2761+
regexp => qr/^
2762+
\QALTER TABLE ONLY dump_test.ordering_table\E
2763+
\n\s+\QADD CONSTRAINT ordering_table_pkey PRIMARY KEY (id);\E
2764+
.*^
2765+
\QCREATE MATERIALIZED VIEW dump_test.ordering_view AS\E
2766+
\n\s+\QSELECT id,\E/xms,
2767+
like =>
2768+
{ %full_runs, %dump_test_schema_runs, section_post_data => 1, },
2769+
unlike => {
2770+
exclude_dump_test_schema => 1,
2771+
only_dump_measurement => 1,
2772+
},
2773+
},
2774+
27352775
'CREATE POLICY p1 ON test_table' => {
27362776
create_order => 22,
27372777
create_sql => 'CREATE POLICY p1 ON dump_test.test_table

0 commit comments

Comments
 (0)