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

Lines changed: 4 additions & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 44 additions & 0 deletions
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

Lines changed: 40 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy