Fix the plan-invalidation mechanism to treat regclass constants that refer to
authorTom Lane
Thu, 11 Oct 2007 18:05:27 +0000 (18:05 +0000)
committerTom Lane
Thu, 11 Oct 2007 18:05:27 +0000 (18:05 +0000)
a relation as a reason to invalidate a plan when the relation changes.  This
handles scenarios such as dropping/recreating a sequence that is referenced by
nextval('seq') in a cached plan.  Rather than teach plancache.c all about
digging through plan trees to find regclass Consts, we charge the planner's
setrefs.c with making a list of the relation OIDs on which each plan depends.
That way the list can be built cheaply during a plan tree traversal that has
to happen anyway.  Per bug #3662 and subsequent discussion.

src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/backend/utils/cache/plancache.c
src/include/nodes/plannodes.h
src/include/nodes/relation.h
src/include/optimizer/planmain.h
src/test/regress/expected/plancache.out
src/test/regress/sql/plancache.sql

index b6c6331d17085809b4d6ea59a02a23a0e416d8ac..c6393effcd649006f5c3519b58059b08a6767736 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.382 2007/09/03 18:46:30 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.383 2007/10/11 18:05:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,6 +83,7 @@ _copyPlannedStmt(PlannedStmt *from)
    COPY_BITMAPSET_FIELD(rewindPlanIDs);
    COPY_NODE_FIELD(returningLists);
    COPY_NODE_FIELD(rowMarks);
+   COPY_NODE_FIELD(relationOids);
    COPY_SCALAR_FIELD(nParamExec);
 
    return newnode;
index db0bf7c050defcb2ef9f2e5433d79aacb32e5896..005879b8c910e5ef892dacd09612719045e5a87d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.314 2007/08/31 01:44:05 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.315 2007/10/11 18:05:27 tgl Exp $
  *
  * NOTES
  *   Every node type that can appear in stored rules' parsetrees *must*
@@ -250,6 +250,7 @@ _outPlannedStmt(StringInfo str, PlannedStmt *node)
    WRITE_BITMAPSET_FIELD(rewindPlanIDs);
    WRITE_NODE_FIELD(returningLists);
    WRITE_NODE_FIELD(rowMarks);
+   WRITE_NODE_FIELD(relationOids);
    WRITE_INT_FIELD(nParamExec);
 }
 
@@ -1300,6 +1301,7 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node)
    WRITE_NODE_FIELD(subrtables);
    WRITE_BITMAPSET_FIELD(rewindPlanIDs);
    WRITE_NODE_FIELD(finalrtable);
+   WRITE_NODE_FIELD(relationOids);
 }
 
 static void
index e36ba97f6b860fadae82642712135e3a1345c73a..c55f89da78d592f19e1524d480b5850d96f68394 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.222 2007/09/20 17:56:31 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.223 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -134,6 +134,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
    glob->subrtables = NIL;
    glob->rewindPlanIDs = NULL;
    glob->finalrtable = NIL;
+   glob->relationOids = NIL;
    glob->transientPlan = false;
 
    /* Determine what fraction of the plan is likely to be scanned */
@@ -194,6 +195,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
    result->rewindPlanIDs = glob->rewindPlanIDs;
    result->returningLists = root->returningLists;
    result->rowMarks = parse->rowMarks;
+   result->relationOids = glob->relationOids;
    result->nParamExec = list_length(glob->paramlist);
 
    return result;
@@ -1184,7 +1186,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
        List       *rlist;
 
        Assert(parse->resultRelation);
