]> granicus.if.org Git - postgresql/commitdiff
Fix the plan-invalidation mechanism to treat regclass constants that refer to
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 11 Oct 2007 18:05:27 +0000 (18:05 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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;