-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.64 2001/07/11 22:14:01 momjian Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.65 2001/08/14 22:21:58 tgl Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
<row>
<entry>COUNT(*)</entry>
<entry>number of input values</entry>
- <entry>The return value is of type <type>integer</type>.</entry>
+ <entry>The return value is of type <type>bigint</type>.</entry>
</row>
<row>
Counts the input values for which the value of <replaceable
class="parameter">expression</replaceable> is not NULL.
</entry>
- <entry></entry>
+ <entry>The return value is of type <type>bigint</type>.</entry>
</row>
<row>
<type>smallint</type>, <type>integer</type>,
<type>bigint</type>, <type>real</type>, <type>double
precision</type>, <type>numeric</type>, <type>interval</type>.
- The result is of type <type>numeric</type> for any integer type
+ The result is of type <type>bigint</type> for <type>smallint</type>
+ or <type>integer</type> input, <type>numeric</type> for
+ <type>bigint</type>
input, <type>double precision</type> for floating point input,
otherwise the same as the input data type.
</entry>
<primary>variance</primary>
</indexterm>
The variance is the square of the standard deviation. The
- supported data types are the same.
+ supported data types and result types are the same as for
+ standard deviation.
</entry>
</row>
It should be noted that except for <function>COUNT</function>,
these functions return NULL when no rows are selected. In
particular, <function>SUM</function> of no rows returns NULL, not
- zero as one might expect.
+ zero as one might expect. <function>COALESCE</function> may be
+ used to substitute zero for NULL when necessary.
</para>
</sect1>
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.30 2001/06/07 00:09:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.31 2001/08/14 22:21:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PG_RETURN_INT64(result);
}
+Datum
+int8inc(PG_FUNCTION_ARGS)
+{
+ int64 arg = PG_GETARG_INT64(0);
+
+ PG_RETURN_INT64(arg + 1);
+}
+
Datum
int8larger(PG_FUNCTION_ARGS)
{
*
* 1998 Jan Wieck
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.42 2001/06/07 00:09:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.43 2001/08/14 22:21:58 tgl Exp $
*
* ----------
*/
/*
* Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow.
+ * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
+ * is overkill for the N and sum(X) values, but definitely not overkill
+ * for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
+ * for stddev/variance --- there are faster special-purpose accumulator
+ * routines for SUM and AVG of these datatypes.
*/
Datum
/*
* 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.
+ * To avoid overflow, we use accumulators wider than the input datatype.
+ * A Numeric accumulator is needed for int8 input; for int4 and int2
+ * inputs, we use int8 accumulators which should be sufficient for practical
+ * purposes. (The latter two therefore don't really belong in this file,
+ * but we keep them here anyway.)
+ *
+ * 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;
- Datum newval;
+ int64 oldsum;
+ int64 newval;
if (PG_ARGISNULL(0))
{
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
- newval = DirectFunctionCall1(int2_numeric, PG_GETARG_DATUM(1));
- PG_RETURN_DATUM(newval);
+ newval = (int64) PG_GETARG_INT16(1);
+ PG_RETURN_INT64(newval);
}
- oldsum = PG_GETARG_NUMERIC(0);
+ oldsum = PG_GETARG_INT64(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
- PG_RETURN_NUMERIC(oldsum);
+ PG_RETURN_INT64(oldsum);
/* OK to do the addition. */
- newval = DirectFunctionCall1(int2_numeric, PG_GETARG_DATUM(1));
+ newval = oldsum + (int64) PG_GETARG_INT16(1);
- PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
- NumericGetDatum(oldsum), newval));
+ PG_RETURN_INT64(newval);
}
Datum
int4_sum(PG_FUNCTION_ARGS)
{
- Numeric oldsum;
- Datum newval;
+ int64 oldsum;
+ int64 newval;
if (PG_ARGISNULL(0))
{
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
- newval = DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(1));
- PG_RETURN_DATUM(newval);
+ newval = (int64) PG_GETARG_INT32(1);
+ PG_RETURN_INT64(newval);
}
- oldsum = PG_GETARG_NUMERIC(0);
+ oldsum = PG_GETARG_INT64(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
- PG_RETURN_NUMERIC(oldsum);
+ PG_RETURN_INT64(oldsum);
/* OK to do the addition. */
- newval = DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(1));
+ newval = oldsum + (int64) PG_GETARG_INT32(1);
- PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
- NumericGetDatum(oldsum), newval));
+ PG_RETURN_INT64(newval);
}
Datum
}
+/*
+ * Routines for avg(int2) and avg(int4). The transition datatype
+ * is a two-element int8 array, holding count and sum.
+ */
+
+typedef struct Int8TransTypeData
+{
+#ifndef INT64_IS_BUSTED
+ int64 count;
+ int64 sum;
+#else
+ /* "int64" isn't really 64 bits, so fake up properly-aligned fields */
+ int32 count;
+ int32 pad1;
+ int32 sum;
+ int32 pad2;
+#endif
+} Int8TransTypeData;
+
+Datum
+int2_avg_accum(PG_FUNCTION_ARGS)
+{
+ ArrayType *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
+ int16 newval = PG_GETARG_INT16(1);
+ Int8TransTypeData *transdata;
+
+ /*
+ * We copied the input array, so it's okay to scribble on it directly.
+ */
+ if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
+ elog(ERROR, "int2_avg_accum: expected 2-element int8 array");
+ transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
+
+ transdata->count++;
+ transdata->sum += newval;
+
+ PG_RETURN_ARRAYTYPE_P(transarray);
+}
+
+Datum
+int4_avg_accum(PG_FUNCTION_ARGS)
+{
+ ArrayType *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
+ int32 newval = PG_GETARG_INT32(1);
+ Int8TransTypeData *transdata;
+
+ /*
+ * We copied the input array, so it's okay to scribble on it directly.
+ */
+ if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
+ elog(ERROR, "int4_avg_accum: expected 2-element int8 array");
+ transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
+
+ transdata->count++;
+ transdata->sum += newval;
+
+ PG_RETURN_ARRAYTYPE_P(transarray);
+}
+
+Datum
+int8_avg(PG_FUNCTION_ARGS)
+{
+ ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ Int8TransTypeData *transdata;
+ Datum countd,
+ sumd;
+
+ if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
+ elog(ERROR, "int8_avg: expected 2-element int8 array");
+ transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
+
+ /* SQL92 defines AVG of no values to be NULL */
+ if (transdata->count == 0)
+ PG_RETURN_NULL();
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(transdata->count));
+ sumd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(transdata->sum));
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+}
+
+
/* ----------------------------------------------------------------------
*
* Local functions follow
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/oid.c,v 1.45 2001/03/22 03:59:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/oid.c,v 1.46 2001/08/14 22:21:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PG_RETURN_BOOL(arg1 > arg2);
}
+Datum
+oidlarger(PG_FUNCTION_ARGS)
+{
+ Oid arg1 = PG_GETARG_OID(0);
+ Oid arg2 = PG_GETARG_OID(1);
+
+ PG_RETURN_OID((arg1 > arg2) ? arg1 : arg2);
+}
+
+Datum
+oidsmaller(PG_FUNCTION_ARGS)
+{
+ Oid arg1 = PG_GETARG_OID(0);
+ Oid arg2 = PG_GETARG_OID(1);
+
+ PG_RETURN_OID((arg1 < arg2) ? arg1 : arg2);
+}
+
Datum
oidvectoreq(PG_FUNCTION_ARGS)
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.53 2001/06/01 02:41:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.54 2001/08/14 22:21:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Datum
Int64GetDatum(int64 X)
{
+#ifndef INT64_IS_BUSTED
int64 *retval = (int64 *) palloc(sizeof(int64));
*retval = X;
return PointerGetDatum(retval);
+#else /* INT64_IS_BUSTED */
+ /*
+ * On a machine with no 64-bit-int C datatype, sizeof(int64) will not be
+ * 8, but we want Int64GetDatum to return an 8-byte object anyway, with
+ * zeroes in the unused bits. This is needed so that, for example,
+ * hash join of int8 will behave properly.
+ */
+ int64 *retval = (int64 *) palloc(Max(sizeof(int64), 8));
+
+ MemSet(retval, 0, Max(sizeof(int64), 8));
+ *retval = X;
+ return PointerGetDatum(retval);
+#endif /* INT64_IS_BUSTED */
}
Datum
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.88 2001/08/13 18:45:36 tgl Exp $
+ * $Id: catversion.h,v 1.89 2001/08/14 22:21:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200108131
+#define CATALOG_VERSION_NO 200108132
#endif
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_aggregate.h,v 1.30 2001/05/18 15:59:04 tgl Exp $
+ * $Id: pg_aggregate.h,v 1.31 2001/08/14 22:21:58 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
*/
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 int4_avg_accum int8_avg 23 1016 1700 "{0,0}" ));
+DATA(insert OID = 0 ( avg PGUID int2_avg_accum int8_avg 21 1016 1700 "{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 second,0 second}" ));
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 int4_sum - 23 20 20 _null_ ));
+DATA(insert OID = 0 ( sum PGUID int2_sum - 21 20 20 _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 ( 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 oidlarger - 26 26 26 _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 ( 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 oidsmaller - 26 26 26 _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 numeric_smaller - 1700 1700 1700 _null_ ));
/*
- * Using int4inc for count() is cheating a little, since it really only
+ * Using int8inc 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 ( count PGUID int8inc - 0 20 20 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}" ));
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_proc.h,v 1.203 2001/08/13 18:45:36 tgl Exp $
+ * $Id: pg_proc.h,v 1.204 2001/08/14 22:21:58 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DATA(insert OID = 1218 ( date_trunc PGUID 12 f t f t 2 f 1186 "25 1186" 100 0 0 100 interval_trunc - ));
DESCR("truncate interval to specified units");
+DATA(insert OID = 1219 ( int8inc PGUID 12 f t t t 1 f 20 "20" 100 0 0 100 int8inc - ));
+DESCR("increment");
DATA(insert OID = 1230 ( int8abs PGUID 12 f t t t 1 f 20 "20" 100 0 0 100 int8abs - ));
DESCR("absolute value");
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 - ));
+DATA(insert OID = 1840 ( int2_sum PGUID 12 f t t f 2 f 20 "20 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 - ));
+DATA(insert OID = 1841 ( int4_sum PGUID 12 f t t f 2 f 20 "20 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");
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");
+DATA(insert OID = 1962 ( int2_avg_accum PGUID 12 f t t t 2 f 1016 "1016 21" 100 0 0 100 int2_avg_accum - ));
+DESCR("AVG(int2) transition function");
+DATA(insert OID = 1963 ( int4_avg_accum PGUID 12 f t t t 2 f 1016 "1016 23" 100 0 0 100 int4_avg_accum - ));
+DESCR("AVG(int4) transition function");
+DATA(insert OID = 1964 ( int8_avg PGUID 12 f t t t 1 f 1700 "1016" 100 0 0 100 int8_avg - ));
+DESCR("AVG(int) aggregate final function");
/* To ASCII conversion */
DATA(insert OID = 1845 ( to_ascii PGUID 12 f t t t 1 f 25 "25" 100 0 0 100 to_ascii_default - ));
DATA(insert OID = 1954 ( byteacmp PGUID 12 f t t t 2 f 23 "17 17" 100 0 0 100 byteacmp - ));
DESCR("less-equal-greater");
+DATA(insert OID = 1965 ( oidlarger PGUID 12 f t t t 2 f 26 "26 26" 100 0 0 100 oidlarger - ));
+DESCR("larger of two");
+DATA(insert OID = 1966 ( oidsmaller PGUID 12 f t t t 2 f 26 "26 26" 100 0 0 100 oidsmaller - ));
+DESCR("smaller of two");
+
/*
* prototypes for functions pg_proc.c
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: builtins.h,v 1.160 2001/08/13 18:45:36 tgl Exp $
+ * $Id: builtins.h,v 1.161 2001/08/14 22:21:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum oidle(PG_FUNCTION_ARGS);
extern Datum oidge(PG_FUNCTION_ARGS);
extern Datum oidgt(PG_FUNCTION_ARGS);
+extern Datum oidlarger(PG_FUNCTION_ARGS);
+extern Datum oidsmaller(PG_FUNCTION_ARGS);
extern Datum oid_text(PG_FUNCTION_ARGS);
extern Datum text_oid(PG_FUNCTION_ARGS);
extern Datum oidvectorin(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
+extern Datum int2_avg_accum(PG_FUNCTION_ARGS);
+extern Datum int4_avg_accum(PG_FUNCTION_ARGS);
+extern Datum int8_avg(PG_FUNCTION_ARGS);
/* ri_triggers.c */
extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: int8.h,v 1.26 2001/06/07 00:09:32 momjian Exp $
+ * $Id: int8.h,v 1.27 2001/08/14 22:21:59 tgl Exp $
*
* NOTES
* These data types are supported on all 64-bit architectures, and may
extern Datum int8abs(PG_FUNCTION_ARGS);
extern Datum int8fac(PG_FUNCTION_ARGS);
extern Datum int8mod(PG_FUNCTION_ARGS);
+extern Datum int8inc(PG_FUNCTION_ARGS);
extern Datum int8larger(PG_FUNCTION_ARGS);
extern Datum int8smaller(PG_FUNCTION_ARGS);
(p2.pronargs = 1 AND p1.aggbasetype = 0)));
oid | aggname | oid | proname
-------+---------+-----+-------------
- 10020 | max | 768 | int4larger
- 10034 | min | 769 | int4smaller
+ 10021 | max | 768 | int4larger
+ 10036 | min | 769 | int4smaller
(2 rows)
-- Cross-check finalfn (if present) against its entry in pg_proc.
where X.a = Y.a
group by X.a, X.b;
create function rtest_viewfunc1(int4) returns int4 as
- 'select count(*) from rtest_view2 where a = $1'
+ 'select count(*)::int4 from rtest_view2 where a = $1'
language 'sql';
create view rtest_vview5 as select a, b, rtest_viewfunc1(a) as refcount
from rtest_view1;
where X.a = Y.a
group by X.a, X.b;
create function rtest_viewfunc1(int4) returns int4 as
- 'select count(*) from rtest_view2 where a = $1'
+ 'select count(*)::int4 from rtest_view2 where a = $1'
language 'sql';
create view rtest_vview5 as select a, b, rtest_viewfunc1(a) as refcount
from rtest_view1;