aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeSubplan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeSubplan.c')
-rw-r--r--src/backend/executor/nodeSubplan.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
new file mode 100644
index 00000000000..610f0a09643
--- /dev/null
+++ b/src/backend/executor/nodeSubplan.c
@@ -0,0 +1,280 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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));
+
+}