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

@ -1,6 +1,6 @@
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.6 2000/06/09 01:43:56 momjian Exp $
.\" $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.7 2000/07/17 03:04:40 tgl Exp $
.TH "SYSTEM CATALOGS" INTRO 03/13/94 PostgreSQL PostgreSQL
.SH "Section 7 - System Catalogs"
.de LS
@ -91,20 +91,16 @@ The following catalogs relate to the class/type system.
* see DEFINE AGGREGATE for an explanation of transition functions
*/
pg_aggregate
NameData aggname /* aggregate name (e.g., "count") */
NameData aggname /* aggregate name (e.g., "count") */
oid aggowner /* usesysid of creator */
regproc aggtransfn1 /* first transition function */
regproc aggtransfn2 /* second transition function */
regproc aggtransfn /* transition function */
regproc aggfinalfn /* final function */
oid aggbasetype /* type of data on which aggregate
operates */
oid aggtranstype1 /* type returned by aggtransfn1 */
oid aggtranstype2 /* type returned by aggtransfn2 */
oid aggfinaltype /* type returned by aggfinalfn */
text agginitval1 /* external format of initial
(starting) value of aggtransfn1 */
text agginitval2 /* external format of initial
(starting) value of aggtransfn2 */
oid aggtranstype /* type of aggregate's transition
(state) data */
oid aggfinaltype /* type of aggregate's final result */
text agginitval /* external format of initial state value */
.fi
.nf M
pg_am

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.9 2000/03/31 14:57:05 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.10 2000/07/17 03:04:41 tgl Exp $
Postgres documentation
-->
@ -21,20 +21,18 @@ Postgres documentation
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>1999-07-20</date>
<date>2000-07-16</date>
</refsynopsisdivinfo>
<synopsis>
CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE = <replaceable class="PARAMETER">input_data_type</replaceable>
[ , SFUNC1 = <replaceable class="PARAMETER">sfunc1</replaceable>, STYPE1 = <replaceable class="PARAMETER">state1_type</replaceable> ]
[ , SFUNC2 = <replaceable class="PARAMETER">sfunc2</replaceable>, STYPE2 = <replaceable class="PARAMETER">state2_type</replaceable> ]
CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE = <replaceable class="PARAMETER">input_data_type</replaceable>,
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>, STYPE = <replaceable class="PARAMETER">state_type</replaceable>
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , INITCOND1 = <replaceable class="PARAMETER">initial_condition1</replaceable> ]
[ , INITCOND2 = <replaceable class="PARAMETER">initial_condition2</replaceable> ] )
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ] )
</synopsis>
<refsect2 id="R2-SQL-CREATEAGGREGATE-1">
<refsect2info>
<date>1998-09-09</date>
<date>2000-07-16</date>
</refsect2info>
<title>
Inputs
@ -55,57 +53,39 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE =
<listitem>
<para>
The input data type on which this aggregate function operates.
This can be specified as ANY for an aggregate that does not
examine its input values
(an example is <function>count(*)</function>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">sfunc1</replaceable></term>
<term><replaceable class="PARAMETER">sfunc</replaceable></term>
<listitem>
<para>
A state transition function
to be called for every non-NULL input data value.
This must be a function of two arguments, the first being of
type <replaceable class="PARAMETER">state1_type</replaceable>
The name of the state transition function
to be called for each input data value.
This is normally a function of two arguments, the first being of
type <replaceable class="PARAMETER">state_type</replaceable>
and the second of
type <replaceable class="PARAMETER">input_data_type</replaceable>.
The function must return a value of
type <replaceable class="PARAMETER">state1_type</replaceable>.
This function takes the current state value 1 and the current
input data item, and returns the next state value 1.
Alternatively, for an aggregate that does not examine its input
values, the function takes just one argument of
type <replaceable class="PARAMETER">state_type</replaceable>.
In either case the function must return a value of
type <replaceable class="PARAMETER">state_type</replaceable>.
This function takes the current state value and the current
input data item, and returns the next state value.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">state1_type</replaceable></term>
<term><replaceable class="PARAMETER">state_type</replaceable></term>
<listitem>
<para>
The data type for the first state value of the aggregate.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">sfunc2</replaceable></term>
<listitem>
<para>
A state transition function
to be called for every non-NULL input data value.
This must be a function of one argument of
type <replaceable class="PARAMETER">state2_type</replaceable>,
returning a value of the same type.
This function takes the current state value 2 and
returns the next state value 2.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">state2_type</replaceable></term>
<listitem>
<para>
The data type for the second state value of the aggregate.
The data type for the aggregate's state value.
</para>
</listitem>
</varlistentry>
@ -114,35 +94,28 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE =
<term><replaceable class="PARAMETER">ffunc</replaceable></term>
<listitem>
<para>
The final function called to compute the aggregate's result
after all input data has been traversed.
If both state values are used, the final function must
take two arguments of types
<replaceable class="PARAMETER">state1_type</replaceable>
and
<replaceable class="PARAMETER">state2_type</replaceable>.
If only one state value is used, the final function must
take a single argument of that state value's type.
The name of the final function called to compute the aggregate's
result after all input data has been traversed. The function
must take a single argument of type
<replaceable class="PARAMETER">state_type</replaceable>.
The output datatype of the aggregate is defined as the return
type of this function.
If <replaceable class="PARAMETER">ffunc</replaceable>
is not specified, then the ending state value is used as the
aggregate's result, and the output type is
<replaceable class="PARAMETER">state_type</replaceable>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">initial_condition1</replaceable></term>
<term><replaceable class="PARAMETER">initial_condition</replaceable></term>
<listitem>
<para>
The initial value for state value 1.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">initial_condition2</replaceable></term>
<listitem>
<para>
The initial value for state value 2.
The initial setting for the state value. This must be a literal
constant in the form accepted for the datatype
<replaceable class="PARAMETER">state_type</replaceable>.
If not specified, the state value starts out NULL.
</para>
</listitem>
</varlistentry>
@ -177,7 +150,7 @@ CREATE
<refsect1 id="R1-SQL-CREATEAGGREGATE-1">
<refsect1info>
<date>1998-09-09</date>
<date>2000-07-16</date>
</refsect1info>
<title>
Description
@ -199,65 +172,76 @@ CREATE
of the same name and input data type as an aggregate.
</para>
<para>
An aggregate function is made from between one and three ordinary
An aggregate function is made from one or two ordinary
functions:
two state transition functions,
<replaceable class="PARAMETER">sfunc1</replaceable>
and <replaceable class="PARAMETER">sfunc2</replaceable>,
and a final calculation function,
a state transition function
<replaceable class="PARAMETER">sfunc</replaceable>,
and an optional final calculation function
<replaceable class="PARAMETER">ffunc</replaceable>.
These are used as follows:
<programlisting>
<replaceable class="PARAMETER">sfunc1</replaceable>( internal-state1, next-data-item ) ---> next-internal-state1
<replaceable class="PARAMETER">sfunc2</replaceable>( internal-state2 ) ---> next-internal-state2
<replaceable class="PARAMETER">ffunc</replaceable>(internal-state1, internal-state2) ---> aggregate-value
<replaceable class="PARAMETER">sfunc</replaceable>( internal-state, next-data-item ) ---> next-internal-state
<replaceable class="PARAMETER">ffunc</replaceable>( internal-state ) ---> aggregate-value
</programlisting>
</para>
<para>
<productname>Postgres</productname> creates one or two temporary variables
(of data types <replaceable class="PARAMETER">stype1</replaceable> and/or
<replaceable class="PARAMETER">stype2</replaceable>) to hold the
current internal states of the aggregate. At each input data item,
the state transition function(s) are invoked to calculate new values
for the internal state values. After all the data has been processed,
<productname>Postgres</productname> creates a temporary variable
of data type <replaceable class="PARAMETER">stype</replaceable>
to hold the current internal state of the aggregate. At each input
data item,
the state transition function is invoked to calculate a new
internal state value. After all the data has been processed,
the final function is invoked once to calculate the aggregate's output
value.
value. If there is no final function then the ending state value
is returned as-is.
</para>
<para>
<replaceable class="PARAMETER">ffunc</replaceable> must be specified if
both transition functions are specified. If only one transition function
is used, then <replaceable class="PARAMETER">ffunc</replaceable> is
optional. The default behavior when
<replaceable class="PARAMETER">ffunc</replaceable> is not provided is
to return the ending value of the internal state value being used
(and, therefore, the aggregate's output type is the same as that
state value's type).
</para>
<para>
An aggregate function may also provide one or two initial conditions,
that is, initial values for the internal state values being used.
These are specified and stored in the database as fields of type
<type>text</type>, but they must be valid external representations
of constants of the state value datatypes. If
<replaceable class="PARAMETER">sfunc1</replaceable> is specified
without an <replaceable class="PARAMETER">initcond1</replaceable> value,
then the system does not call
<replaceable class="PARAMETER">sfunc1</replaceable>
at the first input item; instead, the internal state value 1 is
initialized with the first input value, and
<replaceable class="PARAMETER">sfunc1</replaceable> is called beginning
at the second input item. This is useful for aggregates like MIN and
MAX. Note that an aggregate using this feature will return NULL when
called with no input values. There is no comparable provision for
state value 2; if <replaceable class="PARAMETER">sfunc2</replaceable> is
specified then an <replaceable class="PARAMETER">initcond2</replaceable> is
required.
<para>
An aggregate function may provide an initial condition,
that is, an initial value for the internal state value.
This is specified and stored in the database as a field of type
<type>text</type>, but it must be a valid external representation
of a constant of the state value datatype. If it is not supplied
then the state value starts out NULL.
</para>
<para>
If the state transition function is declared "strict" in pg_proc,
then it cannot be called with NULL inputs. With such a transition
function, aggregate execution behaves as follows. NULL input values
are ignored (the function is not called and the previous state value
is retained). If the initial state value is NULL, then the first
non-NULL input value replaces the state value, and the transition
function is invoked beginning with the second non-NULL input value.
This is handy for implementing aggregates like <function>max</function>.
Note that this behavior is only available when
<replaceable class="PARAMETER">state_type</replaceable>
is the same as
<replaceable class="PARAMETER">input_data_type</replaceable>.
When these types are different, you must supply a non-NULL initial
condition or use a non-strict transition function.
</para>
<para>
If the state transition function is not strict, then it will be called
unconditionally at each input value, and must deal with NULL inputs
and NULL transition values for itself. This allows the aggregate
author to have full control over the aggregate's handling of NULLs.
</para>
<para>
If the final function is declared "strict", then it will not
be called when the ending state value is NULL; instead a NULL result
will be output automatically. (Of course this is just the normal
behavior of strict functions.) In any case the final function has
the option of returning NULL. For example, the final function for
<function>avg</function> returns NULL when it sees there were zero
input tuples.
</para>
<refsect2 id="R2-SQL-CREATEAGGREGATE-3">
<refsect2info>
<date>1998-09-09</date>
<date>2000-07-16</date>
</refsect2info>
<title>
Notes
@ -272,29 +256,6 @@ CREATE
in any order, not just the order illustrated above.
</para>
<para>
It is possible to specify aggregate functions
that have varying combinations of state and final functions.
For example, the <function>count</function> aggregate requires
<replaceable class="PARAMETER">sfunc2</replaceable>
(an incrementing function) but not
<replaceable class="PARAMETER">sfunc1</replaceable> or
<replaceable class="PARAMETER">ffunc</replaceable>,
whereas the <function>sum</function> aggregate requires
<replaceable class="PARAMETER">sfunc1</replaceable> (an addition
function) but not <replaceable class="PARAMETER">sfunc2</replaceable> or
<replaceable class="PARAMETER">ffunc</replaceable>, and the
<function>avg</function>
aggregate requires
both state functions as
well as a <replaceable class="PARAMETER">ffunc</replaceable> (a division
function) to produce its
answer. In any case, at least one state function must be
defined, and any <replaceable class="PARAMETER">sfunc2</replaceable> must
have a corresponding
<replaceable class="PARAMETER">initcond2</replaceable>.
</para>
</refsect2>
</refsect1>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_aggregate.sgml,v 1.7 2000/05/18 14:24:32 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_aggregate.sgml,v 1.8 2000/07/17 03:04:41 tgl Exp $
Postgres documentation
-->
@ -49,7 +49,7 @@ DROP AGGREGATE <replaceable class="PARAMETER">name</replaceable> <replaceable cl
<para>
The type of an existing aggregate function.
(Refer to the <citetitle>PostgreSQL User's Guide</citetitle> for
further information about data types).
further information about data types.)
<comment>This should become a cross-reference rather than a
hard-coded chapter number</comment>
</para>
@ -80,7 +80,7 @@ DROP
</varlistentry>
<varlistentry>
<term><computeroutput>
NOTICE RemoveAggregate: aggregate '<replaceable class="parameter">agg</replaceable>' for '<replaceable class="parameter">type</replaceable>' does not exist
ERROR: RemoveAggregate: aggregate '<replaceable class="parameter">agg</replaceable>' for '<replaceable class="parameter">type</replaceable>' does not exist
</computeroutput></term>
<listitem>
<para>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.7 2000/03/31 03:27:41 thomas Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.8 2000/07/17 03:04:40 tgl Exp $
-->
<chapter id="xaggr">
@ -16,39 +16,20 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.7 2000/03/31 03:27:41 thomas
an initial value for the state, and a state transition
function. The state transition function is just an
ordinary function that could also be used outside the
context of the aggregate.
context of the aggregate. A <firstterm>final function</firstterm>
can also be specified, in case the desired output of the aggregate
is different from the data that needs to be kept in the running
state value.
</para>
<para>
Actually, in order to make it easier to construct useful
aggregates from existing functions, an aggregate can have
one or two separate state values, one or two transition
functions to update those state values, and a
<firstterm>final function</firstterm> that computes the
actual aggregate result from the ending state values.
Thus, in addition to the input and result datatypes seen by a user
of the aggregate, there is an internal state-value datatype that
may be different from both the input and result types.
</para>
<para>
Thus there can be as many as four datatypes involved:
the type of the input data items, the type of the aggregate's
result, and the types of the two state values. Only the
input and result datatypes are seen by a user of the aggregate.
</para>
<para>
Some state transition functions need to look at each successive
input to compute the next state value, while others ignore the
specific input value and simply update their internal state.
(The most useful example of the second kind is a running count
of the number of input items.) The <productname>Postgres</productname>
aggregate machinery defines <acronym>sfunc1</acronym> for
an aggregate as a function that is passed both the old state
value and the current input value, while <acronym>sfunc2</acronym>
is a function that is passed only the old state value.
</para>
<para>
If we define an aggregate that uses only <acronym>sfunc1</acronym>,
If we define an aggregate that does not use a final function,
we have an aggregate that computes a running function of
the attribute values from each instance. "Sum" is an
example of this kind of aggregate. "Sum" starts at
@ -60,10 +41,10 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.7 2000/03/31 03:27:41 thomas
<programlisting>
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;
@ -81,67 +62,48 @@ SELECT complex_sum(a) FROM test_complex;
</para>
<para>
If we define only <acronym>sfunc2</acronym>, we are
specifying an aggregate
that computes a running function that is independent of
the attribute values from each instance.
"Count" is the most common example of this kind of
aggregate. "Count" starts at zero and adds one to its
running total for each instance, ignoring the instance
value. Here, we use the built-in
<acronym>int4inc</acronym> routine to do
the work for us. This routine increments (adds one to)
its argument.
<programlisting>
CREATE AGGREGATE my_count (
sfunc2 = int4inc, -- add one
basetype = int4,
stype2 = int4,
initcond2 = '0'
);
SELECT my_count(*) as emp_count from EMP;
+----------+
|emp_count |
+----------+
|5 |
+----------+
</programlisting>
The above definition of "Sum" will return zero (the initial
state condition) if there are no non-null input values.
Perhaps we want to return NULL in that case instead --- SQL92
expects "Sum" to behave that way. We can do this simply by
omitting the "initcond" phrase, so that the initial state
condition is NULL. Ordinarily this would mean that the sfunc
would need to check for a NULL state-condition input, but for
"Sum" and some other simple aggregates like "Max" and "Min",
it's sufficient to insert the first non-null input value into
the state variable and then start applying the transition function
at the second non-null input value. <productname>Postgres</productname>
will do that automatically if the initial condition is NULL and
the transition function is marked "strict" (ie, not to be called
for NULL inputs).
</para>
<para>
"Average" is an example of an aggregate that requires
both a function to compute the running sum and a function
to compute the running count. When all of the
instances have been processed, the final answer for the
aggregate is the running sum divided by the running
count. We use the <acronym>int4pl</acronym> and
<acronym>int4inc</acronym> routines we used
before as well as the <productname>Postgres</productname> integer division
routine, <acronym>int4div</acronym>, to compute the division of the sum by
the count.
Another bit of default behavior for a "strict" transition function
is that the previous state value is retained unchanged whenever a
NULL input value is encountered. Thus, NULLs are ignored. If you
need some other behavior for NULL inputs, just define your transition
function as non-strict, and code it to test for NULL inputs and do
whatever is needed.
</para>
<para>
"Average" is a more complex example of an aggregate. It requires
two pieces of running state: the sum of the inputs and the count
of the number of inputs. The final result is obtained by dividing
these quantities. Average is typically implemented by using a
two-element array as the transition state value. For example,
the built-in implementation of <function>avg(float8)</function>
looks like:
<programlisting>
CREATE AGGREGATE my_average (
sfunc1 = int4pl, -- sum
basetype = int4,
stype1 = int4,
sfunc2 = int4inc, -- count
stype2 = int4,
finalfunc = int4div, -- division
initcond1 = '0',
initcond2 = '0'
CREATE AGGREGATE avg (
sfunc = float8_accum,
basetype = float8,
stype = _float8,
finalfunc = float8_avg,
initcond = '{0,0}'
);
SELECT my_average(salary) as emp_average FROM EMP;
+------------+
|emp_average |
+------------+
|1640 |
+------------+
</programlisting>
</para>

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é <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;