]> granicus.if.org Git - postgresql/commitdiff
In pg_dump, ensure that view triggers are processed after view rules.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 4 Feb 2016 05:26:10 +0000 (00:26 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 4 Feb 2016 05:26:10 +0000 (00:26 -0500)
If a view is split into CREATE TABLE + CREATE RULE to break a circular
dependency, then any triggers on the view must be dumped/reloaded after
the CREATE RULE; else the backend may reject the CREATE TRIGGER because
it's the wrong type of trigger for a plain table.  This works all right
in plain dump/restore because of pg_dump's sorting heuristic that places
triggers after rules.  However, when using parallel restore, the ordering
must be enforced by a dependency --- and we didn't have one.

Fixing this is a mere matter of adding an addObjectDependency() call,
except that we need to be able to find all the triggers belonging to the
view relation, and there was no easy way to do that.  Add fields to
pg_dump's TableInfo struct to remember where the associated TriggerInfo
struct(s) are.

Per bug report from Dennis Kögel.  The failure can be exhibited at least
as far back as 9.1, so back-patch to all supported branches.

src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/pg_dump_sort.c

index 4f1a5caee4d569f772eb7a07e4d6a9f9881b701c..662d43a5798e608b2d205bf3b1443efdfc42d080 100644 (file)
@@ -5346,6 +5346,9 @@ getTriggers(TableInfo tblinfo[], int numTables)
 
                tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
 
+               tbinfo->numTriggers = ntups;
+               tbinfo->triggers = tginfo;
+
                for (j = 0; j < ntups; j++)
                {
                        tginfo[j].dobj.objType = DO_TRIGGER;
index 0bd291456b4c1a4fc8ad10a4798beb65443c9a1a..d12680e9f0582b0ceea23643ba3f85c40f910d57 100644 (file)
@@ -288,6 +288,8 @@ typedef struct _tableInfo
        int                     numParents;             /* number of (immediate) parent tables */
        struct _tableInfo **parents;    /* TableInfos of immediate parents */
        struct _tableDataInfo *dataObj;         /* TableDataInfo, if dumping its data */
+       int                     numTriggers;    /* number of triggers for table */
+       struct _triggerInfo *triggers;          /* array of TriggerInfo structs */
 } TableInfo;
 
 typedef struct _attrDefInfo
index a9d44897c6e9149feb040ec79e1c00edfe638d26..0c5ef4a27020b5926ce8a782c43575997628baa4 100644 (file)
@@ -756,16 +756,23 @@ static void
 repairViewRuleMultiLoop(DumpableObject *viewobj,
                                                DumpableObject *ruleobj)
 {
+       TableInfo  *viewinfo = (TableInfo *) viewobj;
+       RuleInfo   *ruleinfo = (RuleInfo *) ruleobj;
+       int                     i;
+
        /* remove view's dependency on rule */
        removeObjectDependency(viewobj, ruleobj->dumpId);
        /* pretend view is a plain table and dump it that way */
-       ((TableInfo *) viewobj)->relkind = 'r';         /* RELKIND_RELATION */
+       viewinfo->relkind = 'r';        /* RELKIND_RELATION */
        /* mark rule as needing its own dump */
-       ((RuleInfo *) ruleobj)->separate = true;
+       ruleinfo->separate = true;
        /* put back rule's dependency on view */
        addObjectDependency(ruleobj, viewobj->dumpId);
        /* now that rule is separate, it must be post-data */
        addObjectDependency(ruleobj, postDataBoundId);
+       /* also, any triggers on the view must be dumped after the rule */
+       for (i = 0; i < viewinfo->numTriggers; i++)
+               addObjectDependency(&(viewinfo->triggers[i].dobj), ruleobj->dumpId);
 }
 
 /*