diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-04-11 20:00:18 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-04-11 20:00:18 +0000 |
commit | 902a6a0a4bc62d619a5ccd1ef0ff7fb3a5d897f1 (patch) | |
tree | c5cc85818d8a3ffae03a23bacd3e679945a41dbd /src/backend/executor/nodeAgg.c | |
parent | 3f6299df6c7d905bdef44eb3a4b19f248ebc14dc (diff) | |
download | postgresql-902a6a0a4bc62d619a5ccd1ef0ff7fb3a5d897f1.tar.gz postgresql-902a6a0a4bc62d619a5ccd1ef0ff7fb3a5d897f1.zip |
Restructure representation of aggregate functions so that they have pg_proc
entries, per pghackers discussion. This fixes aggregates to live in
namespaces, and also simplifies/speeds up lookup in parse_func.c.
Also, add a 'proimplicit' flag to pg_proc that controls whether a type
coercion function may be invoked implicitly, or only explicitly. The
current settings of these flags are more permissive than I would like,
but we will need to debate and refine the behavior; for now, I avoided
breaking regression tests as much as I could.
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r-- | src/backend/executor/nodeAgg.c | 97 |
1 files changed, 77 insertions, 20 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index e7da9e5af57..3ccbcd8efc8 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -46,7 +46,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.80 2002/03/20 19:43:54 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.81 2002/04/11 19:59:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,11 +63,13 @@ #include "parser/parse_expr.h" #include "parser/parse_oper.h" #include "parser/parse_type.h" +#include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/tuplesort.h" #include "utils/datum.h" + /* * AggStatePerAggData - per-aggregate working state for the Agg scan */ @@ -160,6 +162,7 @@ static void process_sorted_aggregate(AggState *aggstate, AggStatePerAgg peraggstate); static void finalize_aggregate(AggStatePerAgg peraggstate, Datum *resultVal, bool *resultIsNull); +static Datum GetAggInitVal(Datum textInitVal, Oid transtype); /* @@ -244,7 +247,7 @@ advance_transition_function(AggStatePerAgg peraggstate, * transValue has not been initialized. This is the first * non-NULL input value. We use it as the initial value for * transValue. (We already checked that the agg's input type - * is binary- compatible with its transtype, so straight copy + * is binary-compatible with its transtype, so straight copy * here is OK.) * * We had better copy the datum if it is pass-by-ref, since the @@ -838,11 +841,11 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent) { Aggref *aggref = (Aggref *) lfirst(alist); AggStatePerAgg peraggstate = &peragg[++aggno]; - char *aggname = aggref->aggname; HeapTuple aggTuple; Form_pg_aggregate aggform; Oid transfn_oid, finalfn_oid; + Datum textInitVal; /* Mark Aggref node with its associated index in the result array */ aggref->aggno = aggno; @@ -850,28 +853,34 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent) /* Fill in the peraggstate data */ peraggstate->aggref = aggref; - aggTuple = SearchSysCache(AGGNAME, - PointerGetDatum(aggname), - ObjectIdGetDatum(aggref->basetype), - 0, 0); + aggTuple = SearchSysCache(AGGFNOID, + ObjectIdGetDatum(aggref->aggfnoid), + 0, 0, 0); if (!HeapTupleIsValid(aggTuple)) - elog(ERROR, "ExecAgg: cache lookup failed for aggregate %s(%s)", - aggname, - aggref->basetype ? - typeidTypeName(aggref->basetype) : (char *) ""); + elog(ERROR, "ExecAgg: cache lookup failed for aggregate %u", + aggref->aggfnoid); aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple); - get_typlenbyval(aggform->aggfinaltype, + get_typlenbyval(aggref->aggtype, &peraggstate->resulttypeLen, &peraggstate->resulttypeByVal); get_typlenbyval(aggform->aggtranstype, &peraggstate->transtypeLen, &peraggstate->transtypeByVal); - peraggstate->initValue = - AggNameGetInitVal(aggname, - aggform->aggbasetype, - &peraggstate->initValueIsNull); + /* + * initval is potentially null, so don't try to access it as a struct + * field. Must do it the hard way with SysCacheGetAttr. + */ + textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple, + Anum_pg_aggregate_agginitval, + &peraggstate->initValueIsNull); + + if (peraggstate->initValueIsNull) + peraggstate->initValue = (Datum) 0; + else + peraggstate->initValue = GetAggInitVal(textInitVal, + aggform->aggtranstype); peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn; peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn; @@ -891,21 +900,21 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent) { /* * Note: use the type from the input expression here, not - * aggform->aggbasetype, because the latter might be 0. + * from pg_proc.proargtypes, because the latter might be 0. * (Consider COUNT(*).) */ Oid inputType = exprType(aggref->target); if (!IsBinaryCompatible(inputType, aggform->aggtranstype)) - elog(ERROR, "Aggregate %s needs to have compatible input type and transition type", - aggname); + elog(ERROR, "Aggregate %u needs to have compatible input type and transition type", + aggref->aggfnoid); } if (aggref->aggdistinct) { /* * Note: use the type from the input expression here, not - * aggform->aggbasetype, because the latter might be 0. + * from pg_proc.proargtypes, because the latter might be 0. * (Consider COUNT(*).) */ Oid inputType = exprType(aggref->target); @@ -932,6 +941,36 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent) return TRUE; } +static Datum +GetAggInitVal(Datum textInitVal, Oid transtype) +{ + char *strInitVal; + HeapTuple tup; + Oid typinput, + typelem; + Datum initVal; + + strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal)); + + tup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(transtype), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "GetAggInitVal: cache lookup failed on aggregate transition function return type %u", transtype); + + typinput = ((Form_pg_type) GETSTRUCT(tup))->typinput; + typelem = ((Form_pg_type) GETSTRUCT(tup))->typelem; + ReleaseSysCache(tup); + + initVal = OidFunctionCall3(typinput, + CStringGetDatum(strInitVal), + ObjectIdGetDatum(typelem), + Int32GetDatum(-1)); + + pfree(strInitVal); + return initVal; +} + int ExecCountSlotsAgg(Agg *node) { @@ -985,3 +1024,21 @@ ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent) if (((Plan *) node)->lefttree->chgParam == NULL) ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node); } + +/* + * aggregate_dummy - dummy execution routine for aggregate functions + * + * This function is listed as the implementation (prosrc field) of pg_proc + * entries for aggregate functions. Its only purpose is to throw an error + * if someone mistakenly executes such a function in the normal way. + * + * Perhaps someday we could assign real meaning to the prosrc field of + * an aggregate? + */ +Datum +aggregate_dummy(PG_FUNCTION_ARGS) +{ + elog(ERROR, "Aggregate function %u called as normal function", + fcinfo->flinfo->fn_oid); + return (Datum) 0; /* keep compiler quiet */ +} |