diff options
author | Bruce Momjian <bruce@momjian.us> | 1998-09-01 04:40:42 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1998-09-01 04:40:42 +0000 |
commit | fa1a8d6a97068295fe30ac646aec7493a6305bc2 (patch) | |
tree | 645f7cef3c78fbab4d6d7bbc7c9a61ad2893d273 /src/backend/executor/nodeAgg.c | |
parent | af74855a608da4cd7ef88ceb2241ec1c75537f39 (diff) | |
download | postgresql-fa1a8d6a97068295fe30ac646aec7493a6305bc2.tar.gz postgresql-fa1a8d6a97068295fe30ac646aec7493a6305bc2.zip |
OK, folks, here is the pgindent output.
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r-- | src/backend/executor/nodeAgg.c | 647 |
1 files changed, 328 insertions, 319 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 28f50bdd4f4..c7e69d1a72f 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -109,388 +109,397 @@ ExecAgg(Agg *node) bool isNull = FALSE, isNull1 = FALSE, isNull2 = FALSE; - bool qual_result; - + bool qual_result; + /* --------------------- * get state info from node * --------------------- */ - /* We loop retrieving groups until we find one matching node->plan.qual */ - do { + /* + * We loop retrieving groups until we find one matching + * node->plan.qual + */ + do + { - aggstate = node->aggstate; - if (aggstate->agg_done) - return NULL; + aggstate = node->aggstate; + if (aggstate->agg_done) + return NULL; - estate = node->plan.state; - econtext = aggstate->csstate.cstate.cs_ExprContext; + estate = node->plan.state; + econtext = aggstate->csstate.cstate.cs_ExprContext; - nagg = length(node->aggs); + nagg = length(node->aggs); - aggregates = (Aggreg **) palloc(sizeof(Aggreg *) * nagg); + aggregates = (Aggreg **) palloc(sizeof(Aggreg *) * nagg); - /* take List* and make it an array that can be quickly indexed */ - alist = node->aggs; - for (i = 0; i < nagg; i++) - { - aggregates[i] = lfirst(alist); - aggregates[i]->aggno = i; - alist = lnext(alist); - } - - value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values; - nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls; + /* take List* and make it an array that can be quickly indexed */ + alist = node->aggs; + for (i = 0; i < nagg; i++) + { + aggregates[i] = lfirst(alist); + aggregates[i]->aggno = i; + alist = lnext(alist); + } - value2 = (Datum *) palloc(sizeof(Datum) * nagg); - MemSet(value2, 0, sizeof(Datum) * nagg); + value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values; + nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls; - aggFuncInfo = (AggFuncInfo *) palloc(sizeof(AggFuncInfo) * nagg); - MemSet(aggFuncInfo, 0, sizeof(AggFuncInfo) * nagg); + value2 = (Datum *) palloc(sizeof(Datum) * nagg); + MemSet(value2, 0, sizeof(Datum) * nagg); - noInitValue = (int *) palloc(sizeof(int) * nagg); - MemSet(noInitValue, 0, sizeof(noInitValue) * nagg); + aggFuncInfo = (AggFuncInfo *) palloc(sizeof(AggFuncInfo) * nagg); + MemSet(aggFuncInfo, 0, sizeof(AggFuncInfo) * nagg); - outerPlan = outerPlan(node); - oneTuple = NULL; + noInitValue = (int *) palloc(sizeof(int) * nagg); + MemSet(noInitValue, 0, sizeof(noInitValue) * nagg); - projInfo = aggstate->csstate.cstate.cs_ProjInfo; + outerPlan = outerPlan(node); + oneTuple = NULL; - for (i = 0; i < nagg; i++) - { - Aggreg *agg; - char *aggname; - HeapTuple aggTuple; - Form_pg_aggregate aggp; - Oid xfn1_oid, - xfn2_oid, - finalfn_oid; - - agg = aggregates[i]; - - /* --------------------- - * find transfer functions of all the aggregates and initialize - * their initial values - * --------------------- - */ - aggname = agg->aggname; - aggTuple = SearchSysCacheTuple(AGGNAME, - PointerGetDatum(aggname), - ObjectIdGetDatum(agg->basetype), - 0, 0); - if (!HeapTupleIsValid(aggTuple)) - elog(ERROR, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)", - aggname, - typeidTypeName(agg->basetype)); - aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple); - - xfn1_oid = aggp->aggtransfn1; - xfn2_oid = aggp->aggtransfn2; - finalfn_oid = aggp->aggfinalfn; - - if (OidIsValid(finalfn_oid)) - { - fmgr_info(finalfn_oid, &aggFuncInfo[i].finalfn); - aggFuncInfo[i].finalfn_oid = finalfn_oid; - } + projInfo = aggstate->csstate.cstate.cs_ProjInfo; - if (OidIsValid(xfn2_oid)) + for (i = 0; i < nagg; i++) { - fmgr_info(xfn2_oid, &aggFuncInfo[i].xfn2); - aggFuncInfo[i].xfn2_oid = xfn2_oid; - value2[i] = (Datum) AggNameGetInitVal((char *) aggname, - aggp->aggbasetype, - 2, - &isNull2); - /* ------------------------------------------ - * If there is a second transition function, its initial - * value must exist -- as it does not depend on data values, - * we have no other way of determining an initial value. - * ------------------------------------------ + Aggreg *agg; + char *aggname; + HeapTuple aggTuple; + Form_pg_aggregate aggp; + Oid xfn1_oid, + xfn2_oid, + finalfn_oid; + + agg = aggregates[i]; + + /* --------------------- + * find transfer functions of all the aggregates and initialize + * their initial values + * --------------------- */ - if (isNull2) - elog(ERROR, "ExecAgg: agginitval2 is null"); - } + aggname = agg->aggname; + aggTuple = SearchSysCacheTuple(AGGNAME, + PointerGetDatum(aggname), + ObjectIdGetDatum(agg->basetype), + 0, 0); + if (!HeapTupleIsValid(aggTuple)) + elog(ERROR, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)", + aggname, + typeidTypeName(agg->basetype)); + aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple); + + xfn1_oid = aggp->aggtransfn1; + xfn2_oid = aggp->aggtransfn2; + finalfn_oid = aggp->aggfinalfn; + + if (OidIsValid(finalfn_oid)) + { + fmgr_info(finalfn_oid, &aggFuncInfo[i].finalfn); + aggFuncInfo[i].finalfn_oid = finalfn_oid; + } - if (OidIsValid(xfn1_oid)) - { - fmgr_info(xfn1_oid, &aggFuncInfo[i].xfn1); - aggFuncInfo[i].xfn1_oid = xfn1_oid; - value1[i] = (Datum) AggNameGetInitVal((char *) aggname, - aggp->aggbasetype, - 1, - &isNull1); - - /* ------------------------------------------ - * If the initial value for the first transition function - * doesn't exist in the pg_aggregate table then we let - * the first value returned from the outer procNode become - * the initial value. (This is useful for aggregates like - * max{} and min{}.) - * ------------------------------------------ - */ - if (isNull1) + if (OidIsValid(xfn2_oid)) { - noInitValue[i] = 1; - nulls[i] = 1; + fmgr_info(xfn2_oid, &aggFuncInfo[i].xfn2); + aggFuncInfo[i].xfn2_oid = xfn2_oid; + value2[i] = (Datum) AggNameGetInitVal((char *) aggname, + aggp->aggbasetype, + 2, + &isNull2); + /* ------------------------------------------ + * If there is a second transition function, its initial + * value must exist -- as it does not depend on data values, + * we have no other way of determining an initial value. + * ------------------------------------------ + */ + if (isNull2) + elog(ERROR, "ExecAgg: agginitval2 is null"); } - } - } - - /* ---------------- - * for each tuple from the the outer plan, apply all the aggregates - * ---------------- - */ - for (;;) - { - HeapTuple outerTuple = NULL; - TupleTableSlot *outerslot; - - isNull = isNull1 = isNull2 = 0; - outerslot = ExecProcNode(outerPlan, (Plan *) node); - if (outerslot) - outerTuple = outerslot->val; - if (!HeapTupleIsValid(outerTuple)) - { - /* - * when the outerplan doesn't return a single tuple, create a - * dummy heaptuple anyway because we still need to return a - * valid aggregate value. The value returned will be the - * initial values of the transition functions - */ - if (nTuplesAgged == 0) + if (OidIsValid(xfn1_oid)) { - TupleDesc tupType; - Datum *tupValue; - char *null_array; - - tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor; - tupValue = projInfo->pi_tupValue; - - /* initially, set all the values to NULL */ - null_array = palloc(tupType->natts); - for (i = 0; i < tupType->natts; i++) - null_array[i] = 'n'; - oneTuple = heap_formtuple(tupType, tupValue, null_array); - pfree(null_array); + fmgr_info(xfn1_oid, &aggFuncInfo[i].xfn1); + aggFuncInfo[i].xfn1_oid = xfn1_oid; + value1[i] = (Datum) AggNameGetInitVal((char *) aggname, + aggp->aggbasetype, + 1, + &isNull1); + + /* ------------------------------------------ + * If the initial value for the first transition function + * doesn't exist in the pg_aggregate table then we let + * the first value returned from the outer procNode become + * the initial value. (This is useful for aggregates like + * max{} and min{}.) + * ------------------------------------------ + */ + if (isNull1) + { + noInitValue[i] = 1; + nulls[i] = 1; + } } - break; } - for (i = 0; i < nagg; i++) + /* ---------------- + * for each tuple from the the outer plan, apply all the aggregates + * ---------------- + */ + for (;;) { - AttrNumber attnum; - int2 attlen = 0; - Datum newVal = (Datum) NULL; - AggFuncInfo *aggfns = &aggFuncInfo[i]; - Datum args[2]; - Node *tagnode = NULL; - - switch (nodeTag(aggregates[i]->target)) + HeapTuple outerTuple = NULL; + TupleTableSlot *outerslot; + + isNull = isNull1 = isNull2 = 0; + outerslot = ExecProcNode(outerPlan, (Plan *) node); + if (outerslot) + outerTuple = outerslot->val; + if (!HeapTupleIsValid(outerTuple)) { - case T_Var: - tagnode = NULL; - newVal = aggGetAttr(outerslot, - aggregates[i], - &isNull); - break; - case T_Expr: - tagnode = ((Expr *) aggregates[i]->target)->oper; - econtext->ecxt_scantuple = outerslot; - newVal = ExecEvalExpr(aggregates[i]->target, econtext, - &isNull, &isDone); - break; - case T_Const: - tagnode = NULL; - econtext->ecxt_scantuple = outerslot; - newVal = ExecEvalExpr(aggregates[i]->target, econtext, - &isNull, &isDone); - break; - default: - elog(ERROR, "ExecAgg: Bad Agg->Target for Agg %d", i); - } - if (isNull && !aggregates[i]->usenulls) - continue; /* ignore this tuple for this agg */ + /* + * when the outerplan doesn't return a single tuple, + * create a dummy heaptuple anyway because we still need + * to return a valid aggregate value. The value returned + * will be the initial values of the transition functions + */ + if (nTuplesAgged == 0) + { + TupleDesc tupType; + Datum *tupValue; + char *null_array; + + tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor; + tupValue = projInfo->pi_tupValue; + + /* initially, set all the values to NULL */ + null_array = palloc(tupType->natts); + for (i = 0; i < tupType->natts; i++) + null_array[i] = 'n'; + oneTuple = heap_formtuple(tupType, tupValue, null_array); + pfree(null_array); + } + break; + } - if (aggfns->xfn1.fn_addr != NULL) + for (i = 0; i < nagg; i++) { - if (noInitValue[i]) + AttrNumber attnum; + int2 attlen = 0; + Datum newVal = (Datum) NULL; + AggFuncInfo *aggfns = &aggFuncInfo[i]; + Datum args[2]; + Node *tagnode = NULL; + + switch (nodeTag(aggregates[i]->target)) + { + case T_Var: + tagnode = NULL; + newVal = aggGetAttr(outerslot, + aggregates[i], + &isNull); + break; + case T_Expr: + tagnode = ((Expr *) aggregates[i]->target)->oper; + econtext->ecxt_scantuple = outerslot; + newVal = ExecEvalExpr(aggregates[i]->target, econtext, + &isNull, &isDone); + break; + case T_Const: + tagnode = NULL; + econtext->ecxt_scantuple = outerslot; + newVal = ExecEvalExpr(aggregates[i]->target, econtext, + &isNull, &isDone); + break; + default: + elog(ERROR, "ExecAgg: Bad Agg->Target for Agg %d", i); + } + + if (isNull && !aggregates[i]->usenulls) + continue; /* ignore this tuple for this agg */ + + if (aggfns->xfn1.fn_addr != NULL) { - int byVal = 0; - - /* - * value1 and value2 has not been initialized. This is - * the first non-NULL value. We use it as the initial - * value. - */ - - /* - * but we can't just use it straight, we have to make - * a copy of it since the tuple from which it came - * will be freed on the next iteration of the scan - */ - switch (nodeTag(aggregates[i]->target)) + if (noInitValue[i]) { - case T_Var: - attnum = ((Var *) aggregates[i]->target)->varattno; - attlen = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attlen; - byVal = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attbyval; - - break; - case T_Expr: - { - FunctionCachePtr fcache_ptr; - - if (nodeTag(tagnode) == T_Func) - fcache_ptr = ((Func *) tagnode)->func_fcache; - else - fcache_ptr = ((Oper *) tagnode)->op_fcache; - attlen = fcache_ptr->typlen; - byVal = fcache_ptr->typbyval; + int byVal = 0; + + /* + * value1 and value2 has not been initialized. + * This is the first non-NULL value. We use it as + * the initial value. + */ + + /* + * but we can't just use it straight, we have to + * make a copy of it since the tuple from which it + * came will be freed on the next iteration of the + * scan + */ + switch (nodeTag(aggregates[i]->target)) + { + case T_Var: + attnum = ((Var *) aggregates[i]->target)->varattno; + attlen = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attlen; + byVal = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attbyval; + + break; + case T_Expr: + { + FunctionCachePtr fcache_ptr; + + if (nodeTag(tagnode) == T_Func) + fcache_ptr = ((Func *) tagnode)->func_fcache; + else + fcache_ptr = ((Oper *) tagnode)->op_fcache; + attlen = fcache_ptr->typlen; + byVal = fcache_ptr->typbyval; + + break; + } + case T_Const: + attlen = ((Const *) aggregates[i]->target)->constlen; + byVal = ((Const *) aggregates[i]->target)->constbyval; break; - } - case T_Const: - attlen = ((Const *) aggregates[i]->target)->constlen; - byVal = ((Const *) aggregates[i]->target)->constbyval; - - break; - default: - elog(ERROR, "ExecAgg: Bad Agg->Target for Agg %d", i); + default: + elog(ERROR, "ExecAgg: Bad Agg->Target for Agg %d", i); + } + if (attlen == -1) + { + /* variable length */ + attlen = VARSIZE((struct varlena *) newVal); + } + value1[i] = (Datum) palloc(attlen); + if (byVal) + value1[i] = newVal; + else + memmove((char *) (value1[i]), (char *) newVal, attlen); + noInitValue[i] = 0; + nulls[i] = 0; } - if (attlen == -1) + else { - /* variable length */ - attlen = VARSIZE((struct varlena *) newVal); + + /* + * apply the transition functions. + */ + args[0] = value1[i]; + args[1] = newVal; + value1[i] = + (Datum) fmgr_c(&aggfns->xfn1, + (FmgrValues *) args, + &isNull1); + Assert(!isNull1); } - value1[i] = (Datum) palloc(attlen); - if (byVal) - value1[i] = newVal; - else - memmove((char *) (value1[i]), (char *) newVal, attlen); - noInitValue[i] = 0; - nulls[i] = 0; } - else + + if (aggfns->xfn2.fn_addr != NULL) { + Datum xfn2_val = value2[i]; - /* - * apply the transition functions. - */ - args[0] = value1[i]; - args[1] = newVal; - value1[i] = - (Datum) fmgr_c(&aggfns->xfn1, - (FmgrValues *) args, - &isNull1); - Assert(!isNull1); + value2[i] = + (Datum) fmgr_c(&aggfns->xfn2, + (FmgrValues *) &xfn2_val, &isNull2); + Assert(!isNull2); } } - if (aggfns->xfn2.fn_addr != NULL) - { - Datum xfn2_val = value2[i]; + /* + * keep this for the projection (we only need one of these - + * all the tuples we aggregate over share the same group + * column) + */ + if (!oneTuple) + oneTuple = heap_copytuple(outerslot->val); - value2[i] = - (Datum) fmgr_c(&aggfns->xfn2, - (FmgrValues *) &xfn2_val, &isNull2); - Assert(!isNull2); - } + nTuplesAgged++; } - /* - * keep this for the projection (we only need one of these - all - * the tuples we aggregate over share the same group column) + /* -------------- + * finalize the aggregate (if necessary), and get the resultant value + * -------------- */ - if (!oneTuple) - oneTuple = heap_copytuple(outerslot->val); - - nTuplesAgged++; - } - - /* -------------- - * finalize the aggregate (if necessary), and get the resultant value - * -------------- - */ - for (i = 0; i < nagg; i++) - { - char *args[2]; - AggFuncInfo *aggfns = &aggFuncInfo[i]; - - if (noInitValue[i]) + for (i = 0; i < nagg; i++) { + char *args[2]; + AggFuncInfo *aggfns = &aggFuncInfo[i]; - /* - * No values found for this agg; return current state. This - * seems to fix behavior for avg() aggregate. -tgl 12/96 - */ - } - else if (aggfns->finalfn.fn_addr != NULL && nTuplesAgged > 0) - { - if (aggfns->finalfn.fn_nargs > 1) + if (noInitValue[i]) { - args[0] = (char *) value1[i]; - args[1] = (char *) value2[i]; + + /* + * No values found for this agg; return current state. + * This seems to fix behavior for avg() aggregate. -tgl + * 12/96 + */ + } + else if (aggfns->finalfn.fn_addr != NULL && nTuplesAgged > 0) + { + if (aggfns->finalfn.fn_nargs > 1) + { + args[0] = (char *) value1[i]; + args[1] = (char *) value2[i]; + } + else if (aggfns->xfn1.fn_addr != NULL) + args[0] = (char *) value1[i]; + else if (aggfns->xfn2.fn_addr != NULL) + args[0] = (char *) value2[i]; + else + elog(NOTICE, "ExecAgg: no valid transition functions??"); + value1[i] = (Datum) fmgr_c(&aggfns->finalfn, + (FmgrValues *) args, &(nulls[i])); } else if (aggfns->xfn1.fn_addr != NULL) - args[0] = (char *) value1[i]; + { + + /* + * value in the right place, ignore. (If you remove this + * case, fix the else part. -ay 2/95) + */ + } else if (aggfns->xfn2.fn_addr != NULL) - args[0] = (char *) value2[i]; + value1[i] = value2[i]; else - elog(NOTICE, "ExecAgg: no valid transition functions??"); - value1[i] = (Datum) fmgr_c(&aggfns->finalfn, - (FmgrValues *) args, &(nulls[i])); + elog(ERROR, "ExecAgg: no valid transition functions??"); } - else if (aggfns->xfn1.fn_addr != NULL) - { - /* - * value in the right place, ignore. (If you remove this case, - * fix the else part. -ay 2/95) - */ + /* + * whether the aggregation is done depends on whether we are doing + * aggregation over groups or the entire table + */ + if (nodeTag(outerPlan) == T_Group) + { + /* aggregation over groups */ + aggstate->agg_done = ((Group *) outerPlan)->grpstate->grp_done; } - else if (aggfns->xfn2.fn_addr != NULL) - value1[i] = value2[i]; else - elog(ERROR, "ExecAgg: no valid transition functions??"); - } + aggstate->agg_done = TRUE; - /* - * whether the aggregation is done depends on whether we are doing - * aggregation over groups or the entire table - */ - if (nodeTag(outerPlan) == T_Group) - { - /* aggregation over groups */ - aggstate->agg_done = ((Group *) outerPlan)->grpstate->grp_done; - } - else - aggstate->agg_done = TRUE; + /* ---------------- + * form a projection tuple, store it in the result tuple + * slot and return it. + * ---------------- + */ - /* ---------------- - * form a projection tuple, store it in the result tuple - * slot and return it. - * ---------------- - */ - - ExecStoreTuple(oneTuple, - aggstate->csstate.css_ScanTupleSlot, - InvalidBuffer, - false); - econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot; - - resultSlot = ExecProject(projInfo, &isDone); - - /* As long as the retrieved group does not match the qualifications it is ignored and - * the next group is fetched */ - qual_result=ExecQual(fix_opids(node->plan.qual),econtext); - if (oneTuple) - pfree(oneTuple); - } - while((node->plan.qual!=NULL) && (qual_result!=true)); + ExecStoreTuple(oneTuple, + aggstate->csstate.css_ScanTupleSlot, + InvalidBuffer, + false); + econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot; + + resultSlot = ExecProject(projInfo, &isDone); + + /* + * As long as the retrieved group does not match the + * qualifications it is ignored and the next group is fetched + */ + qual_result = ExecQual(fix_opids(node->plan.qual), econtext); + if (oneTuple) + pfree(oneTuple); + } + while ((node->plan.qual != NULL) && (qual_result != true)); return resultSlot; } |