1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Revise aggregate functions per earlier discussions in pghackers.

There's now only one transition value and transition function.
NULL handling in aggregates is a lot cleaner.  Also, use Numeric
accumulators instead of integer accumulators for sum/avg on integer
datatypes --- this avoids overflow at the cost of being a little slower.
Implement VARIANCE() and STDDEV() aggregates in the standard backend.

Also, enable new LIKE selectivity estimators by default.  Unrelated
change, but as long as I had to force initdb anyway...
This commit is contained in:
Tom Lane
2000-07-17 03:05:41 +00:00
parent 139f19c302
commit bec98a31c5
55 changed files with 1949 additions and 1813 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.34 2000/07/05 23:11:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.35 2000/07/17 03:04:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,6 +21,8 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
@ -36,13 +38,7 @@
* Currently, redefining aggregates using the same name is not
* supported. In such a case, a warning is printed that the
* aggregate already exists. If such is not the case, a new tuple
* is created and inserted in the aggregate relation. The fields
* of this tuple are aggregate name, owner id, 2 transition functions
* (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
* type of data on which aggtransfn1 operates (aggbasetype), return
* types of the two transition functions (aggtranstype1 and
* aggtranstype2), final return type (aggfinaltype), and initial values
* for the two state transition functions (agginitval1 and agginitval2).
* is created and inserted in the aggregate relation.
* All types and functions must have been defined
* prior to defining the aggregate.
*
@ -50,31 +46,27 @@
*/
void
AggregateCreate(char *aggName,
char *aggtransfn1Name,
char *aggtransfn2Name,
char *aggtransfnName,
char *aggfinalfnName,
char *aggbasetypeName,
char *aggtransfn1typeName,
char *aggtransfn2typeName,
char *agginitval1,
char *agginitval2)
char *aggtranstypeName,
char *agginitval)
{
int i;
Relation aggdesc;
HeapTuple tup;
char nulls[Natts_pg_aggregate];
Datum values[Natts_pg_aggregate];
Form_pg_proc proc;
Oid xfn1 = InvalidOid;
Oid xfn2 = InvalidOid;
Oid ffn = InvalidOid;
Oid xbase = InvalidOid;
Oid xret1 = InvalidOid;
Oid xret2 = InvalidOid;
Oid fret = InvalidOid;
Oid transfn;
Oid finalfn = InvalidOid; /* can be omitted */
Oid basetype;
Oid transtype;
Oid finaltype;
Oid fnArgs[FUNC_MAX_ARGS];
int nargs;
NameData aname;
TupleDesc tupDesc;
int i;
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
@ -82,143 +74,112 @@ AggregateCreate(char *aggName,
if (!aggName)
elog(ERROR, "AggregateCreate: no aggregate name supplied");
if (!aggtransfn1Name && !aggtransfn2Name)
elog(ERROR, "AggregateCreate: aggregate must have at least one transition function");
if (!aggtransfnName)
elog(ERROR, "AggregateCreate: aggregate must have a transition function");
if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
/* handle the aggregate's base type (input data type) */
/*
* Handle the aggregate's base type (input data type). This can be
* specified as 'ANY' for a data-independent transition function,
* such as COUNT(*).
*/
tup = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(aggbasetypeName),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
xbase = tup->t_data->t_oid;
if (HeapTupleIsValid(tup))
{
basetype = tup->t_data->t_oid;
Assert(OidIsValid(basetype));
}
else
{
if (strcasecmp(aggbasetypeName, "ANY") != 0)
elog(ERROR, "AggregateCreate: Type '%s' undefined",
aggbasetypeName);
basetype = InvalidOid;
}
/* make sure there is no existing agg of same name and base type */
tup = SearchSysCacheTuple(AGGNAME,
PointerGetDatum(aggName),
ObjectIdGetDatum(xbase),
ObjectIdGetDatum(basetype),
0, 0);
if (HeapTupleIsValid(tup))
elog(ERROR,
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
aggName, aggbasetypeName);
/* handle transfn1 and transtype1 */
if (aggtransfn1Name)
{
tup = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(aggtransfn1typeName),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "AggregateCreate: Type '%s' undefined",
aggtransfn1typeName);
xret1 = tup->t_data->t_oid;
/* handle transtype */
tup = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(aggtranstypeName),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "AggregateCreate: Type '%s' undefined",
aggtranstypeName);
transtype = tup->t_data->t_oid;
Assert(OidIsValid(transtype));
fnArgs[0] = xret1;
fnArgs[1] = xbase;
tup = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(aggtransfn1Name),
Int32GetDatum(2),
PointerGetDatum(fnArgs),
0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "AggregateCreate: '%s('%s', '%s') does not exist",
aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
aggtransfn1Name, aggtransfn1typeName);
xfn1 = tup->t_data->t_oid;
if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
!OidIsValid(xbase))
elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn1Name);
/* handle transfn */
fnArgs[0] = transtype;
if (OidIsValid(basetype))
{
fnArgs[1] = basetype;
nargs = 2;
}
else
{
nargs = 1;
}
tup = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(aggtransfnName),
Int32GetDatum(nargs),
PointerGetDatum(fnArgs),
0);
if (!HeapTupleIsValid(tup))
func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
transfn = tup->t_data->t_oid;
proc = (Form_pg_proc) GETSTRUCT(tup);
if (proc->prorettype != transtype)
elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
aggtransfnName, aggtranstypeName);
Assert(OidIsValid(transfn));
/*
* If the transfn is strict and the initval is NULL, make sure
* input type and transtype are the same (or at least binary-
* compatible), so that it's OK to use the first input value
* as the initial transValue.
*/
if (((Form_pg_proc) GETSTRUCT(tup))->proisstrict && agginitval == NULL)
{
if (basetype != transtype &&
! IS_BINARY_COMPATIBLE(basetype, transtype))
elog(ERROR, "AggregateCreate: must not omit initval when transfn is strict and transtype is not compatible with input type");
}
/* handle transfn2 and transtype2 */
if (aggtransfn2Name)
/* handle finalfn, if supplied */
if (aggfinalfnName)
{
tup = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(aggtransfn2typeName),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "AggregateCreate: Type '%s' undefined",
aggtransfn2typeName);
xret2 = tup->t_data->t_oid;
fnArgs[0] = xret2;
fnArgs[0] = transtype;
fnArgs[1] = 0;
tup = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(aggtransfn2Name),
PointerGetDatum(aggfinalfnName),
Int32GetDatum(1),
PointerGetDatum(fnArgs),
0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
aggtransfn2Name, aggtransfn2typeName);
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
aggtransfn2Name, aggtransfn2typeName);
xfn2 = tup->t_data->t_oid;
if (!OidIsValid(xfn2) || !OidIsValid(xret2))
elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn2Name);
}
/* handle finalfn */
if (aggfinalfnName)
{
int nargs = 0;
if (OidIsValid(xret1))
fnArgs[nargs++] = xret1;
if (OidIsValid(xret2))
fnArgs[nargs++] = xret2;
fnArgs[nargs] = 0; /* make sure slot 2 is empty if just 1 arg */
tup = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(aggfinalfnName),
Int32GetDatum(nargs),
PointerGetDatum(fnArgs),
0);
if (!HeapTupleIsValid(tup))
{
if (nargs == 2)
elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist",
aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
else if (OidIsValid(xret1))
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
aggfinalfnName, aggtransfn1typeName);
else
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
aggfinalfnName, aggtransfn2typeName);
}
ffn = tup->t_data->t_oid;
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
finalfn = tup->t_data->t_oid;
proc = (Form_pg_proc) GETSTRUCT(tup);
fret = proc->prorettype;
if (!OidIsValid(ffn) || !OidIsValid(fret))
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
finaltype = proc->prorettype;
Assert(OidIsValid(finalfn));
}
else
{
/*
* If no finalfn, aggregate result type is type of the sole state
* value (we already checked there is only one)
* If no finalfn, aggregate result type is type of the state value
*/
if (OidIsValid(xret1))
fret = xret1;
else
fret = xret2;
finaltype = transtype;
}
Assert(OidIsValid(fret));
/*
* If transition function 2 is defined, it must have an initial value,
* whereas transition function 1 need not, which allows max and min
* aggregates to return NULL if they are evaluated on empty sets.
*/
if (OidIsValid(xfn2) && !agginitval2)
elog(ERROR, "AggregateCreate: transition function 2 MUST have an initial value");
Assert(OidIsValid(finaltype));
/* initialize nulls and values */
for (i = 0; i < Natts_pg_aggregate; i++)
@ -229,25 +190,17 @@ AggregateCreate(char *aggName,
namestrcpy(&aname, aggName);
values[Anum_pg_aggregate_aggname - 1] = NameGetDatum(&aname);
values[Anum_pg_aggregate_aggowner - 1] = Int32GetDatum(GetUserId());
values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1);
values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2);
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn);
values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase);
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(basetype);
values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(transtype);
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(finaltype);
if (agginitval1)
values[Anum_pg_aggregate_agginitval1 - 1] =
DirectFunctionCall1(textin, CStringGetDatum(agginitval1));
if (agginitval)
values[Anum_pg_aggregate_agginitval - 1] =
DirectFunctionCall1(textin, CStringGetDatum(agginitval));
else
nulls[Anum_pg_aggregate_agginitval1 - 1] = 'n';
if (agginitval2)
values[Anum_pg_aggregate_agginitval2 - 1] =
DirectFunctionCall1(textin, CStringGetDatum(agginitval2));
else
nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
nulls[Anum_pg_aggregate_agginitval - 1] = 'n';
aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
tupDesc = aggdesc->rd_att;
@ -271,11 +224,9 @@ AggregateCreate(char *aggName,
}
Datum
AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
AggNameGetInitVal(char *aggName, Oid basetype, bool *isNull)
{
HeapTuple tup;
Relation aggRel;
int initValAttno;
Oid transtype,
typinput,
typelem;
@ -285,15 +236,6 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
Assert(PointerIsValid(aggName));
Assert(PointerIsValid(isNull));
Assert(xfuncno == 1 || xfuncno == 2);
/*
* since we will have to use fastgetattr (in case one or both init
* vals are NULL), we will need to open the relation. Do that first
* to ensure we don't get a stale tuple from the cache.
*/
aggRel = heap_openr(AggregateRelationName, AccessShareLock);
tup = SearchSysCacheTuple(AGGNAME,
PointerGetDatum(aggName),
@ -302,29 +244,19 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
if (!HeapTupleIsValid(tup))
elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
aggName);
if (xfuncno == 1)
{
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
initValAttno = Anum_pg_aggregate_agginitval1;
}
else
{
/* can only be 1 or 2 */
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
initValAttno = Anum_pg_aggregate_agginitval2;
}
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype;
textInitVal = fastgetattr(tup, initValAttno,
RelationGetDescr(aggRel),
isNull);
/*
* 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(AGGNAME, tup,
Anum_pg_aggregate_agginitval,
isNull);
if (*isNull)
{
heap_close(aggRel, AccessShareLock);
return PointerGetDatum(NULL);
}
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
return (Datum) 0;
heap_close(aggRel, AccessShareLock);
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
tup = SearchSysCacheTuple(TYPEOID,
ObjectIdGetDatum(transtype),

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.44 2000/07/03 23:09:33 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.45 2000/07/17 03:04:44 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -484,16 +484,12 @@ DefineOperator(char *oprName,
*/
void
DefineAggregate(char *aggName, List *parameters)
{
char *stepfunc1Name = NULL;
char *stepfunc2Name = NULL;
char *transfuncName = NULL;
char *finalfuncName = NULL;
char *baseType = NULL;
char *stepfunc1Type = NULL;
char *stepfunc2Type = NULL;
char *init1 = NULL;
char *init2 = NULL;
char *transType = NULL;
char *initval = NULL;
List *pl;
foreach(pl, parameters)
@ -501,47 +497,28 @@ DefineAggregate(char *aggName, List *parameters)
DefElem *defel = (DefElem *) lfirst(pl);
/*
* sfunc1
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
if (!strcasecmp(defel->defname, "sfunc1"))
stepfunc1Name = defGetString(defel);
else if (!strcasecmp(defel->defname, "basetype"))
baseType = defGetString(defel);
else if (!strcasecmp(defel->defname, "stype1"))
{
stepfunc1Type = defGetString(defel);
/*
* sfunc2
*/
}
else if (!strcasecmp(defel->defname, "sfunc2"))
stepfunc2Name = defGetString(defel);
else if (!strcasecmp(defel->defname, "stype2"))
{
stepfunc2Type = defGetString(defel);
/*
* final
*/
}
else if (!strcasecmp(defel->defname, "finalfunc"))
{
if (strcasecmp(defel->defname, "sfunc") == 0)
transfuncName = defGetString(defel);
else if (strcasecmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetString(defel);
else if (strcasecmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetString(defel);
/*
* initial conditions
*/
}
else if (!strcasecmp(defel->defname, "initcond1"))
init1 = defGetString(defel);
else if (!strcasecmp(defel->defname, "initcond2"))
init2 = defGetString(defel);
else if (strcasecmp(defel->defname, "basetype") == 0)
baseType = defGetString(defel);
else if (strcasecmp(defel->defname, "stype") == 0)
transType = defGetString(defel);
else if (strcasecmp(defel->defname, "stype1") == 0)
transType = defGetString(defel);
else if (strcasecmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
else if (strcasecmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
else
{
elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
defel->defname);
}
}
/*
@ -549,31 +526,20 @@ DefineAggregate(char *aggName, List *parameters)
*/
if (baseType == NULL)
elog(ERROR, "Define: \"basetype\" unspecified");
if (stepfunc1Name != NULL)
{
if (stepfunc1Type == NULL)
elog(ERROR, "Define: \"stype1\" unspecified");
}
if (stepfunc2Name != NULL)
{
if (stepfunc2Type == NULL)
elog(ERROR, "Define: \"stype2\" unspecified");
}
if (transType == NULL)
elog(ERROR, "Define: \"stype\" unspecified");
if (transfuncName == NULL)
elog(ERROR, "Define: \"sfunc\" unspecified");
/*
* Most of the argument-checking is done inside of AggregateCreate
*/
AggregateCreate(aggName, /* aggregate name */
stepfunc1Name, /* first step function name */
stepfunc2Name, /* second step function name */
finalfuncName, /* final function name */
baseType, /* type of object being aggregated */
stepfunc1Type, /* return type of first function */
stepfunc2Type, /* return type of second function */
init1, /* first initial condition */
init2); /* second initial condition */
/* XXX free palloc'd memory */
AggregateCreate(aggName, /* aggregate name */
transfuncName, /* step function name */
finalfuncName, /* final function name */
baseType, /* type of data being aggregated */
transType, /* transition data type */
initval); /* initial condition */
}
/*

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.63 2000/07/05 23:11:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.64 2000/07/17 03:04:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -26,6 +26,7 @@
#include "commands/user.h"
#include "libpq/crypt.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.73 2000/07/12 02:37:00 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.74 2000/07/17 03:04:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,6 +40,7 @@
#include "executor/execdebug.h"
#include "executor/functions.h"
#include "executor/nodeSubplan.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/fcache2.h"

View File

@ -12,16 +12,19 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.12 2000/07/12 02:37:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.13 2000/07/17 03:04:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/types.h>
#include <sys/file.h>
#include "postgres.h"
#include "executor/executor.h"
#include "utils/memutils.h"
/* ----------------------------------------------------------------
* ExecScan

View File

@ -3,36 +3,38 @@
* nodeAgg.c
* Routines to handle aggregate nodes.
*
* ExecAgg evaluates each aggregate in the following steps: (initcond1,
* initcond2 are the initial values and sfunc1, sfunc2, and finalfunc are
* the transition functions.)
* ExecAgg evaluates each aggregate in the following steps:
*
* value1 = initcond1
* value2 = initcond2
* transvalue = initcond
* foreach input_value do
* value1 = sfunc1(value1, input_value)
* value2 = sfunc2(value2)
* value1 = finalfunc(value1, value2)
* transvalue = transfunc(transvalue, input_value)
* result = finalfunc(transvalue)
*
* If initcond1 is NULL then the first non-NULL input_value is
* assigned directly to value1. sfunc1 isn't applied until value1
* is non-NULL.
* If a finalfunc is not supplied then the result is just the ending
* value of transvalue.
*
* sfunc1 is never applied when the current tuple's input_value is NULL.
* sfunc2 is applied for each tuple if the aggref is marked 'usenulls',
* otherwise it is only applied when input_value is not NULL.
* (usenulls was formerly used for COUNT(*), but is no longer needed for
* that purpose; as of 10/1999 the support for usenulls is dead code.
* I have not removed it because it seems like a potentially useful
* feature for user-defined aggregates. We'd just need to add a
* flag column to pg_aggregate and a parameter to CREATE AGGREGATE...)
* If transfunc is marked "strict" in pg_proc and initcond is NULL,
* then the first non-NULL input_value is assigned directly to transvalue,
* and transfunc isn't applied until the second non-NULL input_value.
* The agg's input type and transtype must be the same in this case!
*
* If transfunc is marked "strict" then NULL input_values are skipped,
* keeping the previous transvalue. If transfunc is not strict then it
* is called for every input tuple and must deal with NULL initcond
* or NULL input_value for itself.
*
* If finalfunc is marked "strict" then it is not called when the
* ending transvalue is NULL, instead a NULL result is created
* automatically (this is just the usual handling of strict functions,
* of course). A non-strict finalfunc can make its own choice of
* what to return for a NULL ending transvalue.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.69 2000/07/12 02:37:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.70 2000/07/17 03:04:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -45,6 +47,7 @@
#include "executor/executor.h"
#include "executor/nodeAgg.h"
#include "optimizer/clauses.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
@ -67,16 +70,15 @@ typedef struct AggStatePerAggData
Aggref *aggref;
/* Oids of transfer functions */
Oid xfn1_oid;
Oid xfn2_oid;
Oid finalfn_oid;
Oid transfn_oid;
Oid finalfn_oid; /* may be InvalidOid */
/*
* fmgr lookup data for transfer functions --- only valid when
* corresponding oid is not InvalidOid
* corresponding oid is not InvalidOid. Note in particular that
* fn_strict flags are kept here.
*/
FmgrInfo xfn1;
FmgrInfo xfn2;
FmgrInfo transfn;
FmgrInfo finalfn;
/*
@ -94,12 +96,10 @@ typedef struct AggStatePerAggData
FmgrInfo equalfn;
/*
* initial values from pg_aggregate entry
* initial value from pg_aggregate entry
*/
Datum initValue1; /* for transtype1 */
Datum initValue2; /* for transtype2 */
bool initValue1IsNull,
initValue2IsNull;
Datum initValue;
bool initValueIsNull;
/*
* We need the len and byval info for the agg's input, result, and
@ -107,45 +107,42 @@ typedef struct AggStatePerAggData
*/
int inputtypeLen,
resulttypeLen,
transtype1Len,
transtype2Len;
transtypeLen;
bool inputtypeByVal,
resulttypeByVal,
transtype1ByVal,
transtype2ByVal;
transtypeByVal;
/*
* These values are working state that is initialized at the start of
* an input tuple group and updated for each input tuple.
*
* For a simple (non DISTINCT) aggregate, we just feed the input values
* straight to the transition functions. If it's DISTINCT, we pass
* straight to the transition function. If it's DISTINCT, we pass
* the input values into a Tuplesort object; then at completion of the
* input tuple group, we scan the sorted values, eliminate duplicates,
* and run the transition functions on the rest.
* and run the transition function on the rest.
*/
Tuplesortstate *sortstate; /* sort object, if a DISTINCT agg */
Datum value1, /* current transfer values 1 and 2 */
value2;
bool value1IsNull,
value2IsNull;
bool noInitValue; /* true if value1 not set yet */
Datum transValue;
bool transValueIsNull;
bool noTransValue; /* true if transValue not set yet */
/*
* Note: right now, noInitValue always has the same value as
* value1IsNull. But we should keep them separate because once the
* fmgr interface is fixed, we'll need to distinguish a null returned
* by transfn1 from a null we haven't yet replaced with an input
* value.
* Note: noTransValue initially has the same value as transValueIsNull,
* and if true both are cleared to false at the same time. They are
* not the same though: if transfn later returns a NULL, we want to
* keep that NULL and not auto-replace it with a later input value.
* Only the first non-NULL input will be auto-substituted.
*/
} AggStatePerAggData;
static void initialize_aggregate(AggStatePerAgg peraggstate);
static void advance_transition_functions(AggStatePerAgg peraggstate,
Datum newVal, bool isNull);
static void advance_transition_function(AggStatePerAgg peraggstate,
Datum newVal, bool isNull);
static void process_sorted_aggregate(AggState *aggstate,
AggStatePerAgg peraggstate);
static void finalize_aggregate(AggStatePerAgg peraggstate,
@ -182,144 +179,118 @@ initialize_aggregate(AggStatePerAgg peraggstate)
}
/*
* (Re)set value1 and value2 to their initial values.
* (Re)set transValue to the initial value.
*
* Note that when the initial values are pass-by-ref, we just reuse
* them without copying for each group. Hence, transition function
* had better not scribble on its input!
* Note that when the initial value is pass-by-ref, we just reuse it
* without copying for each group. Hence, transition function
* had better not scribble on its input, or it will fail for GROUP BY!
*/
peraggstate->value1 = peraggstate->initValue1;
peraggstate->value1IsNull = peraggstate->initValue1IsNull;
peraggstate->value2 = peraggstate->initValue2;
peraggstate->value2IsNull = peraggstate->initValue2IsNull;
peraggstate->transValue = peraggstate->initValue;
peraggstate->transValueIsNull = peraggstate->initValueIsNull;
/* ------------------------------------------
* If the initial value for the first transition function
* doesn't exist in the pg_aggregate table then we will let
* the first value returned from the outer procNode become
* the initial value. (This is useful for aggregates like
* max{} and min{}.) The noInitValue flag signals that we
* still need to do this.
* If the initial value for the transition state doesn't exist in the
* pg_aggregate table then we will let the first non-NULL value returned
* from the outer procNode become the initial value. (This is useful for
* aggregates like max() and min().) The noTransValue flag signals that
* we still need to do this.
* ------------------------------------------
*/
peraggstate->noInitValue = peraggstate->initValue1IsNull;
peraggstate->noTransValue = peraggstate->initValueIsNull;
}
/*
* Given a new input value, advance the transition functions of an aggregate.
* Given a new input value, advance the transition function of an aggregate.
*
* When called, CurrentMemoryContext should be the context we want transition
* function results to be delivered into on this cycle.
*
* Note: if the agg does not have usenulls set, null inputs will be filtered
* out before reaching here.
* When called, CurrentMemoryContext should be the context we want the
* transition function result to be delivered into on this cycle.
*/
static void
advance_transition_functions(AggStatePerAgg peraggstate,
Datum newVal, bool isNull)
advance_transition_function(AggStatePerAgg peraggstate,
Datum newVal, bool isNull)
{
FunctionCallInfoData fcinfo;
MemSet(&fcinfo, 0, sizeof(fcinfo));
/*
* XXX reconsider isNULL handling here
*/
if (OidIsValid(peraggstate->xfn1_oid) && !isNull)
if (peraggstate->transfn.fn_strict)
{
if (peraggstate->noInitValue)
if (isNull)
{
/*
* value1 has not been initialized. This is the first non-NULL
* input value. We use it as the initial value for value1.
*
* XXX We assume, without having checked, that the agg's input
* type is binary-compatible with its transtype1!
* For a strict transfn, nothing happens at a NULL input tuple;
* we just keep the prior transValue. However, if the transtype
* is pass-by-ref, we have to copy it into the new context
* because the old one is going to get reset.
*/
if (!peraggstate->transValueIsNull)
peraggstate->transValue = datumCopy(peraggstate->transValue,
peraggstate->transtypeByVal,
peraggstate->transtypeLen);
return;
}
if (peraggstate->noTransValue)
{
/*
* 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 here is OK.)
*
* We had better copy the datum if it is pass-by-ref, since
* the given pointer may be pointing into a scan tuple that
* will be freed on the next iteration of the scan.
*/
peraggstate->value1 = datumCopy(newVal,
peraggstate->transtype1ByVal,
peraggstate->transtype1Len);
peraggstate->value1IsNull = false;
peraggstate->noInitValue = false;
peraggstate->transValue = datumCopy(newVal,
peraggstate->transtypeByVal,
peraggstate->transtypeLen);
peraggstate->transValueIsNull = false;
peraggstate->noTransValue = false;
return;
}
else
if (peraggstate->transValueIsNull)
{
/* apply transition function 1 */
fcinfo.flinfo = &peraggstate->xfn1;
fcinfo.nargs = 2;
fcinfo.arg[0] = peraggstate->value1;
fcinfo.argnull[0] = peraggstate->value1IsNull;
fcinfo.arg[1] = newVal;
fcinfo.argnull[1] = isNull;
if (fcinfo.flinfo->fn_strict &&
(peraggstate->value1IsNull || isNull))
{
/* don't call a strict function with NULL inputs */
newVal = (Datum) 0;
fcinfo.isnull = true;
}
else
newVal = FunctionCallInvoke(&fcinfo);
/*
* If the transition function was uncooperative, it may have
* given us a pass-by-ref result that points at the scan tuple
* or the prior-cycle working memory. Copy it into the active
* context if it doesn't look right.
* Don't call a strict function with NULL inputs. Note it is
* possible to get here despite the above tests, if the transfn
* is strict *and* returned a NULL on a prior cycle. If that
* happens we will propagate the NULL all the way to the end.
*/
if (!peraggstate->transtype1ByVal && !fcinfo.isnull &&
! MemoryContextContains(CurrentMemoryContext,
DatumGetPointer(newVal)))
newVal = datumCopy(newVal,
peraggstate->transtype1ByVal,
peraggstate->transtype1Len);
peraggstate->value1 = newVal;
peraggstate->value1IsNull = fcinfo.isnull;
return;
}
}
if (OidIsValid(peraggstate->xfn2_oid))
{
/* apply transition function 2 */
fcinfo.flinfo = &peraggstate->xfn2;
fcinfo.nargs = 1;
fcinfo.arg[0] = peraggstate->value2;
fcinfo.argnull[0] = peraggstate->value2IsNull;
fcinfo.isnull = false; /* must reset after use by xfn1 */
if (fcinfo.flinfo->fn_strict && peraggstate->value2IsNull)
{
/* don't call a strict function with NULL inputs */
newVal = (Datum) 0;
fcinfo.isnull = true;
}
else
newVal = FunctionCallInvoke(&fcinfo);
/*
* If the transition function was uncooperative, it may have
* given us a pass-by-ref result that points at the scan tuple
* or the prior-cycle working memory. Copy it into the active
* context if it doesn't look right.
*/
if (!peraggstate->transtype2ByVal && !fcinfo.isnull &&
! MemoryContextContains(CurrentMemoryContext,
DatumGetPointer(newVal)))
newVal = datumCopy(newVal,
peraggstate->transtype2ByVal,
peraggstate->transtype2Len);
peraggstate->value2 = newVal;
peraggstate->value2IsNull = fcinfo.isnull;
}
/* OK to call the transition function */
MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &peraggstate->transfn;
fcinfo.nargs = 2;
fcinfo.arg[0] = peraggstate->transValue;
fcinfo.argnull[0] = peraggstate->transValueIsNull;
fcinfo.arg[1] = newVal;
fcinfo.argnull[1] = isNull;
newVal = FunctionCallInvoke(&fcinfo);
/*
* If the transition function was uncooperative, it may have
* given us a pass-by-ref result that points at the scan tuple
* or the prior-cycle working memory. Copy it into the active
* context if it doesn't look right.
*/
if (!peraggstate->transtypeByVal && !fcinfo.isnull &&
! MemoryContextContains(CurrentMemoryContext,
DatumGetPointer(newVal)))
newVal = datumCopy(newVal,
peraggstate->transtypeByVal,
peraggstate->transtypeLen);
peraggstate->transValue = newVal;
peraggstate->transValueIsNull = fcinfo.isnull;
}
/*
* Run the transition functions for a DISTINCT aggregate. This is called
* Run the transition function for a DISTINCT aggregate. This is called
* after we have completed entering all the input values into the sort
* object. We complete the sort, read out the value in sorted order, and
* run the transition functions on each non-duplicate value.
* object. We complete the sort, read out the values in sorted order,
* and run the transition function on each non-duplicate value.
*
* When called, CurrentMemoryContext should be the per-query context.
*/
@ -346,13 +317,13 @@ process_sorted_aggregate(AggState *aggstate,
{
/*
* DISTINCT always suppresses nulls, per SQL spec, regardless of
* the aggregate's usenulls setting.
* the transition function's strictness.
*/
if (isNull)
continue;
/*
* Clear and select the current working context for evaluation of
* the equality function and transition functions.
* the equality function and transition function.
*/
MemoryContextReset(aggstate->agg_cxt[aggstate->which_cxt]);
oldContext =
@ -365,11 +336,14 @@ process_sorted_aggregate(AggState *aggstate,
/* equal to prior, so forget this one */
if (!peraggstate->inputtypeByVal)
pfree(DatumGetPointer(newVal));
/* note we do NOT flip contexts in this case... */
/*
* note we do NOT flip contexts in this case, so no need to
* copy prior transValue to other context.
*/
}
else
{
advance_transition_functions(peraggstate, newVal, false);
advance_transition_function(peraggstate, newVal, false);
/*
* Make the other context current so that this transition
* result is preserved.
@ -402,48 +376,19 @@ static void
finalize_aggregate(AggStatePerAgg peraggstate,
Datum *resultVal, bool *resultIsNull)
{
FunctionCallInfoData fcinfo;
MemSet(&fcinfo, 0, sizeof(fcinfo));
/*
* Apply the agg's finalfn, or substitute the appropriate
* transition value if there is no finalfn.
*
* XXX For now, only apply finalfn if we got at least one non-null input
* value. This prevents zero divide in AVG(). If we had cleaner
* handling of null inputs/results in functions, we could probably
* take out this hack and define the result for no inputs as whatever
* finalfn returns for null input.
* Apply the agg's finalfn if one is provided, else return transValue.
*/
if (OidIsValid(peraggstate->finalfn_oid) &&
!peraggstate->noInitValue)
if (OidIsValid(peraggstate->finalfn_oid))
{
FunctionCallInfoData fcinfo;
MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &peraggstate->finalfn;
if (peraggstate->finalfn.fn_nargs > 1)
{
fcinfo.nargs = 2;
fcinfo.arg[0] = peraggstate->value1;
fcinfo.argnull[0] = peraggstate->value1IsNull;
fcinfo.arg[1] = peraggstate->value2;
fcinfo.argnull[1] = peraggstate->value2IsNull;
}
else if (OidIsValid(peraggstate->xfn1_oid))
{
fcinfo.nargs = 1;
fcinfo.arg[0] = peraggstate->value1;
fcinfo.argnull[0] = peraggstate->value1IsNull;
}
else if (OidIsValid(peraggstate->xfn2_oid))
{
fcinfo.nargs = 1;
fcinfo.arg[0] = peraggstate->value2;
fcinfo.argnull[0] = peraggstate->value2IsNull;
}
else
elog(ERROR, "ExecAgg: no valid transition functions??");
if (fcinfo.flinfo->fn_strict &&
(fcinfo.argnull[0] || fcinfo.argnull[1]))
fcinfo.nargs = 1;
fcinfo.arg[0] = peraggstate->transValue;
fcinfo.argnull[0] = peraggstate->transValueIsNull;
if (fcinfo.flinfo->fn_strict && peraggstate->transValueIsNull)
{
/* don't call a strict function with NULL inputs */
*resultVal = (Datum) 0;
@ -455,20 +400,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
*resultIsNull = fcinfo.isnull;
}
}
else if (OidIsValid(peraggstate->xfn1_oid))
{
/* Return value1 */
*resultVal = peraggstate->value1;
*resultIsNull = peraggstate->value1IsNull;
}
else if (OidIsValid(peraggstate->xfn2_oid))
{
/* Return value2 */
*resultVal = peraggstate->value2;
*resultIsNull = peraggstate->value2IsNull;
}
else
elog(ERROR, "ExecAgg: no valid transition functions??");
{
*resultVal = peraggstate->transValue;
*resultIsNull = peraggstate->transValueIsNull;
}
/*
* If result is pass-by-ref, make sure it is in the right context.
*/
@ -588,11 +525,11 @@ ExecAgg(Agg *node)
newVal = ExecEvalExpr(aggref->target, econtext,
&isNull, &isDone);
if (isNull && !aggref->usenulls)
continue; /* ignore this tuple for this agg */
if (aggref->aggdistinct)
{
/* in DISTINCT mode, we may ignore nulls */
if (isNull)
continue;
/* putdatum has to be called in per-query context */
MemoryContextSwitchTo(oldContext);
tuplesort_putdatum(peraggstate->sortstate,
@ -600,8 +537,10 @@ ExecAgg(Agg *node)
MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
}
else
advance_transition_functions(peraggstate,
newVal, isNull);
{
advance_transition_function(peraggstate,
newVal, isNull);
}
}
/*
@ -889,8 +828,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
HeapTuple aggTuple;
Form_pg_aggregate aggform;
Type typeInfo;
Oid xfn1_oid,
xfn2_oid,
Oid transfn_oid,
finalfn_oid;
/* Mark Aggref node with its associated index in the result array */
@ -913,53 +851,51 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
peraggstate->resulttypeLen = typeLen(typeInfo);
peraggstate->resulttypeByVal = typeByVal(typeInfo);
peraggstate->initValue1 =
typeInfo = typeidType(aggform->aggtranstype);
peraggstate->transtypeLen = typeLen(typeInfo);
peraggstate->transtypeByVal = typeByVal(typeInfo);
peraggstate->initValue =
AggNameGetInitVal(aggname,
aggform->aggbasetype,
1,
&peraggstate->initValue1IsNull);
&peraggstate->initValueIsNull);
peraggstate->initValue2 =
AggNameGetInitVal(aggname,
aggform->aggbasetype,
2,
&peraggstate->initValue2IsNull);
peraggstate->xfn1_oid = xfn1_oid = aggform->aggtransfn1;
peraggstate->xfn2_oid = xfn2_oid = aggform->aggtransfn2;
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
if (OidIsValid(xfn1_oid))
{
fmgr_info(xfn1_oid, &peraggstate->xfn1);
/* If a transfn1 is specified, transtype1 had better be, too */
typeInfo = typeidType(aggform->aggtranstype1);
peraggstate->transtype1Len = typeLen(typeInfo);
peraggstate->transtype1ByVal = typeByVal(typeInfo);
}
if (OidIsValid(xfn2_oid))
{
fmgr_info(xfn2_oid, &peraggstate->xfn2);
/* If a transfn2 is specified, transtype2 had better be, too */
typeInfo = typeidType(aggform->aggtranstype2);
peraggstate->transtype2Len = typeLen(typeInfo);
peraggstate->transtype2ByVal = typeByVal(typeInfo);
/* ------------------------------------------
* If there is a second transition function, its initial
* value must exist -- as it does not depend on data values,
* we have no other way of determining an initial value.
* ------------------------------------------
*/
if (peraggstate->initValue2IsNull)
elog(ERROR, "ExecInitAgg: agginitval2 is null");
}
fmgr_info(transfn_oid, &peraggstate->transfn);
if (OidIsValid(finalfn_oid))
fmgr_info(finalfn_oid, &peraggstate->finalfn);
/*
* If the transfn is strict and the initval is NULL, make sure
* input type and transtype are the same (or at least binary-
* compatible), so that it's OK to use the first input value
* as the initial transValue. This should have been checked at
* agg definition time, but just in case...
*/
if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
{
/*
* Note: use the type from the input expression here,
* not aggform->aggbasetype, because the latter might be 0.
* (Consider COUNT(*).)
*/
Oid inputType = exprType(aggref->target);
if (inputType != aggform->aggtranstype &&
! IS_BINARY_COMPATIBLE(inputType, aggform->aggtranstype))
elog(ERROR, "Aggregate %s needs to have compatible input type and transition type",
aggname);
}
if (aggref->aggdistinct)
{
/*
* Note: use the type from the input expression here,
* not aggform->aggbasetype, because the latter might be 0.
* (Consider COUNT(*).)
*/
Oid inputType = exprType(aggref->target);
Operator eq_operator;
Form_pg_operator pgopform;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: nodeHash.c,v 1.49 2000/07/12 02:37:03 tgl Exp $
* $Id: nodeHash.c,v 1.50 2000/07/17 03:04:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,6 +30,8 @@
#include "miscadmin.h"
#include "parser/parse_expr.h"
#include "parser/parse_type.h"
#include "utils/memutils.h"
static int hashFunc(Datum key, int len, bool byVal);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.31 2000/07/12 02:37:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.32 2000/07/17 03:04:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -20,6 +20,8 @@
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "optimizer/clauses.h"
#include "utils/memutils.h"
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
HashJoinState *hjstate);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.17 2000/07/12 02:37:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.18 2000/07/17 03:04:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -18,10 +18,13 @@
* ExecInitNestLoop - initialize the join
* ExecEndNestLoop - shut down the join
*/
#include "postgres.h"
#include "executor/execdebug.h"
#include "executor/nodeNestloop.h"
#include "utils/memutils.h"
/* ----------------------------------------------------------------
* ExecNestLoop(node)

View File

@ -34,7 +34,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.14 2000/07/12 02:37:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.15 2000/07/17 03:04:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -43,6 +43,8 @@
#include "executor/executor.h"
#include "executor/nodeResult.h"
#include "utils/memutils.h"
/* ----------------------------------------------------------------
* ExecResult(node)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.49 2000/07/07 21:12:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.50 2000/07/17 03:04:54 tgl Exp $
*
* NOTES
* This should be moved to a more appropriate place. It is here
@ -43,6 +43,8 @@
#include "libpq/be-fsstubs.h"
#include "libpq/libpq-fs.h"
#include "storage/large_object.h"
#include "utils/memutils.h"
/* [PA] is Pascal Andr<64> <andre@via.ecp.fr> */

View File

@ -19,7 +19,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.116 2000/07/12 02:37:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.117 2000/07/17 03:04:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -843,7 +843,6 @@ _copyAggref(Aggref *from)
newnode->basetype = from->basetype;
newnode->aggtype = from->aggtype;
Node_Copy(from, newnode, target);
newnode->usenulls = from->usenulls;
newnode->aggstar = from->aggstar;
newnode->aggdistinct = from->aggdistinct;
newnode->aggno = from->aggno; /* probably not needed */

View File

@ -24,7 +24,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.68 2000/07/12 02:37:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.69 2000/07/17 03:05:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -257,8 +257,6 @@ _equalAggref(Aggref *a, Aggref *b)
return false;
if (!equal(a->target, b->target))
return false;
if (a->usenulls != b->usenulls)
return false;
if (a->aggstar != b->aggstar)
return false;
if (a->aggdistinct != b->aggdistinct)

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.122 2000/07/15 00:01:37 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.123 2000/07/17 03:05:01 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
@ -729,12 +729,10 @@ _outAggref(StringInfo str, Aggref *node)
appendStringInfo(str, " AGGREG :aggname ");
_outToken(str, node->aggname);
appendStringInfo(str, " :basetype %u :aggtype %u :target ",
node->basetype,
node->aggtype);
node->basetype, node->aggtype);
_outNode(str, node->target);
appendStringInfo(str, " :usenulls %s :aggstar %s :aggdistinct %s ",
node->usenulls ? "true" : "false",
appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
node->aggstar ? "true" : "false",
node->aggdistinct ? "true" : "false");
/* aggno is not dumped */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.92 2000/07/12 02:37:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.93 2000/07/17 03:05:01 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
@ -1117,10 +1117,6 @@ _readAggref()
token = lsptok(NULL, &length); /* eat :target */
local_node->target = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* eat :usenulls */
token = lsptok(NULL, &length); /* get usenulls */
local_node->usenulls = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* eat :aggstar */
token = lsptok(NULL, &length); /* get aggstar */
local_node->aggstar = (token[0] == 't') ? true : false;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.38 2000/06/15 03:32:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.39 2000/07/17 03:05:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -189,18 +189,16 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
{
HeapTuple theAggTuple;
Form_pg_aggregate aggform;
Oid fintype;
Oid xfn1;
Oid vartype;
Aggref *aggref;
bool usenulls = false;
theAggTuple = SearchSysCacheTuple(AGGNAME,
PointerGetDatum(aggname),
ObjectIdGetDatum(basetype),
0, 0);
/* shouldn't happen --- caller should have checked already */
if (!HeapTupleIsValid(theAggTuple))
elog(ERROR, "Aggregate %s does not exist", aggname);
agg_error("ParseAgg", aggname, basetype);
aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
/*
* There used to be a really ugly hack for count(*) here.
@ -209,43 +207,18 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
* does the right thing. (It didn't use to do the right thing,
* because the optimizer had the wrong ideas about semantics of
* queries without explicit variables. Fixed as of Oct 1999 --- tgl.)
*
* Since "1" never evaluates as null, we currently have no need of the
* "usenulls" flag, but it should be kept around; in fact, we should
* extend the pg_aggregate table to let usenulls be specified as an
* attribute of user-defined aggregates. In the meantime, usenulls is
* just always set to "false".
*/
aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
fintype = aggform->aggfinaltype;
xfn1 = aggform->aggtransfn1;
/* only aggregates with transfn1 need a base type */
if (OidIsValid(xfn1))
{
basetype = aggform->aggbasetype;
vartype = exprType(lfirst(args));
if ((basetype != vartype)
&& (!IS_BINARY_COMPATIBLE(basetype, vartype)))
{
Type tp1,
tp2;
tp1 = typeidType(basetype);
tp2 = typeidType(vartype);
elog(ERROR, "Aggregate type mismatch"
"\n\t%s() works on %s, not on %s",
aggname, typeTypeName(tp1), typeTypeName(tp2));
}
}
/*
* We assume caller has already checked that given args are compatible
* with the agg's basetype.
*/
aggref = makeNode(Aggref);
aggref->aggname = pstrdup(aggname);
aggref->basetype = aggform->aggbasetype;
aggref->aggtype = fintype;
aggref->aggtype = aggform->aggfinaltype;
aggref->target = lfirst(args);
aggref->usenulls = usenulls;
aggref->aggstar = agg_star;
aggref->aggdistinct = agg_distinct;
@ -268,10 +241,9 @@ agg_error(char *caller, char *aggname, Oid basetypeID)
*/
if (basetypeID == InvalidOid)
elog(ERROR, "%s: aggregate '%s' for all types does not exist", caller, aggname);
elog(ERROR, "%s: aggregate '%s' for all types does not exist",
caller, aggname);
else
{
elog(ERROR, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
typeidTypeName(basetypeID));
}
elog(ERROR, "%s: aggregate '%s' for '%s' does not exist",
caller, aggname, typeidTypeName(basetypeID));
}

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.156 2000/07/12 22:59:04 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.157 2000/07/17 03:05:04 tgl Exp $
*
* NOTES
*
@ -33,6 +33,7 @@
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <unistd.h>
@ -80,6 +81,7 @@
#include "tcop/tcopprot.h"
#include "utils/exc.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#define INVALID_SOCK (-1)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.70 2000/06/28 03:32:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.71 2000/07/17 03:05:08 tgl Exp $
*
* NOTES
* Outside modules can create a lock table and acquire/release
@ -20,7 +20,7 @@
* Interface:
*
* LockAcquire(), LockRelease(), LockMethodTableInit(),
* LockMethodTableRename(), LockReleaseAll, LockOwners()
* LockMethodTableRename(), LockReleaseAll,
* LockResolveConflicts(), GrantLock()
*
* NOTE: This module is used to define new lock tables. The
@ -35,9 +35,11 @@
#include <signal.h>
#include "postgres.h"
#include "access/xact.h"
#include "miscadmin.h"
#include "storage/proc.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
static int WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode);
@ -1722,181 +1724,6 @@ nxtl: ;
return false;
}
#ifdef NOT_USED
/*
* Return an array with the pids of all processes owning a lock.
* This works only for user locks because normal locks have no
* pid information in the corresponding XIDLookupEnt.
*/
ArrayType *
LockOwners(LOCKMETHOD lockmethod, LOCKTAG *locktag)
{
XIDLookupEnt *xidLook = NULL;
SPINLOCK masterLock;
LOCK *lock;
SHMEM_OFFSET lock_offset;
int count = 0;
LOCKMETHODTABLE *lockMethodTable;
HTAB *xidTable;
bool found;
int ndims,
nitems,
hdrlen,
size;
int lbounds[1],
hbounds[1];
ArrayType *array;
int *data_ptr;
/* Assume that no one will modify the result */
static int empty_array[] = {20, 1, 0, 0, 0};
#ifdef LOCK_DEBUG
if (lockmethod == USER_LOCKMETHOD && Trace_userlocks)
elog(DEBUG, "LockOwners: user lock tag [%u]", locktag->objId.blkno);
#endif
/* This must be changed when short term locks will be used */
locktag->lockmethod = lockmethod;
Assert((lockmethod >= MIN_LOCKMETHOD) && (lockmethod < NumLockMethods));
lockMethodTable = LockMethodTable[lockmethod];
if (!lockMethodTable)
{
elog(NOTICE, "lockMethodTable is null in LockOwners");
return (ArrayType *) &empty_array;
}
if (LockingIsDisabled)
return (ArrayType *) &empty_array;
masterLock = lockMethodTable->ctl->masterLock;
SpinAcquire(masterLock);
/*
* Find a lock with this tag
*/
Assert(lockMethodTable->lockHash->hash == tag_hash);
lock = (LOCK *) hash_search(lockMethodTable->lockHash, (Pointer) locktag,
HASH_FIND, &found);
/*
* let the caller print its own error message, too. Do not elog(WARN).
*/
if (!lock)
{
SpinRelease(masterLock);
elog(NOTICE, "LockOwners: locktable corrupted");
return (ArrayType *) &empty_array;
}
if (!found)
{
SpinRelease(masterLock);
elog(NOTICE, "LockOwners: no such lock");
return (ArrayType *) &empty_array;
}
LOCK_PRINT("LockOwners: found", lock, 0);
Assert((lock->nHolding > 0) && (lock->nActive > 0));
Assert(lock->nActive <= lock->nHolding);
lock_offset = MAKE_OFFSET(lock);
/* Construct a 1-dimensional array */
ndims = 1;
hdrlen = ARR_OVERHEAD(ndims);
lbounds[0] = 0;
hbounds[0] = lock->nActive;
size = hdrlen + sizeof(int) * hbounds[0];
array = (ArrayType *) palloc(size);
MemSet(array, 0, size);
memmove((char *) array, (char *) &size, sizeof(int));
memmove((char *) ARR_NDIM_PTR(array), (char *) &ndims, sizeof(int));
memmove((char *) ARR_DIMS(array), (char *) hbounds, ndims * sizeof(int));
memmove((char *) ARR_LBOUND(array), (char *) lbounds, ndims * sizeof(int));
SET_LO_FLAG(false, array);
data_ptr = (int *) ARR_DATA_PTR(array);
xidTable = lockMethodTable->xidHash;
hash_seq(NULL);
nitems = 0;
while ((xidLook = (XIDLookupEnt *) hash_seq(xidTable)) &&
(xidLook != (XIDLookupEnt *) TRUE))
{
if (count++ > 1000)
{
elog(NOTICE, "LockOwners: possible loop, giving up");
break;
}
if (xidLook->tag.pid == 0)
{
XID_PRINT("LockOwners: no pid", xidLook);
continue;
}
if (!xidLook->tag.lock)
{
XID_PRINT("LockOwners: NULL LOCK", xidLook);
continue;
}
if (xidLook->tag.lock != lock_offset)
{
XID_PRINT("LockOwners: different lock", xidLook);
continue;
}
if (LOCK_LOCKMETHOD(*lock) != lockmethod)
{
XID_PRINT("LockOwners: other table", xidLook);
continue;
}
if (xidLook->nHolding <= 0)
{
XID_PRINT("LockOwners: not holding", xidLook);
continue;
}
if (nitems >= hbounds[0])
{
elog(NOTICE, "LockOwners: array size exceeded");
break;
}
/*
* Check that the holding process is still alive by sending him an
* unused (ignored) signal. If the kill fails the process is not
* alive.
*/
if ((xidLook->tag.pid != MyProcPid) \
&&(kill(xidLook->tag.pid, SIGCHLD)) != 0)
{
/* Return a negative pid to signal that process is dead */
data_ptr[nitems++] = -(xidLook->tag.pid);
XID_PRINT("LockOwners: not alive", xidLook);
/* XXX - TODO: remove this entry and update lock stats */
continue;
}
/* Found a process holding the lock */
XID_PRINT("LockOwners: holding", xidLook);
data_ptr[nitems++] = xidLook->tag.pid;
}
SpinRelease(masterLock);
/* Adjust the actual size of the array */
hbounds[0] = nitems;
size = hdrlen + sizeof(int) * hbounds[0];
memmove((char *) array, (char *) &size, sizeof(int));
memmove((char *) ARR_DIMS(array), (char *) hbounds, ndims * sizeof(int));
return array;
}
#endif /* NOT_USED */
#ifdef LOCK_DEBUG
/*
* Dump all locks in the proc->lockQueue. Must have already acquired

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.73 2000/07/10 04:32:00 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.74 2000/07/17 03:05:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,8 +22,9 @@
#include "catalog/catalog.h"
#include "miscadmin.h"
#include "storage/smgr.h"
#include "utils/inval.h" /* ImmediateSharedRelationCacheInvalidate()
* */
#include "utils/inval.h"
#include "utils/memutils.h"
#undef DIAGNOSTIC

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.169 2000/07/12 17:38:45 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.170 2000/07/17 03:05:14 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -56,6 +56,7 @@
#include "storage/proc.h"
#include "utils/exc.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/temprel.h"
#ifdef MULTIBYTE
@ -1411,7 +1412,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.169 $ $Date: 2000/07/12 17:38:45 $\n");
puts("$Revision: 1.170 $ $Date: 2000/07/17 03:05:14 $\n");
}
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.36 2000/07/12 02:37:15 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.37 2000/07/17 03:05:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -19,8 +19,10 @@
#include "executor/execdefs.h"
#include "executor/executor.h"
#include "tcop/pquery.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
static char *CreateOperationTag(int operationType);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.60 2000/07/03 23:09:50 wieck Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.61 2000/07/17 03:05:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -19,7 +19,6 @@
#include "catalog/catalog.h"
#include "catalog/pg_type.h"
#include "fmgr.h"
#include "libpq/be-fsstubs.h"
#include "libpq/libpq-fs.h"
#include "storage/fd.h"
@ -29,7 +28,8 @@
#define ASSGN "="
/* An array has the following internal structure:
/*
* An array has the following internal structure:
* <nbytes> - total number of bytes
* <ndim> - number of dimensions of the array
* <flags> - bit mask of flags
@ -38,20 +38,18 @@
* <actual data> - whatever is the stored data
*/
/*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
static int _ArrayCount(char *str, int *dim, int typdelim);
static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
FmgrInfo *inputproc, Oid typelem, int32 typmod,
char typdelim, int typlen, bool typbyval,
char typalign, int *nbytes);
#ifdef LOARRAY
static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
int ndim, int *dim, int baseSize);
#endif
static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
char typalign, bool typbyval);
static void CopyArrayEls(char *p, Datum *values, int nitems,
bool typbyval, int typlen, char typalign,
bool freedata);
static void system_cache_lookup(Oid element_type, bool input, int *typlen,
bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
char *typalign);
@ -101,7 +99,7 @@ array_in(PG_FUNCTION_ARGS)
int i,
nitems;
int32 nbytes;
char *dataPtr;
Datum *dataPtr;
ArrayType *retval;
int ndim,
dim[MAXDIM],
@ -187,32 +185,29 @@ array_in(PG_FUNCTION_ARGS)
retval = (ArrayType *) palloc(sizeof(ArrayType));
MemSet(retval, 0, sizeof(ArrayType));
*(int32 *) retval = sizeof(ArrayType);
PG_RETURN_POINTER(retval);
PG_RETURN_ARRAYTYPE_P(retval);
}
if (*p == '{')
{
/* array not a large object */
dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
typmod, typdelim, typlen, typbyval, typalign,
&nbytes);
dataPtr = ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
typmod, typdelim, typlen, typbyval, typalign,
&nbytes);
nbytes += ARR_OVERHEAD(ndim);
retval = (ArrayType *) palloc(nbytes);
MemSet(retval, 0, nbytes);
memmove(retval, (char *) &nbytes, sizeof(int));
memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
retval->size = nbytes;
retval->ndim = ndim;
SET_LO_FLAG(false, retval);
memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
memmove((char *) ARR_LBOUND(retval), (char *) lBound,
ndim * sizeof(int));
memcpy((char *) ARR_DIMS(retval), (char *) dim,
ndim * sizeof(int));
memcpy((char *) ARR_LBOUND(retval), (char *) lBound,
ndim * sizeof(int));
/*
* dataPtr is an array of arbitraystuff even though its type is
* char* cast to char** to pass to _CopyArrayEls for now - jolly
*/
_CopyArrayEls((char **) dataPtr,
ARR_DATA_PTR(retval), nitems,
typlen, typalign, typbyval);
CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems,
typbyval, typlen, typalign, true);
pfree(dataPtr);
}
else
{
@ -226,8 +221,8 @@ array_in(PG_FUNCTION_ARGS)
nbytes = bytes + ARR_OVERHEAD(ndim);
retval = (ArrayType *) palloc(nbytes);
MemSet(retval, 0, nbytes);
memmove(retval, (char *) &nbytes, sizeof(int));
memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
retval->size = nbytes;
retval->ndim = ndim;
SET_LO_FLAG(true, retval);
SET_CHUNK_FLAG(chunked, retval);
memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
@ -238,7 +233,7 @@ array_in(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
pfree(string_save);
PG_RETURN_POINTER(retval);
PG_RETURN_ARRAYTYPE_P(retval);
}
/*-----------------------------------------------------------------------------
@ -331,50 +326,51 @@ _ArrayCount(char *str, int *dim, int typdelim)
}
/*---------------------------------------------------------------------------
* _ReadArrayStr :
* parses the array string pointed by "arrayStr" and converts it in the
* ReadArrayStr :
* parses the array string pointed by "arrayStr" and converts it to
* internal format. The external format expected is like C array
* declaration. Unspecified elements are initialized to zero for fixed length
* base types and to empty varlena structures for variable length base
* types.
* result :
* returns the internal representation of the array elements
* nbytes is set to the size of the array in its internal representation.
* returns a palloc'd array of Datum representations of the array elements.
* If element type is pass-by-ref, the Datums point to palloc'd values.
* *nbytes is set to the amount of data space needed for the array,
* including alignment padding but not including array header overhead.
*---------------------------------------------------------------------------
*/
static char *
_ReadArrayStr(char *arrayStr,
int nitems,
int ndim,
int *dim,
FmgrInfo *inputproc, /* function used for the
* conversion */
Oid typelem,
int32 typmod,
char typdelim,
int typlen,
bool typbyval,
char typalign,
int *nbytes)
static Datum *
ReadArrayStr(char *arrayStr,
int nitems,
int ndim,
int *dim,
FmgrInfo *inputproc,
Oid typelem,
int32 typmod,
char typdelim,
int typlen,
bool typbyval,
char typalign,
int *nbytes)
{
int i,
nest_level = 0;
Datum *values;
char *p,
*q,
*r,
**values;
*r;
bool scanning_string = false;
int indx[MAXDIM],
prod[MAXDIM];
bool eoArray = false;
mda_get_prod(ndim, dim, prod);
for (i = 0; i < ndim; indx[i++] = 0);
/* read array enclosed within {} */
values = (char **) palloc(nitems * sizeof(char *));
MemSet(values, 0, nitems * sizeof(char *));
values = (Datum *) palloc(nitems * sizeof(Datum));
MemSet(values, 0, nitems * sizeof(Datum));
MemSet(indx, 0, sizeof(indx));
q = p = arrayStr;
/* read array enclosed within {} */
while (!eoArray)
{
bool done = false;
@ -442,53 +438,56 @@ _ReadArrayStr(char *arrayStr,
*q = '\0';
if (i >= nitems)
elog(ERROR, "array_in: illformed array constant");
values[i] = (char *) FunctionCall3(inputproc,
CStringGetDatum(p),
ObjectIdGetDatum(typelem),
Int32GetDatum(typmod));
values[i] = FunctionCall3(inputproc,
CStringGetDatum(p),
ObjectIdGetDatum(typelem),
Int32GetDatum(typmod));
p = ++q;
/*
* if not at the end of the array skip white space
*/
if (!eoArray)
/*
* if not at the end of the array skip white space
*/
while (isspace((int) *q))
{
p++;
q++;
}
}
/*
* Initialize any unset items and compute total data space needed
*/
if (typlen > 0)
{
*nbytes = nitems * typlen;
if (!typbyval)
for (i = 0; i < nitems; i++)
if (!values[i])
if (values[i] == (Datum) 0)
{
values[i] = palloc(typlen);
MemSet(values[i], 0, typlen);
values[i] = PointerGetDatum(palloc(typlen));
MemSet(DatumGetPointer(values[i]), 0, typlen);
}
}
else
{
for (i = 0, *nbytes = 0; i < nitems; i++)
*nbytes = 0;
for (i = 0; i < nitems; i++)
{
if (values[i])
if (values[i] != (Datum) 0)
{
if (typalign == 'd')
*nbytes += MAXALIGN(*(int32 *) values[i]);
*nbytes += MAXALIGN(VARSIZE(DatumGetPointer(values[i])));
else
*nbytes += INTALIGN(*(int32 *) values[i]);
*nbytes += INTALIGN(VARSIZE(DatumGetPointer(values[i])));
}
else
{
*nbytes += sizeof(int32);
values[i] = palloc(sizeof(int32));
*(int32 *) values[i] = sizeof(int32);
values[i] = PointerGetDatum(palloc(sizeof(int32)));
VARATT_SIZEP(DatumGetPointer(values[i])) = sizeof(int32);
}
}
}
return (char *) values;
return values;
}
@ -565,26 +564,39 @@ _ReadLOArray(char *str,
#endif
/*----------
* Copy data into an array object from a temporary array of Datums.
*
* p: pointer to start of array data area
* values: array of Datums to be copied
* nitems: number of Datums to be copied
* typbyval, typlen, typalign: info about element datatype
* freedata: if TRUE and element type is pass-by-ref, pfree data values
* referenced by Datums after copying them.
*----------
*/
static void
_CopyArrayEls(char **values,
char *p,
int nitems,
int typlen,
char typalign,
bool typbyval)
CopyArrayEls(char *p,
Datum *values,
int nitems,
bool typbyval,
int typlen,
char typalign,
bool freedata)
{
int i;
int inc;
if (typbyval)
freedata = false;
for (i = 0; i < nitems; i++)
{
int inc;
inc = ArrayCastAndSet((Datum) values[i], typbyval, typlen, p);
inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
p += inc;
if (!typbyval)
pfree(values[i]);
if (freedata)
pfree(DatumGetPointer(values[i]));
}
pfree(values);
}
/*-------------------------------------------------------------------------
@ -596,7 +608,7 @@ _CopyArrayEls(char **values,
Datum
array_out(PG_FUNCTION_ARGS)
{
ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
Oid element_type = PG_GETARG_OID(1);
int typlen;
bool typbyval;
@ -786,7 +798,7 @@ array_out(PG_FUNCTION_ARGS)
Datum
array_dims(PG_FUNCTION_ARGS)
{
ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
text *result;
char *p;
int nbytes,
@ -821,8 +833,8 @@ array_dims(PG_FUNCTION_ARGS)
/*---------------------------------------------------------------------------
* array_ref :
* This routine takes an array pointer and an index array and returns
* a pointer to the referred element if element is passed by
* reference otherwise returns the value of the referred element.
* the referenced item as a Datum. Note that for a pass-by-reference
* datatype, the returned Datum is a pointer into the array object.
*---------------------------------------------------------------------------
*/
Datum
@ -905,7 +917,7 @@ array_ref(ArrayType *array,
{ /* not by value */
char *tempdata = palloc(elmlen);
memmove(tempdata, DatumGetPointer(result), elmlen);
memcpy(tempdata, DatumGetPointer(result), elmlen);
result = PointerGetDatum(tempdata);
}
pfree(v);
@ -1003,14 +1015,15 @@ array_clip(ArrayType *array,
#endif
bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts);
newArr = (ArrayType *) palloc(bytes);
memmove(newArr, array, sizeof(ArrayType));
memmove(newArr, &bytes, sizeof(int));
memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
newArr->size = bytes;
newArr->ndim = array->ndim;
newArr->flags = array->flags;
memcpy(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
memcpy(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
strcpy(ARR_DATA_PTR(newArr), newname);
rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen);
if (rsize < MAX_BUFF_SIZE)
if (rsize < BLCKSZ)
{
char *buff;
@ -1072,10 +1085,11 @@ array_clip(ArrayType *array,
bytes += ARR_OVERHEAD(nSubscripts);
}
newArr = (ArrayType *) palloc(bytes);
memmove(newArr, array, sizeof(ArrayType));
memmove(newArr, &bytes, sizeof(int));
memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
newArr->size = bytes;
newArr->ndim = array->ndim;
newArr->flags = array->flags;
memcpy(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
memcpy(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
_ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1);
return newArr;
}
@ -1322,7 +1336,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
{
ArrayType *v;
ArrayType *result;
char **values;
Datum *values;
char *elt;
int *dim;
int ndim;
@ -1338,14 +1352,13 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
Oid proc;
char typalign;
char *s;
char *p;
/* Get input array */
if (fcinfo->nargs < 1)
elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs);
if (PG_ARGISNULL(0))
elog(ERROR, "array_map: null input array");
v = (ArrayType *) PG_GETARG_VARLENA_P(0);
v = PG_GETARG_ARRAYTYPE_P(0);
/* Large objects not yet supported */
if (ARR_IS_LO(v) == true)
@ -1357,7 +1370,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
/* Check for empty array */
if (nitems <= 0)
PG_RETURN_POINTER(v);
PG_RETURN_ARRAYTYPE_P(v);
/* Lookup source and result types. Unneeded variables are reused. */
system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval,
@ -1366,8 +1379,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
&typdelim, &typelem, &proc, &typalign);
/* Allocate temporary array for new values */
values = (char **) palloc(nitems * sizeof(char *));
MemSet(values, 0, nitems * sizeof(char *));
values = (Datum *) palloc(nitems * sizeof(Datum));
MemSet(values, 0, nitems * sizeof(Datum));
/* Loop over source data */
s = (char *) ARR_DATA_PTR(v);
@ -1411,30 +1424,16 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
fcinfo->arg[0] = (Datum) elt;
fcinfo->argnull[0] = false;
fcinfo->isnull = false;
p = (char *) FunctionCallInvoke(fcinfo);
values[i] = FunctionCallInvoke(fcinfo);
if (fcinfo->isnull)
elog(ERROR, "array_map: cannot handle NULL in array");
/* Update values and total result size */
/* Update total result size */
if (typbyval)
{
values[i] = p;
nbytes += typlen;
}
else
{
int len;
len = ((typlen > 0) ? typlen : INTALIGN(*(int32 *) p));
/* Needed because _CopyArrayEls tries to pfree items */
if (p == elt)
{
p = (char *) palloc(len);
memcpy(p, elt, len);
}
values[i] = p;
nbytes += len;
}
nbytes += ((typlen > 0) ? typlen :
INTALIGN(VARSIZE(DatumGetPointer(values[i]))));
}
/* Allocate and initialize the result array */
@ -1442,18 +1441,130 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
result = (ArrayType *) palloc(nbytes);
MemSet(result, 0, nbytes);
memcpy((char *) result, (char *) &nbytes, sizeof(int));
memcpy((char *) ARR_NDIM_PTR(result), (char *) &ndim, sizeof(int));
memcpy((char *) ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
result->size = nbytes;
result->ndim = ndim;
memcpy(ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
/* Copy new values into the result array. values is pfreed. */
_CopyArrayEls((char **) values,
ARR_DATA_PTR(result), nitems,
typlen, typalign, typbyval);
/* Note: do not risk trying to pfree the results of the called function */
CopyArrayEls(ARR_DATA_PTR(result), values, nitems,
typbyval, typlen, typalign, false);
pfree(values);
PG_RETURN_POINTER(result);
PG_RETURN_ARRAYTYPE_P(result);
}
/*----------
* construct_array --- simple method for constructing an array object
*
* elems: array of Datum items to become the array contents
* nelems: number of items
* elmbyval, elmlen, elmalign: info for the datatype of the items
*
* A palloc'd 1-D array object is constructed and returned. Note that
* elem values will be copied into the object even if pass-by-ref type.
* NULL element values are not supported.
*----------
*/
ArrayType *
construct_array(Datum *elems, int nelems,
bool elmbyval, int elmlen, char elmalign)
{
ArrayType *result;
int nbytes;
int i;
if (elmlen > 0)
{
/* XXX what about alignment? */
nbytes = elmlen * nelems;
}
else
{
/* varlena type */
nbytes = 0;
for (i = 0; i < nelems; i++)
nbytes += INTALIGN(VARSIZE(DatumGetPointer(elems[i])));
}
/* Allocate and initialize 1-D result array */
nbytes += ARR_OVERHEAD(1);
result = (ArrayType *) palloc(nbytes);
result->size = nbytes;
result->ndim = 1;
result->flags = 0;
ARR_DIMS(result)[0] = nelems;
ARR_LBOUND(result)[0] = 1;
CopyArrayEls(ARR_DATA_PTR(result), elems, nelems,
elmbyval, elmlen, elmalign, false);
return result;
}
/*----------
* deconstruct_array --- simple method for extracting data from an array
*
* array: array object to examine (must not be NULL)
* elmbyval, elmlen, elmalign: info for the datatype of the items
* elemsp: return value, set to point to palloc'd array of Datum values
* nelemsp: return value, set to number of extracted values
*
* If array elements are pass-by-ref data type, the returned Datums will
* be pointers into the array object.
*----------
*/
void
deconstruct_array(ArrayType *array,
bool elmbyval, int elmlen, char elmalign,
Datum **elemsp, int *nelemsp)
{
Datum *elems;
int nelems;
char *p;
int i;
nelems = getNitems(ARR_NDIM(array), ARR_DIMS(array));
if (nelems <= 0)
{
*elemsp = NULL;
*nelemsp = 0;
return;
}
*elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum));
*nelemsp = nelems;
p = ARR_DATA_PTR(array);
for (i = 0; i < nelems; i++)
{
if (elmbyval)
{
switch (elmlen)
{
case 1:
elems[i] = CharGetDatum(*p);
break;
case 2:
elems[i] = Int16GetDatum(*(int16 *) p);
break;
case 4:
elems[i] = Int32GetDatum(*(int32 *) p);
break;
}
p += elmlen;
}
else
{
elems[i] = PointerGetDatum(p);
if (elmlen > 0)
p += elmlen;
else
p += INTALIGN(VARSIZE(p));
}
}
}
/*-----------------------------------------------------------------------------
* array_eq :
* compares two arrays for equality
@ -1464,8 +1575,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
Datum
array_eq(PG_FUNCTION_ARGS)
{
ArrayType *array1 = (ArrayType *) PG_GETARG_VARLENA_P(0);
ArrayType *array2 = (ArrayType *) PG_GETARG_VARLENA_P(1);
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
if (*(int32 *) array1 != *(int32 *) array2)
PG_RETURN_BOOL(false);
@ -1493,14 +1604,11 @@ system_cache_lookup(Oid element_type,
typeTuple = SearchSysCacheTuple(TYPEOID,
ObjectIdGetDatum(element_type),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
{
elog(ERROR, "array_out: Cache lookup failed for type %u\n",
elog(ERROR, "array_out: Cache lookup failed for type %u",
element_type);
return;
}
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
*typlen = typeStruct->typlen;
*typbyval = typeStruct->typbyval;
*typdelim = typeStruct->typdelim;
@ -1536,7 +1644,11 @@ _ArrayCast(char *value, bool byval, int len)
return 0;
}
/*
* Copy datum to *dest and return total space used (including align padding)
*
* XXX this routine needs to be told typalign too!
*/
static int
ArrayCastAndSet(Datum src,
bool typbyval,
@ -1560,16 +1672,26 @@ ArrayCastAndSet(Datum src,
case 4:
*(int32 *) dest = DatumGetInt32(src);
break;
default:
elog(ERROR, "ArrayCastAndSet: unexpected typlen");
break;
}
/* For by-val types, assume no alignment padding is needed */
inc = typlen;
}
else
{
memmove(dest, DatumGetPointer(src), typlen);
inc = typlen;
/* XXX WRONG: need to consider type's alignment requirement */
inc = typlen;
}
}
else
{
memmove(dest, DatumGetPointer(src), *(int32 *) DatumGetPointer(src));
inc = (INTALIGN(*(int32 *) DatumGetPointer(src)));
/* varlena type */
memmove(dest, DatumGetPointer(src), VARSIZE(DatumGetPointer(src)));
/* XXX WRONG: should use MAXALIGN or type's alignment requirement */
inc = INTALIGN(VARSIZE(DatumGetPointer(src)));
}
return inc;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.64 2000/07/12 22:59:08 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.65 2000/07/17 03:05:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,7 +17,7 @@
* Basic float4 ops:
* float4in, float4out, float4abs, float4um
* Basic float8 ops:
* float8in, float8inAd, float8out, float8outAd, float8abs, float8um
* float8in, float8out, float8abs, float8um
* Arithmetic operators:
* float4pl, float4mi, float4mul, float4div
* float8pl, float8mi, float8mul, float8div
@ -64,6 +64,7 @@
#endif
#include "fmgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
static void CheckFloat8Val(double val);
@ -90,7 +91,6 @@ static void CheckFloat8Val(double val);
#ifndef atof
extern double atof(const char *p);
#endif
#ifndef HAVE_CBRT
@ -100,9 +100,8 @@ static double cbrt(double x);
#else
#if !defined(nextstep)
extern double cbrt(double x);
#endif
#endif
#endif /* HAVE_CBRT */
#ifndef HAVE_RINT
#define rint my_rint
@ -110,10 +109,9 @@ static double rint(double x);
#else
extern double rint(double x);
#endif /* HAVE_RINT */
#endif
#endif
#endif /* NeXT check */
/* ========== USER I/O ROUTINES ========== */
@ -453,7 +451,6 @@ float8smaller(float64 arg1, float64 arg2)
* float4mi - returns a pointer to arg1 - arg2
* float4mul - returns a pointer to arg1 * arg2
* float4div - returns a pointer to arg1 / arg2
* float4inc - returns a poniter to arg1 + 1.0
*/
float32
float4pl(float32 arg1, float32 arg2)
@ -527,29 +524,11 @@ float4div(float32 arg1, float32 arg2)
return result;
}
float32
float4inc(float32 arg1)
{
float32 result;
double val;
if (!arg1)
return (float32) NULL;
val = *arg1 + (float32data) 1.0;
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return result;
}
/*
* float8pl - returns a pointer to arg1 + arg2
* float8mi - returns a pointer to arg1 - arg2
* float8mul - returns a pointer to arg1 * arg2
* float8div - returns a pointer to arg1 / arg2
* float8inc - returns a pointer to arg1 + 1.0
*/
float64
float8pl(float64 arg1, float64 arg2)
@ -622,22 +601,6 @@ float8div(float64 arg1, float64 arg2)
return result;
}
float64
float8inc(float64 arg1)
{
float64 result;
double val;
if (!arg1)
return (float64) NULL;
val = *arg1 + (float64data) 1.0;
CheckFloat8Val(val);
result = (float64) palloc(sizeof(float64data));
*result = val;
return result;
}
/*
* ====================
@ -1572,10 +1535,181 @@ setseed(float64 seed)
} /* setseed() */
/*
* ====================
* ARITHMETIC OPERATORS
* ====================
* =========================
* FLOAT AGGREGATE OPERATORS
* =========================
*
* float8_accum - accumulate for AVG(), STDDEV(), etc
* float4_accum - same, but input data is float4
* float8_avg - produce final result for float AVG()
* float8_variance - produce final result for float VARIANCE()
* float8_stddev - produce final result for float STDDEV()
*
* The transition datatype for all these aggregates is a 3-element array
* of float8, holding the values N, sum(X), sum(X*X) in that order.
*
* Note that we represent N as a float to avoid having to build a special
* datatype. Given a reasonable floating-point implementation, there should
* be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
* user will have doubtless lost interest anyway...)
*/
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_SIZE(transarray) != (ARR_OVERHEAD(1) + 3 * sizeof(float8)) ||
ARR_NDIM(transarray) != 1 ||
ARR_DIMS(transarray)[0] != 3)
elog(ERROR, "%s: expected 3-element float8 array", caller);
return (float8 *) ARR_DATA_PTR(transarray);
}
Datum
float8_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
float8 newval = PG_GETARG_FLOAT8(1);
float8 *transvalues;
float8 N,
sumX,
sumX2;
Datum transdatums[3];
ArrayType *result;
transvalues = check_float8_array(transarray, "float8_accum");
N = transvalues[0];
sumX = transvalues[1];
sumX2 = transvalues[2];
N += 1.0;
sumX += newval;
sumX2 += newval * newval;
transdatums[0] = Float8GetDatumFast(N);
transdatums[1] = Float8GetDatumFast(sumX);
transdatums[2] = Float8GetDatumFast(sumX2);
result = construct_array(transdatums, 3,
false /* float8 byval */, sizeof(float8), 'd');
PG_RETURN_ARRAYTYPE_P(result);
}
Datum
float4_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
float4 newval4 = PG_GETARG_FLOAT4(1);
float8 *transvalues;
float8 N,
sumX,
sumX2,
newval;
Datum transdatums[3];
ArrayType *result;
transvalues = check_float8_array(transarray, "float4_accum");
N = transvalues[0];
sumX = transvalues[1];
sumX2 = transvalues[2];
/* Do arithmetic in float8 for best accuracy */
newval = newval4;
N += 1.0;
sumX += newval;
sumX2 += newval * newval;
transdatums[0] = Float8GetDatumFast(N);
transdatums[1] = Float8GetDatumFast(sumX);
transdatums[2] = Float8GetDatumFast(sumX2);
result = construct_array(transdatums, 3,
false /* float8 byval */, sizeof(float8), 'd');
PG_RETURN_ARRAYTYPE_P(result);
}
Datum
float8_avg(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
float8 *transvalues;
float8 N,
sumX;
transvalues = check_float8_array(transarray, "float8_avg");
N = transvalues[0];
sumX = transvalues[1];
/* ignore sumX2 */
/* SQL92 defines AVG of no values to be NULL */
if (N == 0.0)
PG_RETURN_NULL();
PG_RETURN_FLOAT8(sumX / N);
}
Datum
float8_variance(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
float8 *transvalues;
float8 N,
sumX,
sumX2;
transvalues = check_float8_array(transarray, "float8_variance");
N = transvalues[0];
sumX = transvalues[1];
sumX2 = transvalues[2];
/* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
if (N == 0.0)
PG_RETURN_NULL();
if (N <= 1.0)
PG_RETURN_FLOAT8(0.0);
PG_RETURN_FLOAT8((N * sumX2 - sumX * sumX) / (N * (N - 1.0)));
}
Datum
float8_stddev(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
float8 *transvalues;
float8 N,
sumX,
sumX2;
transvalues = check_float8_array(transarray, "float8_stddev");
N = transvalues[0];
sumX = transvalues[1];
sumX2 = transvalues[2];
/* We define STDDEV of no values to be NULL, of 1 value to be 0 */
if (N == 0.0)
PG_RETURN_NULL();
if (N <= 1.0)
PG_RETURN_FLOAT8(0.0);
PG_RETURN_FLOAT8(sqrt((N * sumX2 - sumX * sumX) / (N * (N - 1.0))));
}
/*
* ====================================
* MIXED-PRECISION ARITHMETIC OPERATORS
* ====================================
*/
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.40 2000/07/12 22:59:08 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.41 2000/07/17 03:05:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -650,14 +650,6 @@ int2div(PG_FUNCTION_ARGS)
PG_RETURN_INT16(arg1 / arg2);
}
Datum
int2inc(PG_FUNCTION_ARGS)
{
int16 arg = PG_GETARG_INT16(0);
PG_RETURN_INT16(arg + 1);
}
Datum
int24pl(PG_FUNCTION_ARGS)
{

View File

@ -5,7 +5,7 @@
*
* 1998 Jan Wieck
*
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.31 2000/06/15 03:32:29 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.32 2000/07/17 03:05:18 tgl Exp $
*
* ----------
*/
@ -18,6 +18,7 @@
#include <errno.h>
#include <sys/types.h>
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/int8.h"
#include "utils/numeric.h"
@ -1230,49 +1231,6 @@ numeric_inc(Numeric num)
}
/* ----------
* numeric_dec() -
*
* Decrement a number by one
* ----------
*/
Numeric
numeric_dec(Numeric num)
{
NumericVar arg;
Numeric res;
/* ----------
* Handle NULL
* ----------
*/
if (num == NULL)
return NULL;
/* ----------
* Handle NaN
* ----------
*/
if (NUMERIC_IS_NAN(num))
return make_result(&const_nan);
/* ----------
* Compute the result and return it
* ----------
*/
init_var(&arg);
set_var_from_num(num, &arg);
sub_var(&arg, &const_one, &arg);
res = make_result(&arg);
free_var(&arg);
return res;
}
/* ----------
* numeric_smaller() -
*
@ -1733,24 +1691,24 @@ numeric_int4(Numeric num)
}
Numeric
int8_numeric(int64 *val)
Datum
int8_numeric(PG_FUNCTION_ARGS)
{
Datum val = PG_GETARG_DATUM(0);
Numeric res;
NumericVar result;
char *tmp;
init_var(&result);
tmp = DatumGetCString(DirectFunctionCall1(int8out,
PointerGetDatum(val)));
tmp = DatumGetCString(DirectFunctionCall1(int8out, val));
set_var_from_str(tmp, &result);
res = make_result(&result);
free_var(&result);
pfree(tmp);
return res;
PG_RETURN_NUMERIC(res);
}
@ -1939,6 +1897,369 @@ numeric_float4(Numeric num)
}
/* ----------------------------------------------------------------------
*
* Aggregate functions
*
* The transition datatype for all these aggregates is a 3-element array
* of Numeric, holding the values N, sum(X), sum(X*X) in that order.
*
* We represent N as a numeric mainly to avoid having to build a special
* datatype; it's unlikely it'd overflow an int4, but ...
*
* ----------------------------------------------------------------------
*/
static ArrayType *
do_numeric_accum(ArrayType *transarray, Numeric newval)
{
Datum *transdatums;
int ndatums;
Numeric N,
sumX,
sumX2;
ArrayType *result;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
false, -1, 'i',
&transdatums, &ndatums);
if (ndatums != 3)
elog(ERROR, "do_numeric_accum: expected 3-element numeric array");
N = DatumGetNumeric(transdatums[0]);
sumX = DatumGetNumeric(transdatums[1]);
sumX2 = DatumGetNumeric(transdatums[2]);
N = numeric_inc(N);
sumX = numeric_add(sumX, newval);
sumX2 = numeric_add(sumX2, numeric_mul(newval, newval));
transdatums[0] = NumericGetDatum(N);
transdatums[1] = NumericGetDatum(sumX);
transdatums[2] = NumericGetDatum(sumX2);
result = construct_array(transdatums, 3,
false, -1, 'i');
return result;
}
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Numeric newval = PG_GETARG_NUMERIC(1);
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
/*
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval2 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
Datum
int4_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval4 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
Datum
int8_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval8 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
Datum
numeric_avg(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum *transdatums;
int ndatums;
Numeric N,
sumX;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
false, -1, 'i',
&transdatums, &ndatums);
if (ndatums != 3)
elog(ERROR, "numeric_avg: expected 3-element numeric array");
N = DatumGetNumeric(transdatums[0]);
sumX = DatumGetNumeric(transdatums[1]);
/* ignore sumX2 */
/* 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_NUMERIC(numeric_div(sumX, N));
}
Datum
numeric_variance(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum *transdatums;
int ndatums;
Numeric N,
sumX,
sumX2,
res;
NumericVar vN,
vsumX,
vsumX2,
vNminus1;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
false, -1, 'i',
&transdatums, &ndatums);
if (ndatums != 3)
elog(ERROR, "numeric_variance: 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));
/* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
/* N is zero iff no digits (cf. numeric_uminus) */
if (N->varlen == NUMERIC_HDRSZ)
PG_RETURN_NULL();
init_var(&vN);
set_var_from_num(N, &vN);
init_var(&vNminus1);
sub_var(&vN, &const_one, &vNminus1);
if (cmp_var(&vNminus1, &const_zero) <= 0)
{
free_var(&vN);
free_var(&vNminus1);
PG_RETURN_NUMERIC(make_result(&const_zero));
}
init_var(&vsumX);
set_var_from_num(sumX, &vsumX);
init_var(&vsumX2);
set_var_from_num(sumX2, &vsumX2);
mul_var(&vsumX, &vsumX, &vsumX); /* now vsumX contains sumX * sumX */
mul_var(&vN, &vsumX2, &vsumX2); /* now vsumX2 contains N * sumX2 */
sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */
mul_var(&vN, &vNminus1, &vNminus1); /* N * (N - 1) */
div_var(&vsumX2, &vNminus1, &vsumX); /* variance */
res = make_result(&vsumX);
free_var(&vN);
free_var(&vNminus1);
free_var(&vsumX);
free_var(&vsumX2);
PG_RETURN_NUMERIC(res);
}
Datum
numeric_stddev(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum *transdatums;
int ndatums;
Numeric N,
sumX,
sumX2,
res;
NumericVar vN,
vsumX,
vsumX2,
vNminus1;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
false, -1, 'i',
&transdatums, &ndatums);
if (ndatums != 3)
elog(ERROR, "numeric_stddev: 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));
/* We define STDDEV of no values to be NULL, of 1 value to be 0 */
/* N is zero iff no digits (cf. numeric_uminus) */
if (N->varlen == NUMERIC_HDRSZ)
PG_RETURN_NULL();
init_var(&vN);
set_var_from_num(N, &vN);
init_var(&vNminus1);
sub_var(&vN, &const_one, &vNminus1);
if (cmp_var(&vNminus1, &const_zero) <= 0)
{
free_var(&vN);
free_var(&vNminus1);
PG_RETURN_NUMERIC(make_result(&const_zero));
}
init_var(&vsumX);
set_var_from_num(sumX, &vsumX);
init_var(&vsumX2);
set_var_from_num(sumX2, &vsumX2);
mul_var(&vsumX, &vsumX, &vsumX); /* now vsumX contains sumX * sumX */
mul_var(&vN, &vsumX2, &vsumX2); /* now vsumX2 contains N * sumX2 */
sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */
mul_var(&vN, &vNminus1, &vNminus1); /* N * (N - 1) */
div_var(&vsumX2, &vNminus1, &vsumX); /* variance */
sqrt_var(&vsumX, &vsumX); /* stddev */
res = make_result(&vsumX);
free_var(&vN);
free_var(&vNminus1);
free_var(&vsumX);
free_var(&vsumX2);
PG_RETURN_NUMERIC(res);
}
/*
* SUM transition functions for integer datatypes.
*
* We use a Numeric accumulator to avoid overflow. Because SQL92 defines
* the SUM() of no values to be NULL, not zero, the initial condition of
* the transition data value needs to be NULL. This means we can't rely
* on ExecAgg to automatically insert the first non-null data value into
* the transition data: it doesn't know how to do the type conversion.
* The upshot is that these routines have to be marked non-strict and
* handle substitution of the first non-null input themselves.
*/
Datum
int2_sum(PG_FUNCTION_ARGS)
{
Numeric oldsum,
newval;
if (PG_ARGISNULL(0))
{
/* No non-null input seen so far... */
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
PG_RETURN_NUMERIC(newval);
}
oldsum = PG_GETARG_NUMERIC(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
PG_RETURN_NUMERIC(oldsum);
/* OK to do the addition. */
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
PG_RETURN_NUMERIC(numeric_add(oldsum, newval));
}
Datum
int4_sum(PG_FUNCTION_ARGS)
{
Numeric oldsum,
newval;
if (PG_ARGISNULL(0))
{
/* No non-null input seen so far... */
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
PG_RETURN_NUMERIC(newval);
}
oldsum = PG_GETARG_NUMERIC(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
PG_RETURN_NUMERIC(oldsum);
/* OK to do the addition. */
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
PG_RETURN_NUMERIC(numeric_add(oldsum, newval));
}
Datum
int8_sum(PG_FUNCTION_ARGS)
{
Numeric oldsum,
newval;
if (PG_ARGISNULL(0))
{
/* No non-null input seen so far... */
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
PG_RETURN_NUMERIC(newval);
}
oldsum = PG_GETARG_NUMERIC(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
PG_RETURN_NUMERIC(oldsum);
/* OK to do the addition. */
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
PG_RETURN_NUMERIC(numeric_add(oldsum, newval));
}
/* ----------------------------------------------------------------------
*
* Local functions follow
@ -2574,30 +2895,33 @@ add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
*/
switch (cmp_abs(var1, var2))
{
case 0: /* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->rscale = MAX(var1->rscale, var2->rscale);
result->dscale = MAX(var1->dscale, var2->dscale);
break;
case 1: /* ----------
* ABS(var1) > ABS(var2)
* result = +(ABS(var1) - ABS(var2))
* ----------
*/
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = +(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_POS;
break;
case -1: /* ----------
* ABS(var1) < ABS(var2)
* result = -(ABS(var2) - ABS(var1))
* ----------
*/
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = -(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_NEG;
break;
@ -2615,30 +2939,33 @@ add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
*/
switch (cmp_abs(var1, var2))
{
case 0: /* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->rscale = MAX(var1->rscale, var2->rscale);
result->dscale = MAX(var1->dscale, var2->dscale);
break;
case 1: /* ----------
* ABS(var1) > ABS(var2)
* result = -(ABS(var1) - ABS(var2))
* ----------
*/
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = -(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_NEG;
break;
case -1: /* ----------
* ABS(var1) < ABS(var2)
* result = +(ABS(var2) - ABS(var1))
* ----------
*/
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = +(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_POS;
break;
@ -2693,30 +3020,33 @@ sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
*/
switch (cmp_abs(var1, var2))
{
case 0: /* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->rscale = MAX(var1->rscale, var2->rscale);
result->dscale = MAX(var1->dscale, var2->dscale);
break;
case 1: /* ----------
* ABS(var1) > ABS(var2)
* result = +(ABS(var1) - ABS(var2))
* ----------
*/
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = +(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_POS;
break;
case -1: /* ----------
* ABS(var1) < ABS(var2)
* result = -(ABS(var2) - ABS(var1))
* ----------
*/
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = -(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_NEG;
break;
@ -2734,30 +3064,33 @@ sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
*/
switch (cmp_abs(var1, var2))
{
case 0: /* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->rscale = MAX(var1->rscale, var2->rscale);
result->dscale = MAX(var1->dscale, var2->dscale);
break;
case 1: /* ----------
* ABS(var1) > ABS(var2)
* result = -(ABS(var1) - ABS(var2))
* ----------
*/
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = -(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_NEG;
break;
case -1: /* ----------
* ABS(var1) < ABS(var2)
* result = +(ABS(var2) - ABS(var1))
* ----------
*/
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = +(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_POS;
break;
@ -2817,7 +3150,7 @@ mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
{
sum = sum + res_digits[i] + var1->digits[i1] * var2->digits[i2];
sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
res_digits[i--] = sum % 10;
sum /= 10;
}
@ -3067,7 +3400,6 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
/*
* Tidy up
*
*/
digitbuf_free(dividend.buf);
for (i = 1; i < 10; i++)
@ -3552,6 +3884,11 @@ add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
i1,
i2;
int carry = 0;
/* copy these values into local vars for speed in inner loop */
int var1ndigits = var1->ndigits;
int var2ndigits = var2->ndigits;
NumericDigit *var1digits = var1->digits;
NumericDigit *var2digits = var2->digits;
res_weight = MAX(var1->weight, var2->weight) + 1;
res_rscale = MAX(var1->rscale, var2->rscale);
@ -3569,15 +3906,25 @@ add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
{
i1--;
i2--;
if (i1 >= 0 && i1 < var1->ndigits)
carry += var1->digits[i1];
if (i2 >= 0 && i2 < var2->ndigits)
carry += var2->digits[i2];
if (i1 >= 0 && i1 < var1ndigits)
carry += var1digits[i1];
if (i2 >= 0 && i2 < var2ndigits)
carry += var2digits[i2];
res_digits[i] = carry % 10;
carry /= 10;
if (carry >= 10)
{
res_digits[i] = carry - 10;
carry = 1;
}
else
{
res_digits[i] = carry;
carry = 0;
}
}
Assert(carry == 0); /* else we failed to allow for carry out */
while (res_ndigits > 0 && *res_digits == 0)
{
res_digits++;
@ -3623,6 +3970,11 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
i1,
i2;
int borrow = 0;
/* copy these values into local vars for speed in inner loop */
int var1ndigits = var1->ndigits;
int var2ndigits = var2->ndigits;
NumericDigit *var1digits = var1->digits;
NumericDigit *var2digits = var2->digits;
res_weight = var1->weight;
res_rscale = MAX(var1->rscale, var2->rscale);
@ -3640,10 +3992,10 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
{
i1--;
i2--;
if (i1 >= 0 && i1 < var1->ndigits)
borrow += var1->digits[i1];
if (i2 >= 0 && i2 < var2->ndigits)
borrow -= var2->digits[i2];
if (i1 >= 0 && i1 < var1ndigits)
borrow += var1digits[i1];
if (i2 >= 0 && i2 < var2ndigits)
borrow -= var2digits[i2];
if (borrow < 0)
{
@ -3657,6 +4009,8 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
}
}
Assert(borrow == 0); /* else caller gave us var1 < var2 */
while (res_ndigits > 0 && *res_digits == 0)
{
res_digits++;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.33 2000/07/12 22:59:09 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.34 2000/07/17 03:05:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,6 +29,7 @@
#include "access/hash.h"
#include "access/xact.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
@ -882,10 +883,6 @@ overlaps_timestamp(PG_FUNCTION_ARGS)
/*----------------------------------------------------------
* "Arithmetic" operators on date/times.
* timestamp_foo returns foo as an object (pointer) that
* can be passed between languages.
* timestamp_xx is an internal routine which returns the
* actual value.
*---------------------------------------------------------*/
Datum
@ -1150,7 +1147,6 @@ interval_larger(PG_FUNCTION_ARGS)
PG_RETURN_INTERVAL_P(result);
}
Datum
interval_pl(PG_FUNCTION_ARGS)
{
@ -1232,6 +1228,90 @@ interval_div(PG_FUNCTION_ARGS)
PG_RETURN_INTERVAL_P(result);
}
/*
* interval_accum and interval_avg implement the AVG(interval) aggregate.
*
* The transition datatype for this aggregate is a 2-element array of
* intervals, where the first is the running sum and the second contains
* the number of values so far in its 'time' field. This is a bit ugly
* but it beats inventing a specialized datatype for the purpose.
*/
Datum
interval_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Interval *newval = PG_GETARG_INTERVAL_P(1);
Datum *transdatums;
int ndatums;
Interval sumX,
N;
Interval *newsum;
ArrayType *result;
/* We assume the input is array of interval */
deconstruct_array(transarray,
false, 12, 'd',
&transdatums, &ndatums);
if (ndatums != 2)
elog(ERROR, "interval_accum: expected 2-element interval array");
/*
* XXX memcpy, instead of just extracting a pointer, to work around
* buggy array code: it won't ensure proper alignment of Interval
* objects on machines where double requires 8-byte alignment.
* That should be fixed, but in the meantime...
*/
memcpy(&sumX, DatumGetIntervalP(transdatums[0]), sizeof(Interval));
memcpy(&N, DatumGetIntervalP(transdatums[1]), sizeof(Interval));
newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
IntervalPGetDatum(&sumX),
IntervalPGetDatum(newval)));
N.time += 1;
transdatums[0] = IntervalPGetDatum(newsum);
transdatums[1] = IntervalPGetDatum(&N);
result = construct_array(transdatums, 2,
false, 12, 'd');
PG_RETURN_ARRAYTYPE_P(result);
}
Datum
interval_avg(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum *transdatums;
int ndatums;
Interval sumX,
N;
/* We assume the input is array of interval */
deconstruct_array(transarray,
false, 12, 'd',
&transdatums, &ndatums);
if (ndatums != 2)
elog(ERROR, "interval_avg: expected 2-element interval array");
/*
* XXX memcpy, instead of just extracting a pointer, to work around
* buggy array code: it won't ensure proper alignment of Interval
* objects on machines where double requires 8-byte alignment.
* That should be fixed, but in the meantime...
*/
memcpy(&sumX, DatumGetIntervalP(transdatums[0]), sizeof(Interval));
memcpy(&N, DatumGetIntervalP(transdatums[1]), sizeof(Interval));
/* SQL92 defines AVG of no values to be NULL */
if (N.time == 0)
PG_RETURN_NULL();
return DirectFunctionCall2(interval_div,
IntervalPGetDatum(&sumX),
Float8GetDatum(N.time));
}
/* timestamp_age()
* Calculate time difference while retaining year/month fields.
* Note that this does not result in an accurate absolute time span

View File

@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.158 2000/07/11 13:07:17 momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.159 2000/07/17 03:05:20 tgl Exp $
*
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
*
@ -1421,22 +1421,16 @@ clearAggInfo(AggInfo *agginfo, int numArgs)
free(agginfo[i].oid);
if (agginfo[i].aggname)
free(agginfo[i].aggname);
if (agginfo[i].aggtransfn1)
free(agginfo[i].aggtransfn1);
if (agginfo[i].aggtransfn2)
free(agginfo[i].aggtransfn2);
if (agginfo[i].aggtransfn)
free(agginfo[i].aggtransfn);
if (agginfo[i].aggfinalfn)
free(agginfo[i].aggfinalfn);
if (agginfo[i].aggtranstype1)
free(agginfo[i].aggtranstype1);
if (agginfo[i].aggtranstype)
free(agginfo[i].aggtranstype);
if (agginfo[i].aggbasetype)
free(agginfo[i].aggbasetype);
if (agginfo[i].aggtranstype2)
free(agginfo[i].aggtranstype2);
if (agginfo[i].agginitval1)
free(agginfo[i].agginitval1);
if (agginfo[i].agginitval2)
free(agginfo[i].agginitval2);
if (agginfo[i].agginitval)
free(agginfo[i].agginitval);
if (agginfo[i].usename)
free(agginfo[i].usename);
}
@ -1463,22 +1457,19 @@ getAggregates(int *numAggs)
int i_oid;
int i_aggname;
int i_aggtransfn1;
int i_aggtransfn2;
int i_aggtransfn;
int i_aggfinalfn;
int i_aggtranstype1;
int i_aggtranstype;
int i_aggbasetype;
int i_aggtranstype2;
int i_agginitval1;
int i_agginitval2;
int i_agginitval;
int i_usename;
/* find all user-defined aggregates */
appendPQExpBuffer(query,
"SELECT pg_aggregate.oid, aggname, aggtransfn1, aggtransfn2, "
"aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, "
"agginitval1, agginitval2, usename from pg_aggregate, pg_user "
"SELECT pg_aggregate.oid, aggname, aggtransfn, "
"aggfinalfn, aggtranstype, aggbasetype, "
"agginitval, usename from pg_aggregate, pg_user "
"where aggowner = usesysid");
res = PQexec(g_conn, query->data);
@ -1497,28 +1488,22 @@ getAggregates(int *numAggs)
i_oid = PQfnumber(res, "oid");
i_aggname = PQfnumber(res, "aggname");
i_aggtransfn1 = PQfnumber(res, "aggtransfn1");
i_aggtransfn2 = PQfnumber(res, "aggtransfn2");
i_aggtransfn = PQfnumber(res, "aggtransfn");
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
i_aggtranstype1 = PQfnumber(res, "aggtranstype1");
i_aggtranstype = PQfnumber(res, "aggtranstype");
i_aggbasetype = PQfnumber(res, "aggbasetype");
i_aggtranstype2 = PQfnumber(res, "aggtranstype2");
i_agginitval1 = PQfnumber(res, "agginitval1");
i_agginitval2 = PQfnumber(res, "agginitval2");
i_agginitval = PQfnumber(res, "agginitval");
i_usename = PQfnumber(res, "usename");
for (i = 0; i < ntups; i++)
{
agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
agginfo[i].aggtransfn1 = strdup(PQgetvalue(res, i, i_aggtransfn1));
agginfo[i].aggtransfn2 = strdup(PQgetvalue(res, i, i_aggtransfn2));
agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
agginfo[i].aggtranstype1 = strdup(PQgetvalue(res, i, i_aggtranstype1));
agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
agginfo[i].aggtranstype2 = strdup(PQgetvalue(res, i, i_aggtranstype2));
agginfo[i].agginitval1 = strdup(PQgetvalue(res, i, i_agginitval1));
agginfo[i].agginitval2 = strdup(PQgetvalue(res, i, i_agginitval2));
agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
}
@ -2902,69 +2887,32 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
PQExpBuffer q = createPQExpBuffer();
PQExpBuffer delq = createPQExpBuffer();
PQExpBuffer aggSig = createPQExpBuffer();
PQExpBuffer sfunc1 = createPQExpBuffer();
PQExpBuffer sfunc2 = createPQExpBuffer();
PQExpBuffer basetype = createPQExpBuffer();
PQExpBuffer finalfunc = createPQExpBuffer();
char comma1[2],
comma2[2];
PQExpBuffer details = createPQExpBuffer();
for (i = 0; i < numAggs; i++)
{
resetPQExpBuffer(sfunc1);
resetPQExpBuffer(sfunc2);
resetPQExpBuffer(basetype);
resetPQExpBuffer(finalfunc);
resetPQExpBuffer(details);
/* skip all the builtin oids */
if (atoi(agginfo[i].oid) < g_last_builtin_oid)
continue;
appendPQExpBuffer(basetype,
appendPQExpBuffer(details,
"BASETYPE = %s, ",
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
if (!(strcmp(agginfo[i].aggtransfn1, "-") == 0))
{
appendPQExpBuffer(sfunc1,
"SFUNC1 = %s, STYPE1 = %s",
agginfo[i].aggtransfn1,
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype1), false));
if (agginfo[i].agginitval1)
appendPQExpBuffer(sfunc1, ", INITCOND1 = '%s'",
agginfo[i].agginitval1);
appendPQExpBuffer(details,
"SFUNC = %s, STYPE = %s",
agginfo[i].aggtransfn,
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype), false));
}
if (!(strcmp(agginfo[i].aggtransfn2, "-") == 0))
{
appendPQExpBuffer(sfunc2,
"SFUNC2 = %s, STYPE2 = %s",
agginfo[i].aggtransfn2,
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype2), false));
if (agginfo[i].agginitval2)
appendPQExpBuffer(sfunc2, ", INITCOND2 = '%s'",
agginfo[i].agginitval2);
}
if (agginfo[i].agginitval)
appendPQExpBuffer(details, ", INITCOND = '%s'",
agginfo[i].agginitval);
if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
appendPQExpBuffer(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn);
if (sfunc1->data[0] != '\0' && sfunc2->data[0] != '\0')
{
comma1[0] = ',';
comma1[1] = '\0';
}
else
comma1[0] = '\0';
if (finalfunc->data[0] != '\0' && (sfunc1->data[0] != '\0' || sfunc2->data[0] != '\0'))
{
comma2[0] = ',';
comma2[1] = '\0';
}
else
comma2[0] = '\0';
appendPQExpBuffer(details, ", FINALFUNC = %s",
agginfo[i].aggfinalfn);
resetPQExpBuffer(aggSig);
appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
@ -2974,14 +2922,9 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
appendPQExpBuffer(delq, "DROP AGGREGATE %s;\n", aggSig->data);
resetPQExpBuffer(q);
appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s %s%s %s%s %s );\n",
appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
agginfo[i].aggname,
basetype->data,
sfunc1->data,
comma1,
sfunc2->data,
comma2,
finalfunc->data);
details->data);
ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
q->data, delq->data, agginfo[i].usename, NULL, NULL);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_dump.h,v 1.49 2000/07/04 14:25:28 momjian Exp $
* $Id: pg_dump.h,v 1.50 2000/07/17 03:05:20 tgl Exp $
*
* Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
*
@ -133,14 +133,11 @@ typedef struct _aggInfo
{
char *oid;
char *aggname;
char *aggtransfn1;
char *aggtransfn2;
char *aggtransfn;
char *aggfinalfn;
char *aggtranstype1;
char *aggtranstype;
char *aggbasetype;
char *aggtranstype2;
char *agginitval1;
char *agginitval2;
char *agginitval;
char *usename;
} AggInfo;

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: c.h,v 1.78 2000/07/12 22:59:12 petere Exp $
* $Id: c.h,v 1.79 2000/07/17 03:05:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -587,6 +587,25 @@ extern Datum Float8GetDatum(float8 X);
#define Float64GetDatum(X) PointerGetDatum(X)
/*
* Int64GetDatumFast
* Float4GetDatumFast
* Float8GetDatumFast
*
* These macros are intended to allow writing code that does not depend on
* whether int64, float4, float8 are pass-by-reference types, while not
* sacrificing performance when they are. The argument must be a variable
* that will exist and have the same value for as long as the Datum is needed.
* In the pass-by-ref case, the address of the variable is taken to use as
* the Datum. In the pass-by-val case, these will be the same as the non-Fast
* macros.
*/
#define Int64GetDatumFast(X) PointerGetDatum(&(X))
#define Float4GetDatumFast(X) PointerGetDatum(&(X))
#define Float8GetDatumFast(X) PointerGetDatum(&(X))
/* ----------------------------------------------------------------
* Section 5: IsValid macros for system types
* ----------------------------------------------------------------

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.36 2000/07/07 19:24:41 petere Exp $
* $Id: catversion.h,v 1.37 2000/07/17 03:05:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200007071
#define CATALOG_VERSION_NO 200007161
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_aggregate.h,v 1.26 2000/05/30 04:24:55 tgl Exp $
* $Id: pg_aggregate.h,v 1.27 2000/07/17 03:05:23 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -32,30 +32,25 @@
* cpp turns this into typedef struct FormData_pg_aggregate
*
* aggname name of the aggregate
* aggtransfn1 transition function 1
* aggtransfn2 transition function 2
* aggowner owner (creator) of the aggregate
* aggtransfn transition function
* aggfinalfn final function
* aggbasetype type of data on which aggregate operates
* aggtranstype1 output types for transition func 1
* aggtranstype2 output types for transition func 2
* aggfinaltype output type for final function
* agginitval1 initial aggregate value
* agginitval2 initial value for transition state 2
* aggtranstype type of aggregate's transition (state) data
* aggfinaltype type of aggregate's final result
* agginitval initial value for transition state
* ----------------------------------------------------------------
*/
CATALOG(pg_aggregate)
{
NameData aggname;
int4 aggowner;
regproc aggtransfn1;
regproc aggtransfn2;
regproc aggtransfn;
regproc aggfinalfn;
Oid aggbasetype;
Oid aggtranstype1;
Oid aggtranstype2;
Oid aggtranstype;
Oid aggfinaltype;
text agginitval1; /* VARIABLE LENGTH FIELD */
text agginitval2; /* VARIABLE LENGTH FIELD */
text agginitval; /* VARIABLE LENGTH FIELD */
} FormData_pg_aggregate;
/* ----------------
@ -70,18 +65,15 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
* ----------------
*/
#define Natts_pg_aggregate 11
#define Natts_pg_aggregate 8
#define Anum_pg_aggregate_aggname 1
#define Anum_pg_aggregate_aggowner 2
#define Anum_pg_aggregate_aggtransfn1 3
#define Anum_pg_aggregate_aggtransfn2 4
#define Anum_pg_aggregate_aggfinalfn 5
#define Anum_pg_aggregate_aggbasetype 6
#define Anum_pg_aggregate_aggtranstype1 7
#define Anum_pg_aggregate_aggtranstype2 8
#define Anum_pg_aggregate_aggfinaltype 9
#define Anum_pg_aggregate_agginitval1 10
#define Anum_pg_aggregate_agginitval2 11
#define Anum_pg_aggregate_aggtransfn 3
#define Anum_pg_aggregate_aggfinalfn 4
#define Anum_pg_aggregate_aggbasetype 5
#define Anum_pg_aggregate_aggtranstype 6
#define Anum_pg_aggregate_aggfinaltype 7
#define Anum_pg_aggregate_agginitval 8
/* ----------------
@ -89,70 +81,84 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
* ---------------
*/
DATA(insert OID = 0 ( avg PGUID int8pl int4inc int84div 20 20 23 20 _null_ 0 ));
DATA(insert OID = 0 ( avg PGUID int4pl int4inc int4div 23 23 23 23 _null_ 0 ));
DATA(insert OID = 0 ( avg PGUID int2pl int2inc int2div 21 21 21 21 _null_ 0 ));
DATA(insert OID = 0 ( avg PGUID float4pl float4inc float4div 700 700 700 700 _null_ 0.0 ));
DATA(insert OID = 0 ( avg PGUID float8pl float8inc float8div 701 701 701 701 _null_ 0.0 ));
DATA(insert OID = 0 ( avg PGUID cash_pl float8inc cash_div_flt8 790 790 701 790 _null_ 0.0 ));
DATA(insert OID = 0 ( avg PGUID interval_pl float8inc interval_div 1186 1186 701 1186 _null_ 0.0 ));
DATA(insert OID = 0 ( avg PGUID numeric_add numeric_inc numeric_div 1700 1700 1700 1700 _null_ 0 ));
DATA(insert OID = 0 ( avg PGUID int8_accum numeric_avg 20 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( avg PGUID int4_accum numeric_avg 23 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( avg PGUID int2_accum numeric_avg 21 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( avg PGUID numeric_accum numeric_avg 1700 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( avg PGUID float4_accum float8_avg 700 1022 701 "{0,0,0}" ));
DATA(insert OID = 0 ( avg PGUID float8_accum float8_avg 701 1022 701 "{0,0,0}" ));
DATA(insert OID = 0 ( avg PGUID interval_accum interval_avg 1186 1187 1186 "{0,0}" ));
DATA(insert OID = 0 ( sum PGUID int8pl - - 20 20 0 20 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID int4pl - - 23 23 0 23 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID int2pl - - 21 21 0 21 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID float4pl - - 700 700 0 700 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID float8pl - - 701 701 0 701 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID cash_pl - - 790 790 0 790 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID interval_pl - - 1186 1186 0 1186 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID numeric_add - - 1700 1700 0 1700 _null_ _null_ ));
DATA(insert OID = 0 ( sum PGUID int8_sum - 20 1700 1700 _null_ ));
DATA(insert OID = 0 ( sum PGUID int4_sum - 23 1700 1700 _null_ ));
DATA(insert OID = 0 ( sum PGUID int2_sum - 21 1700 1700 _null_ ));
DATA(insert OID = 0 ( sum PGUID float4pl - 700 700 700 _null_ ));
DATA(insert OID = 0 ( sum PGUID float8pl - 701 701 701 _null_ ));
DATA(insert OID = 0 ( sum PGUID cash_pl - 790 790 790 _null_ ));
DATA(insert OID = 0 ( sum PGUID interval_pl - 1186 1186 1186 _null_ ));
DATA(insert OID = 0 ( sum PGUID numeric_add - 1700 1700 1700 _null_ ));
DATA(insert OID = 0 ( max PGUID int8larger - - 20 20 0 20 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID int4larger - - 23 23 0 23 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID int2larger - - 21 21 0 21 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID float4larger - - 700 700 0 700 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID float8larger - - 701 701 0 701 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID int4larger - - 702 702 0 702 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID date_larger - - 1082 1082 0 1082 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID time_larger - - 1083 1083 0 1083 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID timetz_larger - - 1266 1266 0 1266 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID cashlarger - - 790 790 0 790 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID timestamp_larger - - 1184 1184 0 1184 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID interval_larger - - 1186 1186 0 1186 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID text_larger - - 25 25 0 25 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID numeric_larger - - 1700 1700 0 1700 _null_ _null_ ));
DATA(insert OID = 0 ( max PGUID int8larger - 20 20 20 _null_ ));
DATA(insert OID = 0 ( max PGUID int4larger - 23 23 23 _null_ ));
DATA(insert OID = 0 ( max PGUID int2larger - 21 21 21 _null_ ));
DATA(insert OID = 0 ( max PGUID float4larger - 700 700 700 _null_ ));
DATA(insert OID = 0 ( max PGUID float8larger - 701 701 701 _null_ ));
DATA(insert OID = 0 ( max PGUID int4larger - 702 702 702 _null_ ));
DATA(insert OID = 0 ( max PGUID date_larger - 1082 1082 1082 _null_ ));
DATA(insert OID = 0 ( max PGUID time_larger - 1083 1083 1083 _null_ ));
DATA(insert OID = 0 ( max PGUID timetz_larger - 1266 1266 1266 _null_ ));
DATA(insert OID = 0 ( max PGUID cashlarger - 790 790 790 _null_ ));
DATA(insert OID = 0 ( max PGUID timestamp_larger - 1184 1184 1184 _null_ ));
DATA(insert OID = 0 ( max PGUID interval_larger - 1186 1186 1186 _null_ ));
DATA(insert OID = 0 ( max PGUID text_larger - 25 25 25 _null_ ));
DATA(insert OID = 0 ( max PGUID numeric_larger - 1700 1700 1700 _null_ ));
DATA(insert OID = 0 ( min PGUID int8smaller - - 20 20 0 20 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID int4smaller - - 23 23 0 23 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID int2smaller - - 21 21 0 21 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID float4smaller - - 700 700 0 700 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID float8smaller - - 701 701 0 701 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID int4smaller - - 702 702 0 702 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID date_smaller - - 1082 1082 0 1082 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID time_smaller - - 1083 1083 0 1083 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID timetz_smaller - - 1266 1266 0 1266 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID cashsmaller - - 790 790 0 790 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID timestamp_smaller - - 1184 1184 0 1184 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID interval_smaller - - 1186 1186 0 1186 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID text_smaller - - 25 25 0 25 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID numeric_smaller - - 1700 1700 0 1700 _null_ _null_ ));
DATA(insert OID = 0 ( min PGUID int8smaller - 20 20 20 _null_ ));
DATA(insert OID = 0 ( min PGUID int4smaller - 23 23 23 _null_ ));
DATA(insert OID = 0 ( min PGUID int2smaller - 21 21 21 _null_ ));
DATA(insert OID = 0 ( min PGUID float4smaller - 700 700 700 _null_ ));
DATA(insert OID = 0 ( min PGUID float8smaller - 701 701 701 _null_ ));
DATA(insert OID = 0 ( min PGUID int4smaller - 702 702 702 _null_ ));
DATA(insert OID = 0 ( min PGUID date_smaller - 1082 1082 1082 _null_ ));
DATA(insert OID = 0 ( min PGUID time_smaller - 1083 1083 1083 _null_ ));
DATA(insert OID = 0 ( min PGUID timetz_smaller - 1266 1266 1266 _null_ ));
DATA(insert OID = 0 ( min PGUID cashsmaller - 790 790 790 _null_ ));
DATA(insert OID = 0 ( min PGUID timestamp_smaller - 1184 1184 1184 _null_ ));
DATA(insert OID = 0 ( min PGUID interval_smaller - 1186 1186 1186 _null_ ));
DATA(insert OID = 0 ( min PGUID text_smaller - 25 25 25 _null_ ));
DATA(insert OID = 0 ( min PGUID numeric_smaller - 1700 1700 1700 _null_ ));
DATA(insert OID = 0 ( count PGUID - int4inc - 0 0 23 23 _null_ 0 ));
/*
* Using int4inc for count() is cheating a little, since it really only
* takes 1 parameter not 2, but nodeAgg.c won't complain ...
*/
DATA(insert OID = 0 ( count PGUID int4inc - 0 23 23 0 ));
DATA(insert OID = 0 ( variance PGUID int8_accum numeric_variance 20 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( variance PGUID int4_accum numeric_variance 23 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( variance PGUID int2_accum numeric_variance 21 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( variance PGUID float4_accum float8_variance 700 1022 701 "{0,0,0}" ));
DATA(insert OID = 0 ( variance PGUID float8_accum float8_variance 701 1022 701 "{0,0,0}" ));
DATA(insert OID = 0 ( variance PGUID numeric_accum numeric_variance 1700 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( stddev PGUID int8_accum numeric_stddev 20 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( stddev PGUID int4_accum numeric_stddev 23 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( stddev PGUID int2_accum numeric_stddev 21 1231 1700 "{0,0,0}" ));
DATA(insert OID = 0 ( stddev PGUID float4_accum float8_stddev 700 1022 701 "{0,0,0}" ));
DATA(insert OID = 0 ( stddev PGUID float8_accum float8_stddev 701 1022 701 "{0,0,0}" ));
DATA(insert OID = 0 ( stddev PGUID numeric_accum numeric_stddev 1700 1231 1700 "{0,0,0}" ));
/*
* prototypes for functions in pg_aggregate.c
*/
extern void AggregateCreate(char *aggName,
char *aggtransfn1Name,
char *aggtransfn2Name,
char *aggtransfnName,
char *aggfinalfnName,
char *aggbasetypeName,
char *aggtransfn1typeName,
char *aggtransfn2typeName,
char *agginitval1,
char *agginitval2);
char *aggtranstypeName,
char *agginitval);
extern Datum AggNameGetInitVal(char *aggName, Oid basetype,
int xfuncno, bool *isNull);
bool *isNull);
#endif /* PG_AGGREGATE_H */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_operator.h,v 1.76 2000/06/05 07:28:59 tgl Exp $
* $Id: pg_operator.h,v 1.77 2000/07/17 03:05:23 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -323,12 +323,12 @@ DATA(insert OID = 636 ( "-" PGUID 0 b t f 18 18 18 0 0 0 0 charmi - - ))
DATA(insert OID = 637 ( "*" PGUID 0 b t f 18 18 18 0 0 0 0 charmul - - ));
DATA(insert OID = 638 ( "/" PGUID 0 b t f 18 18 18 0 0 0 0 chardiv - - ));
DATA(insert OID = 639 ( "~" PGUID 0 b t f 19 25 16 0 640 0 0 nameregexeq eqsel eqjoinsel ));
DATA(insert OID = 639 ( "~" PGUID 0 b t f 19 25 16 0 640 0 0 nameregexeq regexeqsel regexeqjoinsel ));
#define OID_NAME_REGEXEQ_OP 639
DATA(insert OID = 640 ( "!~" PGUID 0 b t f 19 25 16 0 639 0 0 nameregexne neqsel neqjoinsel ));
DATA(insert OID = 641 ( "~" PGUID 0 b t f 25 25 16 0 642 0 0 textregexeq eqsel eqjoinsel ));
DATA(insert OID = 640 ( "!~" PGUID 0 b t f 19 25 16 0 639 0 0 nameregexne regexnesel regexnejoinsel ));
DATA(insert OID = 641 ( "~" PGUID 0 b t f 25 25 16 0 642 0 0 textregexeq regexeqsel regexeqjoinsel ));
#define OID_TEXT_REGEXEQ_OP 641
DATA(insert OID = 642 ( "!~" PGUID 0 b t f 25 25 16 0 641 0 0 textregexne neqsel neqjoinsel ));
DATA(insert OID = 642 ( "!~" PGUID 0 b t f 25 25 16 0 641 0 0 textregexne regexnesel regexnejoinsel ));
DATA(insert OID = 643 ( "<>" PGUID 0 b t f 19 19 16 643 93 0 0 namene neqsel neqjoinsel ));
DATA(insert OID = 654 ( "||" PGUID 0 b t f 25 25 25 0 0 0 0 textcat - - ));
@ -449,9 +449,9 @@ DATA(insert OID = 974 ( "||" PGUID 0 b t f 1042 1042 1042 0 0 0 0 textc
DATA(insert OID = 979 ( "||" PGUID 0 b t f 1043 1043 1043 0 0 0 0 textcat - - ));
DATA(insert OID = 1054 ( "=" PGUID 0 b t f 1042 1042 16 1054 1057 1058 1058 bpchareq eqsel eqjoinsel ));
DATA(insert OID = 1055 ( "~" PGUID 0 b t f 1042 25 16 0 1056 0 0 textregexeq eqsel eqjoinsel ));
DATA(insert OID = 1055 ( "~" PGUID 0 b t f 1042 25 16 0 1056 0 0 textregexeq regexeqsel regexeqjoinsel ));
#define OID_BPCHAR_REGEXEQ_OP 1055
DATA(insert OID = 1056 ( "!~" PGUID 0 b t f 1042 25 16 0 1055 0 0 textregexne neqsel neqjoinsel ));
DATA(insert OID = 1056 ( "!~" PGUID 0 b t f 1042 25 16 0 1055 0 0 textregexne regexnesel regexnejoinsel ));
DATA(insert OID = 1057 ( "<>" PGUID 0 b t f 1042 1042 16 1057 1054 0 0 bpcharne neqsel neqjoinsel ));
DATA(insert OID = 1058 ( "<" PGUID 0 b t f 1042 1042 16 1060 1061 0 0 bpcharlt scalarltsel scalarltjoinsel ));
DATA(insert OID = 1059 ( "<=" PGUID 0 b t f 1042 1042 16 1061 1060 0 0 bpcharle scalarltsel scalarltjoinsel ));
@ -459,9 +459,9 @@ DATA(insert OID = 1060 ( ">" PGUID 0 b t f 1042 1042 16 1058 1059 0 0 bpcha
DATA(insert OID = 1061 ( ">=" PGUID 0 b t f 1042 1042 16 1059 1058 0 0 bpcharge scalargtsel scalargtjoinsel ));
DATA(insert OID = 1062 ( "=" PGUID 0 b t t 1043 1043 16 1062 1065 1066 1066 varchareq eqsel eqjoinsel ));
DATA(insert OID = 1063 ( "~" PGUID 0 b t f 1043 25 16 0 1064 0 0 textregexeq eqsel eqjoinsel ));
DATA(insert OID = 1063 ( "~" PGUID 0 b t f 1043 25 16 0 1064 0 0 textregexeq regexeqsel regexeqjoinsel ));
#define OID_VARCHAR_REGEXEQ_OP 1063
DATA(insert OID = 1064 ( "!~" PGUID 0 b t f 1043 25 16 0 1063 0 0 textregexne neqsel neqjoinsel ));
DATA(insert OID = 1064 ( "!~" PGUID 0 b t f 1043 25 16 0 1063 0 0 textregexne regexnesel regexnejoinsel ));
DATA(insert OID = 1065 ( "<>" PGUID 0 b t f 1043 1043 16 1065 1062 0 0 varcharne neqsel neqjoinsel ));
DATA(insert OID = 1066 ( "<" PGUID 0 b t f 1043 1043 16 1068 1069 0 0 varcharlt scalarltsel scalarltjoinsel ));
DATA(insert OID = 1067 ( "<=" PGUID 0 b t f 1043 1043 16 1069 1068 0 0 varcharle scalarltsel scalarltjoinsel ));
@ -527,32 +527,32 @@ DATA(insert OID = 1158 ( "!" PGUID 0 r t f 21 0 23 0 0 0 0 int2fac - - ));
DATA(insert OID = 1175 ( "!!" PGUID 0 l t f 0 21 23 0 0 0 0 int2fac - - ));
/* LIKE hacks by Keith Parks. */
DATA(insert OID = 1207 ( "~~" PGUID 0 b t f 19 25 16 0 1208 0 0 namelike eqsel eqjoinsel ));
DATA(insert OID = 1207 ( "~~" PGUID 0 b t f 19 25 16 0 1208 0 0 namelike likesel likejoinsel ));
#define OID_NAME_LIKE_OP 1207
DATA(insert OID = 1208 ( "!~~" PGUID 0 b t f 19 25 16 0 1207 0 0 namenlike neqsel neqjoinsel ));
DATA(insert OID = 1209 ( "~~" PGUID 0 b t f 25 25 16 0 1210 0 0 textlike eqsel eqjoinsel ));
DATA(insert OID = 1208 ( "!~~" PGUID 0 b t f 19 25 16 0 1207 0 0 namenlike nlikesel nlikejoinsel ));
DATA(insert OID = 1209 ( "~~" PGUID 0 b t f 25 25 16 0 1210 0 0 textlike likesel likejoinsel ));
#define OID_TEXT_LIKE_OP 1209
DATA(insert OID = 1210 ( "!~~" PGUID 0 b t f 25 25 16 0 1209 0 0 textnlike neqsel neqjoinsel ));
DATA(insert OID = 1211 ( "~~" PGUID 0 b t f 1042 25 16 0 1212 0 0 textlike eqsel eqjoinsel ));
DATA(insert OID = 1210 ( "!~~" PGUID 0 b t f 25 25 16 0 1209 0 0 textnlike nlikesel nlikejoinsel ));
DATA(insert OID = 1211 ( "~~" PGUID 0 b t f 1042 25 16 0 1212 0 0 textlike likesel likejoinsel ));
#define OID_BPCHAR_LIKE_OP 1211
DATA(insert OID = 1212 ( "!~~" PGUID 0 b t f 1042 25 16 0 1211 0 0 textnlike neqsel neqjoinsel ));
DATA(insert OID = 1213 ( "~~" PGUID 0 b t f 1043 25 16 0 1214 0 0 textlike eqsel eqjoinsel ));
DATA(insert OID = 1212 ( "!~~" PGUID 0 b t f 1042 25 16 0 1211 0 0 textnlike nlikesel nlikejoinsel ));
DATA(insert OID = 1213 ( "~~" PGUID 0 b t f 1043 25 16 0 1214 0 0 textlike likesel likejoinsel ));
#define OID_VARCHAR_LIKE_OP 1213
DATA(insert OID = 1214 ( "!~~" PGUID 0 b t f 1043 25 16 0 1213 0 0 textnlike neqsel neqjoinsel ));
DATA(insert OID = 1214 ( "!~~" PGUID 0 b t f 1043 25 16 0 1213 0 0 textnlike nlikesel nlikejoinsel ));
/* case-insensitive LIKE hacks */
DATA(insert OID = 1226 ( "~*" PGUID 0 b t f 19 25 16 0 1227 0 0 nameicregexeq eqsel eqjoinsel ));
DATA(insert OID = 1226 ( "~*" PGUID 0 b t f 19 25 16 0 1227 0 0 nameicregexeq icregexeqsel icregexeqjoinsel ));
#define OID_NAME_ICREGEXEQ_OP 1226
DATA(insert OID = 1227 ( "!~*" PGUID 0 b t f 19 25 16 0 1226 0 0 nameicregexne neqsel neqjoinsel ));
DATA(insert OID = 1228 ( "~*" PGUID 0 b t f 25 25 16 0 1229 0 0 texticregexeq eqsel eqjoinsel ));
DATA(insert OID = 1227 ( "!~*" PGUID 0 b t f 19 25 16 0 1226 0 0 nameicregexne icregexnesel icregexnejoinsel ));
DATA(insert OID = 1228 ( "~*" PGUID 0 b t f 25 25 16 0 1229 0 0 texticregexeq icregexeqsel icregexeqjoinsel ));
#define OID_TEXT_ICREGEXEQ_OP 1228
DATA(insert OID = 1229 ( "!~*" PGUID 0 b t f 25 25 16 0 1228 0 0 texticregexne neqsel neqjoinsel ));
DATA(insert OID = 1232 ( "~*" PGUID 0 b t f 1043 25 16 0 1233 0 0 texticregexeq eqsel eqjoinsel ));
DATA(insert OID = 1229 ( "!~*" PGUID 0 b t f 25 25 16 0 1228 0 0 texticregexne icregexnesel icregexnejoinsel ));
DATA(insert OID = 1232 ( "~*" PGUID 0 b t f 1043 25 16 0 1233 0 0 texticregexeq icregexeqsel icregexeqjoinsel ));
#define OID_VARCHAR_ICREGEXEQ_OP 1232
DATA(insert OID = 1233 ( "!~*" PGUID 0 b t f 1043 25 16 0 1232 0 0 texticregexne neqsel neqjoinsel ));
DATA(insert OID = 1234 ( "~*" PGUID 0 b t f 1042 25 16 0 1235 0 0 texticregexeq eqsel eqjoinsel ));
DATA(insert OID = 1233 ( "!~*" PGUID 0 b t f 1043 25 16 0 1232 0 0 texticregexne icregexnesel icregexnejoinsel ));
DATA(insert OID = 1234 ( "~*" PGUID 0 b t f 1042 25 16 0 1235 0 0 texticregexeq icregexeqsel icregexeqjoinsel ));
#define OID_BPCHAR_ICREGEXEQ_OP 1234
DATA(insert OID = 1235 ( "!~*" PGUID 0 b t f 1042 25 16 0 1234 0 0 texticregexne neqsel neqjoinsel ));
DATA(insert OID = 1235 ( "!~*" PGUID 0 b t f 1042 25 16 0 1234 0 0 texticregexne icregexnesel icregexnejoinsel ));
/* timestamp operators */
/* name, owner, prec, kind, isleft, canhash, left, right, result, com, negate, lsortop, rsortop, oprcode, operrest, oprjoin */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_proc.h,v 1.147 2000/07/14 22:17:56 tgl Exp $
* $Id: pg_proc.h,v 1.148 2000/07/17 03:05:25 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -433,8 +433,8 @@ DATA(insert OID = 206 ( float4um PGUID 11 f t t t 1 f 700 "700" 100 0 0 100
DESCR("negate");
DATA(insert OID = 207 ( float4abs PGUID 11 f t t t 1 f 700 "700" 100 0 0 100 float4abs - ));
DESCR("absolute value");
DATA(insert OID = 208 ( float4inc PGUID 11 f t t t 1 f 700 "700" 100 0 0 100 float4inc - ));
DESCR("increment");
DATA(insert OID = 208 ( float4_accum PGUID 12 f t t t 2 f 1022 "1022 700" 100 0 0 100 float4_accum - ));
DESCR("aggregate transition function");
DATA(insert OID = 209 ( float4larger PGUID 11 f t t t 2 f 700 "700 700" 100 0 0 100 float4larger - ));
DESCR("larger of two");
DATA(insert OID = 211 ( float4smaller PGUID 11 f t t t 2 f 700 "700 700" 100 0 0 100 float4smaller - ));
@ -461,8 +461,8 @@ DATA(insert OID = 220 ( float8um PGUID 11 f t t t 1 f 701 "701" 100 0 0 100
DESCR("negate");
DATA(insert OID = 221 ( float8abs PGUID 11 f t t t 1 f 701 "701" 100 0 0 100 float8abs - ));
DESCR("absolute value");
DATA(insert OID = 222 ( float8inc PGUID 11 f t t t 1 f 701 "701" 100 0 0 100 float8inc - ));
DESCR("increment");
DATA(insert OID = 222 ( float8_accum PGUID 12 f t t t 2 f 1022 "1022 701" 100 0 0 100 float8_accum - ));
DESCR("aggregate transition function");
DATA(insert OID = 223 ( float8larger PGUID 11 f t t t 2 f 701 "701 701" 100 0 0 100 float8larger - ));
DESCR("larger of two");
DATA(insert OID = 224 ( float8smaller PGUID 11 f t t t 2 f 701 "701 701" 100 0 0 100 float8smaller - ));
@ -1004,8 +1004,6 @@ DESCR("large object export");
DATA(insert OID = 766 ( int4inc PGUID 12 f t t t 1 f 23 "23" 100 0 0 100 int4inc - ));
DESCR("increment");
DATA(insert OID = 767 ( int2inc PGUID 12 f t t t 1 f 21 "21" 100 0 0 100 int2inc - ));
DESCR("increment");
DATA(insert OID = 768 ( int4larger PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100 int4larger - ));
DESCR("larger of two");
DATA(insert OID = 769 ( int4smaller PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100 int4smaller - ));
@ -1181,8 +1179,6 @@ DATA(insert OID = 944 ( char PGUID 12 f t t t 1 f 18 "25" 100 0 0 100 tex
DESCR("convert text to char");
DATA(insert OID = 946 ( text PGUID 12 f t t t 1 f 25 "18" 100 0 0 100 char_text - ));
DESCR("convert char to text");
DATA(insert OID = 948 ( varchar PGUID 12 f t t t 1 f 25 "1043" 100 0 0 100 bpchar_char - ));
DESCR("convert varchar() to text");
DATA(insert OID = 950 ( istrue PGUID 12 f t t f 1 f 16 "16" 100 0 0 100 istrue - ));
DESCR("bool is true (not false or unknown)");
@ -2395,8 +2391,6 @@ DATA(insert OID = 1746 ( float8 PGUID 11 f t t t 1 f 701 "1700" 100 0 0 100
DESCR("(internal)");
DATA(insert OID = 1764 ( numeric_inc PGUID 11 f t t t 1 f 1700 "1700" 100 0 0 100 numeric_inc - ));
DESCR("increment by one");
DATA(insert OID = 1765 ( numeric_dec PGUID 11 f t t t 1 f 1700 "1700" 100 0 0 100 numeric_dec - ));
DESCR("decrement by one");
DATA(insert OID = 1766 ( numeric_smaller PGUID 11 f t t t 2 f 1700 "1700 1700" 100 0 0 100 numeric_smaller - ));
DESCR("smaller of two numbers");
DATA(insert OID = 1767 ( numeric_larger PGUID 11 f t t t 2 f 1700 "1700 1700" 100 0 0 100 numeric_larger - ));
@ -2407,7 +2401,7 @@ DATA(insert OID = 1771 ( numeric_uminus PGUID 11 f t t t 1 f 1700 "1700" 100 0
DESCR("negate");
DATA(insert OID = 1779 ( int8 PGUID 11 f t t t 1 f 20 "1700" 100 0 0 100 numeric_int8 - ));
DESCR("(internal)");
DATA(insert OID = 1781 ( numeric PGUID 11 f t t t 1 f 1700 "20" 100 0 0 100 int8_numeric - ));
DATA(insert OID = 1781 ( numeric PGUID 12 f t t t 1 f 1700 "20" 100 0 0 100 int8_numeric - ));
DESCR("(internal)");
DATA(insert OID = 1782 ( numeric PGUID 12 f t t t 1 f 1700 "21" 100 0 0 100 int2_numeric - ));
DESCR("(internal)");
@ -2465,6 +2459,38 @@ DESCR("join selectivity of NOT LIKE");
DATA(insert OID = 1829 ( icregexnejoinsel PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100 icregexnejoinsel - ));
DESCR("join selectivity of case-insensitive regex non-match");
/* Aggregate-related functions */
DATA(insert OID = 1830 ( float8_avg PGUID 12 f t t t 1 f 701 "1022" 100 0 0 100 float8_avg - ));
DESCR("AVG aggregate final function");
DATA(insert OID = 1831 ( float8_variance PGUID 12 f t t t 1 f 701 "1022" 100 0 0 100 float8_variance - ));
DESCR("VARIANCE aggregate final function");
DATA(insert OID = 1832 ( float8_stddev PGUID 12 f t t t 1 f 701 "1022" 100 0 0 100 float8_stddev - ));
DESCR("STDDEV aggregate final function");
DATA(insert OID = 1833 ( numeric_accum PGUID 12 f t t t 2 f 1231 "1231 1700" 100 0 0 100 numeric_accum - ));
DESCR("aggregate transition function");
DATA(insert OID = 1834 ( int2_accum PGUID 12 f t t t 2 f 1231 "1231 21" 100 0 0 100 int2_accum - ));
DESCR("aggregate transition function");
DATA(insert OID = 1835 ( int4_accum PGUID 12 f t t t 2 f 1231 "1231 23" 100 0 0 100 int4_accum - ));
DESCR("aggregate transition function");
DATA(insert OID = 1836 ( int8_accum PGUID 12 f t t t 2 f 1231 "1231 20" 100 0 0 100 int8_accum - ));
DESCR("aggregate transition function");
DATA(insert OID = 1837 ( numeric_avg PGUID 12 f t t t 1 f 1700 "1231" 100 0 0 100 numeric_avg - ));
DESCR("AVG aggregate final function");
DATA(insert OID = 1838 ( numeric_variance PGUID 12 f t t t 1 f 1700 "1231" 100 0 0 100 numeric_variance - ));
DESCR("VARIANCE aggregate final function");
DATA(insert OID = 1839 ( numeric_stddev PGUID 12 f t t t 1 f 1700 "1231" 100 0 0 100 numeric_stddev - ));
DESCR("STDDEV aggregate final function");
DATA(insert OID = 1840 ( int2_sum PGUID 12 f t t f 2 f 1700 "1700 21" 100 0 0 100 int2_sum - ));
DESCR("SUM(int2) transition function");
DATA(insert OID = 1841 ( int4_sum PGUID 12 f t t f 2 f 1700 "1700 23" 100 0 0 100 int4_sum - ));
DESCR("SUM(int4) transition function");
DATA(insert OID = 1842 ( int8_sum PGUID 12 f t t f 2 f 1700 "1700 20" 100 0 0 100 int8_sum - ));
DESCR("SUM(int8) transition function");
DATA(insert OID = 1843 ( interval_accum PGUID 12 f t t t 2 f 1187 "1187 1186" 100 0 0 100 interval_accum - ));
DESCR("aggregate transition function");
DATA(insert OID = 1844 ( interval_avg PGUID 12 f t t t 1 f 1186 "1187" 100 0 0 100 interval_avg - ));
DESCR("AVG aggregate final function");
/*
* prototypes for functions pg_proc.c

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: primnodes.h,v 1.43 2000/06/12 19:40:49 momjian Exp $
* $Id: primnodes.h,v 1.44 2000/07/17 03:05:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -301,10 +301,9 @@ typedef struct Iter
* basetype - base type Oid of the aggregate (ie, input type)
* aggtype - type Oid of final result of the aggregate
* target - attribute or expression we are aggregating on
* usenulls - TRUE to accept null values as inputs
* aggstar - TRUE if argument was really '*'
* aggdistinct - TRUE if arguments were labeled DISTINCT
* aggno - workspace for nodeAgg.c executor
* aggdistinct - TRUE if it's agg(DISTINCT ...)
* aggno - workspace for executor (see nodeAgg.c)
* ----------------
*/
typedef struct Aggref
@ -314,7 +313,6 @@ typedef struct Aggref
Oid basetype;
Oid aggtype;
Node *target;
bool usenulls;
bool aggstar;
bool aggdistinct;
int aggno;

View File

@ -7,18 +7,16 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: lock.h,v 1.38 2000/05/31 00:28:38 petere Exp $
* $Id: lock.h,v 1.39 2000/07/17 03:05:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LOCK_H_
#define LOCK_H_
#include "postgres.h"
#include "storage/ipc.h"
#include "storage/itemptr.h"
#include "storage/shmem.h"
#include "utils/array.h"
extern SPINLOCK LockMgrLock;
typedef int LOCKMASK;

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: array.h,v 1.25 2000/06/13 07:35:30 tgl Exp $
* $Id: array.h,v 1.26 2000/07/17 03:05:32 tgl Exp $
*
* NOTES
* XXX the data array should be MAXALIGN'd -- notice that the array
@ -24,15 +24,27 @@
#define ARRAY_H
#include "fmgr.h"
#include "utils/memutils.h"
/*
* Arrays are varlena objects, so must meet the varlena convention that
* the first int32 of the object contains the total object size in bytes.
*/
typedef struct
{
int size; /* total array size (in bytes) */
int32 size; /* total array size (varlena requirement) */
int ndim; /* # of dimensions */
int flags; /* implementation flags */
} ArrayType;
/*
* fmgr macros for array objects
*/
#define DatumGetArrayTypeP(X) ((ArrayType *) PG_DETOAST_DATUM(X))
#define DatumGetArrayTypePCopy(X) ((ArrayType *) PG_DETOAST_DATUM_COPY(X))
#define PG_GETARG_ARRAYTYPE_P(n) DatumGetArrayTypeP(PG_GETARG_DATUM(n))
#define PG_GETARG_ARRAYTYPE_P_COPY(n) DatumGetArrayTypePCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_ARRAYTYPE_P(x) PG_RETURN_POINTER(x)
/*
* bitmask of ArrayType flags field:
* 1st bit - large object flag
@ -43,11 +55,9 @@ typedef struct
#define ARR_CHK_FLAG (0x2)
#define ARR_OBJ_MASK (0x1c)
#define ARR_FLAGS(a) ((ArrayType *) a)->flags
#define ARR_SIZE(a) (((ArrayType *) a)->size)
#define ARR_NDIM(a) (((ArrayType *) a)->ndim)
#define ARR_NDIM_PTR(a) (&(((ArrayType *) a)->ndim))
#define ARR_FLAGS(a) (((ArrayType *) a)->flags)
#define ARR_IS_LO(a) \
(((ArrayType *) a)->flags & ARR_LOB_FLAG)
@ -102,7 +112,6 @@ typedef struct
#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
#define NAME_LEN 30
#define MAX_BUFF_SIZE BLCKSZ
typedef struct
{
@ -134,6 +143,12 @@ extern ArrayType *array_assgn(ArrayType *array, int nSubscripts,
bool elmbyval, int elmlen, bool *isNull);
extern Datum array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType);
extern ArrayType *construct_array(Datum *elems, int nelems,
bool elmbyval, int elmlen, char elmalign);
extern void deconstruct_array(ArrayType *array,
bool elmbyval, int elmlen, char elmalign,
Datum **elemsp, int *nelemsp);
extern int _LOtransfer(char **destfd, int size, int nitems, char **srcfd,
int isSrcLO, int isDestLO);
extern char *_array_newLO(int *fd, int flag);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: builtins.h,v 1.123 2000/07/09 21:30:21 petere Exp $
* $Id: builtins.h,v 1.124 2000/07/17 03:05:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -110,7 +110,6 @@ extern Datum int2mi(PG_FUNCTION_ARGS);
extern Datum int2mul(PG_FUNCTION_ARGS);
extern Datum int2div(PG_FUNCTION_ARGS);
extern Datum int2abs(PG_FUNCTION_ARGS);
extern Datum int2inc(PG_FUNCTION_ARGS);
extern Datum int24pl(PG_FUNCTION_ARGS);
extern Datum int24mi(PG_FUNCTION_ARGS);
extern Datum int24mul(PG_FUNCTION_ARGS);
@ -207,12 +206,10 @@ extern float32 float4pl(float32 arg1, float32 arg2);
extern float32 float4mi(float32 arg1, float32 arg2);
extern float32 float4mul(float32 arg1, float32 arg2);
extern float32 float4div(float32 arg1, float32 arg2);
extern float32 float4inc(float32 arg1);
extern float64 float8pl(float64 arg1, float64 arg2);
extern float64 float8mi(float64 arg1, float64 arg2);
extern float64 float8mul(float64 arg1, float64 arg2);
extern float64 float8div(float64 arg1, float64 arg2);
extern float64 float8inc(float64 arg1);
extern bool float4eq(float32 arg1, float32 arg2);
extern bool float4ne(float32 arg1, float32 arg2);
extern bool float4lt(float32 arg1, float32 arg2);
@ -261,6 +258,11 @@ extern float64 radians(float64 arg1);
extern float64 dtan(float64 arg1);
extern float64 drandom(void);
extern int32 setseed(float64 seed);
extern Datum float8_accum(PG_FUNCTION_ARGS);
extern Datum float4_accum(PG_FUNCTION_ARGS);
extern Datum float8_avg(PG_FUNCTION_ARGS);
extern Datum float8_variance(PG_FUNCTION_ARGS);
extern Datum float8_stddev(PG_FUNCTION_ARGS);
extern float64 float48pl(float32 arg1, float64 arg2);
extern float64 float48mi(float32 arg1, float64 arg2);
@ -545,7 +547,6 @@ extern Numeric numeric_mul(Numeric num1, Numeric num2);
extern Numeric numeric_div(Numeric num1, Numeric num2);
extern Numeric numeric_mod(Numeric num1, Numeric num2);
extern Numeric numeric_inc(Numeric num);
extern Numeric numeric_dec(Numeric num);
extern Numeric numeric_smaller(Numeric num1, Numeric num2);
extern Numeric numeric_larger(Numeric num1, Numeric num2);
extern Numeric numeric_sqrt(Numeric num);
@ -555,14 +556,24 @@ extern Numeric numeric_log(Numeric num1, Numeric num2);
extern Numeric numeric_power(Numeric num1, Numeric num2);
extern Datum int4_numeric(PG_FUNCTION_ARGS);
extern int32 numeric_int4(Numeric num);
extern Numeric int8_numeric(int64 *val);
extern Datum int8_numeric(PG_FUNCTION_ARGS);
extern int64 *numeric_int8(Numeric num);
extern Datum int2_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_int2(PG_FUNCTION_ARGS);
extern Numeric float4_numeric(float32 val);
extern float32 numeric_float4(Numeric num);
extern Numeric float8_numeric(float64 val);
extern float64 numeric_float8(Numeric num);
extern Numeric float4_numeric(float32 val);
extern float32 numeric_float4(Numeric num);
extern Datum numeric_accum(PG_FUNCTION_ARGS);
extern Datum int2_accum(PG_FUNCTION_ARGS);
extern Datum int4_accum(PG_FUNCTION_ARGS);
extern Datum int8_accum(PG_FUNCTION_ARGS);
extern Datum numeric_avg(PG_FUNCTION_ARGS);
extern Datum numeric_variance(PG_FUNCTION_ARGS);
extern Datum numeric_stddev(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
/* lztext.c */
extern lztext *lztextin(char *str);

View File

@ -5,7 +5,7 @@
*
* 1998 Jan Wieck
*
* $Header: /cvsroot/pgsql/src/include/utils/numeric.h,v 1.10 2000/06/13 07:35:31 tgl Exp $
* $Header: /cvsroot/pgsql/src/include/utils/numeric.h,v 1.11 2000/07/17 03:05:32 tgl Exp $
*
* ----------
*/
@ -55,7 +55,7 @@
* all leading and trailing zeroes (except there will be a trailing zero
* in the last byte, if the number of digits is odd). In particular,
* if the value is zero, there will be no digits at all! The weight is
* arbitrary in this case, but we normally set it to zero.
* arbitrary in that case, but we normally set it to zero.
* ----------
*/
typedef struct NumericData
@ -75,9 +75,11 @@ typedef NumericData *Numeric;
* fmgr interface macros
*/
#define DatumGetNumeric(X) ((Numeric) PG_DETOAST_DATUM(X))
#define NumericGetDatum(X) PointerGetDatum(X)
#define PG_GETARG_NUMERIC(n) DatumGetNumeric(PG_GETARG_DATUM(n))
#define PG_RETURN_NUMERIC(x) return NumericGetDatum(x)
#define DatumGetNumeric(X) ((Numeric) PG_DETOAST_DATUM(X))
#define DatumGetNumericCopy(X) ((Numeric) PG_DETOAST_DATUM_COPY(X))
#define NumericGetDatum(X) PointerGetDatum(X)
#define PG_GETARG_NUMERIC(n) DatumGetNumeric(PG_GETARG_DATUM(n))
#define PG_GETARG_NUMERIC_COPY(n) DatumGetNumericCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_NUMERIC(x) return NumericGetDatum(x)
#endif /* _PG_NUMERIC_H_ */

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: timestamp.h,v 1.8 2000/06/19 03:54:48 tgl Exp $
* $Id: timestamp.h,v 1.9 2000/07/17 03:05:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -171,6 +171,8 @@ extern Datum interval_mi(PG_FUNCTION_ARGS);
extern Datum interval_mul(PG_FUNCTION_ARGS);
extern Datum mul_d_interval(PG_FUNCTION_ARGS);
extern Datum interval_div(PG_FUNCTION_ARGS);
extern Datum interval_accum(PG_FUNCTION_ARGS);
extern Datum interval_avg(PG_FUNCTION_ARGS);
extern Datum timestamp_mi(PG_FUNCTION_ARGS);
extern Datum timestamp_pl_span(PG_FUNCTION_ARGS);

View File

@ -386,28 +386,33 @@ create function tcl_int4add(int4,int4) returns int4 as '
return [expr $1 + $2]
' language 'pltcl';
create function tcl_int4div(int4,int4) returns int4 as '
return [expr $1 / $2]
-- We use split(n) as a quick-and-dirty way of parsing the input array
-- value, which comes in as a string like '{1,2}'. There are better ways...
create function tcl_int4_accum(_int4,int4) returns _int4 as '
set state [split $1 "{,}"]
set newsum [expr {[lindex $state 1] + $2}]
set newcnt [expr {[lindex $state 2] + 1}]
return "{$newsum,$newcnt}"
' language 'pltcl';
create function tcl_int4inc(int4) returns int4 as '
return [expr $1 + 1]
create function tcl_int4_avg(_int4) returns int4 as '
set state [split $1 "{,}"]
return [expr {[lindex $state 1] / [lindex $state 2]}]
' language 'pltcl';
create aggregate tcl_avg (
sfunc1 = tcl_int4add,
sfunc = tcl_int4_accum,
basetype = int4,
stype1 = int4,
sfunc2 = tcl_int4inc,
stype2 = int4,
finalfunc = tcl_int4div,
initcond2 = '0'
stype = _int4,
finalfunc = tcl_int4_avg,
initcond = '{0,0}'
);
create aggregate tcl_sum (
sfunc1 = tcl_int4add,
sfunc = tcl_int4add,
basetype = int4,
stype1 = int4,
stype = int4,
initcond1 = '0'
);

View File

@ -2,18 +2,20 @@
-- AGGREGATES
--
SELECT avg(four) AS avg_1 FROM onek;
avg_1
-------
1
avg_1
--------------
1.5000000000
(1 row)
SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
avg_32
--------
32
avg_32
---------------
32.6666666667
(1 row)
SELECT avg(b) AS avg_107_943 FROM aggtest;
-- In 7.1, avg(float4) is computed using float8 arithmetic.
-- Round the result to 3 digits to avoid platform-specific results.
SELECT avg(b)::numeric(10,3) AS avg_107_943 FROM aggtest;
avg_107_943
-------------
107.943
@ -116,9 +118,9 @@ select ten, count(four), sum(DISTINCT four) from onek group by ten;
(10 rows)
SELECT newavg(four) AS avg_1 FROM onek;
avg_1
-------
1
avg_1
--------------
1.5000000000
(1 row)
SELECT newsum(four) AS sum_1500 FROM onek;

View File

@ -3,18 +3,17 @@
--
-- all functions CREATEd
CREATE AGGREGATE newavg (
sfunc1 = int4pl, basetype = int4, stype1 = int4,
sfunc2 = int4inc, stype2 = int4,
finalfunc = int4div,
initcond1 = '0', initcond2 = '0'
sfunc = int4_accum, basetype = int4, stype = _numeric,
finalfunc = numeric_avg,
initcond1 = '{0,0,0}'
);
-- sfunc1 (value-dependent) only
-- without finalfunc; test obsolete spellings 'sfunc1' etc
CREATE AGGREGATE newsum (
sfunc1 = int4pl, basetype = int4, stype1 = int4,
initcond1 = '0'
);
-- sfunc2 (value-independent) only
-- value-independent transition function
CREATE AGGREGATE newcnt (
sfunc2 = int4inc, basetype = int4, stype2 = int4,
initcond2 = '0'
sfunc = int4inc, basetype = 'any', stype = int4,
initcond = '0'
);

View File

@ -99,46 +99,18 @@ end;
NOTICE: COMMIT: no transaction in progress
--
-- DEFINE AGGREGATE
-- left out finalfunc
create aggregate newavg1 (sfunc1 = int4pl,
basetype = int4,
stype1 = int4,
sfunc2 = int4inc,
stype2 = int4,
initcond1 = '0',
initcond2 = '0');
ERROR: AggregateCreate: Aggregate must have final function with both transition functions
-- sfunc return type disagreement
create aggregate newavg2 (sfunc1 = int4pl,
basetype = int4,
stype1 = int4,
sfunc2 = int2inc,
stype2 = int2,
finalfunc = int4div,
initcond1 = '0',
initcond2 = '0');
ERROR: AggregateCreate: 'int4div'('int4','int2') does not exist
-- sfunc/finalfunc type disagreement
create aggregate newavg3 (sfunc1 = int4pl,
create aggregate newavg2 (sfunc = int4pl,
basetype = int4,
stype1 = int4,
sfunc2 = int4inc,
stype2 = int4,
finalfunc = int2div,
initcond1 = '0',
initcond2 = '0');
ERROR: AggregateCreate: 'int2div'('int4','int4') does not exist
stype = int4,
finalfunc = int2um,
initcond = '0');
ERROR: AggregateCreate: function 'int2um(int4)' does not exist
-- left out basetype
create aggregate newcnt1 (sfunc2 = int4inc,
stype2 = int4,
initcond2 = '0');
create aggregate newcnt1 (sfunc = int4inc,
stype = int4,
initcond = '0');
ERROR: Define: "basetype" unspecified
-- left out initcond2 (for sfunc2)
create aggregate newcnt1 (sfunc2 = int4inc,
basetype = int4,
stype2 = int4);
ERROR: AggregateCreate: transition function 2 MUST have an initial value
--
-- REMOVE INDEX

View File

@ -1,20 +1,12 @@
--
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
--
SELECT oid, pg_aggregate.aggtransfn1
SELECT oid, pg_aggregate.aggtransfn
FROM pg_aggregate
WHERE pg_aggregate.aggtransfn1 != 0 AND
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn1);
oid | aggtransfn1
-----+-------------
(0 rows)
SELECT oid, pg_aggregate.aggtransfn2
FROM pg_aggregate
WHERE pg_aggregate.aggtransfn2 != 0 AND
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn2);
oid | aggtransfn2
-----+-------------
WHERE pg_aggregate.aggtransfn != 0 AND
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn);
oid | aggtransfn
-----+------------
(0 rows)
SELECT oid, pg_aggregate.aggfinalfn
@ -33,20 +25,12 @@ WHERE pg_aggregate.aggbasetype != 0 AND
-----+-------------
(0 rows)
SELECT oid, pg_aggregate.aggtranstype1
SELECT oid, pg_aggregate.aggtranstype
FROM pg_aggregate
WHERE pg_aggregate.aggtranstype1 != 0 AND
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype1);
oid | aggtranstype1
-----+---------------
(0 rows)
SELECT oid, pg_aggregate.aggtranstype2
FROM pg_aggregate
WHERE pg_aggregate.aggtranstype2 != 0 AND
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype2);
oid | aggtranstype2
-----+---------------
WHERE pg_aggregate.aggtranstype != 0 AND
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype);
oid | aggtranstype
-----+--------------
(0 rows)
SELECT oid, pg_aggregate.aggfinaltype
@ -217,6 +201,22 @@ WHERE pg_class.relam != 0 AND
-----+-------
(0 rows)
SELECT oid, pg_class.reltoastrelid
FROM pg_class
WHERE pg_class.reltoastrelid != 0 AND
NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastrelid);
oid | reltoastrelid
-----+---------------
(0 rows)
SELECT oid, pg_class.reltoastidxid
FROM pg_class
WHERE pg_class.reltoastidxid != 0 AND
NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastidxid);
oid | reltoastidxid
-----+---------------
(0 rows)
SELECT oid, pg_index.indexrelid
FROM pg_index
WHERE pg_index.indexrelid != 0 AND

View File

@ -84,9 +84,8 @@ WHERE p1.oid != p2.oid AND
(p1.prorettype < p2.prorettype);
prorettype | prorettype
------------+------------
18 | 25
25 | 1043
(2 rows)
(1 row)
SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
FROM pg_proc AS p1, pg_proc AS p2
@ -98,8 +97,7 @@ WHERE p1.oid != p2.oid AND
proargtypes | proargtypes
-------------+-------------
25 | 1043
1042 | 1043
(2 rows)
(1 row)
SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
FROM pg_proc AS p1, pg_proc AS p2
@ -434,83 +432,40 @@ WHERE p1.oprjoin = p2.oid AND
-- **************** pg_aggregate ****************
-- Look for illegal values in pg_aggregate fields.
-- aggbasetype can only be 0 if transfn1 is not present (eg, count(*))
-- or itself takes a wild-card input; we check the latter case below.
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE (p1.aggbasetype = 0 AND p1.aggtransfn1 != 0) OR aggfinaltype = 0;
WHERE aggtransfn = 0 OR aggtranstype = 0 OR aggfinaltype = 0;
oid | aggname
-----+---------
(0 rows)
-- Check combinations of transfer functions.
-- Although either transfn1 or transfn2 can be null,
-- it makes no sense for both to be. And if both are defined,
-- presumably there should be a finalfn to combine their results.
-- We also check that transtypes are null just when corresponding
-- transfns are. Also, if there is no finalfn then the output type
-- must be the transtype the result will be taken from.
-- If there is no finalfn then the output type must be the transtype.
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 = 0;
WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
oid | aggname
-----+---------
(0 rows)
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 = 0 AND
(p1.aggtranstype1 = 0 OR p1.aggtranstype2 != 0 OR
(p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype1));
oid | aggname
-----+---------
(0 rows)
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 != 0 AND
(p1.aggtranstype1 != 0 OR p1.aggtranstype2 = 0 OR
(p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype2));
oid | aggname
-----+---------
(0 rows)
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 != 0 AND
(p1.aggtranstype1 = 0 OR p1.aggtranstype2 = 0 OR
p1.aggfinalfn = 0);
oid | aggname
-----+---------
(0 rows)
-- Cross-check transfn1 (if present) against its entry in pg_proc.
-- Cross-check transfn against its entry in pg_proc.
-- FIXME: what about binary-compatible types?
-- NOTE: in 7.1, this search finds max and min on abstime, which are
-- implemented using int4larger/int4smaller. Until we have
-- some cleaner way of dealing with binary-equivalent types, just leave
-- those two tuples in the expected output.
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
FROM pg_aggregate AS p1, pg_proc AS p2
WHERE p1.aggtransfn1 = p2.oid AND
(p2.proretset OR p2.pronargs != 2
-- diked out until we find a way of marking binary-compatible types
-- OR
-- p1.aggtranstype1 != p2.prorettype OR
-- p1.aggtranstype1 != p2.proargtypes[0] OR
-- p1.aggbasetype != p2.proargtypes[1]
);
oid | aggname | oid | proname
-----+---------+-----+---------
(0 rows)
-- Cross-check transfn2 (if present) against its entry in pg_proc.
-- FIXME: what about binary-compatible types?
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
FROM pg_aggregate AS p1, pg_proc AS p2
WHERE p1.aggtransfn2 = p2.oid AND
(p2.proretset OR p1.aggtranstype2 != p2.prorettype OR
p2.pronargs != 1 OR
p1.aggtranstype2 != p2.proargtypes[0]);
oid | aggname | oid | proname
-----+---------+-----+---------
(0 rows)
WHERE p1.aggtransfn = p2.oid AND
(p2.proretset OR
p1.aggtranstype != p2.prorettype OR
p1.aggtranstype != p2.proargtypes[0] OR
NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
(p2.pronargs = 1 AND p1.aggbasetype = 0)));
oid | aggname | oid | proname
-------+---------+-----+-------------
16978 | max | 768 | int4larger
16992 | min | 769 | int4smaller
(2 rows)
-- Cross-check finalfn (if present) against its entry in pg_proc.
-- FIXME: what about binary-compatible types?
@ -518,9 +473,8 @@ SELECT p1.oid, p1.aggname, p2.oid, p2.proname
FROM pg_aggregate AS p1, pg_proc AS p2
WHERE p1.aggfinalfn = p2.oid AND
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
p2.pronargs != 2 OR
p1.aggtranstype1 != p2.proargtypes[0] OR
p1.aggtranstype2 != p2.proargtypes[1]);
p2.pronargs != 1 OR
p1.aggtranstype != p2.proargtypes[0]);
oid | aggname | oid | proname
-----+---------+-----+---------
(0 rows)

View File

@ -6,7 +6,10 @@ SELECT avg(four) AS avg_1 FROM onek;
SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
SELECT avg(b) AS avg_107_943 FROM aggtest;
-- In 7.1, avg(float4) is computed using float8 arithmetic.
-- Round the result to 3 digits to avoid platform-specific results.
SELECT avg(b)::numeric(10,3) AS avg_107_943 FROM aggtest;
SELECT avg(gpa) AS avg_3_4 FROM ONLY student;

View File

@ -4,21 +4,20 @@
-- all functions CREATEd
CREATE AGGREGATE newavg (
sfunc1 = int4pl, basetype = int4, stype1 = int4,
sfunc2 = int4inc, stype2 = int4,
finalfunc = int4div,
initcond1 = '0', initcond2 = '0'
sfunc = int4_accum, basetype = int4, stype = _numeric,
finalfunc = numeric_avg,
initcond1 = '{0,0,0}'
);
-- sfunc1 (value-dependent) only
-- without finalfunc; test obsolete spellings 'sfunc1' etc
CREATE AGGREGATE newsum (
sfunc1 = int4pl, basetype = int4, stype1 = int4,
initcond1 = '0'
);
-- sfunc2 (value-independent) only
-- value-independent transition function
CREATE AGGREGATE newcnt (
sfunc2 = int4inc, basetype = int4, stype2 = int4,
initcond2 = '0'
sfunc = int4inc, basetype = 'any', stype = int4,
initcond = '0'
);

View File

@ -114,45 +114,18 @@ end;
--
-- DEFINE AGGREGATE
-- left out finalfunc
create aggregate newavg1 (sfunc1 = int4pl,
basetype = int4,
stype1 = int4,
sfunc2 = int4inc,
stype2 = int4,
initcond1 = '0',
initcond2 = '0');
-- sfunc return type disagreement
create aggregate newavg2 (sfunc1 = int4pl,
basetype = int4,
stype1 = int4,
sfunc2 = int2inc,
stype2 = int2,
finalfunc = int4div,
initcond1 = '0',
initcond2 = '0');
-- sfunc/finalfunc type disagreement
create aggregate newavg3 (sfunc1 = int4pl,
create aggregate newavg2 (sfunc = int4pl,
basetype = int4,
stype1 = int4,
sfunc2 = int4inc,
stype2 = int4,
finalfunc = int2div,
initcond1 = '0',
initcond2 = '0');
stype = int4,
finalfunc = int2um,
initcond = '0');
-- left out basetype
create aggregate newcnt1 (sfunc2 = int4inc,
stype2 = int4,
initcond2 = '0');
-- left out initcond2 (for sfunc2)
create aggregate newcnt1 (sfunc2 = int4inc,
basetype = int4,
stype2 = int4);
create aggregate newcnt1 (sfunc = int4inc,
stype = int4,
initcond = '0');
--

View File

@ -1,14 +1,10 @@
--
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
--
SELECT oid, pg_aggregate.aggtransfn1
SELECT oid, pg_aggregate.aggtransfn
FROM pg_aggregate
WHERE pg_aggregate.aggtransfn1 != 0 AND
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn1);
SELECT oid, pg_aggregate.aggtransfn2
FROM pg_aggregate
WHERE pg_aggregate.aggtransfn2 != 0 AND
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn2);
WHERE pg_aggregate.aggtransfn != 0 AND
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn);
SELECT oid, pg_aggregate.aggfinalfn
FROM pg_aggregate
WHERE pg_aggregate.aggfinalfn != 0 AND
@ -17,14 +13,10 @@ SELECT oid, pg_aggregate.aggbasetype
FROM pg_aggregate
WHERE pg_aggregate.aggbasetype != 0 AND
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggbasetype);
SELECT oid, pg_aggregate.aggtranstype1
SELECT oid, pg_aggregate.aggtranstype
FROM pg_aggregate
WHERE pg_aggregate.aggtranstype1 != 0 AND
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype1);
SELECT oid, pg_aggregate.aggtranstype2
FROM pg_aggregate
WHERE pg_aggregate.aggtranstype2 != 0 AND
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype2);
WHERE pg_aggregate.aggtranstype != 0 AND
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype);
SELECT oid, pg_aggregate.aggfinaltype
FROM pg_aggregate
WHERE pg_aggregate.aggfinaltype != 0 AND
@ -109,6 +101,14 @@ SELECT oid, pg_class.relam
FROM pg_class
WHERE pg_class.relam != 0 AND
NOT EXISTS(SELECT * FROM pg_am AS t1 WHERE t1.oid = pg_class.relam);
SELECT oid, pg_class.reltoastrelid
FROM pg_class
WHERE pg_class.reltoastrelid != 0 AND
NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastrelid);
SELECT oid, pg_class.reltoastidxid
FROM pg_class
WHERE pg_class.reltoastidxid != 0 AND
NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastidxid);
SELECT oid, pg_index.indexrelid
FROM pg_index
WHERE pg_index.indexrelid != 0 AND

View File

@ -363,66 +363,32 @@ WHERE p1.oprjoin = p2.oid AND
-- **************** pg_aggregate ****************
-- Look for illegal values in pg_aggregate fields.
-- aggbasetype can only be 0 if transfn1 is not present (eg, count(*))
-- or itself takes a wild-card input; we check the latter case below.
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE (p1.aggbasetype = 0 AND p1.aggtransfn1 != 0) OR aggfinaltype = 0;
WHERE aggtransfn = 0 OR aggtranstype = 0 OR aggfinaltype = 0;
-- Check combinations of transfer functions.
-- Although either transfn1 or transfn2 can be null,
-- it makes no sense for both to be. And if both are defined,
-- presumably there should be a finalfn to combine their results.
-- We also check that transtypes are null just when corresponding
-- transfns are. Also, if there is no finalfn then the output type
-- must be the transtype the result will be taken from.
-- If there is no finalfn then the output type must be the transtype.
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 = 0;
WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 = 0 AND
(p1.aggtranstype1 = 0 OR p1.aggtranstype2 != 0 OR
(p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype1));
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 != 0 AND
(p1.aggtranstype1 != 0 OR p1.aggtranstype2 = 0 OR
(p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype2));
SELECT p1.oid, p1.aggname
FROM pg_aggregate as p1
WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 != 0 AND
(p1.aggtranstype1 = 0 OR p1.aggtranstype2 = 0 OR
p1.aggfinalfn = 0);
-- Cross-check transfn1 (if present) against its entry in pg_proc.
-- Cross-check transfn against its entry in pg_proc.
-- FIXME: what about binary-compatible types?
-- NOTE: in 7.1, this search finds max and min on abstime, which are
-- implemented using int4larger/int4smaller. Until we have
-- some cleaner way of dealing with binary-equivalent types, just leave
-- those two tuples in the expected output.
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
FROM pg_aggregate AS p1, pg_proc AS p2
WHERE p1.aggtransfn1 = p2.oid AND
(p2.proretset OR p2.pronargs != 2
-- diked out until we find a way of marking binary-compatible types
-- OR
-- p1.aggtranstype1 != p2.prorettype OR
-- p1.aggtranstype1 != p2.proargtypes[0] OR
-- p1.aggbasetype != p2.proargtypes[1]
);
-- Cross-check transfn2 (if present) against its entry in pg_proc.
-- FIXME: what about binary-compatible types?
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
FROM pg_aggregate AS p1, pg_proc AS p2
WHERE p1.aggtransfn2 = p2.oid AND
(p2.proretset OR p1.aggtranstype2 != p2.prorettype OR
p2.pronargs != 1 OR
p1.aggtranstype2 != p2.proargtypes[0]);
WHERE p1.aggtransfn = p2.oid AND
(p2.proretset OR
p1.aggtranstype != p2.prorettype OR
p1.aggtranstype != p2.proargtypes[0] OR
NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
(p2.pronargs = 1 AND p1.aggbasetype = 0)));
-- Cross-check finalfn (if present) against its entry in pg_proc.
-- FIXME: what about binary-compatible types?
@ -431,9 +397,8 @@ SELECT p1.oid, p1.aggname, p2.oid, p2.proname
FROM pg_aggregate AS p1, pg_proc AS p2
WHERE p1.aggfinalfn = p2.oid AND
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
p2.pronargs != 2 OR
p1.aggtranstype1 != p2.proargtypes[0] OR
p1.aggtranstype2 != p2.proargtypes[1]);
p2.pronargs != 1 OR
p1.aggtranstype != p2.proargtypes[0]);
-- **************** pg_opclass ****************

View File

@ -7,7 +7,7 @@
--
-- Copyright (c) 1994, Regents of the University of California
--
-- $Id: complex.source,v 1.7 2000/03/28 02:49:19 tgl Exp $
-- $Id: complex.source,v 1.8 2000/07/17 03:05:41 tgl Exp $
--
---------------------------------------------------------------------------
@ -111,10 +111,10 @@ SELECT a + '(1.0,1.0)'::complex AS aa,
-----------------------------
CREATE AGGREGATE complex_sum (
sfunc1 = complex_add,
sfunc = complex_add,
basetype = complex,
stype1 = complex,
initcond1 = '(0,0)'
stype = complex,
initcond = '(0,0)'
);
SELECT complex_sum(a) FROM test_complex;