Commit 86a069bb authored by Tom Lane's avatar Tom Lane

Cope with circularities involving a view's ON SELECT rule. I originally

thought there couldn't be any, but the folly of this was exposed by an
example from andrew@supernews.com 5-Dec-2004.  The patch applies the
identical logic already used for table constraints and defaults to ON
SELECT rules, so I have reasonable confidence in it even though it might
look like complicated logic.
parent 94e46706
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.395 2004/12/14 21:35:20 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.396 2004/12/14 22:16:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3160,13 +3160,22 @@ getRules(int *numRules) ...@@ -3160,13 +3160,22 @@ getRules(int *numRules)
*/ */
if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW && if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead) ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
{
addObjectDependency(&ruleinfo[i].ruletable->dobj, addObjectDependency(&ruleinfo[i].ruletable->dobj,
ruleinfo[i].dobj.dumpId); ruleinfo[i].dobj.dumpId);
/* We'll merge the rule into CREATE VIEW, if possible */
ruleinfo[i].separate = false;
}
else else
{
addObjectDependency(&ruleinfo[i].dobj, addObjectDependency(&ruleinfo[i].dobj,
ruleinfo[i].ruletable->dobj.dumpId); ruleinfo[i].ruletable->dobj.dumpId);
ruleinfo[i].separate = true;
} }
} }
else
ruleinfo[i].separate = true;
}
PQclear(res); PQclear(res);
...@@ -7617,10 +7626,10 @@ dumpRule(Archive *fout, RuleInfo *rinfo) ...@@ -7617,10 +7626,10 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
return; return;
/* /*
* If it is an ON SELECT rule, we do not need to dump it because it * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
* will be handled via CREATE VIEW for the table. * we do not want to dump it as a separate object.
*/ */
if (rinfo->ev_type == '1' && rinfo->is_instead) if (!rinfo->separate)
return; return;
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.113 2004/11/05 19:16:19 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.114 2004/12/14 22:16:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -252,6 +252,8 @@ typedef struct _ruleInfo ...@@ -252,6 +252,8 @@ typedef struct _ruleInfo
TableInfo *ruletable; /* link to table the rule is for */ TableInfo *ruletable; /* link to table the rule is for */
char ev_type; char ev_type;
bool is_instead; bool is_instead;
bool separate; /* TRUE if must dump as separate item */
/* separate is always true for non-ON SELECT rules */
} RuleInfo; } RuleInfo;
typedef struct _triggerInfo typedef struct _triggerInfo
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.6 2004/08/29 05:06:53 momjian Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.7 2004/12/14 22:16:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -639,7 +639,8 @@ repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj) ...@@ -639,7 +639,8 @@ repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
/* /*
* Because we force a view to depend on its ON SELECT rule, while there * Because we force a view to depend on its ON SELECT rule, while there
* will be an implicit dependency in the other direction, we need to break * will be an implicit dependency in the other direction, we need to break
* the loop. We can always do this by removing the implicit dependency. * the loop. If there are no other objects in the loop then we can remove
* the implicit dependency and leave the ON SELECT rule non-separate.
*/ */
static void static void
repairViewRuleLoop(DumpableObject *viewobj, repairViewRuleLoop(DumpableObject *viewobj,
...@@ -649,6 +650,29 @@ repairViewRuleLoop(DumpableObject *viewobj, ...@@ -649,6 +650,29 @@ repairViewRuleLoop(DumpableObject *viewobj,
removeObjectDependency(ruleobj, viewobj->dumpId); removeObjectDependency(ruleobj, viewobj->dumpId);
} }
/*
* However, if there are other objects in the loop, we must break the loop
* by making the ON SELECT rule a separately-dumped object.
*
* Because findLoop() finds shorter cycles before longer ones, it's likely
* that we will have previously fired repairViewRuleLoop() and removed the
* rule's dependency on the view. Put it back to ensure the rule won't be
* emitted before the view...
*/
static void
repairViewRuleMultiLoop(DumpableObject *viewobj,
DumpableObject *ruleobj)
{
/* 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 */
/* mark rule as needing its own dump */
((RuleInfo *) ruleobj)->separate = true;
/* put back rule's dependency on view */
addObjectDependency(ruleobj, viewobj->dumpId);
}
/* /*
* Because we make tables depend on their CHECK constraints, while there * Because we make tables depend on their CHECK constraints, while there
* will be an automatic dependency in the other direction, we need to break * will be an automatic dependency in the other direction, we need to break
...@@ -765,7 +789,8 @@ repairDependencyLoop(DumpableObject **loop, ...@@ -765,7 +789,8 @@ repairDependencyLoop(DumpableObject **loop,
loop[0]->objType == DO_TABLE && loop[0]->objType == DO_TABLE &&
loop[1]->objType == DO_RULE && loop[1]->objType == DO_RULE &&
((RuleInfo *) loop[1])->ev_type == '1' && ((RuleInfo *) loop[1])->ev_type == '1' &&
((RuleInfo *) loop[1])->is_instead) ((RuleInfo *) loop[1])->is_instead &&
((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
{ {
repairViewRuleLoop(loop[0], loop[1]); repairViewRuleLoop(loop[0], loop[1]);
return; return;
...@@ -774,12 +799,35 @@ repairDependencyLoop(DumpableObject **loop, ...@@ -774,12 +799,35 @@ repairDependencyLoop(DumpableObject **loop,
loop[1]->objType == DO_TABLE && loop[1]->objType == DO_TABLE &&
loop[0]->objType == DO_RULE && loop[0]->objType == DO_RULE &&
((RuleInfo *) loop[0])->ev_type == '1' && ((RuleInfo *) loop[0])->ev_type == '1' &&
((RuleInfo *) loop[0])->is_instead) ((RuleInfo *) loop[0])->is_instead &&
((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
{ {
repairViewRuleLoop(loop[1], loop[0]); repairViewRuleLoop(loop[1], loop[0]);
return; return;
} }
/* Indirect loop involving view and ON SELECT rule */
if (nLoop > 2)
{
for (i = 0; i < nLoop; i++)
{
if (loop[i]->objType == DO_TABLE)
{
for (j = 0; j < nLoop; j++)
{
if (loop[j]->objType == DO_RULE &&
((RuleInfo *) loop[j])->ev_type == '1' &&
((RuleInfo *) loop[j])->is_instead &&
((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
{
repairViewRuleMultiLoop(loop[i], loop[j]);
return;
}
}
}
}
}
/* Table and CHECK constraint */ /* Table and CHECK constraint */
if (nLoop == 2 && if (nLoop == 2 &&
loop[0]->objType == DO_TABLE && loop[0]->objType == DO_TABLE &&
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment