diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/executor/nodeAgg.c | 21 | ||||
-rw-r--r-- | src/backend/utils/adt/int8.c | 49 |
2 files changed, 58 insertions, 12 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 63a687e9869..8f641cc843b 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -40,12 +40,28 @@ * is used to run finalize functions and compute the output tuple; * this context can be reset once per output tuple. * + * Beginning in PostgreSQL 8.1, the executor's AggState node is passed as + * the fmgr "context" value in all transfunc and finalfunc calls. It is + * not really intended that the transition functions will look into the + * AggState node, but they can use code like + * if (fcinfo->context && IsA(fcinfo->context, AggState)) + * to verify that they are being called by nodeAgg.c and not as ordinary + * SQL functions. The main reason a transition function might want to know + * that is that it can avoid palloc'ing a fixed-size pass-by-ref transition + * value on every call: it can instead just scribble on and return its left + * input. Ordinarily it is completely forbidden for functions to modify + * pass-by-ref inputs, but in the aggregate case we know the left input is + * either the initial transition value or a previous function result, and + * in either case its value need not be preserved. See int8inc() for an + * example. Notice that advance_transition_function() is coded to avoid a + * data copy step when the previous transition value pointer is returned. + * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.128 2005/01/28 19:33:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.129 2005/03/12 20:25:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -363,7 +379,7 @@ advance_transition_function(AggState *aggstate, */ /* MemSet(&fcinfo, 0, sizeof(fcinfo)); */ - fcinfo.context = NULL; + fcinfo.context = (void *) aggstate; fcinfo.resultinfo = NULL; fcinfo.isnull = false; @@ -541,6 +557,7 @@ finalize_aggregate(AggState *aggstate, FunctionCallInfoData fcinfo; MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.context = (void *) aggstate; fcinfo.flinfo = &peraggstate->finalfn; fcinfo.nargs = 1; fcinfo.arg[0] = pergroupstate->transValue; diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index a7f76e31d96..c5c3d30d03d 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.57 2004/12/31 22:01:22 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.58 2005/03/12 20:25:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include "funcapi.h" #include "libpq/pqformat.h" +#include "nodes/nodes.h" #include "utils/int8.h" @@ -649,17 +650,45 @@ int8mod(PG_FUNCTION_ARGS) Datum int8inc(PG_FUNCTION_ARGS) { - int64 arg = PG_GETARG_INT64(0); - int64 result; + if (fcinfo->context && IsA(fcinfo->context, AggState)) + { + /* + * Special case to avoid palloc overhead for COUNT(): when called + * from nodeAgg, we know that the argument is modifiable local + * storage, so just update it in-place. + * + * Note: this assumes int8 is a pass-by-ref type; if we ever support + * pass-by-val int8, this should be ifdef'd out when int8 is + * pass-by-val. + */ + int64 *arg = (int64 *) PG_GETARG_POINTER(0); + int64 result; - result = arg + 1; - /* Overflow check */ - if (arg > 0 && result < 0) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("bigint out of range"))); + result = *arg + 1; + /* Overflow check */ + if (result < 0 && *arg > 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); - PG_RETURN_INT64(result); + *arg = result; + PG_RETURN_POINTER(arg); + } + else + { + /* Not called by nodeAgg, so just do it the dumb way */ + int64 arg = PG_GETARG_INT64(0); + int64 result; + + result = arg + 1; + /* Overflow check */ + if (result < 0 && arg > 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + + PG_RETURN_INT64(result); + } } Datum |