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

Commit 62215de

Browse files
committed
Fix dumping of a materialized view that depends on a table's primary key.
It is possible for a view or materialized view to depend on a table's primary key, if the view query relies on functional dependency to abbreviate a GROUP BY list. This is problematic for pg_dump since we ordinarily want to dump view definitions in the pre-data section but indexes in post-data. pg_dump knows how to deal with this situation for regular views, by breaking the view's ON SELECT rule apart from the view proper. But it had not been taught what to do about materialized views, and in fact mistakenly dumped them as regular views in such cases, as seen in bug #9616 from Jesse Denardo. If we had CREATE OR REPLACE MATERIALIZED VIEW, we could fix this in a manner analogous to what's done for regular views; but we don't yet, and we'd not back-patch such a thing into 9.3 anyway. As a hopefully- temporary workaround, break the circularity by postponing the matview into post-data altogether when this case occurs.
1 parent 8f5578d commit 62215de

File tree

3 files changed

+67
-7
lines changed

3 files changed

+67
-7
lines changed

src/bin/pg_dump/pg_dump.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4796,6 +4796,8 @@ getTables(Archive *fout, int *numTables)
47964796
selectDumpableTable(&tblinfo[i]);
47974797
tblinfo[i].interesting = tblinfo[i].dobj.dump;
47984798

4799+
tblinfo[i].postponed_def = false; /* might get set during sort */
4800+
47994801
/*
48004802
* Read-lock target tables to make sure they aren't DROPPED or altered
48014803
* in schema before we get around to dumping them.
@@ -13611,7 +13613,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1361113613
(tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
1361213614
tbinfo->rolname,
1361313615
(strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13614-
reltypename, SECTION_PRE_DATA,
13616+
reltypename,
13617+
tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
1361513618
q->data, delq->data, NULL,
1361613619
NULL, 0,
1361713620
NULL, NULL);

src/bin/pg_dump/pg_dump.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ typedef struct _tableInfo
241241
char *reltablespace; /* relation tablespace */
242242
char *reloptions; /* options specified by WITH (...) */
243243
char *checkoption; /* WITH CHECK OPTION */
244-
char *toast_reloptions; /* ditto, for the TOAST table */
244+
char *toast_reloptions; /* WITH options for the TOAST table */
245245
bool hasindex; /* does it have any indexes? */
246246
bool hasrules; /* does it have any rules? */
247247
bool hastriggers; /* does it have any triggers? */
@@ -254,9 +254,10 @@ typedef struct _tableInfo
254254
/* these two are set only if table is a sequence owned by a column: */
255255
Oid owning_tab; /* OID of table owning sequence */
256256
int owning_col; /* attr # of column owning sequence */
257-
int relpages;
257+
int relpages; /* table's size in pages (from pg_class) */
258258

259259
bool interesting; /* true if need to collect more data */
260+
bool postponed_def; /* matview must be postponed into post-data */
260261

