/*------------------------------------------------------------------------- * * nodeSubplan.c-- * routines to support subselects * *------------------------------------------------------------------------- */ /* * INTERFACE ROUTINES * ExecSubPlan - process a subselect * ExecInitSubPlan - initialize a subselect * ExecEndSubPlan - shut down a subselect */ #include "postgres.h" #include "access/heapam.h" #include "tcop/pquery.h" #include "executor/executor.h" #include "executor/execdebug.h" #include "executor/nodeSubplan.h" /* ---------------------------------------------------------------- * ExecSubPlan(node) * * ---------------------------------------------------------------- */ Datum ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext) { Plan *plan = node->plan; SubLink *sublink = node->sublink; TupleTableSlot *slot; List *lst; bool result = false; bool found = false; if ( node->setParam != NULL ) elog (ERROR, "ExecSubPlan: can't set parent params from subquery"); /* * Set Params of this plan from parent plan correlation Vars */ if ( node->parParam != NULL ) { foreach (lst, node->parParam) { ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]); prm->value = ExecEvalExpr ((Node*) lfirst(pvar), econtext, &(prm->isnull), NULL); pvar = lnext (pvar); } plan->chgParam = nconc (plan->chgParam, listCopy(node->parParam)); } ExecReScan (plan, (ExprContext*) NULL, plan); for (slot = ExecProcNode (plan, plan); !TupIsNull(slot); slot = ExecProcNode (plan, plan)) { HeapTuple tup = slot->val; TupleDesc tdesc = slot->ttc_tupleDescriptor; int i = 1; if ( sublink->subLinkType == EXPR_SUBLINK && found ) { elog (ERROR, "ExecSubPlan: more than one tuple returned by expression subselect"); return ((Datum) false); } if ( sublink->subLinkType == EXISTS_SUBLINK ) return ((Datum) true); found = true; foreach (lst, sublink->oper) { Expr *expr = (Expr*) lfirst(lst); Const *con = lsecond(expr->args); bool isnull; con->constvalue = heap_getattr (tup, i, tdesc, &(con->constisnull)); result = (bool) ExecEvalExpr ((Node*) expr, econtext, &isnull, (bool*) NULL); if ( isnull ) result = false; if ( (!result && !(sublink->useor)) || (result && sublink->useor) ) break; i++; } if ( (!result && sublink->subLinkType == ALL_SUBLINK) || (result && sublink->subLinkType == ANY_SUBLINK) ) break; } return ((Datum) 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); pfree (sp_estate->es_refcount); sp_estate->es_refcount = estate->es_refcount; if ( !ExecInitNode (node->plan, sp_estate, NULL) ) return (false); node->shutdown = true; /* * If this plan is un-correlated or undirect correlated one and * want to set params for parent plan then prepare parameters. */ if ( node->setParam != NULL ) { 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 plan of node and sets parameters. * ---------------------------------------------------------------- */ void ExecSetParamPlan (SubPlan *node) { Plan *plan = node->plan; SubLink *sublink = node->sublink; TupleTableSlot *slot; List *lst; bool found = false; if ( sublink->subLinkType == ANY_SUBLINK || sublink->subLinkType == ALL_SUBLINK ) elog (ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported"); if ( plan->chgParam != NULL ) ExecReScan (plan, (ExprContext*) NULL, plan); for (slot = ExecProcNode (plan, plan); !TupIsNull(slot); slot = ExecProcNode (plan, plan)) { HeapTuple tup = slot->val; TupleDesc tdesc = slot->ttc_tupleDescriptor; int i = 1; if ( sublink->subLinkType == EXPR_SUBLINK && found ) { elog (ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect"); return; } found = true; if ( sublink->subLinkType == EXISTS_SUBLINK ) { ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]); prm->execPlan = NULL; prm->value = (Datum) true; prm->isnull = false; break; } 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 = (Datum) 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) NULL; prm->isnull = true; } } } if ( plan->extParam == NULL ) /* un-correlated ... */ { ExecEndNode (plan, plan); node->shutdown = false; } } /* ---------------------------------------------------------------- * ExecEndSubPlan * ---------------------------------------------------------------- */ void ExecEndSubPlan(SubPlan *node) { if ( node->shutdown ) { ExecEndNode (node->plan, node->plan); node->shutdown = false; } } 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, plan); */ 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)); }