diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 9ea32d7707..7b2c521a35 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -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); diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 68d0d54a53..3b48a5cf18 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -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: diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index f7ca022f1c..d3d9886e3c 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -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; diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index d055b0160c..96e4b98a4e 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -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); } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 2d38d7fd60..cdf98de568 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index d3f18c1ce7..a173cf59df 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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 diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index fdaed3d472..4d3d926a16 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -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; } diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index bec0ddf7c4..3d9f5486bc 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -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); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index e79991a0f6..af035d9b10 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -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: diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index c9aa190b33..cdd7b4d2e4 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -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; /*