-       rlist = set_returning_clause_references(parse->returningList,
+       rlist = set_returning_clause_references(root->glob,
+                                               parse->returningList,
                                                result_plan,
                                                parse->resultRelation);
        root->returningLists = list_make1(rlist);
index 055b47beec7d6791aa055749eafe65f4299ccc0b..bc8ce00d4e8ba68393b97d4b9dcbcd04de2118e7 100644 (file)
@@ -2,19 +2,20 @@
  *
  * setrefs.c
  *   Post-processing of a completed plan tree: fix references to subplan
- *   vars, and compute regproc values for operators
+ *   vars, compute regproc values for operators, etc
  *
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.136 2007/06/11 01:16:23 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.137 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
@@ -42,11 +43,13 @@ typedef struct
 
 typedef struct
 {
+   PlannerGlobal *glob;
    int         rtoffset;
 } fix_scan_expr_context;
 
 typedef struct
 {
+   PlannerGlobal *glob;
    indexed_tlist *outer_itlist;
    indexed_tlist *inner_itlist;
    Index       acceptable_rel;
@@ -55,24 +58,25 @@ typedef struct
 
 typedef struct
 {
+   PlannerGlobal *glob;
    indexed_tlist *subplan_itlist;
    int         rtoffset;
 } fix_upper_expr_context;
 
-#define fix_scan_list(lst, rtoffset) \
-   ((List *) fix_scan_expr((Node *) (lst), rtoffset))
+#define fix_scan_list(glob, lst, rtoffset) \
+   ((List *) fix_scan_expr(glob, (Node *) (lst), rtoffset))
 
 static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset);
 static Plan *set_subqueryscan_references(PlannerGlobal *glob,
                                         SubqueryScan *plan,
                                         int rtoffset);
 static bool trivial_subqueryscan(SubqueryScan *plan);
-static Node *fix_scan_expr(Node *node, int rtoffset);
+static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset);
 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
-static void set_join_references(Join *join, int rtoffset);
-static void set_inner_join_references(Plan *inner_plan,
+static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset);
+static void set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
                          indexed_tlist *outer_itlist);
-static void set_upper_references(Plan *plan, int rtoffset);
+static void set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset);
 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
 static indexed_tlist *build_tlist_index(List *tlist);
 static Var *search_indexed_tlist_for_var(Var *var,
@@ -82,13 +86,15 @@ static Var *search_indexed_tlist_for_var(Var *var,
 static Var *search_indexed_tlist_for_non_var(Node *node,
                                 indexed_tlist *itlist,
                                 Index newvarno);
-static List *fix_join_expr(List *clauses,
+static List *fix_join_expr(PlannerGlobal *glob,
+                          List *clauses,
                           indexed_tlist *outer_itlist,
                           indexed_tlist *inner_itlist,
                           Index acceptable_rel, int rtoffset);
 static Node *fix_join_expr_mutator(Node *node,
                                   fix_join_expr_context *context);
-static Node *fix_upper_expr(Node *node,
+static Node *fix_upper_expr(PlannerGlobal *glob,
+                           Node *node,
                            indexed_tlist *subplan_itlist,
                            int rtoffset);
 static Node *fix_upper_expr_mutator(Node *node,
@@ -120,6 +126,11 @@ static bool fix_opfuncids_walker(Node *node, void *context);
  * 4. We compute regproc OIDs for operators (ie, we look up the function
  * that implements each op).
  *
+ * 5. We create a list of OIDs of relations that the plan depends on.
+ * This will be used by plancache.c to drive invalidation of cached plans.
+ * (Someday we might want to generalize this to include other types of
+ * objects, but for now tracking relations seems to solve most problems.)
+ *
  * We also perform one final optimization step, which is to delete
  * SubqueryScan plan nodes that aren't doing anything useful (ie, have
  * no qual and a no-op targetlist).  The reason for doing this last is that
@@ -128,7 +139,7 @@ static bool fix_opfuncids_walker(Node *node, void *context);
  * wouldn't match up with the Vars in the outer plan tree.  The SubqueryScan
  * serves a necessary function as a buffer between outer query and subquery
  * variable numbering ... but after we've flattened the rangetable this is
- * no longer a problem, since there's only one rtindex namespace.
+ * no longer a problem, since then there's only one rtindex namespace.
  *
  * set_plan_references recursively traverses the whole plan tree.
  *
@@ -140,7 +151,8 @@ static bool fix_opfuncids_walker(Node *node, void *context);
  * The return value is normally the same Plan node passed in, but can be
  * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
  *
- * The flattened rangetable entries are appended to glob->finalrtable.
+ * The flattened rangetable entries are appended to glob->finalrtable, and
+ * the list of relation OIDs is appended to glob->relationOids.
  *
  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
  * to process targetlist and qual expressions.  We can assume that the Plan
@@ -177,6 +189,22 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable)
        newrte->joinaliasvars = NIL;
 
        glob->finalrtable = lappend(glob->finalrtable, newrte);
+
+       /*
+        * If it's a plain relation RTE, add the table to relationOids.
+        *
+        * We do this even though the RTE might be unreferenced in the
+        * plan tree; this would correspond to cases such as views that
+        * were expanded, child tables that were eliminated by constraint
+        * exclusion, etc.  Schema invalidation on such a rel must still
+        * force rebuilding of the plan.
+        *
+        * Note we don't bother to avoid duplicate list entries.  We could,
+        * but it would probably cost more cycles than it would save.
+        */
+       if (newrte->rtekind == RTE_RELATION)
+           glob->relationOids = lappend_oid(glob->relationOids,
+                                            newrte->relid);
    }
 
    /* Now fix the Plan tree */
@@ -205,9 +233,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
                splan->scanrelid += rtoffset;
                splan->plan.targetlist =
-                   fix_scan_list(splan->plan.targetlist, rtoffset);
+                   fix_scan_list(glob, splan->plan.targetlist, rtoffset);
                splan->plan.qual =
-                   fix_scan_list(splan->plan.qual, rtoffset);
+                   fix_scan_list(glob, splan->plan.qual, rtoffset);
            }
            break;
        case T_IndexScan:
@@ -216,13 +244,13 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
                splan->scan.scanrelid += rtoffset;
                splan->scan.plan.targetlist =
-                   fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
                splan->scan.plan.qual =
-                   fix_scan_list(splan->scan.plan.qual, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
                splan->indexqual =
-                   fix_scan_list(splan->indexqual, rtoffset);
+                   fix_scan_list(glob, splan->indexqual, rtoffset);
                splan->indexqualorig =
-                   fix_scan_list(splan->indexqualorig, rtoffset);
+                   fix_scan_list(glob, splan->indexqualorig, rtoffset);
            }
            break;
        case T_BitmapIndexScan:
@@ -234,9 +262,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
                Assert(splan->scan.plan.targetlist == NIL);
                Assert(splan->scan.plan.qual == NIL);
                splan->indexqual =
-                   fix_scan_list(splan->indexqual, rtoffset);
+                   fix_scan_list(glob, splan->indexqual, rtoffset);
                splan->indexqualorig =
-                   fix_scan_list(splan->indexqualorig, rtoffset);
+                   fix_scan_list(glob, splan->indexqualorig, rtoffset);
            }
            break;
        case T_BitmapHeapScan:
