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:
parent
139f19c302
commit
bec98a31c5
|
@ -1,6 +1,6 @@
|
||||||
.\" This is -*-nroff-*-
|
.\" This is -*-nroff-*-
|
||||||
.\" XXX standard disclaimer belongs here....
|
.\" 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
|
.TH "SYSTEM CATALOGS" INTRO 03/13/94 PostgreSQL PostgreSQL
|
||||||
.SH "Section 7 - System Catalogs"
|
.SH "Section 7 - System Catalogs"
|
||||||
.de LS
|
.de LS
|
||||||
|
@ -91,20 +91,16 @@ The following catalogs relate to the class/type system.
|
||||||
* see DEFINE AGGREGATE for an explanation of transition functions
|
* see DEFINE AGGREGATE for an explanation of transition functions
|
||||||
*/
|
*/
|
||||||
pg_aggregate
|
pg_aggregate
|
||||||
NameData aggname /* aggregate name (e.g., "count") */
|
NameData aggname /* aggregate name (e.g., "count") */
|
||||||
oid aggowner /* usesysid of creator */
|
oid aggowner /* usesysid of creator */
|
||||||
regproc aggtransfn1 /* first transition function */
|
regproc aggtransfn /* transition function */
|
||||||
regproc aggtransfn2 /* second transition function */
|
|
||||||
regproc aggfinalfn /* final function */
|
regproc aggfinalfn /* final function */
|
||||||
oid aggbasetype /* type of data on which aggregate
|
oid aggbasetype /* type of data on which aggregate
|
||||||
operates */
|
operates */
|
||||||
oid aggtranstype1 /* type returned by aggtransfn1 */
|
oid aggtranstype /* type of aggregate's transition
|
||||||
oid aggtranstype2 /* type returned by aggtransfn2 */
|
(state) data */
|
||||||
oid aggfinaltype /* type returned by aggfinalfn */
|
oid aggfinaltype /* type of aggregate's final result */
|
||||||
text agginitval1 /* external format of initial
|
text agginitval /* external format of initial state value */
|
||||||
(starting) value of aggtransfn1 */
|
|
||||||
text agginitval2 /* external format of initial
|
|
||||||
(starting) value of aggtransfn2 */
|
|
||||||
.fi
|
.fi
|
||||||
.nf M
|
.nf M
|
||||||
pg_am
|
pg_am
|
||||||
|
|
|
@ -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
|
Postgres documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -21,20 +21,18 @@ Postgres documentation
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<refsynopsisdivinfo>
|
<refsynopsisdivinfo>
|
||||||
<date>1999-07-20</date>
|
<date>2000-07-16</date>
|
||||||
</refsynopsisdivinfo>
|
</refsynopsisdivinfo>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE = <replaceable class="PARAMETER">input_data_type</replaceable>
|
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> ]
|
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>, STYPE = <replaceable class="PARAMETER">state_type</replaceable>
|
||||||
[ , SFUNC2 = <replaceable class="PARAMETER">sfunc2</replaceable>, STYPE2 = <replaceable class="PARAMETER">state2_type</replaceable> ]
|
|
||||||
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
|
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
|
||||||
[ , INITCOND1 = <replaceable class="PARAMETER">initial_condition1</replaceable> ]
|
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ] )
|
||||||
[ , INITCOND2 = <replaceable class="PARAMETER">initial_condition2</replaceable> ] )
|
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
<refsect2 id="R2-SQL-CREATEAGGREGATE-1">
|
<refsect2 id="R2-SQL-CREATEAGGREGATE-1">
|
||||||
<refsect2info>
|
<refsect2info>
|
||||||
<date>1998-09-09</date>
|
<date>2000-07-16</date>
|
||||||
</refsect2info>
|
</refsect2info>
|
||||||
<title>
|
<title>
|
||||||
Inputs
|
Inputs
|
||||||
|
@ -55,57 +53,39 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE =
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The input data type on which this aggregate function operates.
|
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>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="PARAMETER">sfunc1</replaceable></term>
|
<term><replaceable class="PARAMETER">sfunc</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
A state transition function
|
The name of the state transition function
|
||||||
to be called for every non-NULL input data value.
|
to be called for each input data value.
|
||||||
This must be a function of two arguments, the first being of
|
This is normally a function of two arguments, the first being of
|
||||||
type <replaceable class="PARAMETER">state1_type</replaceable>
|
type <replaceable class="PARAMETER">state_type</replaceable>
|
||||||
and the second of
|
and the second of
|
||||||
type <replaceable class="PARAMETER">input_data_type</replaceable>.
|
type <replaceable class="PARAMETER">input_data_type</replaceable>.
|
||||||
The function must return a value of
|
Alternatively, for an aggregate that does not examine its input
|
||||||
type <replaceable class="PARAMETER">state1_type</replaceable>.
|
values, the function takes just one argument of
|
||||||
This function takes the current state value 1 and the current
|
type <replaceable class="PARAMETER">state_type</replaceable>.
|
||||||
input data item, and returns the next state value 1.
|
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>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="PARAMETER">state1_type</replaceable></term>
|
<term><replaceable class="PARAMETER">state_type</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The data type for the first state value of the aggregate.
|
The data type for the aggregate's state value.
|
||||||
</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.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -114,35 +94,28 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE =
|
||||||
<term><replaceable class="PARAMETER">ffunc</replaceable></term>
|
<term><replaceable class="PARAMETER">ffunc</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The final function called to compute the aggregate's result
|
The name of the final function called to compute the aggregate's
|
||||||
after all input data has been traversed.
|
result after all input data has been traversed. The function
|
||||||
If both state values are used, the final function must
|
must take a single argument of type
|
||||||
take two arguments of types
|
<replaceable class="PARAMETER">state_type</replaceable>.
|
||||||
<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 output datatype of the aggregate is defined as the return
|
The output datatype of the aggregate is defined as the return
|
||||||
type of this function.
|
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>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="PARAMETER">initial_condition1</replaceable></term>
|
<term><replaceable class="PARAMETER">initial_condition</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The initial value for state value 1.
|
The initial setting for the state value. This must be a literal
|
||||||
</para>
|
constant in the form accepted for the datatype
|
||||||
</listitem>
|
<replaceable class="PARAMETER">state_type</replaceable>.
|
||||||
</varlistentry>
|
If not specified, the state value starts out NULL.
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><replaceable class="PARAMETER">initial_condition2</replaceable></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The initial value for state value 2.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -177,7 +150,7 @@ CREATE
|
||||||
|
|
||||||
<refsect1 id="R1-SQL-CREATEAGGREGATE-1">
|
<refsect1 id="R1-SQL-CREATEAGGREGATE-1">
|
||||||
<refsect1info>
|
<refsect1info>
|
||||||
<date>1998-09-09</date>
|
<date>2000-07-16</date>
|
||||||
</refsect1info>
|
</refsect1info>
|
||||||
<title>
|
<title>
|
||||||
Description
|
Description
|
||||||
|
@ -199,65 +172,76 @@ CREATE
|
||||||
of the same name and input data type as an aggregate.
|
of the same name and input data type as an aggregate.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
An aggregate function is made from between one and three ordinary
|
An aggregate function is made from one or two ordinary
|
||||||
functions:
|
functions:
|
||||||
two state transition functions,
|
a state transition function
|
||||||
<replaceable class="PARAMETER">sfunc1</replaceable>
|
<replaceable class="PARAMETER">sfunc</replaceable>,
|
||||||
and <replaceable class="PARAMETER">sfunc2</replaceable>,
|
and an optional final calculation function
|
||||||
and a final calculation function,
|
|
||||||
<replaceable class="PARAMETER">ffunc</replaceable>.
|
<replaceable class="PARAMETER">ffunc</replaceable>.
|
||||||
These are used as follows:
|
These are used as follows:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
<replaceable class="PARAMETER">sfunc1</replaceable>( internal-state1, next-data-item ) ---> next-internal-state1
|
<replaceable class="PARAMETER">sfunc</replaceable>( internal-state, next-data-item ) ---> next-internal-state
|
||||||
<replaceable class="PARAMETER">sfunc2</replaceable>( internal-state2 ) ---> next-internal-state2
|
<replaceable class="PARAMETER">ffunc</replaceable>( internal-state ) ---> aggregate-value
|
||||||
<replaceable class="PARAMETER">ffunc</replaceable>(internal-state1, internal-state2) ---> aggregate-value
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
<productname>Postgres</productname> creates one or two temporary variables
|
<productname>Postgres</productname> creates a temporary variable
|
||||||
(of data types <replaceable class="PARAMETER">stype1</replaceable> and/or
|
of data type <replaceable class="PARAMETER">stype</replaceable>
|
||||||
<replaceable class="PARAMETER">stype2</replaceable>) to hold the
|
to hold the current internal state of the aggregate. At each input
|
||||||
current internal states of the aggregate. At each input data item,
|
data item,
|
||||||
the state transition function(s) are invoked to calculate new values
|
the state transition function is invoked to calculate a new
|
||||||
for the internal state values. After all the data has been processed,
|
internal state value. After all the data has been processed,
|
||||||
the final function is invoked once to calculate the aggregate's output
|
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
|
||||||
</para>
|
is returned as-is.
|
||||||
<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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
An aggregate function may also provide one or two initial conditions,
|
An aggregate function may provide an initial condition,
|
||||||
that is, initial values for the internal state values being used.
|
that is, an initial value for the internal state value.
|
||||||
These are specified and stored in the database as fields of type
|
This is specified and stored in the database as a field of type
|
||||||
<type>text</type>, but they must be valid external representations
|
<type>text</type>, but it must be a valid external representation
|
||||||
of constants of the state value datatypes. If
|
of a constant of the state value datatype. If it is not supplied
|
||||||
<replaceable class="PARAMETER">sfunc1</replaceable> is specified
|
then the state value starts out NULL.
|
||||||
without an <replaceable class="PARAMETER">initcond1</replaceable> value,
|
</para>
|
||||||
then the system does not call
|
|
||||||
<replaceable class="PARAMETER">sfunc1</replaceable>
|
<para>
|
||||||
at the first input item; instead, the internal state value 1 is
|
If the state transition function is declared "strict" in pg_proc,
|
||||||
initialized with the first input value, and
|
then it cannot be called with NULL inputs. With such a transition
|
||||||
<replaceable class="PARAMETER">sfunc1</replaceable> is called beginning
|
function, aggregate execution behaves as follows. NULL input values
|
||||||
at the second input item. This is useful for aggregates like MIN and
|
are ignored (the function is not called and the previous state value
|
||||||
MAX. Note that an aggregate using this feature will return NULL when
|
is retained). If the initial state value is NULL, then the first
|
||||||
called with no input values. There is no comparable provision for
|
non-NULL input value replaces the state value, and the transition
|
||||||
state value 2; if <replaceable class="PARAMETER">sfunc2</replaceable> is
|
function is invoked beginning with the second non-NULL input value.
|
||||||
specified then an <replaceable class="PARAMETER">initcond2</replaceable> is
|
This is handy for implementing aggregates like <function>max</function>.
|
||||||
required.
|
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>
|
</para>
|
||||||
|
|
||||||
<refsect2 id="R2-SQL-CREATEAGGREGATE-3">
|
<refsect2 id="R2-SQL-CREATEAGGREGATE-3">
|
||||||
<refsect2info>
|
<refsect2info>
|
||||||
<date>1998-09-09</date>
|
<date>2000-07-16</date>
|
||||||
</refsect2info>
|
</refsect2info>
|
||||||
<title>
|
<title>
|
||||||
Notes
|
Notes
|
||||||
|
@ -272,29 +256,6 @@ CREATE
|
||||||
in any order, not just the order illustrated above.
|
in any order, not just the order illustrated above.
|
||||||
</para>
|
</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>
|
</refsect2>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
|
@ -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
|
Postgres documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ DROP AGGREGATE <replaceable class="PARAMETER">name</replaceable> <replaceable cl
|
||||||
<para>
|
<para>
|
||||||
The type of an existing aggregate function.
|
The type of an existing aggregate function.
|
||||||
(Refer to the <citetitle>PostgreSQL User's Guide</citetitle> for
|
(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
|
<comment>This should become a cross-reference rather than a
|
||||||
hard-coded chapter number</comment>
|
hard-coded chapter number</comment>
|
||||||
</para>
|
</para>
|
||||||
|
@ -80,7 +80,7 @@ DROP
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><computeroutput>
|
<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>
|
</computeroutput></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -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">
|
<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
|
an initial value for the state, and a state transition
|
||||||
function. The state transition function is just an
|
function. The state transition function is just an
|
||||||
ordinary function that could also be used outside the
|
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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Actually, in order to make it easier to construct useful
|
Thus, in addition to the input and result datatypes seen by a user
|
||||||
aggregates from existing functions, an aggregate can have
|
of the aggregate, there is an internal state-value datatype that
|
||||||
one or two separate state values, one or two transition
|
may be different from both the input and result types.
|
||||||
functions to update those state values, and a
|
|
||||||
<firstterm>final function</firstterm> that computes the
|
|
||||||
actual aggregate result from the ending state values.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Thus there can be as many as four datatypes involved:
|
If we define an aggregate that does not use a final function,
|
||||||
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>,
|
|
||||||
we have an aggregate that computes a running function of
|
we have an aggregate that computes a running function of
|
||||||
the attribute values from each instance. "Sum" is an
|
the attribute values from each instance. "Sum" is an
|
||||||
example of this kind of aggregate. "Sum" starts at
|
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>
|
<programlisting>
|
||||||
CREATE AGGREGATE complex_sum (
|
CREATE AGGREGATE complex_sum (
|
||||||
sfunc1 = complex_add,
|
sfunc = complex_add,
|
||||||
basetype = complex,
|
basetype = complex,
|
||||||
stype1 = complex,
|
stype = complex,
|
||||||
initcond1 = '(0,0)'
|
initcond = '(0,0)'
|
||||||
);
|
);
|
||||||
|
|
||||||
SELECT complex_sum(a) FROM test_complex;
|
SELECT complex_sum(a) FROM test_complex;
|
||||||
|
@ -81,67 +62,48 @@ SELECT complex_sum(a) FROM test_complex;
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If we define only <acronym>sfunc2</acronym>, we are
|
The above definition of "Sum" will return zero (the initial
|
||||||
specifying an aggregate
|
state condition) if there are no non-null input values.
|
||||||
that computes a running function that is independent of
|
Perhaps we want to return NULL in that case instead --- SQL92
|
||||||
the attribute values from each instance.
|
expects "Sum" to behave that way. We can do this simply by
|
||||||
"Count" is the most common example of this kind of
|
omitting the "initcond" phrase, so that the initial state
|
||||||
aggregate. "Count" starts at zero and adds one to its
|
condition is NULL. Ordinarily this would mean that the sfunc
|
||||||
running total for each instance, ignoring the instance
|
would need to check for a NULL state-condition input, but for
|
||||||
value. Here, we use the built-in
|
"Sum" and some other simple aggregates like "Max" and "Min",
|
||||||
<acronym>int4inc</acronym> routine to do
|
it's sufficient to insert the first non-null input value into
|
||||||
the work for us. This routine increments (adds one to)
|
the state variable and then start applying the transition function
|
||||||
its argument.
|
at the second non-null input value. <productname>Postgres</productname>
|
||||||
|
will do that automatically if the initial condition is NULL and
|
||||||
<programlisting>
|
the transition function is marked "strict" (ie, not to be called
|
||||||
CREATE AGGREGATE my_count (
|
for NULL inputs).
|
||||||
sfunc2 = int4inc, -- add one
|
|
||||||
basetype = int4,
|
|
||||||
stype2 = int4,
|
|
||||||
initcond2 = '0'
|
|
||||||
);
|
|
||||||
|
|
||||||
SELECT my_count(*) as emp_count from EMP;
|
|
||||||
|
|
||||||
+----------+
|
|
||||||
|emp_count |
|
|
||||||
+----------+
|
|
||||||
|5 |
|
|
||||||
+----------+
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
"Average" is an example of an aggregate that requires
|
Another bit of default behavior for a "strict" transition function
|
||||||
both a function to compute the running sum and a function
|
is that the previous state value is retained unchanged whenever a
|
||||||
to compute the running count. When all of the
|
NULL input value is encountered. Thus, NULLs are ignored. If you
|
||||||
instances have been processed, the final answer for the
|
need some other behavior for NULL inputs, just define your transition
|
||||||
aggregate is the running sum divided by the running
|
function as non-strict, and code it to test for NULL inputs and do
|
||||||
count. We use the <acronym>int4pl</acronym> and
|
whatever is needed.
|
||||||
<acronym>int4inc</acronym> routines we used
|
</para>
|
||||||
before as well as the <productname>Postgres</productname> integer division
|
|
||||||
routine, <acronym>int4div</acronym>, to compute the division of the sum by
|
<para>
|
||||||
the count.
|
"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>
|
<programlisting>
|
||||||
CREATE AGGREGATE my_average (
|
CREATE AGGREGATE avg (
|
||||||
sfunc1 = int4pl, -- sum
|
sfunc = float8_accum,
|
||||||
basetype = int4,
|
basetype = float8,
|
||||||
stype1 = int4,
|
stype = _float8,
|
||||||
sfunc2 = int4inc, -- count
|
finalfunc = float8_avg,
|
||||||
stype2 = int4,
|
initcond = '{0,0}'
|
||||||
finalfunc = int4div, -- division
|
|
||||||
initcond1 = '0',
|
|
||||||
initcond2 = '0'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
SELECT my_average(salary) as emp_average FROM EMP;
|
|
||||||
|
|
||||||
+------------+
|
|
||||||
|emp_average |
|
|
||||||
+------------+
|
|
||||||
|1640 |
|
|
||||||
+------------+
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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_proc.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "parser/parse_coerce.h"
|
||||||
|
#include "parser/parse_func.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
@ -36,13 +38,7 @@
|
||||||
* Currently, redefining aggregates using the same name is not
|
* Currently, redefining aggregates using the same name is not
|
||||||
* supported. In such a case, a warning is printed that the
|
* supported. In such a case, a warning is printed that the
|
||||||
* aggregate already exists. If such is not the case, a new tuple
|
* aggregate already exists. If such is not the case, a new tuple
|
||||||
* is created and inserted in the aggregate relation. The fields
|
* is created and inserted in the aggregate relation.
|
||||||
* 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).
|
|
||||||
* All types and functions must have been defined
|
* All types and functions must have been defined
|
||||||
* prior to defining the aggregate.
|
* prior to defining the aggregate.
|
||||||
*
|
*
|
||||||
|
@ -50,31 +46,27 @@
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
AggregateCreate(char *aggName,
|
AggregateCreate(char *aggName,
|
||||||
char *aggtransfn1Name,
|
char *aggtransfnName,
|
||||||
char *aggtransfn2Name,
|
|
||||||
char *aggfinalfnName,
|
char *aggfinalfnName,
|
||||||
char *aggbasetypeName,
|
char *aggbasetypeName,
|
||||||
char *aggtransfn1typeName,
|
char *aggtranstypeName,
|
||||||
char *aggtransfn2typeName,
|
char *agginitval)
|
||||||
char *agginitval1,
|
|
||||||
char *agginitval2)
|
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Relation aggdesc;
|
Relation aggdesc;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
char nulls[Natts_pg_aggregate];
|
char nulls[Natts_pg_aggregate];
|
||||||
Datum values[Natts_pg_aggregate];
|
Datum values[Natts_pg_aggregate];
|
||||||
Form_pg_proc proc;
|
Form_pg_proc proc;
|
||||||
Oid xfn1 = InvalidOid;
|
Oid transfn;
|
||||||
Oid xfn2 = InvalidOid;
|
Oid finalfn = InvalidOid; /* can be omitted */
|
||||||
Oid ffn = InvalidOid;
|
Oid basetype;
|
||||||
Oid xbase = InvalidOid;
|
Oid transtype;
|
||||||
Oid xret1 = InvalidOid;
|
Oid finaltype;
|
||||||
Oid xret2 = InvalidOid;
|
|
||||||
Oid fret = InvalidOid;
|
|
||||||
Oid fnArgs[FUNC_MAX_ARGS];
|
Oid fnArgs[FUNC_MAX_ARGS];
|
||||||
|
int nargs;
|
||||||
NameData aname;
|
NameData aname;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
int i;
|
||||||
|
|
||||||
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||||
|
|
||||||
|
@ -82,143 +74,112 @@ AggregateCreate(char *aggName,
|
||||||
if (!aggName)
|
if (!aggName)
|
||||||
elog(ERROR, "AggregateCreate: no aggregate name supplied");
|
elog(ERROR, "AggregateCreate: no aggregate name supplied");
|
||||||
|
|
||||||
if (!aggtransfn1Name && !aggtransfn2Name)
|
if (!aggtransfnName)
|
||||||
elog(ERROR, "AggregateCreate: aggregate must have at least one transition function");
|
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). This can be
|
||||||
|
* specified as 'ANY' for a data-independent transition function,
|
||||||
/* handle the aggregate's base type (input data type) */
|
* such as COUNT(*).
|
||||||
|
*/
|
||||||
tup = SearchSysCacheTuple(TYPENAME,
|
tup = SearchSysCacheTuple(TYPENAME,
|
||||||
PointerGetDatum(aggbasetypeName),
|
PointerGetDatum(aggbasetypeName),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (!HeapTupleIsValid(tup))
|
if (HeapTupleIsValid(tup))
|
||||||
elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
|
{
|
||||||
xbase = tup->t_data->t_oid;
|
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 */
|
/* make sure there is no existing agg of same name and base type */
|
||||||
tup = SearchSysCacheTuple(AGGNAME,
|
tup = SearchSysCacheTuple(AGGNAME,
|
||||||
PointerGetDatum(aggName),
|
PointerGetDatum(aggName),
|
||||||
ObjectIdGetDatum(xbase),
|
ObjectIdGetDatum(basetype),
|
||||||
0, 0);
|
0, 0);
|
||||||
if (HeapTupleIsValid(tup))
|
if (HeapTupleIsValid(tup))
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
|
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
|
||||||
aggName, aggbasetypeName);
|
aggName, aggbasetypeName);
|
||||||
|
|
||||||
/* handle transfn1 and transtype1 */
|
/* handle transtype */
|
||||||
if (aggtransfn1Name)
|
tup = SearchSysCacheTuple(TYPENAME,
|
||||||
{
|
PointerGetDatum(aggtranstypeName),
|
||||||
tup = SearchSysCacheTuple(TYPENAME,
|
0, 0, 0);
|
||||||
PointerGetDatum(aggtransfn1typeName),
|
if (!HeapTupleIsValid(tup))
|
||||||
0, 0, 0);
|
elog(ERROR, "AggregateCreate: Type '%s' undefined",
|
||||||
if (!HeapTupleIsValid(tup))
|
aggtranstypeName);
|
||||||
elog(ERROR, "AggregateCreate: Type '%s' undefined",
|
transtype = tup->t_data->t_oid;
|
||||||
aggtransfn1typeName);
|
Assert(OidIsValid(transtype));
|
||||||
xret1 = tup->t_data->t_oid;
|
|
||||||
|
|
||||||
fnArgs[0] = xret1;
|
/* handle transfn */
|
||||||
fnArgs[1] = xbase;
|
fnArgs[0] = transtype;
|
||||||
tup = SearchSysCacheTuple(PROCNAME,
|
if (OidIsValid(basetype))
|
||||||
PointerGetDatum(aggtransfn1Name),
|
{
|
||||||
Int32GetDatum(2),
|
fnArgs[1] = basetype;
|
||||||
PointerGetDatum(fnArgs),
|
nargs = 2;
|
||||||
0);
|
}
|
||||||
if (!HeapTupleIsValid(tup))
|
else
|
||||||
elog(ERROR, "AggregateCreate: '%s('%s', '%s') does not exist",
|
{
|
||||||
aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
|
nargs = 1;
|
||||||
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
|
}
|
||||||
elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
|
tup = SearchSysCacheTuple(PROCNAME,
|
||||||
aggtransfn1Name, aggtransfn1typeName);
|
PointerGetDatum(aggtransfnName),
|
||||||
xfn1 = tup->t_data->t_oid;
|
Int32GetDatum(nargs),
|
||||||
if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
|
PointerGetDatum(fnArgs),
|
||||||
!OidIsValid(xbase))
|
0);
|
||||||
elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn1Name);
|
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 */
|
/* handle finalfn, if supplied */
|
||||||
if (aggtransfn2Name)
|
if (aggfinalfnName)
|
||||||
{
|
{
|
||||||
tup = SearchSysCacheTuple(TYPENAME,
|
fnArgs[0] = transtype;
|
||||||
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[1] = 0;
|
fnArgs[1] = 0;
|
||||||
tup = SearchSysCacheTuple(PROCNAME,
|
tup = SearchSysCacheTuple(PROCNAME,
|
||||||
PointerGetDatum(aggtransfn2Name),
|
PointerGetDatum(aggfinalfnName),
|
||||||
Int32GetDatum(1),
|
Int32GetDatum(1),
|
||||||
PointerGetDatum(fnArgs),
|
PointerGetDatum(fnArgs),
|
||||||
0);
|
0);
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
|
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
|
||||||
aggtransfn2Name, aggtransfn2typeName);
|
finalfn = tup->t_data->t_oid;
|
||||||
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;
|
|
||||||
proc = (Form_pg_proc) GETSTRUCT(tup);
|
proc = (Form_pg_proc) GETSTRUCT(tup);
|
||||||
fret = proc->prorettype;
|
finaltype = proc->prorettype;
|
||||||
if (!OidIsValid(ffn) || !OidIsValid(fret))
|
Assert(OidIsValid(finalfn));
|
||||||
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If no finalfn, aggregate result type is type of the sole state
|
* If no finalfn, aggregate result type is type of the state value
|
||||||
* value (we already checked there is only one)
|
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(xret1))
|
finaltype = transtype;
|
||||||
fret = xret1;
|
|
||||||
else
|
|
||||||
fret = xret2;
|
|
||||||
}
|
}
|
||||||
Assert(OidIsValid(fret));
|
Assert(OidIsValid(finaltype));
|
||||||
|
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
|
|
||||||
/* initialize nulls and values */
|
/* initialize nulls and values */
|
||||||
for (i = 0; i < Natts_pg_aggregate; i++)
|
for (i = 0; i < Natts_pg_aggregate; i++)
|
||||||
|
@ -229,25 +190,17 @@ AggregateCreate(char *aggName,
|
||||||
namestrcpy(&aname, aggName);
|
namestrcpy(&aname, aggName);
|
||||||
values[Anum_pg_aggregate_aggname - 1] = NameGetDatum(&aname);
|
values[Anum_pg_aggregate_aggname - 1] = NameGetDatum(&aname);
|
||||||
values[Anum_pg_aggregate_aggowner - 1] = Int32GetDatum(GetUserId());
|
values[Anum_pg_aggregate_aggowner - 1] = Int32GetDatum(GetUserId());
|
||||||
values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1);
|
values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
|
||||||
values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2);
|
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
|
||||||
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn);
|
values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(basetype);
|
||||||
values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase);
|
values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(transtype);
|
||||||
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
|
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(finaltype);
|
||||||
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
|
|
||||||
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
|
|
||||||
|
|
||||||
if (agginitval1)
|
if (agginitval)
|
||||||
values[Anum_pg_aggregate_agginitval1 - 1] =
|
values[Anum_pg_aggregate_agginitval - 1] =
|
||||||
DirectFunctionCall1(textin, CStringGetDatum(agginitval1));
|
DirectFunctionCall1(textin, CStringGetDatum(agginitval));
|
||||||
else
|
else
|
||||||
nulls[Anum_pg_aggregate_agginitval1 - 1] = 'n';
|
nulls[Anum_pg_aggregate_agginitval - 1] = 'n';
|
||||||
|
|
||||||
if (agginitval2)
|
|
||||||
values[Anum_pg_aggregate_agginitval2 - 1] =
|
|
||||||
DirectFunctionCall1(textin, CStringGetDatum(agginitval2));
|
|
||||||
else
|
|
||||||
nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
|
|
||||||
|
|
||||||
aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
|
aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
|
||||||
tupDesc = aggdesc->rd_att;
|
tupDesc = aggdesc->rd_att;
|
||||||
|
@ -271,11 +224,9 @@ AggregateCreate(char *aggName,
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
|
AggNameGetInitVal(char *aggName, Oid basetype, bool *isNull)
|
||||||
{
|
{
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Relation aggRel;
|
|
||||||
int initValAttno;
|
|
||||||
Oid transtype,
|
Oid transtype,
|
||||||
typinput,
|
typinput,
|
||||||
typelem;
|
typelem;
|
||||||
|
@ -285,15 +236,6 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
|
||||||
|
|
||||||
Assert(PointerIsValid(aggName));
|
Assert(PointerIsValid(aggName));
|
||||||
Assert(PointerIsValid(isNull));
|
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,
|
tup = SearchSysCacheTuple(AGGNAME,
|
||||||
PointerGetDatum(aggName),
|
PointerGetDatum(aggName),
|
||||||
|
@ -302,29 +244,19 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
|
elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
|
||||||
aggName);
|
aggName);
|
||||||
if (xfuncno == 1)
|
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
textInitVal = fastgetattr(tup, initValAttno,
|
/*
|
||||||
RelationGetDescr(aggRel),
|
* initval is potentially null, so don't try to access it as a struct
|
||||||
isNull);
|
* field. Must do it the hard way with SysCacheGetAttr.
|
||||||
|
*/
|
||||||
|
textInitVal = SysCacheGetAttr(AGGNAME, tup,
|
||||||
|
Anum_pg_aggregate_agginitval,
|
||||||
|
isNull);
|
||||||
if (*isNull)
|
if (*isNull)
|
||||||
{
|
return (Datum) 0;
|
||||||
heap_close(aggRel, AccessShareLock);
|
|
||||||
return PointerGetDatum(NULL);
|
|
||||||
}
|
|
||||||
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
|
|
||||||
|
|
||||||
heap_close(aggRel, AccessShareLock);
|
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
|
||||||
|
|
||||||
tup = SearchSysCacheTuple(TYPEOID,
|
tup = SearchSysCacheTuple(TYPEOID,
|
||||||
ObjectIdGetDatum(transtype),
|
ObjectIdGetDatum(transtype),
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
|
@ -484,16 +484,12 @@ DefineOperator(char *oprName,
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
DefineAggregate(char *aggName, List *parameters)
|
DefineAggregate(char *aggName, List *parameters)
|
||||||
|
|
||||||
{
|
{
|
||||||
char *stepfunc1Name = NULL;
|
char *transfuncName = NULL;
|
||||||
char *stepfunc2Name = NULL;
|
|
||||||
char *finalfuncName = NULL;
|
char *finalfuncName = NULL;
|
||||||
char *baseType = NULL;
|
char *baseType = NULL;
|
||||||
char *stepfunc1Type = NULL;
|
char *transType = NULL;
|
||||||
char *stepfunc2Type = NULL;
|
char *initval = NULL;
|
||||||
char *init1 = NULL;
|
|
||||||
char *init2 = NULL;
|
|
||||||
List *pl;
|
List *pl;
|
||||||
|
|
||||||
foreach(pl, parameters)
|
foreach(pl, parameters)
|
||||||
|
@ -501,47 +497,28 @@ DefineAggregate(char *aggName, List *parameters)
|
||||||
DefElem *defel = (DefElem *) lfirst(pl);
|
DefElem *defel = (DefElem *) lfirst(pl);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sfunc1
|
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
|
||||||
|
* for sfunc, stype, initcond.
|
||||||
*/
|
*/
|
||||||
if (!strcasecmp(defel->defname, "sfunc1"))
|
if (strcasecmp(defel->defname, "sfunc") == 0)
|
||||||
stepfunc1Name = defGetString(defel);
|
transfuncName = defGetString(defel);
|
||||||
else if (!strcasecmp(defel->defname, "basetype"))
|
else if (strcasecmp(defel->defname, "sfunc1") == 0)
|
||||||
baseType = defGetString(defel);
|
transfuncName = defGetString(defel);
|
||||||
else if (!strcasecmp(defel->defname, "stype1"))
|
else if (strcasecmp(defel->defname, "finalfunc") == 0)
|
||||||
{
|
|
||||||
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"))
|
|
||||||
{
|
|
||||||
finalfuncName = defGetString(defel);
|
finalfuncName = defGetString(defel);
|
||||||
|
else if (strcasecmp(defel->defname, "basetype") == 0)
|
||||||
/*
|
baseType = defGetString(defel);
|
||||||
* initial conditions
|
else if (strcasecmp(defel->defname, "stype") == 0)
|
||||||
*/
|
transType = defGetString(defel);
|
||||||
}
|
else if (strcasecmp(defel->defname, "stype1") == 0)
|
||||||
else if (!strcasecmp(defel->defname, "initcond1"))
|
transType = defGetString(defel);
|
||||||
init1 = defGetString(defel);
|
else if (strcasecmp(defel->defname, "initcond") == 0)
|
||||||
else if (!strcasecmp(defel->defname, "initcond2"))
|
initval = defGetString(defel);
|
||||||
init2 = defGetString(defel);
|
else if (strcasecmp(defel->defname, "initcond1") == 0)
|
||||||
|
initval = defGetString(defel);
|
||||||
else
|
else
|
||||||
{
|
|
||||||
elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
|
elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
|
||||||
defel->defname);
|
defel->defname);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -549,31 +526,20 @@ DefineAggregate(char *aggName, List *parameters)
|
||||||
*/
|
*/
|
||||||
if (baseType == NULL)
|
if (baseType == NULL)
|
||||||
elog(ERROR, "Define: \"basetype\" unspecified");
|
elog(ERROR, "Define: \"basetype\" unspecified");
|
||||||
if (stepfunc1Name != NULL)
|
if (transType == NULL)
|
||||||
{
|
elog(ERROR, "Define: \"stype\" unspecified");
|
||||||
if (stepfunc1Type == NULL)
|
if (transfuncName == NULL)
|
||||||
elog(ERROR, "Define: \"stype1\" unspecified");
|
elog(ERROR, "Define: \"sfunc\" unspecified");
|
||||||
}
|
|
||||||
if (stepfunc2Name != NULL)
|
|
||||||
{
|
|
||||||
if (stepfunc2Type == NULL)
|
|
||||||
elog(ERROR, "Define: \"stype2\" unspecified");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Most of the argument-checking is done inside of AggregateCreate
|
* Most of the argument-checking is done inside of AggregateCreate
|
||||||
*/
|
*/
|
||||||
AggregateCreate(aggName, /* aggregate name */
|
AggregateCreate(aggName, /* aggregate name */
|
||||||
stepfunc1Name, /* first step function name */
|
transfuncName, /* step function name */
|
||||||
stepfunc2Name, /* second step function name */
|
finalfuncName, /* final function name */
|
||||||
finalfuncName, /* final function name */
|
baseType, /* type of data being aggregated */
|
||||||
baseType, /* type of object being aggregated */
|
transType, /* transition data type */
|
||||||
stepfunc1Type, /* return type of first function */
|
initval); /* initial condition */
|
||||||
stepfunc2Type, /* return type of second function */
|
|
||||||
init1, /* first initial condition */
|
|
||||||
init2); /* second initial condition */
|
|
||||||
|
|
||||||
/* XXX free palloc'd memory */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 "commands/user.h"
|
||||||
#include "libpq/crypt.h"
|
#include "libpq/crypt.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/execdebug.h"
|
||||||
#include "executor/functions.h"
|
#include "executor/functions.h"
|
||||||
#include "executor/nodeSubplan.h"
|
#include "executor/nodeSubplan.h"
|
||||||
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/fcache2.h"
|
#include "utils/fcache2.h"
|
||||||
|
|
|
@ -12,16 +12,19 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/types.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecScan
|
* ExecScan
|
||||||
|
|
|
@ -3,36 +3,38 @@
|
||||||
* nodeAgg.c
|
* nodeAgg.c
|
||||||
* Routines to handle aggregate nodes.
|
* Routines to handle aggregate nodes.
|
||||||
*
|
*
|
||||||
* ExecAgg evaluates each aggregate in the following steps: (initcond1,
|
* ExecAgg evaluates each aggregate in the following steps:
|
||||||
* initcond2 are the initial values and sfunc1, sfunc2, and finalfunc are
|
|
||||||
* the transition functions.)
|
|
||||||
*
|
*
|
||||||
* value1 = initcond1
|
* transvalue = initcond
|
||||||
* value2 = initcond2
|
|
||||||
* foreach input_value do
|
* foreach input_value do
|
||||||
* value1 = sfunc1(value1, input_value)
|
* transvalue = transfunc(transvalue, input_value)
|
||||||
* value2 = sfunc2(value2)
|
* result = finalfunc(transvalue)
|
||||||
* value1 = finalfunc(value1, value2)
|
|
||||||
*
|
*
|
||||||
* If initcond1 is NULL then the first non-NULL input_value is
|
* If a finalfunc is not supplied then the result is just the ending
|
||||||
* assigned directly to value1. sfunc1 isn't applied until value1
|
* value of transvalue.
|
||||||
* is non-NULL.
|
|
||||||
*
|
*
|
||||||
* sfunc1 is never applied when the current tuple's input_value is NULL.
|
* If transfunc is marked "strict" in pg_proc and initcond is NULL,
|
||||||
* sfunc2 is applied for each tuple if the aggref is marked 'usenulls',
|
* then the first non-NULL input_value is assigned directly to transvalue,
|
||||||
* otherwise it is only applied when input_value is not NULL.
|
* and transfunc isn't applied until the second non-NULL input_value.
|
||||||
* (usenulls was formerly used for COUNT(*), but is no longer needed for
|
* The agg's input type and transtype must be the same in this case!
|
||||||
* 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
|
* If transfunc is marked "strict" then NULL input_values are skipped,
|
||||||
* feature for user-defined aggregates. We'd just need to add a
|
* keeping the previous transvalue. If transfunc is not strict then it
|
||||||
* flag column to pg_aggregate and a parameter to CREATE AGGREGATE...)
|
* 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) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/executor.h"
|
||||||
#include "executor/nodeAgg.h"
|
#include "executor/nodeAgg.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
|
#include "parser/parse_coerce.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
|
@ -67,16 +70,15 @@ typedef struct AggStatePerAggData
|
||||||
Aggref *aggref;
|
Aggref *aggref;
|
||||||
|
|
||||||
/* Oids of transfer functions */
|
/* Oids of transfer functions */
|
||||||
Oid xfn1_oid;
|
Oid transfn_oid;
|
||||||
Oid xfn2_oid;
|
Oid finalfn_oid; /* may be InvalidOid */
|
||||||
Oid finalfn_oid;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fmgr lookup data for transfer functions --- only valid when
|
* 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 transfn;
|
||||||
FmgrInfo xfn2;
|
|
||||||
FmgrInfo finalfn;
|
FmgrInfo finalfn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -94,12 +96,10 @@ typedef struct AggStatePerAggData
|
||||||
FmgrInfo equalfn;
|
FmgrInfo equalfn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initial values from pg_aggregate entry
|
* initial value from pg_aggregate entry
|
||||||
*/
|
*/
|
||||||
Datum initValue1; /* for transtype1 */
|
Datum initValue;
|
||||||
Datum initValue2; /* for transtype2 */
|
bool initValueIsNull;
|
||||||
bool initValue1IsNull,
|
|
||||||
initValue2IsNull;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need the len and byval info for the agg's input, result, and
|
* We need the len and byval info for the agg's input, result, and
|
||||||
|
@ -107,45 +107,42 @@ typedef struct AggStatePerAggData
|
||||||
*/
|
*/
|
||||||
int inputtypeLen,
|
int inputtypeLen,
|
||||||
resulttypeLen,
|
resulttypeLen,
|
||||||
transtype1Len,
|
transtypeLen;
|
||||||
transtype2Len;
|
|
||||||
bool inputtypeByVal,
|
bool inputtypeByVal,
|
||||||
resulttypeByVal,
|
resulttypeByVal,
|
||||||
transtype1ByVal,
|
transtypeByVal;
|
||||||
transtype2ByVal;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These values are working state that is initialized at the start of
|
* These values are working state that is initialized at the start of
|
||||||
* an input tuple group and updated for each input tuple.
|
* an input tuple group and updated for each input tuple.
|
||||||
*
|
*
|
||||||
* For a simple (non DISTINCT) aggregate, we just feed the input values
|
* 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
|
* the input values into a Tuplesort object; then at completion of the
|
||||||
* input tuple group, we scan the sorted values, eliminate duplicates,
|
* 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 */
|
Tuplesortstate *sortstate; /* sort object, if a DISTINCT agg */
|
||||||
|
|
||||||
Datum value1, /* current transfer values 1 and 2 */
|
Datum transValue;
|
||||||
value2;
|
bool transValueIsNull;
|
||||||
bool value1IsNull,
|
|
||||||
value2IsNull;
|
bool noTransValue; /* true if transValue not set yet */
|
||||||
bool noInitValue; /* true if value1 not set yet */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: right now, noInitValue always has the same value as
|
* Note: noTransValue initially has the same value as transValueIsNull,
|
||||||
* value1IsNull. But we should keep them separate because once the
|
* and if true both are cleared to false at the same time. They are
|
||||||
* fmgr interface is fixed, we'll need to distinguish a null returned
|
* not the same though: if transfn later returns a NULL, we want to
|
||||||
* by transfn1 from a null we haven't yet replaced with an input
|
* keep that NULL and not auto-replace it with a later input value.
|
||||||
* value.
|
* Only the first non-NULL input will be auto-substituted.
|
||||||
*/
|
*/
|
||||||
} AggStatePerAggData;
|
} AggStatePerAggData;
|
||||||
|
|
||||||
|
|
||||||
static void initialize_aggregate(AggStatePerAgg peraggstate);
|
static void initialize_aggregate(AggStatePerAgg peraggstate);
|
||||||
static void advance_transition_functions(AggStatePerAgg peraggstate,
|
static void advance_transition_function(AggStatePerAgg peraggstate,
|
||||||
Datum newVal, bool isNull);
|
Datum newVal, bool isNull);
|
||||||
static void process_sorted_aggregate(AggState *aggstate,
|
static void process_sorted_aggregate(AggState *aggstate,
|
||||||
AggStatePerAgg peraggstate);
|
AggStatePerAgg peraggstate);
|
||||||
static void finalize_aggregate(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
|
* Note that when the initial value is pass-by-ref, we just reuse it
|
||||||
* them without copying for each group. Hence, transition function
|
* without copying for each group. Hence, transition function
|
||||||
* had better not scribble on its input!
|
* had better not scribble on its input, or it will fail for GROUP BY!
|
||||||
*/
|
*/
|
||||||
peraggstate->value1 = peraggstate->initValue1;
|
peraggstate->transValue = peraggstate->initValue;
|
||||||
peraggstate->value1IsNull = peraggstate->initValue1IsNull;
|
peraggstate->transValueIsNull = peraggstate->initValueIsNull;
|
||||||
peraggstate->value2 = peraggstate->initValue2;
|
|
||||||
peraggstate->value2IsNull = peraggstate->initValue2IsNull;
|
|
||||||
|
|
||||||
/* ------------------------------------------
|
/* ------------------------------------------
|
||||||
* If the initial value for the first transition function
|
* If the initial value for the transition state doesn't exist in the
|
||||||
* doesn't exist in the pg_aggregate table then we will let
|
* pg_aggregate table then we will let the first non-NULL value returned
|
||||||
* the first value returned from the outer procNode become
|
* from the outer procNode become the initial value. (This is useful for
|
||||||
* the initial value. (This is useful for aggregates like
|
* aggregates like max() and min().) The noTransValue flag signals that
|
||||||
* max{} and min{}.) The noInitValue flag signals that we
|
* we still need to do this.
|
||||||
* 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
|
* When called, CurrentMemoryContext should be the context we want the
|
||||||
* function results to be delivered into on this cycle.
|
* transition function result 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.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
advance_transition_functions(AggStatePerAgg peraggstate,
|
advance_transition_function(AggStatePerAgg peraggstate,
|
||||||
Datum newVal, bool isNull)
|
Datum newVal, bool isNull)
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fcinfo;
|
FunctionCallInfoData fcinfo;
|
||||||
|
|
||||||
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
if (peraggstate->transfn.fn_strict)
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX reconsider isNULL handling here
|
|
||||||
*/
|
|
||||||
if (OidIsValid(peraggstate->xfn1_oid) && !isNull)
|
|
||||||
{
|
{
|
||||||
if (peraggstate->noInitValue)
|
if (isNull)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* value1 has not been initialized. This is the first non-NULL
|
* For a strict transfn, nothing happens at a NULL input tuple;
|
||||||
* input value. We use it as the initial value for value1.
|
* we just keep the prior transValue. However, if the transtype
|
||||||
*
|
* is pass-by-ref, we have to copy it into the new context
|
||||||
* XXX We assume, without having checked, that the agg's input
|
* because the old one is going to get reset.
|
||||||
* type is binary-compatible with its transtype1!
|
*/
|
||||||
|
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
|
* We had better copy the datum if it is pass-by-ref, since
|
||||||
* the given pointer may be pointing into a scan tuple that
|
* the given pointer may be pointing into a scan tuple that
|
||||||
* will be freed on the next iteration of the scan.
|
* will be freed on the next iteration of the scan.
|
||||||
*/
|
*/
|
||||||
peraggstate->value1 = datumCopy(newVal,
|
peraggstate->transValue = datumCopy(newVal,
|
||||||
peraggstate->transtype1ByVal,
|
peraggstate->transtypeByVal,
|
||||||
peraggstate->transtype1Len);
|
peraggstate->transtypeLen);
|
||||||
peraggstate->value1IsNull = false;
|
peraggstate->transValueIsNull = false;
|
||||||
peraggstate->noInitValue = 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
|
* Don't call a strict function with NULL inputs. Note it is
|
||||||
* given us a pass-by-ref result that points at the scan tuple
|
* possible to get here despite the above tests, if the transfn
|
||||||
* or the prior-cycle working memory. Copy it into the active
|
* is strict *and* returned a NULL on a prior cycle. If that
|
||||||
* context if it doesn't look right.
|
* happens we will propagate the NULL all the way to the end.
|
||||||
*/
|
*/
|
||||||
if (!peraggstate->transtype1ByVal && !fcinfo.isnull &&
|
return;
|
||||||
! MemoryContextContains(CurrentMemoryContext,
|
|
||||||
DatumGetPointer(newVal)))
|
|
||||||
newVal = datumCopy(newVal,
|
|
||||||
peraggstate->transtype1ByVal,
|
|
||||||
peraggstate->transtype1Len);
|
|
||||||
peraggstate->value1 = newVal;
|
|
||||||
peraggstate->value1IsNull = fcinfo.isnull;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OidIsValid(peraggstate->xfn2_oid))
|
/* OK to call the transition function */
|
||||||
{
|
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||||
/* apply transition function 2 */
|
fcinfo.flinfo = &peraggstate->transfn;
|
||||||
fcinfo.flinfo = &peraggstate->xfn2;
|
fcinfo.nargs = 2;
|
||||||
fcinfo.nargs = 1;
|
fcinfo.arg[0] = peraggstate->transValue;
|
||||||
fcinfo.arg[0] = peraggstate->value2;
|
fcinfo.argnull[0] = peraggstate->transValueIsNull;
|
||||||
fcinfo.argnull[0] = peraggstate->value2IsNull;
|
fcinfo.arg[1] = newVal;
|
||||||
fcinfo.isnull = false; /* must reset after use by xfn1 */
|
fcinfo.argnull[1] = isNull;
|
||||||
if (fcinfo.flinfo->fn_strict && peraggstate->value2IsNull)
|
|
||||||
{
|
newVal = FunctionCallInvoke(&fcinfo);
|
||||||
/* don't call a strict function with NULL inputs */
|
|
||||||
newVal = (Datum) 0;
|
/*
|
||||||
fcinfo.isnull = true;
|
* If the transition function was uncooperative, it may have
|
||||||
}
|
* given us a pass-by-ref result that points at the scan tuple
|
||||||
else
|
* or the prior-cycle working memory. Copy it into the active
|
||||||
newVal = FunctionCallInvoke(&fcinfo);
|
* context if it doesn't look right.
|
||||||
/*
|
*/
|
||||||
* If the transition function was uncooperative, it may have
|
if (!peraggstate->transtypeByVal && !fcinfo.isnull &&
|
||||||
* given us a pass-by-ref result that points at the scan tuple
|
! MemoryContextContains(CurrentMemoryContext,
|
||||||
* or the prior-cycle working memory. Copy it into the active
|
DatumGetPointer(newVal)))
|
||||||
* context if it doesn't look right.
|
newVal = datumCopy(newVal,
|
||||||
*/
|
peraggstate->transtypeByVal,
|
||||||
if (!peraggstate->transtype2ByVal && !fcinfo.isnull &&
|
peraggstate->transtypeLen);
|
||||||
! MemoryContextContains(CurrentMemoryContext,
|
|
||||||
DatumGetPointer(newVal)))
|
peraggstate->transValue = newVal;
|
||||||
newVal = datumCopy(newVal,
|
peraggstate->transValueIsNull = fcinfo.isnull;
|
||||||
peraggstate->transtype2ByVal,
|
|
||||||
peraggstate->transtype2Len);
|
|
||||||
peraggstate->value2 = newVal;
|
|
||||||
peraggstate->value2IsNull = 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
|
* 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
|
* object. We complete the sort, read out the values in sorted order,
|
||||||
* run the transition functions on each non-duplicate value.
|
* and run the transition function on each non-duplicate value.
|
||||||
*
|
*
|
||||||
* When called, CurrentMemoryContext should be the per-query context.
|
* 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
|
* DISTINCT always suppresses nulls, per SQL spec, regardless of
|
||||||
* the aggregate's usenulls setting.
|
* the transition function's strictness.
|
||||||
*/
|
*/
|
||||||
if (isNull)
|
if (isNull)
|
||||||
continue;
|
continue;
|
||||||
/*
|
/*
|
||||||
* Clear and select the current working context for evaluation of
|
* 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]);
|
MemoryContextReset(aggstate->agg_cxt[aggstate->which_cxt]);
|
||||||
oldContext =
|
oldContext =
|
||||||
|
@ -365,11 +336,14 @@ process_sorted_aggregate(AggState *aggstate,
|
||||||
/* equal to prior, so forget this one */
|
/* equal to prior, so forget this one */
|
||||||
if (!peraggstate->inputtypeByVal)
|
if (!peraggstate->inputtypeByVal)
|
||||||
pfree(DatumGetPointer(newVal));
|
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
|
else
|
||||||
{
|
{
|
||||||
advance_transition_functions(peraggstate, newVal, false);
|
advance_transition_function(peraggstate, newVal, false);
|
||||||
/*
|
/*
|
||||||
* Make the other context current so that this transition
|
* Make the other context current so that this transition
|
||||||
* result is preserved.
|
* result is preserved.
|
||||||
|
@ -402,48 +376,19 @@ static void
|
||||||
finalize_aggregate(AggStatePerAgg peraggstate,
|
finalize_aggregate(AggStatePerAgg peraggstate,
|
||||||
Datum *resultVal, bool *resultIsNull)
|
Datum *resultVal, bool *resultIsNull)
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
|
|
||||||
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply the agg's finalfn, or substitute the appropriate
|
* Apply the agg's finalfn if one is provided, else return transValue.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(peraggstate->finalfn_oid) &&
|
if (OidIsValid(peraggstate->finalfn_oid))
|
||||||
!peraggstate->noInitValue)
|
|
||||||
{
|
{
|
||||||
|
FunctionCallInfoData fcinfo;
|
||||||
|
|
||||||
|
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||||
fcinfo.flinfo = &peraggstate->finalfn;
|
fcinfo.flinfo = &peraggstate->finalfn;
|
||||||
if (peraggstate->finalfn.fn_nargs > 1)
|
fcinfo.nargs = 1;
|
||||||
{
|
fcinfo.arg[0] = peraggstate->transValue;
|
||||||
fcinfo.nargs = 2;
|
fcinfo.argnull[0] = peraggstate->transValueIsNull;
|
||||||
fcinfo.arg[0] = peraggstate->value1;
|
if (fcinfo.flinfo->fn_strict && peraggstate->transValueIsNull)
|
||||||
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]))
|
|
||||||
{
|
{
|
||||||
/* don't call a strict function with NULL inputs */
|
/* don't call a strict function with NULL inputs */
|
||||||
*resultVal = (Datum) 0;
|
*resultVal = (Datum) 0;
|
||||||
|
@ -455,20 +400,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
|
||||||
*resultIsNull = fcinfo.isnull;
|
*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
|
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.
|
* 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,
|
newVal = ExecEvalExpr(aggref->target, econtext,
|
||||||
&isNull, &isDone);
|
&isNull, &isDone);
|
||||||
|
|
||||||
if (isNull && !aggref->usenulls)
|
|
||||||
continue; /* ignore this tuple for this agg */
|
|
||||||
|
|
||||||
if (aggref->aggdistinct)
|
if (aggref->aggdistinct)
|
||||||
{
|
{
|
||||||
|
/* in DISTINCT mode, we may ignore nulls */
|
||||||
|
if (isNull)
|
||||||
|
continue;
|
||||||
/* putdatum has to be called in per-query context */
|
/* putdatum has to be called in per-query context */
|
||||||
MemoryContextSwitchTo(oldContext);
|
MemoryContextSwitchTo(oldContext);
|
||||||
tuplesort_putdatum(peraggstate->sortstate,
|
tuplesort_putdatum(peraggstate->sortstate,
|
||||||
|
@ -600,8 +537,10 @@ ExecAgg(Agg *node)
|
||||||
MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
||||||
}
|
}
|
||||||
else
|
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;
|
HeapTuple aggTuple;
|
||||||
Form_pg_aggregate aggform;
|
Form_pg_aggregate aggform;
|
||||||
Type typeInfo;
|
Type typeInfo;
|
||||||
Oid xfn1_oid,
|
Oid transfn_oid,
|
||||||
xfn2_oid,
|
|
||||||
finalfn_oid;
|
finalfn_oid;
|
||||||
|
|
||||||
/* Mark Aggref node with its associated index in the result array */
|
/* 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->resulttypeLen = typeLen(typeInfo);
|
||||||
peraggstate->resulttypeByVal = typeByVal(typeInfo);
|
peraggstate->resulttypeByVal = typeByVal(typeInfo);
|
||||||
|
|
||||||
peraggstate->initValue1 =
|
typeInfo = typeidType(aggform->aggtranstype);
|
||||||
|
peraggstate->transtypeLen = typeLen(typeInfo);
|
||||||
|
peraggstate->transtypeByVal = typeByVal(typeInfo);
|
||||||
|
|
||||||
|
peraggstate->initValue =
|
||||||
AggNameGetInitVal(aggname,
|
AggNameGetInitVal(aggname,
|
||||||
aggform->aggbasetype,
|
aggform->aggbasetype,
|
||||||
1,
|
&peraggstate->initValueIsNull);
|
||||||
&peraggstate->initValue1IsNull);
|
|
||||||
|
|
||||||
peraggstate->initValue2 =
|
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
|
||||||
AggNameGetInitVal(aggname,
|
|
||||||
aggform->aggbasetype,
|
|
||||||
2,
|
|
||||||
&peraggstate->initValue2IsNull);
|
|
||||||
|
|
||||||
peraggstate->xfn1_oid = xfn1_oid = aggform->aggtransfn1;
|
|
||||||
peraggstate->xfn2_oid = xfn2_oid = aggform->aggtransfn2;
|
|
||||||
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
|
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
|
||||||
|
|
||||||
if (OidIsValid(xfn1_oid))
|
fmgr_info(transfn_oid, &peraggstate->transfn);
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OidIsValid(finalfn_oid))
|
if (OidIsValid(finalfn_oid))
|
||||||
fmgr_info(finalfn_oid, &peraggstate->finalfn);
|
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)
|
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);
|
Oid inputType = exprType(aggref->target);
|
||||||
Operator eq_operator;
|
Operator eq_operator;
|
||||||
Form_pg_operator pgopform;
|
Form_pg_operator pgopform;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 "miscadmin.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
static int hashFunc(Datum key, int len, bool byVal);
|
static int hashFunc(Datum key, int len, bool byVal);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/nodeHash.h"
|
||||||
#include "executor/nodeHashjoin.h"
|
#include "executor/nodeHashjoin.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
|
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
|
||||||
HashJoinState *hjstate);
|
HashJoinState *hjstate);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* ExecInitNestLoop - initialize the join
|
||||||
* ExecEndNestLoop - shut down the join
|
* ExecEndNestLoop - shut down the join
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "executor/execdebug.h"
|
#include "executor/execdebug.h"
|
||||||
#include "executor/nodeNestloop.h"
|
#include "executor/nodeNestloop.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecNestLoop(node)
|
* ExecNestLoop(node)
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/executor.h"
|
||||||
#include "executor/nodeResult.h"
|
#include "executor/nodeResult.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecResult(node)
|
* ExecResult(node)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* This should be moved to a more appropriate place. It is here
|
* This should be moved to a more appropriate place. It is here
|
||||||
|
@ -43,6 +43,8 @@
|
||||||
#include "libpq/be-fsstubs.h"
|
#include "libpq/be-fsstubs.h"
|
||||||
#include "libpq/libpq-fs.h"
|
#include "libpq/libpq-fs.h"
|
||||||
#include "storage/large_object.h"
|
#include "storage/large_object.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
/* [PA] is Pascal André <andre@via.ecp.fr> */
|
/* [PA] is Pascal André <andre@via.ecp.fr> */
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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->basetype = from->basetype;
|
||||||
newnode->aggtype = from->aggtype;
|
newnode->aggtype = from->aggtype;
|
||||||
Node_Copy(from, newnode, target);
|
Node_Copy(from, newnode, target);
|
||||||
newnode->usenulls = from->usenulls;
|
|
||||||
newnode->aggstar = from->aggstar;
|
newnode->aggstar = from->aggstar;
|
||||||
newnode->aggdistinct = from->aggdistinct;
|
newnode->aggdistinct = from->aggdistinct;
|
||||||
newnode->aggno = from->aggno; /* probably not needed */
|
newnode->aggno = from->aggno; /* probably not needed */
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
return false;
|
||||||
if (!equal(a->target, b->target))
|
if (!equal(a->target, b->target))
|
||||||
return false;
|
return false;
|
||||||
if (a->usenulls != b->usenulls)
|
|
||||||
return false;
|
|
||||||
if (a->aggstar != b->aggstar)
|
if (a->aggstar != b->aggstar)
|
||||||
return false;
|
return false;
|
||||||
if (a->aggdistinct != b->aggdistinct)
|
if (a->aggdistinct != b->aggdistinct)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* NOTES
|
||||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||||
|
@ -729,12 +729,10 @@ _outAggref(StringInfo str, Aggref *node)
|
||||||
appendStringInfo(str, " AGGREG :aggname ");
|
appendStringInfo(str, " AGGREG :aggname ");
|
||||||
_outToken(str, node->aggname);
|
_outToken(str, node->aggname);
|
||||||
appendStringInfo(str, " :basetype %u :aggtype %u :target ",
|
appendStringInfo(str, " :basetype %u :aggtype %u :target ",
|
||||||
node->basetype,
|
node->basetype, node->aggtype);
|
||||||
node->aggtype);
|
|
||||||
_outNode(str, node->target);
|
_outNode(str, node->target);
|
||||||
|
|
||||||
appendStringInfo(str, " :usenulls %s :aggstar %s :aggdistinct %s ",
|
appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
|
||||||
node->usenulls ? "true" : "false",
|
|
||||||
node->aggstar ? "true" : "false",
|
node->aggstar ? "true" : "false",
|
||||||
node->aggdistinct ? "true" : "false");
|
node->aggdistinct ? "true" : "false");
|
||||||
/* aggno is not dumped */
|
/* aggno is not dumped */
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* Most of the read functions for plan nodes are tested. (In fact, they
|
* Most of the read functions for plan nodes are tested. (In fact, they
|
||||||
|
@ -1117,10 +1117,6 @@ _readAggref()
|
||||||
token = lsptok(NULL, &length); /* eat :target */
|
token = lsptok(NULL, &length); /* eat :target */
|
||||||
local_node->target = nodeRead(true); /* now read it */
|
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); /* eat :aggstar */
|
||||||
token = lsptok(NULL, &length); /* get aggstar */
|
token = lsptok(NULL, &length); /* get aggstar */
|
||||||
local_node->aggstar = (token[0] == 't') ? true : false;
|
local_node->aggstar = (token[0] == 't') ? true : false;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
HeapTuple theAggTuple;
|
||||||
Form_pg_aggregate aggform;
|
Form_pg_aggregate aggform;
|
||||||
Oid fintype;
|
|
||||||
Oid xfn1;
|
|
||||||
Oid vartype;
|
|
||||||
Aggref *aggref;
|
Aggref *aggref;
|
||||||
bool usenulls = false;
|
|
||||||
|
|
||||||
theAggTuple = SearchSysCacheTuple(AGGNAME,
|
theAggTuple = SearchSysCacheTuple(AGGNAME,
|
||||||
PointerGetDatum(aggname),
|
PointerGetDatum(aggname),
|
||||||
ObjectIdGetDatum(basetype),
|
ObjectIdGetDatum(basetype),
|
||||||
0, 0);
|
0, 0);
|
||||||
|
/* shouldn't happen --- caller should have checked already */
|
||||||
if (!HeapTupleIsValid(theAggTuple))
|
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.
|
* 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,
|
* does the right thing. (It didn't use to do the right thing,
|
||||||
* because the optimizer had the wrong ideas about semantics of
|
* because the optimizer had the wrong ideas about semantics of
|
||||||
* queries without explicit variables. Fixed as of Oct 1999 --- tgl.)
|
* 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;
|
* We assume caller has already checked that given args are compatible
|
||||||
xfn1 = aggform->aggtransfn1;
|
* with the agg's basetype.
|
||||||
|
*/
|
||||||
/* 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aggref = makeNode(Aggref);
|
aggref = makeNode(Aggref);
|
||||||
aggref->aggname = pstrdup(aggname);
|
aggref->aggname = pstrdup(aggname);
|
||||||
aggref->basetype = aggform->aggbasetype;
|
aggref->basetype = aggform->aggbasetype;
|
||||||
aggref->aggtype = fintype;
|
aggref->aggtype = aggform->aggfinaltype;
|
||||||
aggref->target = lfirst(args);
|
aggref->target = lfirst(args);
|
||||||
aggref->usenulls = usenulls;
|
|
||||||
aggref->aggstar = agg_star;
|
aggref->aggstar = agg_star;
|
||||||
aggref->aggdistinct = agg_distinct;
|
aggref->aggdistinct = agg_distinct;
|
||||||
|
|
||||||
|
@ -268,10 +241,9 @@ agg_error(char *caller, char *aggname, Oid basetypeID)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (basetypeID == InvalidOid)
|
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
|
else
|
||||||
{
|
elog(ERROR, "%s: aggregate '%s' for '%s' does not exist",
|
||||||
elog(ERROR, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
|
caller, aggname, typeidTypeName(basetypeID));
|
||||||
typeidTypeName(basetypeID));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
*
|
*
|
||||||
|
@ -33,6 +33,7 @@
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -80,6 +81,7 @@
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "utils/exc.h"
|
#include "utils/exc.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
#define INVALID_SOCK (-1)
|
#define INVALID_SOCK (-1)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* Outside modules can create a lock table and acquire/release
|
* Outside modules can create a lock table and acquire/release
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
* Interface:
|
* Interface:
|
||||||
*
|
*
|
||||||
* LockAcquire(), LockRelease(), LockMethodTableInit(),
|
* LockAcquire(), LockRelease(), LockMethodTableInit(),
|
||||||
* LockMethodTableRename(), LockReleaseAll, LockOwners()
|
* LockMethodTableRename(), LockReleaseAll,
|
||||||
* LockResolveConflicts(), GrantLock()
|
* LockResolveConflicts(), GrantLock()
|
||||||
*
|
*
|
||||||
* NOTE: This module is used to define new lock tables. The
|
* NOTE: This module is used to define new lock tables. The
|
||||||
|
@ -35,9 +35,11 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
|
|
||||||
static int WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode);
|
static int WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode);
|
||||||
|
@ -1722,181 +1724,6 @@ nxtl: ;
|
||||||
return false;
|
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
|
#ifdef LOCK_DEBUG
|
||||||
/*
|
/*
|
||||||
* Dump all locks in the proc->lockQueue. Must have already acquired
|
* Dump all locks in the proc->lockQueue. Must have already acquired
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "catalog/catalog.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/inval.h" /* ImmediateSharedRelationCacheInvalidate()
|
#include "utils/inval.h"
|
||||||
* */
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
#undef DIAGNOSTIC
|
#undef DIAGNOSTIC
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
|
@ -56,6 +56,7 @@
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "utils/exc.h"
|
#include "utils/exc.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
#include "utils/temprel.h"
|
#include "utils/temprel.h"
|
||||||
#ifdef MULTIBYTE
|
#ifdef MULTIBYTE
|
||||||
|
@ -1411,7 +1412,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface ");
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/execdefs.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "tcop/pquery.h"
|
#include "tcop/pquery.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
|
|
||||||
|
|
||||||
static char *CreateOperationTag(int operationType);
|
static char *CreateOperationTag(int operationType);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/catalog.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "fmgr.h"
|
|
||||||
#include "libpq/be-fsstubs.h"
|
#include "libpq/be-fsstubs.h"
|
||||||
#include "libpq/libpq-fs.h"
|
#include "libpq/libpq-fs.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
|
@ -29,7 +28,8 @@
|
||||||
|
|
||||||
#define ASSGN "="
|
#define ASSGN "="
|
||||||
|
|
||||||
/* An array has the following internal structure:
|
/*
|
||||||
|
* An array has the following internal structure:
|
||||||
* <nbytes> - total number of bytes
|
* <nbytes> - total number of bytes
|
||||||
* <ndim> - number of dimensions of the array
|
* <ndim> - number of dimensions of the array
|
||||||
* <flags> - bit mask of flags
|
* <flags> - bit mask of flags
|
||||||
|
@ -38,20 +38,18 @@
|
||||||
* <actual data> - whatever is the stored data
|
* <actual data> - whatever is the stored data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
|
|
||||||
static int _ArrayCount(char *str, int *dim, int typdelim);
|
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,
|
FmgrInfo *inputproc, Oid typelem, int32 typmod,
|
||||||
char typdelim, int typlen, bool typbyval,
|
char typdelim, int typlen, bool typbyval,
|
||||||
char typalign, int *nbytes);
|
char typalign, int *nbytes);
|
||||||
|
|
||||||
#ifdef LOARRAY
|
#ifdef LOARRAY
|
||||||
static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
|
static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
|
||||||
int ndim, int *dim, int baseSize);
|
int ndim, int *dim, int baseSize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
|
static void CopyArrayEls(char *p, Datum *values, int nitems,
|
||||||
char typalign, bool typbyval);
|
bool typbyval, int typlen, char typalign,
|
||||||
|
bool freedata);
|
||||||
static void system_cache_lookup(Oid element_type, bool input, int *typlen,
|
static void system_cache_lookup(Oid element_type, bool input, int *typlen,
|
||||||
bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
|
bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
|
||||||
char *typalign);
|
char *typalign);
|
||||||
|
@ -101,7 +99,7 @@ array_in(PG_FUNCTION_ARGS)
|
||||||
int i,
|
int i,
|
||||||
nitems;
|
nitems;
|
||||||
int32 nbytes;
|
int32 nbytes;
|
||||||
char *dataPtr;
|
Datum *dataPtr;
|
||||||
ArrayType *retval;
|
ArrayType *retval;
|
||||||
int ndim,
|
int ndim,
|
||||||
dim[MAXDIM],
|
dim[MAXDIM],
|
||||||
|
@ -187,32 +185,29 @@ array_in(PG_FUNCTION_ARGS)
|
||||||
retval = (ArrayType *) palloc(sizeof(ArrayType));
|
retval = (ArrayType *) palloc(sizeof(ArrayType));
|
||||||
MemSet(retval, 0, sizeof(ArrayType));
|
MemSet(retval, 0, sizeof(ArrayType));
|
||||||
*(int32 *) retval = sizeof(ArrayType);
|
*(int32 *) retval = sizeof(ArrayType);
|
||||||
PG_RETURN_POINTER(retval);
|
PG_RETURN_ARRAYTYPE_P(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == '{')
|
if (*p == '{')
|
||||||
{
|
{
|
||||||
/* array not a large object */
|
/* array not a large object */
|
||||||
dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
|
dataPtr = ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
|
||||||
typmod, typdelim, typlen, typbyval, typalign,
|
typmod, typdelim, typlen, typbyval, typalign,
|
||||||
&nbytes);
|
&nbytes);
|
||||||
nbytes += ARR_OVERHEAD(ndim);
|
nbytes += ARR_OVERHEAD(ndim);
|
||||||
retval = (ArrayType *) palloc(nbytes);
|
retval = (ArrayType *) palloc(nbytes);
|
||||||
MemSet(retval, 0, nbytes);
|
MemSet(retval, 0, nbytes);
|
||||||
memmove(retval, (char *) &nbytes, sizeof(int));
|
retval->size = nbytes;
|
||||||
memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
|
retval->ndim = ndim;
|
||||||
SET_LO_FLAG(false, retval);
|
SET_LO_FLAG(false, retval);
|
||||||
memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
|
memcpy((char *) ARR_DIMS(retval), (char *) dim,
|
||||||
memmove((char *) ARR_LBOUND(retval), (char *) lBound,
|
ndim * sizeof(int));
|
||||||
ndim * sizeof(int));
|
memcpy((char *) ARR_LBOUND(retval), (char *) lBound,
|
||||||
|
ndim * sizeof(int));
|
||||||
|
|
||||||
/*
|
CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems,
|
||||||
* dataPtr is an array of arbitraystuff even though its type is
|
typbyval, typlen, typalign, true);
|
||||||
* char* cast to char** to pass to _CopyArrayEls for now - jolly
|
pfree(dataPtr);
|
||||||
*/
|
|
||||||
_CopyArrayEls((char **) dataPtr,
|
|
||||||
ARR_DATA_PTR(retval), nitems,
|
|
||||||
typlen, typalign, typbyval);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -226,8 +221,8 @@ array_in(PG_FUNCTION_ARGS)
|
||||||
nbytes = bytes + ARR_OVERHEAD(ndim);
|
nbytes = bytes + ARR_OVERHEAD(ndim);
|
||||||
retval = (ArrayType *) palloc(nbytes);
|
retval = (ArrayType *) palloc(nbytes);
|
||||||
MemSet(retval, 0, nbytes);
|
MemSet(retval, 0, nbytes);
|
||||||
memmove(retval, (char *) &nbytes, sizeof(int));
|
retval->size = nbytes;
|
||||||
memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
|
retval->ndim = ndim;
|
||||||
SET_LO_FLAG(true, retval);
|
SET_LO_FLAG(true, retval);
|
||||||
SET_CHUNK_FLAG(chunked, retval);
|
SET_CHUNK_FLAG(chunked, retval);
|
||||||
memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
|
memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
|
||||||
|
@ -238,7 +233,7 @@ array_in(PG_FUNCTION_ARGS)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
pfree(string_save);
|
pfree(string_save);
|
||||||
PG_RETURN_POINTER(retval);
|
PG_RETURN_ARRAYTYPE_P(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
|
@ -331,50 +326,51 @@ _ArrayCount(char *str, int *dim, int typdelim)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------
|
/*---------------------------------------------------------------------------
|
||||||
* _ReadArrayStr :
|
* ReadArrayStr :
|
||||||
* parses the array string pointed by "arrayStr" and converts it in the
|
* parses the array string pointed by "arrayStr" and converts it to
|
||||||
* internal format. The external format expected is like C array
|
* internal format. The external format expected is like C array
|
||||||
* declaration. Unspecified elements are initialized to zero for fixed length
|
* declaration. Unspecified elements are initialized to zero for fixed length
|
||||||
* base types and to empty varlena structures for variable length base
|
* base types and to empty varlena structures for variable length base
|
||||||
* types.
|
* types.
|
||||||
* result :
|
* result :
|
||||||
* returns the internal representation of the array elements
|
* returns a palloc'd array of Datum representations of the array elements.
|
||||||
* nbytes is set to the size of the array in its internal representation.
|
* 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 *
|
static Datum *
|
||||||
_ReadArrayStr(char *arrayStr,
|
ReadArrayStr(char *arrayStr,
|
||||||
int nitems,
|
int nitems,
|
||||||
int ndim,
|
int ndim,
|
||||||
int *dim,
|
int *dim,
|
||||||
FmgrInfo *inputproc, /* function used for the
|
FmgrInfo *inputproc,
|
||||||
* conversion */
|
Oid typelem,
|
||||||
Oid typelem,
|
int32 typmod,
|
||||||
int32 typmod,
|
char typdelim,
|
||||||
char typdelim,
|
int typlen,
|
||||||
int typlen,
|
bool typbyval,
|
||||||
bool typbyval,
|
char typalign,
|
||||||
char typalign,
|
int *nbytes)
|
||||||
int *nbytes)
|
|
||||||
{
|
{
|
||||||
int i,
|
int i,
|
||||||
nest_level = 0;
|
nest_level = 0;
|
||||||
|
Datum *values;
|
||||||
char *p,
|
char *p,
|
||||||
*q,
|
*q,
|
||||||
*r,
|
*r;
|
||||||
**values;
|
|
||||||
bool scanning_string = false;
|
bool scanning_string = false;
|
||||||
int indx[MAXDIM],
|
int indx[MAXDIM],
|
||||||
prod[MAXDIM];
|
prod[MAXDIM];
|
||||||
bool eoArray = false;
|
bool eoArray = false;
|
||||||
|
|
||||||
mda_get_prod(ndim, dim, prod);
|
mda_get_prod(ndim, dim, prod);
|
||||||
for (i = 0; i < ndim; indx[i++] = 0);
|
values = (Datum *) palloc(nitems * sizeof(Datum));
|
||||||
/* read array enclosed within {} */
|
MemSet(values, 0, nitems * sizeof(Datum));
|
||||||
values = (char **) palloc(nitems * sizeof(char *));
|
MemSet(indx, 0, sizeof(indx));
|
||||||
MemSet(values, 0, nitems * sizeof(char *));
|
|
||||||
q = p = arrayStr;
|
q = p = arrayStr;
|
||||||
|
|
||||||
|
/* read array enclosed within {} */
|
||||||
while (!eoArray)
|
while (!eoArray)
|
||||||
{
|
{
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
@ -442,53 +438,56 @@ _ReadArrayStr(char *arrayStr,
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
if (i >= nitems)
|
if (i >= nitems)
|
||||||
elog(ERROR, "array_in: illformed array constant");
|
elog(ERROR, "array_in: illformed array constant");
|
||||||
values[i] = (char *) FunctionCall3(inputproc,
|
values[i] = FunctionCall3(inputproc,
|
||||||
CStringGetDatum(p),
|
CStringGetDatum(p),
|
||||||
ObjectIdGetDatum(typelem),
|
ObjectIdGetDatum(typelem),
|
||||||
Int32GetDatum(typmod));
|
Int32GetDatum(typmod));
|
||||||
p = ++q;
|
p = ++q;
|
||||||
|
/*
|
||||||
|
* if not at the end of the array skip white space
|
||||||
|
*/
|
||||||
if (!eoArray)
|
if (!eoArray)
|
||||||
|
|
||||||
/*
|
|
||||||
* if not at the end of the array skip white space
|
|
||||||
*/
|
|
||||||
while (isspace((int) *q))
|
while (isspace((int) *q))
|
||||||
{
|
{
|
||||||
p++;
|
p++;
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Initialize any unset items and compute total data space needed
|
||||||
|
*/
|
||||||
if (typlen > 0)
|
if (typlen > 0)
|
||||||
{
|
{
|
||||||
*nbytes = nitems * typlen;
|
*nbytes = nitems * typlen;
|
||||||
if (!typbyval)
|
if (!typbyval)
|
||||||
for (i = 0; i < nitems; i++)
|
for (i = 0; i < nitems; i++)
|
||||||
if (!values[i])
|
if (values[i] == (Datum) 0)
|
||||||
{
|
{
|
||||||
values[i] = palloc(typlen);
|
values[i] = PointerGetDatum(palloc(typlen));
|
||||||
MemSet(values[i], 0, typlen);
|
MemSet(DatumGetPointer(values[i]), 0, typlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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')
|
if (typalign == 'd')
|
||||||
*nbytes += MAXALIGN(*(int32 *) values[i]);
|
*nbytes += MAXALIGN(VARSIZE(DatumGetPointer(values[i])));
|
||||||
else
|
else
|
||||||
*nbytes += INTALIGN(*(int32 *) values[i]);
|
*nbytes += INTALIGN(VARSIZE(DatumGetPointer(values[i])));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*nbytes += sizeof(int32);
|
*nbytes += sizeof(int32);
|
||||||
values[i] = palloc(sizeof(int32));
|
values[i] = PointerGetDatum(palloc(sizeof(int32)));
|
||||||
*(int32 *) values[i] = sizeof(int32);
|
VARATT_SIZEP(DatumGetPointer(values[i])) = sizeof(int32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (char *) values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -565,26 +564,39 @@ _ReadLOArray(char *str,
|
||||||
|
|
||||||
#endif
|
#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
|
static void
|
||||||
_CopyArrayEls(char **values,
|
CopyArrayEls(char *p,
|
||||||
char *p,
|
Datum *values,
|
||||||
int nitems,
|
int nitems,
|
||||||
int typlen,
|
bool typbyval,
|
||||||
char typalign,
|
int typlen,
|
||||||
bool typbyval)
|
char typalign,
|
||||||
|
bool freedata)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int inc;
|
||||||
|
|
||||||
|
if (typbyval)
|
||||||
|
freedata = false;
|
||||||
|
|
||||||
for (i = 0; i < nitems; i++)
|
for (i = 0; i < nitems; i++)
|
||||||
{
|
{
|
||||||
int inc;
|
inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
|
||||||
|
|
||||||
inc = ArrayCastAndSet((Datum) values[i], typbyval, typlen, p);
|
|
||||||
p += inc;
|
p += inc;
|
||||||
if (!typbyval)
|
if (freedata)
|
||||||
pfree(values[i]);
|
pfree(DatumGetPointer(values[i]));
|
||||||
}
|
}
|
||||||
pfree(values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
|
@ -596,7 +608,7 @@ _CopyArrayEls(char **values,
|
||||||
Datum
|
Datum
|
||||||
array_out(PG_FUNCTION_ARGS)
|
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);
|
Oid element_type = PG_GETARG_OID(1);
|
||||||
int typlen;
|
int typlen;
|
||||||
bool typbyval;
|
bool typbyval;
|
||||||
|
@ -786,7 +798,7 @@ array_out(PG_FUNCTION_ARGS)
|
||||||
Datum
|
Datum
|
||||||
array_dims(PG_FUNCTION_ARGS)
|
array_dims(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
|
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
|
||||||
text *result;
|
text *result;
|
||||||
char *p;
|
char *p;
|
||||||
int nbytes,
|
int nbytes,
|
||||||
|
@ -821,8 +833,8 @@ array_dims(PG_FUNCTION_ARGS)
|
||||||
/*---------------------------------------------------------------------------
|
/*---------------------------------------------------------------------------
|
||||||
* array_ref :
|
* array_ref :
|
||||||
* This routine takes an array pointer and an index array and returns
|
* This routine takes an array pointer and an index array and returns
|
||||||
* a pointer to the referred element if element is passed by
|
* the referenced item as a Datum. Note that for a pass-by-reference
|
||||||
* reference otherwise returns the value of the referred element.
|
* datatype, the returned Datum is a pointer into the array object.
|
||||||
*---------------------------------------------------------------------------
|
*---------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
|
@ -905,7 +917,7 @@ array_ref(ArrayType *array,
|
||||||
{ /* not by value */
|
{ /* not by value */
|
||||||
char *tempdata = palloc(elmlen);
|
char *tempdata = palloc(elmlen);
|
||||||
|
|
||||||
memmove(tempdata, DatumGetPointer(result), elmlen);
|
memcpy(tempdata, DatumGetPointer(result), elmlen);
|
||||||
result = PointerGetDatum(tempdata);
|
result = PointerGetDatum(tempdata);
|
||||||
}
|
}
|
||||||
pfree(v);
|
pfree(v);
|
||||||
|
@ -1003,14 +1015,15 @@ array_clip(ArrayType *array,
|
||||||
#endif
|
#endif
|
||||||
bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts);
|
bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts);
|
||||||
newArr = (ArrayType *) palloc(bytes);
|
newArr = (ArrayType *) palloc(bytes);
|
||||||
memmove(newArr, array, sizeof(ArrayType));
|
newArr->size = bytes;
|
||||||
memmove(newArr, &bytes, sizeof(int));
|
newArr->ndim = array->ndim;
|
||||||
memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
|
newArr->flags = array->flags;
|
||||||
memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
|
memcpy(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
|
||||||
|
memcpy(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
|
||||||
strcpy(ARR_DATA_PTR(newArr), newname);
|
strcpy(ARR_DATA_PTR(newArr), newname);
|
||||||
|
|
||||||
rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen);
|
rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen);
|
||||||
if (rsize < MAX_BUFF_SIZE)
|
if (rsize < BLCKSZ)
|
||||||
{
|
{
|
||||||
char *buff;
|
char *buff;
|
||||||
|
|
||||||
|
@ -1072,10 +1085,11 @@ array_clip(ArrayType *array,
|
||||||
bytes += ARR_OVERHEAD(nSubscripts);
|
bytes += ARR_OVERHEAD(nSubscripts);
|
||||||
}
|
}
|
||||||
newArr = (ArrayType *) palloc(bytes);
|
newArr = (ArrayType *) palloc(bytes);
|
||||||
memmove(newArr, array, sizeof(ArrayType));
|
newArr->size = bytes;
|
||||||
memmove(newArr, &bytes, sizeof(int));
|
newArr->ndim = array->ndim;
|
||||||
memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
|
newArr->flags = array->flags;
|
||||||
memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
|
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);
|
_ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1);
|
||||||
return newArr;
|
return newArr;
|
||||||
}
|
}
|
||||||
|
@ -1322,7 +1336,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
|
||||||
{
|
{
|
||||||
ArrayType *v;
|
ArrayType *v;
|
||||||
ArrayType *result;
|
ArrayType *result;
|
||||||
char **values;
|
Datum *values;
|
||||||
char *elt;
|
char *elt;
|
||||||
int *dim;
|
int *dim;
|
||||||
int ndim;
|
int ndim;
|
||||||
|
@ -1338,14 +1352,13 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
|
||||||
Oid proc;
|
Oid proc;
|
||||||
char typalign;
|
char typalign;
|
||||||
char *s;
|
char *s;
|
||||||
char *p;
|
|
||||||
|
|
||||||
/* Get input array */
|
/* Get input array */
|
||||||
if (fcinfo->nargs < 1)
|
if (fcinfo->nargs < 1)
|
||||||
elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs);
|
elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs);
|
||||||
if (PG_ARGISNULL(0))
|
if (PG_ARGISNULL(0))
|
||||||
elog(ERROR, "array_map: null input array");
|
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 */
|
/* Large objects not yet supported */
|
||||||
if (ARR_IS_LO(v) == true)
|
if (ARR_IS_LO(v) == true)
|
||||||
|
@ -1357,7 +1370,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
|
||||||
|
|
||||||
/* Check for empty array */
|
/* Check for empty array */
|
||||||
if (nitems <= 0)
|
if (nitems <= 0)
|
||||||
PG_RETURN_POINTER(v);
|
PG_RETURN_ARRAYTYPE_P(v);
|
||||||
|
|
||||||
/* Lookup source and result types. Unneeded variables are reused. */
|
/* Lookup source and result types. Unneeded variables are reused. */
|
||||||
system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval,
|
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);
|
&typdelim, &typelem, &proc, &typalign);
|
||||||
|
|
||||||
/* Allocate temporary array for new values */
|
/* Allocate temporary array for new values */
|
||||||
values = (char **) palloc(nitems * sizeof(char *));
|
values = (Datum *) palloc(nitems * sizeof(Datum));
|
||||||
MemSet(values, 0, nitems * sizeof(char *));
|
MemSet(values, 0, nitems * sizeof(Datum));
|
||||||
|
|
||||||
/* Loop over source data */
|
/* Loop over source data */
|
||||||
s = (char *) ARR_DATA_PTR(v);
|
s = (char *) ARR_DATA_PTR(v);
|
||||||
|
@ -1411,30 +1424,16 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
|
||||||
fcinfo->arg[0] = (Datum) elt;
|
fcinfo->arg[0] = (Datum) elt;
|
||||||
fcinfo->argnull[0] = false;
|
fcinfo->argnull[0] = false;
|
||||||
fcinfo->isnull = false;
|
fcinfo->isnull = false;
|
||||||
p = (char *) FunctionCallInvoke(fcinfo);
|
values[i] = FunctionCallInvoke(fcinfo);
|
||||||
if (fcinfo->isnull)
|
if (fcinfo->isnull)
|
||||||
elog(ERROR, "array_map: cannot handle NULL in array");
|
elog(ERROR, "array_map: cannot handle NULL in array");
|
||||||
|
|
||||||
/* Update values and total result size */
|
/* Update total result size */
|
||||||
if (typbyval)
|
if (typbyval)
|
||||||
{
|
|
||||||
values[i] = p;
|
|
||||||
nbytes += typlen;
|
nbytes += typlen;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
nbytes += ((typlen > 0) ? typlen :
|
||||||
int len;
|
INTALIGN(VARSIZE(DatumGetPointer(values[i]))));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and initialize the result array */
|
/* Allocate and initialize the result array */
|
||||||
|
@ -1442,18 +1441,130 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
|
||||||
result = (ArrayType *) palloc(nbytes);
|
result = (ArrayType *) palloc(nbytes);
|
||||||
MemSet(result, 0, nbytes);
|
MemSet(result, 0, nbytes);
|
||||||
|
|
||||||
memcpy((char *) result, (char *) &nbytes, sizeof(int));
|
result->size = nbytes;
|
||||||
memcpy((char *) ARR_NDIM_PTR(result), (char *) &ndim, sizeof(int));
|
result->ndim = ndim;
|
||||||
memcpy((char *) ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
|
memcpy(ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
|
||||||
|
|
||||||
/* Copy new values into the result array. values is pfreed. */
|
/* Note: do not risk trying to pfree the results of the called function */
|
||||||
_CopyArrayEls((char **) values,
|
CopyArrayEls(ARR_DATA_PTR(result), values, nitems,
|
||||||
ARR_DATA_PTR(result), nitems,
|
typbyval, typlen, typalign, false);
|
||||||
typlen, typalign, typbyval);
|
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 :
|
* array_eq :
|
||||||
* compares two arrays for equality
|
* compares two arrays for equality
|
||||||
|
@ -1464,8 +1575,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
|
||||||
Datum
|
Datum
|
||||||
array_eq(PG_FUNCTION_ARGS)
|
array_eq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
ArrayType *array1 = (ArrayType *) PG_GETARG_VARLENA_P(0);
|
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
|
||||||
ArrayType *array2 = (ArrayType *) PG_GETARG_VARLENA_P(1);
|
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
|
||||||
|
|
||||||
if (*(int32 *) array1 != *(int32 *) array2)
|
if (*(int32 *) array1 != *(int32 *) array2)
|
||||||
PG_RETURN_BOOL(false);
|
PG_RETURN_BOOL(false);
|
||||||
|
@ -1493,14 +1604,11 @@ system_cache_lookup(Oid element_type,
|
||||||
typeTuple = SearchSysCacheTuple(TYPEOID,
|
typeTuple = SearchSysCacheTuple(TYPEOID,
|
||||||
ObjectIdGetDatum(element_type),
|
ObjectIdGetDatum(element_type),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
if (!HeapTupleIsValid(typeTuple))
|
if (!HeapTupleIsValid(typeTuple))
|
||||||
{
|
elog(ERROR, "array_out: Cache lookup failed for type %u",
|
||||||
elog(ERROR, "array_out: Cache lookup failed for type %u\n",
|
|
||||||
element_type);
|
element_type);
|
||||||
return;
|
|
||||||
}
|
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
|
||||||
|
|
||||||
*typlen = typeStruct->typlen;
|
*typlen = typeStruct->typlen;
|
||||||
*typbyval = typeStruct->typbyval;
|
*typbyval = typeStruct->typbyval;
|
||||||
*typdelim = typeStruct->typdelim;
|
*typdelim = typeStruct->typdelim;
|
||||||
|
@ -1536,7 +1644,11 @@ _ArrayCast(char *value, bool byval, int len)
|
||||||
return 0;
|
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
|
static int
|
||||||
ArrayCastAndSet(Datum src,
|
ArrayCastAndSet(Datum src,
|
||||||
bool typbyval,
|
bool typbyval,
|
||||||
|
@ -1560,16 +1672,26 @@ ArrayCastAndSet(Datum src,
|
||||||
case 4:
|
case 4:
|
||||||
*(int32 *) dest = DatumGetInt32(src);
|
*(int32 *) dest = DatumGetInt32(src);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "ArrayCastAndSet: unexpected typlen");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
/* For by-val types, assume no alignment padding is needed */
|
||||||
|
inc = typlen;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
memmove(dest, DatumGetPointer(src), typlen);
|
memmove(dest, DatumGetPointer(src), typlen);
|
||||||
inc = typlen;
|
/* XXX WRONG: need to consider type's alignment requirement */
|
||||||
|
inc = typlen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memmove(dest, DatumGetPointer(src), *(int32 *) DatumGetPointer(src));
|
/* varlena type */
|
||||||
inc = (INTALIGN(*(int32 *) DatumGetPointer(src)));
|
memmove(dest, DatumGetPointer(src), VARSIZE(DatumGetPointer(src)));
|
||||||
|
/* XXX WRONG: should use MAXALIGN or type's alignment requirement */
|
||||||
|
inc = INTALIGN(VARSIZE(DatumGetPointer(src)));
|
||||||
}
|
}
|
||||||
return inc;
|
return inc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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:
|
* Basic float4 ops:
|
||||||
* float4in, float4out, float4abs, float4um
|
* float4in, float4out, float4abs, float4um
|
||||||
* Basic float8 ops:
|
* Basic float8 ops:
|
||||||
* float8in, float8inAd, float8out, float8outAd, float8abs, float8um
|
* float8in, float8out, float8abs, float8um
|
||||||
* Arithmetic operators:
|
* Arithmetic operators:
|
||||||
* float4pl, float4mi, float4mul, float4div
|
* float4pl, float4mi, float4mul, float4div
|
||||||
* float8pl, float8mi, float8mul, float8div
|
* float8pl, float8mi, float8mul, float8div
|
||||||
|
@ -64,6 +64,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
static void CheckFloat8Val(double val);
|
static void CheckFloat8Val(double val);
|
||||||
|
@ -90,7 +91,6 @@ static void CheckFloat8Val(double val);
|
||||||
|
|
||||||
#ifndef atof
|
#ifndef atof
|
||||||
extern double atof(const char *p);
|
extern double atof(const char *p);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_CBRT
|
#ifndef HAVE_CBRT
|
||||||
|
@ -100,9 +100,8 @@ static double cbrt(double x);
|
||||||
#else
|
#else
|
||||||
#if !defined(nextstep)
|
#if !defined(nextstep)
|
||||||
extern double cbrt(double x);
|
extern double cbrt(double x);
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* HAVE_CBRT */
|
||||||
|
|
||||||
#ifndef HAVE_RINT
|
#ifndef HAVE_RINT
|
||||||
#define rint my_rint
|
#define rint my_rint
|
||||||
|
@ -110,10 +109,9 @@ static double rint(double x);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
extern double rint(double x);
|
extern double rint(double x);
|
||||||
|
#endif /* HAVE_RINT */
|
||||||
|
|
||||||
#endif
|
#endif /* NeXT check */
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ========== USER I/O ROUTINES ========== */
|
/* ========== USER I/O ROUTINES ========== */
|
||||||
|
|
||||||
|
@ -453,7 +451,6 @@ float8smaller(float64 arg1, float64 arg2)
|
||||||
* float4mi - returns a pointer to arg1 - arg2
|
* float4mi - returns a pointer to arg1 - arg2
|
||||||
* float4mul - returns a pointer to arg1 * arg2
|
* float4mul - returns a pointer to arg1 * arg2
|
||||||
* float4div - returns a pointer to arg1 / arg2
|
* float4div - returns a pointer to arg1 / arg2
|
||||||
* float4inc - returns a poniter to arg1 + 1.0
|
|
||||||
*/
|
*/
|
||||||
float32
|
float32
|
||||||
float4pl(float32 arg1, float32 arg2)
|
float4pl(float32 arg1, float32 arg2)
|
||||||
|
@ -527,29 +524,11 @@ float4div(float32 arg1, float32 arg2)
|
||||||
return result;
|
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
|
* float8pl - returns a pointer to arg1 + arg2
|
||||||
* float8mi - returns a pointer to arg1 - arg2
|
* float8mi - returns a pointer to arg1 - arg2
|
||||||
* float8mul - returns a pointer to arg1 * arg2
|
* float8mul - returns a pointer to arg1 * arg2
|
||||||
* float8div - returns a pointer to arg1 / arg2
|
* float8div - returns a pointer to arg1 / arg2
|
||||||
* float8inc - returns a pointer to arg1 + 1.0
|
|
||||||
*/
|
*/
|
||||||
float64
|
float64
|
||||||
float8pl(float64 arg1, float64 arg2)
|
float8pl(float64 arg1, float64 arg2)
|
||||||
|
@ -622,22 +601,6 @@ float8div(float64 arg1, float64 arg2)
|
||||||
return result;
|
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() */
|
} /* 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
|
||||||
|
* ====================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
PG_RETURN_INT16(arg1 / arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
|
||||||
int2inc(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
int16 arg = PG_GETARG_INT16(0);
|
|
||||||
|
|
||||||
PG_RETURN_INT16(arg + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
int24pl(PG_FUNCTION_ARGS)
|
int24pl(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* 1998 Jan Wieck
|
* 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 <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/int8.h"
|
#include "utils/int8.h"
|
||||||
#include "utils/numeric.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() -
|
* numeric_smaller() -
|
||||||
*
|
*
|
||||||
|
@ -1733,24 +1691,24 @@ numeric_int4(Numeric num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Numeric
|
Datum
|
||||||
int8_numeric(int64 *val)
|
int8_numeric(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
Datum val = PG_GETARG_DATUM(0);
|
||||||
Numeric res;
|
Numeric res;
|
||||||
NumericVar result;
|
NumericVar result;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
init_var(&result);
|
init_var(&result);
|
||||||
|
|
||||||
tmp = DatumGetCString(DirectFunctionCall1(int8out,
|
tmp = DatumGetCString(DirectFunctionCall1(int8out, val));
|
||||||
PointerGetDatum(val)));
|
|
||||||
set_var_from_str(tmp, &result);
|
set_var_from_str(tmp, &result);
|
||||||
res = make_result(&result);
|
res = make_result(&result);
|
||||||
|
|
||||||
free_var(&result);
|
free_var(&result);
|
||||||
pfree(tmp);
|
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
|
* Local functions follow
|
||||||
|
@ -2574,30 +2895,33 @@ add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
*/
|
*/
|
||||||
switch (cmp_abs(var1, var2))
|
switch (cmp_abs(var1, var2))
|
||||||
{
|
{
|
||||||
case 0: /* ----------
|
case 0:
|
||||||
* ABS(var1) == ABS(var2)
|
/* ----------
|
||||||
* result = ZERO
|
* ABS(var1) == ABS(var2)
|
||||||
* ----------
|
* result = ZERO
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
zero_var(result);
|
zero_var(result);
|
||||||
result->rscale = MAX(var1->rscale, var2->rscale);
|
result->rscale = MAX(var1->rscale, var2->rscale);
|
||||||
result->dscale = MAX(var1->dscale, var2->dscale);
|
result->dscale = MAX(var1->dscale, var2->dscale);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* ----------
|
case 1:
|
||||||
* ABS(var1) > ABS(var2)
|
/* ----------
|
||||||
* result = +(ABS(var1) - ABS(var2))
|
* ABS(var1) > ABS(var2)
|
||||||
* ----------
|
* result = +(ABS(var1) - ABS(var2))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var1, var2, result);
|
sub_abs(var1, var2, result);
|
||||||
result->sign = NUMERIC_POS;
|
result->sign = NUMERIC_POS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -1: /* ----------
|
case -1:
|
||||||
* ABS(var1) < ABS(var2)
|
/* ----------
|
||||||
* result = -(ABS(var2) - ABS(var1))
|
* ABS(var1) < ABS(var2)
|
||||||
* ----------
|
* result = -(ABS(var2) - ABS(var1))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var2, var1, result);
|
sub_abs(var2, var1, result);
|
||||||
result->sign = NUMERIC_NEG;
|
result->sign = NUMERIC_NEG;
|
||||||
break;
|
break;
|
||||||
|
@ -2615,30 +2939,33 @@ add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
*/
|
*/
|
||||||
switch (cmp_abs(var1, var2))
|
switch (cmp_abs(var1, var2))
|
||||||
{
|
{
|
||||||
case 0: /* ----------
|
case 0:
|
||||||
* ABS(var1) == ABS(var2)
|
/* ----------
|
||||||
* result = ZERO
|
* ABS(var1) == ABS(var2)
|
||||||
* ----------
|
* result = ZERO
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
zero_var(result);
|
zero_var(result);
|
||||||
result->rscale = MAX(var1->rscale, var2->rscale);
|
result->rscale = MAX(var1->rscale, var2->rscale);
|
||||||
result->dscale = MAX(var1->dscale, var2->dscale);
|
result->dscale = MAX(var1->dscale, var2->dscale);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* ----------
|
case 1:
|
||||||
* ABS(var1) > ABS(var2)
|
/* ----------
|
||||||
* result = -(ABS(var1) - ABS(var2))
|
* ABS(var1) > ABS(var2)
|
||||||
* ----------
|
* result = -(ABS(var1) - ABS(var2))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var1, var2, result);
|
sub_abs(var1, var2, result);
|
||||||
result->sign = NUMERIC_NEG;
|
result->sign = NUMERIC_NEG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -1: /* ----------
|
case -1:
|
||||||
* ABS(var1) < ABS(var2)
|
/* ----------
|
||||||
* result = +(ABS(var2) - ABS(var1))
|
* ABS(var1) < ABS(var2)
|
||||||
* ----------
|
* result = +(ABS(var2) - ABS(var1))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var2, var1, result);
|
sub_abs(var2, var1, result);
|
||||||
result->sign = NUMERIC_POS;
|
result->sign = NUMERIC_POS;
|
||||||
break;
|
break;
|
||||||
|
@ -2693,30 +3020,33 @@ sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
*/
|
*/
|
||||||
switch (cmp_abs(var1, var2))
|
switch (cmp_abs(var1, var2))
|
||||||
{
|
{
|
||||||
case 0: /* ----------
|
case 0:
|
||||||
* ABS(var1) == ABS(var2)
|
/* ----------
|
||||||
* result = ZERO
|
* ABS(var1) == ABS(var2)
|
||||||
* ----------
|
* result = ZERO
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
zero_var(result);
|
zero_var(result);
|
||||||
result->rscale = MAX(var1->rscale, var2->rscale);
|
result->rscale = MAX(var1->rscale, var2->rscale);
|
||||||
result->dscale = MAX(var1->dscale, var2->dscale);
|
result->dscale = MAX(var1->dscale, var2->dscale);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* ----------
|
case 1:
|
||||||
* ABS(var1) > ABS(var2)
|
/* ----------
|
||||||
* result = +(ABS(var1) - ABS(var2))
|
* ABS(var1) > ABS(var2)
|
||||||
* ----------
|
* result = +(ABS(var1) - ABS(var2))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var1, var2, result);
|
sub_abs(var1, var2, result);
|
||||||
result->sign = NUMERIC_POS;
|
result->sign = NUMERIC_POS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -1: /* ----------
|
case -1:
|
||||||
* ABS(var1) < ABS(var2)
|
/* ----------
|
||||||
* result = -(ABS(var2) - ABS(var1))
|
* ABS(var1) < ABS(var2)
|
||||||
* ----------
|
* result = -(ABS(var2) - ABS(var1))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var2, var1, result);
|
sub_abs(var2, var1, result);
|
||||||
result->sign = NUMERIC_NEG;
|
result->sign = NUMERIC_NEG;
|
||||||
break;
|
break;
|
||||||
|
@ -2734,30 +3064,33 @@ sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
*/
|
*/
|
||||||
switch (cmp_abs(var1, var2))
|
switch (cmp_abs(var1, var2))
|
||||||
{
|
{
|
||||||
case 0: /* ----------
|
case 0:
|
||||||
* ABS(var1) == ABS(var2)
|
/* ----------
|
||||||
* result = ZERO
|
* ABS(var1) == ABS(var2)
|
||||||
* ----------
|
* result = ZERO
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
zero_var(result);
|
zero_var(result);
|
||||||
result->rscale = MAX(var1->rscale, var2->rscale);
|
result->rscale = MAX(var1->rscale, var2->rscale);
|
||||||
result->dscale = MAX(var1->dscale, var2->dscale);
|
result->dscale = MAX(var1->dscale, var2->dscale);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* ----------
|
case 1:
|
||||||
* ABS(var1) > ABS(var2)
|
/* ----------
|
||||||
* result = -(ABS(var1) - ABS(var2))
|
* ABS(var1) > ABS(var2)
|
||||||
* ----------
|
* result = -(ABS(var1) - ABS(var2))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var1, var2, result);
|
sub_abs(var1, var2, result);
|
||||||
result->sign = NUMERIC_NEG;
|
result->sign = NUMERIC_NEG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -1: /* ----------
|
case -1:
|
||||||
* ABS(var1) < ABS(var2)
|
/* ----------
|
||||||
* result = +(ABS(var2) - ABS(var1))
|
* ABS(var1) < ABS(var2)
|
||||||
* ----------
|
* result = +(ABS(var2) - ABS(var1))
|
||||||
*/
|
* ----------
|
||||||
|
*/
|
||||||
sub_abs(var2, var1, result);
|
sub_abs(var2, var1, result);
|
||||||
result->sign = NUMERIC_POS;
|
result->sign = NUMERIC_POS;
|
||||||
break;
|
break;
|
||||||
|
@ -2817,7 +3150,7 @@ mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
|
|
||||||
for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
|
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;
|
res_digits[i--] = sum % 10;
|
||||||
sum /= 10;
|
sum /= 10;
|
||||||
}
|
}
|
||||||
|
@ -3067,7 +3400,6 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tidy up
|
* Tidy up
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
digitbuf_free(dividend.buf);
|
digitbuf_free(dividend.buf);
|
||||||
for (i = 1; i < 10; i++)
|
for (i = 1; i < 10; i++)
|
||||||
|
@ -3552,6 +3884,11 @@ add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
i1,
|
i1,
|
||||||
i2;
|
i2;
|
||||||
int carry = 0;
|
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_weight = MAX(var1->weight, var2->weight) + 1;
|
||||||
res_rscale = MAX(var1->rscale, var2->rscale);
|
res_rscale = MAX(var1->rscale, var2->rscale);
|
||||||
|
@ -3569,15 +3906,25 @@ add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
{
|
{
|
||||||
i1--;
|
i1--;
|
||||||
i2--;
|
i2--;
|
||||||
if (i1 >= 0 && i1 < var1->ndigits)
|
if (i1 >= 0 && i1 < var1ndigits)
|
||||||
carry += var1->digits[i1];
|
carry += var1digits[i1];
|
||||||
if (i2 >= 0 && i2 < var2->ndigits)
|
if (i2 >= 0 && i2 < var2ndigits)
|
||||||
carry += var2->digits[i2];
|
carry += var2digits[i2];
|
||||||
|
|
||||||
res_digits[i] = carry % 10;
|
if (carry >= 10)
|
||||||
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)
|
while (res_ndigits > 0 && *res_digits == 0)
|
||||||
{
|
{
|
||||||
res_digits++;
|
res_digits++;
|
||||||
|
@ -3623,6 +3970,11 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
i1,
|
i1,
|
||||||
i2;
|
i2;
|
||||||
int borrow = 0;
|
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_weight = var1->weight;
|
||||||
res_rscale = MAX(var1->rscale, var2->rscale);
|
res_rscale = MAX(var1->rscale, var2->rscale);
|
||||||
|
@ -3640,10 +3992,10 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
{
|
{
|
||||||
i1--;
|
i1--;
|
||||||
i2--;
|
i2--;
|
||||||
if (i1 >= 0 && i1 < var1->ndigits)
|
if (i1 >= 0 && i1 < var1ndigits)
|
||||||
borrow += var1->digits[i1];
|
borrow += var1digits[i1];
|
||||||
if (i2 >= 0 && i2 < var2->ndigits)
|
if (i2 >= 0 && i2 < var2ndigits)
|
||||||
borrow -= var2->digits[i2];
|
borrow -= var2digits[i2];
|
||||||
|
|
||||||
if (borrow < 0)
|
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)
|
while (res_ndigits > 0 && *res_digits == 0)
|
||||||
{
|
{
|
||||||
res_digits++;
|
res_digits++;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/hash.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -882,10 +883,6 @@ overlaps_timestamp(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*----------------------------------------------------------
|
/*----------------------------------------------------------
|
||||||
* "Arithmetic" operators on date/times.
|
* "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
|
Datum
|
||||||
|
@ -1150,7 +1147,6 @@ interval_larger(PG_FUNCTION_ARGS)
|
||||||
PG_RETURN_INTERVAL_P(result);
|
PG_RETURN_INTERVAL_P(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
interval_pl(PG_FUNCTION_ARGS)
|
interval_pl(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -1232,6 +1228,90 @@ interval_div(PG_FUNCTION_ARGS)
|
||||||
PG_RETURN_INTERVAL_P(result);
|
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()
|
/* timestamp_age()
|
||||||
* Calculate time difference while retaining year/month fields.
|
* Calculate time difference while retaining year/month fields.
|
||||||
* Note that this does not result in an accurate absolute time span
|
* Note that this does not result in an accurate absolute time span
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
|
||||||
*
|
*
|
||||||
|
@ -1421,22 +1421,16 @@ clearAggInfo(AggInfo *agginfo, int numArgs)
|
||||||
free(agginfo[i].oid);
|
free(agginfo[i].oid);
|
||||||
if (agginfo[i].aggname)
|
if (agginfo[i].aggname)
|
||||||
free(agginfo[i].aggname);
|
free(agginfo[i].aggname);
|
||||||
if (agginfo[i].aggtransfn1)
|
if (agginfo[i].aggtransfn)
|
||||||
free(agginfo[i].aggtransfn1);
|
free(agginfo[i].aggtransfn);
|
||||||
if (agginfo[i].aggtransfn2)
|
|
||||||
free(agginfo[i].aggtransfn2);
|
|
||||||
if (agginfo[i].aggfinalfn)
|
if (agginfo[i].aggfinalfn)
|
||||||
free(agginfo[i].aggfinalfn);
|
free(agginfo[i].aggfinalfn);
|
||||||
if (agginfo[i].aggtranstype1)
|
if (agginfo[i].aggtranstype)
|
||||||
free(agginfo[i].aggtranstype1);
|
free(agginfo[i].aggtranstype);
|
||||||
if (agginfo[i].aggbasetype)
|
if (agginfo[i].aggbasetype)
|
||||||
free(agginfo[i].aggbasetype);
|
free(agginfo[i].aggbasetype);
|
||||||
if (agginfo[i].aggtranstype2)
|
if (agginfo[i].agginitval)
|
||||||
free(agginfo[i].aggtranstype2);
|
free(agginfo[i].agginitval);
|
||||||
if (agginfo[i].agginitval1)
|
|
||||||
free(agginfo[i].agginitval1);
|
|
||||||
if (agginfo[i].agginitval2)
|
|
||||||
free(agginfo[i].agginitval2);
|
|
||||||
if (agginfo[i].usename)
|
if (agginfo[i].usename)
|
||||||
free(agginfo[i].usename);
|
free(agginfo[i].usename);
|
||||||
}
|
}
|
||||||
|
@ -1463,22 +1457,19 @@ getAggregates(int *numAggs)
|
||||||
|
|
||||||
int i_oid;
|
int i_oid;
|
||||||
int i_aggname;
|
int i_aggname;
|
||||||
int i_aggtransfn1;
|
int i_aggtransfn;
|
||||||
int i_aggtransfn2;
|
|
||||||
int i_aggfinalfn;
|
int i_aggfinalfn;
|
||||||
int i_aggtranstype1;
|
int i_aggtranstype;
|
||||||
int i_aggbasetype;
|
int i_aggbasetype;
|
||||||
int i_aggtranstype2;
|
int i_agginitval;
|
||||||
int i_agginitval1;
|
|
||||||
int i_agginitval2;
|
|
||||||
int i_usename;
|
int i_usename;
|
||||||
|
|
||||||
/* find all user-defined aggregates */
|
/* find all user-defined aggregates */
|
||||||
|
|
||||||
appendPQExpBuffer(query,
|
appendPQExpBuffer(query,
|
||||||
"SELECT pg_aggregate.oid, aggname, aggtransfn1, aggtransfn2, "
|
"SELECT pg_aggregate.oid, aggname, aggtransfn, "
|
||||||
"aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, "
|
"aggfinalfn, aggtranstype, aggbasetype, "
|
||||||
"agginitval1, agginitval2, usename from pg_aggregate, pg_user "
|
"agginitval, usename from pg_aggregate, pg_user "
|
||||||
"where aggowner = usesysid");
|
"where aggowner = usesysid");
|
||||||
|
|
||||||
res = PQexec(g_conn, query->data);
|
res = PQexec(g_conn, query->data);
|
||||||
|
@ -1497,28 +1488,22 @@ getAggregates(int *numAggs)
|
||||||
|
|
||||||
i_oid = PQfnumber(res, "oid");
|
i_oid = PQfnumber(res, "oid");
|
||||||
i_aggname = PQfnumber(res, "aggname");
|
i_aggname = PQfnumber(res, "aggname");
|
||||||
i_aggtransfn1 = PQfnumber(res, "aggtransfn1");
|
i_aggtransfn = PQfnumber(res, "aggtransfn");
|
||||||
i_aggtransfn2 = PQfnumber(res, "aggtransfn2");
|
|
||||||
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
|
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
|
||||||
i_aggtranstype1 = PQfnumber(res, "aggtranstype1");
|
i_aggtranstype = PQfnumber(res, "aggtranstype");
|
||||||
i_aggbasetype = PQfnumber(res, "aggbasetype");
|
i_aggbasetype = PQfnumber(res, "aggbasetype");
|
||||||
i_aggtranstype2 = PQfnumber(res, "aggtranstype2");
|
i_agginitval = PQfnumber(res, "agginitval");
|
||||||
i_agginitval1 = PQfnumber(res, "agginitval1");
|
|
||||||
i_agginitval2 = PQfnumber(res, "agginitval2");
|
|
||||||
i_usename = PQfnumber(res, "usename");
|
i_usename = PQfnumber(res, "usename");
|
||||||
|
|
||||||
for (i = 0; i < ntups; i++)
|
for (i = 0; i < ntups; i++)
|
||||||
{
|
{
|
||||||
agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
|
agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
|
||||||
agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
|
agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
|
||||||
agginfo[i].aggtransfn1 = strdup(PQgetvalue(res, i, i_aggtransfn1));
|
agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
|
||||||
agginfo[i].aggtransfn2 = strdup(PQgetvalue(res, i, i_aggtransfn2));
|
|
||||||
agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
|
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].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
|
||||||
agginfo[i].aggtranstype2 = strdup(PQgetvalue(res, i, i_aggtranstype2));
|
agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
|
||||||
agginfo[i].agginitval1 = strdup(PQgetvalue(res, i, i_agginitval1));
|
|
||||||
agginfo[i].agginitval2 = strdup(PQgetvalue(res, i, i_agginitval2));
|
|
||||||
agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
|
agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2902,69 +2887,32 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
|
||||||
PQExpBuffer q = createPQExpBuffer();
|
PQExpBuffer q = createPQExpBuffer();
|
||||||
PQExpBuffer delq = createPQExpBuffer();
|
PQExpBuffer delq = createPQExpBuffer();
|
||||||
PQExpBuffer aggSig = createPQExpBuffer();
|
PQExpBuffer aggSig = createPQExpBuffer();
|
||||||
PQExpBuffer sfunc1 = createPQExpBuffer();
|
PQExpBuffer details = createPQExpBuffer();
|
||||||
PQExpBuffer sfunc2 = createPQExpBuffer();
|
|
||||||
PQExpBuffer basetype = createPQExpBuffer();
|
|
||||||
PQExpBuffer finalfunc = createPQExpBuffer();
|
|
||||||
char comma1[2],
|
|
||||||
comma2[2];
|
|
||||||
|
|
||||||
for (i = 0; i < numAggs; i++)
|
for (i = 0; i < numAggs; i++)
|
||||||
{
|
{
|
||||||
|
resetPQExpBuffer(details);
|
||||||
resetPQExpBuffer(sfunc1);
|
|
||||||
resetPQExpBuffer(sfunc2);
|
|
||||||
resetPQExpBuffer(basetype);
|
|
||||||
resetPQExpBuffer(finalfunc);
|
|
||||||
|
|
||||||
/* skip all the builtin oids */
|
/* skip all the builtin oids */
|
||||||
if (atoi(agginfo[i].oid) < g_last_builtin_oid)
|
if (atoi(agginfo[i].oid) < g_last_builtin_oid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
appendPQExpBuffer(basetype,
|
appendPQExpBuffer(details,
|
||||||
"BASETYPE = %s, ",
|
"BASETYPE = %s, ",
|
||||||
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
|
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
|
||||||
|
|
||||||
if (!(strcmp(agginfo[i].aggtransfn1, "-") == 0))
|
appendPQExpBuffer(details,
|
||||||
{
|
"SFUNC = %s, STYPE = %s",
|
||||||
appendPQExpBuffer(sfunc1,
|
agginfo[i].aggtransfn,
|
||||||
"SFUNC1 = %s, STYPE1 = %s",
|
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype), false));
|
||||||
agginfo[i].aggtransfn1,
|
|
||||||
fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype1), false));
|
|
||||||
if (agginfo[i].agginitval1)
|
|
||||||
appendPQExpBuffer(sfunc1, ", INITCOND1 = '%s'",
|
|
||||||
agginfo[i].agginitval1);
|
|
||||||
|
|
||||||
}
|
if (agginfo[i].agginitval)
|
||||||
|
appendPQExpBuffer(details, ", INITCOND = '%s'",
|
||||||
if (!(strcmp(agginfo[i].aggtransfn2, "-") == 0))
|
agginfo[i].agginitval);
|
||||||
{
|
|
||||||
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 (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
|
if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
|
||||||
appendPQExpBuffer(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn);
|
appendPQExpBuffer(details, ", FINALFUNC = %s",
|
||||||
if (sfunc1->data[0] != '\0' && sfunc2->data[0] != '\0')
|
agginfo[i].aggfinalfn);
|
||||||
{
|
|
||||||
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';
|
|
||||||
|
|
||||||
resetPQExpBuffer(aggSig);
|
resetPQExpBuffer(aggSig);
|
||||||
appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
|
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);
|
appendPQExpBuffer(delq, "DROP AGGREGATE %s;\n", aggSig->data);
|
||||||
|
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s %s%s %s%s %s );\n",
|
appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
|
||||||
agginfo[i].aggname,
|
agginfo[i].aggname,
|
||||||
basetype->data,
|
details->data);
|
||||||
sfunc1->data,
|
|
||||||
comma1,
|
|
||||||
sfunc2->data,
|
|
||||||
comma2,
|
|
||||||
finalfunc->data);
|
|
||||||
|
|
||||||
ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
|
ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
|
||||||
q->data, delq->data, agginfo[i].usename, NULL, NULL);
|
q->data, delq->data, agginfo[i].usename, NULL, NULL);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
|
||||||
*
|
*
|
||||||
|
@ -133,14 +133,11 @@ typedef struct _aggInfo
|
||||||
{
|
{
|
||||||
char *oid;
|
char *oid;
|
||||||
char *aggname;
|
char *aggname;
|
||||||
char *aggtransfn1;
|
char *aggtransfn;
|
||||||
char *aggtransfn2;
|
|
||||||
char *aggfinalfn;
|
char *aggfinalfn;
|
||||||
char *aggtranstype1;
|
char *aggtranstype;
|
||||||
char *aggbasetype;
|
char *aggbasetype;
|
||||||
char *aggtranstype2;
|
char *agginitval;
|
||||||
char *agginitval1;
|
|
||||||
char *agginitval2;
|
|
||||||
char *usename;
|
char *usename;
|
||||||
} AggInfo;
|
} AggInfo;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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)
|
#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
|
* Section 5: IsValid macros for system types
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200007071
|
#define CATALOG_VERSION_NO 200007161
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -32,30 +32,25 @@
|
||||||
* cpp turns this into typedef struct FormData_pg_aggregate
|
* cpp turns this into typedef struct FormData_pg_aggregate
|
||||||
*
|
*
|
||||||
* aggname name of the aggregate
|
* aggname name of the aggregate
|
||||||
* aggtransfn1 transition function 1
|
* aggowner owner (creator) of the aggregate
|
||||||
* aggtransfn2 transition function 2
|
* aggtransfn transition function
|
||||||
* aggfinalfn final function
|
* aggfinalfn final function
|
||||||
* aggbasetype type of data on which aggregate operates
|
* aggbasetype type of data on which aggregate operates
|
||||||
* aggtranstype1 output types for transition func 1
|
* aggtranstype type of aggregate's transition (state) data
|
||||||
* aggtranstype2 output types for transition func 2
|
* aggfinaltype type of aggregate's final result
|
||||||
* aggfinaltype output type for final function
|
* agginitval initial value for transition state
|
||||||
* agginitval1 initial aggregate value
|
|
||||||
* agginitval2 initial value for transition state 2
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
CATALOG(pg_aggregate)
|
CATALOG(pg_aggregate)
|
||||||
{
|
{
|
||||||
NameData aggname;
|
NameData aggname;
|
||||||
int4 aggowner;
|
int4 aggowner;
|
||||||
regproc aggtransfn1;
|
regproc aggtransfn;
|
||||||
regproc aggtransfn2;
|
|
||||||
regproc aggfinalfn;
|
regproc aggfinalfn;
|
||||||
Oid aggbasetype;
|
Oid aggbasetype;
|
||||||
Oid aggtranstype1;
|
Oid aggtranstype;
|
||||||
Oid aggtranstype2;
|
|
||||||
Oid aggfinaltype;
|
Oid aggfinaltype;
|
||||||
text agginitval1; /* VARIABLE LENGTH FIELD */
|
text agginitval; /* VARIABLE LENGTH FIELD */
|
||||||
text agginitval2; /* VARIABLE LENGTH FIELD */
|
|
||||||
} FormData_pg_aggregate;
|
} 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_aggname 1
|
||||||
#define Anum_pg_aggregate_aggowner 2
|
#define Anum_pg_aggregate_aggowner 2
|
||||||
#define Anum_pg_aggregate_aggtransfn1 3
|
#define Anum_pg_aggregate_aggtransfn 3
|
||||||
#define Anum_pg_aggregate_aggtransfn2 4
|
#define Anum_pg_aggregate_aggfinalfn 4
|
||||||
#define Anum_pg_aggregate_aggfinalfn 5
|
#define Anum_pg_aggregate_aggbasetype 5
|
||||||
#define Anum_pg_aggregate_aggbasetype 6
|
#define Anum_pg_aggregate_aggtranstype 6
|
||||||
#define Anum_pg_aggregate_aggtranstype1 7
|
#define Anum_pg_aggregate_aggfinaltype 7
|
||||||
#define Anum_pg_aggregate_aggtranstype2 8
|
#define Anum_pg_aggregate_agginitval 8
|
||||||
#define Anum_pg_aggregate_aggfinaltype 9
|
|
||||||
#define Anum_pg_aggregate_agginitval1 10
|
|
||||||
#define Anum_pg_aggregate_agginitval2 11
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -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 int8_accum numeric_avg 20 1231 1700 "{0,0,0}" ));
|
||||||
DATA(insert OID = 0 ( avg PGUID int4pl int4inc int4div 23 23 23 23 _null_ 0 ));
|
DATA(insert OID = 0 ( avg PGUID int4_accum numeric_avg 23 1231 1700 "{0,0,0}" ));
|
||||||
DATA(insert OID = 0 ( avg PGUID int2pl int2inc int2div 21 21 21 21 _null_ 0 ));
|
DATA(insert OID = 0 ( avg PGUID int2_accum numeric_avg 21 1231 1700 "{0,0,0}" ));
|
||||||
DATA(insert OID = 0 ( avg PGUID float4pl float4inc float4div 700 700 700 700 _null_ 0.0 ));
|
DATA(insert OID = 0 ( avg PGUID numeric_accum numeric_avg 1700 1231 1700 "{0,0,0}" ));
|
||||||
DATA(insert OID = 0 ( avg PGUID float8pl float8inc float8div 701 701 701 701 _null_ 0.0 ));
|
DATA(insert OID = 0 ( avg PGUID float4_accum float8_avg 700 1022 701 "{0,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 float8_accum float8_avg 701 1022 701 "{0,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 interval_accum interval_avg 1186 1187 1186 "{0,0}" ));
|
||||||
DATA(insert OID = 0 ( avg PGUID numeric_add numeric_inc numeric_div 1700 1700 1700 1700 _null_ 0 ));
|
|
||||||
|
|
||||||
DATA(insert OID = 0 ( sum PGUID int8pl - - 20 20 0 20 _null_ _null_ ));
|
DATA(insert OID = 0 ( sum PGUID int8_sum - 20 1700 1700 _null_ ));
|
||||||
DATA(insert OID = 0 ( sum PGUID int4pl - - 23 23 0 23 _null_ _null_ ));
|
DATA(insert OID = 0 ( sum PGUID int4_sum - 23 1700 1700 _null_ ));
|
||||||
DATA(insert OID = 0 ( sum PGUID int2pl - - 21 21 0 21 _null_ _null_ ));
|
DATA(insert OID = 0 ( sum PGUID int2_sum - 21 1700 1700 _null_ ));
|
||||||
DATA(insert OID = 0 ( sum PGUID float4pl - - 700 700 0 700 _null_ _null_ ));
|
DATA(insert OID = 0 ( sum PGUID float4pl - 700 700 700 _null_ ));
|
||||||
DATA(insert OID = 0 ( sum PGUID float8pl - - 701 701 0 701 _null_ _null_ ));
|
DATA(insert OID = 0 ( sum PGUID float8pl - 701 701 701 _null_ ));
|
||||||
DATA(insert OID = 0 ( sum PGUID cash_pl - - 790 790 0 790 _null_ _null_ ));
|
DATA(insert OID = 0 ( sum PGUID cash_pl - 790 790 790 _null_ ));
|
||||||
DATA(insert OID = 0 ( sum PGUID interval_pl - - 1186 1186 0 1186 _null_ _null_ ));
|
DATA(insert OID = 0 ( sum PGUID interval_pl - 1186 1186 1186 _null_ ));
|
||||||
DATA(insert OID = 0 ( sum PGUID numeric_add - - 1700 1700 0 1700 _null_ _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 int8larger - 20 20 20 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID int4larger - - 23 23 0 23 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID int4larger - 23 23 23 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID int2larger - - 21 21 0 21 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID int2larger - 21 21 21 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID float4larger - - 700 700 0 700 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID float4larger - 700 700 700 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID float8larger - - 701 701 0 701 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID float8larger - 701 701 701 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID int4larger - - 702 702 0 702 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID int4larger - 702 702 702 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID date_larger - - 1082 1082 0 1082 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID date_larger - 1082 1082 1082 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID time_larger - - 1083 1083 0 1083 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID time_larger - 1083 1083 1083 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID timetz_larger - - 1266 1266 0 1266 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID timetz_larger - 1266 1266 1266 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID cashlarger - - 790 790 0 790 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID cashlarger - 790 790 790 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID timestamp_larger - - 1184 1184 0 1184 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID timestamp_larger - 1184 1184 1184 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID interval_larger - - 1186 1186 0 1186 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID interval_larger - 1186 1186 1186 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID text_larger - - 25 25 0 25 _null_ _null_ ));
|
DATA(insert OID = 0 ( max PGUID text_larger - 25 25 25 _null_ ));
|
||||||
DATA(insert OID = 0 ( max PGUID numeric_larger - - 1700 1700 0 1700 _null_ _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 int8smaller - 20 20 20 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID int4smaller - - 23 23 0 23 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID int4smaller - 23 23 23 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID int2smaller - - 21 21 0 21 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID int2smaller - 21 21 21 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID float4smaller - - 700 700 0 700 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID float4smaller - 700 700 700 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID float8smaller - - 701 701 0 701 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID float8smaller - 701 701 701 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID int4smaller - - 702 702 0 702 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID int4smaller - 702 702 702 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID date_smaller - - 1082 1082 0 1082 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID date_smaller - 1082 1082 1082 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID time_smaller - - 1083 1083 0 1083 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID time_smaller - 1083 1083 1083 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID timetz_smaller - - 1266 1266 0 1266 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID timetz_smaller - 1266 1266 1266 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID cashsmaller - - 790 790 0 790 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID cashsmaller - 790 790 790 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID timestamp_smaller - - 1184 1184 0 1184 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID timestamp_smaller - 1184 1184 1184 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID interval_smaller - - 1186 1186 0 1186 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID interval_smaller - 1186 1186 1186 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID text_smaller - - 25 25 0 25 _null_ _null_ ));
|
DATA(insert OID = 0 ( min PGUID text_smaller - 25 25 25 _null_ ));
|
||||||
DATA(insert OID = 0 ( min PGUID numeric_smaller - - 1700 1700 0 1700 _null_ _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
|
* prototypes for functions in pg_aggregate.c
|
||||||
*/
|
*/
|
||||||
extern void AggregateCreate(char *aggName,
|
extern void AggregateCreate(char *aggName,
|
||||||
char *aggtransfn1Name,
|
char *aggtransfnName,
|
||||||
char *aggtransfn2Name,
|
|
||||||
char *aggfinalfnName,
|
char *aggfinalfnName,
|
||||||
char *aggbasetypeName,
|
char *aggbasetypeName,
|
||||||
char *aggtransfn1typeName,
|
char *aggtranstypeName,
|
||||||
char *aggtransfn2typeName,
|
char *agginitval);
|
||||||
char *agginitval1,
|
|
||||||
char *agginitval2);
|
|
||||||
|
|
||||||
extern Datum AggNameGetInitVal(char *aggName, Oid basetype,
|
extern Datum AggNameGetInitVal(char *aggName, Oid basetype,
|
||||||
int xfuncno, bool *isNull);
|
bool *isNull);
|
||||||
|
|
||||||
#endif /* PG_AGGREGATE_H */
|
#endif /* PG_AGGREGATE_H */
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* 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 = 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 = 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
|
#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 = 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 eqsel eqjoinsel ));
|
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
|
#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 = 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 - - ));
|
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 = 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 = 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
|
#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 = 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 = 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 ));
|
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 = 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 = 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
|
#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 = 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 = 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 ));
|
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 - - ));
|
DATA(insert OID = 1175 ( "!!" PGUID 0 l t f 0 21 23 0 0 0 0 int2fac - - ));
|
||||||
|
|
||||||
/* LIKE hacks by Keith Parks. */
|
/* 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
|
#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 = 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 eqsel eqjoinsel ));
|
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
|
#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 = 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 eqsel eqjoinsel ));
|
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
|
#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 = 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 eqsel eqjoinsel ));
|
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
|
#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 */
|
/* 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
|
#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 = 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 eqsel eqjoinsel ));
|
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
|
#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 = 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 eqsel eqjoinsel ));
|
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
|
#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 = 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 eqsel eqjoinsel ));
|
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
|
#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 */
|
/* timestamp operators */
|
||||||
/* name, owner, prec, kind, isleft, canhash, left, right, result, com, negate, lsortop, rsortop, oprcode, operrest, oprjoin */
|
/* name, owner, prec, kind, isleft, canhash, left, right, result, com, negate, lsortop, rsortop, oprcode, operrest, oprjoin */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* 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");
|
DESCR("negate");
|
||||||
DATA(insert OID = 207 ( float4abs PGUID 11 f t t t 1 f 700 "700" 100 0 0 100 float4abs - ));
|
DATA(insert OID = 207 ( float4abs PGUID 11 f t t t 1 f 700 "700" 100 0 0 100 float4abs - ));
|
||||||
DESCR("absolute value");
|
DESCR("absolute value");
|
||||||
DATA(insert OID = 208 ( float4inc PGUID 11 f t t t 1 f 700 "700" 100 0 0 100 float4inc - ));
|
DATA(insert OID = 208 ( float4_accum PGUID 12 f t t t 2 f 1022 "1022 700" 100 0 0 100 float4_accum - ));
|
||||||
DESCR("increment");
|
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 - ));
|
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");
|
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 - ));
|
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");
|
DESCR("negate");
|
||||||
DATA(insert OID = 221 ( float8abs PGUID 11 f t t t 1 f 701 "701" 100 0 0 100 float8abs - ));
|
DATA(insert OID = 221 ( float8abs PGUID 11 f t t t 1 f 701 "701" 100 0 0 100 float8abs - ));
|
||||||
DESCR("absolute value");
|
DESCR("absolute value");
|
||||||
DATA(insert OID = 222 ( float8inc PGUID 11 f t t t 1 f 701 "701" 100 0 0 100 float8inc - ));
|
DATA(insert OID = 222 ( float8_accum PGUID 12 f t t t 2 f 1022 "1022 701" 100 0 0 100 float8_accum - ));
|
||||||
DESCR("increment");
|
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 - ));
|
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");
|
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 - ));
|
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 - ));
|
DATA(insert OID = 766 ( int4inc PGUID 12 f t t t 1 f 23 "23" 100 0 0 100 int4inc - ));
|
||||||
DESCR("increment");
|
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 - ));
|
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");
|
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 - ));
|
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");
|
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 - ));
|
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");
|
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 - ));
|
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)");
|
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)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1764 ( numeric_inc PGUID 11 f t t t 1 f 1700 "1700" 100 0 0 100 numeric_inc - ));
|
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");
|
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 - ));
|
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");
|
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 - ));
|
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");
|
DESCR("negate");
|
||||||
DATA(insert OID = 1779 ( int8 PGUID 11 f t t t 1 f 20 "1700" 100 0 0 100 numeric_int8 - ));
|
DATA(insert OID = 1779 ( int8 PGUID 11 f t t t 1 f 20 "1700" 100 0 0 100 numeric_int8 - ));
|
||||||
DESCR("(internal)");
|
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)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1782 ( numeric PGUID 12 f t t t 1 f 1700 "21" 100 0 0 100 int2_numeric - ));
|
DATA(insert OID = 1782 ( numeric PGUID 12 f t t t 1 f 1700 "21" 100 0 0 100 int2_numeric - ));
|
||||||
DESCR("(internal)");
|
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 - ));
|
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");
|
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
|
* prototypes for functions pg_proc.c
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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)
|
* basetype - base type Oid of the aggregate (ie, input type)
|
||||||
* aggtype - type Oid of final result of the aggregate
|
* aggtype - type Oid of final result of the aggregate
|
||||||
* target - attribute or expression we are aggregating on
|
* target - attribute or expression we are aggregating on
|
||||||
* usenulls - TRUE to accept null values as inputs
|
|
||||||
* aggstar - TRUE if argument was really '*'
|
* aggstar - TRUE if argument was really '*'
|
||||||
* aggdistinct - TRUE if arguments were labeled DISTINCT
|
* aggdistinct - TRUE if it's agg(DISTINCT ...)
|
||||||
* aggno - workspace for nodeAgg.c executor
|
* aggno - workspace for executor (see nodeAgg.c)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct Aggref
|
typedef struct Aggref
|
||||||
|
@ -314,7 +313,6 @@ typedef struct Aggref
|
||||||
Oid basetype;
|
Oid basetype;
|
||||||
Oid aggtype;
|
Oid aggtype;
|
||||||
Node *target;
|
Node *target;
|
||||||
bool usenulls;
|
|
||||||
bool aggstar;
|
bool aggstar;
|
||||||
bool aggdistinct;
|
bool aggdistinct;
|
||||||
int aggno;
|
int aggno;
|
||||||
|
|
|
@ -7,18 +7,16 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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_
|
#ifndef LOCK_H_
|
||||||
#define LOCK_H_
|
#define LOCK_H_
|
||||||
|
|
||||||
#include "postgres.h"
|
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/itemptr.h"
|
#include "storage/itemptr.h"
|
||||||
#include "storage/shmem.h"
|
#include "storage/shmem.h"
|
||||||
#include "utils/array.h"
|
|
||||||
|
|
||||||
extern SPINLOCK LockMgrLock;
|
extern SPINLOCK LockMgrLock;
|
||||||
typedef int LOCKMASK;
|
typedef int LOCKMASK;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* NOTES
|
||||||
* XXX the data array should be MAXALIGN'd -- notice that the array
|
* XXX the data array should be MAXALIGN'd -- notice that the array
|
||||||
|
@ -24,15 +24,27 @@
|
||||||
#define ARRAY_H
|
#define ARRAY_H
|
||||||
|
|
||||||
#include "fmgr.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
|
typedef struct
|
||||||
{
|
{
|
||||||
int size; /* total array size (in bytes) */
|
int32 size; /* total array size (varlena requirement) */
|
||||||
int ndim; /* # of dimensions */
|
int ndim; /* # of dimensions */
|
||||||
int flags; /* implementation flags */
|
int flags; /* implementation flags */
|
||||||
} ArrayType;
|
} 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:
|
* bitmask of ArrayType flags field:
|
||||||
* 1st bit - large object flag
|
* 1st bit - large object flag
|
||||||
|
@ -43,11 +55,9 @@ typedef struct
|
||||||
#define ARR_CHK_FLAG (0x2)
|
#define ARR_CHK_FLAG (0x2)
|
||||||
#define ARR_OBJ_MASK (0x1c)
|
#define ARR_OBJ_MASK (0x1c)
|
||||||
|
|
||||||
#define ARR_FLAGS(a) ((ArrayType *) a)->flags
|
|
||||||
#define ARR_SIZE(a) (((ArrayType *) a)->size)
|
#define ARR_SIZE(a) (((ArrayType *) a)->size)
|
||||||
|
|
||||||
#define ARR_NDIM(a) (((ArrayType *) a)->ndim)
|
#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) \
|
#define ARR_IS_LO(a) \
|
||||||
(((ArrayType *) a)->flags & ARR_LOB_FLAG)
|
(((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 RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
|
||||||
|
|
||||||
#define NAME_LEN 30
|
#define NAME_LEN 30
|
||||||
#define MAX_BUFF_SIZE BLCKSZ
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -134,6 +143,12 @@ extern ArrayType *array_assgn(ArrayType *array, int nSubscripts,
|
||||||
bool elmbyval, int elmlen, bool *isNull);
|
bool elmbyval, int elmlen, bool *isNull);
|
||||||
extern Datum array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType);
|
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,
|
extern int _LOtransfer(char **destfd, int size, int nitems, char **srcfd,
|
||||||
int isSrcLO, int isDestLO);
|
int isSrcLO, int isDestLO);
|
||||||
extern char *_array_newLO(int *fd, int flag);
|
extern char *_array_newLO(int *fd, int flag);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 int2mul(PG_FUNCTION_ARGS);
|
||||||
extern Datum int2div(PG_FUNCTION_ARGS);
|
extern Datum int2div(PG_FUNCTION_ARGS);
|
||||||
extern Datum int2abs(PG_FUNCTION_ARGS);
|
extern Datum int2abs(PG_FUNCTION_ARGS);
|
||||||
extern Datum int2inc(PG_FUNCTION_ARGS);
|
|
||||||
extern Datum int24pl(PG_FUNCTION_ARGS);
|
extern Datum int24pl(PG_FUNCTION_ARGS);
|
||||||
extern Datum int24mi(PG_FUNCTION_ARGS);
|
extern Datum int24mi(PG_FUNCTION_ARGS);
|
||||||
extern Datum int24mul(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 float4mi(float32 arg1, float32 arg2);
|
||||||
extern float32 float4mul(float32 arg1, float32 arg2);
|
extern float32 float4mul(float32 arg1, float32 arg2);
|
||||||
extern float32 float4div(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 float8pl(float64 arg1, float64 arg2);
|
||||||
extern float64 float8mi(float64 arg1, float64 arg2);
|
extern float64 float8mi(float64 arg1, float64 arg2);
|
||||||
extern float64 float8mul(float64 arg1, float64 arg2);
|
extern float64 float8mul(float64 arg1, float64 arg2);
|
||||||
extern float64 float8div(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 float4eq(float32 arg1, float32 arg2);
|
||||||
extern bool float4ne(float32 arg1, float32 arg2);
|
extern bool float4ne(float32 arg1, float32 arg2);
|
||||||
extern bool float4lt(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 dtan(float64 arg1);
|
||||||
extern float64 drandom(void);
|
extern float64 drandom(void);
|
||||||
extern int32 setseed(float64 seed);
|
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 float48pl(float32 arg1, float64 arg2);
|
||||||
extern float64 float48mi(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_div(Numeric num1, Numeric num2);
|
||||||
extern Numeric numeric_mod(Numeric num1, Numeric num2);
|
extern Numeric numeric_mod(Numeric num1, Numeric num2);
|
||||||
extern Numeric numeric_inc(Numeric num);
|
extern Numeric numeric_inc(Numeric num);
|
||||||
extern Numeric numeric_dec(Numeric num);
|
|
||||||
extern Numeric numeric_smaller(Numeric num1, Numeric num2);
|
extern Numeric numeric_smaller(Numeric num1, Numeric num2);
|
||||||
extern Numeric numeric_larger(Numeric num1, Numeric num2);
|
extern Numeric numeric_larger(Numeric num1, Numeric num2);
|
||||||
extern Numeric numeric_sqrt(Numeric num);
|
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 Numeric numeric_power(Numeric num1, Numeric num2);
|
||||||
extern Datum int4_numeric(PG_FUNCTION_ARGS);
|
extern Datum int4_numeric(PG_FUNCTION_ARGS);
|
||||||
extern int32 numeric_int4(Numeric num);
|
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 int64 *numeric_int8(Numeric num);
|
||||||
extern Datum int2_numeric(PG_FUNCTION_ARGS);
|
extern Datum int2_numeric(PG_FUNCTION_ARGS);
|
||||||
extern Datum numeric_int2(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 Numeric float8_numeric(float64 val);
|
||||||
extern float64 numeric_float8(Numeric num);
|
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 */
|
/* lztext.c */
|
||||||
extern lztext *lztextin(char *str);
|
extern lztext *lztextin(char *str);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* 1998 Jan Wieck
|
* 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
|
* 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,
|
* 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
|
* 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
|
typedef struct NumericData
|
||||||
|
@ -75,9 +75,11 @@ typedef NumericData *Numeric;
|
||||||
* fmgr interface macros
|
* fmgr interface macros
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DatumGetNumeric(X) ((Numeric) PG_DETOAST_DATUM(X))
|
#define DatumGetNumeric(X) ((Numeric) PG_DETOAST_DATUM(X))
|
||||||
#define NumericGetDatum(X) PointerGetDatum(X)
|
#define DatumGetNumericCopy(X) ((Numeric) PG_DETOAST_DATUM_COPY(X))
|
||||||
#define PG_GETARG_NUMERIC(n) DatumGetNumeric(PG_GETARG_DATUM(n))
|
#define NumericGetDatum(X) PointerGetDatum(X)
|
||||||
#define PG_RETURN_NUMERIC(x) return NumericGetDatum(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_ */
|
#endif /* _PG_NUMERIC_H_ */
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 interval_mul(PG_FUNCTION_ARGS);
|
||||||
extern Datum mul_d_interval(PG_FUNCTION_ARGS);
|
extern Datum mul_d_interval(PG_FUNCTION_ARGS);
|
||||||
extern Datum interval_div(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_mi(PG_FUNCTION_ARGS);
|
||||||
extern Datum timestamp_pl_span(PG_FUNCTION_ARGS);
|
extern Datum timestamp_pl_span(PG_FUNCTION_ARGS);
|
||||||
|
|
|
@ -386,28 +386,33 @@ create function tcl_int4add(int4,int4) returns int4 as '
|
||||||
return [expr $1 + $2]
|
return [expr $1 + $2]
|
||||||
' language 'pltcl';
|
' language 'pltcl';
|
||||||
|
|
||||||
create function tcl_int4div(int4,int4) returns int4 as '
|
-- We use split(n) as a quick-and-dirty way of parsing the input array
|
||||||
return [expr $1 / $2]
|
-- 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';
|
' language 'pltcl';
|
||||||
|
|
||||||
create function tcl_int4inc(int4) returns int4 as '
|
create function tcl_int4_avg(_int4) returns int4 as '
|
||||||
return [expr $1 + 1]
|
set state [split $1 "{,}"]
|
||||||
|
return [expr {[lindex $state 1] / [lindex $state 2]}]
|
||||||
' language 'pltcl';
|
' language 'pltcl';
|
||||||
|
|
||||||
create aggregate tcl_avg (
|
create aggregate tcl_avg (
|
||||||
sfunc1 = tcl_int4add,
|
sfunc = tcl_int4_accum,
|
||||||
basetype = int4,
|
basetype = int4,
|
||||||
stype1 = int4,
|
stype = _int4,
|
||||||
sfunc2 = tcl_int4inc,
|
finalfunc = tcl_int4_avg,
|
||||||
stype2 = int4,
|
initcond = '{0,0}'
|
||||||
finalfunc = tcl_int4div,
|
|
||||||
initcond2 = '0'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
create aggregate tcl_sum (
|
create aggregate tcl_sum (
|
||||||
sfunc1 = tcl_int4add,
|
sfunc = tcl_int4add,
|
||||||
basetype = int4,
|
basetype = int4,
|
||||||
stype1 = int4,
|
stype = int4,
|
||||||
initcond1 = '0'
|
initcond1 = '0'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,20 @@
|
||||||
-- AGGREGATES
|
-- AGGREGATES
|
||||||
--
|
--
|
||||||
SELECT avg(four) AS avg_1 FROM onek;
|
SELECT avg(four) AS avg_1 FROM onek;
|
||||||
avg_1
|
avg_1
|
||||||
-------
|
--------------
|
||||||
1
|
1.5000000000
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
|
SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
|
||||||
avg_32
|
avg_32
|
||||||
--------
|
---------------
|
||||||
32
|
32.6666666667
|
||||||
(1 row)
|
(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
|
avg_107_943
|
||||||
-------------
|
-------------
|
||||||
107.943
|
107.943
|
||||||
|
@ -116,9 +118,9 @@ select ten, count(four), sum(DISTINCT four) from onek group by ten;
|
||||||
(10 rows)
|
(10 rows)
|
||||||
|
|
||||||
SELECT newavg(four) AS avg_1 FROM onek;
|
SELECT newavg(four) AS avg_1 FROM onek;
|
||||||
avg_1
|
avg_1
|
||||||
-------
|
--------------
|
||||||
1
|
1.5000000000
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT newsum(four) AS sum_1500 FROM onek;
|
SELECT newsum(four) AS sum_1500 FROM onek;
|
||||||
|
|
|
@ -3,18 +3,17 @@
|
||||||
--
|
--
|
||||||
-- all functions CREATEd
|
-- all functions CREATEd
|
||||||
CREATE AGGREGATE newavg (
|
CREATE AGGREGATE newavg (
|
||||||
sfunc1 = int4pl, basetype = int4, stype1 = int4,
|
sfunc = int4_accum, basetype = int4, stype = _numeric,
|
||||||
sfunc2 = int4inc, stype2 = int4,
|
finalfunc = numeric_avg,
|
||||||
finalfunc = int4div,
|
initcond1 = '{0,0,0}'
|
||||||
initcond1 = '0', initcond2 = '0'
|
|
||||||
);
|
);
|
||||||
-- sfunc1 (value-dependent) only
|
-- without finalfunc; test obsolete spellings 'sfunc1' etc
|
||||||
CREATE AGGREGATE newsum (
|
CREATE AGGREGATE newsum (
|
||||||
sfunc1 = int4pl, basetype = int4, stype1 = int4,
|
sfunc1 = int4pl, basetype = int4, stype1 = int4,
|
||||||
initcond1 = '0'
|
initcond1 = '0'
|
||||||
);
|
);
|
||||||
-- sfunc2 (value-independent) only
|
-- value-independent transition function
|
||||||
CREATE AGGREGATE newcnt (
|
CREATE AGGREGATE newcnt (
|
||||||
sfunc2 = int4inc, basetype = int4, stype2 = int4,
|
sfunc = int4inc, basetype = 'any', stype = int4,
|
||||||
initcond2 = '0'
|
initcond = '0'
|
||||||
);
|
);
|
||||||
|
|
|
@ -99,46 +99,18 @@ end;
|
||||||
NOTICE: COMMIT: no transaction in progress
|
NOTICE: COMMIT: no transaction in progress
|
||||||
--
|
--
|
||||||
-- DEFINE AGGREGATE
|
-- 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
|
-- sfunc/finalfunc type disagreement
|
||||||
create aggregate newavg3 (sfunc1 = int4pl,
|
create aggregate newavg2 (sfunc = int4pl,
|
||||||
basetype = int4,
|
basetype = int4,
|
||||||
stype1 = int4,
|
stype = int4,
|
||||||
sfunc2 = int4inc,
|
finalfunc = int2um,
|
||||||
stype2 = int4,
|
initcond = '0');
|
||||||
finalfunc = int2div,
|
ERROR: AggregateCreate: function 'int2um(int4)' does not exist
|
||||||
initcond1 = '0',
|
|
||||||
initcond2 = '0');
|
|
||||||
ERROR: AggregateCreate: 'int2div'('int4','int4') does not exist
|
|
||||||
-- left out basetype
|
-- left out basetype
|
||||||
create aggregate newcnt1 (sfunc2 = int4inc,
|
create aggregate newcnt1 (sfunc = int4inc,
|
||||||
stype2 = int4,
|
stype = int4,
|
||||||
initcond2 = '0');
|
initcond = '0');
|
||||||
ERROR: Define: "basetype" unspecified
|
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
|
-- REMOVE INDEX
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
--
|
--
|
||||||
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
|
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
|
||||||
--
|
--
|
||||||
SELECT oid, pg_aggregate.aggtransfn1
|
SELECT oid, pg_aggregate.aggtransfn
|
||||||
FROM pg_aggregate
|
FROM pg_aggregate
|
||||||
WHERE pg_aggregate.aggtransfn1 != 0 AND
|
WHERE pg_aggregate.aggtransfn != 0 AND
|
||||||
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn1);
|
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn);
|
||||||
oid | aggtransfn1
|
oid | aggtransfn
|
||||||
-----+-------------
|
-----+------------
|
||||||
(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
|
|
||||||
-----+-------------
|
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT oid, pg_aggregate.aggfinalfn
|
SELECT oid, pg_aggregate.aggfinalfn
|
||||||
|
@ -33,20 +25,12 @@ WHERE pg_aggregate.aggbasetype != 0 AND
|
||||||
-----+-------------
|
-----+-------------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT oid, pg_aggregate.aggtranstype1
|
SELECT oid, pg_aggregate.aggtranstype
|
||||||
FROM pg_aggregate
|
FROM pg_aggregate
|
||||||
WHERE pg_aggregate.aggtranstype1 != 0 AND
|
WHERE pg_aggregate.aggtranstype != 0 AND
|
||||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype1);
|
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype);
|
||||||
oid | aggtranstype1
|
oid | aggtranstype
|
||||||
-----+---------------
|
-----+--------------
|
||||||
(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
|
|
||||||
-----+---------------
|
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT oid, pg_aggregate.aggfinaltype
|
SELECT oid, pg_aggregate.aggfinaltype
|
||||||
|
@ -217,6 +201,22 @@ WHERE pg_class.relam != 0 AND
|
||||||
-----+-------
|
-----+-------
|
||||||
(0 rows)
|
(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
|
SELECT oid, pg_index.indexrelid
|
||||||
FROM pg_index
|
FROM pg_index
|
||||||
WHERE pg_index.indexrelid != 0 AND
|
WHERE pg_index.indexrelid != 0 AND
|
||||||
|
|
|
@ -84,9 +84,8 @@ WHERE p1.oid != p2.oid AND
|
||||||
(p1.prorettype < p2.prorettype);
|
(p1.prorettype < p2.prorettype);
|
||||||
prorettype | prorettype
|
prorettype | prorettype
|
||||||
------------+------------
|
------------+------------
|
||||||
18 | 25
|
|
||||||
25 | 1043
|
25 | 1043
|
||||||
(2 rows)
|
(1 row)
|
||||||
|
|
||||||
SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
|
SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
|
||||||
FROM pg_proc AS p1, pg_proc AS p2
|
FROM pg_proc AS p1, pg_proc AS p2
|
||||||
|
@ -98,8 +97,7 @@ WHERE p1.oid != p2.oid AND
|
||||||
proargtypes | proargtypes
|
proargtypes | proargtypes
|
||||||
-------------+-------------
|
-------------+-------------
|
||||||
25 | 1043
|
25 | 1043
|
||||||
1042 | 1043
|
(1 row)
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
|
SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
|
||||||
FROM pg_proc AS p1, pg_proc AS p2
|
FROM pg_proc AS p1, pg_proc AS p2
|
||||||
|
@ -434,83 +432,40 @@ WHERE p1.oprjoin = p2.oid AND
|
||||||
|
|
||||||
-- **************** pg_aggregate ****************
|
-- **************** pg_aggregate ****************
|
||||||
-- Look for illegal values in pg_aggregate fields.
|
-- 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
|
SELECT p1.oid, p1.aggname
|
||||||
FROM pg_aggregate as p1
|
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
|
oid | aggname
|
||||||
-----+---------
|
-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Check combinations of transfer functions.
|
-- If there is no finalfn then the output type must be the transtype.
|
||||||
-- 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.
|
|
||||||
SELECT p1.oid, p1.aggname
|
SELECT p1.oid, p1.aggname
|
||||||
FROM pg_aggregate as p1
|
FROM pg_aggregate as p1
|
||||||
WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 = 0;
|
WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
|
||||||
oid | aggname
|
oid | aggname
|
||||||
-----+---------
|
-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT p1.oid, p1.aggname
|
-- Cross-check transfn against its entry in pg_proc.
|
||||||
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.
|
|
||||||
-- FIXME: what about binary-compatible types?
|
-- 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
|
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||||
WHERE p1.aggtransfn1 = p2.oid AND
|
WHERE p1.aggtransfn = p2.oid AND
|
||||||
(p2.proretset OR p2.pronargs != 2
|
(p2.proretset OR
|
||||||
-- diked out until we find a way of marking binary-compatible types
|
p1.aggtranstype != p2.prorettype OR
|
||||||
-- OR
|
p1.aggtranstype != p2.proargtypes[0] OR
|
||||||
-- p1.aggtranstype1 != p2.prorettype OR
|
NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
|
||||||
-- p1.aggtranstype1 != p2.proargtypes[0] OR
|
(p2.pronargs = 1 AND p1.aggbasetype = 0)));
|
||||||
-- p1.aggbasetype != p2.proargtypes[1]
|
oid | aggname | oid | proname
|
||||||
);
|
-------+---------+-----+-------------
|
||||||
oid | aggname | oid | proname
|
16978 | max | 768 | int4larger
|
||||||
-----+---------+-----+---------
|
16992 | min | 769 | int4smaller
|
||||||
(0 rows)
|
(2 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)
|
|
||||||
|
|
||||||
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
||||||
-- FIXME: what about binary-compatible types?
|
-- 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
|
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||||
WHERE p1.aggfinalfn = p2.oid AND
|
WHERE p1.aggfinalfn = p2.oid AND
|
||||||
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
|
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
|
||||||
p2.pronargs != 2 OR
|
p2.pronargs != 1 OR
|
||||||
p1.aggtranstype1 != p2.proargtypes[0] OR
|
p1.aggtranstype != p2.proargtypes[0]);
|
||||||
p1.aggtranstype2 != p2.proargtypes[1]);
|
|
||||||
oid | aggname | oid | proname
|
oid | aggname | oid | proname
|
||||||
-----+---------+-----+---------
|
-----+---------+-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
|
@ -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(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;
|
SELECT avg(gpa) AS avg_3_4 FROM ONLY student;
|
||||||
|
|
||||||
|
|
|
@ -4,21 +4,20 @@
|
||||||
|
|
||||||
-- all functions CREATEd
|
-- all functions CREATEd
|
||||||
CREATE AGGREGATE newavg (
|
CREATE AGGREGATE newavg (
|
||||||
sfunc1 = int4pl, basetype = int4, stype1 = int4,
|
sfunc = int4_accum, basetype = int4, stype = _numeric,
|
||||||
sfunc2 = int4inc, stype2 = int4,
|
finalfunc = numeric_avg,
|
||||||
finalfunc = int4div,
|
initcond1 = '{0,0,0}'
|
||||||
initcond1 = '0', initcond2 = '0'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
-- sfunc1 (value-dependent) only
|
-- without finalfunc; test obsolete spellings 'sfunc1' etc
|
||||||
CREATE AGGREGATE newsum (
|
CREATE AGGREGATE newsum (
|
||||||
sfunc1 = int4pl, basetype = int4, stype1 = int4,
|
sfunc1 = int4pl, basetype = int4, stype1 = int4,
|
||||||
initcond1 = '0'
|
initcond1 = '0'
|
||||||
);
|
);
|
||||||
|
|
||||||
-- sfunc2 (value-independent) only
|
-- value-independent transition function
|
||||||
CREATE AGGREGATE newcnt (
|
CREATE AGGREGATE newcnt (
|
||||||
sfunc2 = int4inc, basetype = int4, stype2 = int4,
|
sfunc = int4inc, basetype = 'any', stype = int4,
|
||||||
initcond2 = '0'
|
initcond = '0'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -115,44 +115,17 @@ end;
|
||||||
--
|
--
|
||||||
-- DEFINE AGGREGATE
|
-- 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
|
-- sfunc/finalfunc type disagreement
|
||||||
create aggregate newavg3 (sfunc1 = int4pl,
|
create aggregate newavg2 (sfunc = int4pl,
|
||||||
basetype = int4,
|
basetype = int4,
|
||||||
stype1 = int4,
|
stype = int4,
|
||||||
sfunc2 = int4inc,
|
finalfunc = int2um,
|
||||||
stype2 = int4,
|
initcond = '0');
|
||||||
finalfunc = int2div,
|
|
||||||
initcond1 = '0',
|
|
||||||
initcond2 = '0');
|
|
||||||
|
|
||||||
-- left out basetype
|
-- left out basetype
|
||||||
create aggregate newcnt1 (sfunc2 = int4inc,
|
create aggregate newcnt1 (sfunc = int4inc,
|
||||||
stype2 = int4,
|
stype = int4,
|
||||||
initcond2 = '0');
|
initcond = '0');
|
||||||
|
|
||||||
-- left out initcond2 (for sfunc2)
|
|
||||||
create aggregate newcnt1 (sfunc2 = int4inc,
|
|
||||||
basetype = int4,
|
|
||||||
stype2 = int4);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
--
|
--
|
||||||
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
|
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
|
||||||
--
|
--
|
||||||
SELECT oid, pg_aggregate.aggtransfn1
|
SELECT oid, pg_aggregate.aggtransfn
|
||||||
FROM pg_aggregate
|
FROM pg_aggregate
|
||||||
WHERE pg_aggregate.aggtransfn1 != 0 AND
|
WHERE pg_aggregate.aggtransfn != 0 AND
|
||||||
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn1);
|
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn);
|
||||||
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);
|
|
||||||
SELECT oid, pg_aggregate.aggfinalfn
|
SELECT oid, pg_aggregate.aggfinalfn
|
||||||
FROM pg_aggregate
|
FROM pg_aggregate
|
||||||
WHERE pg_aggregate.aggfinalfn != 0 AND
|
WHERE pg_aggregate.aggfinalfn != 0 AND
|
||||||
|
@ -17,14 +13,10 @@ SELECT oid, pg_aggregate.aggbasetype
|
||||||
FROM pg_aggregate
|
FROM pg_aggregate
|
||||||
WHERE pg_aggregate.aggbasetype != 0 AND
|
WHERE pg_aggregate.aggbasetype != 0 AND
|
||||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggbasetype);
|
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
|
FROM pg_aggregate
|
||||||
WHERE pg_aggregate.aggtranstype1 != 0 AND
|
WHERE pg_aggregate.aggtranstype != 0 AND
|
||||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype1);
|
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype);
|
||||||
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);
|
|
||||||
SELECT oid, pg_aggregate.aggfinaltype
|
SELECT oid, pg_aggregate.aggfinaltype
|
||||||
FROM pg_aggregate
|
FROM pg_aggregate
|
||||||
WHERE pg_aggregate.aggfinaltype != 0 AND
|
WHERE pg_aggregate.aggfinaltype != 0 AND
|
||||||
|
@ -109,6 +101,14 @@ SELECT oid, pg_class.relam
|
||||||
FROM pg_class
|
FROM pg_class
|
||||||
WHERE pg_class.relam != 0 AND
|
WHERE pg_class.relam != 0 AND
|
||||||
NOT EXISTS(SELECT * FROM pg_am AS t1 WHERE t1.oid = pg_class.relam);
|
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
|
SELECT oid, pg_index.indexrelid
|
||||||
FROM pg_index
|
FROM pg_index
|
||||||
WHERE pg_index.indexrelid != 0 AND
|
WHERE pg_index.indexrelid != 0 AND
|
||||||
|
|
|
@ -363,66 +363,32 @@ WHERE p1.oprjoin = p2.oid AND
|
||||||
-- **************** pg_aggregate ****************
|
-- **************** pg_aggregate ****************
|
||||||
|
|
||||||
-- Look for illegal values in pg_aggregate fields.
|
-- 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
|
SELECT p1.oid, p1.aggname
|
||||||
FROM pg_aggregate as p1
|
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.
|
-- If there is no finalfn then the output type must be the transtype.
|
||||||
-- 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.
|
|
||||||
|
|
||||||
SELECT p1.oid, p1.aggname
|
SELECT p1.oid, p1.aggname
|
||||||
FROM pg_aggregate as p1
|
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
|
-- Cross-check transfn against its entry in pg_proc.
|
||||||
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.
|
|
||||||
-- FIXME: what about binary-compatible types?
|
-- 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
|
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||||
WHERE p1.aggtransfn1 = p2.oid AND
|
WHERE p1.aggtransfn = p2.oid AND
|
||||||
(p2.proretset OR p2.pronargs != 2
|
(p2.proretset OR
|
||||||
-- diked out until we find a way of marking binary-compatible types
|
p1.aggtranstype != p2.prorettype OR
|
||||||
-- OR
|
p1.aggtranstype != p2.proargtypes[0] OR
|
||||||
-- p1.aggtranstype1 != p2.prorettype OR
|
NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
|
||||||
-- p1.aggtranstype1 != p2.proargtypes[0] OR
|
(p2.pronargs = 1 AND p1.aggbasetype = 0)));
|
||||||
-- 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]);
|
|
||||||
|
|
||||||
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
||||||
-- FIXME: what about binary-compatible types?
|
-- 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
|
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||||
WHERE p1.aggfinalfn = p2.oid AND
|
WHERE p1.aggfinalfn = p2.oid AND
|
||||||
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
|
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
|
||||||
p2.pronargs != 2 OR
|
p2.pronargs != 1 OR
|
||||||
p1.aggtranstype1 != p2.proargtypes[0] OR
|
p1.aggtranstype != p2.proargtypes[0]);
|
||||||
p1.aggtranstype2 != p2.proargtypes[1]);
|
|
||||||
|
|
||||||
-- **************** pg_opclass ****************
|
-- **************** pg_opclass ****************
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
--
|
--
|
||||||
-- Copyright (c) 1994, Regents of the University of California
|
-- 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 (
|
CREATE AGGREGATE complex_sum (
|
||||||
sfunc1 = complex_add,
|
sfunc = complex_add,
|
||||||
basetype = complex,
|
basetype = complex,
|
||||||
stype1 = complex,
|
stype = complex,
|
||||||
initcond1 = '(0,0)'
|
initcond = '(0,0)'
|
||||||
);
|
);
|
||||||
|
|
||||||
SELECT complex_sum(a) FROM test_complex;
|
SELECT complex_sum(a) FROM test_complex;
|
||||||
|
|
Loading…
Reference in New Issue