]> granicus.if.org Git - postgresql/commitdiff
Cope with circularities involving a view's ON SELECT rule. I originally
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Dec 2004 22:16:32 +0000 (22:16 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Dec 2004 22:16:32 +0000 (22:16 +0000)
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.

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

index c161b3d0afe14ed96edc121e61b9502c1f7e9132..4b96613a1cc586ea20749424b211c46f589aa201 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * 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,12 +3160,21 @@ getRules(int *numRules)
                         */
                        if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
                                ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
+                       {
                                addObjectDependency(&ruleinfo[i].ruletable->dobj,
                                                                        ruleinfo[i].dobj.dumpId);
+                               /* We'll merge the rule into CREATE VIEW, if possible */
+                               ruleinfo[i].separate = false;
+                       }
                        else
+                       {
                                addObjectDependency(&ruleinfo[i].dobj,
                                                                        ruleinfo[i].ruletable->dobj.dumpId);
+                               ruleinfo[i].separate = true;
+                       }
                }
+               else
+                       ruleinfo[i].separate = true;
        }
 
        PQclear(res);
@@ -7617,10 +7626,10 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
                return;
 
        /*
-        * If it is an ON SELECT rule, we do not need to dump it because it
-        * will be handled via CREATE VIEW for the table.
+        * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
+        * we do not want to dump it as a separate object.
         */
-       if (rinfo->ev_type == '1' && rinfo->is_instead)
+       if (!rinfo->separate)
                return;
 
        /*
index 07798c90f4720e3fd155f04c2ec3e798362da990..a6a010d187abf21f39223f8046277092a41b2e3b 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
  * 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
        TableInfo  *ruletable;          /* link to table the rule is for */
        char            ev_type;
        bool            is_instead;
+       bool            separate;               /* TRUE if must dump as separate item */
+       /* separate is always true for non-ON SELECT rules */
 } RuleInfo;
 
 typedef struct _triggerInfo
index 79696f452f767d6336c96c48e0cf2a41df1f271e..34b4b468b1f178c485d7e993cc2c176875b6921f 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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)
 /*
  * 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
- * 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
 repairViewRuleLoop(DumpableObject *viewobj,
@@ -649,6 +650,29 @@ repairViewRuleLoop(DumpableObject *viewobj,
        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
  * will be an automatic dependency in the other direction, we need to break
@@ -765,7 +789,8 @@ repairDependencyLoop(DumpableObject **loop,
                loop[0]->objType == DO_TABLE &&
                loop[1]->objType == DO_RULE &&
                ((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]);
                return;
@@ -774,12 +799,35 @@ repairDependencyLoop(DumpableObject **loop,
                loop[1]->objType == DO_TABLE &&
                loop[0]->objType == DO_RULE &&
                ((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]);
                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 */
        if (nLoop == 2 &&
                loop[0]->objType == DO_TABLE &&