@@ -245,11 +273,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
                splan->scan.scanrelid += rtoffset;
                splan->scan.plan.targetlist =
-                   fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
                splan->scan.plan.qual =
-                   fix_scan_list(splan->scan.plan.qual, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
                splan->bitmapqualorig =
-                   fix_scan_list(splan->bitmapqualorig, rtoffset);
+                   fix_scan_list(glob, splan->bitmapqualorig, rtoffset);
            }
            break;
        case T_TidScan:
@@ -258,11 +286,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
                splan->scan.scanrelid += rtoffset;
                splan->scan.plan.targetlist =
-                   fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
                splan->scan.plan.qual =
-                   fix_scan_list(splan->scan.plan.qual, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
                splan->tidquals =
-                   fix_scan_list(splan->tidquals, rtoffset);
+                   fix_scan_list(glob, splan->tidquals, rtoffset);
            }
            break;
        case T_SubqueryScan:
@@ -276,11 +304,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
                splan->scan.scanrelid += rtoffset;
                splan->scan.plan.targetlist =
-                   fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
                splan->scan.plan.qual =
-                   fix_scan_list(splan->scan.plan.qual, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
                splan->funcexpr =
-                   fix_scan_expr(splan->funcexpr, rtoffset);
+                   fix_scan_expr(glob, splan->funcexpr, rtoffset);
            }
            break;
        case T_ValuesScan:
@@ -289,18 +317,18 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
                splan->scan.scanrelid += rtoffset;
                splan->scan.plan.targetlist =
-                   fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
                splan->scan.plan.qual =
-                   fix_scan_list(splan->scan.plan.qual, rtoffset);
+                   fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
                splan->values_lists =
-                   fix_scan_list(splan->values_lists, rtoffset);
+                   fix_scan_list(glob, splan->values_lists, rtoffset);
            }
            break;
 
        case T_NestLoop:
        case T_MergeJoin:
        case T_HashJoin:
