mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
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
This commit is contained in:
parent
b3f32a6c31
commit
0161074786
@ -6085,6 +6085,7 @@ getAggregates(Archive *fout, int *numAggs)
|
||||
agginfo[i].aggfn.argtypes,
|
||||
agginfo[i].aggfn.nargs);
|
||||
}
|
||||
agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
|
||||
@ -6283,6 +6284,7 @@ getFuncs(Archive *fout, int *numFuncs)
|
||||
parseOidArray(PQgetvalue(res, i, i_proargtypes),
|
||||
finfo[i].argtypes, finfo[i].nargs);
|
||||
}
|
||||
finfo[i].postponed_def = false; /* might get set during sort */
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(finfo[i].dobj), fout);
|
||||
@ -12168,7 +12170,8 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
|
||||
.namespace = finfo->dobj.namespace->dobj.name,
|
||||
.owner = finfo->rolname,
|
||||
.description = keyword,
|
||||
.section = SECTION_PRE_DATA,
|
||||
.section = finfo->postponed_def ?
|
||||
SECTION_POST_DATA : SECTION_PRE_DATA,
|
||||
.createStmt = q->data,
|
||||
.dropStmt = delqry->data));
|
||||
|
||||
|
@ -227,6 +227,7 @@ typedef struct _funcInfo
|
||||
int nargs;
|
||||
Oid *argtypes;
|
||||
Oid prorettype;
|
||||
bool postponed_def; /* function must be postponed into post-data */
|
||||
} FuncInfo;
|
||||
|
||||
/* AggInfo is a superset of FuncInfo */
|
||||
|
@ -868,6 +868,28 @@ repairMatViewBoundaryMultiLoop(DumpableObject *boundaryobj,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If a function is involved in a multi-object loop, we can't currently fix
|
||||
* that by splitting it into two DumpableObjects. As a stopgap, we try to fix
|
||||
* it by dropping the constraint that the function be dumped in the pre-data
|
||||
* section. This is sufficient to handle cases where a function depends on
|
||||
* some unique index, as can happen if it has a GROUP BY for example.
|
||||
*/
|
||||
static void
|
||||
repairFunctionBoundaryMultiLoop(DumpableObject *boundaryobj,
|
||||
DumpableObject *nextobj)
|
||||
{
|
||||
/* remove boundary's dependency on object after it in loop */
|
||||
removeObjectDependency(boundaryobj, nextobj->dumpId);
|
||||
/* if that object is a function, mark it as postponed into post-data */
|
||||
if (nextobj->objType == DO_FUNC)
|
||||
{
|
||||
FuncInfo *nextinfo = (FuncInfo *) nextobj;
|
||||
|
||||
nextinfo->postponed_def = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we make tables depend on their CHECK constraints, while there
|
||||
* will be an automatic dependency in the other direction, we need to break
|
||||
@ -1062,6 +1084,28 @@ repairDependencyLoop(DumpableObject **loop,
|
||||
}
|
||||
}
|
||||
|
||||
/* Indirect loop involving function and data boundary */
|
||||
if (nLoop > 2)
|
||||
{
|
||||
for (i = 0; i < nLoop; i++)
|
||||
{
|
||||
if (loop[i]->objType == DO_FUNC)
|
||||
{
|
||||
for (j = 0; j < nLoop; j++)
|
||||
{
|
||||
if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
|
||||
{
|
||||
DumpableObject *nextobj;
|
||||
|
||||
nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
|
||||
repairFunctionBoundaryMultiLoop(loop[j], nextobj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Table and CHECK constraint */
|
||||
if (nLoop == 2 &&
|
||||
loop[0]->objType == DO_TABLE &&
|
||||
|
@ -2490,6 +2490,27 @@ my %tests = (
|
||||
},
|
||||
},
|
||||
|
||||
'Check ordering of a function that depends on a primary key' => {
|
||||
create_order => 41,
|
||||
create_sql => '
|
||||
CREATE TABLE dump_test.ordering_table (id int primary key, data int);
|
||||
CREATE FUNCTION dump_test.ordering_func ()
|
||||
RETURNS SETOF dump_test.ordering_table
|
||||
LANGUAGE sql BEGIN ATOMIC
|
||||
SELECT * FROM dump_test.ordering_table GROUP BY id; END;',
|
||||
regexp => qr/^
|
||||
\QALTER TABLE ONLY dump_test.ordering_table\E
|
||||
\n\s+\QADD CONSTRAINT ordering_table_pkey PRIMARY KEY (id);\E
|
||||
.*^
|
||||
\QCREATE FUNCTION dump_test.ordering_func\E/xms,
|
||||
like =>
|
||||
{ %full_runs, %dump_test_schema_runs, section_post_data => 1, },
|
||||
unlike => {
|
||||
exclude_dump_test_schema => 1,
|
||||
only_dump_measurement => 1,
|
||||
},
|
||||
},
|
||||
|
||||
'CREATE PROCEDURE dump_test.ptest1' => {
|
||||
create_order => 41,
|
||||
create_sql => 'CREATE PROCEDURE dump_test.ptest1(a int)
|
||||
@ -2732,6 +2753,25 @@ my %tests = (
|
||||
},
|
||||
},
|
||||
|
||||
'Check ordering of a matview that depends on a primary key' => {
|
||||
create_order => 42,
|
||||
create_sql => '
|
||||
CREATE MATERIALIZED VIEW dump_test.ordering_view AS
|
||||
SELECT * FROM dump_test.ordering_table GROUP BY id;',
|
||||
regexp => qr/^
|
||||
\QALTER TABLE ONLY dump_test.ordering_table\E
|
||||
\n\s+\QADD CONSTRAINT ordering_table_pkey PRIMARY KEY (id);\E
|
||||
.*^
|
||||
\QCREATE MATERIALIZED VIEW dump_test.ordering_view AS\E
|
||||
\n\s+\QSELECT id,\E/xms,
|
||||
like =>
|
||||
{ %full_runs, %dump_test_schema_runs, section_post_data => 1, },
|
||||
unlike => {
|
||||
exclude_dump_test_schema => 1,
|
||||
only_dump_measurement => 1,
|
||||
},
|
||||
},
|
||||
|
||||
'CREATE POLICY p1 ON test_table' => {
|
||||
create_order => 22,
|
||||
create_sql => 'CREATE POLICY p1 ON dump_test.test_table
|
||||
|
Loading…
x
Reference in New Issue
Block a user