diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 8 | ||||
-rw-r--r-- | src/backend/executor/nodeAgg.c | 223 | ||||
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 498 |
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); -} |