-           set_join_references((Join *) plan, rtoffset);
+           set_join_references(glob, (Join *) plan, rtoffset);
            break;
 
        case T_Hash:
@@ -337,14 +365,14 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
                Assert(splan->plan.qual == NIL);
 
                splan->limitOffset =
-                   fix_scan_expr(splan->limitOffset, rtoffset);
+                   fix_scan_expr(glob, splan->limitOffset, rtoffset);
                splan->limitCount =
-                   fix_scan_expr(splan->limitCount, rtoffset);
+                   fix_scan_expr(glob, splan->limitCount, rtoffset);
            }
            break;
        case T_Agg:
        case T_Group:
-           set_upper_references(plan, rtoffset);
+           set_upper_references(glob, plan, rtoffset);
            break;
        case T_Result:
            {
@@ -355,17 +383,17 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
                 * like a scan node than an upper node.
                 */
                if (splan->plan.lefttree != NULL)
-                   set_upper_references(plan, rtoffset);
+                   set_upper_references(glob, plan, rtoffset);
                else
                {
                    splan->plan.targetlist =
-                       fix_scan_list(splan->plan.targetlist, rtoffset);
+                       fix_scan_list(glob, splan->plan.targetlist, rtoffset);
                    splan->plan.qual =
-                       fix_scan_list(splan->plan.qual, rtoffset);
+                       fix_scan_list(glob, splan->plan.qual, rtoffset);
                }
                /* resconstantqual can't contain any subplan variable refs */
                splan->resconstantqual =
-                   fix_scan_expr(splan->resconstantqual, rtoffset);
+                   fix_scan_expr(glob, splan->resconstantqual, rtoffset);
            }
            break;
        case T_Append:
@@ -497,9 +525,9 @@ set_subqueryscan_references(PlannerGlobal *glob,
         */
        plan->scan.scanrelid += rtoffset;
        plan->scan.plan.targetlist =
-           fix_scan_list(plan->scan.plan.targetlist, rtoffset);
+           fix_scan_list(glob, plan->scan.plan.targetlist, rtoffset);
        plan->scan.plan.qual =
-           fix_scan_list(plan->scan.plan.qual, rtoffset);
+           fix_scan_list(glob, plan->scan.plan.qual, rtoffset);
 
        result = (Plan *) plan;
    }
@@ -585,14 +613,16 @@ copyVar(Var *var)
  * fix_scan_expr
  *     Do set_plan_references processing on a scan-level expression
  *
- * This consists of incrementing all Vars' varnos by rtoffset and
- * looking up operator opcode info for OpExpr and related nodes.
+ * This consists of incrementing all Vars' varnos by rtoffset,
+ * looking up operator opcode info for OpExpr and related nodes,
+ * and adding OIDs from regclass Const nodes into glob->relationOids.
  */
 static Node *
-fix_scan_expr(Node *node, int rtoffset)
+fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset)
 {
    fix_scan_expr_context context;
 
+   context.glob = glob;
    context.rtoffset = rtoffset;
    return fix_scan_expr_mutator(node, &context);
 }
@@ -639,6 +669,17 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
        set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
    else if (IsA(node, ScalarArrayOpExpr))
        set_sa_opfuncid((ScalarArrayOpExpr *) node);
+   else if (IsA(node, Const))
+   {
+       Const      *con = (Const *) node;
+
+       /* Check for regclass reference */
+       if (con->consttype == REGCLASSOID && !con->constisnull)
+           context->glob->relationOids =
+               lappend_oid(context->glob->relationOids,
+                           DatumGetObjectId(con->constvalue));
+       /* Fall through to let expression_tree_mutator copy it */
+   }
    return expression_tree_mutator(node, fix_scan_expr_mutator,
                                   (void *) context);
 }
@@ -649,14 +690,14 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
  *   subplans, by setting the varnos to OUTER or INNER and setting attno
  *   values to the result domain number of either the corresponding outer
  *   or inner join tuple item.  Also perform opcode lookup for these
- *   expressions.
+ *   expressions. and add regclass OIDs to glob->relationOids.
  *
  * In the case of a nestloop with inner indexscan, we will also need to
  * apply the same transformation to any outer vars appearing in the
  * quals of the child indexscan.  set_inner_join_references does that.
  */
 static void
