X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fexecutor%2FnodeResult.c;h=a753a53419183cefebf5c3e0ed9fe6a9f8e8ac37;hb=b8d7f053c5c2bf2a7e8734fe3327f6a8bc711755;hp=770cc47ccc4f405b80e6f1083e1b35ac6c1c36f7;hpb=bec98a31c55a4f799b398d01541e68d7c086bb81;p=postgresql diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 770cc47ccc..a753a53419 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -8,33 +8,37 @@ * Result nodes are used in queries where no relations are scanned. * Examples of such queries are: * - * retrieve (x = 1) - * and - * append emp (name = "mike", salary = 15000) + * select 1 * 2 + * + * insert into emp values ('mike', 15000) + * + * (Remember that in an INSERT or UPDATE, we need a plan tree that + * generates the new rows.) * * Result nodes are also used to optimise queries with constant * qualifications (ie, quals that do not depend on the scanned data), * such as: * - * retrieve (emp.all) where 2 > 1 + * select * from emp where 2 > 1 * * In this case, the plan generated is * * Result (with 2 > 1 qual) * / - * SeqScan (emp.all) + * SeqScan (emp.*) * - * At runtime, the Result node evaluates the constant qual once. - * If it's false, we can return an empty result set without running - * the controlled plan at all. If it's true, we run the controlled + * At runtime, the Result node evaluates the constant qual once, + * which is shown by EXPLAIN as a One-Time Filter. If it's + * false, we can return an empty result set without running the + * controlled plan at all. If it's true, we run the controlled * plan normally and pass back the results. * * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.15 2000/07/17 03:04:53 tgl Exp $ + * src/backend/executor/nodeResult.c * *------------------------------------------------------------------------- */ @@ -60,185 +64,171 @@ * ---------------------------------------------------------------- */ TupleTableSlot * -ExecResult(Result *node) +ExecResult(ResultState *node) { - ResultState *resstate; TupleTableSlot *outerTupleSlot; - TupleTableSlot *resultSlot; - Plan *outerPlan; + PlanState *outerPlan; ExprContext *econtext; - bool isDone; - ProjectionInfo *projInfo; - /* ---------------- - * initialize the result node's state - * ---------------- - */ - resstate = node->resstate; - econtext = resstate->cstate.cs_ExprContext; - - /* ---------------- - * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. - * ---------------- - */ - ResetExprContext(econtext); + econtext = node->ps.ps_ExprContext; - /* ---------------- - * check constant qualifications like (2 > 1), if not already done - * ---------------- + /* + * check constant qualifications like (2 > 1), if not already done */ - if (resstate->rs_checkqual) + if (node->rs_checkqual) { - bool qualResult = ExecQual((List *) node->resconstantqual, - econtext, - false); + bool qualResult = ExecQual(node->resconstantqual, econtext); - resstate->rs_checkqual = false; - if (qualResult == false) + node->rs_checkqual = false; + if (!qualResult) { - resstate->rs_done = true; + node->rs_done = true; return NULL; } } - /* ---------------- - * Check to see if we're still projecting out tuples from a previous - * scan tuple (because there is a function-returning-set in the - * projection expressions). If so, try to project another one. - * ---------------- + /* + * Reset per-tuple memory context to free any expression evaluation + * storage allocated in the previous tuple cycle. */ - if (resstate->cstate.cs_TupFromTlist) - { - resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone); - if (!isDone) - return resultSlot; - /* Done with that source tuple... */ - resstate->cstate.cs_TupFromTlist = false; - } + ResetExprContext(econtext); - /* ---------------- - * if rs_done is true then it means that we were asked to return - * a constant tuple and we already did the last time ExecResult() - * was called, OR that we failed the constant qual check. - * Either way, now we are through. - * ---------------- + /* + * if rs_done is true then it means that we were asked to return a + * constant tuple and we already did the last time ExecResult() was + * called, OR that we failed the constant qual check. Either way, now we + * are through. */ - if (!resstate->rs_done) + while (!node->rs_done) { - outerPlan = outerPlan(node); + outerPlan = outerPlanState(node); if (outerPlan != NULL) { - /* ---------------- - * retrieve tuples from the outer plan until there are no more. - * ---------------- + /* + * retrieve tuples from the outer plan until there are no more. */ - outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node); + outerTupleSlot = ExecProcNode(outerPlan); if (TupIsNull(outerTupleSlot)) return NULL; - resstate->cstate.cs_OuterTupleSlot = outerTupleSlot; - - /* ---------------- - * XXX gross hack. use outer tuple as scan tuple for projection - * ---------------- + /* + * prepare to compute projection expressions, which will expect to + * access the input tuples as varno OUTER. */ econtext->ecxt_outertuple = outerTupleSlot; - econtext->ecxt_scantuple = outerTupleSlot; } else { - /* ---------------- - * if we don't have an outer plan, then we are just generating - * the results from a constant target list. Do it only once. - * ---------------- + /* + * if we don't have an outer plan, then we are just generating the + * results from a constant target list. Do it only once. */ - resstate->rs_done = true; + node->rs_done = true; } - /* ---------------- - * form the result tuple using ExecProject(), and return it. - * ---------------- - */ - projInfo = resstate->cstate.cs_ProjInfo; - resultSlot = ExecProject(projInfo, &isDone); - resstate->cstate.cs_TupFromTlist = !isDone; - return resultSlot; + /* form the result tuple using ExecProject(), and return it */ + return ExecProject(node->ps.ps_ProjInfo); } return NULL; } +/* ---------------------------------------------------------------- + * ExecResultMarkPos + * ---------------------------------------------------------------- + */ +void +ExecResultMarkPos(ResultState *node) +{ + PlanState *outerPlan = outerPlanState(node); + + if (outerPlan != NULL) + ExecMarkPos(outerPlan); + else + elog(DEBUG2, "Result nodes do not support mark/restore"); +} + +/* ---------------------------------------------------------------- + * ExecResultRestrPos + * ---------------------------------------------------------------- + */ +void +ExecResultRestrPos(ResultState *node) +{ + PlanState *outerPlan = outerPlanState(node); + + if (outerPlan != NULL) + ExecRestrPos(outerPlan); + else + elog(ERROR, "Result nodes do not support mark/restore"); +} + /* ---------------------------------------------------------------- * ExecInitResult * * Creates the run-time state information for the result node - * produced by the planner and initailizes outer relations + * produced by the planner and initializes outer relations * (child nodes). * ---------------------------------------------------------------- */ -bool -ExecInitResult(Result *node, EState *estate, Plan *parent) +ResultState * +ExecInitResult(Result *node, EState *estate, int eflags) { ResultState *resstate; - /* ---------------- - * assign execution state to node - * ---------------- - */ - node->plan.state = estate; + /* check for unsupported flags */ + Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) || + outerPlan(node) != NULL); - /* ---------------- - * create new ResultState for node - * ---------------- + /* + * create state structure */ resstate = makeNode(ResultState); + resstate->ps.plan = (Plan *) node; + resstate->ps.state = estate; + resstate->rs_done = false; resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true; - node->resstate = resstate; - /* ---------------- - * Miscellaneous initialization + /* + * Miscellaneous initialization * - * + create expression context for node - * ---------------- + * create expression context for node */ - ExecAssignExprContext(estate, &resstate->cstate); + ExecAssignExprContext(estate, &resstate->ps); -#define RESULT_NSLOTS 1 - /* ---------------- - * tuple table initialization - * ---------------- + /* + * tuple table initialization + */ + ExecInitResultTupleSlot(estate, &resstate->ps); + + /* + * initialize child expressions */ - ExecInitResultTupleSlot(estate, &resstate->cstate); + resstate->ps.qual = + ExecInitQual(node->plan.qual, (PlanState *) resstate); + resstate->resconstantqual = + ExecInitQual((List *) node->resconstantqual, (PlanState *) resstate); - /* ---------------- - * then initialize children - * ---------------- + /* + * initialize child nodes */ - ExecInitNode(outerPlan(node), estate, (Plan *) node); + outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags); /* * we don't use inner plan */ Assert(innerPlan(node) == NULL); - /* ---------------- - * initialize tuple type and projection info - * ---------------- + /* + * initialize tuple type and projection info */ - ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate); - ExecAssignProjectionInfo((Plan *) node, &resstate->cstate); + ExecAssignResultTypeFromTL(&resstate->ps); + ExecAssignProjectionInfo(&resstate->ps, NULL); - return TRUE; -} - -int -ExecCountSlotsResult(Result *node) -{ - return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS; + return resstate; } /* ---------------------------------------------------------------- @@ -248,53 +238,35 @@ ExecCountSlotsResult(Result *node) * ---------------------------------------------------------------- */ void -ExecEndResult(Result *node) +ExecEndResult(ResultState *node) { - ResultState *resstate; - - resstate = node->resstate; - - /* ---------------- - * Free the projection info - * - * Note: we don't ExecFreeResultType(resstate) - * because the rule manager depends on the tupType - * returned by ExecMain(). So for now, this - * is freed at end-transaction time. -cim 6/2/91 - * ---------------- + /* + * Free the exprcontext */ - ExecFreeProjectionInfo(&resstate->cstate); - ExecFreeExprContext(&resstate->cstate); + ExecFreeExprContext(&node->ps); - /* ---------------- - * shut down subplans - * ---------------- + /* + * clean out the tuple table */ - ExecEndNode(outerPlan(node), (Plan *) node); + ExecClearTuple(node->ps.ps_ResultTupleSlot); - /* ---------------- - * clean out the tuple table - * ---------------- + /* + * shut down subplans */ - ExecClearTuple(resstate->cstate.cs_ResultTupleSlot); - pfree(resstate); - node->resstate = NULL; /* XXX - new for us - er1p */ + ExecEndNode(outerPlanState(node)); } void -ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent) +ExecReScanResult(ResultState *node) { - ResultState *resstate = node->resstate; - - resstate->rs_done = false; - resstate->cstate.cs_TupFromTlist = false; - resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true; + node->rs_done = false; + node->rs_checkqual = (node->resconstantqual == NULL) ? false : true; /* - * if chgParam of subnode is not null then plan will be re-scanned by + * If chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((Plan *) node)->lefttree && - ((Plan *) node)->lefttree->chgParam == NULL) - ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node); + if (node->ps.lefttree && + node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); }