261262
/*
262263
* These fields are computed only if we decide the table is interesting

src/bin/pg_dump/pg_dump_sort.c

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
798798
* will be an implicit dependency in the other direction, we need to break
799799
* the loop. If there are no other objects in the loop then we can remove
800800
* the implicit dependency and leave the ON SELECT rule non-separate.
801+
* This applies to matviews, as well.
801802
*/
802803
static void
803804
repairViewRuleLoop(DumpableObject *viewobj,
@@ -814,7 +815,9 @@ repairViewRuleLoop(DumpableObject *viewobj,
814815
* Because findLoop() finds shorter cycles before longer ones, it's likely
815816
* that we will have previously fired repairViewRuleLoop() and removed the
816817
* rule's dependency on the view. Put it back to ensure the rule won't be
817-
* emitted before the view...
818+
* emitted before the view.
819+
*
820+
* Note: this approach does *not* work for matviews, at the moment.
818821
*/
819822
static void
820823
repairViewRuleMultiLoop(DumpableObject *viewobj,
@@ -841,6 +844,30 @@ repairViewRuleMultiLoop(DumpableObject *viewobj,
841844
addObjectDependency(ruleobj, postDataBoundId);
842845
}
843846

847+
/*
848+
* If a matview is involved in a multi-object loop, we can't currently fix
849+
* that by splitting off the rule. As a stopgap, we try to fix it by
850+
* dropping the constraint that the matview be dumped in the pre-data section.
851+
* This is sufficient to handle cases where a matview depends on some unique
852+
* index, as can happen if it has a GROUP BY for example.
853+
*
854+
* Note that the "next object" is not necessarily the matview itself;
855+
* it could be the matview's rowtype, for example. We may come through here
856+
* several times while removing all the pre-data linkages.
857+
*/
858+
static void
859+
repairMatViewBoundaryMultiLoop(DumpableObject *matviewobj,
860+
DumpableObject *boundaryobj,
861+
DumpableObject *nextobj)
862+
{
863+
TableInfo *matviewinfo = (TableInfo *) matviewobj;
864+
865+
/* remove boundary's dependency on object after it in loop */
866+
removeObjectDependency(boundaryobj, nextobj->dumpId);
867+
/* mark matview as postponed into post-data section */
868+
matviewinfo->postponed_def = true;
869+
}
870+
844871
/*
845872
* Because we make tables depend on their CHECK constraints, while there
846873
* will be an automatic dependency in the other direction, we need to break
@@ -956,10 +983,12 @@ repairDependencyLoop(DumpableObject **loop,
956983
return;
957984
}
958985

959-
/* View and its ON SELECT rule */
986+
/* View (including matview) and its ON SELECT rule */
960987
if (nLoop == 2 &&
961988
loop[0]->objType == DO_TABLE &&
962989
loop[1]->objType == DO_RULE &&
990+
(((TableInfo *) loop[0])->relkind == 'v' || /* RELKIND_VIEW */
991+
((TableInfo *) loop[0])->relkind == 'm') && /* RELKIND_MATVIEW */
963992
((RuleInfo *) loop[1])->ev_type == '1' &&
964993
((RuleInfo *) loop[1])->is_instead &&
965994
((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
@@ -970,6 +999,8 @@ repairDependencyLoop(DumpableObject **loop,
970999
if (nLoop == 2 &&
9711000
loop[1]->objType == DO_TABLE &&
9721001
loop[0]->objType == DO_RULE &&
1002+
(((TableInfo *) loop[1])->relkind == 'v' || /* RELKIND_VIEW */
1003+
((TableInfo *) loop[1])->relkind == 'm') && /* RELKIND_MATVIEW */
9731004
((RuleInfo *) loop[0])->ev_type == '1' &&
9741005
((RuleInfo *) loop[0])->is_instead &&
9751006
((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
@@ -978,12 +1009,13 @@ repairDependencyLoop(DumpableObject **loop,
9781009
return;
9791010
}
9801011

981-
/* Indirect loop involving view and ON SELECT rule */
1012+
/* Indirect loop involving view (but not matview) and ON SELECT rule */
9821013
if (nLoop > 2)
9831014
{
9841015
for (i = 0; i < nLoop; i++)
9851016
{
986-
if (loop[i]->objType == DO_TABLE)
1017+
if (loop[i]->objType == DO_TABLE &&
1018+
((TableInfo *) loop[i])->relkind == 'v') /* RELKIND_VIEW */
9871019
{
9881020
for (j = 0; j < nLoop; j++)
9891021
{
@@ -1000,6 +1032,30 @@ repairDependencyLoop(DumpableObject **loop,
10001032
}
10011033
}
10021034

1035+
/* Indirect loop involving matview and data boundary */
1036+
if (nLoop > 2)
1037+
{
1038+
for (i = 0; i < nLoop; i++)
1039+
{
1040+
if (loop[i]->objType == DO_TABLE &&
1041+
((TableInfo *) loop[i])->relkind == 'm') /* RELKIND_MATVIEW */
1042+
{
1043+
for (j = 0; j < nLoop; j++)
1044+
{
1045+
if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
1046+
{
1047+
DumpableObject *nextobj;
1048+
1049+
nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
1050+
repairMatViewBoundaryMultiLoop(loop[i], loop[j],
1051+
nextobj);
1052+
return;
1053+
}
1054+
}
1055+
}
1056+
}
1057+
}
1058+
10031059
/* Table and CHECK constraint */
10041060
if (nLoop == 2 &&
10051061
loop[0]->objType == DO_TABLE &&

0 commit comments

Comments
 (0)