-set_join_references(Join *join, int rtoffset)
+set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
 {
    Plan       *outer_plan = join->plan.lefttree;
    Plan       *inner_plan = join->plan.righttree;
@@ -667,17 +708,20 @@ set_join_references(Join *join, int rtoffset)
    inner_itlist = build_tlist_index(inner_plan->targetlist);
 
    /* All join plans have tlist, qual, and joinqual */
-   join->plan.targetlist = fix_join_expr(join->plan.targetlist,
+   join->plan.targetlist = fix_join_expr(glob,
+                                         join->plan.targetlist,
                                          outer_itlist,
                                          inner_itlist,
                                          (Index) 0,
                                          rtoffset);
-   join->plan.qual = fix_join_expr(join->plan.qual,
+   join->plan.qual = fix_join_expr(glob,
+                                   join->plan.qual,
                                    outer_itlist,
                                    inner_itlist,
                                    (Index) 0,
                                    rtoffset);
-   join->joinqual = fix_join_expr(join->joinqual,
+   join->joinqual = fix_join_expr(glob,
+                                  join->joinqual,
                                   outer_itlist,
                                   inner_itlist,
                                   (Index) 0,
@@ -687,13 +731,14 @@ set_join_references(Join *join, int rtoffset)
    if (IsA(join, NestLoop))
    {
        /* This processing is split out to handle possible recursion */
-       set_inner_join_references(inner_plan, outer_itlist);
+       set_inner_join_references(glob, inner_plan, outer_itlist);
    }
    else if (IsA(join, MergeJoin))
    {
        MergeJoin  *mj = (MergeJoin *) join;
 
-       mj->mergeclauses = fix_join_expr(mj->mergeclauses,
+       mj->mergeclauses = fix_join_expr(glob,
+                                        mj->mergeclauses,
                                         outer_itlist,
                                         inner_itlist,
                                         (Index) 0,
@@ -703,7 +748,8 @@ set_join_references(Join *join, int rtoffset)
    {
        HashJoin   *hj = (HashJoin *) join;
 
-       hj->hashclauses = fix_join_expr(hj->hashclauses,
+       hj->hashclauses = fix_join_expr(glob,
+                                       hj->hashclauses,
                                        outer_itlist,
                                        inner_itlist,
                                        (Index) 0,
@@ -728,7 +774,8 @@ set_join_references(Join *join, int rtoffset)
  * recursion reaches the inner indexscan, and so we'd have done it twice.
  */
 static void
-set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
+set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
+                         indexed_tlist *outer_itlist)
 {
    if (IsA(inner_plan, IndexScan))
    {
@@ -747,12 +794,14 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
            Index       innerrel = innerscan->scan.scanrelid;
 
            /* only refs to outer vars get changed in the inner qual */
-           innerscan->indexqualorig = fix_join_expr(indexqualorig,
+           innerscan->indexqualorig = fix_join_expr(glob,
+                                                    indexqualorig,
                                                     outer_itlist,
                                                     NULL,
                                                     innerrel,
                                                     0);
-           innerscan->indexqual = fix_join_expr(innerscan->indexqual,
+           innerscan->indexqual = fix_join_expr(glob,
+                                                innerscan->indexqual,
                                                 outer_itlist,
                                                 NULL,
                                                 innerrel,
@@ -764,7 +813,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
             * may get rechecked as qpquals).
             */
            if (NumRelids((Node *) inner_plan->qual) > 1)
-               inner_plan->qual = fix_join_expr(inner_plan->qual,
+               inner_plan->qual = fix_join_expr(glob,
+                                                inner_plan->qual,
                                                 outer_itlist,
                                                 NULL,
                                                 innerrel,
@@ -785,12 +835,14 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
            Index       innerrel = innerscan->scan.scanrelid;
 
            /* only refs to outer vars get changed in the inner qual */
-           innerscan->indexqualorig = fix_join_expr(indexqualorig,
+           innerscan->indexqualorig = fix_join_expr(glob,
+                                                    indexqualorig,
                                                     outer_itlist,
                                                     NULL,
                                                     innerrel,
                                                     0);
-           innerscan->indexqual = fix_join_expr(innerscan->indexqual,
+           innerscan->indexqual = fix_join_expr(glob,
+                                                innerscan->indexqual,
                                                 outer_itlist,
                                                 NULL,
                                                 innerrel,
@@ -814,7 +866,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
        /* only refs to outer vars get changed in the inner qual */
        if (NumRelids((Node *) bitmapqualorig) > 1)
-           innerscan->bitmapqualorig = fix_join_expr(bitmapqualorig,
+           innerscan->bitmapqualorig = fix_join_expr(glob,
+                                                     bitmapqualorig,
                                                      outer_itlist,
                                                      NULL,
                                                      innerrel,
@@ -826,14 +879,15 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
         * get rechecked as qpquals).
         */
        if (NumRelids((Node *) inner_plan->qual) > 1)
-           inner_plan->qual = fix_join_expr(inner_plan->qual,
+           inner_plan->qual = fix_join_expr(glob,
+                                            inner_plan->qual,
                                             outer_itlist,
                                             NULL,
                                             innerrel,
                                             0);
 
        /* Now recurse */
-       set_inner_join_references(inner_plan->lefttree, outer_itlist);
+       set_inner_join_references(glob, inner_plan->lefttree, outer_itlist);
    }
    else if (IsA(inner_plan, BitmapAnd))
    {
@@ -843,7 +897,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
        foreach(l, innerscan->bitmapplans)
        {
-           set_inner_join_references((Plan *) lfirst(l), outer_itlist);
+           set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
        }
    }
    else if (IsA(inner_plan, BitmapOr))
@@ -854,7 +908,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
        foreach(l, innerscan->bitmapplans)
        {
-           set_inner_join_references((Plan *) lfirst(l), outer_itlist);
+           set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
        }
    }
    else if (IsA(inner_plan, TidScan))
@@ -862,7 +916,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
        TidScan    *innerscan = (TidScan *) inner_plan;
        Index       innerrel = innerscan->scan.scanrelid;
 
-       innerscan->tidquals = fix_join_expr(innerscan->tidquals,
+       innerscan->tidquals = fix_join_expr(glob,
+                                           innerscan->tidquals,
                                            outer_itlist,
                                            NULL,
                                            innerrel,
@@ -879,7 +934,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
        foreach(l, appendplan->appendplans)
        {
-           set_inner_join_references((Plan *) lfirst(l), outer_itlist);
+           set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
        }
    }
    else if (IsA(inner_plan, Result))
@@ -888,7 +943,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
        Result     *result = (Result *) inner_plan;
 
        if (result->plan.lefttree)
-           set_inner_join_references(result->plan.lefttree, outer_itlist);
+           set_inner_join_references(glob, result->plan.lefttree, outer_itlist);
    }
 }
 
@@ -896,7 +951,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
  * set_upper_references
  *   Update the targetlist and quals of an upper-level plan node
  *   to refer to the tuples returned by its lefttree subplan.
- *   Also perform opcode lookup for these expressions.
+ *   Also perform opcode lookup for these expressions, and
+ *   add regclass OIDs to glob->relationOids.
  *
  * This is used for single-input plan types like Agg, Group, Result.
  *
@@ -910,7 +966,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
  * the expression.
  */
 static void
-set_upper_references(Plan *plan, int rtoffset)
+set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset)
 {
    Plan       *subplan = plan->lefttree;
    indexed_tlist *subplan_itlist;
@@ -925,7 +981,8 @@ set_upper_references(Plan *plan, int rtoffset)
        TargetEntry *tle = (TargetEntry *) lfirst(l);
        Node       *newexpr;
 
-       newexpr = fix_upper_expr((Node *) tle->expr,
+       newexpr = fix_upper_expr(glob,
+                                (Node *) tle->expr,
                                 subplan_itlist,
                                 rtoffset);
        tle = flatCopyTargetEntry(tle);
@@ -935,7 +992,8 @@ set_upper_references(Plan *plan, int rtoffset)
    plan->targetlist = output_targetlist;
 
    plan->qual = (List *)
-       fix_upper_expr((Node *) plan->qual,
+       fix_upper_expr(glob,
+                      (Node *) plan->qual,
                       subplan_itlist,
                       rtoffset);
 
@@ -1166,7 +1224,8 @@ search_indexed_tlist_for_non_var(Node *node,
  *    Create a new set of targetlist entries or join qual clauses by
  *    changing the varno/varattno values of variables in the clauses
  *    to reference target list values from the outer and inner join
- *    relation target lists.  Also perform opcode lookup.
+ *    relation target lists.  Also perform opcode lookup and add
+ *    regclass OIDs to glob->relationOids.
  *
  * This is used in two different scenarios: a normal join clause, where
  * all the Vars in the clause *must* be replaced by OUTER or INNER references;
@@ -1192,7 +1251,8 @@ search_indexed_tlist_for_non_var(Node *node,
  * not modified.
  */
 static List *
-fix_join_expr(List *clauses,
+fix_join_expr(PlannerGlobal *glob,
+             List *clauses,
              indexed_tlist *outer_itlist,
              indexed_tlist *inner_itlist,
              Index acceptable_rel,
@@ -1200,6 +1260,7 @@ fix_join_expr(List *clauses,
 {
    fix_join_expr_context context;
 
+   context.glob = glob;
    context.outer_itlist = outer_itlist;
    context.inner_itlist = inner_itlist;
    context.acceptable_rel = acceptable_rel;
@@ -1276,6 +1337,17 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
        set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
    else if (IsA(node, ScalarArrayOpExpr))
        set_sa_opfuncid((ScalarArrayOpExpr *) node);
+   else if (IsA(node, Const))
+   {
+       Const      *con = (Const *) node;
+
+       /* Check for regclass reference */
+       if (con->consttype == REGCLASSOID && !con->constisnull)
+           context->glob->relationOids =
+               lappend_oid(context->glob->relationOids,
+                           DatumGetObjectId(con->constvalue));
+       /* Fall through to let expression_tree_mutator copy it */
+   }
    return expression_tree_mutator(node,
                                   fix_join_expr_mutator,
                                   (void *) context);
@@ -1284,7 +1356,8 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
 /*
  * fix_upper_expr
  *     Modifies an expression tree so that all Var nodes reference outputs
- *     of a subplan.  Also performs opcode lookup.
+ *     of a subplan.  Also performs opcode lookup, and adds regclass OIDs to
+ *     glob->relationOids.
  *
  * This is used to fix up target and qual expressions of non-join upper-level
  * plan nodes.
@@ -1308,12 +1381,14 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
  * The original tree is not modified.
  */
 static Node *
-fix_upper_expr(Node *node,
+fix_upper_expr(PlannerGlobal *glob,
+              Node *node,
               indexed_tlist *subplan_itlist,
               int rtoffset)
 {
    fix_upper_expr_context context;
 
+   context.glob = glob;
    context.subplan_itlist = subplan_itlist;
    context.rtoffset = rtoffset;
    return fix_upper_expr_mutator(node, &context);
@@ -1359,6 +1434,17 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
        set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
    else if (IsA(node, ScalarArrayOpExpr))
        set_sa_opfuncid((ScalarArrayOpExpr *) node);
+   else if (IsA(node, Const))
+   {
+       Const      *con = (Const *) node;
+
+       /* Check for regclass reference */
+       if (con->consttype == REGCLASSOID && !con->constisnull)
+           context->glob->relationOids =
+               lappend_oid(context->glob->relationOids,
+                           DatumGetObjectId(con->constvalue));
+       /* Fall through to let expression_tree_mutator copy it */
+   }
    return expression_tree_mutator(node,
                                   fix_upper_expr_mutator,
                                   (void *) context);
@@ -1376,7 +1462,8 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
  * adjusted RETURNING list, result-table Vars will still have their
  * original varno, but Vars for other rels will have varno OUTER.
  *
- * We also must perform opcode lookup.
+ * We also must perform opcode lookup and add regclass OIDs to
+ * glob->relationOids.
  *
  * 'rlist': the RETURNING targetlist to be fixed
  * 'topplan': the top Plan node for the query (not yet passed through
@@ -1387,7 +1474,8 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
  * they are not coming from a subplan.
  */
 List *
-set_returning_clause_references(List *rlist,
+set_returning_clause_references(PlannerGlobal *glob,
+                               List *rlist,
                                Plan *topplan,
                                Index resultRelation)
 {
@@ -1402,7 +1490,8 @@ set_returning_clause_references(List *rlist,
     */
    itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
 
-   rlist = fix_join_expr(rlist,
+   rlist = fix_join_expr(glob,
+                         rlist,
                          itlist,
                          NULL,
                          resultRelation,
index 43297281f5ffb0504ad185eae0c91357d4f80846..2f52ed7a8cc39bf88fed62fb0c5ff0fad83cd695 100644 (file)
@@ -33,7 +33,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.11 2007/09/20 17:56:31 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.12 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -921,26 +921,17 @@ PlanCacheCallback(Datum arg, Oid relid)
            foreach(lc2, plan->stmt_list)
            {
                PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc2);
-               ListCell   *lc3;
 
                Assert(!IsA(plannedstmt, Query));
                if (!IsA(plannedstmt, PlannedStmt))
                    continue;           /* Ignore utility statements */
-               foreach(lc3, plannedstmt->rtable)
+               if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
+                   list_member_oid(plannedstmt->relationOids, relid))
                {
-                   RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc3);
-
-                   if (rte->rtekind != RTE_RELATION)
-                       continue;
-                   if (relid == rte->relid || relid == InvalidOid)
-                   {
-                       /* Invalidate the plan! */
-                       plan->dead = true;
-                       break;      /* out of rangetable scan */
-                   }
-               }
-               if (plan->dead)
+                   /* Invalidate the plan! */
+                   plan->dead = true;
                    break;          /* out of stmt_list scan */
+               }
            }
        }
        else
index 992b47f58d80fc8bc649ae6419cf349bdb0ab3d7..9b6c637284677daf9c09a93d23cf17329195f3e2 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.95 2007/09/20 17:56:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.96 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -70,6 +70,8 @@ typedef struct PlannedStmt
 
    List       *rowMarks;       /* a list of RowMarkClause's */
 
+   List       *relationOids;   /* OIDs of relations the plan depends on */
+
    int         nParamExec;     /* number of PARAM_EXEC Params used */
 } PlannedStmt;
 
index 32c699b6de6fcaddb0ad7816cf2c166107cbb0b0..389035202223be64409f62cc5384ab40f661ebe5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.146 2007/09/20 17:56:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.147 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,6 +72,8 @@ typedef struct PlannerGlobal
 
    List       *finalrtable;    /* "flat" rangetable for executor */
 
+   List       *relationOids;   /* OIDs of relations the plan depends on */
+
    bool        transientPlan;  /* redo plan when TransactionXmin changes? */
 } PlannerGlobal;
 
index 4673d53098fbe2af826787a280aa560993260241..43769c71e11e725a801b8f4d43a8432f1082ead2 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.102 2007/10/04 20:44:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.103 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,7 +96,8 @@ extern RestrictInfo *build_implied_join_equality(Oid opno,
 extern Plan *set_plan_references(PlannerGlobal *glob,
                                 Plan *plan,
                                 List *rtable);
-extern List *set_returning_clause_references(List *rlist,
+extern List *set_returning_clause_references(PlannerGlobal *glob,
+                               List *rlist,
                                Plan *topplan,
                                Index resultRelation);
 extern void fix_opfuncids(Node *node);
index a96ba2a5da017c1626d3717e7dbb9600e52e5ca7..d7d7be92529aee67b0ab7b08e4de39e5157749b2 100644 (file)
@@ -202,3 +202,20 @@ drop schema s1 cascade;
 NOTICE:  drop cascades to table s1.abc
 drop schema s2 cascade;
 NOTICE:  drop cascades to table abc
+-- Check that invalidation deals with regclass constants
+create temp sequence seq;
+prepare p2 as select nextval('seq');
+execute p2;
+ nextval 
+---------
+       1
+(1 row)
+
+drop sequence seq;
+create temp sequence seq;
+execute p2;
+ nextval 
+---------
+       1
+(1 row)
+
index e285c071f6edca537fed03b07834cb9dda909c1c..fc57279d985c702476509b7f2bda227ac2e37dd2 100644 (file)
@@ -123,3 +123,17 @@ execute p1;
 
 drop schema s1 cascade;
 drop schema s2 cascade;
+
+-- Check that invalidation deals with regclass constants
+
+create temp sequence seq;
+
+prepare p2 as select nextval('seq');
+
+execute p2;
+
+drop sequence seq;
+
+create temp sequence seq;
+
+execute p2;