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.c498
1 files changed, 226 insertions, 272 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 62aaa7e8d43..64567377684 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.48 2003/06/24 23:14:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.49 2003/06/25 21:30:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,23 @@
#include "utils/datum.h"
#include "utils/lsyscache.h"
+
+typedef struct ArrayBuildState
+{
+ MemoryContext mcontext; /* where all the temp stuff is kept */
+ Datum *dvalues; /* array of accumulated Datums */
+ /*
+ * The allocated size of dvalues[] is always a multiple of
+ * ARRAY_ELEMS_CHUNKSIZE
+ */
+#define ARRAY_ELEMS_CHUNKSIZE 64
+ int nelems; /* number of valid Datums in dvalues[] */
+ Oid element_type; /* data type of the Datums */
+ int16 typlen; /* needed info about datatype */
+ bool typbyval;
+ char typalign;
+} ArrayBuildState;
+
static Datum ExecHashSubPlan(SubPlanState *node,
ExprContext *econtext,
bool *isNull);
@@ -37,6 +54,13 @@ static Datum ExecScanSubPlan(SubPlanState *node,
static void buildSubPlanHash(SubPlanState *node);
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
static bool tupleAllNulls(HeapTuple tuple);
+static ArrayBuildState *accumArrayResult(ArrayBuildState *astate,
+ Datum dvalue, bool disnull,
+ Oid element_type,
+ MemoryContext rcontext);
+static Datum makeArrayResult(ArrayBuildState *astate,
+ MemoryContext rcontext);
+
/* ----------------------------------------------------------------
* ExecSubPlan
@@ -200,7 +224,6 @@ ExecScanSubPlan(SubPlanState *node,
PlanState *planstate = node->planstate;
SubLinkType subLinkType = subplan->subLinkType;
bool useOr = subplan->useOr;
- bool isExpr = subplan->isExpr;
MemoryContext oldcontext;
TupleTableSlot *slot;
Datum result;
@@ -271,11 +294,6 @@ ExecScanSubPlan(SubPlanState *node,
bool rownull = false;
int col = 1;
List *plst;
- int numelems;
- int elemnum;
- Datum dvalue;
- Datum *dvalues = NULL;
- bool disnull;
if (subLinkType == EXISTS_SUBLINK)
{
@@ -313,6 +331,9 @@ ExecScanSubPlan(SubPlanState *node,
if (subLinkType == ARRAY_SUBLINK)
{
+ Datum dvalue;
+ bool disnull;
+
found = true;
/* stash away current value */
dvalue = heap_getattr(tup, 1, tdesc, &disnull);
@@ -330,164 +351,99 @@ ExecScanSubPlan(SubPlanState *node,
found = true;
/*
- * When isExpr is true, we have either a scalar expression or an
- * array. In the former case, this is no different than the !isExpr
- * case. In the latter case, iterate over the elements as if they
- * were from multiple input tuples.
+ * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
+ * operators for columns of tuple.
*/
- if (!isExpr)
- numelems = 1;
- else
+ plst = subplan->paramIds;
+ foreach(lst, node->exprs)
{
- Oid expr_typeid = tdesc->attrs[0]->atttypid;
+ ExprState *exprstate = (ExprState *) lfirst(lst);
+ int paramid = lfirsti(plst);
+ ParamExecData *prmdata;
+ Datum expresult;
+ bool expnull;
- if (expr_typeid != subplan->exprtype)
- {
- subplan->exprtype = expr_typeid;
- subplan->elemtype = get_element_type(expr_typeid);
-
- if (subplan->elemtype != InvalidOid)
- get_typlenbyvalalign(subplan->elemtype,
- &subplan->elmlen,
- &subplan->elmbyval,
- &subplan->elmalign);
- }
+ /*
+ * Load up the Param representing this column of the sub-select.
+ */
+ prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
+ Assert(prmdata->execPlan == NULL);
+ prmdata->value = heap_getattr(tup, col, tdesc,
+ &(prmdata->isnull));
- /* get current value */
- dvalue = heap_getattr(tup, 1, tdesc, &disnull);
+ /*
+ * Now we can eval the combining operator for this column.
+ */
+ expresult = ExecEvalExprSwitchContext(exprstate, econtext,
+ &expnull, NULL);
- /* XXX this will need work if/when arrays support NULL elements */
- if (!disnull)
+ /*
+ * Combine the result into the row result as appropriate.
+ */
+ if (col == 1)
{
- if (subplan->elemtype != InvalidOid)
- {
- ArrayType *v = DatumGetArrayTypeP(dvalue);
-
- deconstruct_array(v, subplan->elemtype, subplan->elmlen,
- subplan->elmbyval, subplan->elmalign,
- &dvalues, &numelems);
- }
- else
+ rowresult = expresult;
+ rownull = expnull;
+ }
+ else if (useOr)
+ {
+ /* combine within row per OR semantics */
+ if (expnull)
+ rownull = true;
+ else if (DatumGetBool(expresult))
{
- numelems = 1;
- dvalues = (Datum *) palloc(numelems * sizeof(Datum));
- dvalues[0] = dvalue;
+ rowresult = BoolGetDatum(true);
+ rownull = false;
+ break; /* needn't look at any more columns */
}
}
else
{
- numelems = 1;
- dvalues = (Datum *) palloc(numelems * sizeof(Datum));
- dvalues[0] = (Datum) 0;
+ /* 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 */
+ }
}
+ plst = lnext(plst);
+ col++;
}
- for (elemnum = 0; elemnum < numelems; elemnum++)
+ if (subLinkType == ANY_SUBLINK)
{
- /*
- * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
- * operators for columns of tuple.
- */
- col = 1;
- plst = subplan->paramIds;
- foreach(lst, node->exprs)
+ /* combine across rows per OR semantics */
+ if (rownull)
+ *isNull = true;
+ else if (DatumGetBool(rowresult))
{
- ExprState *exprstate = (ExprState *) lfirst(lst);
- int paramid = lfirsti(plst);
- ParamExecData *prmdata;
- Datum expresult;
- bool expnull;
-
- /*
- * Load up the Param representing this column of the sub-select.
- */
- prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
- Assert(prmdata->execPlan == NULL);
-
- if (!isExpr)
- prmdata->value = heap_getattr(tup, col, tdesc,
- &(prmdata->isnull));
- else
- {
- prmdata->value = dvalues[elemnum];
- prmdata->isnull = disnull;
- }
-
- /*
- * Now we can eval the combining operator for this column.
- */
- expresult = ExecEvalExprSwitchContext(exprstate, 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 */
- }
- }
-
- plst = lnext(plst);
- 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 */
- }
+ result = BoolGetDatum(true);
+ *isNull = false;
+ break; /* needn't look at any more rows */
}
- else
+ }
+ else if (subLinkType == ALL_SUBLINK)
+ {
+ /* combine across rows per AND semantics */
+ if (rownull)
+ *isNull = true;
+ else if (!DatumGetBool(rowresult))
{
- /* must be MULTIEXPR_SUBLINK */
- result = rowresult;
- *isNull = rownull;
+ result = BoolGetDatum(false);
+ *isNull = false;
+ break; /* needn't look at any more rows */
}
}
+ else
+ {
+ /* must be MULTIEXPR_SUBLINK */
+ result = rowresult;
+ *isNull = rownull;
+ }
}
if (!found)
@@ -524,7 +480,6 @@ static void
buildSubPlanHash(SubPlanState *node)
{
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
- bool isExpr = subplan->isExpr;
PlanState *planstate = node->planstate;
int ncols = length(node->exprs);
ExprContext *innerecontext = node->innerecontext;
@@ -532,7 +487,6 @@ buildSubPlanHash(SubPlanState *node)
MemoryContext oldcontext;
int nbuckets;
TupleTableSlot *slot;
- TupleTableSlot *arrslot = NULL;
Assert(subplan->subLinkType == ANY_SUBLINK);
Assert(!subplan->useOr);
@@ -612,139 +566,43 @@ buildSubPlanHash(SubPlanState *node)
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
- TupleDesc arrtdesc = NULL;
+ int col = 1;
List *plst;
bool isnew;
- int numelems;
- int elemnum;
- Datum dvalue;
- Datum *dvalues = NULL;
- bool disnull;
/*
- * When isExpr is true, we have either a scalar expression or an
- * array. In the former case, this is no different than the !isExpr
- * case. In the latter case, iterate over the elements as if they
- * were from multiple input tuples.
+ * Load up the Params representing the raw sub-select outputs,
+ * then form the projection tuple to store in the hashtable.
*/
- if (!isExpr)
- numelems = 1;
- else
+ foreach(plst, subplan->paramIds)
{
- Oid expr_typeid = tdesc->attrs[0]->atttypid;
-
- if (expr_typeid != subplan->exprtype)
- {
- subplan->exprtype = expr_typeid;
- subplan->elemtype = get_element_type(expr_typeid);
-
- if (subplan->elemtype != InvalidOid)
- get_typlenbyvalalign(subplan->elemtype,
- &subplan->elmlen,
- &subplan->elmbyval,
- &subplan->elmalign);
- }
-
- /* get current value */
- dvalue = heap_getattr(tup, 1, tdesc, &disnull);
-
- if (subplan->elemtype != InvalidOid)
- {
- TupleTable tupleTable;
- ArrayType *v = DatumGetArrayTypeP(dvalue);
-
- arrtdesc = CreateTemplateTupleDesc(1, false);
- TupleDescInitEntry(arrtdesc, 1, "elem", subplan->elemtype,
- -1, 0, false);
-
- tupleTable = ExecCreateTupleTable(1);
- arrslot = ExecAllocTableSlot(tupleTable);
- ExecSetSlotDescriptor(arrslot, arrtdesc, true);
-
- /* XXX this will need work if/when arrays support NULL elements */
- if (!disnull)
- {
- deconstruct_array(v, subplan->elemtype, subplan->elmlen,
- subplan->elmbyval, subplan->elmalign,
- &dvalues, &numelems);
- }
- else
- {
- numelems = 1;
- dvalues = (Datum *) palloc(numelems * sizeof(Datum));
- dvalues[0] = (Datum) 0;
- }
- }
- else
- {
- numelems = 1;
- dvalues = (Datum *) palloc(numelems * sizeof(Datum));
- dvalues[0] = dvalue;
- }
-
+ int paramid = lfirsti(plst);
+ ParamExecData *prmdata;
+
+ prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
+ Assert(prmdata->execPlan == NULL);
+ prmdata->value = heap_getattr(tup, col, tdesc,
+ &(prmdata->isnull));
+ col++;
}
+ slot = ExecProject(node->projRight, NULL);
+ tup = slot->val;
- for (elemnum = 0; elemnum < numelems; elemnum++)
+ /*
+ * If result contains any nulls, store separately or not at all.
+ * (Since we know the projection tuple has no junk columns, we
+ * can just look at the overall hasnull info bit, instead of
+ * groveling through the columns.)
+ */
+ if (HeapTupleNoNulls(tup))
{
- int col = 1;
-
- if (!isExpr || subplan->elemtype == InvalidOid)
- {
- /*
- * Load up the Params representing the raw sub-select outputs,
- * then form the projection tuple to store in the hashtable.
- */
- foreach(plst, subplan->paramIds)
- {
- int paramid = lfirsti(plst);
- ParamExecData *prmdata;
-
- prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
- Assert(prmdata->execPlan == NULL);
-
- prmdata->value = heap_getattr(tup, col, tdesc,
- &(prmdata->isnull));
-
- col++;
- }
- slot = ExecProject(node->projRight, NULL);
- tup = slot->val;
- }
- else
- {
- /*
- * For array type expressions, we need to build up our own
- * tuple and slot
- */
- char nullflag;
-
- nullflag = disnull ? 'n' : ' ';
- tup = heap_formtuple(arrtdesc, &dvalues[elemnum], &nullflag);
- arrslot = ExecStoreTuple(tup, arrslot, InvalidBuffer, true);
- }
-
- /*
- * If result contains any nulls, store separately or not at all.
- * (Since we know the projection tuple has no junk columns, we
- * can just look at the overall hasnull info bit, instead of
- * groveling through the columns.)
- */
- if (HeapTupleNoNulls(tup))
- {
- if (!isExpr)
- (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
- else
- (void) LookupTupleHashEntry(node->hashtable, arrslot, &isnew);
- node->havehashrows = true;
- }
- else if (node->hashnulls)
- {
- if (!isExpr)
- (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
- else
- (void) LookupTupleHashEntry(node->hashnulls, arrslot, &isnew);
- node->havenullrows = true;
- }
+ (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
+ node->havehashrows = true;
+ }
+ else if (node->hashnulls)
+ {
+ (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
+ node->havenullrows = true;
}
/*
@@ -761,8 +619,6 @@ buildSubPlanHash(SubPlanState *node)
* have the potential for a double free attempt.
*/
ExecClearTuple(node->projRight->pi_slot);
- if (arrslot)
- ExecClearTuple(arrslot);
MemoryContextSwitchTo(oldcontext);
}
@@ -1243,3 +1099,101 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
parent->chgParam = bms_add_member(parent->chgParam, paramid);
}
}
+
+/*
+ * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK
+ *
+ * astate is working state (NULL on first call)
+ * rcontext is where to keep working state
+ */
+static ArrayBuildState *
+accumArrayResult(ArrayBuildState *astate,
+ Datum dvalue, bool disnull,
+ Oid element_type,
+ MemoryContext rcontext)
+{
+ MemoryContext arr_context,
+ oldcontext;
+
+ if (astate == NULL)
+ {
+ /* First time through --- initialize */
+
+ /* Make a temporary context to hold all the junk */
+ arr_context = AllocSetContextCreate(rcontext,
+ "ARRAY_SUBLINK Result",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ oldcontext = MemoryContextSwitchTo(arr_context);
+ astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
+ astate->mcontext = arr_context;
+ astate->dvalues = (Datum *)
+ palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum));
+ astate->nelems = 0;
+ astate->element_type = element_type;
+ get_typlenbyvalalign(element_type,
+ &astate->typlen,
+ &astate->typbyval,
+ &astate->typalign);
+ }
+ else
+ {
+ oldcontext = MemoryContextSwitchTo(astate->mcontext);
+ Assert(astate->element_type == element_type);
+ /* enlarge dvalues[] if needed */
+ if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0)
+ astate->dvalues = (Datum *)
+ repalloc(astate->dvalues,
+ (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum));
+ }
+
+ if (disnull)
+ elog(ERROR, "NULL elements not allowed in Arrays");
+
+ /* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */
+ astate->dvalues[astate->nelems++] =
+ datumCopy(dvalue, astate->typbyval, astate->typlen);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ return astate;
+}
+
+/*
+ * makeArrayResult - produce final result of ARRAY_SUBLINK
+ *
+ * astate is working state (not NULL)
+ * rcontext is where to construct result
+ */
+static Datum
+makeArrayResult(ArrayBuildState *astate,
+ MemoryContext rcontext)
+{
+ ArrayType *result;
+ int dims[1];
+ int lbs[1];
+ MemoryContext oldcontext;
+
+ /* Build the final array result in rcontext */
+ oldcontext = MemoryContextSwitchTo(rcontext);
+
+ dims[0] = astate->nelems;
+ lbs[0] = 1;
+
+ result = construct_md_array(astate->dvalues,
+ 1,
+ dims,
+ lbs,
+ astate->element_type,
+ astate->typlen,
+ astate->typbyval,
+ astate->typalign);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ /* Clean up all the junk */
+ MemoryContextDelete(astate->mcontext);
+
+ return PointerGetDatum(result);
+}