diff options
Diffstat (limited to 'src/backend/executor/nodeSubplan.c')
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 491 |
1 files changed, 0 insertions, 491 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c deleted file mode 100644 index 0c7b3557cff..00000000000 --- a/src/backend/executor/nodeSubplan.c +++ /dev/null @@ -1,491 +0,0 @@ -/*------------------------------------------------------------------------- - * - * nodeSubplan.c - * routines to support subselects - * - * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.33 2002/06/20 20:29:28 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -/* - * INTERFACE ROUTINES - * ExecSubPlan - process a subselect - * ExecInitSubPlan - initialize a subselect - * ExecEndSubPlan - shut down a subselect - */ -#include "postgres.h" - -#include "access/heapam.h" -#include "executor/executor.h" -#include "executor/nodeSubplan.h" -#include "tcop/pquery.h" - - -/* ---------------------------------------------------------------- - * ExecSubPlan(node) - * - * ---------------------------------------------------------------- - */ -Datum -ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) -{ - Plan *plan = node->plan; - SubLink *sublink = node->sublink; - SubLinkType subLinkType = sublink->subLinkType; - bool useor = sublink->useor; - MemoryContext oldcontext; - TupleTableSlot *slot; - Datum result; - bool found = false; /* TRUE if got at least one subplan tuple */ - List *lst; - - /* - * We are probably in a short-lived expression-evaluation context. - * Switch to longer-lived per-query context. - */ - oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); - - if (node->setParam != NIL) - elog(ERROR, "ExecSubPlan: can't set parent params from subquery"); - - /* - * Set Params of this plan from parent plan correlation Vars - */ - if (node->parParam != NIL) - { - foreach(lst, node->parParam) - { - ParamExecData *prm; - - prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]); - Assert(pvar != NIL); - prm->value = ExecEvalExprSwitchContext((Node *) lfirst(pvar), - econtext, - &(prm->isnull), - NULL); - pvar = lnext(pvar); - } - plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam)); - } - Assert(pvar == NIL); - - ExecReScan(plan, NULL, NULL); - - /* - * For all sublink types except EXPR_SUBLINK, the result is boolean as - * are the results of the combining operators. We combine results - * within a tuple (if there are multiple columns) using OR semantics - * if "useor" is true, AND semantics if not. We then combine results - * across tuples (if the subplan produces more than one) using OR - * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. - * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.) - * NULL results from the combining operators are handled according to - * the usual SQL semantics for OR and AND. The result for no input - * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for - * MULTIEXPR_SUBLINK. - * - * For EXPR_SUBLINK we require the subplan to produce no more than one - * tuple, else an error is raised. If zero tuples are produced, we - * return NULL. Assuming we get a tuple, we just return its first - * column (there can be only one non-junk column in this case). - */ - result = BoolGetDatum(subLinkType == ALL_SUBLINK); - *isNull = false; - - for (slot = ExecProcNode(plan, NULL); - !TupIsNull(slot); - slot = ExecProcNode(plan, NULL)) - { - HeapTuple tup = slot->val; - TupleDesc tdesc = slot->ttc_tupleDescriptor; - Datum rowresult = BoolGetDatum(!useor); - bool rownull = false; - int col = 1; - - if (subLinkType == EXISTS_SUBLINK) - { - found = true; - result = BoolGetDatum(true); - break; - } - - if (subLinkType == EXPR_SUBLINK) - { - /* cannot allow multiple input tuples for EXPR sublink */ - if (found) - elog(ERROR, "More than one tuple returned by a subselect used as an expression."); - found = true; - - /* - * We need to copy the subplan's tuple in case the result is - * of pass-by-ref type --- our return value will point into - * this copied tuple! Can't use the subplan's instance of the - * tuple since it won't still be valid after next - * ExecProcNode() call. node->curTuple keeps track of the - * copied tuple for eventual freeing. - */ - tup = heap_copytuple(tup); - if (node->curTuple) - heap_freetuple(node->curTuple); - node->curTuple = tup; - result = heap_getattr(tup, col, tdesc, isNull); - /* keep scanning subplan to make sure there's only one tuple */ - continue; - } - - /* cannot allow multiple input tuples for MULTIEXPR sublink either */ - if (subLinkType == MULTIEXPR_SUBLINK && found) - elog(ERROR, "More than one tuple returned by a subselect used as an expression."); - - found = true; - - /* - * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining - * operators for columns of tuple. - */ - foreach(lst, sublink->oper) - { - Expr *expr = (Expr *) lfirst(lst); - Const *con = lsecond(expr->args); - Datum expresult; - bool expnull; - - /* - * The righthand side of the expression should be either a - * Const or a function call or RelabelType node taking a Const - * as arg (these nodes represent run-time type coercions - * inserted by the parser to get to the input type needed by - * the operator). Find the Const node and insert the actual - * righthand-side value into it. - */ - if (!IsA(con, Const)) - { - switch (con->type) - { - case T_Expr: - con = lfirst(((Expr *) con)->args); - break; - case T_RelabelType: - con = (Const *) (((RelabelType *) con)->arg); - break; - default: - /* will fail below */ - break; - } - if (!IsA(con, Const)) - elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result"); - } - con->constvalue = heap_getattr(tup, col, tdesc, - &(con->constisnull)); - - /* - * Now we can eval the combining operator for this column. - */ - expresult = ExecEvalExprSwitchContext((Node *) expr, econtext, - &expnull, NULL); - - /* - * Combine the result into the row result as appropriate. - */ - if (col == 1) - { - rowresult = expresult; - rownull = expnull; - } - else if (useor) - { - /* combine within row per OR semantics */ - if (expnull) - rownull = true; - else if (DatumGetBool(expresult)) - { - rowresult = BoolGetDatum(true); - rownull = false; - break; /* needn't look at any more columns */ - } - } - else - { - /* combine within row per AND semantics */ - if (expnull) - rownull = true; - else if (!DatumGetBool(expresult)) - { - rowresult = BoolGetDatum(false); - rownull = false; - break; /* needn't look at any more columns */ - } - } - col++; - } - - if (subLinkType == ANY_SUBLINK) - { - /* combine across rows per OR semantics */ - if (rownull) - *isNull = true; - else if (DatumGetBool(rowresult)) - { - result = BoolGetDatum(true); - *isNull = false; - break; /* needn't look at any more rows */ - } - } - else if (subLinkType == ALL_SUBLINK) - { - /* combine across rows per AND semantics */ - if (rownull) - *isNull = true; - else if (!DatumGetBool(rowresult)) - { - result = BoolGetDatum(false); - *isNull = false; - break; /* needn't look at any more rows */ - } - } - else - { - /* must be MULTIEXPR_SUBLINK */ - result = rowresult; - *isNull = rownull; - } - } - - if (!found) - { - /* - * deal with empty subplan result. result/isNull were previously - * initialized correctly for all sublink types except EXPR and - * MULTIEXPR; for those, return NULL. - */ - if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK) - { - result = (Datum) 0; - *isNull = true; - } - } - - MemoryContextSwitchTo(oldcontext); - - return result; -} - -/* ---------------------------------------------------------------- - * ExecInitSubPlan - * - * ---------------------------------------------------------------- - */ -bool -ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent) -{ - EState *sp_estate = CreateExecutorState(); - - sp_estate->es_range_table = node->rtable; - sp_estate->es_param_list_info = estate->es_param_list_info; - sp_estate->es_param_exec_vals = estate->es_param_exec_vals; - sp_estate->es_tupleTable = - ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10); - sp_estate->es_snapshot = estate->es_snapshot; - - node->needShutdown = false; - node->curTuple = NULL; - - if (!ExecInitNode(node->plan, sp_estate, parent)) - return false; - - node->needShutdown = true; /* now we need to shutdown the subplan */ - - /* - * If this plan is un-correlated or undirect correlated one and want - * to set params for parent plan then prepare parameters. - */ - if (node->setParam != NIL) - { - List *lst; - - foreach(lst, node->setParam) - { - ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]); - - prm->execPlan = node; - } - - /* - * Note that in the case of un-correlated subqueries we don't care - * about setting parent->chgParam here: indices take care about - * it, for others - it doesn't matter... - */ - } - - return true; -} - -/* ---------------------------------------------------------------- - * ExecSetParamPlan - * - * Executes an InitPlan subplan and sets its output parameters. - * - * This is called from ExecEvalParam() when the value of a PARAM_EXEC - * parameter is requested and the param's execPlan field is set (indicating - * that the param has not yet been evaluated). This allows lazy evaluation - * of initplans: we don't run the subplan until/unless we need its output. - * Note that this routine MUST clear the execPlan fields of the plan's - * output parameters after evaluating them! - * ---------------------------------------------------------------- - */ -void -ExecSetParamPlan(SubPlan *node, ExprContext *econtext) -{ - Plan *plan = node->plan; - SubLink *sublink = node->sublink; - MemoryContext oldcontext; - TupleTableSlot *slot; - List *lst; - bool found = false; - - /* - * We are probably in a short-lived expression-evaluation context. - * Switch to longer-lived per-query context. - */ - oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); - - if (sublink->subLinkType == ANY_SUBLINK || - sublink->subLinkType == ALL_SUBLINK) - elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported"); - - if (plan->chgParam != NULL) - ExecReScan(plan, NULL, NULL); - - for (slot = ExecProcNode(plan, NULL); - !TupIsNull(slot); - slot = ExecProcNode(plan, NULL)) - { - HeapTuple tup = slot->val; - TupleDesc tdesc = slot->ttc_tupleDescriptor; - int i = 1; - - if (sublink->subLinkType == EXISTS_SUBLINK) - { - ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]); - - prm->execPlan = NULL; - prm->value = BoolGetDatum(true); - prm->isnull = false; - found = true; - break; - } - - if (found && - (sublink->subLinkType == EXPR_SUBLINK || - sublink->subLinkType == MULTIEXPR_SUBLINK)) - elog(ERROR, "More than one tuple returned by a subselect used as an expression."); - - found = true; - - /* - * We need to copy the subplan's tuple in case any of the params - * are pass-by-ref type --- the pointers stored in the param - * structs will point at this copied tuple! node->curTuple keeps - * track of the copied tuple for eventual freeing. - */ - tup = heap_copytuple(tup); - if (node->curTuple) - heap_freetuple(node->curTuple); - node->curTuple = tup; - - foreach(lst, node->setParam) - { - ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]); - - prm->execPlan = NULL; - prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull)); - i++; - } - } - - if (!found) - { - if (sublink->subLinkType == EXISTS_SUBLINK) - { - ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]); - - prm->execPlan = NULL; - prm->value = BoolGetDatum(false); - prm->isnull = false; - } - else - { - foreach(lst, node->setParam) - { - ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]); - - prm->execPlan = NULL; - prm->value = (Datum) 0; - prm->isnull = true; - } - } - } - - if (plan->extParam == NULL) /* un-correlated ... */ - { - ExecEndNode(plan, NULL); - node->needShutdown = false; - } - - MemoryContextSwitchTo(oldcontext); -} - -/* ---------------------------------------------------------------- - * ExecEndSubPlan - * ---------------------------------------------------------------- - */ -void -ExecEndSubPlan(SubPlan *node) -{ - if (node->needShutdown) - { - ExecEndNode(node->plan, NULL); - node->needShutdown = false; - } - if (node->curTuple) - { - heap_freetuple(node->curTuple); - node->curTuple = NULL; - } -} - -void -ExecReScanSetParamPlan(SubPlan *node, Plan *parent) -{ - Plan *plan = node->plan; - List *lst; - - if (node->parParam != NULL) - elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet"); - if (node->setParam == NULL) - elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL"); - if (plan->extParam == NULL) - elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL"); - - /* - * Don't actual re-scan: ExecSetParamPlan does re-scan if - * node->plan->chgParam is not NULL... ExecReScan (plan, NULL, NULL); - */ - - /* - * Mark this subplan's output parameters as needing recalculation - */ - foreach(lst, node->setParam) - { - ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]); - - prm->execPlan = node; - } - - parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam)); - -} |