Put function expressions and values lists into FunctionScan and ValuesScan
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Feb 2007 02:23:12 +0000 (02:23 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Feb 2007 02:23:12 +0000 (02:23 +0000)
plan nodes, so that the executor does not need to get these items from
the range table at runtime.  This will avoid needing to include these
fields in the compact range table I'm expecting to make the executor use.

src/backend/commands/explain.c
src/backend/executor/execAmi.c
src/backend/executor/nodeFunctionscan.c
src/backend/executor/nodeValuesscan.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/plan/subselect.c
src/include/nodes/plannodes.h

index 9ea32d7707aeb49877634745ed974956a6a69466..7b2c521a3535dd833cee3fccb4868b62f1468ab5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.154 2007/02/14 01:58:56 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.155 2007/02/19 02:23:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -640,6 +640,7 @@ explain_outNode(StringInfo str,
            {
                RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
                                              es->rtable);
+               Node       *funcexpr;
                char       *proname;
 
                /* Assert it's on a RangeFunction */
@@ -651,10 +652,10 @@ explain_outNode(StringInfo str,
                 * happen if the optimizer simplified away the function call,
                 * for example).
                 */
-               if (rte->funcexpr && IsA(rte->funcexpr, FuncExpr))
+               funcexpr = ((FunctionScan *) plan)->funcexpr;
+               if (funcexpr && IsA(funcexpr, FuncExpr))
                {
-                   FuncExpr   *funcexpr = (FuncExpr *) rte->funcexpr;
-                   Oid         funcid = funcexpr->funcid;
+                   Oid         funcid = ((FuncExpr *) funcexpr)->funcid;
 
                    /* We only show the func name, not schema name */
                    proname = get_func_name(funcid);
index 68d0d54a53c54f08bca345400be39cf32a601085..3b48a5cf18bd7aceeea742d61dd6338fcf56f334 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.91 2007/02/15 03:07:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.92 2007/02/19 02:23:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -444,13 +444,16 @@ ExecMayReturnRawTuples(PlanState *node)
        case T_IndexScanState:
        case T_BitmapHeapScanState:
        case T_TidScanState:
-       case T_SubqueryScanState:
-       case T_FunctionScanState:
-       case T_ValuesScanState:
            if (node->ps_ProjInfo == NULL)
                return true;
            break;
 
+       case T_SubqueryScanState:
+           /* If not projecting, look at input plan */
+           if (node->ps_ProjInfo == NULL)
+               return ExecMayReturnRawTuples(((SubqueryScanState *) node)->subplan);
+           break;
+
            /* Non-projecting nodes */
        case T_HashState:
        case T_MaterialState:
index f7ca022f1c7d1970fd51733a565db60128d05494..d3d9886e3c3aee128500537974eec19cf7893b27 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.42 2007/01/05 22:19:28 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.43 2007/02/19 02:23:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -118,7 +118,6 @@ FunctionScanState *
 ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
 {
    FunctionScanState *scanstate;
-   RangeTblEntry *rte;
    Oid         funcrettype;
    TypeFuncClass functypclass;
    TupleDesc   tupdesc = NULL;
@@ -161,17 +160,11 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
        ExecInitExpr((Expr *) node->scan.plan.qual,
                     (PlanState *) scanstate);
 
-   /*
-    * get info about function
-    */
-   rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
-   Assert(rte->rtekind == RTE_FUNCTION);
-
    /*
     * Now determine if the function returns a simple or composite type, and
     * build an appropriate tupdesc.
     */
-   functypclass = get_expr_result_type(rte->funcexpr,
+   functypclass = get_expr_result_type(node->funcexpr,
                                        &funcrettype,
                                        &tupdesc);
 
@@ -185,7 +178,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
    else if (functypclass == TYPEFUNC_SCALAR)
    {
        /* Base data type, i.e. scalar */
-       char       *attname = strVal(linitial(rte->eref->colnames));
+       char       *attname = strVal(linitial(node->funccolnames));
 
        tupdesc = CreateTemplateTupleDesc(1, false);
        TupleDescInitEntry(tupdesc,
@@ -197,9 +190,9 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
    }
    else if (functypclass == TYPEFUNC_RECORD)
    {
-       tupdesc = BuildDescFromLists(rte->eref->colnames,
-                                    rte->funccoltypes,
-                                    rte->funccoltypmods);
+       tupdesc = BuildDescFromLists(node->funccolnames,
+                                    node->funccoltypes,
+                                    node->funccoltypmods);
    }
    else
    {
@@ -221,7 +214,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
     * Other node-specific setup
     */
    scanstate->tuplestorestate = NULL;
-   scanstate->funcexpr = ExecInitExpr((Expr *) rte->funcexpr,
+   scanstate->funcexpr = ExecInitExpr((Expr *) node->funcexpr,
                                       (PlanState *) scanstate);
 
    scanstate->ss.ps.ps_TupFromTlist = false;
index d055b0160c5361ad578454964b210250b93e13f1..96e4b98a4e25cd947c30d2b5f16ca85796264810 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.5 2007/01/05 22:19:28 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.6 2007/02/19 02:23:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -182,7 +182,6 @@ ValuesScanState *
 ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
 {
    ValuesScanState *scanstate;
-   RangeTblEntry *rte;
    TupleDesc   tupdesc;
    ListCell   *vtl;
    int         i;
@@ -236,9 +235,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
    /*
     * get info about values list
     */
-   rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
-   Assert(rte->rtekind == RTE_VALUES);
-   tupdesc = ExecTypeFromExprList((List *) linitial(rte->values_lists));
+   tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
 
    ExecAssignScanType(&scanstate->ss, tupdesc);
 
@@ -247,13 +244,13 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
     */
    scanstate->marked_idx = -1;
    scanstate->curr_idx = -1;
-   scanstate->array_len = list_length(rte->values_lists);
+   scanstate->array_len = list_length(node->values_lists);
 
    /* convert list of sublists into array of sublists for easy addressing */
    scanstate->exprlists = (List **)
        palloc(scanstate->array_len * sizeof(List *));
    i = 0;
-   foreach(vtl, rte->values_lists)
+   foreach(vtl, node->values_lists)
    {
        scanstate->exprlists[i++] = (List *) lfirst(vtl);
    }
index 2d38d7fd60c0160a97a399c6fd7c5ae12f78d777..cdf98de568a6e158c0e496ccff8a2280c77ebe04 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.365 2007/02/03 14:06:54 petere Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.366 2007/02/19 02:23:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -363,6 +363,14 @@ _copyFunctionScan(FunctionScan *from)
     */
    CopyScanFields((Scan *) from, (Scan *) newnode);
 
+   /*
+    * copy remainder of node
+    */
+   COPY_NODE_FIELD(funcexpr);
+   COPY_NODE_FIELD(funccolnames);
+   COPY_NODE_FIELD(funccoltypes);
+   COPY_NODE_FIELD(funccoltypmods);
+
    return newnode;
 }
 
@@ -379,6 +387,11 @@ _copyValuesScan(ValuesScan *from)
     */
    CopyScanFields((Scan *) from, (Scan *) newnode);
 
+   /*
+    * copy remainder of node
+    */
+   COPY_NODE_FIELD(values_lists);
+
    return newnode;
 }
 
index d3f18c1ce7366bf14bf4366d3802f71e7036ce37..a173cf59dff671e75bde996a1b6778d61a1ed8f9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.297 2007/02/12 17:19:30 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.298 2007/02/19 02:23:12 tgl Exp $
  *
  * NOTES
  *   Every node type that can appear in stored rules' parsetrees *must*
@@ -408,6 +408,11 @@ _outFunctionScan(StringInfo str, FunctionScan *node)
    WRITE_NODE_TYPE("FUNCTIONSCAN");
 
    _outScanInfo(str, (Scan *) node);
+
+   WRITE_NODE_FIELD(funcexpr);
+   WRITE_NODE_FIELD(funccolnames);
+   WRITE_NODE_FIELD(funccoltypes);
+   WRITE_NODE_FIELD(funccoltypmods);
 }
 
 static void
@@ -416,6 +421,8 @@ _outValuesScan(StringInfo str, ValuesScan *node)
    WRITE_NODE_TYPE("VALUESSCAN");
 
    _outScanInfo(str, (Scan *) node);
+
+   WRITE_NODE_FIELD(values_lists);
 }
 
 static void
index fdaed3d472ed3908aafe8b1cf5f4e4db3abae25e..4d3d926a167fa58b1d2f06af0ae60013cbba26a3 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.224 2007/01/30 01:33:36 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.225 2007/02/19 02:23:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,9 +96,10 @@ static BitmapHeapScan *make_bitmap_heapscan(List *qptlist,
 static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
             List *tidquals);
 static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
-                 Index scanrelid);
+                 Index scanrelid, Node *funcexpr, List *funccolnames,
+                 List *funccoltypes, List *funccoltypmods);
 static ValuesScan *make_valuesscan(List *qptlist, List *qpqual,
-               Index scanrelid);
+               Index scanrelid, List *values_lists);
 static BitmapAnd *make_bitmap_and(List *bitmapplans);
 static BitmapOr *make_bitmap_or(List *bitmapplans);
 static NestLoop *make_nestloop(List *tlist,
@@ -1350,10 +1351,12 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path,
 {
    FunctionScan *scan_plan;
    Index       scan_relid = best_path->parent->relid;
+   RangeTblEntry *rte;
 
    /* it should be a function base rel... */
    Assert(scan_relid > 0);
-   Assert(best_path->parent->rtekind == RTE_FUNCTION);
+   rte = rt_fetch(scan_relid, root->parse->rtable);
+   Assert(rte->rtekind == RTE_FUNCTION);
 
    /* Sort clauses into best execution order */
    scan_clauses = order_qual_clauses(root, scan_clauses);
@@ -1361,7 +1364,11 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path,
    /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
    scan_clauses = extract_actual_clauses(scan_clauses, false);
 
-   scan_plan = make_functionscan(tlist, scan_clauses, scan_relid);
+   scan_plan = make_functionscan(tlist, scan_clauses, scan_relid,
+                                 rte->funcexpr,
+                                 rte->eref->colnames,
+                                 rte->funccoltypes,
+                                 rte->funccoltypmods);
 
    copy_path_costsize(&scan_plan->scan.plan, best_path);
 
@@ -1379,10 +1386,12 @@ create_valuesscan_plan(PlannerInfo *root, Path *best_path,
 {
    ValuesScan *scan_plan;
    Index       scan_relid = best_path->parent->relid;
+   RangeTblEntry *rte;
 
    /* it should be a values base rel... */
    Assert(scan_relid > 0);
-   Assert(best_path->parent->rtekind == RTE_VALUES);
+   rte = rt_fetch(scan_relid, root->parse->rtable);
+   Assert(rte->rtekind == RTE_VALUES);
 
    /* Sort clauses into best execution order */
    scan_clauses = order_qual_clauses(root, scan_clauses);
@@ -1390,7 +1399,8 @@ create_valuesscan_plan(PlannerInfo *root, Path *best_path,
    /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
    scan_clauses = extract_actual_clauses(scan_clauses, false);
 
-   scan_plan = make_valuesscan(tlist, scan_clauses, scan_relid);
+   scan_plan = make_valuesscan(tlist, scan_clauses, scan_relid,
+                               rte->values_lists);
 
    copy_path_costsize(&scan_plan->scan.plan, best_path);
 
@@ -2342,7 +2352,11 @@ make_subqueryscan(List *qptlist,
 static FunctionScan *
 make_functionscan(List *qptlist,
                  List *qpqual,
-                 Index scanrelid)
+                 Index scanrelid,
+                 Node *funcexpr,
+                 List *funccolnames,
+                 List *funccoltypes,
+                 List *funccoltypmods)
 {
    FunctionScan *node = makeNode(FunctionScan);
    Plan       *plan = &node->scan.plan;
@@ -2353,6 +2367,10 @@ make_functionscan(List *qptlist,
    plan->lefttree = NULL;
    plan->righttree = NULL;
    node->scan.scanrelid = scanrelid;
+   node->funcexpr = funcexpr;
+   node->funccolnames = funccolnames;
+   node->funccoltypes = funccoltypes;
+   node->funccoltypmods = funccoltypmods;
 
    return node;
 }
@@ -2360,7 +2378,8 @@ make_functionscan(List *qptlist,
 static ValuesScan *
 make_valuesscan(List *qptlist,
                List *qpqual,
-               Index scanrelid)
+               Index scanrelid,
+               List *values_lists)
 {
    ValuesScan *node = makeNode(ValuesScan);
    Plan       *plan = &node->scan.plan;
@@ -2371,6 +2390,7 @@ make_valuesscan(List *qptlist,
    plan->lefttree = NULL;
    plan->righttree = NULL;
    node->scan.scanrelid = scanrelid;
+   node->values_lists = values_lists;
 
    return node;
 }
index bec0ddf7c4b33aeae0769d82e10f18788eda6412..3d9f5486bccfce75f312eee1be38fb6b7ec90a75 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.129 2007/02/16 03:49:04 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.130 2007/02/19 02:23:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -171,28 +171,15 @@ set_plan_references(Plan *plan, List *rtable)
            /* Needs special treatment, see comments below */
            return set_subqueryscan_references((SubqueryScan *) plan, rtable);
        case T_FunctionScan:
-           {
-               RangeTblEntry *rte;
-
-               fix_expr_references(plan, (Node *) plan->targetlist);
-               fix_expr_references(plan, (Node *) plan->qual);
-               rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
-                              rtable);
-               Assert(rte->rtekind == RTE_FUNCTION);
-               fix_expr_references(plan, rte->funcexpr);
-           }
+           fix_expr_references(plan, (Node *) plan->targetlist);
+           fix_expr_references(plan, (Node *) plan->qual);
+           fix_expr_references(plan, ((FunctionScan *) plan)->funcexpr);
            break;
        case T_ValuesScan:
-           {
-               RangeTblEntry *rte;
-
-               fix_expr_references(plan, (Node *) plan->targetlist);
-               fix_expr_references(plan, (Node *) plan->qual);
-               rte = rt_fetch(((ValuesScan *) plan)->scan.scanrelid,
-                              rtable);
-               Assert(rte->rtekind == RTE_VALUES);
-               fix_expr_references(plan, (Node *) rte->values_lists);
-           }
+           fix_expr_references(plan, (Node *) plan->targetlist);
+           fix_expr_references(plan, (Node *) plan->qual);
+           fix_expr_references(plan,
+                               (Node *) ((ValuesScan *) plan)->values_lists);
            break;
        case T_NestLoop:
            set_join_references((Join *) plan);
@@ -369,10 +356,6 @@ set_subqueryscan_references(SubqueryScan *plan, List *rtable)
                   *lc;
 
        sub_rtable = copyObject(rte->subquery->rtable);
-       range_table_walker(sub_rtable,
-                          adjust_expr_varnos_walker,
-                          (void *) &rtoffset,
-                          QTW_IGNORE_RT_SUBQUERIES);
        rtable = list_concat(rtable, sub_rtable);
 
        /*
@@ -544,13 +527,15 @@ adjust_plan_varnos(Plan *plan, int rtoffset)
            ((FunctionScan *) plan)->scan.scanrelid += rtoffset;
            adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
            adjust_expr_varnos((Node *) plan->qual, rtoffset);
-           /* rte was already fixed by set_subqueryscan_references */
+           adjust_expr_varnos(((FunctionScan *) plan)->funcexpr,
+                              rtoffset);
            break;
        case T_ValuesScan:
            ((ValuesScan *) plan)->scan.scanrelid += rtoffset;
            adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
            adjust_expr_varnos((Node *) plan->qual, rtoffset);
-           /* rte was already fixed by set_subqueryscan_references */
+           adjust_expr_varnos((Node *) ((ValuesScan *) plan)->values_lists,
+                              rtoffset);
            break;
        case T_NestLoop:
            adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
index e79991a0f60b039d89e661f7150b5e62b485ee8b..af035d9b104cbbff3e3fd395f85fa7c3d019f122 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.118 2007/02/06 02:59:11 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.119 2007/02/19 02:23:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1103,25 +1103,13 @@ finalize_plan(Plan *plan, List *rtable,
            break;
 
        case T_FunctionScan:
-           {
-               RangeTblEntry *rte;
-
-               rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
-                              rtable);
-               Assert(rte->rtekind == RTE_FUNCTION);
-               finalize_primnode(rte->funcexpr, &context);
-           }
+           finalize_primnode(((FunctionScan *) plan)->funcexpr,
+                             &context);
            break;
 
        case T_ValuesScan:
-           {
-               RangeTblEntry *rte;
-
-               rte = rt_fetch(((ValuesScan *) plan)->scan.scanrelid,
-                              rtable);
-               Assert(rte->rtekind == RTE_VALUES);
-               finalize_primnode((Node *) rte->values_lists, &context);
-           }
+           finalize_primnode((Node *) ((ValuesScan *) plan)->values_lists,
+                             &context);
            break;
 
        case T_Append:
index c9aa190b33dc6b260fd5fec6965292cfaa3a4fc3..cdd7b4d2e43707fb574fb0ae2e7c040a2117d2f3 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.89 2007/01/10 18:06:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.90 2007/02/19 02:23:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -270,9 +270,11 @@ typedef struct TidScan
  *     subquery scan node
  *
  * SubqueryScan is for scanning the output of a sub-query in the range table.
- * We need a special plan node above the sub-query's plan as a place to switch
- * execution contexts. Although we are not scanning a physical relation,
- * we make this a descendant of Scan anyway for code-sharing purposes.
+ * We often need an extra plan node above the sub-query's plan to perform
+ * expression evaluations (which we can't push into the sub-query without
+ * risking changing its semantics).  Although we are not scanning a physical
+ * relation, we make this a descendant of Scan anyway for code-sharing
+ * purposes.
  *
  * Note: we store the sub-plan in the type-specific subplan field, not in
  * the generic lefttree field as you might expect. This is because we do
@@ -293,7 +295,10 @@ typedef struct SubqueryScan
 typedef struct FunctionScan
 {
    Scan        scan;
-   /* no other fields needed at present */
+   Node       *funcexpr;       /* expression tree for func call */
+   List       *funccolnames;   /* output column names (string Value nodes) */
+   List       *funccoltypes;   /* OID list of column type OIDs */
+   List       *funccoltypmods; /* integer list of column typmods */
 } FunctionScan;
 
 /* ----------------
@@ -303,7 +308,7 @@ typedef struct FunctionScan
 typedef struct ValuesScan
 {
    Scan        scan;
-   /* no other fields needed at present */
+   List       *values_lists;   /* list of expression lists */
 } ValuesScan;
 
 /*