aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execQual.c8
-rw-r--r--src/backend/executor/nodeAgg.c223
-rw-r--r--src/backend/executor/nodeSubplan.c498
3 files changed, 487 insertions, 242 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 8dac4b2e440..e729344060e 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.130 2003/05/28 22:32:49 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.131 2003/06/24 23:14:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1528,17 +1528,17 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
{
/* Check other sub-arrays are compatible */
if (elem_ndims != ARR_NDIM(array))
- elog(ERROR, "Multiple dimension arrays must have array "
+ elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching number of dimensions");
if (memcmp(elem_dims, ARR_DIMS(array),
elem_ndims * sizeof(int)) != 0)
- elog(ERROR, "Multiple dimension arrays must have array "
+ elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching dimensions");
if (memcmp(elem_lbs, ARR_LBOUND(array),
elem_ndims * sizeof(int)) != 0)
- elog(ERROR, "Multiple dimension arrays must have array "
+ elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching dimensions");
}
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index d0dd6b31c99..dc8c1554bb0 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.107 2003/06/22 22:04:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.108 2003/06/24 23:14:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -58,6 +58,7 @@
#include "executor/executor.h"
#include "executor/nodeAgg.h"
#include "miscadmin.h"
+#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
@@ -212,7 +213,7 @@ static TupleTableSlot *agg_retrieve_direct(AggState *aggstate);
static void agg_fill_hash_table(AggState *aggstate);
static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate);
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
-
+static Oid resolve_type(Oid type_to_resolve, Oid context_type);
/*
* Initialize all aggregates for a new group of input values.
@@ -351,14 +352,12 @@ advance_transition_function(AggState *aggstate,
fcinfo.context = NULL;
fcinfo.resultinfo = NULL;
fcinfo.isnull = false;
-
fcinfo.flinfo = &peraggstate->transfn;
fcinfo.nargs = 2;
fcinfo.arg[0] = pergroupstate->transValue;
fcinfo.argnull[0] = pergroupstate->transValueIsNull;
fcinfo.arg[1] = newVal;
fcinfo.argnull[1] = isNull;
-
newVal = FunctionCallInvoke(&fcinfo);
/*
@@ -1187,7 +1186,21 @@ ExecInitAgg(Agg *node, EState *estate)
AclResult aclresult;
Oid transfn_oid,
finalfn_oid;
+ FuncExpr *transfnexpr,
+ *finalfnexpr;
Datum textInitVal;
+ List *fargs;
+ Oid agg_rt_type;
+ Oid *transfn_arg_types;
+ List *transfn_args = NIL;
+ int transfn_nargs;
+ Oid transfn_ret_type;
+ Oid *finalfn_arg_types = NULL;
+ List *finalfn_args = NIL;
+ Oid finalfn_ret_type = InvalidOid;
+ int finalfn_nargs = 0;
+ Node *arg0;
+ Node *arg1;
int i;
/* Planner should have assigned aggregate to correct level */
@@ -1238,6 +1251,166 @@ ExecInitAgg(Agg *node, EState *estate)
&peraggstate->transtypeLen,
&peraggstate->transtypeByVal);
+ peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
+ peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
+
+ /* get the runtime aggregate argument type */
+ fargs = aggref->args;
+ agg_rt_type = exprType((Node *) nth(0, fargs));
+
+ /* get the transition function argument and return types */
+ transfn_ret_type = get_func_rettype(transfn_oid);
+ transfn_arg_types = get_func_argtypes(transfn_oid, &transfn_nargs);
+
+ /* resolve any polymorphic types */
+ if (transfn_nargs == 2)
+ /* base type was not ANY */
+ {
+ if (transfn_arg_types[1] == ANYARRAYOID ||
+ transfn_arg_types[1] == ANYELEMENTOID)
+ transfn_arg_types[1] = agg_rt_type;
+
+ transfn_arg_types[0] = resolve_type(transfn_arg_types[0],
+ agg_rt_type);
+
+ /*
+ * Build arg list to use on the transfn FuncExpr node. We really
+ * only care that the node type is correct so that the transfn
+ * can discover the actual argument types at runtime using
+ * get_fn_expr_argtype()
+ */
+ arg0 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[0],
+ -1, COERCE_DONTCARE);
+ arg1 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[1],
+ -1, COERCE_DONTCARE);
+ transfn_args = makeList2(arg0, arg1);
+
+ /*
+ * the state transition function always returns the same type
+ * as its first argument
+ */
+ if (transfn_ret_type == ANYARRAYOID ||
+ transfn_ret_type == ANYELEMENTOID)
+ transfn_ret_type = transfn_arg_types[0];
+ }
+ else if (transfn_nargs == 1)
+ /*
+ * base type was ANY, therefore the aggregate return type should
+ * be non-polymorphic
+ */
+ {
+ Oid finaltype = get_func_rettype(aggref->aggfnoid);
+
+ /*
+ * this should have been prevented in AggregateCreate,
+ * but check anyway
+ */
+ if (finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID)
+ elog(ERROR, "aggregate with base type ANY must have a " \
+ "non-polymorphic return type");
+
+ /* see if we have a final function */
+ if (OidIsValid(finalfn_oid))
+ {
+ finalfn_arg_types = get_func_argtypes(finalfn_oid, &finalfn_nargs);
+ if (finalfn_nargs != 1)
+ elog(ERROR, "final function takes unexpected number " \
+ "of arguments: %d", finalfn_nargs);
+
+ /*
+ * final function argument is always the same as the state
+ * function return type
+ */
+ if (finalfn_arg_types[0] != ANYARRAYOID &&
+ finalfn_arg_types[0] != ANYELEMENTOID)
+ {
+ /* if it is not ambiguous, use it */
+ transfn_ret_type = finalfn_arg_types[0];
+ }
+ else
+ {
+ /* if it is ambiguous, try to derive it */
+ finalfn_ret_type = finaltype;
+ finalfn_arg_types[0] = resolve_type(finalfn_arg_types[0],
+ finalfn_ret_type);
+ transfn_ret_type = finalfn_arg_types[0];
+ }
+ }
+ else
+ transfn_ret_type = finaltype;
+
+ transfn_arg_types[0] = resolve_type(transfn_arg_types[0],
+ transfn_ret_type);
+
+ /*
+ * Build arg list to use on the transfn FuncExpr node. We really
+ * only care that the node type is correct so that the transfn
+ * can discover the actual argument types at runtime using
+ * get_fn_expr_argtype()
+ */
+ arg0 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[0],
+ -1, COERCE_DONTCARE);
+ transfn_args = makeList1(arg0);
+ }
+ else
+ elog(ERROR, "state transition function takes unexpected number " \
+ "of arguments: %d", transfn_nargs);
+
+ if (OidIsValid(finalfn_oid))
+ {
+ /* get the final function argument and return types */
+ if (finalfn_ret_type == InvalidOid)
+ finalfn_ret_type = get_func_rettype(finalfn_oid);
+
+ if (!finalfn_arg_types)
+ {
+ finalfn_arg_types = get_func_argtypes(finalfn_oid, &finalfn_nargs);
+ if (finalfn_nargs != 1)
+ elog(ERROR, "final function takes unexpected number " \
+ "of arguments: %d", finalfn_nargs);
+ }
+
+ /*
+ * final function argument is always the same as the state
+ * function return type, which by now should have been resolved
+ */
+ if (finalfn_arg_types[0] == ANYARRAYOID ||
+ finalfn_arg_types[0] == ANYELEMENTOID)
+ finalfn_arg_types[0] = transfn_ret_type;
+
+ /*
+ * Build arg list to use on the finalfn FuncExpr node. We really
+ * only care that the node type is correct so that the finalfn
+ * can discover the actual argument type at runtime using
+ * get_fn_expr_argtype()
+ */
+ arg0 = (Node *) makeRelabelType((Expr *) NULL, finalfn_arg_types[0],
+ -1, COERCE_DONTCARE);
+ finalfn_args = makeList1(arg0);
+
+ finalfn_ret_type = resolve_type(finalfn_ret_type,
+ finalfn_arg_types[0]);
+ }
+
+ fmgr_info(transfn_oid, &peraggstate->transfn);
+ transfnexpr = (FuncExpr *) make_funcclause(transfn_oid,
+ transfn_ret_type,
+ false, /* cannot be a set */
+ COERCE_DONTCARE, /* to match any user expr */
+ transfn_args);
+ peraggstate->transfn.fn_expr = (Node *) transfnexpr;
+
+ if (OidIsValid(finalfn_oid))
+ {
+ fmgr_info(finalfn_oid, &peraggstate->finalfn);
+ finalfnexpr = (FuncExpr *) make_funcclause(finalfn_oid,
+ finalfn_ret_type,
+ false, /* cannot be a set */
+ COERCE_DONTCARE, /* to match any user expr */
+ finalfn_args);
+ peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
+ }
+
/*
* initval is potentially null, so don't try to access it as a
* struct field. Must do it the hard way with SysCacheGetAttr.
@@ -1250,14 +1423,7 @@ ExecInitAgg(Agg *node, EState *estate)
peraggstate->initValue = (Datum) 0;
else
peraggstate->initValue = GetAggInitVal(textInitVal,
- aggform->aggtranstype);
-
- peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
- peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
-
- fmgr_info(transfn_oid, &peraggstate->transfn);
- if (OidIsValid(finalfn_oid))
- fmgr_info(finalfn_oid, &peraggstate->finalfn);
+ transfn_arg_types[0]);
/*
* If the transfn is strict and the initval is NULL, make sure
@@ -1469,3 +1635,36 @@ aggregate_dummy(PG_FUNCTION_ARGS)
fcinfo->flinfo->fn_oid);
return (Datum) 0; /* keep compiler quiet */
}
+
+static Oid
+resolve_type(Oid type_to_resolve, Oid context_type)
+{
+ Oid resolved_type;
+
+ if (context_type == ANYARRAYOID || context_type == ANYELEMENTOID)
+ resolved_type = type_to_resolve;
+ else if (type_to_resolve == ANYARRAYOID)
+ /* any array */
+ {
+ Oid context_type_arraytype = get_array_type(context_type);
+
+ if (context_type_arraytype != InvalidOid)
+ resolved_type = context_type_arraytype;
+ else
+ resolved_type = context_type;
+ }
+ else if (type_to_resolve == ANYELEMENTOID)
+ /* any element */
+ {
+ Oid context_type_elemtype = get_element_type(context_type);
+
+ if (context_type_elemtype != InvalidOid)
+ resolved_type = context_type_elemtype;
+ else
+ resolved_type = context_type;
+ }
+ else
+ resolved_type = type_to_resolve;
+
+ return resolved_type;
+}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 82502c985e8..62aaa7e8d43 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.47 2003/06/22 22:04:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.48 2003/06/24 23:14:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,23 +28,6 @@
#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);
@@ -54,13 +37,6 @@ 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
@@ -224,6 +200,7 @@ 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;
@@ -294,6 +271,11 @@ 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)
{
@@ -331,9 +313,6 @@ ExecScanSubPlan(SubPlanState *node,
if (subLinkType == ARRAY_SUBLINK)
{
- Datum dvalue;
- bool disnull;
-
found = true;
/* stash away current value */
dvalue = heap_getattr(tup, 1, tdesc, &disnull);
@@ -351,98 +330,163 @@ ExecScanSubPlan(SubPlanState *node,
found = true;
/*
- * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
- * operators for columns of tuple.
+ * 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.
*/
- plst = subplan->paramIds;
- foreach(lst, node->exprs)
+ if (!isExpr)
+ numelems = 1;
+ else
{
- 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);
- prmdata->value = heap_getattr(tup, col, tdesc,
- &(prmdata->isnull));
+ Oid expr_typeid = tdesc->attrs[0]->atttypid;
- /*
- * 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)
+ if (expr_typeid != subplan->exprtype)
{
- rowresult = expresult;
- rownull = expnull;
+ 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);
}
- else if (useOr)
+
+ /* get current value */
+ dvalue = heap_getattr(tup, 1, tdesc, &disnull);
+
+ /* XXX this will need work if/when arrays support NULL elements */
+ if (!disnull)
{
- /* combine within row per OR semantics */
- if (expnull)
- rownull = true;
- else if (DatumGetBool(expresult))
+ if (subplan->elemtype != InvalidOid)
{
- rowresult = BoolGetDatum(true);
- rownull = false;
- break; /* needn't look at any more columns */
+ ArrayType *v = DatumGetArrayTypeP(dvalue);
+
+ deconstruct_array(v, subplan->elemtype, subplan->elmlen,
+ subplan->elmbyval, subplan->elmalign,
+ &dvalues, &numelems);
+ }
+ else
+ {
+ numelems = 1;
+ dvalues = (Datum *) palloc(numelems * sizeof(Datum));
+ dvalues[0] = dvalue;
}
}
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 */
- }
+ numelems = 1;
+ dvalues = (Datum *) palloc(numelems * sizeof(Datum));
+ dvalues[0] = (Datum) 0;
}
- plst = lnext(plst);
- col++;
}
- if (subLinkType == ANY_SUBLINK)
+ for (elemnum = 0; elemnum < numelems; elemnum++)
{
- /* combine across rows per OR semantics */
- if (rownull)
- *isNull = true;
- else if (DatumGetBool(rowresult))
+ /*
+ * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
+ * operators for columns of tuple.
+ */
+ col = 1;
+ plst = subplan->paramIds;
+ foreach(lst, node->exprs)
{
- result = BoolGetDatum(true);
- *isNull = false;
- break; /* needn't look at any more rows */
+ 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++;
}
- }
- else if (subLinkType == ALL_SUBLINK)
- {
- /* combine across rows per AND semantics */
- if (rownull)
- *isNull = true;
- else if (!DatumGetBool(rowresult))
+
+ if (subLinkType == ANY_SUBLINK)
{
- result = BoolGetDatum(false);
- *isNull = false;
- break; /* needn't look at any more rows */
+ /* 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;
}
- }
- else
- {
- /* must be MULTIEXPR_SUBLINK */
- result = rowresult;
- *isNull = rownull;
}
}
@@ -480,6 +524,7 @@ 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;
@@ -487,6 +532,7 @@ buildSubPlanHash(SubPlanState *node)
MemoryContext oldcontext;
int nbuckets;
TupleTableSlot *slot;
+ TupleTableSlot *arrslot = NULL;
Assert(subplan->subLinkType == ANY_SUBLINK);
Assert(!subplan->useOr);
@@ -566,43 +612,139 @@ buildSubPlanHash(SubPlanState *node)
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
- int col = 1;
+ TupleDesc arrtdesc = NULL;
List *plst;
bool isnew;
+ int numelems;
+ int elemnum;
+ Datum dvalue;
+ Datum *dvalues = NULL;
+ bool disnull;
/*
- * Load up the Params representing the raw sub-select outputs,
- * then form the projection tuple to store in the hashtable.
+ * 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.
*/
- foreach(plst, subplan->paramIds)
+ if (!isExpr)
+ numelems = 1;
+ else
{
- 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;
+ 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;
+ }
- /*
- * 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))
- {
- (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
- node->havehashrows = true;
}
- else if (node->hashnulls)
+
+ for (elemnum = 0; elemnum < numelems; elemnum++)
{
- (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
- node->havenullrows = true;
+ 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;
+ }
}
/*
@@ -619,6 +761,8 @@ buildSubPlanHash(SubPlanState *node)
* have the potential for a double free attempt.
*/
ExecClearTuple(node->projRight->pi_slot);
+ if (arrslot)
+ ExecClearTuple(arrslot);
MemoryContextSwitchTo(oldcontext);
}
@@ -1099,101 +1243,3 @@ 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);
-}