aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeAgg.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-04-11 20:00:18 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-04-11 20:00:18 +0000
commit902a6a0a4bc62d619a5ccd1ef0ff7fb3a5d897f1 (patch)
treec5cc85818d8a3ffae03a23bacd3e679945a41dbd /src/backend/executor/nodeAgg.c
parent3f6299df6c7d905bdef44eb3a4b19f248ebc14dc (diff)
downloadpostgresql-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.c97
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 */
+}