Index: src/backend/catalog/pg_aggregate.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v retrieving revision 1.81 diff -c -r1.81 pg_aggregate.c *** src/backend/catalog/pg_aggregate.c 14 Jul 2006 14:52:17 -0000 1.81 --- src/backend/catalog/pg_aggregate.c 25 Jul 2006 09:12:37 -0000 *************** *** 42,48 **** void AggregateCreate(const char *aggName, Oid aggNamespace, ! Oid aggBaseType, List *aggtransfnName, List *aggfinalfnName, List *aggsortopName, --- 42,49 ---- void AggregateCreate(const char *aggName, Oid aggNamespace, ! Oid *aggBaseTypeArray, ! int numArgs, List *aggtransfnName, List *aggfinalfnName, List *aggsortopName, *************** *** 59,71 **** Oid sortop = InvalidOid; /* can be omitted */ Oid rettype; Oid finaltype; ! Oid fnArgs[2]; /* we only deal with 1- and 2-arg fns */ int nargs_transfn; Oid procOid; TupleDesc tupDesc; int i; ObjectAddress myself, referenced; /* sanity checks (caller should have caught these) */ if (!aggName) --- 60,74 ---- Oid sortop = InvalidOid; /* can be omitted */ Oid rettype; Oid finaltype; ! Oid *fnArgs; int nargs_transfn; Oid procOid; TupleDesc tupDesc; int i; ObjectAddress myself, referenced; + bool hasAnyArrElOids = false,/* ANYARRAYOID or ANYELEMENTOID */ + hasAnyOids = false; /* ANYOID */ /* sanity checks (caller should have caught these) */ if (!aggName) *************** *** 74,99 **** if (!aggtransfnName) elog(ERROR, "aggregate must have a transition function"); /* * If transtype is polymorphic, basetype must be polymorphic also; else we * will have no way to deduce the actual transtype. */ ! if ((aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID) && ! !(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine transition data type"), errdetail("An aggregate using \"anyarray\" or \"anyelement\" as " "transition type must have one of them as its base type."))); /* handle transfn */ fnArgs[0] = aggTransType; ! if (aggBaseType == ANYOID) nargs_transfn = 1; else { ! fnArgs[1] = aggBaseType; ! nargs_transfn = 2; } transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs, &rettype); --- 77,135 ---- if (!aggtransfnName) elog(ERROR, "aggregate must have a transition function"); + for(i = 0 ; i < numArgs ; i++) + { + if ((aggBaseTypeArray[i] == ANYARRAYOID) || + (aggBaseTypeArray[i] == ANYELEMENTOID)) + { + hasAnyArrElOids = true; + } + else if (aggBaseTypeArray[i] == ANYOID) + { + hasAnyOids = true; + } + } + /* * If transtype is polymorphic, basetype must be polymorphic also; else we * will have no way to deduce the actual transtype. */ ! if ((!hasAnyArrElOids) && ! (aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID)) ! { ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine transition data type"), errdetail("An aggregate using \"anyarray\" or \"anyelement\" as " "transition type must have one of them as its base type."))); + } + + /* + * Currently I disallow the ANYOID types in multi-argument aggregates + * Just because I don't see any sense in that ,and because the standart + * (if I understand correctly) doesn't allow "*" arguments in polyArgAggs + */ + + if ((hasAnyOids) && (numArgs > 1)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("The ANYOID types are not allowed in multi argument aggregates"))); + + } /* handle transfn */ + fnArgs = palloc((numArgs + 1) * sizeof(Oid)); fnArgs[0] = aggTransType; ! if (aggBaseTypeArray[0] == ANYOID) nargs_transfn = 1; else { ! for(i = 1 ; i <= numArgs; i++) ! { ! fnArgs[i] = aggBaseTypeArray[i - 1]; ! } ! nargs_transfn = numArgs + 1; } transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs, &rettype); *************** *** 129,135 **** */ if (proc->proisstrict && agginitval == NULL) { ! if (!IsBinaryCoercible(aggBaseType, aggTransType)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type"))); --- 165,171 ---- */ if (proc->proisstrict && agginitval == NULL) { ! if (!IsBinaryCoercible(aggBaseTypeArray[0], aggTransType)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type"))); *************** *** 160,167 **** * that itself violates the rule against polymorphic result with no * polymorphic input.) */ ! if ((finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID) && ! !(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot determine result data type"), --- 196,203 ---- * that itself violates the rule against polymorphic result with no * polymorphic input.) */ ! if ((!hasAnyArrElOids)&& ! (finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot determine result data type"), *************** *** 170,184 **** /* handle sortop, if supplied */ if (aggsortopName) sortop = LookupOperName(NULL, aggsortopName, ! aggBaseType, aggBaseType, false, -1); ! /* * Everything looks okay. Try to create the pg_proc entry for the * aggregate. (This could fail if there's already a conflicting entry.) */ ! fnArgs[0] = aggBaseType; procOid = ProcedureCreate(aggName, aggNamespace, --- 206,228 ---- /* handle sortop, if supplied */ if (aggsortopName) + { + if (numArgs != 1) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("The sort operator cannot be used in" + " multi argument aggregates"))); + } sortop = LookupOperName(NULL, aggsortopName, ! aggBaseTypeArray[0], aggBaseTypeArray[0], false, -1); ! } /* * Everything looks okay. Try to create the pg_proc entry for the * aggregate. (This could fail if there's already a conflicting entry.) */ ! procOid = ProcedureCreate(aggName, aggNamespace, *************** *** 195,201 **** false, /* isStrict (not needed for agg) */ PROVOLATILE_IMMUTABLE, /* volatility (not * needed for agg) */ ! buildoidvector(fnArgs, 1), /* paramTypes */ PointerGetDatum(NULL), /* allParamTypes */ PointerGetDatum(NULL), /* parameterModes */ PointerGetDatum(NULL)); /* parameterNames */ --- 239,246 ---- false, /* isStrict (not needed for agg) */ PROVOLATILE_IMMUTABLE, /* volatility (not * needed for agg) */ ! buildoidvector(aggBaseTypeArray, ! numArgs), /* paramTypes */ PointerGetDatum(NULL), /* allParamTypes */ PointerGetDatum(NULL), /* parameterModes */ PointerGetDatum(NULL)); /* parameterNames */ *************** *** 279,284 **** --- 324,331 ---- Oid *true_oid_array; FuncDetailCode fdresult; AclResult aclresult; + int i; + bool allANY = true; /* * func_get_detail looks up the function in the catalogs, does *************** *** 302,315 **** (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function %s returns a set", func_signature_string(fnName, nargs, input_types)))); /* * If the given type(s) are all polymorphic, there's nothing we can check. * Otherwise, enforce consistency, and possibly refine the result type. */ ! if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) && ! (nargs == 1 || ! (input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID))) { /* nothing to check here */ } --- 349,370 ---- (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function %s returns a set", func_signature_string(fnName, nargs, input_types)))); + + for (i = 0; i < nargs ; i++) + { + if (input_types[i] != ANYARRAYOID && + input_types[i] != ANYELEMENTOID) + { + allANY = false; + break; + } + } /* * If the given type(s) are all polymorphic, there's nothing we can check. * Otherwise, enforce consistency, and possibly refine the result type. */ ! if (allANY) { /* nothing to check here */ } *************** *** 325,346 **** * func_get_detail will find functions requiring run-time argument type * coercion, but nodeAgg.c isn't prepared to deal with that */ ! if (true_oid_array[0] != ANYARRAYOID && ! true_oid_array[0] != ANYELEMENTOID && ! !IsBinaryCoercible(input_types[0], true_oid_array[0])) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("function %s requires run-time type coercion", ! func_signature_string(fnName, nargs, true_oid_array)))); ! ! if (nargs == 2 && ! true_oid_array[1] != ANYARRAYOID && ! true_oid_array[1] != ANYELEMENTOID && ! !IsBinaryCoercible(input_types[1], true_oid_array[1])) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("function %s requires run-time type coercion", ! func_signature_string(fnName, nargs, true_oid_array)))); /* Check aggregate creator has permission to call the function */ aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE); --- 380,397 ---- * func_get_detail will find functions requiring run-time argument type * coercion, but nodeAgg.c isn't prepared to deal with that */ ! for (i = 0; i < nargs; i++) ! { ! if (true_oid_array[i] != ANYARRAYOID && ! true_oid_array[i] != ANYELEMENTOID && ! !IsBinaryCoercible(input_types[i], true_oid_array[i])) ! { ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("function %s requires run-time type coercion", ! func_signature_string(fnName, nargs, true_oid_array)))); ! } ! } /* Check aggregate creator has permission to call the function */ aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE); Index: src/backend/commands/aggregatecmds.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v retrieving revision 1.37 diff -c -r1.37 aggregatecmds.c *** src/backend/commands/aggregatecmds.c 14 Jul 2006 14:52:18 -0000 1.37 --- src/backend/commands/aggregatecmds.c 25 Jul 2006 09:12:38 -0000 *************** *** 57,65 **** TypeName *baseType = NULL; TypeName *transType = NULL; char *initval = NULL; ! Oid baseTypeId; Oid transTypeId; ListCell *pl; /* Convert list of names to a name and namespace */ aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName); --- 57,66 ---- TypeName *baseType = NULL; TypeName *transType = NULL; char *initval = NULL; ! Oid *baseTypeIdArray; Oid transTypeId; ListCell *pl; + int numArgs; /* Convert list of names to a name and namespace */ aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName); *************** *** 131,146 **** (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregate input type must be specified"))); if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0) ! baseTypeId = ANYOID; else ! baseTypeId = typenameTypeId(NULL, baseType); } else { /* ! * New style: args is a list of TypeNames. For the moment, though, ! * we allow at most one. */ if (baseType != NULL) ereport(ERROR, --- 132,148 ---- (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregate input type must be specified"))); + baseTypeIdArray = palloc(sizeof(Oid)*1); if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0) ! baseTypeIdArray[0] = ANYOID; else ! baseTypeIdArray[0] = typenameTypeId(NULL, baseType); ! numArgs = 1; } else { /* ! * New style: args is a list of TypeNames. */ if (baseType != NULL) ereport(ERROR, *************** *** 150,168 **** if (args == NIL) { /* special case for agg(*) */ ! baseTypeId = ANYOID; ! } ! else if (list_length(args) != 1) ! { ! /* temporarily reject > 1 arg */ ! ereport(ERROR, ! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("aggregates can have only one input"))); ! baseTypeId = InvalidOid; /* keep compiler quiet */ } else { ! baseTypeId = typenameTypeId(NULL, (TypeName *) linitial(args)); } } --- 152,173 ---- if (args == NIL) { /* special case for agg(*) */ ! baseTypeIdArray = palloc(sizeof(Oid)*1); ! baseTypeIdArray[0] = ANYOID; ! numArgs = 1; } else { ! int i = 0; ! ListCell *lc; ! TypeName *curTypeName; ! baseTypeIdArray = palloc(sizeof(Oid)*list_length(args)); ! foreach (lc, args) ! { ! curTypeName = lfirst(lc); ! baseTypeIdArray[i++] = typenameTypeId(NULL, curTypeName); ! } ! numArgs = i; } } *************** *** 187,193 **** */ AggregateCreate(aggName, /* aggregate name */ aggNamespace, /* namespace */ ! baseTypeId, /* type of data being aggregated */ transfuncName, /* step function name */ finalfuncName, /* final function name */ sortoperatorName, /* sort operator name */ --- 192,199 ---- */ AggregateCreate(aggName, /* aggregate name */ aggNamespace, /* namespace */ ! baseTypeIdArray, /* type of data being aggregated */ ! numArgs, transfuncName, /* step function name */ finalfuncName, /* final function name */ sortoperatorName, /* sort operator name */ Index: src/backend/executor/execQual.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/executor/execQual.c,v retrieving revision 1.192 diff -c -r1.192 execQual.c *** src/backend/executor/execQual.c 14 Jul 2006 14:52:19 -0000 1.192 --- src/backend/executor/execQual.c 25 Jul 2006 09:12:47 -0000 *************** *** 3174,3180 **** aggstate->aggs = lcons(astate, aggstate->aggs); naggs = ++aggstate->numaggs; ! astate->target = ExecInitExpr(aggref->target, parent); /* * Complain if the aggregate's argument contains any --- 3174,3181 ---- aggstate->aggs = lcons(astate, aggstate->aggs); naggs = ++aggstate->numaggs; ! astate->args = (List *) ExecInitExpr((Expr *)aggref->args, ! parent); /* * Complain if the aggregate's argument contains any Index: src/backend/executor/nodeAgg.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/executor/nodeAgg.c,v retrieving revision 1.144 diff -c -r1.144 nodeAgg.c *** src/backend/executor/nodeAgg.c 14 Jul 2006 14:52:19 -0000 1.144 --- src/backend/executor/nodeAgg.c 25 Jul 2006 09:12:47 -0000 *************** *** 123,128 **** --- 123,137 ---- Oid inputType; Oid sortOperator; + int numArguments; + + /* + * The preallocated arrays used to store the arguments of Aggs + * and the isNull flags. + */ + Datum *newArgValArray; + bool *isNullArray; + /* * fmgr lookup data for input type's equality operator --- only set/used * when aggregate has DISTINCT flag. *************** *** 214,220 **** static void advance_transition_function(AggState *aggstate, AggStatePerAgg peraggstate, AggStatePerGroup pergroupstate, ! Datum newVal, bool isNull); static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup); static void process_sorted_aggregate(AggState *aggstate, AggStatePerAgg peraggstate, --- 223,230 ---- static void advance_transition_function(AggState *aggstate, AggStatePerAgg peraggstate, AggStatePerGroup pergroupstate, ! FunctionCallInfoData *fcinfo, ! int numArguments); static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup); static void process_sorted_aggregate(AggState *aggstate, AggStatePerAgg peraggstate, *************** *** 322,331 **** advance_transition_function(AggState *aggstate, AggStatePerAgg peraggstate, AggStatePerGroup pergroupstate, ! Datum newVal, bool isNull) { - FunctionCallInfoData fcinfo; MemoryContext oldContext; if (peraggstate->transfn.fn_strict) { --- 332,343 ---- advance_transition_function(AggState *aggstate, AggStatePerAgg peraggstate, AggStatePerGroup pergroupstate, ! FunctionCallInfoData *fcinfo, ! int numArguments) { MemoryContext oldContext; + Datum newComputedTransValue; + int i; if (peraggstate->transfn.fn_strict) { *************** *** 333,340 **** * For a strict transfn, nothing happens at a NULL input tuple; we * just keep the prior transValue. */ ! if (isNull) ! return; if (pergroupstate->noTransValue) { /* --- 345,355 ---- * For a strict transfn, nothing happens at a NULL input tuple; we * just keep the prior transValue. */ ! for (i = 1; (i <= numArguments); i++) ! { ! if (fcinfo->argnull[i]) ! return; ! } if (pergroupstate->noTransValue) { /* *************** *** 347,353 **** * do not need to pfree the old transValue, since it's NULL. */ oldContext = MemoryContextSwitchTo(aggstate->aggcontext); ! pergroupstate->transValue = datumCopy(newVal, peraggstate->transtypeByVal, peraggstate->transtypeLen); pergroupstate->transValueIsNull = false; --- 362,368 ---- * do not need to pfree the old transValue, since it's NULL. */ oldContext = MemoryContextSwitchTo(aggstate->aggcontext); ! pergroupstate->transValue = datumCopy(fcinfo->arg[1], peraggstate->transtypeByVal, peraggstate->transtypeLen); pergroupstate->transValueIsNull = false; *************** *** 373,386 **** /* * OK to call the transition function */ ! InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn), 2, ! (void *) aggstate, NULL); ! fcinfo.arg[0] = pergroupstate->transValue; ! fcinfo.argnull[0] = pergroupstate->transValueIsNull; ! fcinfo.arg[1] = newVal; ! fcinfo.argnull[1] = isNull; ! newVal = FunctionCallInvoke(&fcinfo); /* * If pass-by-ref datatype, must copy the new value into aggcontext and --- 388,397 ---- /* * OK to call the transition function */ ! fcinfo->arg[0] = pergroupstate->transValue; ! fcinfo->argnull[0] = pergroupstate->transValueIsNull; ! newComputedTransValue = FunctionCallInvoke(fcinfo); /* * If pass-by-ref datatype, must copy the new value into aggcontext and *************** *** 388,399 **** * first input, we don't need to do anything. */ if (!peraggstate->transtypeByVal && ! DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue)) { ! if (!fcinfo.isnull) { MemoryContextSwitchTo(aggstate->aggcontext); ! newVal = datumCopy(newVal, peraggstate->transtypeByVal, peraggstate->transtypeLen); } --- 399,410 ---- * first input, we don't need to do anything. */ if (!peraggstate->transtypeByVal && ! DatumGetPointer(newComputedTransValue) != DatumGetPointer(pergroupstate->transValue)) { ! if (!fcinfo->isnull) { MemoryContextSwitchTo(aggstate->aggcontext); ! newComputedTransValue = datumCopy(newComputedTransValue, peraggstate->transtypeByVal, peraggstate->transtypeLen); } *************** *** 401,408 **** pfree(DatumGetPointer(pergroupstate->transValue)); } ! pergroupstate->transValue = newVal; ! pergroupstate->transValueIsNull = fcinfo.isnull; MemoryContextSwitchTo(oldContext); } --- 412,419 ---- pfree(DatumGetPointer(pergroupstate->transValue)); } ! pergroupstate->transValue = newComputedTransValue; ! pergroupstate->transValueIsNull = fcinfo->isnull; MemoryContextSwitchTo(oldContext); } *************** *** 419,449 **** advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) { ExprContext *econtext = aggstate->tmpcontext; int aggno; for (aggno = 0; aggno < aggstate->numaggs; aggno++) { ! AggStatePerAgg peraggstate = &aggstate->peragg[aggno]; ! AggStatePerGroup pergroupstate = &pergroup[aggno]; ! AggrefExprState *aggrefstate = peraggstate->aggrefstate; ! Aggref *aggref = peraggstate->aggref; ! Datum newVal; ! bool isNull; ! ! newVal = ExecEvalExprSwitchContext(aggrefstate->target, econtext, ! &isNull, NULL); if (aggref->aggdistinct) { /* in DISTINCT mode, we may ignore nulls */ ! if (isNull) continue; ! tuplesort_putdatum(peraggstate->sortstate, newVal, isNull); } else { advance_transition_function(aggstate, peraggstate, pergroupstate, ! newVal, isNull); } } } --- 430,491 ---- advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) { ExprContext *econtext = aggstate->tmpcontext; + Datum *newArgValArray; + bool *isNullArray; int aggno; for (aggno = 0; aggno < aggstate->numaggs; aggno++) { ! AggStatePerAgg peraggstate = &aggstate->peragg[aggno]; ! AggStatePerGroup pergroupstate = &pergroup[aggno]; ! AggrefExprState *aggrefstate = peraggstate->aggrefstate; ! Aggref *aggref = peraggstate->aggref; ! int i, numArguments; ! ListCell *arg; ! MemoryContext oldContext; ! FunctionCallInfoData fcinfo; ! ! newArgValArray = peraggstate->newArgValArray; ! isNullArray = peraggstate->isNullArray; ! numArguments = peraggstate->numArguments; ! ! i = 0; ! ! ! /* Switch first to the per-tuple memory context of the expression */ ! oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); ! ! InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn), ! 1 + numArguments, (void *) aggstate, ! NULL); ! ! i = 1; ! /* We start from 1, since the 0th arg will be the transition value */ ! foreach(arg, aggrefstate->args) ! { ! ExprState *argstate = (ExprState *) lfirst(arg); ! fcinfo.arg[i] = ExecEvalExpr(argstate, econtext, ! fcinfo.argnull + i, NULL); ! i++; ! } ! ! /* Switch back */ ! MemoryContextSwitchTo(oldContext); if (aggref->aggdistinct) { + /* We use one-argument aggs when in DISTINCT mode */ + /* in DISTINCT mode, we may ignore nulls */ ! if (fcinfo.argnull[1]) continue; ! tuplesort_putdatum(peraggstate->sortstate, fcinfo.arg[1], ! fcinfo.argnull[1]); } else { advance_transition_function(aggstate, peraggstate, pergroupstate, ! &fcinfo, numArguments); } } } *************** *** 465,475 **** bool haveOldVal = false; MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory; MemoryContext oldContext; ! Datum newVal; ! bool isNull; tuplesort_performsort(peraggstate->sortstate); /* * Note: if input type is pass-by-ref, the datums returned by the sort are * freshly palloc'd in the per-query context, so we must be careful to --- 507,524 ---- bool haveOldVal = false; MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory; MemoryContext oldContext; ! Datum *newVal; ! bool *isNull; ! FunctionCallInfoData fcinfo; tuplesort_performsort(peraggstate->sortstate); + InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn), + 2, (void *) aggstate, + NULL); + newVal = fcinfo.arg + 1; + isNull = fcinfo.argnull + 1; + /* * Note: if input type is pass-by-ref, the datums returned by the sort are * freshly palloc'd in the per-query context, so we must be careful to *************** *** 477,489 **** */ while (tuplesort_getdatum(peraggstate->sortstate, true, ! &newVal, &isNull)) { /* * DISTINCT always suppresses nulls, per SQL spec, regardless of the * transition function's strictness. */ ! if (isNull) continue; /* --- 526,538 ---- */ while (tuplesort_getdatum(peraggstate->sortstate, true, ! newVal, isNull)) { /* * DISTINCT always suppresses nulls, per SQL spec, regardless of the * transition function's strictness. */ ! if (*isNull) continue; /* *************** *** 495,515 **** if (haveOldVal && DatumGetBool(FunctionCall2(&peraggstate->equalfn, ! oldVal, newVal))) { /* equal to prior, so forget this one */ if (!peraggstate->inputtypeByVal) ! pfree(DatumGetPointer(newVal)); } else { advance_transition_function(aggstate, peraggstate, pergroupstate, ! newVal, false); /* forget the old value, if any */ if (haveOldVal && !peraggstate->inputtypeByVal) pfree(DatumGetPointer(oldVal)); /* and remember the new one for subsequent equality checks */ ! oldVal = newVal; haveOldVal = true; } --- 544,564 ---- if (haveOldVal && DatumGetBool(FunctionCall2(&peraggstate->equalfn, ! oldVal, *newVal))) { /* equal to prior, so forget this one */ if (!peraggstate->inputtypeByVal) ! pfree(DatumGetPointer(*newVal)); } else { advance_transition_function(aggstate, peraggstate, pergroupstate, ! &fcinfo, 1); /* forget the old value, if any */ if (haveOldVal && !peraggstate->inputtypeByVal) pfree(DatumGetPointer(oldVal)); /* and remember the new one for subsequent equality checks */ ! oldVal = *newVal; haveOldVal = true; } *************** *** 1120,1125 **** --- 1169,1176 ---- int numaggs, aggno; ListCell *l; + Oid *inputTypeArray = 0; + /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); *************** *** 1286,1292 **** AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l); Aggref *aggref = (Aggref *) aggrefstate->xprstate.expr; AggStatePerAgg peraggstate; - Oid inputType; HeapTuple aggTuple; Form_pg_aggregate aggform; Oid aggtranstype; --- 1337,1342 ---- *************** *** 1297,1306 **** --- 1347,1364 ---- *finalfnexpr; Datum textInitVal; int i; + int numArguments; + ListCell *curArgument; + /* Planner should have assigned aggregate to correct level */ Assert(aggref->agglevelsup == 0); + + /* KS XXX Probably it should work even for polyArgAggs, but + * it shoud be checked -- I'm not sure that the + * equal(aggref, aggref) works fine for the polyArgAggs + */ /* Look for a previous duplicate aggregate */ for (i = 0; i <= aggno; i++) { *************** *** 1324,1336 **** /* Fill in the peraggstate data */ peraggstate->aggrefstate = aggrefstate; peraggstate->aggref = aggref; /* * Get actual datatype of the input. We need this because it may be * different from the agg's declared input type, when the agg accepts * ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT. */ ! inputType = exprType((Node *) aggref->target); aggTuple = SearchSysCache(AGGFNOID, ObjectIdGetDatum(aggref->aggfnoid), --- 1382,1419 ---- /* Fill in the peraggstate data */ peraggstate->aggrefstate = aggrefstate; peraggstate->aggref = aggref; + + numArguments = list_length(aggref->args); + peraggstate->numArguments = numArguments; + if (!inputTypeArray) + { + inputTypeArray = (Oid *) palloc(sizeof(Oid) * numArguments); + } + else + { + inputTypeArray = (Oid *) repalloc(inputTypeArray, + numArguments * sizeof(Oid)); + } + + /* Preallocate the arrays for storing the arguments of the Aggs + * and the isNull flags + */ + peraggstate->newArgValArray = (Datum *) palloc(sizeof(Datum) * + numArguments); + peraggstate->isNullArray = (bool *) palloc(sizeof(bool) * + numArguments); /* * Get actual datatype of the input. We need this because it may be * different from the agg's declared input type, when the agg accepts * ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT. */ ! i = 0; ! foreach(curArgument, aggref->args) ! { ! inputTypeArray[i++] = exprType((Node *) lfirst(curArgument)); ! } ! aggTuple = SearchSysCache(AGGFNOID, ObjectIdGetDatum(aggref->aggfnoid), *************** *** 1384,1403 **** if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID) { /* have to fetch the agg's declared input type... */ ! Oid *agg_arg_types; int agg_nargs; (void) get_func_signature(aggref->aggfnoid, ! &agg_arg_types, &agg_nargs); ! Assert(agg_nargs == 1); ! aggtranstype = resolve_generic_type(aggtranstype, ! inputType, ! agg_arg_types[0]); ! pfree(agg_arg_types); } /* build expression trees using actual argument & result types */ ! build_aggregate_fnexprs(inputType, aggtranstype, aggref->aggtype, transfn_oid, --- 1467,1486 ---- if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID) { /* have to fetch the agg's declared input type... */ ! Oid *declaredArgTypes; int agg_nargs; (void) get_func_signature(aggref->aggfnoid, ! &declaredArgTypes, &agg_nargs); ! aggtranstype = enforce_generic_type_consistency(inputTypeArray, ! declaredArgTypes, ! agg_nargs, ! aggtranstype); ! pfree(declaredArgTypes); } /* build expression trees using actual argument & result types */ ! build_aggregate_fnexprs(inputTypeArray, aggtranstype, aggref->aggtype, transfn_oid, *************** *** 1444,1450 **** */ if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull) { ! if (!IsBinaryCoercible(inputType, aggtranstype)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregate %u needs to have compatible input type and transition type", --- 1527,1533 ---- */ if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull) { ! if (!IsBinaryCoercible(inputTypeArray[0], aggtranstype)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregate %u needs to have compatible input type and transition type", *************** *** 1457,1476 **** /* We don't implement DISTINCT aggs in the HASHED case */ Assert(node->aggstrategy != AGG_HASHED); ! peraggstate->inputType = inputType; ! get_typlenbyval(inputType, &peraggstate->inputtypeLen, &peraggstate->inputtypeByVal); ! eq_function = equality_oper_funcid(inputType); fmgr_info(eq_function, &(peraggstate->equalfn)); ! peraggstate->sortOperator = ordering_oper_opid(inputType); peraggstate->sortstate = NULL; } ReleaseSysCache(aggTuple); } /* Update numaggs to match number of unique aggregates found */ aggstate->numaggs = aggno + 1; --- 1540,1569 ---- /* We don't implement DISTINCT aggs in the HASHED case */ Assert(node->aggstrategy != AGG_HASHED); + + /* We don't implement the DISTINCT aggs for the aggs having + * more than one argument + */ + Assert(numArguments == 1); ! peraggstate->inputType = inputTypeArray[0]; ! get_typlenbyval(inputTypeArray[0], &peraggstate->inputtypeLen, &peraggstate->inputtypeByVal); ! eq_function = equality_oper_funcid(inputTypeArray[0]); fmgr_info(eq_function, &(peraggstate->equalfn)); ! peraggstate->sortOperator = ordering_oper_opid(inputTypeArray[0]); peraggstate->sortstate = NULL; } ReleaseSysCache(aggTuple); } + + if (inputTypeArray) + { + pfree(inputTypeArray); + } /* Update numaggs to match number of unique aggregates found */ aggstate->numaggs = aggno + 1; Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v retrieving revision 1.343 diff -c -r1.343 copyfuncs.c *** src/backend/nodes/copyfuncs.c 14 Jul 2006 14:52:19 -0000 1.343 --- src/backend/nodes/copyfuncs.c 25 Jul 2006 09:12:49 -0000 *************** *** 743,749 **** COPY_SCALAR_FIELD(aggfnoid); COPY_SCALAR_FIELD(aggtype); ! COPY_NODE_FIELD(target); COPY_SCALAR_FIELD(agglevelsup); COPY_SCALAR_FIELD(aggstar); COPY_SCALAR_FIELD(aggdistinct); --- 743,749 ---- COPY_SCALAR_FIELD(aggfnoid); COPY_SCALAR_FIELD(aggtype); ! COPY_NODE_FIELD(args); COPY_SCALAR_FIELD(agglevelsup); COPY_SCALAR_FIELD(aggstar); COPY_SCALAR_FIELD(aggdistinct); Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v retrieving revision 1.277 diff -c -r1.277 equalfuncs.c *** src/backend/nodes/equalfuncs.c 14 Jul 2006 14:52:20 -0000 1.277 --- src/backend/nodes/equalfuncs.c 25 Jul 2006 09:12:49 -0000 *************** *** 156,162 **** { COMPARE_SCALAR_FIELD(aggfnoid); COMPARE_SCALAR_FIELD(aggtype); ! COMPARE_NODE_FIELD(target); COMPARE_SCALAR_FIELD(agglevelsup); COMPARE_SCALAR_FIELD(aggstar); COMPARE_SCALAR_FIELD(aggdistinct); --- 156,162 ---- { COMPARE_SCALAR_FIELD(aggfnoid); COMPARE_SCALAR_FIELD(aggtype); ! COMPARE_NODE_FIELD(args); COMPARE_SCALAR_FIELD(agglevelsup); COMPARE_SCALAR_FIELD(aggstar); COMPARE_SCALAR_FIELD(aggdistinct); Index: src/backend/nodes/outfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/outfuncs.c,v retrieving revision 1.278 diff -c -r1.278 outfuncs.c *** src/backend/nodes/outfuncs.c 14 Jul 2006 14:52:20 -0000 1.278 --- src/backend/nodes/outfuncs.c 25 Jul 2006 09:12:50 -0000 *************** *** 635,641 **** WRITE_OID_FIELD(aggfnoid); WRITE_OID_FIELD(aggtype); ! WRITE_NODE_FIELD(target); WRITE_UINT_FIELD(agglevelsup); WRITE_BOOL_FIELD(aggstar); WRITE_BOOL_FIELD(aggdistinct); --- 635,641 ---- WRITE_OID_FIELD(aggfnoid); WRITE_OID_FIELD(aggtype); ! WRITE_NODE_FIELD(args); WRITE_UINT_FIELD(agglevelsup); WRITE_BOOL_FIELD(aggstar); WRITE_BOOL_FIELD(aggdistinct); Index: src/backend/nodes/readfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/readfuncs.c,v retrieving revision 1.191 diff -c -r1.191 readfuncs.c *** src/backend/nodes/readfuncs.c 3 Jul 2006 22:45:39 -0000 1.191 --- src/backend/nodes/readfuncs.c 25 Jul 2006 09:12:50 -0000 *************** *** 348,354 **** READ_OID_FIELD(aggfnoid); READ_OID_FIELD(aggtype); ! READ_NODE_FIELD(target); READ_UINT_FIELD(agglevelsup); READ_BOOL_FIELD(aggstar); READ_BOOL_FIELD(aggdistinct); --- 348,354 ---- READ_OID_FIELD(aggfnoid); READ_OID_FIELD(aggtype); ! READ_NODE_FIELD(args); READ_UINT_FIELD(agglevelsup); READ_BOOL_FIELD(aggstar); READ_BOOL_FIELD(aggdistinct); Index: src/backend/optimizer/plan/planagg.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/plan/planagg.c,v retrieving revision 1.18 diff -c -r1.18 planagg.c *** src/backend/optimizer/plan/planagg.c 14 Jul 2006 14:52:20 -0000 1.18 --- src/backend/optimizer/plan/planagg.c 25 Jul 2006 09:12:51 -0000 *************** *** 219,224 **** --- 219,225 ---- Oid aggsortop; MinMaxAggInfo *info; ListCell *l; + Expr *curTarget; Assert(aggref->agglevelsup == 0); if (aggref->aggstar) *************** *** 228,233 **** --- 229,237 ---- aggsortop = fetch_agg_sort_op(aggref->aggfnoid); if (!OidIsValid(aggsortop)) return true; /* not a MIN/MAX aggregate */ + + /* Here we should have only one arg aggs... Isn't it ? */ + curTarget = linitial(aggref->args); /* * Check whether it's already in the list, and add it if not. *************** *** 236,249 **** { info = (MinMaxAggInfo *) lfirst(l); if (info->aggfnoid == aggref->aggfnoid && ! equal(info->target, aggref->target)) return false; } info = (MinMaxAggInfo *) palloc0(sizeof(MinMaxAggInfo)); info->aggfnoid = aggref->aggfnoid; info->aggsortop = aggsortop; ! info->target = aggref->target; *context = lappend(*context, info); --- 240,253 ---- { info = (MinMaxAggInfo *) lfirst(l); if (info->aggfnoid == aggref->aggfnoid && ! equal(info->target, curTarget)) return false; } info = (MinMaxAggInfo *) palloc0(sizeof(MinMaxAggInfo)); info->aggfnoid = aggref->aggfnoid; info->aggsortop = aggsortop; ! info->target = curTarget; *context = lappend(*context, info); *************** *** 520,532 **** { Aggref *aggref = (Aggref *) node; ListCell *l; foreach(l, *context) { MinMaxAggInfo *info = (MinMaxAggInfo *) lfirst(l); if (info->aggfnoid == aggref->aggfnoid && ! equal(info->target, aggref->target)) return (Node *) info->param; } elog(ERROR, "failed to re-find aggregate info record"); --- 524,537 ---- { Aggref *aggref = (Aggref *) node; ListCell *l; + Expr *curTarget = linitial(aggref->args); foreach(l, *context) { MinMaxAggInfo *info = (MinMaxAggInfo *) lfirst(l); if (info->aggfnoid == aggref->aggfnoid && ! equal(info->target, curTarget)) return (Node *) info->param; } elog(ERROR, "failed to re-find aggregate info record"); Index: src/backend/optimizer/util/clauses.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v retrieving revision 1.214 diff -c -r1.214 clauses.c *** src/backend/optimizer/util/clauses.c 14 Jul 2006 14:52:21 -0000 1.214 --- src/backend/optimizer/util/clauses.c 25 Jul 2006 09:12:52 -0000 *************** *** 397,413 **** if (IsA(node, Aggref)) { Aggref *aggref = (Aggref *) node; ! Oid inputType; HeapTuple aggTuple; Form_pg_aggregate aggform; Oid aggtranstype; ! Assert(aggref->agglevelsup == 0); counts->numAggs++; if (aggref->aggdistinct) counts->numDistinctAggs++; ! inputType = exprType((Node *) aggref->target); /* fetch aggregate transition datatype from pg_aggregate */ aggTuple = SearchSysCache(AGGFNOID, --- 397,425 ---- if (IsA(node, Aggref)) { Aggref *aggref = (Aggref *) node; ! Oid *inputTypeArray; HeapTuple aggTuple; Form_pg_aggregate aggform; Oid aggtranstype; ! int numArguments; ! int i; ! ListCell *curArgument; ! Assert(aggref->agglevelsup == 0); counts->numAggs++; if (aggref->aggdistinct) counts->numDistinctAggs++; ! numArguments = list_length(aggref->args); ! ! inputTypeArray = (Oid *) palloc(sizeof(Oid) * numArguments); ! ! i = 0; ! foreach(curArgument, aggref->args) ! { ! inputTypeArray[i++] = exprType((Node *) lfirst(curArgument)); ! } ! /* fetch aggregate transition datatype from pg_aggregate */ aggTuple = SearchSysCache(AGGFNOID, *************** *** 424,439 **** if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID) { /* have to fetch the agg's declared input type... */ ! Oid *agg_arg_types; int agg_nargs; (void) get_func_signature(aggref->aggfnoid, ! &agg_arg_types, &agg_nargs); ! Assert(agg_nargs == 1); ! aggtranstype = resolve_generic_type(aggtranstype, ! inputType, ! agg_arg_types[0]); ! pfree(agg_arg_types); } /* --- 436,452 ---- if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID) { /* have to fetch the agg's declared input type... */ ! Oid *declaredArgTypes; int agg_nargs; (void) get_func_signature(aggref->aggfnoid, ! &declaredArgTypes, &agg_nargs); ! /* To be thought about what to do with resolve_generic_type */ ! aggtranstype = enforce_generic_type_consistency(inputTypeArray, ! declaredArgTypes, ! agg_nargs, ! aggtranstype); ! pfree(declaredArgTypes); } /* *************** *** 452,459 **** * same typmod (same width) as well. This works for cases like * MAX/MIN and is probably somewhat reasonable otherwise. */ ! if (aggtranstype == inputType) ! aggtranstypmod = exprTypmod((Node *) aggref->target); else aggtranstypmod = -1; --- 465,472 ---- * same typmod (same width) as well. This works for cases like * MAX/MIN and is probably somewhat reasonable otherwise. */ ! if (aggtranstype == inputTypeArray[0]) ! aggtranstypmod = exprTypmod((Node *) linitial(aggref->args)); else aggtranstypmod = -1; *************** *** 467,477 **** * Complain if the aggregate's argument contains any aggregates; * nested agg functions are semantically nonsensical. */ - if (contain_agg_clause((Node *) aggref->target)) - ereport(ERROR, - (errcode(ERRCODE_GROUPING_ERROR), - errmsg("aggregate function calls may not be nested"))); /* * Having checked that, we need not recurse into the argument. */ --- 480,495 ---- * Complain if the aggregate's argument contains any aggregates; * nested agg functions are semantically nonsensical. */ + foreach(curArgument, aggref->args) + { + if (contain_agg_clause((Node *) lfirst(curArgument))) + ereport(ERROR, + (errcode(ERRCODE_GROUPING_ERROR), + errmsg("aggregate function calls may not be nested"))); + } + + pfree(inputTypeArray); /* * Having checked that, we need not recurse into the argument. */ *************** *** 3026,3032 **** /* primitive node types with no expression subnodes */ break; case T_Aggref: ! return walker(((Aggref *) node)->target, context); case T_ArrayRef: { ArrayRef *aref = (ArrayRef *) node; --- 3044,3057 ---- /* primitive node types with no expression subnodes */ break; case T_Aggref: ! { ! Aggref *aggref = (Aggref *) node; ! ! if (expression_tree_walker((Node *) aggref->args, ! walker, context)) ! return true; ! } ! break; case T_ArrayRef: { ArrayRef *aref = (ArrayRef *) node; *************** *** 3448,3454 **** Aggref *newnode; FLATCOPY(newnode, aggref, Aggref); ! MUTATE(newnode->target, aggref->target, Expr *); return (Node *) newnode; } break; --- 3473,3479 ---- Aggref *newnode; FLATCOPY(newnode, aggref, Aggref); ! MUTATE(newnode->args, aggref->args, List *); return (Node *) newnode; } break; Index: src/backend/parser/parse_agg.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_agg.c,v retrieving revision 1.72 diff -c -r1.72 parse_agg.c *** src/backend/parser/parse_agg.c 14 Jul 2006 14:52:21 -0000 1.72 --- src/backend/parser/parse_agg.c 25 Jul 2006 09:12:53 -0000 *************** *** 51,84 **** void transformAggregateCall(ParseState *pstate, Aggref *agg) { ! int min_varlevel; ! ! /* ! * The aggregate's level is the same as the level of the lowest-level ! * variable or aggregate in its argument; or if it contains no variables ! * at all, we presume it to be local. ! */ ! min_varlevel = find_minimum_var_level((Node *) agg->target); ! ! /* ! * An aggregate can't directly contain another aggregate call of the same ! * level (though outer aggs are okay). We can skip this check if we ! * didn't find any local vars or aggs. ! */ ! if (min_varlevel == 0) { ! if (checkExprHasAggs((Node *) agg->target)) ! ereport(ERROR, ! (errcode(ERRCODE_GROUPING_ERROR), ! errmsg("aggregate function calls may not be nested"))); } ! if (min_varlevel < 0) ! min_varlevel = 0; ! agg->agglevelsup = min_varlevel; /* Mark the correct pstate as having aggregates */ ! while (min_varlevel-- > 0) pstate = pstate->parentParseState; pstate->p_hasAggs = true; } --- 51,98 ---- void transformAggregateCall(ParseState *pstate, Aggref *agg) { ! int minVarLevel, ! minMinVarLevel = -1; ! ListCell *curArgument; ! foreach(curArgument, agg->args) { ! Node *curNode = (Node *)lfirst(curArgument); ! /* ! * The aggregate's level is the same as the level of the lowest-level ! * variable or aggregate in its argument; or if it contains no variables ! * at all, we presume it to be local. ! */ ! minVarLevel = find_minimum_var_level(curNode); ! ! /* ! * An aggregate can't directly contain another aggregate call of the same ! * level (though outer aggs are okay). We can skip this check if we ! * didn't find any local vars or aggs. ! */ ! if (minVarLevel == 0) ! { ! if (checkExprHasAggs(curNode)) ! ereport(ERROR, ! (errcode(ERRCODE_GROUPING_ERROR), ! errmsg("aggregate function calls may not be nested"))); ! } ! ! /* KS XXX !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! * !!!!!!!!!!!!!!!Very important!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! * that logic should be fixed... I don't understand currently how I should ! * update the minMinVarLevel. Should it be the minimum value among minVarLevels ! * of different arguments or maximum value among minVarLevels or something else... ! * Currently it is just the minVarLevel of the last argument.... ! */ ! minMinVarLevel = minVarLevel; } ! if (minMinVarLevel < 0) ! minMinVarLevel = 0; ! agg->agglevelsup = minMinVarLevel; /* Mark the correct pstate as having aggregates */ ! while (minMinVarLevel-- > 0) pstate = pstate->parentParseState; pstate->p_hasAggs = true; } *************** *** 371,377 **** * *finalfnexpr. The latter is set to NULL if there's no finalfn. */ void ! build_aggregate_fnexprs(Oid agg_input_type, Oid agg_state_type, Oid agg_result_type, Oid transfn_oid, --- 385,391 ---- * *finalfnexpr. The latter is set to NULL if there's no finalfn. */ void ! build_aggregate_fnexprs(Oid *agg_input_type, Oid agg_state_type, Oid agg_result_type, Oid transfn_oid, *************** *** 379,392 **** Expr **transfnexpr, Expr **finalfnexpr) { ! int transfn_nargs; Param *arg0; Param *arg1; List *args; /* get the transition function arg count */ transfn_nargs = get_func_nargs(transfn_oid); ! /* * Build arg list to use in the transfn FuncExpr node. We really only care * that transfn can discover the actual argument types at runtime using --- 393,409 ---- Expr **transfnexpr, Expr **finalfnexpr) { ! int transfn_nargs, ! aggfn_nargs, ! i; Param *arg0; Param *arg1; List *args; /* get the transition function arg count */ transfn_nargs = get_func_nargs(transfn_oid); ! aggfn_nargs = transfn_nargs - 1; ! /* * Build arg list to use in the transfn FuncExpr node. We really only care * that transfn can discover the actual argument types at runtime using *************** *** 398,403 **** --- 415,432 ---- arg0->paramid = -1; arg0->paramtype = agg_state_type; + args = list_make1(arg0); + + for(i = 0; i < aggfn_nargs; i++) + { + arg1 = makeNode(Param); + arg1->paramkind = PARAM_EXEC; + arg1->paramid = -1; + arg1->paramtype = agg_input_type[i]; + lappend(args, arg1); + } + + /* if (transfn_nargs == 2) { arg1 = makeNode(Param); *************** *** 409,415 **** } else args = list_make1(arg0); ! *transfnexpr = (Expr *) makeFuncExpr(transfn_oid, agg_state_type, args, --- 438,444 ---- } else args = list_make1(arg0); ! */ *transfnexpr = (Expr *) makeFuncExpr(transfn_oid, agg_state_type, args, Index: src/backend/parser/parse_func.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_func.c,v retrieving revision 1.188 diff -c -r1.188 parse_func.c *** src/backend/parser/parse_func.c 14 Jul 2006 14:52:22 -0000 1.188 --- src/backend/parser/parse_func.c 25 Jul 2006 09:12:53 -0000 *************** *** 259,267 **** aggref->aggfnoid = funcid; aggref->aggtype = rettype; ! aggref->target = linitial(fargs); aggref->aggstar = agg_star; aggref->aggdistinct = agg_distinct; /* parse_agg.c does additional aggregate-specific processing */ transformAggregateCall(pstate, aggref); --- 259,285 ---- aggref->aggfnoid = funcid; aggref->aggtype = rettype; ! aggref->args = fargs; aggref->aggstar = agg_star; aggref->aggdistinct = agg_distinct; + + /* From the current understanding of the SQL standart the + * DISTINCT keyword can be used only in one-argument aggregates + * And '*' cannot be used in multi-arg. aggregates + */ + if (list_length(fargs) > 1) + { + if (agg_distinct) + { + elog(ERROR, "It is not allowed to use DISTINCT keyword " + "with aggregates with more than one argument"); + } + if (agg_star) + { + elog(ERROR, "It is not allowed to use * arguments" + "with aggregates with more than one argument"); + } + } /* parse_agg.c does additional aggregate-specific processing */ transformAggregateCall(pstate, aggref); Index: src/backend/utils/adt/float.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/float.c,v retrieving revision 1.127 diff -c -r1.127 float.c *** src/backend/utils/adt/float.c 14 Jul 2006 14:52:24 -0000 1.127 --- src/backend/utils/adt/float.c 25 Jul 2006 09:13:23 -0000 *************** *** 1878,1895 **** */ static float8 * ! check_float8_array(ArrayType *transarray, const char *caller) { /* ! * We expect the input to be a 3-element float array; verify that. We * don't need to use deconstruct_array() since the array data is just ! * going to look like a C array of 3 float8 values. */ if (ARR_NDIM(transarray) != 1 || ! ARR_DIMS(transarray)[0] != 3 || ARR_HASNULL(transarray) || ARR_ELEMTYPE(transarray) != FLOAT8OID) ! elog(ERROR, "%s: expected 3-element float8 array", caller); return (float8 *) ARR_DATA_PTR(transarray); } --- 1878,1895 ---- */ static float8 * ! check_float8_array(ArrayType *transarray, const char *caller, int nelts) { /* ! * We expect the input to be a nelts-element float array; verify that. We * don't need to use deconstruct_array() since the array data is just ! * going to look like a C array of nelts float8 values. */ if (ARR_NDIM(transarray) != 1 || ! ARR_DIMS(transarray)[0] != nelts || ARR_HASNULL(transarray) || ARR_ELEMTYPE(transarray) != FLOAT8OID) ! elog(ERROR, "%s: expected %d-element float8 array", caller, nelts); return (float8 *) ARR_DATA_PTR(transarray); } *************** *** 1903,1909 **** sumX, sumX2; ! transvalues = check_float8_array(transarray, "float8_accum"); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; --- 1903,1909 ---- sumX, sumX2; ! transvalues = check_float8_array(transarray, "float8_accum", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; *************** *** 1953,1959 **** sumX2, newval; ! transvalues = check_float8_array(transarray, "float4_accum"); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; --- 1953,1959 ---- sumX2, newval; ! transvalues = check_float8_array(transarray, "float4_accum", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; *************** *** 2003,2009 **** float8 N, sumX; ! transvalues = check_float8_array(transarray, "float8_avg"); N = transvalues[0]; sumX = transvalues[1]; /* ignore sumX2 */ --- 2003,2009 ---- float8 N, sumX; ! transvalues = check_float8_array(transarray, "float8_avg", 3); N = transvalues[0]; sumX = transvalues[1]; /* ignore sumX2 */ *************** *** 2025,2031 **** sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_var_pop"); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; --- 2025,2031 ---- sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_var_pop", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; *************** *** 2053,2059 **** sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_var_samp"); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; --- 2053,2059 ---- sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_var_samp", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; *************** *** 2081,2087 **** sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_stddev_pop"); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; --- 2081,2087 ---- sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_stddev_pop", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; *************** *** 2109,2115 **** sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_stddev_samp"); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; --- 2109,2115 ---- sumX2, numerator; ! transvalues = check_float8_array(transarray, "float8_stddev_samp", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; *************** *** 2127,2132 **** --- 2127,3003 ---- PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0)))); } + Datum float8_regr_count_accum(PG_FUNCTION_ARGS) + { + int64 i = PG_GETARG_INT64(0); + if (PG_ARGISNULL(1)||PG_ARGISNULL(2)) + { + PG_RETURN_INT64(i); + } + else + { + PG_RETURN_INT64(i+1); + } + } + + Datum float4_regr_sxx_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT4(2); + float8 *transvalues; + float8 N, + sumX, + sumX2; + + transvalues = check_float8_array(transarray, "float4_regr_sxx_accum", 3); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + + N += 1.0; + sumX += newval; + sumX2 += newval * newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + transvalues[2] = sumX2; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[3]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + transdatums[2] = Float8GetDatumFast(sumX2); + + result = construct_array(transdatums, 3, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + + Datum float4_regr_avgx_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT4(2); + float8 *transvalues; + float8 N, + sumX; + + transvalues = check_float8_array(transarray, "float4_regr_avgx_accum", 2); + N = transvalues[0]; + sumX = transvalues[1]; + + N += 1.0; + sumX += newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[2]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + + result = construct_array(transdatums, 2, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + Datum float8_regr_avgx_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT8(2); + float8 *transvalues; + float8 N, + sumX; + + transvalues = check_float8_array(transarray, "float8_regr_avgx_accum", 2); + N = transvalues[0]; + sumX = transvalues[1]; + + N += 1.0; + sumX += newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[2]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + + result = construct_array(transdatums, 2, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + Datum float4_regr_avgy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT4(1); + float8 *transvalues; + float8 N, + sumY; + + transvalues = check_float8_array(transarray, "float4_regr_avgy_accum", 2); + N = transvalues[0]; + sumY = transvalues[1]; + + N += 1.0; + sumY += newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumY; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[2]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumY); + + result = construct_array(transdatums, 2, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + Datum float8_regr_avgy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT8(1); + float8 *transvalues; + float8 N, + sumY; + + transvalues = check_float8_array(transarray, "float8_regr_avgy_accum", 2); + N = transvalues[0]; + sumY = transvalues[1]; + + N += 1.0; + sumY += newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumY; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[2]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumY); + + result = construct_array(transdatums, 2, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + + + Datum float8_regr_avg(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, + sum, + numerator; + + transvalues = check_float8_array(transarray, "float8_regr_avg", 2); + N = transvalues[0]; + sum = transvalues[1]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numerator = sum; + + PG_RETURN_FLOAT8( numerator / N); + } + + + Datum float8_regr_sxx_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT8(2); + float8 *transvalues; + float8 N, + sumX, + sumX2; + + transvalues = check_float8_array(transarray, "float8_regr_sxx_accum", 3); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + + N += 1.0; + sumX += newval; + sumX2 += newval * newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + transvalues[2] = sumX2; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[3]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + transdatums[2] = Float8GetDatumFast(sumX2); + + result = construct_array(transdatums, 3, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + + + Datum float8_regr_sxx(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, + sumX, + sumX2, + numerator; + + transvalues = check_float8_array(transarray, "float8_regr_sxx", 3); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numerator = N * sumX2 - sumX * sumX; + + /* Watch out for roundoff error producing a negative numerator */ + if (numerator <= 0.0) + PG_RETURN_FLOAT8(0.0); + + PG_RETURN_FLOAT8( numerator / N); + } + + + Datum float4_regr_syy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT4(1); + float8 *transvalues; + float8 N, + sumY, + sumY2; + + transvalues = check_float8_array(transarray, "float4_regr_syy_accum", 3); + N = transvalues[0]; + sumY = transvalues[1]; + sumY2 = transvalues[2]; + + N += 1.0; + sumY += newval; + sumY2 += newval * newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumY; + transvalues[2] = sumY2; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[3]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumY); + transdatums[2] = Float8GetDatumFast(sumY2); + + result = construct_array(transdatums, 3, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + Datum float8_regr_syy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newval = PG_GETARG_FLOAT8(1); + float8 *transvalues; + float8 N, + sumY, + sumY2; + + transvalues = check_float8_array(transarray, "float8_regr_syy_accum", 3); + N = transvalues[0]; + sumY = transvalues[1]; + sumY2 = transvalues[2]; + + N += 1.0; + sumY += newval; + sumY2 += newval * newval; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumY; + transvalues[2] = sumY2; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[3]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumY); + transdatums[2] = Float8GetDatumFast(sumY2); + + result = construct_array(transdatums, 3, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + + + Datum float8_regr_syy(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, + sumY, + sumY2, + numerator; + + transvalues = check_float8_array(transarray, "float8_regr_syy", 3); + N = transvalues[0]; + sumY = transvalues[1]; + sumY2 = transvalues[2]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numerator = N * sumY2 - sumY * sumY; + + /* Watch out for roundoff error producing a negative numerator */ + if (numerator <= 0.0) + PG_RETURN_FLOAT8(0.0); + + PG_RETURN_FLOAT8( numerator / N); + } + + + Datum float4_regr_sxy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newvalX = PG_GETARG_FLOAT4(2); + float8 newvalY = PG_GETARG_FLOAT4(1); + float8 *transvalues; + float8 N, sumX, sumY, sumXY; + + transvalues = check_float8_array(transarray, "float4_regr_sxy_accum", 4); + N = transvalues[0]; + sumX = transvalues[1]; + sumY = transvalues[2]; + sumXY = transvalues[3]; + + N += 1.0; + sumX += newvalX; + sumY += newvalY; + sumXY += newvalX * newvalY; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + transvalues[2] = sumY; + transvalues[3] = sumXY; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[4]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + transdatums[2] = Float8GetDatumFast(sumY); + transdatums[3] = Float8GetDatumFast(sumXY); + + result = construct_array(transdatums, 4, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + Datum float4_regr_all_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newvalX = PG_GETARG_FLOAT4(2); + float8 newvalY = PG_GETARG_FLOAT4(1); + float8 *transvalues; + float8 N, sumX, sumY, sumXY, sumX2, sumY2; + + transvalues = check_float8_array(transarray, "float4_regr_all_accum", 6); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + sumY = transvalues[3]; + sumY2 = transvalues[4]; + sumXY = transvalues[5]; + + N += 1.0; + sumX += newvalX; + sumY += newvalY; + sumXY += newvalX * newvalY; + sumX2 += newvalX * newvalX; + sumY2 += newvalY * newvalY; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + transvalues[2] = sumX2; + transvalues[3] = sumY; + transvalues[4] = sumY2; + transvalues[5] = sumXY; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[6]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + transdatums[2] = Float8GetDatumFast(sumX2); + transdatums[3] = Float8GetDatumFast(sumY); + transdatums[4] = Float8GetDatumFast(sumY2); + transdatums[5] = Float8GetDatumFast(sumXY); + + result = construct_array(transdatums, 6, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + + Datum float8_regr_all_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newvalX = PG_GETARG_FLOAT8(2); + float8 newvalY = PG_GETARG_FLOAT8(1); + float8 *transvalues; + float8 N, sumX, sumY, sumXY, sumX2, sumY2; + + transvalues = check_float8_array(transarray, "float8_regr_all_accum", 6); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + sumY = transvalues[3]; + sumY2 = transvalues[4]; + sumXY = transvalues[5]; + + N += 1.0; + sumX += newvalX; + sumY += newvalY; + sumXY += newvalX * newvalY; + sumX2 += newvalX * newvalX; + sumY2 += newvalY * newvalY; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + transvalues[2] = sumX2; + transvalues[3] = sumY; + transvalues[4] = sumY2; + transvalues[5] = sumXY; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[6]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + transdatums[2] = Float8GetDatumFast(sumX2); + transdatums[3] = Float8GetDatumFast(sumY); + transdatums[4] = Float8GetDatumFast(sumY2); + transdatums[5] = Float8GetDatumFast(sumXY); + + result = construct_array(transdatums, 6, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + + + Datum float8_regr_sxy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 newvalX = PG_GETARG_FLOAT8(2); + float8 newvalY = PG_GETARG_FLOAT8(1); + float8 *transvalues; + float8 N, sumX, sumY, sumXY; + + transvalues = check_float8_array(transarray, "float8_regr_sxy_accum", 4); + N = transvalues[0]; + sumX = transvalues[1]; + sumY = transvalues[2]; + sumXY = transvalues[3]; + + N += 1.0; + sumX += newvalX; + sumY += newvalY; + sumXY += newvalX * newvalY; + + /* + * If we're invoked by nodeAgg, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we construct a + * new array with the updated transition data and return it. + */ + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + transvalues[0] = N; + transvalues[1] = sumX; + transvalues[2] = sumY; + transvalues[3] = sumXY; + + PG_RETURN_ARRAYTYPE_P(transarray); + } + else + { + Datum transdatums[4]; + ArrayType *result; + + transdatums[0] = Float8GetDatumFast(N); + transdatums[1] = Float8GetDatumFast(sumX); + transdatums[2] = Float8GetDatumFast(sumY); + transdatums[3] = Float8GetDatumFast(sumXY); + + result = construct_array(transdatums, 4, + FLOAT8OID, + sizeof(float8), false /* float8 byval */ , 'd'); + + PG_RETURN_ARRAYTYPE_P(result); + } + } + + Datum float8_regr_sxy(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, sumX, sumY, sumXY, numerator; + + transvalues = check_float8_array(transarray, "float8_regr_sxy", 4); + N = transvalues[0]; + sumX = transvalues[1]; + sumY = transvalues[2]; + sumXY = transvalues[3]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numerator = N * sumXY - sumX * sumY; + + PG_RETURN_FLOAT8( numerator / N); + } + + + Datum float8_covar_pop(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, sumX, sumY, sumXY, numerator; + + transvalues = check_float8_array(transarray, "float8_covar_pop", 4); + N = transvalues[0]; + sumX = transvalues[1]; + sumY = transvalues[2]; + sumXY = transvalues[3]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numerator = N * sumXY - sumX * sumY; + + PG_RETURN_FLOAT8( numerator / (N * N)); + } + + + Datum float8_covar_samp(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, sumX, sumY, sumXY, numerator; + + transvalues = check_float8_array(transarray, "float8_covar_samp", 4); + N = transvalues[0]; + sumX = transvalues[1]; + sumY = transvalues[2]; + sumXY = transvalues[3]; + + /* if N is <=1 we should return NULL */ + if (N < 2.0) + PG_RETURN_NULL(); + + numerator = N * sumXY - sumX * sumY; + + PG_RETURN_FLOAT8( numerator / (N * (N - 1))); + } + + + Datum float8_corr(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX, + numeratorY, numeratorXY; + + transvalues = check_float8_array(transarray, "float8_corr", 6); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + sumY = transvalues[3]; + sumY2 = transvalues[4]; + sumXY = transvalues[5]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numeratorX = N * sumX2 - sumX * sumX; + numeratorY = N * sumY2 - sumY * sumY; + numeratorXY = N * sumXY - sumX * sumY; + if ((numeratorX <= 0) && (numeratorY <= 0)) + { + PG_RETURN_NULL(); + } + + PG_RETURN_FLOAT8( sqrt (numeratorXY * numeratorXY / + (numeratorX * numeratorY))); + } + + Datum float8_regr_r2(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX, + numeratorY, numeratorXY; + + transvalues = check_float8_array(transarray, "float8_regr_r2", 6); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + sumY = transvalues[3]; + sumY2 = transvalues[4]; + sumXY = transvalues[5]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numeratorX = N * sumX2 - sumX * sumX; + numeratorY = N * sumY2 - sumY * sumY; + numeratorXY = N * sumXY - sumX * sumY; + if ((numeratorX <= 0) && (numeratorY <= 0)) + { + PG_RETURN_NULL(); + } + + PG_RETURN_FLOAT8( numeratorXY * numeratorXY / + (numeratorX * numeratorY)); + } + + Datum float8_regr_slope(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX, + numeratorXY; + + transvalues = check_float8_array(transarray, "float8_regr_slope", 6); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + sumY = transvalues[3]; + sumY2 = transvalues[4]; /* will be ignored */ + sumXY = transvalues[5]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numeratorX = N * sumX2 - sumX * sumX; + numeratorXY = N * sumXY - sumX * sumY; + if (numeratorX <= 0) + { + PG_RETURN_NULL(); + } + + PG_RETURN_FLOAT8( numeratorXY / numeratorX ); + } + + Datum float8_regr_intercept(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + float8 *transvalues; + float8 N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX, + numeratorXXY; + + transvalues = check_float8_array(transarray, "float8_regr_intercept", 6); + N = transvalues[0]; + sumX = transvalues[1]; + sumX2 = transvalues[2]; + sumY = transvalues[3]; + sumY2 = transvalues[4]; /* will be ignored */ + sumXY = transvalues[5]; + + /* if N is 0 we should return NULL */ + if (N < 1.0) + PG_RETURN_NULL(); + + numeratorX = N * sumX2 - sumX * sumX; + numeratorXXY = sumY * sumX2 - sumX * sumXY; + if (numeratorX <= 0) + { + PG_RETURN_NULL(); + } + + PG_RETURN_FLOAT8( numeratorXXY / numeratorX ); + } + /* * ==================================== Index: src/backend/utils/adt/numeric.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/numeric.c,v retrieving revision 1.94 diff -c -r1.94 numeric.c *** src/backend/utils/adt/numeric.c 14 Jul 2006 05:28:28 -0000 1.94 --- src/backend/utils/adt/numeric.c 25 Jul 2006 09:13:24 -0000 *************** *** 2106,2111 **** --- 2106,2358 ---- PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval)); } + Datum numeric_regr_avgx_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Numeric newvalX = PG_GETARG_NUMERIC(2); + ArrayType *outputarray; + Datum *transdatums; + int ndatums; + Datum N, + sumX; + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 2) + elog(ERROR, "expected 2-element numeric array"); + N = transdatums[0]; + sumX = transdatums[1]; + + N = DirectFunctionCall1(numeric_inc, N); + sumX = DirectFunctionCall2(numeric_add, sumX, + NumericGetDatum(newvalX)); + + transdatums[0] = N; + transdatums[1] = sumX; + + outputarray = construct_array(transdatums, 2, + NUMERICOID, -1, false, 'i'); + + PG_RETURN_ARRAYTYPE_P(outputarray); + } + + + Datum numeric_regr_avgy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Numeric newvalY = PG_GETARG_NUMERIC(1); + ArrayType *outputarray; + Datum *transdatums; + int ndatums; + Datum N, sumY; + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 2) + elog(ERROR, "expected 2-element numeric array"); + N = transdatums[0]; + sumY = transdatums[1]; + + N = DirectFunctionCall1(numeric_inc, N); + sumY = DirectFunctionCall2(numeric_add, sumY, + NumericGetDatum(newvalY)); + + transdatums[0] = N; + transdatums[1] = sumY; + + outputarray = construct_array(transdatums, 2, + NUMERICOID, -1, false, 'i'); + + PG_RETURN_ARRAYTYPE_P(outputarray); + } + + + Datum numeric_regr_sxx_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Numeric newvalX = PG_GETARG_NUMERIC(2); + ArrayType *outputarray; + Datum *transdatums; + int ndatums; + Datum N, + sumX, + sumX2; + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 3) + elog(ERROR, "expected 3-element numeric array"); + N = transdatums[0]; + sumX = transdatums[1]; + sumX2 = transdatums[2]; + + N = DirectFunctionCall1(numeric_inc, N); + sumX = DirectFunctionCall2(numeric_add, sumX, + NumericGetDatum(newvalX)); + sumX2 = DirectFunctionCall2(numeric_add, sumX2, + DirectFunctionCall2(numeric_mul, + NumericGetDatum(newvalX), + NumericGetDatum(newvalX))); + + transdatums[0] = N; + transdatums[1] = sumX; + transdatums[2] = sumX2; + + outputarray = construct_array(transdatums, 3, + NUMERICOID, -1, false, 'i'); + + + PG_RETURN_ARRAYTYPE_P(outputarray); + } + + Datum numeric_regr_syy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Numeric newvalY = PG_GETARG_NUMERIC(1); + ArrayType *outputarray; + Datum *transdatums; + int ndatums; + Datum N, + sumY, + sumY2; + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 3) + elog(ERROR, "expected 3-element numeric array"); + N = transdatums[0]; + sumY = transdatums[1]; + sumY2 = transdatums[2]; + + N = DirectFunctionCall1(numeric_inc, N); + sumY = DirectFunctionCall2(numeric_add, sumY, + NumericGetDatum(newvalY)); + sumY2 = DirectFunctionCall2(numeric_add, sumY2, + DirectFunctionCall2(numeric_mul, + NumericGetDatum(newvalY), + NumericGetDatum(newvalY))); + + transdatums[0] = N; + transdatums[1] = sumY; + transdatums[2] = sumY2; + + outputarray = construct_array(transdatums, 3, + NUMERICOID, -1, false, 'i'); + + PG_RETURN_ARRAYTYPE_P(outputarray); + } + + Datum numeric_regr_sxy_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Numeric newvalX = PG_GETARG_NUMERIC(2); + Numeric newvalY = PG_GETARG_NUMERIC(1); + ArrayType *outputarray; + Datum *transdatums; + int ndatums; + Datum N, sumX, sumY, sumXY; + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 4) + elog(ERROR, "expected 4-element numeric array"); + N = transdatums[0]; + sumX = transdatums[1]; + sumY = transdatums[2]; + sumXY = transdatums[3]; + + N = DirectFunctionCall1(numeric_inc, N); + sumX = DirectFunctionCall2(numeric_add, sumX, + NumericGetDatum(newvalX)); + sumY = DirectFunctionCall2(numeric_add, sumY, + NumericGetDatum(newvalY)); + sumXY = DirectFunctionCall2(numeric_add, sumXY, + DirectFunctionCall2(numeric_mul, + NumericGetDatum(newvalX), + NumericGetDatum(newvalY))); + + transdatums[0] = N; + transdatums[1] = sumX; + transdatums[2] = sumY; + transdatums[3] = sumXY; + + outputarray = construct_array(transdatums, 4, + NUMERICOID, -1, false, 'i'); + + PG_RETURN_ARRAYTYPE_P(outputarray); + } + + + Datum numeric_regr_all_accum(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Numeric newvalX = PG_GETARG_NUMERIC(2); + Numeric newvalY = PG_GETARG_NUMERIC(1); + ArrayType *outputarray; + Datum *transdatums; + int ndatums; + Datum N, sumX, sumX2, sumY, sumY2, sumXY; + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 6) + elog(ERROR, "expected 6-element numeric array"); + N = transdatums[0]; + sumX = transdatums[1]; + sumX2 = transdatums[2]; + sumY = transdatums[3]; + sumY2 = transdatums[4]; + sumXY = transdatums[5]; + + N = DirectFunctionCall1(numeric_inc, N); + + /* Probably can and should be optimized to not repeat + * NumericGetDatum several times */ + sumX = DirectFunctionCall2(numeric_add, sumX, + NumericGetDatum(newvalX)); + sumY = DirectFunctionCall2(numeric_add, sumY, + NumericGetDatum(newvalY)); + sumXY = DirectFunctionCall2(numeric_add, sumXY, + DirectFunctionCall2(numeric_mul, + NumericGetDatum(newvalX), + NumericGetDatum(newvalY))); + sumX2 = DirectFunctionCall2(numeric_add, sumX2, + DirectFunctionCall2(numeric_mul, + NumericGetDatum(newvalX), + NumericGetDatum(newvalX))); + sumY2 = DirectFunctionCall2(numeric_add, sumY2, + DirectFunctionCall2(numeric_mul, + NumericGetDatum(newvalY), + NumericGetDatum(newvalY))); + + transdatums[0] = N; + transdatums[1] = sumX; + transdatums[2] = sumX2; + transdatums[3] = sumY; + transdatums[4] = sumY2; + transdatums[5] = sumXY; + + outputarray = construct_array(transdatums, 6, + NUMERICOID, -1, false, 'i'); + + PG_RETURN_ARRAYTYPE_P(outputarray); + } + + + + /* * Integer data types all use Numeric accumulators to share code and * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation *************** *** 2151,2156 **** --- 2398,2416 ---- PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval)); } + Datum numeric_regr_count_accum(PG_FUNCTION_ARGS) + { + int64 i = PG_GETARG_INT64(0); + if (PG_ARGISNULL(1)||PG_ARGISNULL(2)) + { + PG_RETURN_INT64(i); + } + else + { + PG_RETURN_INT64(i+1); + } + } + Datum numeric_avg(PG_FUNCTION_ARGS) { *************** *** 2283,2288 **** --- 2543,3392 ---- return res; } + Datum numeric_regr_avg(PG_FUNCTION_ARGS) + { + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Datum *transdatums; + int ndatums; + Numeric N, + sum; + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 2) + elog(ERROR, "expected 2-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sum = DatumGetNumeric(transdatums[1]); + + /* SQL92 defines AVG of no values to be NULL */ + /* N is zero iff no digits (cf. numeric_uminus) */ + if (N->varlen == NUMERIC_HDRSZ) + PG_RETURN_NULL(); + + PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, + NumericGetDatum(sum), + NumericGetDatum(N))); + } + + + Datum numeric_regr_sxx(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, + sumX, + sumX2, + res; + NumericVar vN, + vsumX, + vsumX2; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 3) + elog(ERROR, "expected 3-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumX2 = DatumGetNumeric(transdatums[2]); + + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumX2); + set_var_from_num(sumX2, &vsumX2); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale * 2; + + mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */ + mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */ + sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */ + + if (cmp_var(&vsumX2, &const_zero) <= 0) + { + /* Watch out for roundoff error producing a negative numerator */ + res = make_result(&const_zero); + } + else + { + rscale = select_div_scale(&vsumX2, &vN); + div_var(&vsumX2, &vN, &vsumX, rscale, true); + + res = make_result(&vsumX); + } + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumX2); + + PG_RETURN_NUMERIC(res); + } + + + Datum numeric_regr_syy(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, + sumY, + sumY2, + res; + NumericVar vN, + vsumY, + vsumY2; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 3) + elog(ERROR, "expected 3-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumY = DatumGetNumeric(transdatums[1]); + sumY2 = DatumGetNumeric(transdatums[2]); + + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumY2)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumY2); + set_var_from_num(sumY2, &vsumY2); + + /* compute rscale for mul_var calls */ + rscale = vsumY.dscale * 2; + + mul_var(&vsumY, &vsumY, &vsumY, rscale); /* vsumY = sumY * sumY */ + mul_var(&vN, &vsumY2, &vsumY2, rscale); /* vsumY2 = N * sumY2 */ + sub_var(&vsumY2, &vsumY, &vsumY2); /* N * sumY2 - sumY * sumY */ + + if (cmp_var(&vsumY2, &const_zero) <= 0) + { + /* Watch out for roundoff error producing a negative numerator */ + res = make_result(&const_zero); + } + else + { + rscale = select_div_scale(&vsumY2, &vN); + div_var(&vsumY2, &vN, &vsumY, rscale, true); /* variance */ + + res = make_result(&vsumY); + } + + free_var(&vN); + free_var(&vsumY); + free_var(&vsumY2); + + PG_RETURN_NUMERIC(res); + } + + Datum numeric_regr_sxy(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, sumX, sumY, sumXY, res; + NumericVar vN, vsumX, vsumY, vsumXY; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 4) + elog(ERROR, "expected 4-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumY = DatumGetNumeric(transdatums[2]); + sumXY = DatumGetNumeric(transdatums[3]); + + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumXY); + set_var_from_num(sumXY, &vsumXY); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale + vsumY.dscale; + + mul_var(&vsumX, &vsumY, &vsumY, rscale); /* vsumY = sumX * sumY */ + mul_var(&vN, &vsumXY, &vsumXY, rscale); /* vsumXY = N * sumXY */ + sub_var(&vsumXY, &vsumY, &vsumXY); /* N * sumXY - sumX * sumY */ + + rscale = select_div_scale(&vsumXY, &vN); + div_var(&vsumXY, &vN, &vsumY, rscale, true); /* variance */ + + res = make_result(&vsumY); + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + + PG_RETURN_NUMERIC(res); + } + + Datum numeric_covar_samp(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, sumX, sumY, sumXY, res; + NumericVar vN, vsumX, vsumY, vsumXY, vNminus1; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 4) + elog(ERROR, "expected 4-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumY = DatumGetNumeric(transdatums[2]); + sumXY = DatumGetNumeric(transdatums[3]); + + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + init_var(&vN); + set_var_from_num(N, &vN); + init_var(&vNminus1); + sub_var(&vN, &const_one, &vNminus1); + + comp = &const_zero; + + if (cmp_var(&vNminus1, comp) <= 0) + { + free_var(&vN); + free_var(&vNminus1); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumXY); + set_var_from_num(sumXY, &vsumXY); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale + vsumY.dscale; + + mul_var(&vsumX, &vsumY, &vsumY, rscale); /* vsumY = sumX * sumY */ + mul_var(&vN, &vsumXY, &vsumXY, rscale); /* vsumXY = N * sumXY */ + sub_var(&vsumXY, &vsumY, &vsumXY); /* N * sumXY - sumX * sumY */ + + mul_var(&vN, &vNminus1, &vNminus1, 0); /* N * (N - 1) */ + rscale = select_div_scale(&vsumXY, &vNminus1); + div_var(&vsumXY, &vNminus1, &vsumY, rscale, true); + + res = make_result(&vsumY); + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vNminus1); + + PG_RETURN_NUMERIC(res); + } + + + Datum numeric_covar_pop(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, sumX, sumY, sumXY, res; + NumericVar vN, vsumX, vsumY, vsumXY; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 4) + elog(ERROR, "expected 4-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumY = DatumGetNumeric(transdatums[2]); + sumXY = DatumGetNumeric(transdatums[3]); + + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumXY); + set_var_from_num(sumXY, &vsumXY); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale + vsumY.dscale; + + mul_var(&vsumX, &vsumY, &vsumY, rscale); /* vsumY = sumX * sumY */ + mul_var(&vN, &vsumXY, &vsumXY, rscale); /* vsumXY = N * sumXY */ + sub_var(&vsumXY, &vsumY, &vsumXY); /* N * sumXY - sumX * sumY */ + + mul_var(&vN, &vN, &vN, 0); /* N * N */ + rscale = select_div_scale(&vsumXY, &vN); + div_var(&vsumXY, &vN, &vsumY, rscale, true); + + res = make_result(&vsumY); + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + + PG_RETURN_NUMERIC(res); + } + + Datum numeric_corr(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, sumX, sumY, sumXY, sumX2, sumY2, res; + NumericVar vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 6) + elog(ERROR, "expected 6-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumX2 = DatumGetNumeric(transdatums[2]); + sumY = DatumGetNumeric(transdatums[3]); + sumY2 = DatumGetNumeric(transdatums[4]); + sumXY = DatumGetNumeric(transdatums[5]); + /* I'm not really sure that the check for NAN does make sense + * for sumY2 when sumY is already not NAN, but ... + */ + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || + NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) || + NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2)) + { + PG_RETURN_NUMERIC(make_result(&const_nan)); + } + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumX2); + set_var_from_num(sumX2, &vsumX2); + init_var(&vsumY2); + set_var_from_num(sumY2, &vsumY2); + init_var(&vsumXY); + set_var_from_num(sumXY, &vsumXY); + init_var(&vtmpXY); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale + vsumY.dscale; + + mul_var(&vsumX, &vsumY, &vtmpXY, rscale); /* vtmpXY = sumX * sumY */ + mul_var(&vN, &vsumXY, &vsumXY, rscale); /* vsumXY = N * sumXY */ + sub_var(&vsumXY, &vtmpXY, &vsumXY); /* vsumXY = N * sumXY - sumX * sumY */ + + rscale = vsumXY.dscale * 2; + mul_var(&vsumXY, &vsumXY, &vsumXY, rscale); + + rscale = 2 * vsumX.dscale; + + mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */ + mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */ + sub_var(&vsumX2, &vsumX, &vsumX2); /* vsumX2 = N * sumX2 - sumX * sumX */ + + if (cmp_var(&vsumX2, comp) <= 0) + { + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + PG_RETURN_NULL(); + } + + + rscale = 2 * vsumY.dscale; + + mul_var(&vsumY, &vsumY, &vsumY, rscale); /* vsumY = sumY * sumY */ + mul_var(&vN, &vsumY2, &vsumY2, rscale); /* vsumY2 = N * sumY2 */ + sub_var(&vsumY2, &vsumY, &vsumY2); /* vsumY2 = N * sumY2 - sumY * sumY */ + + if (cmp_var(&vsumY2, comp) <= 0) + { + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + PG_RETURN_NULL(); + } + + rscale = vsumY2.dscale + vsumX2.dscale; + mul_var(&vsumX2, &vsumY2, &vsumY2, rscale); /* vsumY2 = sumX2 * sumY2 */ + + rscale = select_div_scale(&vsumXY, &vsumY2); + div_var(&vsumXY, &vsumY2, &vsumY, rscale, true); /* variance */ + + sqrt_var(&vsumY, &vsumY, rscale); + res = make_result(&vsumY); + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + + PG_RETURN_NUMERIC(res); + } + + Datum numeric_regr_r2(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, sumX, sumY, sumXY, sumX2, sumY2, res; + NumericVar vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 6) + elog(ERROR, "expected 6-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumX2 = DatumGetNumeric(transdatums[2]); + sumY = DatumGetNumeric(transdatums[3]); + sumY2 = DatumGetNumeric(transdatums[4]); + sumXY = DatumGetNumeric(transdatums[5]); + /* I'm not really sure that the check for NAN does make sense + * for sumY2 when sumY is already not NAN, but ... + */ + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || + NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) || + NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2)) + { + PG_RETURN_NUMERIC(make_result(&const_nan)); + } + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumX2); + set_var_from_num(sumX2, &vsumX2); + init_var(&vsumY2); + set_var_from_num(sumY2, &vsumY2); + init_var(&vsumXY); + set_var_from_num(sumXY, &vsumXY); + init_var(&vtmpXY); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale + vsumY.dscale; + + mul_var(&vsumX, &vsumY, &vtmpXY, rscale); /* vtmpXY = sumX * sumY */ + mul_var(&vN, &vsumXY, &vsumXY, rscale); /* vsumXY = N * sumXY */ + sub_var(&vsumXY, &vtmpXY, &vsumXY); /* vtmpXY = N * sumXY - sumX * sumY */ + + rscale = vsumXY.dscale * 2; + mul_var(&vsumXY, &vsumXY, &vsumXY, rscale); + + + rscale = 2 * vsumX.dscale; + + mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */ + mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */ + sub_var(&vsumX2, &vsumX, &vsumX2); /* vsumX2 = N * sumX2 - sumX * sumX */ + + if (cmp_var(&vsumX2, comp) <= 0) + { + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + PG_RETURN_NULL(); + } + + + rscale = 2 * vsumY.dscale; + + mul_var(&vsumY, &vsumY, &vsumY, rscale); /* vsumY = sumY * sumY */ + mul_var(&vN, &vsumY2, &vsumY2, rscale); /* vsumY2 = N * sumY2 */ + sub_var(&vsumY2, &vsumY, &vsumY2); /* vsumY2 = N * sumY2 - sumY * sumY */ + + if (cmp_var(&vsumY2, comp) <= 0) + { + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + PG_RETURN_NULL(); + } + + + rscale = vsumY2.dscale + vsumX2.dscale; + mul_var(&vsumX2, &vsumY2, &vsumY2, rscale); /* vsumY2 = sumX2 * sumY2 */ + + rscale = select_div_scale(&vsumXY, &vsumY2); + div_var(&vsumXY, &vsumY2, &vsumY, rscale, true); /* variance */ + + res = make_result(&vsumY); + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + + PG_RETURN_NUMERIC(res); + } + + + Datum numeric_regr_slope(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, sumX, sumY, sumXY, sumX2, sumY2, res; + NumericVar vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 6) + elog(ERROR, "expected 6-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumX2 = DatumGetNumeric(transdatums[2]); + sumY = DatumGetNumeric(transdatums[3]); + sumY2 = DatumGetNumeric(transdatums[4]); + sumXY = DatumGetNumeric(transdatums[5]); + /* I'm not really sure that the check for NAN does make sense + * for sumY2 when sumY is already not NAN, but ... + */ + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || + NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) || + NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2)) + { + PG_RETURN_NUMERIC(make_result(&const_nan)); + } + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumX2); + set_var_from_num(sumX2, &vsumX2); + init_var(&vsumY2); + set_var_from_num(sumY2, &vsumY2); + init_var(&vsumXY); + set_var_from_num(sumXY, &vsumXY); + init_var(&vtmpXY); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale + vsumY.dscale; + + mul_var(&vsumX, &vsumY, &vtmpXY, rscale); /* vtmpXY = sumX * sumY */ + mul_var(&vN, &vsumXY, &vsumXY, rscale); /* vsumXY = N * sumXY */ + sub_var(&vsumXY, &vtmpXY, &vsumXY); /* vtmpXY = N * sumXY - sumX * sumY */ + + rscale = 2 * vsumX.dscale; + + mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */ + mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */ + sub_var(&vsumX2, &vsumX, &vsumX2); /* vsumX2 = N * sumX2 - sumX * sumX */ + + if (cmp_var(&vsumX2, comp) <= 0) + { + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + PG_RETURN_NULL(); + } + + + rscale = select_div_scale(&vsumXY, &vsumX2); + div_var(&vsumXY, &vsumX2, &vsumX, rscale, true); /* variance */ + + res = make_result(&vsumX); + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + + PG_RETURN_NUMERIC(res); + } + + + Datum numeric_regr_intercept(PG_FUNCTION_ARGS) + { + ArrayType *transarray; + Datum *transdatums; + int ndatums; + Numeric N, sumX, sumY, sumXY, sumX2, sumY2, res; + NumericVar vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2, vtmpX, vtmpX2, vtmpY2; + NumericVar *comp; + int rscale; + + transarray = PG_GETARG_ARRAYTYPE_P(0); + + + /* We assume the input is array of numeric */ + deconstruct_array(transarray, + NUMERICOID, -1, false, 'i', + &transdatums, NULL, &ndatums); + if (ndatums != 6) + elog(ERROR, "expected 6-element numeric array"); + N = DatumGetNumeric(transdatums[0]); + sumX = DatumGetNumeric(transdatums[1]); + sumX2 = DatumGetNumeric(transdatums[2]); + sumY = DatumGetNumeric(transdatums[3]); + sumY2 = DatumGetNumeric(transdatums[4]); + sumXY = DatumGetNumeric(transdatums[5]); + /* I'm not really sure that the check for NAN does make sense + * for sumY2 when sumY is already not NAN, but ... + */ + if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || + NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) || + NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2)) + { + PG_RETURN_NUMERIC(make_result(&const_nan)); + } + + init_var(&vN); + set_var_from_num(N, &vN); + + comp = &const_zero; + + if (cmp_var(&vN, comp) <= 0) + { + free_var(&vN); + PG_RETURN_NULL(); + } + + + init_var(&vsumX); + set_var_from_num(sumX, &vsumX); + init_var(&vsumY); + set_var_from_num(sumY, &vsumY); + init_var(&vsumX2); + set_var_from_num(sumX2, &vsumX2); + init_var(&vsumY2); + set_var_from_num(sumY2, &vsumY2); + init_var(&vsumXY); + set_var_from_num(sumXY, &vsumXY); + init_var(&vtmpXY); + init_var(&vtmpX2); + init_var(&vtmpY2); + + /* compute rscale for mul_var calls */ + rscale = vsumX.dscale + vsumXY.dscale; + mul_var(&vsumX, &vsumXY, &vtmpXY, rscale); /* vtmpXY = sumX * sumXY */ + rscale = vsumY.dscale + vsumX2.dscale; + mul_var(&vsumY, &vsumX2, &vtmpY2, rscale); /* vtmpY2 = vsumY * sumX2 */ + sub_var(&vtmpY2, &vtmpXY, &vtmpXY); /* vtmpXY = vsumY * sumX2 - sumX * sumXY */ + + rscale = 2 * vsumX.dscale; + mul_var(&vsumX, &vsumX, &vtmpX, rscale); /* vsumX = sumX * sumX */ + mul_var(&vN, &vsumX2, &vtmpX2, rscale); /* vtmpX2 = N * sumX2 */ + sub_var(&vtmpX2, &vtmpX, &vtmpX2); /* vtmpX2 = N * sumX2 - sumX * sumX */ + + if (cmp_var(&vsumX2, comp) <= 0) + { + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vtmpX2); + free_var(&vtmpY2); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + PG_RETURN_NULL(); + } + + rscale = select_div_scale(&vtmpXY, &vtmpX2); + div_var(&vtmpXY, &vtmpX2, &vsumX, rscale, true); + + res = make_result(&vsumX); + + free_var(&vN); + free_var(&vsumX); + free_var(&vsumY); + free_var(&vsumXY); + free_var(&vtmpX2); + free_var(&vtmpY2); + free_var(&vsumY2); + free_var(&vsumX2); + free_var(&vtmpXY); + + PG_RETURN_NUMERIC(res); + } + + Datum numeric_var_samp(PG_FUNCTION_ARGS) { Index: src/backend/utils/adt/ruleutils.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v retrieving revision 1.228 diff -c -r1.228 ruleutils.c *** src/backend/utils/adt/ruleutils.c 14 Jul 2006 14:52:24 -0000 1.228 --- src/backend/utils/adt/ruleutils.c 25 Jul 2006 09:13:26 -0000 *************** *** 3880,3894 **** get_agg_expr(Aggref *aggref, deparse_context *context) { StringInfo buf = context->buf; ! Oid argtype = exprType((Node *) aggref->target); appendStringInfo(buf, "%s(%s", ! generate_function_name(aggref->aggfnoid, 1, &argtype), aggref->aggdistinct ? "DISTINCT " : ""); if (aggref->aggstar) appendStringInfo(buf, "*"); else ! get_rule_expr((Node *) aggref->target, context, true); appendStringInfoChar(buf, ')'); } --- 3880,3908 ---- get_agg_expr(Aggref *aggref, deparse_context *context) { StringInfo buf = context->buf; ! Oid argtypes[FUNC_MAX_ARGS]; ! int nargs; ! ListCell *l; ! ! nargs = 0; ! foreach(l, aggref->args) ! { ! if (nargs >= FUNC_MAX_ARGS) ! ereport(ERROR, ! (errcode(ERRCODE_TOO_MANY_ARGUMENTS), ! errmsg("too many arguments"))); ! argtypes[nargs] = exprType((Node *) lfirst(l)); ! nargs++; ! } appendStringInfo(buf, "%s(%s", ! generate_function_name(aggref->aggfnoid, nargs, argtypes), aggref->aggdistinct ? "DISTINCT " : ""); + /* aggstar can be set only in one-argument aggregates */ if (aggref->aggstar) appendStringInfo(buf, "*"); else ! get_rule_expr((Node *) aggref->args, context, true); appendStringInfoChar(buf, ')'); } Index: src/include/catalog/pg_aggregate.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_aggregate.h,v retrieving revision 1.55 diff -c -r1.55 pg_aggregate.h *** src/include/catalog/pg_aggregate.h 21 Jul 2006 20:51:33 -0000 1.55 --- src/include/catalog/pg_aggregate.h 25 Jul 2006 09:14:29 -0000 *************** *** 194,199 **** --- 194,240 ---- DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" )); DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); + DATA(insert ( 2800 numeric_regr_count_accum - 0 20 0 )); + DATA(insert ( 2801 float8_regr_count_accum - 0 20 0 )); + DATA(insert ( 2802 float4_regr_sxx_accum float8_regr_sxx 0 1022 "{0,0,0}" )); + DATA(insert ( 2803 float4_regr_syy_accum float8_regr_syy 0 1022 "{0,0,0}" )); + DATA(insert ( 2804 float4_regr_sxy_accum float8_regr_sxy 0 1022 "{0,0,0,0}" )); + DATA(insert ( 2805 float4_regr_avgx_accum float8_regr_avg 0 1022 "{0,0}" )); + DATA(insert ( 2806 float4_regr_avgy_accum float8_regr_avg 0 1022 "{0,0}" )); + + DATA(insert ( 2807 float8_regr_sxx_accum float8_regr_sxx 0 1022 "{0,0,0}" )); + DATA(insert ( 2808 float8_regr_syy_accum float8_regr_syy 0 1022 "{0,0,0}" )); + DATA(insert ( 2809 float8_regr_sxy_accum float8_regr_sxy 0 1022 "{0,0,0,0}" )); + DATA(insert ( 2810 float8_regr_avgx_accum float8_regr_avg 0 1022 "{0,0}" )); + DATA(insert ( 2811 float8_regr_avgy_accum float8_regr_avg 0 1022 "{0,0}" )); + + DATA(insert ( 2812 numeric_regr_sxx_accum numeric_regr_sxx 0 1231 "{0,0,0}" )); + DATA(insert ( 2813 numeric_regr_syy_accum numeric_regr_syy 0 1231 "{0,0,0}" )); + DATA(insert ( 2814 numeric_regr_sxy_accum numeric_regr_sxy 0 1231 "{0,0,0,0}" )); + DATA(insert ( 2815 numeric_regr_avgx_accum numeric_regr_avg 0 1231 "{0,0}" )); + DATA(insert ( 2816 numeric_regr_avgy_accum numeric_regr_avg 0 1231 "{0,0}" )); + + DATA(insert ( 2817 float4_regr_sxy_accum float8_covar_pop 0 1022 "{0,0,0,0}" )); + DATA(insert ( 2818 float8_regr_sxy_accum float8_covar_pop 0 1022 "{0,0,0,0}" )); + DATA(insert ( 2819 numeric_regr_sxy_accum numeric_covar_pop 0 1231 "{0,0,0,0}" )); + DATA(insert ( 2820 float4_regr_sxy_accum float8_covar_samp 0 1022 "{0,0,0,0}" )); + DATA(insert ( 2821 float8_regr_sxy_accum float8_covar_samp 0 1022 "{0,0,0,0}" )); + DATA(insert ( 2822 numeric_regr_sxy_accum numeric_covar_samp 0 1231 "{0,0,0,0}" )); + + DATA(insert ( 2823 float4_regr_all_accum float8_corr 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2824 float8_regr_all_accum float8_corr 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2825 numeric_regr_all_accum numeric_corr 0 1231 "{0,0,0,0,0,0}" )); + DATA(insert ( 2826 float4_regr_all_accum float8_regr_r2 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2827 float8_regr_all_accum float8_regr_r2 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2828 numeric_regr_all_accum numeric_regr_r2 0 1231 "{0,0,0,0,0,0}" )); + DATA(insert ( 2829 float4_regr_all_accum float8_regr_slope 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2830 float8_regr_all_accum float8_regr_slope 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2831 numeric_regr_all_accum numeric_regr_slope 0 1231 "{0,0,0,0,0,0}" )); + DATA(insert ( 2832 float4_regr_all_accum float8_regr_intercept 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2833 float8_regr_all_accum float8_regr_intercept 0 1022 "{0,0,0,0,0,0}" )); + DATA(insert ( 2834 numeric_regr_all_accum numeric_regr_intercept 0 1231 "{0,0,0,0,0,0}" )); + + /* boolean-and and boolean-or */ DATA(insert ( 2517 booland_statefunc - 0 16 _null_ )); DATA(insert ( 2518 boolor_statefunc - 0 16 _null_ )); *************** *** 214,220 **** */ extern void AggregateCreate(const char *aggName, Oid aggNamespace, ! Oid aggBaseType, List *aggtransfnName, List *aggfinalfnName, List *aggsortopName, --- 255,262 ---- */ extern void AggregateCreate(const char *aggName, Oid aggNamespace, ! Oid *aggBaseTypeArray, ! int numArgs, List *aggtransfnName, List *aggfinalfnName, List *aggsortopName, Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.416 diff -c -r1.416 pg_proc.h *** src/include/catalog/pg_proc.h 21 Jul 2006 20:51:33 -0000 1.416 --- src/include/catalog/pg_proc.h 25 Jul 2006 09:14:30 -0000 *************** *** 2728,2733 **** --- 2728,2827 ---- DESCR("AVG(int4) transition function"); DATA(insert OID = 1964 ( int8_avg PGNSP PGUID 12 f f t f i 1 1700 "1016" _null_ _null_ _null_ int8_avg - _null_ )); DESCR("AVG(int) aggregate final function"); + DATA(insert OID = 2850 ( numeric_regr_count_accum PGNSP PGUID 12 f f t f i 3 20 "20 1700 1700" _null_ _null_ _null_ numeric_regr_count_accum - _null_ )); + DESCR("REGR_COUNT(numeric) transition function"); + DATA(insert OID = 2851 ( float8_regr_count_accum PGNSP PGUID 12 f f t f i 3 20 "20 701 701" _null_ _null_ _null_ float8_regr_count_accum - _null_ )); + DESCR("REGR_COUNT(double, double) transition function"); + DATA(insert OID = 2852 ( float4_regr_sxx_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_sxx_accum - _null_ )); + DESCR("REGR_SXX(float, float) aggregate transition function"); + DATA(insert OID = 2853 ( float4_regr_syy_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_syy_accum - _null_ )); + DESCR("REGR_SYY(float, float) aggregate transition function"); + DATA(insert OID = 2854 ( float4_regr_sxy_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_sxy_accum - _null_ )); + DESCR("REGR_SXY(float, float) aggregate transition function"); + DATA(insert OID = 2855 ( float4_regr_avgx_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_avgx_accum - _null_ )); + DESCR("REGR_AVGX(float, float) aggregate transition function"); + DATA(insert OID = 2856 ( float4_regr_avgy_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_avgy_accum - _null_ )); + DESCR("REGR_AVGY(float, float) aggregate transition function"); + DATA(insert OID = 2857 ( float8_regr_sxx_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_sxx_accum - _null_ )); + DESCR("REGR_SXX(double, double) aggregate transition function"); + DATA(insert OID = 2858 ( float8_regr_syy_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_syy_accum - _null_ )); + DESCR("REGR_SYY(double, double) aggregate transition function"); + DATA(insert OID = 2859 ( float8_regr_sxy_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_sxy_accum - _null_ )); + DESCR("REGR_SXY(double, double) aggregate transition function"); + DATA(insert OID = 2860 ( float8_regr_avgx_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_avgx_accum - _null_ )); + DESCR("REGR_AVGX(float, float) aggregate transition function"); + DATA(insert OID = 2861 ( float8_regr_avgy_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_avgy_accum - _null_ )); + DESCR("REGR_AVGY(float, float) aggregate transition function"); + DATA(insert OID = 2862 ( numeric_regr_sxx_accum PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_sxx_accum - _null_ )); + DESCR("REGR_SXX(numeric, numeric) aggregate transition function"); + DATA(insert OID = 2863 ( numeric_regr_syy_accum PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_syy_accum - _null_ )); + DESCR("REGR_SYY(numeric, numeric) aggregate transition function"); + DATA(insert OID = 2864 ( numeric_regr_sxy_accum PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_sxy_accum - _null_ )); + DESCR("REGR_SXY(numeric, numeric) aggregate transition function"); + DATA(insert OID = 2865 ( numeric_regr_avgx_accum PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_avgx_accum - _null_ )); + DESCR("REGR_AVGX(numeric, numeric) aggregate transition function"); + DATA(insert OID = 2866 ( numeric_regr_avgy_accum PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_avgy_accum - _null_ )); + DESCR("REGR_AVGY(numeric, numeric) aggregate transition function"); + + DATA(insert OID = 2867 ( float8_regr_sxx PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_sxx - _null_ )); + DESCR("REGR_SXX(double, double) aggregate final function"); + DATA(insert OID = 2868 ( float8_regr_syy PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_syy - _null_ )); + DESCR("REGR_SYY(double, double) aggregate final function"); + DATA(insert OID = 2869 ( float8_regr_sxy PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_sxy - _null_ )); + DESCR("REGR_SXY(double, double) aggregate final function"); + DATA(insert OID = 2870 ( float8_regr_avg PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_avg - _null_ )); + DESCR("REGR_AVGX(double, double) AND REGR_AVGY(double,double) aggregate final function"); + + DATA(insert OID = 2871 ( numeric_regr_sxx PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_sxx - _null_ )); + DESCR("REGR_SXX(numeric, numeric) aggregate final function"); + DATA(insert OID = 2872 ( numeric_regr_syy PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_syy - _null_ )); + DESCR("REGR_SYY(numeric, numeric) aggregate final function"); + DATA(insert OID = 2873 ( numeric_regr_sxy PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_sxy - _null_ )); + DESCR("REGR_SXY(numeric, numeric) aggregate final function"); + DATA(insert OID = 2874 ( numeric_regr_avg PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_avg - _null_ )); + DESCR("REGR_AVGX(numeric, numeric) AND REGR_AVGY(numeric, numeric) aggregate final function"); + DATA(insert OID = 2875 ( float8_covar_samp PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_covar_samp - _null_ )); + DESCR("COVAR_SAMP(float8, float8) aggregate final function"); + DATA(insert OID = 2876 ( numeric_covar_samp PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_covar_samp - _null_ )); + DESCR("COVAR_SAMP(numeric, numeric) aggregate final function"); + DATA(insert OID = 2877 ( float8_covar_pop PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_covar_pop - _null_ )); + DESCR("COVAR_POP(float8, float8) aggregate final function"); + DATA(insert OID = 2878 ( numeric_covar_pop PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_covar_pop - _null_ )); + DESCR("COVAR_POP(numeric, numeric) aggregate final function"); + DATA(insert OID = 2879 ( float4_regr_all_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_all_accum - _null_ )); + DESCR("REGR_...(float4, float4) aggregate transition function"); + DATA(insert OID = 2880 ( float8_regr_all_accum PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_all_accum - _null_ )); + DESCR("REGR_...(float8, float8) aggregate transition function"); + DATA(insert OID = 2881 ( numeric_regr_all_accum PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_all_accum - _null_ )); + DESCR("REGR_...(numeric, numeric) aggregate transition function"); + + DATA(insert OID = 2882 ( float4_corr PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_corr - _null_ )); + DESCR("CORR(float4, float4) aggregate final function"); + DATA(insert OID = 2883 ( float4_regr_r2 PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_r2 - _null_ )); + DESCR("REGR_R2(float4, float4) aggregate final function"); + DATA(insert OID = 2884 ( float4_regr_slope PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_slope - _null_ )); + DESCR("REGR_SLOPE(float4, float4) aggregate final function"); + DATA(insert OID = 2885 ( float4_regr_intercept PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_intercept - _null_ )); + DESCR("REGR_INTERCEPT(float4, float4) aggregate final function"); + + DATA(insert OID = 2886 ( float8_corr PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_corr - _null_ )); + DESCR("CORR(double, double) aggregate final function"); + DATA(insert OID = 2887 ( float8_regr_r2 PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_r2 - _null_ )); + DESCR("REGR_R2(double, double) aggregate final function"); + DATA(insert OID = 2888 ( float8_regr_slope PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_slope - _null_ )); + DESCR("REGR_SLOPE(double, double) aggregate final function"); + DATA(insert OID = 2889 ( float8_regr_intercept PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_intercept - _null_ )); + DESCR("REGR_INTERCEPT(double, double) aggregate final function"); + + DATA(insert OID = 2890 ( numeric_corr PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_corr - _null_ )); + DESCR("CORR(numeric, numeric) aggregate final function"); + DATA(insert OID = 2891 ( numeric_regr_r2 PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_r2 - _null_ )); + DESCR("REGR_R2(numeric, numeric) aggregate final function"); + DATA(insert OID = 2892 ( numeric_regr_slope PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_slope - _null_ )); + DESCR("REGR_SLOPE(numeric, numeric) aggregate final function"); + DATA(insert OID = 2893 ( numeric_regr_intercept PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_intercept - _null_ )); + DESCR("REGR_INTERCEPT(numeric, numeric) aggregate final function"); + /* To ASCII conversion */ DATA(insert OID = 1845 ( to_ascii PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ to_ascii_default - _null_ )); *************** *** 3192,3197 **** --- 3286,3330 ---- DATA(insert OID = 2158 ( stddev PGNSP PGUID 12 t f f f i 1 701 "701" _null_ _null_ _null_ aggregate_dummy - _null_ )); DATA(insert OID = 2159 ( stddev PGNSP PGUID 12 t f f f i 1 1700 "1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2800 ( regr_count PGNSP PGUID 12 t f f f i 2 20 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2801 ( regr_count PGNSP PGUID 12 t f f f i 2 20 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2802 ( regr_sxx PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2803 ( regr_syy PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2804 ( regr_sxy PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2805 ( regr_avgx PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2806 ( regr_avgy PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2807 ( regr_sxx PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2808 ( regr_syy PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2809 ( regr_sxy PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2810 ( regr_avgx PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2811 ( regr_avgy PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2812 ( regr_sxx PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2813 ( regr_syy PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2814 ( regr_sxy PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2815 ( regr_avgx PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2816 ( regr_avgy PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + + DATA(insert OID = 2817 ( covar_pop PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2818 ( covar_pop PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2819 ( covar_pop PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2820 ( covar_samp PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2821 ( covar_samp PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2822 ( covar_samp PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + + DATA(insert OID = 2823 ( corr PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2824 ( corr PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2825 ( corr PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2826 ( regr_r2 PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2827 ( regr_r2 PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2828 ( regr_r2 PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2829 ( regr_slope PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2830 ( regr_slope PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2831 ( regr_slope PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2832 ( regr_intercept PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2833 ( regr_intercept PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2834 ( regr_intercept PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + + DATA(insert OID = 2160 ( text_pattern_lt PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_lt - _null_ )); DATA(insert OID = 2161 ( text_pattern_le PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_le - _null_ )); DATA(insert OID = 2162 ( text_pattern_eq PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_eq - _null_ )); Index: src/include/nodes/execnodes.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/nodes/execnodes.h,v retrieving revision 1.153 diff -c -r1.153 execnodes.h *** src/include/nodes/execnodes.h 13 Jul 2006 16:49:19 -0000 1.153 --- src/include/nodes/execnodes.h 25 Jul 2006 09:14:30 -0000 *************** *** 449,455 **** typedef struct AggrefExprState { ExprState xprstate; ! ExprState *target; /* state of my child node */ int aggno; /* ID number for agg within its plan node */ } AggrefExprState; --- 449,455 ---- typedef struct AggrefExprState { ExprState xprstate; ! List *args; /* states of argument expressions */ int aggno; /* ID number for agg within its plan node */ } AggrefExprState; Index: src/include/nodes/primnodes.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/nodes/primnodes.h,v retrieving revision 1.114 diff -c -r1.114 primnodes.h *** src/include/nodes/primnodes.h 13 Jul 2006 16:49:19 -0000 1.114 --- src/include/nodes/primnodes.h 25 Jul 2006 09:14:31 -0000 *************** *** 184,190 **** Expr xpr; Oid aggfnoid; /* pg_proc Oid of the aggregate */ Oid aggtype; /* type Oid of result of the aggregate */ ! Expr *target; /* expression we are aggregating on */ Index agglevelsup; /* > 0 if agg belongs to outer query */ bool aggstar; /* TRUE if argument was really '*' */ bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */ --- 184,190 ---- Expr xpr; Oid aggfnoid; /* pg_proc Oid of the aggregate */ Oid aggtype; /* type Oid of result of the aggregate */ ! List *args; /* arguments to the function */ Index agglevelsup; /* > 0 if agg belongs to outer query */ bool aggstar; /* TRUE if argument was really '*' */ bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */ Index: src/include/parser/parse_agg.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/parser/parse_agg.h,v retrieving revision 1.33 diff -c -r1.33 parse_agg.h *** src/include/parser/parse_agg.h 5 Mar 2006 15:58:57 -0000 1.33 --- src/include/parser/parse_agg.h 25 Jul 2006 09:14:31 -0000 *************** *** 19,25 **** extern void parseCheckAggregates(ParseState *pstate, Query *qry); ! extern void build_aggregate_fnexprs(Oid agg_input_type, Oid agg_state_type, Oid agg_result_type, Oid transfn_oid, --- 19,25 ---- extern void parseCheckAggregates(ParseState *pstate, Query *qry); ! extern void build_aggregate_fnexprs(Oid *agg_input_type, Oid agg_state_type, Oid agg_result_type, Oid transfn_oid, Index: src/include/utils/builtins.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v retrieving revision 1.280 diff -c -r1.280 builtins.h *** src/include/utils/builtins.h 21 Jul 2006 20:51:33 -0000 1.280 --- src/include/utils/builtins.h 25 Jul 2006 09:14:31 -0000 *************** *** 368,373 **** --- 368,389 ---- extern Datum float84le(PG_FUNCTION_ARGS); extern Datum float84gt(PG_FUNCTION_ARGS); extern Datum float84ge(PG_FUNCTION_ARGS); + extern Datum float8_regr_count_accum(PG_FUNCTION_ARGS); + extern Datum float8_regr_sxx_accum(PG_FUNCTION_ARGS); + extern Datum float8_regr_syy_accum(PG_FUNCTION_ARGS); + extern Datum float8_regr_sxy_accum(PG_FUNCTION_ARGS); + extern Datum float8_regr_avgx_accum(PG_FUNCTION_ARGS); + extern Datum float8_regr_avgy_accum(PG_FUNCTION_ARGS); + extern Datum float4_regr_sxx_accum(PG_FUNCTION_ARGS); + extern Datum float4_regr_syy_accum(PG_FUNCTION_ARGS); + extern Datum float4_regr_sxy_accum(PG_FUNCTION_ARGS); + extern Datum float4_regr_avgx_accum(PG_FUNCTION_ARGS); + extern Datum float4_regr_avgy_accum(PG_FUNCTION_ARGS); + extern Datum float8_regr_sxx(PG_FUNCTION_ARGS); + extern Datum float8_regr_syy(PG_FUNCTION_ARGS); + extern Datum float8_regr_sxy(PG_FUNCTION_ARGS); + extern Datum float8_regr_avg(PG_FUNCTION_ARGS); + /* dbsize.c */ extern Datum pg_tablespace_size_oid(PG_FUNCTION_ARGS); *************** *** 836,841 **** --- 852,885 ---- extern Datum int4_avg_accum(PG_FUNCTION_ARGS); extern Datum int8_avg(PG_FUNCTION_ARGS); extern Datum width_bucket_numeric(PG_FUNCTION_ARGS); + extern Datum numeric_regr_count_accum(PG_FUNCTION_ARGS); + extern Datum numeric_regr_sxx_accum(PG_FUNCTION_ARGS); + extern Datum numeric_regr_syy_accum(PG_FUNCTION_ARGS); + extern Datum numeric_regr_sxy_accum(PG_FUNCTION_ARGS); + extern Datum numeric_regr_avgx_accum(PG_FUNCTION_ARGS); + extern Datum numeric_regr_avgy_accum(PG_FUNCTION_ARGS); + extern Datum numeric_regr_sxx(PG_FUNCTION_ARGS); + extern Datum numeric_regr_syy(PG_FUNCTION_ARGS); + extern Datum numeric_regr_sxy(PG_FUNCTION_ARGS); + extern Datum numeric_regr_avg(PG_FUNCTION_ARGS); + extern Datum numeric_covar_pop(PG_FUNCTION_ARGS); + extern Datum numeric_covar_samp(PG_FUNCTION_ARGS); + extern Datum float8_covar_pop(PG_FUNCTION_ARGS); + extern Datum float8_covar_samp(PG_FUNCTION_ARGS); + + extern Datum float4_regr_all_accum(PG_FUNCTION_ARGS); + extern Datum float8_regr_all_accum(PG_FUNCTION_ARGS); + extern Datum float8_corr(PG_FUNCTION_ARGS); + extern Datum float8_regr_r2(PG_FUNCTION_ARGS); + extern Datum float8_regr_slope(PG_FUNCTION_ARGS); + extern Datum float8_regr_intercept(PG_FUNCTION_ARGS); + + extern Datum numeric_regr_all_accum(PG_FUNCTION_ARGS); + extern Datum numeric_corr(PG_FUNCTION_ARGS); + extern Datum numeric_regr_r2(PG_FUNCTION_ARGS); + extern Datum numeric_regr_slope(PG_FUNCTION_ARGS); + extern Datum numeric_regr_intercept(PG_FUNCTION_ARGS); + /* ri_triggers.c */ extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS); Index: src/test/regress/expected/opr_sanity.out =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/opr_sanity.out,v retrieving revision 1.64 diff -c -r1.64 opr_sanity.out *** src/test/regress/expected/opr_sanity.out 11 Jul 2006 19:49:14 -0000 1.64 --- src/test/regress/expected/opr_sanity.out 25 Jul 2006 09:14:51 -0000 *************** *** 72,77 **** --- 72,78 ---- WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND + p1.proisagg = false AND p2.proisagg = false AND (p1.prolang != p2.prolang OR p1.proisagg != p2.proisagg OR p1.prosecdef != p2.prosecdef OR *************** *** 617,623 **** SELECT a.aggfnoid::oid, p.proname FROM pg_aggregate as a, pg_proc as p WHERE a.aggfnoid = p.oid AND ! (NOT p.proisagg OR p.pronargs != 1 OR p.proretset); aggfnoid | proname ----------+--------- (0 rows) --- 618,624 ---- SELECT a.aggfnoid::oid, p.proname FROM pg_aggregate as a, pg_proc as p WHERE a.aggfnoid = p.oid AND ! (NOT p.proisagg OR p.proretset); aggfnoid | proname ----------+--------- (0 rows) *************** *** 650,656 **** (ptr.proretset OR NOT physically_coercible(ptr.prorettype, a.aggtranstype) OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0]) ! OR NOT ((ptr.pronargs = 2 AND physically_coercible(p.proargtypes[0], ptr.proargtypes[1])) OR (ptr.pronargs = 1 AND --- 651,657 ---- (ptr.proretset OR NOT physically_coercible(ptr.prorettype, a.aggtranstype) OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0]) ! OR NOT ((ptr.pronargs > 1 AND physically_coercible(p.proargtypes[0], ptr.proargtypes[1])) OR (ptr.pronargs = 1 AND Index: src/test/regress/sql/opr_sanity.sql =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/opr_sanity.sql,v retrieving revision 1.50 diff -c -r1.50 opr_sanity.sql *** src/test/regress/sql/opr_sanity.sql 2 May 2006 11:28:56 -0000 1.50 --- src/test/regress/sql/opr_sanity.sql 25 Jul 2006 09:14:55 -0000 *************** *** 75,80 **** --- 75,81 ---- WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND + p1.proisagg = false AND p2.proisagg = false AND (p1.prolang != p2.prolang OR p1.proisagg != p2.proisagg OR p1.prosecdef != p2.prosecdef OR *************** *** 515,521 **** SELECT a.aggfnoid::oid, p.proname FROM pg_aggregate as a, pg_proc as p WHERE a.aggfnoid = p.oid AND ! (NOT p.proisagg OR p.pronargs != 1 OR p.proretset); -- Make sure there are no proisagg pg_proc entries without matches. --- 516,522 ---- SELECT a.aggfnoid::oid, p.proname FROM pg_aggregate as a, pg_proc as p WHERE a.aggfnoid = p.oid AND ! (NOT p.proisagg OR p.proretset); -- Make sure there are no proisagg pg_proc entries without matches. *************** *** 541,547 **** (ptr.proretset OR NOT physically_coercible(ptr.prorettype, a.aggtranstype) OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0]) ! OR NOT ((ptr.pronargs = 2 AND physically_coercible(p.proargtypes[0], ptr.proargtypes[1])) OR (ptr.pronargs = 1 AND --- 542,548 ---- (ptr.proretset OR NOT physically_coercible(ptr.prorettype, a.aggtranstype) OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0]) ! OR NOT ((ptr.pronargs > 1 AND physically_coercible(p.proargtypes[0], ptr.proargtypes[1])) OR (ptr.pronargs = 1 AND