]> granicus.if.org Git - postgresql/commitdiff
Revise aggregate functions per earlier discussions in pghackers.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Jul 2000 03:05:41 +0000 (03:05 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Jul 2000 03:05:41 +0000 (03:05 +0000)
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...

55 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/create_aggregate.sgml
doc/src/sgml/ref/drop_aggregate.sgml
doc/src/sgml/xaggr.sgml
src/backend/catalog/pg_aggregate.c
src/backend/commands/define.c
src/backend/commands/user.c
src/backend/executor/execQual.c
src/backend/executor/execScan.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeNestloop.c
src/backend/executor/nodeResult.c
src/backend/libpq/be-fsstubs.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/parser/parse_agg.c
src/backend/postmaster/postmaster.c
src/backend/storage/lmgr/lock.c
src/backend/storage/smgr/md.c
src/backend/tcop/postgres.c
src/backend/tcop/pquery.c
src/backend/utils/adt/arrayfuncs.c
src/backend/utils/adt/float.c
src/backend/utils/adt/int.c
src/backend/utils/adt/numeric.c
src/backend/utils/adt/timestamp.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/include/c.h
src/include/catalog/catversion.h
src/include/catalog/pg_aggregate.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/nodes/primnodes.h
src/include/storage/lock.h
src/include/utils/array.h
src/include/utils/builtins.h
src/include/utils/numeric.h
src/include/utils/timestamp.h
src/pl/tcl/test/test_setup.sql
src/test/regress/expected/aggregates.out
src/test/regress/expected/create_aggregate.out
src/test/regress/expected/errors.out
src/test/regress/expected/oidjoins.out
src/test/regress/expected/opr_sanity.out
src/test/regress/sql/aggregates.sql
src/test/regress/sql/create_aggregate.sql
src/test/regress/sql/errors.sql
src/test/regress/sql/oidjoins.sql
src/test/regress/sql/opr_sanity.sql
src/tutorial/complex.source

index 91cea30605fee9a0bd6cb4c897041d31f76c9877..1613774f26be2981842625b7b2f36f30479f308a 100644 (file)
@@ -1,6 +1,6 @@
 .\" This is -*-nroff-*-
 .\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.6 2000/06/09 01:43:56 momjian Exp $
+.\" $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.7 2000/07/17 03:04:40 tgl Exp $
 .TH "SYSTEM CATALOGS" INTRO 03/13/94 PostgreSQL PostgreSQL
 .SH "Section 7 - System Catalogs"
 .de LS
@@ -91,20 +91,16 @@ The following catalogs relate to the class/type system.
  * see DEFINE AGGREGATE for an explanation of transition functions
  */
 pg_aggregate
-    NameData      aggname      /* aggregate name (e.g., "count") */
+    NameData    aggname                /* aggregate name (e.g., "count") */
     oid         aggowner       /* usesysid of creator */
-    regproc     aggtransfn1    /* first transition function */
-    regproc     aggtransfn2    /* second transition function */
+    regproc     aggtransfn     /* transition function */
     regproc     aggfinalfn     /* final function */
     oid         aggbasetype    /* type of data on which aggregate
                                   operates */
-    oid         aggtranstype1  /* type returned by aggtransfn1 */
-    oid         aggtranstype2  /* type returned by aggtransfn2 */
-    oid         aggfinaltype   /* type returned by aggfinalfn */
-    text        agginitval1    /* external format of initial
-                                  (starting) value of aggtransfn1 */
-    text        agginitval2    /* external format of initial
-                                  (starting) value of aggtransfn2 */
+    oid         aggtranstype   /* type of aggregate's transition
+                                  (state) data */
+    oid         aggfinaltype   /* type of aggregate's final result */
+    text        agginitval     /* external format of initial state value */
 .fi
 .nf M
 pg_am
index 44291458d60a9cfbe71ab93aa0cadd98335c9e88..07b45c112aa7ca88b8bac146501875f4687b950f 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.9 2000/03/31 14:57:05 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.10 2000/07/17 03:04:41 tgl Exp $
 Postgres documentation
 -->
 
@@ -21,20 +21,18 @@ Postgres documentation
  </refnamediv>
  <refsynopsisdiv>
   <refsynopsisdivinfo>
-   <date>1999-07-20</date>
+   <date>2000-07-16</date>
   </refsynopsisdivinfo>
   <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE = <replaceable class="PARAMETER">input_data_type</replaceable>
-    [ , SFUNC1 = <replaceable class="PARAMETER">sfunc1</replaceable>, STYPE1 = <replaceable class="PARAMETER">state1_type</replaceable> ]
-    [ , SFUNC2 = <replaceable class="PARAMETER">sfunc2</replaceable>, STYPE2 = <replaceable class="PARAMETER">state2_type</replaceable> ]
+CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE = <replaceable class="PARAMETER">input_data_type</replaceable>,
+    SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>, STYPE = <replaceable class="PARAMETER">state_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
-    [ , INITCOND1 = <replaceable class="PARAMETER">initial_condition1</replaceable> ]
-    [ , INITCOND2 = <replaceable class="PARAMETER">initial_condition2</replaceable> ] )
+    [ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ] )
   </synopsis>
 
   <refsect2 id="R2-SQL-CREATEAGGREGATE-1">
    <refsect2info>
-    <date>1998-09-09</date>
+    <date>2000-07-16</date>
    </refsect2info>
    <title>
     Inputs
@@ -55,57 +53,39 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE =
       <listitem>
        <para>
        The input data type on which this aggregate function operates.
+       This can be specified as ANY for an aggregate that does not
+       examine its input values
+       (an example is <function>count(*)</function>).
        </para>
       </listitem>
      </varlistentry>
 
      <varlistentry>
-      <term><replaceable class="PARAMETER">sfunc1</replaceable></term>
+      <term><replaceable class="PARAMETER">sfunc</replaceable></term>
       <listitem>
        <para>
-       A state transition function
-       to be called for every non-NULL input data value.
-       This must be a function of two arguments, the first being of
-       type <replaceable class="PARAMETER">state1_type</replaceable>
+       The name of the state transition function
+       to be called for each input data value.
+       This is normally a function of two arguments, the first being of
+       type <replaceable class="PARAMETER">state_type</replaceable>
        and the second of
        type <replaceable class="PARAMETER">input_data_type</replaceable>.
-       The function must return a value of
-       type <replaceable class="PARAMETER">state1_type</replaceable>.
-       This function takes the current state value 1 and the current
-       input data item, and returns the next state value 1.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">state1_type</replaceable></term>
-      <listitem>
-       <para>
-       The data type for the first state value of the aggregate.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">sfunc2</replaceable></term>
-      <listitem>
-       <para>
-       A state transition function
-       to be called for every non-NULL input data value.
-       This must be a function of one argument of
-       type <replaceable class="PARAMETER">state2_type</replaceable>,
-       returning a value of the same type.
-       This function takes the current state value 2 and
-       returns the next state value 2.
+       Alternatively, for an aggregate that does not examine its input
+       values, the function takes just one argument of
+       type <replaceable class="PARAMETER">state_type</replaceable>.
+       In either case the function must return a value of
+       type <replaceable class="PARAMETER">state_type</replaceable>.
+       This function takes the current state value and the current
+       input data item, and returns the next state value.
        </para>
       </listitem>
      </varlistentry>
 
      <varlistentry>
-      <term><replaceable class="PARAMETER">state2_type</replaceable></term>
+      <term><replaceable class="PARAMETER">state_type</replaceable></term>
       <listitem>
        <para>
-       The data type for the second state value of the aggregate.
+       The data type for the aggregate's state value.
        </para>
       </listitem>
      </varlistentry>
@@ -114,35 +94,28 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( BASETYPE =
       <term><replaceable class="PARAMETER">ffunc</replaceable></term>
       <listitem>
        <para>
-       The final function called to compute the aggregate's result
-       after all input data has been traversed.
-       If both state values are used, the final function must
-       take two arguments of types
-       <replaceable class="PARAMETER">state1_type</replaceable>
-       and
-       <replaceable class="PARAMETER">state2_type</replaceable>.
-       If only one state value is used, the final function must
-       take a single argument of that state value's type.
+       The name of the final function called to compute the aggregate's
+       result after all input data has been traversed.  The function
+       must take a single argument of type
+       <replaceable class="PARAMETER">state_type</replaceable>.
        The output datatype of the aggregate is defined as the return
        type of this function.
+       If <replaceable class="PARAMETER">ffunc</replaceable>
+       is not specified, then the ending state value is used as the
+       aggregate's result, and the output type is
+       <replaceable class="PARAMETER">state_type</replaceable>.
        </para>
       </listitem>
      </varlistentry>
 
      <varlistentry>
-      <term><replaceable class="PARAMETER">initial_condition1</replaceable></term>
+      <term><replaceable class="PARAMETER">initial_condition</replaceable></term>
       <listitem>
        <para>
-       The initial value for state value 1.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="PARAMETER">initial_condition2</replaceable></term>
-      <listitem>
-       <para>
-       The initial value for state value 2.
+       The initial setting for the state value.  This must be a literal
+       constant in the form accepted for the datatype
+       <replaceable class="PARAMETER">state_type</replaceable>.
+       If not specified, the state value starts out NULL.
        </para>
       </listitem>
      </varlistentry>
@@ -177,7 +150,7 @@ CREATE
 
  <refsect1 id="R1-SQL-CREATEAGGREGATE-1">
   <refsect1info>
-   <date>1998-09-09</date>
+   <date>2000-07-16</date>
   </refsect1info>
   <title>
    Description
@@ -199,65 +172,76 @@ CREATE
    of the same name and input data type as an aggregate.
   </para>
   <para>
-   An  aggregate  function is made from between one and three ordinary
+   An  aggregate function is made from one or two ordinary
    functions:
-   two state transition functions, 
-   <replaceable class="PARAMETER">sfunc1</replaceable>
-   and <replaceable class="PARAMETER">sfunc2</replaceable>,
-   and a final calculation function,
+   a state transition function
+   <replaceable class="PARAMETER">sfunc</replaceable>,
+   and an optional final calculation function
    <replaceable class="PARAMETER">ffunc</replaceable>.
    These are used as follows:
    <programlisting>
-<replaceable class="PARAMETER">sfunc1</replaceable>( internal-state1, next-data-item ) ---> next-internal-state1
-<replaceable class="PARAMETER">sfunc2</replaceable>( internal-state2 ) ---> next-internal-state2
-<replaceable class="PARAMETER">ffunc</replaceable>(internal-state1, internal-state2) ---> aggregate-value
+<replaceable class="PARAMETER">sfunc</replaceable>( internal-state, next-data-item ) ---> next-internal-state
+<replaceable class="PARAMETER">ffunc</replaceable>( internal-state ) ---> aggregate-value
    </programlisting>
   </para>
   <para>
-   <productname>Postgres</productname> creates one or two temporary variables
-   (of data types <replaceable class="PARAMETER">stype1</replaceable> and/or
-   <replaceable class="PARAMETER">stype2</replaceable>) to hold the
-   current internal states of the aggregate.  At each input data item,
-   the state transition function(s) are invoked to calculate new values
-   for the internal state values.  After all the data has been processed,
+   <productname>Postgres</productname> creates a temporary variable
+   of data type <replaceable class="PARAMETER">stype</replaceable>
+   to hold the current internal state of the aggregate.  At each input
+   data item,
+   the state transition function is invoked to calculate a new
+   internal state value.  After all the data has been processed,
    the final function is invoked once to calculate the aggregate's output
-   value.
+   value.  If there is no final function then the ending state value
+   is returned as-is.
   </para>
+  
   <para>
-   <replaceable class="PARAMETER">ffunc</replaceable> must be specified if
-   both transition functions are specified.  If only one transition function
-   is used, then <replaceable class="PARAMETER">ffunc</replaceable> is
-   optional.  The default behavior when
-   <replaceable class="PARAMETER">ffunc</replaceable> is not provided is
-   to return the ending value of the internal state value being used
-   (and, therefore, the aggregate's output type is the same as that
-   state value's type).
-  </para>  
+   An aggregate function may provide an initial condition,
+   that is, an initial value for the internal state value.
+   This is specified and stored in the database as a field of type
+   <type>text</type>, but it must be a valid external representation
+   of a constant of the state value datatype.  If it is not supplied
+   then the state value starts out NULL.
+  </para>
   
-  <para>       
-   An aggregate function may also provide one or two initial conditions,
-   that is, initial values for the internal state values being used.
-   These are specified and  stored in the database as fields of type
-   <type>text</type>, but they must be valid external representations
-   of constants of the state value datatypes.  If
-   <replaceable class="PARAMETER">sfunc1</replaceable> is specified 
-   without an <replaceable class="PARAMETER">initcond1</replaceable> value,
-   then the system does not call
-   <replaceable class="PARAMETER">sfunc1</replaceable> 
-   at the first input item; instead, the internal state value 1 is
-   initialized with the first input value, and
-   <replaceable class="PARAMETER">sfunc1</replaceable> is called beginning 
-   at the second input item.  This is useful for aggregates like MIN and
-   MAX.  Note that an aggregate using this feature will return NULL when
-   called with no input values.  There is no comparable provision for
-   state value 2; if <replaceable class="PARAMETER">sfunc2</replaceable> is
-   specified then an <replaceable class="PARAMETER">initcond2</replaceable> is
-   required.
+  <para>
+   If the state transition function is declared "strict" in pg_proc,
+   then it cannot be called with NULL inputs.  With such a transition
+   function, aggregate execution behaves as follows.  NULL input values
+   are ignored (the function is not called and the previous state value
+   is retained).  If the initial state value is NULL, then the first
+   non-NULL input value replaces the state value, and the transition
+   function is invoked beginning with the second non-NULL input value.
+   This is handy for implementing aggregates like <function>max</function>.
+   Note that this behavior is only available when
+   <replaceable class="PARAMETER">state_type</replaceable>
+   is the same as
+   <replaceable class="PARAMETER">input_data_type</replaceable>.
+   When these types are different, you must supply a non-NULL initial
+   condition or use a non-strict transition function.
+  </para>
+  
+  <para>
+   If the state transition function is not strict, then it will be called
+   unconditionally at each input value, and must deal with NULL inputs
+   and NULL transition values for itself.  This allows the aggregate
+   author to have full control over the aggregate's handling of NULLs.
+  </para>
+  
+  <para>
+   If the final function is declared "strict", then it will not
+   be called when the ending state value is NULL; instead a NULL result
+   will be output automatically.  (Of course this is just the normal
+   behavior of strict functions.)  In any case the final function has
+   the option of returning NULL.  For example, the final function for
+   <function>avg</function> returns NULL when it sees there were zero
+   input tuples.
   </para>
   
   <refsect2 id="R2-SQL-CREATEAGGREGATE-3">
    <refsect2info>
-    <date>1998-09-09</date>
+    <date>2000-07-16</date>
    </refsect2info>
    <title>
     Notes
@@ -272,29 +256,6 @@ CREATE
     in any order, not just the order illustrated above.
    </para>
 
-   <para>
-    It  is possible to specify aggregate functions
-    that have varying combinations of state  and  final  functions. 
-    For example, the <function>count</function> aggregate requires
-    <replaceable class="PARAMETER">sfunc2</replaceable> 
-    (an incrementing function) but not
-    <replaceable class="PARAMETER">sfunc1</replaceable>  or  
-    <replaceable class="PARAMETER">ffunc</replaceable>,
-    whereas  the  <function>sum</function> aggregate requires
-    <replaceable class="PARAMETER">sfunc1</replaceable> (an addition
-    function) but not <replaceable class="PARAMETER">sfunc2</replaceable> or
-    <replaceable class="PARAMETER">ffunc</replaceable>,  and  the
-    <function>avg</function>
-    aggregate  requires 
-    both state functions as
-    well as a <replaceable class="PARAMETER">ffunc</replaceable> (a division
-    function) to  produce  its 
-    answer.   In any case, at least one state function must be
-    defined, and any <replaceable class="PARAMETER">sfunc2</replaceable> must
-    have  a  corresponding
-    <replaceable class="PARAMETER">initcond2</replaceable>. 
-   </para>
-
   </refsect2>
  </refsect1>
 
index 465f5d6421588cf0aed51cc4f348a105a27016f0..8efc31a732e695852baddcb3ae7fb8d2bc6495b5 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_aggregate.sgml,v 1.7 2000/05/18 14:24:32 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_aggregate.sgml,v 1.8 2000/07/17 03:04:41 tgl Exp $
 Postgres documentation
 -->
 
@@ -49,7 +49,7 @@ DROP AGGREGATE <replaceable class="PARAMETER">name</replaceable> <replaceable cl
        <para>
        The type of an existing aggregate function.
        (Refer to the <citetitle>PostgreSQL User's Guide</citetitle> for
-       further information about data types).
+       further information about data types.)
        <comment>This should become a cross-reference rather than a
         hard-coded chapter number</comment>
        </para>
@@ -80,7 +80,7 @@ DROP
      </varlistentry>
      <varlistentry>
       <term><computeroutput>
-NOTICE RemoveAggregate: aggregate '<replaceable class="parameter">agg</replaceable>' for '<replaceable class="parameter">type</replaceable>' does not exist
+ERROR: RemoveAggregate: aggregate '<replaceable class="parameter">agg</replaceable>' for '<replaceable class="parameter">type</replaceable>' does not exist
        </computeroutput></term>
       <listitem>
        <para>
index 8d5cb93a2d904536c5d5dbbaee7f19d17360e4e5..c1e32f9b015bbb66602755a797258002b6ade21e 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.7 2000/03/31 03:27:41 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.8 2000/07/17 03:04:40 tgl Exp $
 -->
 
  <chapter id="xaggr">
@@ -16,39 +16,20 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.7 2000/03/31 03:27:41 thomas
    an initial value for the state, and a state transition
    function.  The state transition function is just an
    ordinary function that could also be used outside the
-   context of the aggregate.
+   context of the aggregate.  A <firstterm>final function</firstterm>
+   can also be specified, in case the desired output of the aggregate
+   is different from the data that needs to be kept in the running
+   state value.
   </para>
 
   <para>
-   Actually, in order to make it easier to construct useful
-   aggregates from existing functions, an aggregate can have
-   one or two separate state values, one or two transition
-   functions to update those state values, and a
-   <firstterm>final function</firstterm> that computes the
-   actual aggregate result from the ending state values.
+   Thus, in addition to the input and result datatypes seen by a user
+   of the aggregate, there is an internal state-value datatype that
+   may be different from both the input and result types.
   </para>
 
   <para>
-   Thus there can be as many as four datatypes involved:
-   the type of the input data items, the type of the aggregate's
-   result, and the types of the two state values.  Only the
-   input and result datatypes are seen by a user of the aggregate.
-  </para>
-
-  <para>
-   Some state transition functions need to look at each successive
-   input to compute the next state value, while others ignore the
-   specific input value and simply update their internal state.
-   (The most useful example of the second kind is a running count
-   of the number of input items.)  The <productname>Postgres</productname>
-   aggregate machinery defines <acronym>sfunc1</acronym> for
-   an aggregate as a function that is passed both the old state
-   value and the current input value, while <acronym>sfunc2</acronym>
-   is a function that is passed only the old state value.
-  </para>
-
-  <para>
-   If we define an aggregate that  uses  only <acronym>sfunc1</acronym>,
+   If we define an aggregate that does not use a final function,
    we have an aggregate that computes a running function of
    the attribute values from each instance.  "Sum"  is  an
    example  of  this  kind  of aggregate.  "Sum" starts at
@@ -60,10 +41,10 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xaggr.sgml,v 1.7 2000/03/31 03:27:41 thomas
    
    <programlisting>
 CREATE AGGREGATE complex_sum (
-    sfunc1 = complex_add,
+    sfunc = complex_add,
     basetype = complex,
-    stype1 = complex,
-    initcond1 = '(0,0)'
+    stype = complex,
+    initcond = '(0,0)'
 );
 
 SELECT complex_sum(a) FROM test_complex;
@@ -81,67 +62,48 @@ SELECT complex_sum(a) FROM test_complex;
   </para>
 
   <para>
-   If we define only <acronym>sfunc2</acronym>, we are 
-   specifying  an  aggregate  
-   that computes a running function that is independent  of  
-   the  attribute  values  from  each  instance.
-   "Count"  is  the  most  common  example of this kind of
-   aggregate.  "Count" starts at zero and adds one to  its
-   running  total for each instance, ignoring the instance
-   value.  Here, we use the built-in 
-   <acronym>int4inc</acronym> routine to do
-   the work for us.  This routine increments (adds one to)
-   its argument.
-   
-   <programlisting>
-CREATE AGGREGATE my_count (
-    sfunc2 = int4inc, -- add one
-    basetype = int4,
-    stype2 = int4,
-    initcond2 = '0'
-);
-
-SELECT my_count(*) as emp_count from EMP;
-
-         +----------+
-         |emp_count |
-         +----------+
-         |5         |
-         +----------+
-   </programlisting>
+   The above definition of "Sum" will return zero (the initial
+   state condition) if there are no non-null input values.
+   Perhaps we want to return NULL in that case instead --- SQL92
+   expects "Sum" to behave that way.  We can do this simply by
+   omitting the "initcond" phrase, so that the initial state
+   condition is NULL.  Ordinarily this would mean that the sfunc
+   would need to check for a NULL state-condition input, but for
+   "Sum" and some other simple aggregates like "Max" and "Min",
+   it's sufficient to insert the first non-null input value into
+   the state variable and then start applying the transition function
+   at the second non-null input value.  <productname>Postgres</productname>
+   will do that automatically if the initial condition is NULL and
+   the transition function is marked "strict" (ie, not to be called
+   for NULL inputs).
   </para>
   
   <para>
-   "Average" is an example of an aggregate  that  requires
-   both  a function to compute the running sum and a function 
-   to compute the running count.   When  all  of  the
-   instances have been processed, the final answer for the
-   aggregate is the running sum  divided  by  the  running
-   count.   We use the <acronym>int4pl</acronym> and
-   <acronym>int4inc</acronym> routines we used
-   before as well as the <productname>Postgres</productname>  integer  division  
-   routine,  <acronym>int4div</acronym>,  to  compute the division of the sum by
-   the count.
-   
+   Another bit of default behavior for a "strict" transition function
+   is that the previous state value is retained unchanged whenever a
+   NULL input value is encountered.  Thus, NULLs are ignored.  If you
+   need some other behavior for NULL inputs, just define your transition
+   function as non-strict, and code it to test for NULL inputs and do
+   whatever is needed.
+  </para>
+  
+  <para>
+   "Average" is a more complex example of an aggregate.  It requires
+   two pieces of running state: the sum of the inputs and the count
+   of the number of inputs.  The final result is obtained by dividing
+   these quantities.  Average is typically implemented by using a
+   two-element array as the transition state value.  For example,
+   the built-in implementation of <function>avg(float8)</function>
+   looks like:
+
    <programlisting>
-CREATE AGGREGATE my_average (
-    sfunc1 = int4pl,     --  sum
-    basetype = int4,
-    stype1 = int4,
-    sfunc2 = int4inc,    -- count
-    stype2 = int4,
-    finalfunc = int4div, -- division
-    initcond1 = '0',
-    initcond2 = '0'
+CREATE AGGREGATE avg (
+    sfunc = float8_accum,
+    basetype = float8,
+    stype = _float8,
+    finalfunc = float8_avg,
+    initcond = '{0,0}'
 );
-
-SELECT my_average(salary) as emp_average FROM EMP;
-
-         +------------+
-         |emp_average |
-         +------------+
-         |1640        |
-         +------------+
    </programlisting>
   </para>
 
index f068c897ec13e732d238e572a691cd37525962e6..e3fa7c5535be56ed69d40570b9b2ab1d49982548 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.34 2000/07/05 23:11:07 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.35 2000/07/17 03:04:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,8 @@
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
+#include "parser/parse_coerce.h"
+#include "parser/parse_func.h"
 #include "utils/builtins.h"
 #include "utils/syscache.h"
 
  *             Currently, redefining aggregates using the same name is not
  *             supported.      In such a case, a warning is printed that the
  *             aggregate already exists.  If such is not the case, a new tuple
- *             is created and inserted in the aggregate relation.      The fields
- *             of this tuple are aggregate name, owner id, 2 transition functions
- *             (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
- *             type of data on which aggtransfn1 operates (aggbasetype), return
- *             types of the two transition functions (aggtranstype1 and
- *             aggtranstype2), final return type (aggfinaltype), and initial values
- *             for the two state transition functions (agginitval1 and agginitval2).
+ *             is created and inserted in the aggregate relation.
  *             All types and functions must have been defined
  *             prior to defining the aggregate.
  *
  */
 void
 AggregateCreate(char *aggName,
-                               char *aggtransfn1Name,
-                               char *aggtransfn2Name,
+                               char *aggtransfnName,
                                char *aggfinalfnName,
                                char *aggbasetypeName,
-                               char *aggtransfn1typeName,
-                               char *aggtransfn2typeName,
-                               char *agginitval1,
-                               char *agginitval2)
+                               char *aggtranstypeName,
+                               char *agginitval)
 {
-       int                     i;
        Relation        aggdesc;
        HeapTuple       tup;
        char            nulls[Natts_pg_aggregate];
        Datum           values[Natts_pg_aggregate];
        Form_pg_proc proc;
-       Oid                     xfn1 = InvalidOid;
-       Oid                     xfn2 = InvalidOid;
-       Oid                     ffn = InvalidOid;
-       Oid                     xbase = InvalidOid;
-       Oid                     xret1 = InvalidOid;
-       Oid                     xret2 = InvalidOid;
-       Oid                     fret = InvalidOid;
+       Oid                     transfn;
+       Oid                     finalfn = InvalidOid; /* can be omitted */
+       Oid                     basetype;
+       Oid                     transtype;
+       Oid                     finaltype;
        Oid                     fnArgs[FUNC_MAX_ARGS];
+       int                     nargs;
        NameData        aname;
        TupleDesc       tupDesc;
+       int                     i;
 
        MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
@@ -82,143 +74,112 @@ AggregateCreate(char *aggName,
        if (!aggName)
                elog(ERROR, "AggregateCreate: no aggregate name supplied");
 
-       if (!aggtransfn1Name && !aggtransfn2Name)
-               elog(ERROR, "AggregateCreate: aggregate must have at least one transition function");
-
-       if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
-               elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
+       if (!aggtransfnName)
+               elog(ERROR, "AggregateCreate: aggregate must have a transition function");
 
-       /* handle the aggregate's base type (input data type) */
+       /*
+        * Handle the aggregate's base type (input data type).  This can be
+        * specified as 'ANY' for a data-independent transition function,
+        * such as COUNT(*).
+        */
        tup = SearchSysCacheTuple(TYPENAME,
                                                          PointerGetDatum(aggbasetypeName),
                                                          0, 0, 0);
-       if (!HeapTupleIsValid(tup))
-               elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
-       xbase = tup->t_data->t_oid;
+       if (HeapTupleIsValid(tup))
+       {
+               basetype = tup->t_data->t_oid;
+               Assert(OidIsValid(basetype));
+       }
+       else
+       {
+               if (strcasecmp(aggbasetypeName, "ANY") != 0)
+                       elog(ERROR, "AggregateCreate: Type '%s' undefined",
+                                aggbasetypeName);
+               basetype = InvalidOid;
+       }
 
        /* make sure there is no existing agg of same name and base type */
        tup = SearchSysCacheTuple(AGGNAME,
                                                          PointerGetDatum(aggName),
-                                                         ObjectIdGetDatum(xbase),
+                                                         ObjectIdGetDatum(basetype),
                                                          0, 0);
        if (HeapTupleIsValid(tup))
                elog(ERROR,
                         "AggregateCreate: aggregate '%s' with base type '%s' already exists",
                         aggName, aggbasetypeName);
 
-       /* handle transfn1 and transtype1 */
-       if (aggtransfn1Name)
+       /* handle transtype */
+       tup = SearchSysCacheTuple(TYPENAME,
+                                                         PointerGetDatum(aggtranstypeName),
+                                                         0, 0, 0);
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "AggregateCreate: Type '%s' undefined",
+                        aggtranstypeName);
+       transtype = tup->t_data->t_oid;
+       Assert(OidIsValid(transtype));
+
+       /* handle transfn */
+       fnArgs[0] = transtype;
+       if (OidIsValid(basetype))
        {
-               tup = SearchSysCacheTuple(TYPENAME,
-                                                                 PointerGetDatum(aggtransfn1typeName),
-                                                                 0, 0, 0);
-               if (!HeapTupleIsValid(tup))
-                       elog(ERROR, "AggregateCreate: Type '%s' undefined",
-                                aggtransfn1typeName);
-               xret1 = tup->t_data->t_oid;
-
-               fnArgs[0] = xret1;
-               fnArgs[1] = xbase;
-               tup = SearchSysCacheTuple(PROCNAME,
-                                                                 PointerGetDatum(aggtransfn1Name),
-                                                                 Int32GetDatum(2),
-                                                                 PointerGetDatum(fnArgs),
-                                                                 0);
-               if (!HeapTupleIsValid(tup))
-                       elog(ERROR, "AggregateCreate: '%s('%s', '%s') does not exist",
-                                aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
-               if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
-                       elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
-                                aggtransfn1Name, aggtransfn1typeName);
-               xfn1 = tup->t_data->t_oid;
-               if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
-                       !OidIsValid(xbase))
-                       elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn1Name);
+               fnArgs[1] = basetype;
+               nargs = 2;
        }
-
-       /* handle transfn2 and transtype2 */
-       if (aggtransfn2Name)
+       else
        {
-               tup = SearchSysCacheTuple(TYPENAME,
-                                                                 PointerGetDatum(aggtransfn2typeName),
-                                                                 0, 0, 0);
-               if (!HeapTupleIsValid(tup))
-                       elog(ERROR, "AggregateCreate: Type '%s' undefined",
-                                aggtransfn2typeName);
-               xret2 = tup->t_data->t_oid;
-
-               fnArgs[0] = xret2;
-               fnArgs[1] = 0;
-               tup = SearchSysCacheTuple(PROCNAME,
-                                                                 PointerGetDatum(aggtransfn2Name),
-                                                                 Int32GetDatum(1),
-                                                                 PointerGetDatum(fnArgs),
-                                                                 0);
-               if (!HeapTupleIsValid(tup))
-                       elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
-                                aggtransfn2Name, aggtransfn2typeName);
-               if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
-                       elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
-                                aggtransfn2Name, aggtransfn2typeName);
-               xfn2 = tup->t_data->t_oid;
-               if (!OidIsValid(xfn2) || !OidIsValid(xret2))
-                       elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn2Name);
+               nargs = 1;
+       }
+       tup = SearchSysCacheTuple(PROCNAME,
+                                                         PointerGetDatum(aggtransfnName),
+                                                         Int32GetDatum(nargs),
+                                                         PointerGetDatum(fnArgs),
+                                                         0);
+       if (!HeapTupleIsValid(tup))
+               func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
+       transfn = tup->t_data->t_oid;
+       proc = (Form_pg_proc) GETSTRUCT(tup);
+       if (proc->prorettype != transtype)
+               elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
+                        aggtransfnName, aggtranstypeName);
+       Assert(OidIsValid(transfn));
+       /*
+        * If the transfn is strict and the initval is NULL, make sure
+        * input type and transtype are the same (or at least binary-
+        * compatible), so that it's OK to use the first input value
+        * as the initial transValue.
+        */
+       if (((Form_pg_proc) GETSTRUCT(tup))->proisstrict && agginitval == NULL)
+       {
+               if (basetype != transtype &&
+                       ! IS_BINARY_COMPATIBLE(basetype, transtype))
+                       elog(ERROR, "AggregateCreate: must not omit initval when transfn is strict and transtype is not compatible with input type");
        }
 
-       /* handle finalfn */
+       /* handle finalfn, if supplied */
        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 */
+               fnArgs[0] = transtype;
+               fnArgs[1] = 0;
                tup = SearchSysCacheTuple(PROCNAME,
                                                                  PointerGetDatum(aggfinalfnName),
-                                                                 Int32GetDatum(nargs),
+                                                                 Int32GetDatum(1),
                                                                  PointerGetDatum(fnArgs),
                                                                  0);
                if (!HeapTupleIsValid(tup))
-               {
-                       if (nargs == 2)
-                               elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist",
-                               aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
-                       else if (OidIsValid(xret1))
-                               elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
-                                        aggfinalfnName, aggtransfn1typeName);
-                       else
-                               elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
-                                        aggfinalfnName, aggtransfn2typeName);
-               }
-               ffn = tup->t_data->t_oid;
+                       func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
+               finalfn = tup->t_data->t_oid;
                proc = (Form_pg_proc) GETSTRUCT(tup);
-               fret = proc->prorettype;
-               if (!OidIsValid(ffn) || !OidIsValid(fret))
-                       elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
+               finaltype = proc->prorettype;
+               Assert(OidIsValid(finalfn));
        }
        else
        {
-
                /*
-                * If no finalfn, aggregate result type is type of the sole state
-                * value (we already checked there is only one)
+                * If no finalfn, aggregate result type is type of the state value
                 */
-               if (OidIsValid(xret1))
-                       fret = xret1;
-               else
-                       fret = xret2;
+               finaltype = transtype;
        }
-       Assert(OidIsValid(fret));
-
-       /*
-        * If transition function 2 is defined, it must have an initial value,
-        * whereas transition function 1 need not, which allows max and min
-        * aggregates to return NULL if they are evaluated on empty sets.
-        */
-       if (OidIsValid(xfn2) && !agginitval2)
-               elog(ERROR, "AggregateCreate: transition function 2 MUST have an initial value");
+       Assert(OidIsValid(finaltype));
 
        /* initialize nulls and values */
        for (i = 0; i < Natts_pg_aggregate; i++)
@@ -229,25 +190,17 @@ AggregateCreate(char *aggName,
        namestrcpy(&aname, aggName);
        values[Anum_pg_aggregate_aggname - 1] = NameGetDatum(&aname);
        values[Anum_pg_aggregate_aggowner - 1] = Int32GetDatum(GetUserId());
-       values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1);
-       values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2);
-       values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn);
-       values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase);
-       values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
-       values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
-       values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
-
-       if (agginitval1)
-               values[Anum_pg_aggregate_agginitval1 - 1] =
-                       DirectFunctionCall1(textin, CStringGetDatum(agginitval1));
-       else
-               nulls[Anum_pg_aggregate_agginitval1 - 1] = 'n';
-
-       if (agginitval2)
-               values[Anum_pg_aggregate_agginitval2 - 1] =
-                       DirectFunctionCall1(textin, CStringGetDatum(agginitval2));
+       values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
+       values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
+       values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(basetype);
+       values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(transtype);
+       values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(finaltype);
+
+       if (agginitval)
+               values[Anum_pg_aggregate_agginitval - 1] =
+                       DirectFunctionCall1(textin, CStringGetDatum(agginitval));
        else
-               nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
+               nulls[Anum_pg_aggregate_agginitval - 1] = 'n';
 
        aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
        tupDesc = aggdesc->rd_att;
@@ -271,11 +224,9 @@ AggregateCreate(char *aggName,
 }
 
 Datum
-AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
+AggNameGetInitVal(char *aggName, Oid basetype, bool *isNull)
 {
        HeapTuple       tup;
-       Relation        aggRel;
-       int                     initValAttno;
        Oid                     transtype,
                                typinput,
                                typelem;
@@ -285,15 +236,6 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
 
        Assert(PointerIsValid(aggName));
        Assert(PointerIsValid(isNull));
-       Assert(xfuncno == 1 || xfuncno == 2);
-
-       /*
-        * since we will have to use fastgetattr (in case one or both init
-        * vals are NULL), we will need to open the relation.  Do that first
-        * to ensure we don't get a stale tuple from the cache.
-        */
-
-       aggRel = heap_openr(AggregateRelationName, AccessShareLock);
 
        tup = SearchSysCacheTuple(AGGNAME,
                                                          PointerGetDatum(aggName),
@@ -302,29 +244,19 @@ AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
        if (!HeapTupleIsValid(tup))
                elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
                         aggName);
-       if (xfuncno == 1)
-       {
-               transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
-               initValAttno = Anum_pg_aggregate_agginitval1;
-       }
-       else
-       {
-               /* can only be 1 or 2 */
-               transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
-               initValAttno = Anum_pg_aggregate_agginitval2;
-       }
+       transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype;
 
-       textInitVal = fastgetattr(tup, initValAttno,
-                                                         RelationGetDescr(aggRel),
-                                                         isNull);
+       /*
+        * initval is potentially null, so don't try to access it as a struct
+        * field. Must do it the hard way with SysCacheGetAttr.
+        */
+       textInitVal = SysCacheGetAttr(AGGNAME, tup,
+                                                                 Anum_pg_aggregate_agginitval,
+                                                                 isNull);
        if (*isNull)
-       {
-               heap_close(aggRel, AccessShareLock);
-               return PointerGetDatum(NULL);
-       }
-       strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
+               return (Datum) 0;
 
-       heap_close(aggRel, AccessShareLock);
+       strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
 
        tup = SearchSysCacheTuple(TYPEOID,
                                                          ObjectIdGetDatum(transtype),
index d3da6cc2b27202e766ebd934835fc527372fbc0d..b90ef61a3b0dc49f1bcd4a02ccd9b8f80ae409e9 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.44 2000/07/03 23:09:33 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.45 2000/07/17 03:04:44 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -484,16 +484,12 @@ DefineOperator(char *oprName,
  */
 void
 DefineAggregate(char *aggName, List *parameters)
-
 {
-       char       *stepfunc1Name = NULL;
-       char       *stepfunc2Name = NULL;
+       char       *transfuncName = NULL;
        char       *finalfuncName = NULL;
        char       *baseType = NULL;
-       char       *stepfunc1Type = NULL;
-       char       *stepfunc2Type = NULL;
-       char       *init1 = NULL;
-       char       *init2 = NULL;
+       char       *transType = NULL;
+       char       *initval = NULL;
        List       *pl;
 
        foreach(pl, parameters)
@@ -501,47 +497,28 @@ DefineAggregate(char *aggName, List *parameters)
                DefElem    *defel = (DefElem *) lfirst(pl);
 
                /*
-                * sfunc1
+                * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
+                * for sfunc, stype, initcond.
                 */
-               if (!strcasecmp(defel->defname, "sfunc1"))
-                       stepfunc1Name = defGetString(defel);
-               else if (!strcasecmp(defel->defname, "basetype"))
-                       baseType = defGetString(defel);
-               else if (!strcasecmp(defel->defname, "stype1"))
-               {
-                       stepfunc1Type = defGetString(defel);
-
-                       /*
-                        * sfunc2
-                        */
-               }
-               else if (!strcasecmp(defel->defname, "sfunc2"))
-                       stepfunc2Name = defGetString(defel);
-               else if (!strcasecmp(defel->defname, "stype2"))
-               {
-                       stepfunc2Type = defGetString(defel);
-
-                       /*
-                        * final
-                        */
-               }
-               else if (!strcasecmp(defel->defname, "finalfunc"))
-               {
+               if (strcasecmp(defel->defname, "sfunc") == 0)
+                       transfuncName = defGetString(defel);
+               else if (strcasecmp(defel->defname, "sfunc1") == 0)
+                       transfuncName = defGetString(defel);
+               else if (strcasecmp(defel->defname, "finalfunc") == 0)
                        finalfuncName = defGetString(defel);
-
-                       /*
-                        * initial conditions
-                        */
-               }
-               else if (!strcasecmp(defel->defname, "initcond1"))
-                       init1 = defGetString(defel);
-               else if (!strcasecmp(defel->defname, "initcond2"))
-                       init2 = defGetString(defel);
+               else if (strcasecmp(defel->defname, "basetype") == 0)
+                       baseType = defGetString(defel);
+               else if (strcasecmp(defel->defname, "stype") == 0)
+                       transType = defGetString(defel);
+               else if (strcasecmp(defel->defname, "stype1") == 0)
+                       transType = defGetString(defel);
+               else if (strcasecmp(defel->defname, "initcond") == 0)
+                       initval = defGetString(defel);
+               else if (strcasecmp(defel->defname, "initcond1") == 0)
+                       initval = defGetString(defel);
                else
-               {
                        elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
                                 defel->defname);
-               }
        }
 
        /*
@@ -549,31 +526,20 @@ DefineAggregate(char *aggName, List *parameters)
         */
        if (baseType == NULL)
                elog(ERROR, "Define: \"basetype\" unspecified");
-       if (stepfunc1Name != NULL)
-       {
-               if (stepfunc1Type == NULL)
-                       elog(ERROR, "Define: \"stype1\" unspecified");
-       }
-       if (stepfunc2Name != NULL)
-       {
-               if (stepfunc2Type == NULL)
-                       elog(ERROR, "Define: \"stype2\" unspecified");
-       }
+       if (transType == NULL)
+               elog(ERROR, "Define: \"stype\" unspecified");
+       if (transfuncName == NULL)
+               elog(ERROR, "Define: \"sfunc\" unspecified");
 
        /*
         * Most of the argument-checking is done inside of AggregateCreate
         */
-       AggregateCreate(aggName,        /* aggregate name */
-                                       stepfunc1Name,          /* first step function name */
-                                       stepfunc2Name,          /* second step function name */
-                                       finalfuncName,          /* final function name */
-                                       baseType,       /* type of object being aggregated */
-                                       stepfunc1Type,          /* return type of first function */
-                                       stepfunc2Type,          /* return type of second function */
-                                       init1,          /* first initial condition */
-                                       init2);         /* second initial condition */
-
-       /* XXX free palloc'd memory */
+       AggregateCreate(aggName,                /* aggregate name */
+                                       transfuncName,  /* step function name */
+                                       finalfuncName,  /* final function name */
+                                       baseType,               /* type of data being aggregated */
+                                       transType,              /* transition data type */
+                                       initval);               /* initial condition */
 }
 
 /*
index 4698fa850c07033d2df75c3f090277ec596ff15d..deaaf51df2a1bb264a76de3526484ca917d9a43a 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.63 2000/07/05 23:11:11 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.64 2000/07/17 03:04:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@
 #include "commands/user.h"
 #include "libpq/crypt.h"
 #include "miscadmin.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/syscache.h"
index fd9d761ffc477bf16392dbe4b496e32ce9200f7d..48cd8aa169ce44db8f69c60471b83144837a77c5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.73 2000/07/12 02:37:00 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.74 2000/07/17 03:04:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@
 #include "executor/execdebug.h"
 #include "executor/functions.h"
 #include "executor/nodeSubplan.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/fcache2.h"
index 40bbbd916f651a510c45f3ae55dd0be5a6fa25f4..a3f66d20cad24d39cfdf3921c742ce4d26a00279 100644 (file)
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.12 2000/07/12 02:37:01 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.13 2000/07/17 03:04:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include <sys/types.h>
 #include <sys/file.h>
+
 #include "postgres.h"
 
 #include "executor/executor.h"
+#include "utils/memutils.h"
+
 
 /* ----------------------------------------------------------------
  *             ExecScan
index 1ac5c3c9e21e53c88e048afaeb2d50c39ccfbf38..547a946b4ce81bf941dfb5ae41181d8dd591b0c6 100644 (file)
@@ -3,36 +3,38 @@
  * nodeAgg.c
  *       Routines to handle aggregate nodes.
  *
- *       ExecAgg evaluates each aggregate in the following steps: (initcond1,
- *       initcond2 are the initial values and sfunc1, sfunc2, and finalfunc are
- *       the transition functions.)
+ *       ExecAgg evaluates each aggregate in the following steps:
  *
- *              value1 = initcond1
- *              value2 = initcond2
+ *              transvalue = initcond
  *              foreach input_value do
- *                     value1 = sfunc1(value1, input_value)
- *                     value2 = sfunc2(value2)
- *              value1 = finalfunc(value1, value2)
+ *                     transvalue = transfunc(transvalue, input_value)
+ *              result = finalfunc(transvalue)
  *
- *       If initcond1 is NULL then the first non-NULL input_value is
- *       assigned directly to value1.  sfunc1 isn't applied until value1
- *       is non-NULL.
+ *       If a finalfunc is not supplied then the result is just the ending
+ *       value of transvalue.
  *
- *       sfunc1 is never applied when the current tuple's input_value is NULL.
- *       sfunc2 is applied for each tuple if the aggref is marked 'usenulls',
- *       otherwise it is only applied when input_value is not NULL.
- *       (usenulls was formerly used for COUNT(*), but is no longer needed for
- *       that purpose; as of 10/1999 the support for usenulls is dead code.
- *       I have not removed it because it seems like a potentially useful
- *       feature for user-defined aggregates.  We'd just need to add a
- *       flag column to pg_aggregate and a parameter to CREATE AGGREGATE...)
+ *       If transfunc is marked "strict" in pg_proc and initcond is NULL,
+ *       then the first non-NULL input_value is assigned directly to transvalue,
+ *       and transfunc isn't applied until the second non-NULL input_value.
+ *       The agg's input type and transtype must be the same in this case!
+ *
+ *       If transfunc is marked "strict" then NULL input_values are skipped,
+ *       keeping the previous transvalue.  If transfunc is not strict then it
+ *       is called for every input tuple and must deal with NULL initcond
+ *       or NULL input_value for itself.
+ *
+ *       If finalfunc is marked "strict" then it is not called when the
+ *       ending transvalue is NULL, instead a NULL result is created
+ *       automatically (this is just the usual handling of strict functions,
+ *       of course).  A non-strict finalfunc can make its own choice of
+ *       what to return for a NULL ending transvalue.
  *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.69 2000/07/12 02:37:03 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.70 2000/07/17 03:04:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,6 +47,7 @@
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "optimizer/clauses.h"
+#include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_type.h"
@@ -67,16 +70,15 @@ typedef struct AggStatePerAggData
        Aggref     *aggref;
 
        /* Oids of transfer functions */
-       Oid                     xfn1_oid;
-       Oid                     xfn2_oid;
-       Oid                     finalfn_oid;
+       Oid                     transfn_oid;
+       Oid                     finalfn_oid;    /* may be InvalidOid */
 
        /*
         * fmgr lookup data for transfer functions --- only valid when
-        * corresponding oid is not InvalidOid
+        * corresponding oid is not InvalidOid.  Note in particular that
+        * fn_strict flags are kept here.
         */
-       FmgrInfo        xfn1;
-       FmgrInfo        xfn2;
+       FmgrInfo        transfn;
        FmgrInfo        finalfn;
 
        /*
@@ -94,12 +96,10 @@ typedef struct AggStatePerAggData
        FmgrInfo        equalfn;
 
        /*
-        * initial values from pg_aggregate entry
+        * initial value from pg_aggregate entry
         */
-       Datum           initValue1;             /* for transtype1 */
-       Datum           initValue2;             /* for transtype2 */
-       bool            initValue1IsNull,
-                               initValue2IsNull;
+       Datum           initValue;
+       bool            initValueIsNull;
 
        /*
         * We need the len and byval info for the agg's input, result, and
@@ -107,45 +107,42 @@ typedef struct AggStatePerAggData
         */
        int                     inputtypeLen,
                                resulttypeLen,
-                               transtype1Len,
-                               transtype2Len;
+                               transtypeLen;
        bool            inputtypeByVal,
                                resulttypeByVal,
-                               transtype1ByVal,
-                               transtype2ByVal;
+                               transtypeByVal;
 
        /*
         * These values are working state that is initialized at the start of
         * an input tuple group and updated for each input tuple.
         *
         * For a simple (non DISTINCT) aggregate, we just feed the input values
-        * straight to the transition functions.  If it's DISTINCT, we pass
+        * straight to the transition function.  If it's DISTINCT, we pass
         * the input values into a Tuplesort object; then at completion of the
         * input tuple group, we scan the sorted values, eliminate duplicates,
-        * and run the transition functions on the rest.
+        * and run the transition function on the rest.
         */
 
        Tuplesortstate *sortstate;      /* sort object, if a DISTINCT agg */
 
-       Datum           value1,                 /* current transfer values 1 and 2 */
-                               value2;
-       bool            value1IsNull,
-                               value2IsNull;
-       bool            noInitValue;    /* true if value1 not set yet */
+       Datum           transValue;
+       bool            transValueIsNull;
+
+       bool            noTransValue;   /* true if transValue not set yet */
 
        /*
-        * Note: right now, noInitValue always has the same value as
-        * value1IsNull. But we should keep them separate because once the
-        * fmgr interface is fixed, we'll need to distinguish a null returned
-        * by transfn1 from a null we haven't yet replaced with an input
-        * value.
+        * Note: noTransValue initially has the same value as transValueIsNull,
+        * and if true both are cleared to false at the same time.  They are
+        * not the same though: if transfn later returns a NULL, we want to
+        * keep that NULL and not auto-replace it with a later input value.
+        * Only the first non-NULL input will be auto-substituted.
         */
 } AggStatePerAggData;
 
 
 static void initialize_aggregate(AggStatePerAgg peraggstate);
-static void advance_transition_functions(AggStatePerAgg peraggstate,
-                                                        Datum newVal, bool isNull);
+static void advance_transition_function(AggStatePerAgg peraggstate,
+                                                                               Datum newVal, bool isNull);
 static void process_sorted_aggregate(AggState *aggstate,
                                                                         AggStatePerAgg peraggstate);
 static void finalize_aggregate(AggStatePerAgg peraggstate,
@@ -182,144 +179,118 @@ initialize_aggregate(AggStatePerAgg peraggstate)
        }
 
        /*
-        * (Re)set value1 and value2 to their initial values.
+        * (Re)set transValue to the initial value.
         *
-        * Note that when the initial values are pass-by-ref, we just reuse
-        * them without copying for each group.  Hence, transition function
-        * had better not scribble on its input!
+        * Note that when the initial value is pass-by-ref, we just reuse it
+        * without copying for each group.  Hence, transition function
+        * had better not scribble on its input, or it will fail for GROUP BY!
         */
-       peraggstate->value1 = peraggstate->initValue1;
-       peraggstate->value1IsNull = peraggstate->initValue1IsNull;
-       peraggstate->value2 = peraggstate->initValue2;
-       peraggstate->value2IsNull = peraggstate->initValue2IsNull;
+       peraggstate->transValue = peraggstate->initValue;
+       peraggstate->transValueIsNull = peraggstate->initValueIsNull;
 
        /* ------------------------------------------
-        * If the initial value for the first transition function
-        * doesn't exist in the pg_aggregate table then we will let
-        * the first value returned from the outer procNode become
-        * the initial value. (This is useful for aggregates like
-        * max{} and min{}.)  The noInitValue flag signals that we
-        * still need to do this.
+        * If the initial value for the transition state doesn't exist in the
+        * pg_aggregate table then we will let the first non-NULL value returned
+        * from the outer procNode become the initial value. (This is useful for
+        * aggregates like max() and min().)  The noTransValue flag signals that
+        * we still need to do this.
         * ------------------------------------------
         */
-       peraggstate->noInitValue = peraggstate->initValue1IsNull;
+       peraggstate->noTransValue = peraggstate->initValueIsNull;
 }
 
 /*
- * Given a new input value, advance the transition functions of an aggregate.
+ * Given a new input value, advance the transition function of an aggregate.
  *
- * When called, CurrentMemoryContext should be the context we want transition
- * function results to be delivered into on this cycle.
- *
- * Note: if the agg does not have usenulls set, null inputs will be filtered
- * out before reaching here.
+ * When called, CurrentMemoryContext should be the context we want the
+ * transition function result to be delivered into on this cycle.
  */
 static void
-advance_transition_functions(AggStatePerAgg peraggstate,
-                                                        Datum newVal, bool isNull)
+advance_transition_function(AggStatePerAgg peraggstate,
+                                                       Datum newVal, bool isNull)
 {
        FunctionCallInfoData    fcinfo;
 
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
-
-       /*
-        * XXX reconsider isNULL handling here
-        */
-       if (OidIsValid(peraggstate->xfn1_oid) && !isNull)
+       if (peraggstate->transfn.fn_strict)
        {
-               if (peraggstate->noInitValue)
+               if (isNull)
                {
-
                        /*
-                        * value1 has not been initialized. This is the first non-NULL
-                        * input value. We use it as the initial value for value1.
-                        *
-                        * XXX We assume, without having checked, that the agg's input
-                        * type is binary-compatible with its transtype1!
+                        * For a strict transfn, nothing happens at a NULL input tuple;
+                        * we just keep the prior transValue.  However, if the transtype
+                        * is pass-by-ref, we have to copy it into the new context
+                        * because the old one is going to get reset.
+                        */
+                       if (!peraggstate->transValueIsNull)
+                               peraggstate->transValue = datumCopy(peraggstate->transValue,
+                                                                                               peraggstate->transtypeByVal,
+                                                                                               peraggstate->transtypeLen);
+                       return;
+               }
+               if (peraggstate->noTransValue)
+               {
+                       /*
+                        * transValue has not been initialized. This is the first non-NULL
+                        * input value. We use it as the initial value for transValue.
+                        * (We already checked that the agg's input type is binary-
+                        * compatible with its transtype, so straight copy here is OK.)
                         *
                         * We had better copy the datum if it is pass-by-ref, since
                         * the given pointer may be pointing into a scan tuple that
                         * will be freed on the next iteration of the scan.
                         */
-                       peraggstate->value1 = datumCopy(newVal,
-                                                                                       peraggstate->transtype1ByVal,
-                                                                                       peraggstate->transtype1Len);
-                       peraggstate->value1IsNull = false;
-                       peraggstate->noInitValue = false;
+                       peraggstate->transValue = datumCopy(newVal,
+                                                                                               peraggstate->transtypeByVal,
+                                                                                               peraggstate->transtypeLen);
+                       peraggstate->transValueIsNull = false;
+                       peraggstate->noTransValue = false;
+                       return;
                }
-               else
+               if (peraggstate->transValueIsNull)
                {
-                       /* apply transition function 1 */
-                       fcinfo.flinfo = &peraggstate->xfn1;
-                       fcinfo.nargs = 2;
-                       fcinfo.arg[0] = peraggstate->value1;
-                       fcinfo.argnull[0] = peraggstate->value1IsNull;
-                       fcinfo.arg[1] = newVal;
-                       fcinfo.argnull[1] = isNull;
-                       if (fcinfo.flinfo->fn_strict &&
-                               (peraggstate->value1IsNull || isNull))
-                       {
-                               /* don't call a strict function with NULL inputs */
-                               newVal = (Datum) 0;
-                               fcinfo.isnull = true;
-                       }
-                       else
-                               newVal = FunctionCallInvoke(&fcinfo);
                        /*
-                        * If the transition function was uncooperative, it may have
-                        * given us a pass-by-ref result that points at the scan tuple
-                        * or the prior-cycle working memory.  Copy it into the active
-                        * context if it doesn't look right.
+                        * Don't call a strict function with NULL inputs.  Note it is
+                        * possible to get here despite the above tests, if the transfn
+                        * is strict *and* returned a NULL on a prior cycle.  If that
+                        * happens we will propagate the NULL all the way to the end.
                         */
-                       if (!peraggstate->transtype1ByVal && !fcinfo.isnull &&
-                               ! MemoryContextContains(CurrentMemoryContext,
-                                                                               DatumGetPointer(newVal)))
-                               newVal = datumCopy(newVal,
-                                                                  peraggstate->transtype1ByVal,
-                                                                  peraggstate->transtype1Len);
-                       peraggstate->value1 = newVal;
-                       peraggstate->value1IsNull = fcinfo.isnull;
+                       return;
                }
        }
 
-       if (OidIsValid(peraggstate->xfn2_oid))
-       {
-               /* apply transition function 2 */
-               fcinfo.flinfo = &peraggstate->xfn2;
-               fcinfo.nargs = 1;
-               fcinfo.arg[0] = peraggstate->value2;
-               fcinfo.argnull[0] = peraggstate->value2IsNull;
-               fcinfo.isnull = false;  /* must reset after use by xfn1 */
-               if (fcinfo.flinfo->fn_strict && peraggstate->value2IsNull)
-               {
-                       /* don't call a strict function with NULL inputs */
-                       newVal = (Datum) 0;
-                       fcinfo.isnull = true;
-               }
-               else
-                       newVal = FunctionCallInvoke(&fcinfo);
-               /*
-                * If the transition function was uncooperative, it may have
-                * given us a pass-by-ref result that points at the scan tuple
-                * or the prior-cycle working memory.  Copy it into the active
-                * context if it doesn't look right.
-                */
-               if (!peraggstate->transtype2ByVal && !fcinfo.isnull &&
-                       ! MemoryContextContains(CurrentMemoryContext,
-                                                                       DatumGetPointer(newVal)))
-                       newVal = datumCopy(newVal,
-                                                          peraggstate->transtype2ByVal,
-                                                          peraggstate->transtype2Len);
-               peraggstate->value2 = newVal;
-               peraggstate->value2IsNull = fcinfo.isnull;
-       }
+       /* OK to call the transition function */
+       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       fcinfo.flinfo = &peraggstate->transfn;
+       fcinfo.nargs = 2;
+       fcinfo.arg[0] = peraggstate->transValue;
+       fcinfo.argnull[0] = peraggstate->transValueIsNull;
+       fcinfo.arg[1] = newVal;
+       fcinfo.argnull[1] = isNull;
+
+       newVal = FunctionCallInvoke(&fcinfo);
+
+       /*
+        * If the transition function was uncooperative, it may have
+        * given us a pass-by-ref result that points at the scan tuple
+        * or the prior-cycle working memory.  Copy it into the active
+        * context if it doesn't look right.
+        */
+       if (!peraggstate->transtypeByVal && !fcinfo.isnull &&
+               ! MemoryContextContains(CurrentMemoryContext,
+                                                               DatumGetPointer(newVal)))
+               newVal = datumCopy(newVal,
+                                                  peraggstate->transtypeByVal,
+                                                  peraggstate->transtypeLen);
+
+       peraggstate->transValue = newVal;
+       peraggstate->transValueIsNull = fcinfo.isnull;
 }
 
 /*
- * Run the transition functions for a DISTINCT aggregate.  This is called
+ * Run the transition function for a DISTINCT aggregate.  This is called
  * after we have completed entering all the input values into the sort
- * object.  We complete the sort, read out the value in sorted order, and
- * run the transition functions on each non-duplicate value.
+ * object.  We complete the sort, read out the values in sorted order,
+ * and run the transition function on each non-duplicate value.
  *
  * When called, CurrentMemoryContext should be the per-query context.
  */
@@ -346,13 +317,13 @@ process_sorted_aggregate(AggState *aggstate,
        {
                /*
                 * DISTINCT always suppresses nulls, per SQL spec, regardless of
-                * the aggregate's usenulls setting.
+                * the transition function's strictness.
                 */
                if (isNull)
                        continue;
                /*
                 * Clear and select the current working context for evaluation of
-                * the equality function and transition functions.
+                * the equality function and transition function.
                 */
                MemoryContextReset(aggstate->agg_cxt[aggstate->which_cxt]);
                oldContext =
@@ -365,11 +336,14 @@ process_sorted_aggregate(AggState *aggstate,
                        /* equal to prior, so forget this one */
                        if (!peraggstate->inputtypeByVal)
                                pfree(DatumGetPointer(newVal));
-                       /* note we do NOT flip contexts in this case... */
+                       /*
+                        * note we do NOT flip contexts in this case, so no need to
+                        * copy prior transValue to other context.
+                        */
                }
                else
                {
-                       advance_transition_functions(peraggstate, newVal, false);
+                       advance_transition_function(peraggstate, newVal, false);
                        /*
                         * Make the other context current so that this transition
                         * result is preserved.
@@ -402,48 +376,19 @@ static void
 finalize_aggregate(AggStatePerAgg peraggstate,
                                   Datum *resultVal, bool *resultIsNull)
 {
-       FunctionCallInfoData    fcinfo;
-
-       MemSet(&fcinfo, 0, sizeof(fcinfo));
-
        /*
-        * Apply the agg's finalfn, or substitute the appropriate
-        * transition value if there is no finalfn.
-        *
-        * XXX For now, only apply finalfn if we got at least one non-null input
-        * value.  This prevents zero divide in AVG(). If we had cleaner
-        * handling of null inputs/results in functions, we could probably
-        * take out this hack and define the result for no inputs as whatever
-        * finalfn returns for null input.
+        * Apply the agg's finalfn if one is provided, else return transValue.
         */
-       if (OidIsValid(peraggstate->finalfn_oid) &&
-               !peraggstate->noInitValue)
+       if (OidIsValid(peraggstate->finalfn_oid))
        {
+               FunctionCallInfoData    fcinfo;
+
+               MemSet(&fcinfo, 0, sizeof(fcinfo));
                fcinfo.flinfo = &peraggstate->finalfn;
-               if (peraggstate->finalfn.fn_nargs > 1)
-               {
-                       fcinfo.nargs = 2;
-                       fcinfo.arg[0] = peraggstate->value1;
-                       fcinfo.argnull[0] = peraggstate->value1IsNull;
-                       fcinfo.arg[1] = peraggstate->value2;
-                       fcinfo.argnull[1] = peraggstate->value2IsNull;
-               }
-               else if (OidIsValid(peraggstate->xfn1_oid))
-               {
-                       fcinfo.nargs = 1;
-                       fcinfo.arg[0] = peraggstate->value1;
-                       fcinfo.argnull[0] = peraggstate->value1IsNull;
-               }
-               else if (OidIsValid(peraggstate->xfn2_oid))
-               {
-                       fcinfo.nargs = 1;
-                       fcinfo.arg[0] = peraggstate->value2;
-                       fcinfo.argnull[0] = peraggstate->value2IsNull;
-               }
-               else
-                       elog(ERROR, "ExecAgg: no valid transition functions??");
-               if (fcinfo.flinfo->fn_strict &&
-                       (fcinfo.argnull[0] || fcinfo.argnull[1]))
+               fcinfo.nargs = 1;
+               fcinfo.arg[0] = peraggstate->transValue;
+               fcinfo.argnull[0] = peraggstate->transValueIsNull;
+               if (fcinfo.flinfo->fn_strict && peraggstate->transValueIsNull)
                {
                        /* don't call a strict function with NULL inputs */
                        *resultVal = (Datum) 0;
@@ -455,20 +400,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
                        *resultIsNull = fcinfo.isnull;
                }
        }
-       else if (OidIsValid(peraggstate->xfn1_oid))
-       {
-               /* Return value1 */
-               *resultVal = peraggstate->value1;
-               *resultIsNull = peraggstate->value1IsNull;
-       }
-       else if (OidIsValid(peraggstate->xfn2_oid))
+       else
        {
-               /* Return value2 */
-               *resultVal = peraggstate->value2;
-               *resultIsNull = peraggstate->value2IsNull;
+               *resultVal = peraggstate->transValue;
+               *resultIsNull = peraggstate->transValueIsNull;
        }
-       else
-               elog(ERROR, "ExecAgg: no valid transition functions??");
+
        /*
         * If result is pass-by-ref, make sure it is in the right context.
         */
@@ -588,11 +525,11 @@ ExecAgg(Agg *node)
                                newVal = ExecEvalExpr(aggref->target, econtext,
                                                                          &isNull, &isDone);
 
-                               if (isNull && !aggref->usenulls)
-                                       continue;       /* ignore this tuple for this agg */
-
                                if (aggref->aggdistinct)
                                {
+                                       /* in DISTINCT mode, we may ignore nulls */
+                                       if (isNull)
+                                               continue;
                                        /* putdatum has to be called in per-query context */
                                        MemoryContextSwitchTo(oldContext);
                                        tuplesort_putdatum(peraggstate->sortstate,
@@ -600,8 +537,10 @@ ExecAgg(Agg *node)
                                        MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
                                }
                                else
-                                       advance_transition_functions(peraggstate,
-                                                                                                newVal, isNull);
+                               {
+                                       advance_transition_function(peraggstate,
+                                                                                               newVal, isNull);
+                               }
                        }
 
                        /*
@@ -889,8 +828,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
                HeapTuple       aggTuple;
                Form_pg_aggregate aggform;
                Type            typeInfo;
-               Oid                     xfn1_oid,
-                                       xfn2_oid,
+               Oid                     transfn_oid,
                                        finalfn_oid;
 
                /* Mark Aggref node with its associated index in the result array */
@@ -913,53 +851,51 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
                peraggstate->resulttypeLen = typeLen(typeInfo);
                peraggstate->resulttypeByVal = typeByVal(typeInfo);
 
-               peraggstate->initValue1 =
-                       AggNameGetInitVal(aggname,
-                                                         aggform->aggbasetype,
-                                                         1,
-                                                         &peraggstate->initValue1IsNull);
+               typeInfo = typeidType(aggform->aggtranstype);
+               peraggstate->transtypeLen = typeLen(typeInfo);
+               peraggstate->transtypeByVal = typeByVal(typeInfo);
 
-               peraggstate->initValue2 =
+               peraggstate->initValue =
                        AggNameGetInitVal(aggname,
                                                          aggform->aggbasetype,
-                                                         2,
-                                                         &peraggstate->initValue2IsNull);
+                                                         &peraggstate->initValueIsNull);
 
-               peraggstate->xfn1_oid = xfn1_oid = aggform->aggtransfn1;
-               peraggstate->xfn2_oid = xfn2_oid = aggform->aggtransfn2;
+               peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
                peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
 
-               if (OidIsValid(xfn1_oid))
-               {
-                       fmgr_info(xfn1_oid, &peraggstate->xfn1);
-                       /* If a transfn1 is specified, transtype1 had better be, too */
-                       typeInfo = typeidType(aggform->aggtranstype1);
-                       peraggstate->transtype1Len = typeLen(typeInfo);
-                       peraggstate->transtype1ByVal = typeByVal(typeInfo);
-               }
+               fmgr_info(transfn_oid, &peraggstate->transfn);
+               if (OidIsValid(finalfn_oid))
+                       fmgr_info(finalfn_oid, &peraggstate->finalfn);
 
-               if (OidIsValid(xfn2_oid))
+               /*
+                * 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)
                {
-                       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.
-                        * ------------------------------------------
+                       /*
+                        * Note: use the type from the input expression here,
+                        * not aggform->aggbasetype, because the latter might be 0.
+                        * (Consider COUNT(*).)
                         */
-                       if (peraggstate->initValue2IsNull)
-                               elog(ERROR, "ExecInitAgg: agginitval2 is null");
-               }
+                       Oid                     inputType = exprType(aggref->target);
 
-               if (OidIsValid(finalfn_oid))
-                       fmgr_info(finalfn_oid, &peraggstate->finalfn);
+                       if (inputType != aggform->aggtranstype &&
+                               ! IS_BINARY_COMPATIBLE(inputType, aggform->aggtranstype))
+                               elog(ERROR, "Aggregate %s needs to have compatible input type and transition type",
+                                        aggname);
+               }
 
                if (aggref->aggdistinct)
                {
+                       /*
+                        * Note: use the type from the input expression here,
+                        * not aggform->aggbasetype, because the latter might be 0.
+                        * (Consider COUNT(*).)
+                        */
                        Oid                     inputType = exprType(aggref->target);
                        Operator        eq_operator;
                        Form_pg_operator pgopform;
index 9c2d293858ca061c0fd3261bca58b93bb8141878..f63ffe4943575c812f601beaaf8abd00bd4aa204 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- *     $Id: nodeHash.c,v 1.49 2000/07/12 02:37:03 tgl Exp $
+ *     $Id: nodeHash.c,v 1.50 2000/07/17 03:04:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,6 +30,8 @@
 #include "miscadmin.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_type.h"
+#include "utils/memutils.h"
+
 
 static int     hashFunc(Datum key, int len, bool byVal);
 
index e136c13154165fc6edf8c0e04af32ae214b8761b..54af882db12333b3d914b5091deab068467d99ec 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.31 2000/07/12 02:37:03 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.32 2000/07/17 03:04:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,8 @@
 #include "executor/nodeHash.h"
 #include "executor/nodeHashjoin.h"
 #include "optimizer/clauses.h"
+#include "utils/memutils.h"
+
 
 static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
                                                  HashJoinState *hjstate);
index 0186e394367849505ab660cf2254a1c44427873f..70b98a97e3a19bcdc79ac3acb8bd2f5f3d792075 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.17 2000/07/12 02:37:03 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.18 2000/07/17 03:04:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *             ExecInitNestLoop - initialize the join
  *             ExecEndNestLoop  - shut down the join
  */
+
 #include "postgres.h"
 
 #include "executor/execdebug.h"
 #include "executor/nodeNestloop.h"
+#include "utils/memutils.h"
+
 
 /* ----------------------------------------------------------------
  *             ExecNestLoop(node)
index a1daaf52c4bccb31ad70f21a32ed3cc87b3ab217..770cc47ccc4f405b80e6f1083e1b35ac6c1c36f7 100644 (file)
@@ -34,7 +34,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.14 2000/07/12 02:37:04 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.15 2000/07/17 03:04:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,6 +43,8 @@
 
 #include "executor/executor.h"
 #include "executor/nodeResult.h"
+#include "utils/memutils.h"
+
 
 /* ----------------------------------------------------------------
  *             ExecResult(node)
index 929ddad5aa85cff56afc401fab53bf4682caa377..8d3af03664516475ed32c64723a4f1243423b60f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.49 2000/07/07 21:12:53 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.50 2000/07/17 03:04:54 tgl Exp $
  *
  * NOTES
  *       This should be moved to a more appropriate place.  It is here
@@ -43,6 +43,8 @@
 #include "libpq/be-fsstubs.h"
 #include "libpq/libpq-fs.h"
 #include "storage/large_object.h"
+#include "utils/memutils.h"
+
 
 /* [PA] is Pascal André <andre@via.ecp.fr> */
 
index bc305382dfea192c957b90832c04a5f0044359de..4013a0f77b24d34268ce79c81fa8d075a3e13ab5 100644 (file)
@@ -19,7 +19,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.116 2000/07/12 02:37:04 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.117 2000/07/17 03:04:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -843,7 +843,6 @@ _copyAggref(Aggref *from)
        newnode->basetype = from->basetype;
        newnode->aggtype = from->aggtype;
        Node_Copy(from, newnode, target);
-       newnode->usenulls = from->usenulls;
        newnode->aggstar = from->aggstar;
        newnode->aggdistinct = from->aggdistinct;
        newnode->aggno = from->aggno;           /* probably not needed */
index b8814786180158ae7951368244fd2cc7ebcd5e69..b1772e6436cd829c88b962fe9d5164dd2abcb7b8 100644 (file)
@@ -24,7 +24,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.68 2000/07/12 02:37:04 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.69 2000/07/17 03:05:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -257,8 +257,6 @@ _equalAggref(Aggref *a, Aggref *b)
                return false;
        if (!equal(a->target, b->target))
                return false;
-       if (a->usenulls != b->usenulls)
-               return false;
        if (a->aggstar != b->aggstar)
                return false;
        if (a->aggdistinct != b->aggdistinct)
index f6fed845069c68ac23de4ef2cc23c63ed3c1e2a2..c561ad5126841f994012f5f69799570a5117638c 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.122 2000/07/15 00:01:37 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.123 2000/07/17 03:05:01 tgl Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -729,12 +729,10 @@ _outAggref(StringInfo str, Aggref *node)
        appendStringInfo(str, " AGGREG :aggname ");
        _outToken(str, node->aggname);
        appendStringInfo(str, " :basetype %u :aggtype %u :target ",
-                                        node->basetype,
-                                        node->aggtype);
+                                        node->basetype, node->aggtype);
        _outNode(str, node->target);
 
-       appendStringInfo(str, " :usenulls %s :aggstar %s :aggdistinct %s ",
-                                        node->usenulls ? "true" : "false",
+       appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
                                         node->aggstar ? "true" : "false",
                                         node->aggdistinct ? "true" : "false");
        /* aggno is not dumped */
index 4754cbc327add461cfec06bc700cda1811013aef..b9916ce6b06ee6e8352d7448cde0a7f29a8a3780 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.92 2000/07/12 02:37:06 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.93 2000/07/17 03:05:01 tgl Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -1117,10 +1117,6 @@ _readAggref()
        token = lsptok(NULL, &length);          /* eat :target */
        local_node->target = nodeRead(true);            /* now read it */
 
-       token = lsptok(NULL, &length);          /* eat :usenulls */
-       token = lsptok(NULL, &length);          /* get usenulls */
-       local_node->usenulls = (token[0] == 't') ? true : false;
-
        token = lsptok(NULL, &length);          /* eat :aggstar */
        token = lsptok(NULL, &length);          /* get aggstar */
        local_node->aggstar = (token[0] == 't') ? true : false;
index 600371a09f2bc27d509e62fc5895557c234b91ce..bbc8f5c70764e37c987008267136bbc772b079b8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.38 2000/06/15 03:32:19 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.39 2000/07/17 03:05:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -189,18 +189,16 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
 {
        HeapTuple       theAggTuple;
        Form_pg_aggregate aggform;
-       Oid                     fintype;
-       Oid                     xfn1;
-       Oid                     vartype;
        Aggref     *aggref;
-       bool            usenulls = false;
 
        theAggTuple = SearchSysCacheTuple(AGGNAME,
                                                                          PointerGetDatum(aggname),
                                                                          ObjectIdGetDatum(basetype),
                                                                          0, 0);
+       /* shouldn't happen --- caller should have checked already */
        if (!HeapTupleIsValid(theAggTuple))
-               elog(ERROR, "Aggregate %s does not exist", aggname);
+               agg_error("ParseAgg", aggname, basetype);
+       aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
 
        /*
         * There used to be a really ugly hack for count(*) here.
@@ -209,43 +207,18 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
         * does the right thing.  (It didn't use to do the right thing,
         * because the optimizer had the wrong ideas about semantics of
         * queries without explicit variables.  Fixed as of Oct 1999 --- tgl.)
-        *
-        * Since "1" never evaluates as null, we currently have no need of the
-        * "usenulls" flag, but it should be kept around; in fact, we should
-        * extend the pg_aggregate table to let usenulls be specified as an
-        * attribute of user-defined aggregates.  In the meantime, usenulls is
-        * just always set to "false".
         */
 
-       aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
-       fintype = aggform->aggfinaltype;
-       xfn1 = aggform->aggtransfn1;
-
-       /* only aggregates with transfn1 need a base type */
-       if (OidIsValid(xfn1))
-       {
-               basetype = aggform->aggbasetype;
-               vartype = exprType(lfirst(args));
-               if ((basetype != vartype)
-                       && (!IS_BINARY_COMPATIBLE(basetype, vartype)))
-               {
-                       Type            tp1,
-                                               tp2;
-
-                       tp1 = typeidType(basetype);
-                       tp2 = typeidType(vartype);
-                       elog(ERROR, "Aggregate type mismatch"
-                                "\n\t%s() works on %s, not on %s",
-                                aggname, typeTypeName(tp1), typeTypeName(tp2));
-               }
-       }
+       /*
+        * We assume caller has already checked that given args are compatible
+        * with the agg's basetype.
+        */
 
        aggref = makeNode(Aggref);
        aggref->aggname = pstrdup(aggname);
        aggref->basetype = aggform->aggbasetype;
-       aggref->aggtype = fintype;
+       aggref->aggtype = aggform->aggfinaltype;
        aggref->target = lfirst(args);
-       aggref->usenulls = usenulls;
        aggref->aggstar = agg_star;
        aggref->aggdistinct = agg_distinct;
 
@@ -268,10 +241,9 @@ agg_error(char *caller, char *aggname, Oid basetypeID)
         */
 
        if (basetypeID == InvalidOid)
-               elog(ERROR, "%s: aggregate '%s' for all types does not exist", caller, aggname);
+               elog(ERROR, "%s: aggregate '%s' for all types does not exist",
+                        caller, aggname);
        else
-       {
-               elog(ERROR, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
-                        typeidTypeName(basetypeID));
-       }
+               elog(ERROR, "%s: aggregate '%s' for '%s' does not exist",
+                        caller, aggname, typeidTypeName(basetypeID));
 }
index b22aff762a3155fc65613f3aefe46302b31aa518..30023453367bad8057f3a6242080a315c36fa2df 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.156 2000/07/12 22:59:04 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.157 2000/07/17 03:05:04 tgl Exp $
  *
  * NOTES
  *
@@ -33,6 +33,7 @@
  *
  *-------------------------------------------------------------------------
  */
+
 #include "postgres.h"
 
 #include <unistd.h>
@@ -80,6 +81,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/exc.h"
 #include "utils/guc.h"
+#include "utils/memutils.h"
 
 
 #define INVALID_SOCK   (-1)
index 12a8372c7c5d5b5b2c8c95348e253e6f41e84e4e..23a2dcf1e24e8f8f2f35e045642c17ebebe69db4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.70 2000/06/28 03:32:07 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.71 2000/07/17 03:05:08 tgl Exp $
  *
  * NOTES
  *       Outside modules can create a lock table and acquire/release
@@ -20,7 +20,7 @@
  *     Interface:
  *
  *     LockAcquire(), LockRelease(), LockMethodTableInit(),
- *     LockMethodTableRename(), LockReleaseAll, LockOwners()
+ *     LockMethodTableRename(), LockReleaseAll,
  *     LockResolveConflicts(), GrantLock()
  *
  *     NOTE: This module is used to define new lock tables.  The
 #include <signal.h>
 
 #include "postgres.h"
+
 #include "access/xact.h"
 #include "miscadmin.h"
 #include "storage/proc.h"
+#include "utils/memutils.h"
 #include "utils/ps_status.h"
 
 static int     WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode);
@@ -1722,181 +1724,6 @@ nxtl:   ;
        return false;
 }
 
-#ifdef NOT_USED
-/*
- * Return an array with the pids of all processes owning a lock.
- * This works only for user locks because normal locks have no
- * pid information in the corresponding XIDLookupEnt.
- */
-ArrayType  *
-LockOwners(LOCKMETHOD lockmethod, LOCKTAG *locktag)
-{
-       XIDLookupEnt *xidLook = NULL;
-       SPINLOCK        masterLock;
-       LOCK       *lock;
-       SHMEM_OFFSET lock_offset;
-       int                     count = 0;
-       LOCKMETHODTABLE *lockMethodTable;
-       HTAB       *xidTable;
-       bool            found;
-       int                     ndims,
-                               nitems,
-                               hdrlen,
-                               size;
-       int                     lbounds[1],
-                               hbounds[1];
-       ArrayType  *array;
-       int                *data_ptr;
-
-       /* Assume that no one will modify the result */
-       static int      empty_array[] = {20, 1, 0, 0, 0};
-
-#ifdef LOCK_DEBUG
-       if (lockmethod == USER_LOCKMETHOD && Trace_userlocks)
-        elog(DEBUG, "LockOwners: user lock tag [%u]", locktag->objId.blkno);
-#endif
-
-       /* This must be changed when short term locks will be used */
-       locktag->lockmethod = lockmethod;
-
-       Assert((lockmethod >= MIN_LOCKMETHOD) && (lockmethod < NumLockMethods));
-       lockMethodTable = LockMethodTable[lockmethod];
-       if (!lockMethodTable)
-       {
-               elog(NOTICE, "lockMethodTable is null in LockOwners");
-               return (ArrayType *) &empty_array;
-       }
-
-       if (LockingIsDisabled)
-               return (ArrayType *) &empty_array;
-
-       masterLock = lockMethodTable->ctl->masterLock;
-       SpinAcquire(masterLock);
-
-       /*
-        * Find a lock with this tag
-        */
-       Assert(lockMethodTable->lockHash->hash == tag_hash);
-       lock = (LOCK *) hash_search(lockMethodTable->lockHash, (Pointer) locktag,
-                                                               HASH_FIND, &found);
-
-       /*
-        * let the caller print its own error message, too. Do not elog(WARN).
-        */
-       if (!lock)
-       {
-               SpinRelease(masterLock);
-               elog(NOTICE, "LockOwners: locktable corrupted");
-               return (ArrayType *) &empty_array;
-       }
-
-       if (!found)
-       {
-               SpinRelease(masterLock);
-        elog(NOTICE, "LockOwners: no such lock");
-               return (ArrayType *) &empty_array;
-       }
-       LOCK_PRINT("LockOwners: found", lock, 0);
-       Assert((lock->nHolding > 0) && (lock->nActive > 0));
-       Assert(lock->nActive <= lock->nHolding);
-       lock_offset = MAKE_OFFSET(lock);
-
-       /* Construct a 1-dimensional array */
-       ndims = 1;
-       hdrlen = ARR_OVERHEAD(ndims);
-       lbounds[0] = 0;
-       hbounds[0] = lock->nActive;
-       size = hdrlen + sizeof(int) * hbounds[0];
-       array = (ArrayType *) palloc(size);
-       MemSet(array, 0, size);
-       memmove((char *) array, (char *) &size, sizeof(int));
-       memmove((char *) ARR_NDIM_PTR(array), (char *) &ndims, sizeof(int));
-       memmove((char *) ARR_DIMS(array), (char *) hbounds, ndims * sizeof(int));
-       memmove((char *) ARR_LBOUND(array), (char *) lbounds, ndims * sizeof(int));
-       SET_LO_FLAG(false, array);
-       data_ptr = (int *) ARR_DATA_PTR(array);
-
-       xidTable = lockMethodTable->xidHash;
-       hash_seq(NULL);
-       nitems = 0;
-       while ((xidLook = (XIDLookupEnt *) hash_seq(xidTable)) &&
-                  (xidLook != (XIDLookupEnt *) TRUE))
-       {
-               if (count++ > 1000)
-               {
-                       elog(NOTICE, "LockOwners: possible loop, giving up");
-                       break;
-               }
-
-               if (xidLook->tag.pid == 0)
-               {
-                       XID_PRINT("LockOwners: no pid", xidLook);
-                       continue;
-               }
-
-               if (!xidLook->tag.lock)
-               {
-                       XID_PRINT("LockOwners: NULL LOCK", xidLook);
-                       continue;
-               }
-
-               if (xidLook->tag.lock != lock_offset)
-               {
-                       XID_PRINT("LockOwners: different lock", xidLook);
-                       continue;
-               }
-
-               if (LOCK_LOCKMETHOD(*lock) != lockmethod)
-               {
-                       XID_PRINT("LockOwners: other table", xidLook);
-                       continue;
-               }
-
-               if (xidLook->nHolding <= 0)
-               {
-                       XID_PRINT("LockOwners: not holding", xidLook);
-                       continue;
-               }
-
-               if (nitems >= hbounds[0])
-               {
-                       elog(NOTICE, "LockOwners: array size exceeded");
-                       break;
-               }
-
-               /*
-                * Check that the holding process is still alive by sending him an
-                * unused (ignored) signal. If the kill fails the process is not
-                * alive.
-                */
-               if ((xidLook->tag.pid != MyProcPid) \
-                       &&(kill(xidLook->tag.pid, SIGCHLD)) != 0)
-               {
-                       /* Return a negative pid to signal that process is dead */
-                       data_ptr[nitems++] = -(xidLook->tag.pid);
-                       XID_PRINT("LockOwners: not alive", xidLook);
-                       /* XXX - TODO: remove this entry and update lock stats */
-                       continue;
-               }
-
-               /* Found a process holding the lock */
-               XID_PRINT("LockOwners: holding", xidLook);
-               data_ptr[nitems++] = xidLook->tag.pid;
-       }
-
-       SpinRelease(masterLock);
-
-       /* Adjust the actual size of the array */
-       hbounds[0] = nitems;
-       size = hdrlen + sizeof(int) * hbounds[0];
-       memmove((char *) array, (char *) &size, sizeof(int));
-       memmove((char *) ARR_DIMS(array), (char *) hbounds, ndims * sizeof(int));
-
-       return array;
-}
-
-#endif /* NOT_USED */
-
 #ifdef LOCK_DEBUG
 /*
  * Dump all locks in the proc->lockQueue. Must have already acquired
index 5baf6935d0a0d8e85ffc1897b0d660cd2fece8ea..2207af4fa19f932cff04a583d5eefa23446c6c18 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.73 2000/07/10 04:32:00 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.74 2000/07/17 03:05:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,9 @@
 #include "catalog/catalog.h"
 #include "miscadmin.h"
 #include "storage/smgr.h"
-#include "utils/inval.h"               /* ImmediateSharedRelationCacheInvalidate()
-                                                                * */
+#include "utils/inval.h"
+#include "utils/memutils.h"
+
 
 #undef DIAGNOSTIC
 
index fce4e2cc28347a5905b2b014699a33c94487ceb6..e87492fe5536c6331c568e90f5af95ef3ec55c5e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.169 2000/07/12 17:38:45 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.170 2000/07/17 03:05:14 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -56,6 +56,7 @@
 #include "storage/proc.h"
 #include "utils/exc.h"
 #include "utils/guc.h"
+#include "utils/memutils.h"
 #include "utils/ps_status.h"
 #include "utils/temprel.h"
 #ifdef MULTIBYTE
@@ -1411,7 +1412,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
        if (!IsUnderPostmaster)
        {
                puts("\nPOSTGRES backend interactive interface ");
-               puts("$Revision: 1.169 $ $Date: 2000/07/12 17:38:45 $\n");
+               puts("$Revision: 1.170 $ $Date: 2000/07/17 03:05:14 $\n");
        }
 
        /*
index 57818afb9edadcdebad9afd6add333f18da3a353..104a82cde3e7f584980e04af59e034d9b6c2b39c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.36 2000/07/12 02:37:15 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.37 2000/07/17 03:05:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "executor/execdefs.h"
 #include "executor/executor.h"
 #include "tcop/pquery.h"
+#include "utils/memutils.h"
 #include "utils/ps_status.h"
 
+
 static char *CreateOperationTag(int operationType);
 
 
index 3fc0061304251770df9fd82d6bba92121130f100..907082a7268ba2b85682ca17e0183c1f80b8326d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.60 2000/07/03 23:09:50 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.61 2000/07/17 03:05:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,7 +19,6 @@
 
 #include "catalog/catalog.h"
 #include "catalog/pg_type.h"
-#include "fmgr.h"
 #include "libpq/be-fsstubs.h"
 #include "libpq/libpq-fs.h"
 #include "storage/fd.h"
@@ -29,7 +28,8 @@
 
 #define ASSGN   "="
 
-/* An array has the following internal structure:
+/*
+ * An array has the following internal structure:
  *       <nbytes>              - total number of bytes
  *       <ndim>                - number of dimensions of the array
  *       <flags>               - bit mask of flags
  *       <actual data> - whatever is the stored data
  */
 
-/*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
 static int     _ArrayCount(char *str, int *dim, int typdelim);
-static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
+static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
                          FmgrInfo *inputproc, Oid typelem, int32 typmod,
                          char typdelim, int typlen, bool typbyval,
                          char typalign, int *nbytes);
-
 #ifdef LOARRAY
 static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
                         int ndim, int *dim, int baseSize);
-
 #endif
-static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
-                         char typalign, bool typbyval);
+static void CopyArrayEls(char *p, Datum *values, int nitems,
+                                                bool typbyval, int typlen, char typalign,
+                                                bool freedata);
 static void system_cache_lookup(Oid element_type, bool input, int *typlen,
                                 bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
                                        char *typalign);
@@ -101,7 +99,7 @@ array_in(PG_FUNCTION_ARGS)
        int                     i,
                                nitems;
        int32           nbytes;
-       char       *dataPtr;
+       Datum      *dataPtr;
        ArrayType  *retval;
        int                     ndim,
                                dim[MAXDIM],
@@ -187,32 +185,29 @@ array_in(PG_FUNCTION_ARGS)
                retval = (ArrayType *) palloc(sizeof(ArrayType));
                MemSet(retval, 0, sizeof(ArrayType));
                *(int32 *) retval = sizeof(ArrayType);
-               PG_RETURN_POINTER(retval);
+               PG_RETURN_ARRAYTYPE_P(retval);
        }
 
        if (*p == '{')
        {
                /* array not a large object */
-               dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
-                                                       typmod, typdelim, typlen, typbyval, typalign,
-                                                                                &nbytes);
+               dataPtr = ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
+                                                          typmod, typdelim, typlen, typbyval, typalign,
+                                                          &nbytes);
                nbytes += ARR_OVERHEAD(ndim);
                retval = (ArrayType *) palloc(nbytes);
                MemSet(retval, 0, nbytes);
-               memmove(retval, (char *) &nbytes, sizeof(int));
-               memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
+               retval->size = nbytes;
+               retval->ndim = ndim;
                SET_LO_FLAG(false, retval);
-               memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
-               memmove((char *) ARR_LBOUND(retval), (char *) lBound,
-                               ndim * sizeof(int));
-
-               /*
-                * dataPtr is an array of arbitraystuff even though its type is
-                * char* cast to char** to pass to _CopyArrayEls for now  - jolly
-                */
-               _CopyArrayEls((char **) dataPtr,
-                                         ARR_DATA_PTR(retval), nitems,
-                                         typlen, typalign, typbyval);
+               memcpy((char *) ARR_DIMS(retval), (char *) dim,
+                          ndim * sizeof(int));
+               memcpy((char *) ARR_LBOUND(retval), (char *) lBound,
+                          ndim * sizeof(int));
+
+               CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems,
+                                        typbyval, typlen, typalign, true);
+               pfree(dataPtr);
        }
        else
        {
@@ -226,8 +221,8 @@ array_in(PG_FUNCTION_ARGS)
                nbytes = bytes + ARR_OVERHEAD(ndim);
                retval = (ArrayType *) palloc(nbytes);
                MemSet(retval, 0, nbytes);
-               memmove(retval, (char *) &nbytes, sizeof(int));
-               memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
+               retval->size = nbytes;
+               retval->ndim = ndim;
                SET_LO_FLAG(true, retval);
                SET_CHUNK_FLAG(chunked, retval);
                memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
@@ -238,7 +233,7 @@ array_in(PG_FUNCTION_ARGS)
                PG_RETURN_NULL();
        }
        pfree(string_save);
-       PG_RETURN_POINTER(retval);
+       PG_RETURN_ARRAYTYPE_P(retval);
 }
 
 /*-----------------------------------------------------------------------------
@@ -331,50 +326,51 @@ _ArrayCount(char *str, int *dim, int typdelim)
 }
 
 /*---------------------------------------------------------------------------
- * _ReadArrayStr :
- *      parses the array string pointed by "arrayStr" and converts it in the
+ * ReadArrayStr :
+ *      parses the array string pointed by "arrayStr" and converts it to
  *      internal format. The external format expected is like C array
  *      declaration. Unspecified elements are initialized to zero for fixed length
  *      base types and to empty varlena structures for variable length base
  *      types.
  * result :
- *      returns the internal representation of the array elements
- *      nbytes is set to the size of the array in its internal representation.
+ *      returns a palloc'd array of Datum representations of the array elements.
+ *      If element type is pass-by-ref, the Datums point to palloc'd values.
+ *      *nbytes is set to the amount of data space needed for the array,
+ *      including alignment padding but not including array header overhead.
  *---------------------------------------------------------------------------
  */
-static char *
-_ReadArrayStr(char *arrayStr,
-                         int nitems,
-                         int ndim,
-                         int *dim,
-                         FmgrInfo *inputproc,          /* function used for the
-                                                                                * conversion */
-                         Oid typelem,
-                         int32 typmod,
-                         char typdelim,
-                         int typlen,
-                         bool typbyval,
-                         char typalign,
-                         int *nbytes)
+static Datum *
+ReadArrayStr(char *arrayStr,
+                        int nitems,
+                        int ndim,
+                        int *dim,
+                        FmgrInfo *inputproc,
+                        Oid typelem,
+                        int32 typmod,
+                        char typdelim,
+                        int typlen,
+                        bool typbyval,
+                        char typalign,
+                        int *nbytes)
 {
        int                     i,
                                nest_level = 0;
+       Datum      *values;
        char       *p,
                           *q,
-                          *r,
-                         **values;
+                          *r;
        bool            scanning_string = false;
        int                     indx[MAXDIM],
                                prod[MAXDIM];
        bool            eoArray = false;
 
        mda_get_prod(ndim, dim, prod);
-       for (i = 0; i < ndim; indx[i++] = 0);
-       /* read array enclosed within {} */
-       values = (char **) palloc(nitems * sizeof(char *));
-       MemSet(values, 0, nitems * sizeof(char *));
+       values = (Datum *) palloc(nitems * sizeof(Datum));
+       MemSet(values, 0, nitems * sizeof(Datum));
+       MemSet(indx, 0, sizeof(indx));
        q = p = arrayStr;
 
+       /* read array enclosed within {} */
        while (!eoArray)
        {
                bool            done = false;
@@ -442,53 +438,56 @@ _ReadArrayStr(char *arrayStr,
                *q = '\0';
                if (i >= nitems)
                        elog(ERROR, "array_in: illformed array constant");
-               values[i] = (char *) FunctionCall3(inputproc,
-                                                                                  CStringGetDatum(p),
-                                                                                  ObjectIdGetDatum(typelem),
-                                                                                  Int32GetDatum(typmod));
+               values[i] = FunctionCall3(inputproc,
+                                                                 CStringGetDatum(p),
+                                                                 ObjectIdGetDatum(typelem),
+                                                                 Int32GetDatum(typmod));
                p = ++q;
+               /*
+                * if not at the end of the array skip white space
+                */
                if (!eoArray)
-
-                       /*
-                        * if not at the end of the array skip white space
-                        */
                        while (isspace((int) *q))
                        {
                                p++;
                                q++;
                        }
        }
+       /*
+        * Initialize any unset items and compute total data space needed
+        */
        if (typlen > 0)
        {
                *nbytes = nitems * typlen;
                if (!typbyval)
                        for (i = 0; i < nitems; i++)
-                               if (!values[i])
+                               if (values[i] == (Datum) 0)
                                {
-                                       values[i] = palloc(typlen);
-                                       MemSet(values[i], 0, typlen);
+                                       values[i] = PointerGetDatum(palloc(typlen));
+                                       MemSet(DatumGetPointer(values[i]), 0, typlen);
                                }
        }
        else
        {
-               for (i = 0, *nbytes = 0; i < nitems; i++)
+               *nbytes = 0;
+               for (i = 0; i < nitems; i++)
                {
-                       if (values[i])
+                       if (values[i] != (Datum) 0)
                        {
                                if (typalign == 'd')
-                                       *nbytes += MAXALIGN(*(int32 *) values[i]);
+                                       *nbytes += MAXALIGN(VARSIZE(DatumGetPointer(values[i])));
                                else
-                                       *nbytes += INTALIGN(*(int32 *) values[i]);
+                                       *nbytes += INTALIGN(VARSIZE(DatumGetPointer(values[i])));
                        }
                        else
                        {
                                *nbytes += sizeof(int32);
-                               values[i] = palloc(sizeof(int32));
-                               *(int32 *) values[i] = sizeof(int32);
+                               values[i] = PointerGetDatum(palloc(sizeof(int32)));
+                               VARATT_SIZEP(DatumGetPointer(values[i])) = sizeof(int32);
                        }
                }
        }
-       return (char *) values;
+       return values;
 }
 
 
@@ -565,26 +564,39 @@ _ReadLOArray(char *str,
 
 #endif
 
+/*----------
+ * Copy data into an array object from a temporary array of Datums.
+ *
+ * p: pointer to start of array data area
+ * values: array of Datums to be copied
+ * nitems: number of Datums to be copied
+ * typbyval, typlen, typalign: info about element datatype
+ * freedata: if TRUE and element type is pass-by-ref, pfree data values
+ * referenced by Datums after copying them.
+ *----------
+ */
 static void
-_CopyArrayEls(char **values,
-                         char *p,
-                         int nitems,
-                         int typlen,
-                         char typalign,
-                         bool typbyval)
+CopyArrayEls(char *p,
+                        Datum *values,
+                        int nitems,
+                        bool typbyval,
+                        int typlen,
+                        char typalign,
+                        bool freedata)
 {
        int                     i;
+       int                     inc;
+
+       if (typbyval)
+               freedata = false;
 
        for (i = 0; i < nitems; i++)
        {
-               int                     inc;
-
-               inc = ArrayCastAndSet((Datum) values[i], typbyval, typlen, p);
+               inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
                p += inc;
-               if (!typbyval)
-                       pfree(values[i]);
+               if (freedata)
+                       pfree(DatumGetPointer(values[i]));
        }
-       pfree(values);
 }
 
 /*-------------------------------------------------------------------------
@@ -596,7 +608,7 @@ _CopyArrayEls(char **values,
 Datum
 array_out(PG_FUNCTION_ARGS)
 {
-       ArrayType  *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
+       ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
        Oid                     element_type = PG_GETARG_OID(1);
        int                     typlen;
        bool            typbyval;
@@ -786,7 +798,7 @@ array_out(PG_FUNCTION_ARGS)
 Datum
 array_dims(PG_FUNCTION_ARGS)
 {
-       ArrayType  *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
+       ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
        text       *result;
        char       *p;
        int                     nbytes,
@@ -821,8 +833,8 @@ array_dims(PG_FUNCTION_ARGS)
 /*---------------------------------------------------------------------------
  * array_ref :
  *       This routine takes an array pointer and an index array and returns
- *       a pointer to the referred element if element is passed by
- *       reference otherwise returns the value of the referred element.
+ *       the referenced item as a Datum.  Note that for a pass-by-reference
+ *       datatype, the returned Datum is a pointer into the array object.
  *---------------------------------------------------------------------------
  */
 Datum
@@ -905,7 +917,7 @@ array_ref(ArrayType *array,
                {                                               /* not by value */
                        char       *tempdata = palloc(elmlen);
 
-                       memmove(tempdata, DatumGetPointer(result), elmlen);
+                       memcpy(tempdata, DatumGetPointer(result), elmlen);
                        result = PointerGetDatum(tempdata);
                }
                pfree(v);
@@ -1003,14 +1015,15 @@ array_clip(ArrayType *array,
 #endif
                bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts);
                newArr = (ArrayType *) palloc(bytes);
-               memmove(newArr, array, sizeof(ArrayType));
-               memmove(newArr, &bytes, sizeof(int));
-               memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
-               memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
+               newArr->size = bytes;
+               newArr->ndim = array->ndim;
+               newArr->flags = array->flags;
+               memcpy(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
+               memcpy(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
                strcpy(ARR_DATA_PTR(newArr), newname);
 
                rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen);
-               if (rsize < MAX_BUFF_SIZE)
+               if (rsize < BLCKSZ)
                {
                        char       *buff;
 
@@ -1072,10 +1085,11 @@ array_clip(ArrayType *array,
                bytes += ARR_OVERHEAD(nSubscripts);
        }
        newArr = (ArrayType *) palloc(bytes);
-       memmove(newArr, array, sizeof(ArrayType));
-       memmove(newArr, &bytes, sizeof(int));
-       memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
-       memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
+       newArr->size = bytes;
+       newArr->ndim = array->ndim;
+       newArr->flags = array->flags;
+       memcpy(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
+       memcpy(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
        _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1);
        return newArr;
 }
@@ -1322,7 +1336,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
 {
        ArrayType  *v;
        ArrayType  *result;
-       char      **values;
+       Datum      *values;
        char       *elt;
        int                *dim;
        int                     ndim;
@@ -1338,14 +1352,13 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
        Oid                     proc;
        char            typalign;
        char       *s;
-       char       *p;
 
        /* Get input array */
        if (fcinfo->nargs < 1)
                elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs);
        if (PG_ARGISNULL(0))
                elog(ERROR, "array_map: null input array");
-       v = (ArrayType *) PG_GETARG_VARLENA_P(0);
+       v = PG_GETARG_ARRAYTYPE_P(0);
 
        /* Large objects not yet supported */
        if (ARR_IS_LO(v) == true)
@@ -1357,7 +1370,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
 
        /* Check for empty array */
        if (nitems <= 0)
-               PG_RETURN_POINTER(v);
+               PG_RETURN_ARRAYTYPE_P(v);
 
        /* Lookup source and result types. Unneeded variables are reused. */
        system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval,
@@ -1366,8 +1379,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
                                                &typdelim, &typelem, &proc, &typalign);
 
        /* Allocate temporary array for new values */
-       values = (char **) palloc(nitems * sizeof(char *));
-       MemSet(values, 0, nitems * sizeof(char *));
+       values = (Datum *) palloc(nitems * sizeof(Datum));
+       MemSet(values, 0, nitems * sizeof(Datum));
 
        /* Loop over source data */
        s = (char *) ARR_DATA_PTR(v);
@@ -1411,30 +1424,16 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
                fcinfo->arg[0] = (Datum) elt;
                fcinfo->argnull[0] = false;
                fcinfo->isnull = false;
-               p = (char *) FunctionCallInvoke(fcinfo);
+               values[i] = FunctionCallInvoke(fcinfo);
                if (fcinfo->isnull)
                        elog(ERROR, "array_map: cannot handle NULL in array");
 
-               /* Update values and total result size */
+               /* Update total result size */
                if (typbyval)
-               {
-                       values[i] = p;
                        nbytes += typlen;
-               }
                else
-               {
-                       int                     len;
-
-                       len = ((typlen > 0) ? typlen : INTALIGN(*(int32 *) p));
-                       /* Needed because _CopyArrayEls tries to pfree items */
-                       if (p == elt)
-                       {
-                               p = (char *) palloc(len);
-                               memcpy(p, elt, len);
-                       }
-                       values[i] = p;
-                       nbytes += len;
-               }
+                       nbytes += ((typlen > 0) ? typlen :
+                                          INTALIGN(VARSIZE(DatumGetPointer(values[i]))));
        }
 
        /* Allocate and initialize the result array */
@@ -1442,18 +1441,130 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
        result = (ArrayType *) palloc(nbytes);
        MemSet(result, 0, nbytes);
 
-       memcpy((char *) result, (char *) &nbytes, sizeof(int));
-       memcpy((char *) ARR_NDIM_PTR(result), (char *) &ndim, sizeof(int));
-       memcpy((char *) ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
+       result->size = nbytes;
+       result->ndim = ndim;
+       memcpy(ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
 
-       /* Copy new values into the result array. values is pfreed. */
-       _CopyArrayEls((char **) values,
-                                 ARR_DATA_PTR(result), nitems,
-                                 typlen, typalign, typbyval);
+       /* Note: do not risk trying to pfree the results of the called function */
+       CopyArrayEls(ARR_DATA_PTR(result), values, nitems,
+                                typbyval, typlen, typalign, false);
+       pfree(values);
 
-       PG_RETURN_POINTER(result);
+       PG_RETURN_ARRAYTYPE_P(result);
 }
 
+/*----------
+ * construct_array  --- simple method for constructing an array object
+ *
+ * elems: array of Datum items to become the array contents
+ * nelems: number of items
+ * elmbyval, elmlen, elmalign: info for the datatype of the items
+ *
+ * A palloc'd 1-D array object is constructed and returned.  Note that
+ * elem values will be copied into the object even if pass-by-ref type.
+ * NULL element values are not supported.
+ *----------
+ */
+ArrayType *
+construct_array(Datum *elems, int nelems,
+                               bool elmbyval, int elmlen, char elmalign)
+{
+       ArrayType  *result;
+       int                     nbytes;
+       int                     i;
+
+       if (elmlen > 0)
+       {
+               /* XXX what about alignment? */
+               nbytes = elmlen * nelems;
+       }
+       else
+       {
+               /* varlena type */
+               nbytes = 0;
+               for (i = 0; i < nelems; i++)
+                       nbytes += INTALIGN(VARSIZE(DatumGetPointer(elems[i])));
+       }
+
+       /* Allocate and initialize 1-D result array */
+       nbytes += ARR_OVERHEAD(1);
+       result = (ArrayType *) palloc(nbytes);
+
+       result->size = nbytes;
+       result->ndim = 1;
+       result->flags = 0;
+       ARR_DIMS(result)[0] = nelems;
+       ARR_LBOUND(result)[0] = 1;
+
+       CopyArrayEls(ARR_DATA_PTR(result), elems, nelems,
+                                elmbyval, elmlen, elmalign, false);
+
+       return result;
+}
+
+/*----------
+ * deconstruct_array  --- simple method for extracting data from an array
+ *
+ * array: array object to examine (must not be NULL)
+ * elmbyval, elmlen, elmalign: info for the datatype of the items
+ * elemsp: return value, set to point to palloc'd array of Datum values
+ * nelemsp: return value, set to number of extracted values
+ *
+ * If array elements are pass-by-ref data type, the returned Datums will
+ * be pointers into the array object.
+ *----------
+ */
+void
+deconstruct_array(ArrayType *array,
+                                 bool elmbyval, int elmlen, char elmalign,
+                                 Datum **elemsp, int *nelemsp)
+{
+       Datum      *elems;
+       int                     nelems;
+       char       *p;
+       int                     i;
+
+       nelems = getNitems(ARR_NDIM(array), ARR_DIMS(array));
+       if (nelems <= 0)
+       {
+               *elemsp = NULL;
+               *nelemsp = 0;
+               return;
+       }
+       *elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum));
+       *nelemsp = nelems;
+
+       p = ARR_DATA_PTR(array);
+       for (i = 0; i < nelems; i++)
+       {
+               if (elmbyval)
+               {
+                       switch (elmlen)
+                       {
+                               case 1:
+                                       elems[i] = CharGetDatum(*p);
+                                       break;
+                               case 2:
+                                       elems[i] = Int16GetDatum(*(int16 *) p);
+                                       break;
+                               case 4:
+                                       elems[i] = Int32GetDatum(*(int32 *) p);
+                                       break;
+                       }
+                       p += elmlen;
+               }
+               else
+               {
+                       elems[i] = PointerGetDatum(p);
+                       if (elmlen > 0)
+                               p += elmlen;
+                       else
+                               p += INTALIGN(VARSIZE(p));
+               }
+       }
+}
+
+
 /*-----------------------------------------------------------------------------
  * array_eq :
  *               compares two arrays for equality
@@ -1464,8 +1575,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
 Datum
 array_eq(PG_FUNCTION_ARGS)
 {
-       ArrayType  *array1 = (ArrayType *) PG_GETARG_VARLENA_P(0);
-       ArrayType  *array2 = (ArrayType *) PG_GETARG_VARLENA_P(1);
+       ArrayType  *array1 = PG_GETARG_ARRAYTYPE_P(0);
+       ArrayType  *array2 = PG_GETARG_ARRAYTYPE_P(1);
 
        if (*(int32 *) array1 != *(int32 *) array2)
                PG_RETURN_BOOL(false);
@@ -1493,14 +1604,11 @@ system_cache_lookup(Oid element_type,
        typeTuple = SearchSysCacheTuple(TYPEOID,
                                                                        ObjectIdGetDatum(element_type),
                                                                        0, 0, 0);
-
        if (!HeapTupleIsValid(typeTuple))
-       {
-               elog(ERROR, "array_out: Cache lookup failed for type %u\n",
+               elog(ERROR, "array_out: Cache lookup failed for type %u",
                         element_type);
-               return;
-       }
        typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
        *typlen = typeStruct->typlen;
        *typbyval = typeStruct->typbyval;
        *typdelim = typeStruct->typdelim;
@@ -1536,7 +1644,11 @@ _ArrayCast(char *value, bool byval, int len)
        return 0;
 }
 
-
+/*
+ * Copy datum to *dest and return total space used (including align padding)
+ *
+ * XXX this routine needs to be told typalign too!
+ */
 static int
 ArrayCastAndSet(Datum src,
                                bool typbyval,
@@ -1560,16 +1672,26 @@ ArrayCastAndSet(Datum src,
                                case 4:
                                        *(int32 *) dest = DatumGetInt32(src);
                                        break;
+                               default:
+                                       elog(ERROR, "ArrayCastAndSet: unexpected typlen");
+                                       break;
                        }
+                       /* For by-val types, assume no alignment padding is needed */
+                       inc = typlen;
                }
                else
+               {
                        memmove(dest, DatumGetPointer(src), typlen);
-               inc = typlen;
+                       /* XXX WRONG: need to consider type's alignment requirement */
+                       inc = typlen;
+               }
        }
        else
        {
-               memmove(dest, DatumGetPointer(src), *(int32 *) DatumGetPointer(src));
-               inc = (INTALIGN(*(int32 *) DatumGetPointer(src)));
+               /* varlena type */
+               memmove(dest, DatumGetPointer(src), VARSIZE(DatumGetPointer(src)));
+               /* XXX WRONG: should use MAXALIGN or type's alignment requirement */
+               inc = INTALIGN(VARSIZE(DatumGetPointer(src)));
        }
        return inc;
 }
index 0b6a0db2eaac145b7314bc7e4e61a6f2dbabf431..bfa439f41565d77ac9d2d05ade49a0c6528286cc 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.64 2000/07/12 22:59:08 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.65 2000/07/17 03:05:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,7 @@
  *             Basic float4 ops:
  *              float4in, float4out, float4abs, float4um
  *             Basic float8 ops:
- *              float8in, float8inAd, float8out, float8outAd, float8abs, float8um
+ *              float8in, float8out, float8abs, float8um
  *             Arithmetic operators:
  *              float4pl, float4mi, float4mul, float4div
  *              float8pl, float8mi, float8mul, float8div
@@ -64,6 +64,7 @@
 #endif
 
 #include "fmgr.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 
 static void CheckFloat8Val(double val);
@@ -90,7 +91,6 @@ static void CheckFloat8Val(double val);
 
 #ifndef atof
 extern double atof(const char *p);
-
 #endif
 
 #ifndef HAVE_CBRT
@@ -100,9 +100,8 @@ static double cbrt(double x);
 #else
 #if !defined(nextstep)
 extern double cbrt(double x);
-
-#endif
 #endif
+#endif /* HAVE_CBRT */
 
 #ifndef HAVE_RINT
 #define rint my_rint
@@ -110,10 +109,9 @@ static double rint(double x);
 
 #else
 extern double rint(double x);
+#endif /* HAVE_RINT */
 
-#endif
-
-#endif
+#endif /* NeXT check */
 
 /* ========== USER I/O ROUTINES ========== */
 
@@ -453,7 +451,6 @@ float8smaller(float64 arg1, float64 arg2)
  *             float4mi                - returns a pointer to arg1 - arg2
  *             float4mul               - returns a pointer to arg1 * arg2
  *             float4div               - returns a pointer to arg1 / arg2
- *             float4inc               - returns a poniter to arg1 + 1.0
  */
 float32
 float4pl(float32 arg1, float32 arg2)
@@ -527,29 +524,11 @@ float4div(float32 arg1, float32 arg2)
        return result;
 }
 
-float32
-float4inc(float32 arg1)
-{
-       float32         result;
-       double          val;
-
-       if (!arg1)
-               return (float32) NULL;
-
-       val = *arg1 + (float32data) 1.0;
-
-       CheckFloat4Val(val);
-       result = (float32) palloc(sizeof(float32data));
-       *result = val;
-       return result;
-}
-
 /*
  *             float8pl                - returns a pointer to arg1 + arg2
  *             float8mi                - returns a pointer to arg1 - arg2
  *             float8mul               - returns a pointer to arg1 * arg2
  *             float8div               - returns a pointer to arg1 / arg2
- *             float8inc               - returns a pointer to arg1 + 1.0
  */
 float64
 float8pl(float64 arg1, float64 arg2)
@@ -622,22 +601,6 @@ float8div(float64 arg1, float64 arg2)
        return result;
 }
 
-float64
-float8inc(float64 arg1)
-{
-       float64         result;
-       double          val;
-
-       if (!arg1)
-               return (float64) NULL;
-
-       val = *arg1 + (float64data) 1.0;
-       CheckFloat8Val(val);
-       result = (float64) palloc(sizeof(float64data));
-       *result = val;
-       return result;
-}
-
 
 /*
  *             ====================
@@ -1572,10 +1535,181 @@ setseed(float64 seed)
 }      /* setseed() */
 
 
+
 /*
- *             ====================
- *             ARITHMETIC OPERATORS
- *             ====================
+ *             =========================
+ *             FLOAT AGGREGATE OPERATORS
+ *             =========================
+ *
+ *             float8_accum    - accumulate for AVG(), STDDEV(), etc
+ *             float4_accum    - same, but input data is float4
+ *             float8_avg              - produce final result for float AVG()
+ *             float8_variance - produce final result for float VARIANCE()
+ *             float8_stddev   - produce final result for float STDDEV()
+ *
+ * The transition datatype for all these aggregates is a 3-element array
+ * of float8, holding the values N, sum(X), sum(X*X) in that order.
+ *
+ * Note that we represent N as a float to avoid having to build a special
+ * datatype.  Given a reasonable floating-point implementation, there should
+ * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
+ * user will have doubtless lost interest anyway...)
+ */
+
+static float8 *
+check_float8_array(ArrayType *transarray, const char *caller)
+{
+       /*
+        * We expect the input to be a 3-element float array; verify that.
+        * We don't need to use deconstruct_array() since the array data
+        * is just going to look like a C array of 3 float8 values.
+        */
+       if (ARR_SIZE(transarray) != (ARR_OVERHEAD(1) + 3 * sizeof(float8)) ||
+               ARR_NDIM(transarray) != 1 ||
+               ARR_DIMS(transarray)[0] != 3)
+               elog(ERROR, "%s: expected 3-element float8 array", caller);
+       return (float8 *) ARR_DATA_PTR(transarray);
+}
+
+Datum
+float8_accum(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       float8          newval = PG_GETARG_FLOAT8(1);
+       float8     *transvalues;
+       float8          N,
+                               sumX,
+                               sumX2;
+       Datum           transdatums[3];
+       ArrayType  *result;
+
+       transvalues = check_float8_array(transarray, "float8_accum");
+       N = transvalues[0];
+       sumX = transvalues[1];
+       sumX2 = transvalues[2];
+
+       N += 1.0;
+       sumX += newval;
+       sumX2 += newval * newval;
+
+       transdatums[0] = Float8GetDatumFast(N);
+       transdatums[1] = Float8GetDatumFast(sumX);
+       transdatums[2] = Float8GetDatumFast(sumX2);
+
+       result = construct_array(transdatums, 3,
+                                                        false /* float8 byval */, sizeof(float8), 'd');
+
+       PG_RETURN_ARRAYTYPE_P(result);
+}
+
+Datum
+float4_accum(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       float4          newval4 = PG_GETARG_FLOAT4(1);
+       float8     *transvalues;
+       float8          N,
+                               sumX,
+                               sumX2,
+                               newval;
+       Datum           transdatums[3];
+       ArrayType  *result;
+
+       transvalues = check_float8_array(transarray, "float4_accum");
+       N = transvalues[0];
+       sumX = transvalues[1];
+       sumX2 = transvalues[2];
+
+       /* Do arithmetic in float8 for best accuracy */
+       newval = newval4;
+
+       N += 1.0;
+       sumX += newval;
+       sumX2 += newval * newval;
+
+       transdatums[0] = Float8GetDatumFast(N);
+       transdatums[1] = Float8GetDatumFast(sumX);
+       transdatums[2] = Float8GetDatumFast(sumX2);
+
+       result = construct_array(transdatums, 3,
+                                                        false /* float8 byval */, sizeof(float8), 'd');
+
+       PG_RETURN_ARRAYTYPE_P(result);
+}
+
+Datum
+float8_avg(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       float8     *transvalues;
+       float8          N,
+                               sumX;
+
+       transvalues = check_float8_array(transarray, "float8_avg");
+       N = transvalues[0];
+       sumX = transvalues[1];
+       /* ignore sumX2 */
+
+       /* SQL92 defines AVG of no values to be NULL */
+       if (N == 0.0)
+               PG_RETURN_NULL();
+
+       PG_RETURN_FLOAT8(sumX / N);
+}
+
+Datum
+float8_variance(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       float8     *transvalues;
+       float8          N,
+                               sumX,
+                               sumX2;
+
+       transvalues = check_float8_array(transarray, "float8_variance");
+       N = transvalues[0];
+       sumX = transvalues[1];
+       sumX2 = transvalues[2];
+
+       /* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
+       if (N == 0.0)
+               PG_RETURN_NULL();
+
+       if (N <= 1.0)
+               PG_RETURN_FLOAT8(0.0);
+
+       PG_RETURN_FLOAT8((N * sumX2 - sumX * sumX) / (N * (N - 1.0)));
+}
+
+Datum
+float8_stddev(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       float8     *transvalues;
+       float8          N,
+                               sumX,
+                               sumX2;
+
+       transvalues = check_float8_array(transarray, "float8_stddev");
+       N = transvalues[0];
+       sumX = transvalues[1];
+       sumX2 = transvalues[2];
+
+       /* We define STDDEV of no values to be NULL, of 1 value to be 0 */
+       if (N == 0.0)
+               PG_RETURN_NULL();
+
+       if (N <= 1.0)
+               PG_RETURN_FLOAT8(0.0);
+
+       PG_RETURN_FLOAT8(sqrt((N * sumX2 - sumX * sumX) / (N * (N - 1.0))));
+}
+
+
+/*
+ *             ====================================
+ *             MIXED-PRECISION ARITHMETIC OPERATORS
+ *             ====================================
  */
 
 /*
index bf7758c18655c8909d25783bc573a88e1ade0b1c..7133142c0b6cbe6bbc0316c68c1c2328915f6bd1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.40 2000/07/12 22:59:08 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.41 2000/07/17 03:05:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -650,14 +650,6 @@ int2div(PG_FUNCTION_ARGS)
        PG_RETURN_INT16(arg1 / arg2);
 }
 
-Datum
-int2inc(PG_FUNCTION_ARGS)
-{
-       int16           arg = PG_GETARG_INT16(0);
-
-       PG_RETURN_INT16(arg + 1);
-}
-
 Datum
 int24pl(PG_FUNCTION_ARGS)
 {
index 5748986bbfea5324022c1687cce14e8ffdb61545..437bb69b832a6a66c2825f155a6c8dbbff800f58 100644 (file)
@@ -5,7 +5,7 @@
  *
  *     1998 Jan Wieck
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.31 2000/06/15 03:32:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.32 2000/07/17 03:05:18 tgl Exp $
  *
  * ----------
  */
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <sys/types.h>
 
+#include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
@@ -1230,49 +1231,6 @@ numeric_inc(Numeric num)
 }
 
 
-/* ----------
- * numeric_dec() -
- *
- *     Decrement a number by one
- * ----------
- */
-Numeric
-numeric_dec(Numeric num)
-{
-       NumericVar      arg;
-       Numeric         res;
-
-       /* ----------
-        * Handle NULL
-        * ----------
-        */
-       if (num == NULL)
-               return NULL;
-
-       /* ----------
-        * Handle NaN
-        * ----------
-        */
-       if (NUMERIC_IS_NAN(num))
-               return make_result(&const_nan);
-
-       /* ----------
-        * Compute the result and return it
-        * ----------
-        */
-       init_var(&arg);
-
-       set_var_from_num(num, &arg);
-
-       sub_var(&arg, &const_one, &arg);
-       res = make_result(&arg);
-
-       free_var(&arg);
-
-       return res;
-}
-
-
 /* ----------
  * numeric_smaller() -
  *
@@ -1733,24 +1691,24 @@ numeric_int4(Numeric num)
 }
 
 
-Numeric
-int8_numeric(int64 *val)
+Datum
+int8_numeric(PG_FUNCTION_ARGS)
 {
+       Datum           val = PG_GETARG_DATUM(0);
        Numeric         res;
        NumericVar      result;
        char       *tmp;
 
        init_var(&result);
 
-       tmp = DatumGetCString(DirectFunctionCall1(int8out,
-                                                                                         PointerGetDatum(val)));
+       tmp = DatumGetCString(DirectFunctionCall1(int8out, val));
        set_var_from_str(tmp, &result);
        res = make_result(&result);
 
        free_var(&result);
        pfree(tmp);
 
-       return res;
+       PG_RETURN_NUMERIC(res);
 }
 
 
@@ -1939,6 +1897,369 @@ numeric_float4(Numeric num)
 }
 
 
+/* ----------------------------------------------------------------------
+ *
+ * Aggregate functions
+ *
+ * The transition datatype for all these aggregates is a 3-element array
+ * of Numeric, holding the values N, sum(X), sum(X*X) in that order.
+ *
+ * We represent N as a numeric mainly to avoid having to build a special
+ * datatype; it's unlikely it'd overflow an int4, but ...
+ *
+ * ----------------------------------------------------------------------
+ */
+
+static ArrayType *
+do_numeric_accum(ArrayType *transarray, Numeric newval)
+{
+       Datum      *transdatums;
+       int                     ndatums;
+       Numeric         N,
+                               sumX,
+                               sumX2;
+       ArrayType  *result;
+
+       /* We assume the input is array of numeric */
+       deconstruct_array(transarray,
+                                         false, -1, 'i',
+                                         &transdatums, &ndatums);
+       if (ndatums != 3)
+               elog(ERROR, "do_numeric_accum: expected 3-element numeric array");
+       N = DatumGetNumeric(transdatums[0]);
+       sumX = DatumGetNumeric(transdatums[1]);
+       sumX2 = DatumGetNumeric(transdatums[2]);
+
+       N = numeric_inc(N);
+       sumX = numeric_add(sumX, newval);
+       sumX2 = numeric_add(sumX2, numeric_mul(newval, newval));
+
+       transdatums[0] = NumericGetDatum(N);
+       transdatums[1] = NumericGetDatum(sumX);
+       transdatums[2] = NumericGetDatum(sumX2);
+
+       result = construct_array(transdatums, 3,
+                                                        false, -1, 'i');
+
+       return result;
+}
+
+Datum
+numeric_accum(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Numeric         newval = PG_GETARG_NUMERIC(1);
+
+       PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+}
+
+/*
+ * Integer data types all use Numeric accumulators to share code and
+ * avoid risk of overflow.
+ */
+
+Datum
+int2_accum(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Datum           newval2 = PG_GETARG_DATUM(1);
+       Numeric         newval;
+
+       newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
+
+       PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+}
+
+Datum
+int4_accum(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Datum           newval4 = PG_GETARG_DATUM(1);
+       Numeric         newval;
+
+       newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
+
+       PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+}
+
+Datum
+int8_accum(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Datum           newval8 = PG_GETARG_DATUM(1);
+       Numeric         newval;
+
+       newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+
+       PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+}
+
+Datum
+numeric_avg(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Datum      *transdatums;
+       int                     ndatums;
+       Numeric         N,
+                               sumX;
+
+       /* We assume the input is array of numeric */
+       deconstruct_array(transarray,
+                                         false, -1, 'i',
+                                         &transdatums, &ndatums);
+       if (ndatums != 3)
+               elog(ERROR, "numeric_avg: expected 3-element numeric array");
+       N = DatumGetNumeric(transdatums[0]);
+       sumX = DatumGetNumeric(transdatums[1]);
+       /* ignore sumX2 */
+
+       /* SQL92 defines AVG of no values to be NULL */
+       /* N is zero iff no digits (cf. numeric_uminus) */
+       if (N->varlen == NUMERIC_HDRSZ)
+               PG_RETURN_NULL();
+
+       PG_RETURN_NUMERIC(numeric_div(sumX, N));
+}
+
+Datum
+numeric_variance(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Datum      *transdatums;
+       int                     ndatums;
+       Numeric         N,
+                               sumX,
+                               sumX2,
+                               res;
+       NumericVar      vN,
+                               vsumX,
+                               vsumX2,
+                               vNminus1;
+
+       /* We assume the input is array of numeric */
+       deconstruct_array(transarray,
+                                         false, -1, 'i',
+                                         &transdatums, &ndatums);
+       if (ndatums != 3)
+               elog(ERROR, "numeric_variance: expected 3-element numeric array");
+       N = DatumGetNumeric(transdatums[0]);
+       sumX = DatumGetNumeric(transdatums[1]);
+       sumX2 = DatumGetNumeric(transdatums[2]);
+
+       if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
+               PG_RETURN_NUMERIC(make_result(&const_nan));
+
+       /* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
+       /* N is zero iff no digits (cf. numeric_uminus) */
+       if (N->varlen == NUMERIC_HDRSZ)
+               PG_RETURN_NULL();
+
+       init_var(&vN);
+       set_var_from_num(N, &vN);
+
+       init_var(&vNminus1);
+       sub_var(&vN, &const_one, &vNminus1);
+
+       if (cmp_var(&vNminus1, &const_zero) <= 0)
+       {
+               free_var(&vN);
+               free_var(&vNminus1);
+               PG_RETURN_NUMERIC(make_result(&const_zero));
+       }
+
+       init_var(&vsumX);
+       set_var_from_num(sumX, &vsumX);
+       init_var(&vsumX2);
+       set_var_from_num(sumX2, &vsumX2);
+
+       mul_var(&vsumX, &vsumX, &vsumX);        /* now vsumX contains sumX * sumX */
+       mul_var(&vN, &vsumX2, &vsumX2);         /* now vsumX2 contains N * sumX2 */
+       sub_var(&vsumX2, &vsumX, &vsumX2);      /* N * sumX2 - sumX * sumX */
+       mul_var(&vN, &vNminus1, &vNminus1);     /* N * (N - 1) */
+       div_var(&vsumX2, &vNminus1, &vsumX); /* variance */
+
+       res = make_result(&vsumX);
+
+       free_var(&vN);
+       free_var(&vNminus1);
+       free_var(&vsumX);
+       free_var(&vsumX2);
+
+       PG_RETURN_NUMERIC(res);
+}
+
+Datum
+numeric_stddev(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Datum      *transdatums;
+       int                     ndatums;
+       Numeric         N,
+                               sumX,
+                               sumX2,
+                               res;
+       NumericVar      vN,
+                               vsumX,
+                               vsumX2,
+                               vNminus1;
+
+       /* We assume the input is array of numeric */
+       deconstruct_array(transarray,
+                                         false, -1, 'i',
+                                         &transdatums, &ndatums);
+       if (ndatums != 3)
+               elog(ERROR, "numeric_stddev: expected 3-element numeric array");
+       N = DatumGetNumeric(transdatums[0]);
+       sumX = DatumGetNumeric(transdatums[1]);
+       sumX2 = DatumGetNumeric(transdatums[2]);
+
+       if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
+               PG_RETURN_NUMERIC(make_result(&const_nan));
+
+       /* We define STDDEV of no values to be NULL, of 1 value to be 0 */
+       /* N is zero iff no digits (cf. numeric_uminus) */
+       if (N->varlen == NUMERIC_HDRSZ)
+               PG_RETURN_NULL();
+
+       init_var(&vN);
+       set_var_from_num(N, &vN);
+
+       init_var(&vNminus1);
+       sub_var(&vN, &const_one, &vNminus1);
+
+       if (cmp_var(&vNminus1, &const_zero) <= 0)
+       {
+               free_var(&vN);
+               free_var(&vNminus1);
+               PG_RETURN_NUMERIC(make_result(&const_zero));
+       }
+
+       init_var(&vsumX);
+       set_var_from_num(sumX, &vsumX);
+       init_var(&vsumX2);
+       set_var_from_num(sumX2, &vsumX2);
+
+       mul_var(&vsumX, &vsumX, &vsumX);        /* now vsumX contains sumX * sumX */
+       mul_var(&vN, &vsumX2, &vsumX2);         /* now vsumX2 contains N * sumX2 */
+       sub_var(&vsumX2, &vsumX, &vsumX2);      /* N * sumX2 - sumX * sumX */
+       mul_var(&vN, &vNminus1, &vNminus1);     /* N * (N - 1) */
+       div_var(&vsumX2, &vNminus1, &vsumX); /* variance */
+       sqrt_var(&vsumX, &vsumX);                       /* stddev */
+
+       res = make_result(&vsumX);
+
+       free_var(&vN);
+       free_var(&vNminus1);
+       free_var(&vsumX);
+       free_var(&vsumX2);
+
+       PG_RETURN_NUMERIC(res);
+}
+
+
+/*
+ * SUM transition functions for integer datatypes.
+ *
+ * We use a Numeric accumulator to avoid overflow.  Because SQL92 defines
+ * the SUM() of no values to be NULL, not zero, the initial condition of
+ * the transition data value needs to be NULL.  This means we can't rely
+ * on ExecAgg to automatically insert the first non-null data value into
+ * the transition data: it doesn't know how to do the type conversion.
+ * The upshot is that these routines have to be marked non-strict and
+ * handle substitution of the first non-null input themselves.
+ */
+
+Datum
+int2_sum(PG_FUNCTION_ARGS)
+{
+       Numeric         oldsum,
+                               newval;
+
+       if (PG_ARGISNULL(0))
+       {
+               /* No non-null input seen so far... */
+               if (PG_ARGISNULL(1))
+                       PG_RETURN_NULL();       /* still no non-null */
+               /* This is the first non-null input. */
+               newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
+                                                                                                        PG_GETARG_DATUM(1)));
+               PG_RETURN_NUMERIC(newval);
+       }
+
+       oldsum = PG_GETARG_NUMERIC(0);
+
+       /* Leave sum unchanged if new input is null. */
+       if (PG_ARGISNULL(1))
+               PG_RETURN_NUMERIC(oldsum);
+
+       /* OK to do the addition. */
+       newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
+                                                                                                PG_GETARG_DATUM(1)));
+
+       PG_RETURN_NUMERIC(numeric_add(oldsum, newval));
+}
+
+Datum
+int4_sum(PG_FUNCTION_ARGS)
+{
+       Numeric         oldsum,
+                               newval;
+
+       if (PG_ARGISNULL(0))
+       {
+               /* No non-null input seen so far... */
+               if (PG_ARGISNULL(1))
+                       PG_RETURN_NULL();       /* still no non-null */
+               /* This is the first non-null input. */
+               newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
+                                                                                                        PG_GETARG_DATUM(1)));
+               PG_RETURN_NUMERIC(newval);
+       }
+
+       oldsum = PG_GETARG_NUMERIC(0);
+
+       /* Leave sum unchanged if new input is null. */
+       if (PG_ARGISNULL(1))
+               PG_RETURN_NUMERIC(oldsum);
+
+       /* OK to do the addition. */
+       newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
+                                                                                                PG_GETARG_DATUM(1)));
+
+       PG_RETURN_NUMERIC(numeric_add(oldsum, newval));
+}
+
+Datum
+int8_sum(PG_FUNCTION_ARGS)
+{
+       Numeric         oldsum,
+                               newval;
+
+       if (PG_ARGISNULL(0))
+       {
+               /* No non-null input seen so far... */
+               if (PG_ARGISNULL(1))
+                       PG_RETURN_NULL();       /* still no non-null */
+               /* This is the first non-null input. */
+               newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
+                                                                                                        PG_GETARG_DATUM(1)));
+               PG_RETURN_NUMERIC(newval);
+       }
+
+       oldsum = PG_GETARG_NUMERIC(0);
+
+       /* Leave sum unchanged if new input is null. */
+       if (PG_ARGISNULL(1))
+               PG_RETURN_NUMERIC(oldsum);
+
+       /* OK to do the addition. */
+       newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
+                                                                                                PG_GETARG_DATUM(1)));
+
+       PG_RETURN_NUMERIC(numeric_add(oldsum, newval));
+}
+
+
 /* ----------------------------------------------------------------------
  *
  * Local functions follow
@@ -2574,30 +2895,33 @@ add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
                         */
                        switch (cmp_abs(var1, var2))
                        {
-                               case 0: /* ----------
-                                                                                                                                * ABS(var1) == ABS(var2)
-                                                                                                                                * result = ZERO
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 0:
+                                       /* ----------
+                                        * ABS(var1) == ABS(var2)
+                                        * result = ZERO
+                                        * ----------
+                                        */
                                        zero_var(result);
                                        result->rscale = MAX(var1->rscale, var2->rscale);
                                        result->dscale = MAX(var1->dscale, var2->dscale);
                                        break;
 
-                               case 1: /* ----------
-                                                                                                                                * ABS(var1) > ABS(var2)
-                                                                                                                                * result = +(ABS(var1) - ABS(var2))
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 1:
+                                       /* ----------
+                                        * ABS(var1) > ABS(var2)
+                                        * result = +(ABS(var1) - ABS(var2))
+                                        * ----------
+                                        */
                                        sub_abs(var1, var2, result);
                                        result->sign = NUMERIC_POS;
                                        break;
 
-                               case -1:                /* ----------
-                                                                * ABS(var1) < ABS(var2)
-                                                                * result = -(ABS(var2) - ABS(var1))
-                                                                * ----------
-                                                                */
+                               case -1:
+                                       /* ----------
+                                        * ABS(var1) < ABS(var2)
+                                        * result = -(ABS(var2) - ABS(var1))
+                                        * ----------
+                                        */
                                        sub_abs(var2, var1, result);
                                        result->sign = NUMERIC_NEG;
                                        break;
@@ -2615,30 +2939,33 @@ add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
                         */
                        switch (cmp_abs(var1, var2))
                        {
-                               case 0: /* ----------
-                                                                                                                                * ABS(var1) == ABS(var2)
-                                                                                                                                * result = ZERO
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 0:
+                                       /* ----------
+                                        * ABS(var1) == ABS(var2)
+                                        * result = ZERO
+                                        * ----------
+                                        */
                                        zero_var(result);
                                        result->rscale = MAX(var1->rscale, var2->rscale);
                                        result->dscale = MAX(var1->dscale, var2->dscale);
                                        break;
 
-                               case 1: /* ----------
-                                                                                                                                * ABS(var1) > ABS(var2)
-                                                                                                                                * result = -(ABS(var1) - ABS(var2))
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 1:
+                                       /* ----------
+                                        * ABS(var1) > ABS(var2)
+                                        * result = -(ABS(var1) - ABS(var2))
+                                        * ----------
+                                        */
                                        sub_abs(var1, var2, result);
                                        result->sign = NUMERIC_NEG;
                                        break;
 
-                               case -1:                /* ----------
-                                                                * ABS(var1) < ABS(var2)
-                                                                * result = +(ABS(var2) - ABS(var1))
-                                                                * ----------
-                                                                */
+                               case -1:
+                                       /* ----------
+                                        * ABS(var1) < ABS(var2)
+                                        * result = +(ABS(var2) - ABS(var1))
+                                        * ----------
+                                        */
                                        sub_abs(var2, var1, result);
                                        result->sign = NUMERIC_POS;
                                        break;
@@ -2693,30 +3020,33 @@ sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
                         */
                        switch (cmp_abs(var1, var2))
                        {
-                               case 0: /* ----------
-                                                                                                                                * ABS(var1) == ABS(var2)
-                                                                                                                                * result = ZERO
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 0:
+                                       /* ----------
+                                        * ABS(var1) == ABS(var2)
+                                        * result = ZERO
+                                        * ----------
+                                        */
                                        zero_var(result);
                                        result->rscale = MAX(var1->rscale, var2->rscale);
                                        result->dscale = MAX(var1->dscale, var2->dscale);
                                        break;
 
-                               case 1: /* ----------
-                                                                                                                                * ABS(var1) > ABS(var2)
-                                                                                                                                * result = +(ABS(var1) - ABS(var2))
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 1:
+                                       /* ----------
+                                        * ABS(var1) > ABS(var2)
+                                        * result = +(ABS(var1) - ABS(var2))
+                                        * ----------
+                                        */
                                        sub_abs(var1, var2, result);
                                        result->sign = NUMERIC_POS;
                                        break;
 
-                               case -1:                /* ----------
-                                                                * ABS(var1) < ABS(var2)
-                                                                * result = -(ABS(var2) - ABS(var1))
-                                                                * ----------
-                                                                */
+                               case -1:
+                                       /* ----------
+                                        * ABS(var1) < ABS(var2)
+                                        * result = -(ABS(var2) - ABS(var1))
+                                        * ----------
+                                        */
                                        sub_abs(var2, var1, result);
                                        result->sign = NUMERIC_NEG;
                                        break;
@@ -2734,30 +3064,33 @@ sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
                         */
                        switch (cmp_abs(var1, var2))
                        {
-                               case 0: /* ----------
-                                                                                                                                * ABS(var1) == ABS(var2)
-                                                                                                                                * result = ZERO
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 0:
+                                       /* ----------
+                                        * ABS(var1) == ABS(var2)
+                                        * result = ZERO
+                                        * ----------
+                                        */
                                        zero_var(result);
                                        result->rscale = MAX(var1->rscale, var2->rscale);
                                        result->dscale = MAX(var1->dscale, var2->dscale);
                                        break;
 
-                               case 1: /* ----------
-                                                                                                                                * ABS(var1) > ABS(var2)
-                                                                                                                                * result = -(ABS(var1) - ABS(var2))
-                                                                                                                                * ----------
-                                                                                                                                */
+                               case 1:
+                                       /* ----------
+                                        * ABS(var1) > ABS(var2)
+                                        * result = -(ABS(var1) - ABS(var2))
+                                        * ----------
+                                        */
                                        sub_abs(var1, var2, result);
                                        result->sign = NUMERIC_NEG;
                                        break;
 
-                               case -1:                /* ----------
-                                                                * ABS(var1) < ABS(var2)
-                                                                * result = +(ABS(var2) - ABS(var1))
-                                                                * ----------
-                                                                */
+                               case -1:
+                                       /* ----------
+                                        * ABS(var1) < ABS(var2)
+                                        * result = +(ABS(var2) - ABS(var1))
+                                        * ----------
+                                        */
                                        sub_abs(var2, var1, result);
                                        result->sign = NUMERIC_POS;
                                        break;
@@ -2817,7 +3150,7 @@ mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
 
                for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
                {
-                       sum = sum + res_digits[i] + var1->digits[i1] * var2->digits[i2];
+                       sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
                        res_digits[i--] = sum % 10;
                        sum /= 10;
                }
@@ -3067,7 +3400,6 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
 
        /*
         * Tidy up
-        *
         */
        digitbuf_free(dividend.buf);
        for (i = 1; i < 10; i++)
@@ -3552,6 +3884,11 @@ add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
                                i1,
                                i2;
        int                     carry = 0;
+       /* copy these values into local vars for speed in inner loop */
+       int                     var1ndigits = var1->ndigits;
+       int                     var2ndigits = var2->ndigits;
+       NumericDigit *var1digits = var1->digits;
+       NumericDigit *var2digits = var2->digits;
 
        res_weight = MAX(var1->weight, var2->weight) + 1;
        res_rscale = MAX(var1->rscale, var2->rscale);
@@ -3569,15 +3906,25 @@ add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
        {
                i1--;
                i2--;
-               if (i1 >= 0 && i1 < var1->ndigits)
-                       carry += var1->digits[i1];
-               if (i2 >= 0 && i2 < var2->ndigits)
-                       carry += var2->digits[i2];
+               if (i1 >= 0 && i1 < var1ndigits)
+                       carry += var1digits[i1];
+               if (i2 >= 0 && i2 < var2ndigits)
+                       carry += var2digits[i2];
 
-               res_digits[i] = carry % 10;
-               carry /= 10;
+               if (carry >= 10)
+               {
+                       res_digits[i] = carry - 10;
+                       carry = 1;
+               }
+               else
+               {
+                       res_digits[i] = carry;
+                       carry = 0;
+               }
        }
 
+       Assert(carry == 0);                     /* else we failed to allow for carry out */
+
        while (res_ndigits > 0 && *res_digits == 0)
        {
                res_digits++;
@@ -3623,6 +3970,11 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
                                i1,
                                i2;
        int                     borrow = 0;
+       /* copy these values into local vars for speed in inner loop */
+       int                     var1ndigits = var1->ndigits;
+       int                     var2ndigits = var2->ndigits;
+       NumericDigit *var1digits = var1->digits;
+       NumericDigit *var2digits = var2->digits;
 
        res_weight = var1->weight;
        res_rscale = MAX(var1->rscale, var2->rscale);
@@ -3640,10 +3992,10 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
        {
                i1--;
                i2--;
-               if (i1 >= 0 && i1 < var1->ndigits)
-                       borrow += var1->digits[i1];
-               if (i2 >= 0 && i2 < var2->ndigits)
-                       borrow -= var2->digits[i2];
+               if (i1 >= 0 && i1 < var1ndigits)
+                       borrow += var1digits[i1];
+               if (i2 >= 0 && i2 < var2ndigits)
+                       borrow -= var2digits[i2];
 
                if (borrow < 0)
                {
@@ -3657,6 +4009,8 @@ sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result)
                }
        }
 
+       Assert(borrow == 0);            /* else caller gave us var1 < var2 */
+
        while (res_ndigits > 0 && *res_digits == 0)
        {
                res_digits++;
index b4736dd6ae8c3d50c359082a2068be92c2818c03..0730d56147350f5f482e60636ec4bffabcd257bb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.33 2000/07/12 22:59:09 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.34 2000/07/17 03:05:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,7 @@
 #include "access/hash.h"
 #include "access/xact.h"
 #include "miscadmin.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 
 
@@ -882,10 +883,6 @@ overlaps_timestamp(PG_FUNCTION_ARGS)
 
 /*----------------------------------------------------------
  *     "Arithmetic" operators on date/times.
- *             timestamp_foo   returns foo as an object (pointer) that
- *                                             can be passed between languages.
- *             timestamp_xx            is an internal routine which returns the
- *                                             actual value.
  *---------------------------------------------------------*/
 
 Datum
@@ -1150,7 +1147,6 @@ interval_larger(PG_FUNCTION_ARGS)
        PG_RETURN_INTERVAL_P(result);
 }
 
-
 Datum
 interval_pl(PG_FUNCTION_ARGS)
 {
@@ -1232,6 +1228,90 @@ interval_div(PG_FUNCTION_ARGS)
        PG_RETURN_INTERVAL_P(result);
 }
 
+/*
+ * interval_accum and interval_avg implement the AVG(interval) aggregate.
+ *
+ * The transition datatype for this aggregate is a 2-element array of
+ * intervals, where the first is the running sum and the second contains
+ * the number of values so far in its 'time' field.  This is a bit ugly
+ * but it beats inventing a specialized datatype for the purpose.
+ */
+
+Datum
+interval_accum(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Interval   *newval = PG_GETARG_INTERVAL_P(1);
+       Datum      *transdatums;
+       int                     ndatums;
+       Interval        sumX,
+                               N;
+       Interval   *newsum;
+       ArrayType  *result;
+
+       /* We assume the input is array of interval */
+       deconstruct_array(transarray,
+                                         false, 12, 'd',
+                                         &transdatums, &ndatums);
+       if (ndatums != 2)
+               elog(ERROR, "interval_accum: expected 2-element interval array");
+       /*
+        * XXX memcpy, instead of just extracting a pointer, to work around
+        * buggy array code: it won't ensure proper alignment of Interval
+        * objects on machines where double requires 8-byte alignment.
+        * That should be fixed, but in the meantime...
+        */
+       memcpy(&sumX, DatumGetIntervalP(transdatums[0]), sizeof(Interval));
+       memcpy(&N, DatumGetIntervalP(transdatums[1]), sizeof(Interval));
+
+       newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
+                                                                                                  IntervalPGetDatum(&sumX),
+                                                                                                  IntervalPGetDatum(newval)));
+       N.time += 1;
+
+       transdatums[0] = IntervalPGetDatum(newsum);
+       transdatums[1] = IntervalPGetDatum(&N);
+
+       result = construct_array(transdatums, 2,
+                                                        false, 12, 'd');
+
+       PG_RETURN_ARRAYTYPE_P(result);
+}
+
+Datum
+interval_avg(PG_FUNCTION_ARGS)
+{
+       ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+       Datum      *transdatums;
+       int                     ndatums;
+       Interval        sumX,
+                               N;
+
+       /* We assume the input is array of interval */
+       deconstruct_array(transarray,
+                                         false, 12, 'd',
+                                         &transdatums, &ndatums);
+       if (ndatums != 2)
+               elog(ERROR, "interval_avg: expected 2-element interval array");
+       /*
+        * XXX memcpy, instead of just extracting a pointer, to work around
+        * buggy array code: it won't ensure proper alignment of Interval
+        * objects on machines where double requires 8-byte alignment.
+        * That should be fixed, but in the meantime...
+        */
+       memcpy(&sumX, DatumGetIntervalP(transdatums[0]), sizeof(Interval));
+       memcpy(&N, DatumGetIntervalP(transdatums[1]), sizeof(Interval));
+
+       /* SQL92 defines AVG of no values to be NULL */
+       if (N.time == 0)
+               PG_RETURN_NULL();
+
+       return DirectFunctionCall2(interval_div,
+                                                          IntervalPGetDatum(&sumX),
+                                                          Float8GetDatum(N.time));
+}
+
+
 /* timestamp_age()
  * Calculate time difference while retaining year/month fields.
  * Note that this does not result in an accurate absolute time span
index b15840eea5e1929753da8f12acb20680119ec9fd..8e8e81feb49067cd7b7377feb3ecc28a41a9a28a 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.158 2000/07/11 13:07:17 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.159 2000/07/17 03:05:20 tgl Exp $
  *
  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  *
@@ -1421,22 +1421,16 @@ clearAggInfo(AggInfo *agginfo, int numArgs)
                        free(agginfo[i].oid);
                if (agginfo[i].aggname)
                        free(agginfo[i].aggname);
-               if (agginfo[i].aggtransfn1)
-                       free(agginfo[i].aggtransfn1);
-               if (agginfo[i].aggtransfn2)
-                       free(agginfo[i].aggtransfn2);
+               if (agginfo[i].aggtransfn)
+                       free(agginfo[i].aggtransfn);
                if (agginfo[i].aggfinalfn)
                        free(agginfo[i].aggfinalfn);
-               if (agginfo[i].aggtranstype1)
-                       free(agginfo[i].aggtranstype1);
+               if (agginfo[i].aggtranstype)
+                       free(agginfo[i].aggtranstype);
                if (agginfo[i].aggbasetype)
                        free(agginfo[i].aggbasetype);
-               if (agginfo[i].aggtranstype2)
-                       free(agginfo[i].aggtranstype2);
-               if (agginfo[i].agginitval1)
-                       free(agginfo[i].agginitval1);
-               if (agginfo[i].agginitval2)
-                       free(agginfo[i].agginitval2);
+               if (agginfo[i].agginitval)
+                       free(agginfo[i].agginitval);
                if (agginfo[i].usename)
                        free(agginfo[i].usename);
        }
@@ -1463,22 +1457,19 @@ getAggregates(int *numAggs)
 
        int                     i_oid;
        int                     i_aggname;
-       int                     i_aggtransfn1;
-       int                     i_aggtransfn2;
+       int                     i_aggtransfn;
        int                     i_aggfinalfn;
-       int                     i_aggtranstype1;
+       int                     i_aggtranstype;
        int                     i_aggbasetype;
-       int                     i_aggtranstype2;
-       int                     i_agginitval1;
-       int                     i_agginitval2;
+       int                     i_agginitval;
        int                     i_usename;
 
        /* find all user-defined aggregates */
 
        appendPQExpBuffer(query,
-                  "SELECT pg_aggregate.oid, aggname, aggtransfn1, aggtransfn2, "
-                               "aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, "
-                 "agginitval1, agginitval2, usename from pg_aggregate, pg_user "
+                                         "SELECT pg_aggregate.oid, aggname, aggtransfn, "
+                                         "aggfinalfn, aggtranstype, aggbasetype, "
+                                         "agginitval, usename from pg_aggregate, pg_user "
                                          "where aggowner = usesysid");
 
        res = PQexec(g_conn, query->data);
@@ -1497,28 +1488,22 @@ getAggregates(int *numAggs)
 
        i_oid = PQfnumber(res, "oid");
        i_aggname = PQfnumber(res, "aggname");
-       i_aggtransfn1 = PQfnumber(res, "aggtransfn1");
-       i_aggtransfn2 = PQfnumber(res, "aggtransfn2");
+       i_aggtransfn = PQfnumber(res, "aggtransfn");
        i_aggfinalfn = PQfnumber(res, "aggfinalfn");
-       i_aggtranstype1 = PQfnumber(res, "aggtranstype1");
+       i_aggtranstype = PQfnumber(res, "aggtranstype");
        i_aggbasetype = PQfnumber(res, "aggbasetype");
-       i_aggtranstype2 = PQfnumber(res, "aggtranstype2");
-       i_agginitval1 = PQfnumber(res, "agginitval1");
-       i_agginitval2 = PQfnumber(res, "agginitval2");
+       i_agginitval = PQfnumber(res, "agginitval");
        i_usename = PQfnumber(res, "usename");
 
        for (i = 0; i < ntups; i++)
        {
                agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
                agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
-               agginfo[i].aggtransfn1 = strdup(PQgetvalue(res, i, i_aggtransfn1));
-               agginfo[i].aggtransfn2 = strdup(PQgetvalue(res, i, i_aggtransfn2));
+               agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
                agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
-               agginfo[i].aggtranstype1 = strdup(PQgetvalue(res, i, i_aggtranstype1));
+               agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
                agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
-               agginfo[i].aggtranstype2 = strdup(PQgetvalue(res, i, i_aggtranstype2));
-               agginfo[i].agginitval1 = strdup(PQgetvalue(res, i, i_agginitval1));
-               agginfo[i].agginitval2 = strdup(PQgetvalue(res, i, i_agginitval2));
+               agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
                agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
        }
 
@@ -2902,69 +2887,32 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
        PQExpBuffer q = createPQExpBuffer();
        PQExpBuffer delq = createPQExpBuffer();
        PQExpBuffer aggSig = createPQExpBuffer();
-       PQExpBuffer sfunc1 = createPQExpBuffer();
-       PQExpBuffer sfunc2 = createPQExpBuffer();
-       PQExpBuffer basetype = createPQExpBuffer();
-       PQExpBuffer finalfunc = createPQExpBuffer();
-       char            comma1[2],
-                               comma2[2];
+       PQExpBuffer details = createPQExpBuffer();
 
        for (i = 0; i < numAggs; i++)
        {
-
-               resetPQExpBuffer(sfunc1);
-               resetPQExpBuffer(sfunc2);
-               resetPQExpBuffer(basetype);
-               resetPQExpBuffer(finalfunc);
+               resetPQExpBuffer(details);
 
                /* skip all the builtin oids */
                if (atoi(agginfo[i].oid) < g_last_builtin_oid)
                        continue;
 
-               appendPQExpBuffer(basetype,
+               appendPQExpBuffer(details,
                                                  "BASETYPE = %s, ",
                                                  fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
 
-               if (!(strcmp(agginfo[i].aggtransfn1, "-") == 0))
-               {
-                       appendPQExpBuffer(sfunc1,
-                                                         "SFUNC1 = %s, STYPE1 = %s",
-                                                         agginfo[i].aggtransfn1,
-                                                         fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype1), false));
-                       if (agginfo[i].agginitval1)
-                               appendPQExpBuffer(sfunc1, ", INITCOND1 = '%s'",
-                                                                 agginfo[i].agginitval1);
+               appendPQExpBuffer(details,
+                                                 "SFUNC = %s, STYPE = %s",
+                                                 agginfo[i].aggtransfn,
+                                                 fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype), false));
 
-               }
-
-               if (!(strcmp(agginfo[i].aggtransfn2, "-") == 0))
-               {
-                       appendPQExpBuffer(sfunc2,
-                                                         "SFUNC2 = %s, STYPE2 = %s",
-                                                         agginfo[i].aggtransfn2,
-                                                         fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype2), false));
-                       if (agginfo[i].agginitval2)
-                               appendPQExpBuffer(sfunc2, ", INITCOND2 = '%s'",
-                                                                 agginfo[i].agginitval2);
-               }
+               if (agginfo[i].agginitval)
+                       appendPQExpBuffer(details, ", INITCOND = '%s'",
+                                                         agginfo[i].agginitval);
 
                if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
-                       appendPQExpBuffer(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn);
-               if (sfunc1->data[0] != '\0' && sfunc2->data[0] != '\0')
-               {
-                       comma1[0] = ',';
-                       comma1[1] = '\0';
-               }
-               else
-                       comma1[0] = '\0';
-
-               if (finalfunc->data[0] != '\0' && (sfunc1->data[0] != '\0' || sfunc2->data[0] != '\0'))
-               {
-                       comma2[0] = ',';
-                       comma2[1] = '\0';
-               }
-               else
-                       comma2[0] = '\0';
+                       appendPQExpBuffer(details, ", FINALFUNC = %s",
+                                                         agginfo[i].aggfinalfn);
 
                resetPQExpBuffer(aggSig);
                appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
@@ -2974,14 +2922,9 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
                appendPQExpBuffer(delq, "DROP AGGREGATE %s;\n", aggSig->data);
 
                resetPQExpBuffer(q);
-               appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s %s%s %s%s %s );\n",
+               appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
                                                  agginfo[i].aggname,
-                                                 basetype->data,
-                                                 sfunc1->data,
-                                                 comma1,
-                                                 sfunc2->data,
-                                                 comma2,
-                                                 finalfunc->data);
+                                                 details->data);
 
                ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
                                                q->data, delq->data, agginfo[i].usename, NULL, NULL);
index 609868dbcd607f82de54dd0a61ce1bef72dd3b68..8ad340f64bb46719342f80d465f2893ecfb9cb1f 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.49 2000/07/04 14:25:28 momjian Exp $
+ * $Id: pg_dump.h,v 1.50 2000/07/17 03:05:20 tgl Exp $
  *
  * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
  *
@@ -133,14 +133,11 @@ typedef struct _aggInfo
 {
        char       *oid;
        char       *aggname;
-       char       *aggtransfn1;
-       char       *aggtransfn2;
+       char       *aggtransfn;
        char       *aggfinalfn;
-       char       *aggtranstype1;
+       char       *aggtranstype;
        char       *aggbasetype;
-       char       *aggtranstype2;
-       char       *agginitval1;
-       char       *agginitval2;
+       char       *agginitval;
        char       *usename;
 } AggInfo;
 
index 603c5bbfe852ccea6e7f4df015bc7cd461294e15..60abde17368c87570a0652f5fe896b97b07e4db4 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: c.h,v 1.78 2000/07/12 22:59:12 petere Exp $
+ * $Id: c.h,v 1.79 2000/07/17 03:05:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -587,6 +587,25 @@ extern Datum Float8GetDatum(float8 X);
 
 #define Float64GetDatum(X) PointerGetDatum(X)
 
+/*
+ * Int64GetDatumFast
+ * Float4GetDatumFast
+ * Float8GetDatumFast
+ *
+ * These macros are intended to allow writing code that does not depend on
+ * whether int64, float4, float8 are pass-by-reference types, while not
+ * sacrificing performance when they are.  The argument must be a variable
+ * that will exist and have the same value for as long as the Datum is needed.
+ * In the pass-by-ref case, the address of the variable is taken to use as
+ * the Datum.  In the pass-by-val case, these will be the same as the non-Fast
+ * macros.
+ */
+
+#define Int64GetDatumFast(X)  PointerGetDatum(&(X))
+#define Float4GetDatumFast(X) PointerGetDatum(&(X))
+#define Float8GetDatumFast(X) PointerGetDatum(&(X))
+
+
 /* ----------------------------------------------------------------
  *                             Section 5:      IsValid macros for system types
  * ----------------------------------------------------------------
index 0d4aec6c7ec25995cbf3bb637b2689ed6ddad1b6..80be91a70f48d87d4ed70426e4089fc4f93aa7f7 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.36 2000/07/07 19:24:41 petere Exp $
+ * $Id: catversion.h,v 1.37 2000/07/17 03:05:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200007071
+#define CATALOG_VERSION_NO     200007161
 
 #endif
index 2350d7385655c55d8366fb0f5acf58893f8dfc57..1c061cd6687f3801cad33e6dfa51167a4a20604c 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_aggregate.h,v 1.26 2000/05/30 04:24:55 tgl Exp $
+ * $Id: pg_aggregate.h,v 1.27 2000/07/17 03:05:23 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
  *             cpp turns this into typedef struct FormData_pg_aggregate
  *
  *     aggname                         name of the aggregate
- *     aggtransfn1                     transition function 1
- *     aggtransfn2                     transition function 2
+ *     aggowner                        owner (creator) of the aggregate
+ *     aggtransfn                      transition function
  *     aggfinalfn                      final function
  *     aggbasetype                     type of data on which aggregate operates
- *     aggtranstype1           output types for transition func 1
- *     aggtranstype2           output types for transition func 2
- *     aggfinaltype            output type for final function
- *     agginitval1                     initial aggregate value
- *     agginitval2                     initial value for transition state 2
+ *     aggtranstype            type of aggregate's transition (state) data
+ *     aggfinaltype            type of aggregate's final result
+ *     agginitval                      initial value for transition state
  * ----------------------------------------------------------------
  */
 CATALOG(pg_aggregate)
 {
        NameData        aggname;
        int4            aggowner;
-       regproc         aggtransfn1;
-       regproc         aggtransfn2;
+       regproc         aggtransfn;
        regproc         aggfinalfn;
        Oid                     aggbasetype;
-       Oid                     aggtranstype1;
-       Oid                     aggtranstype2;
+       Oid                     aggtranstype;
        Oid                     aggfinaltype;
-       text            agginitval1;    /* VARIABLE LENGTH FIELD */
-       text            agginitval2;    /* VARIABLE LENGTH FIELD */
+       text            agginitval;             /* VARIABLE LENGTH FIELD */
 } FormData_pg_aggregate;
 
 /* ----------------
@@ -70,18 +65,15 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
  * ----------------
  */
 
-#define Natts_pg_aggregate                             11
+#define Natts_pg_aggregate                             8
 #define Anum_pg_aggregate_aggname              1
 #define Anum_pg_aggregate_aggowner             2
-#define Anum_pg_aggregate_aggtransfn1  3
-#define Anum_pg_aggregate_aggtransfn2  4
-#define Anum_pg_aggregate_aggfinalfn   5
-#define Anum_pg_aggregate_aggbasetype  6
-#define Anum_pg_aggregate_aggtranstype1 7
-#define Anum_pg_aggregate_aggtranstype2 8
-#define Anum_pg_aggregate_aggfinaltype 9
-#define Anum_pg_aggregate_agginitval1  10
-#define Anum_pg_aggregate_agginitval2  11
+#define Anum_pg_aggregate_aggtransfn   3
+#define Anum_pg_aggregate_aggfinalfn   4
+#define Anum_pg_aggregate_aggbasetype  5
+#define Anum_pg_aggregate_aggtranstype 6
+#define Anum_pg_aggregate_aggfinaltype 7
+#define Anum_pg_aggregate_agginitval   8
 
 
 /* ----------------
@@ -89,70 +81,84 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
  * ---------------
  */
 
-DATA(insert OID = 0 ( avg      PGUID int8pl      int4inc       int84div                20       20   23   20 _null_ 0 ));
-DATA(insert OID = 0 ( avg      PGUID int4pl      int4inc       int4div                 23       23   23   23 _null_ 0 ));
-DATA(insert OID = 0 ( avg      PGUID int2pl      int2inc       int2div                 21       21   21   21 _null_ 0 ));
-DATA(insert OID = 0 ( avg      PGUID float4pl    float4inc float4div      700  700  700  700 _null_ 0.0 ));
-DATA(insert OID = 0 ( avg      PGUID float8pl    float8inc float8div      701  701  701  701 _null_ 0.0 ));
-DATA(insert OID = 0 ( avg      PGUID cash_pl     float8inc cash_div_flt8  790  790  701  790 _null_ 0.0 ));
-DATA(insert OID = 0 ( avg      PGUID interval_pl float8inc interval_div  1186 1186  701 1186 _null_ 0.0 ));
-DATA(insert OID = 0 ( avg      PGUID numeric_add numeric_inc numeric_div 1700 1700 1700 1700 _null_ 0 ));
-
-DATA(insert OID = 0 ( sum      PGUID int8pl                    - -   20   20 0   20 _null_ _null_ ));
-DATA(insert OID = 0 ( sum      PGUID int4pl                    - -   23   23 0   23 _null_ _null_ ));
-DATA(insert OID = 0 ( sum      PGUID int2pl                    - -   21   21 0   21 _null_ _null_ ));
-DATA(insert OID = 0 ( sum      PGUID float4pl                  - -  700  700 0  700 _null_ _null_ ));
-DATA(insert OID = 0 ( sum      PGUID float8pl                  - -  701  701 0  701 _null_ _null_ ));
-DATA(insert OID = 0 ( sum      PGUID cash_pl                   - -  790  790 0  790 _null_ _null_ ));
-DATA(insert OID = 0 ( sum      PGUID interval_pl               - - 1186 1186 0 1186 _null_ _null_ ));
-DATA(insert OID = 0 ( sum      PGUID numeric_add               - - 1700 1700 0 1700 _null_ _null_ ));
-
-DATA(insert OID = 0 ( max      PGUID int8larger                - -   20   20 0   20 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID int4larger                - -   23   23 0   23 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID int2larger                - -   21   21 0   21 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID float4larger              - -  700  700 0  700 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID float8larger              - -  701  701 0  701 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID int4larger                - -  702  702 0  702 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID date_larger               - - 1082 1082 0 1082 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID time_larger               - - 1083 1083 0 1083 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID timetz_larger             - - 1266 1266 0 1266 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID cashlarger                - -  790  790 0  790 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID timestamp_larger  - - 1184 1184 0 1184 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID interval_larger   - - 1186 1186 0 1186 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID text_larger               - -   25   25 0   25 _null_ _null_ ));
-DATA(insert OID = 0 ( max      PGUID numeric_larger    - - 1700 1700 0 1700 _null_ _null_ ));
-
-DATA(insert OID = 0 ( min      PGUID int8smaller               - -   20   20 0   20 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID int4smaller               - -   23   23 0   23 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID int2smaller               - -   21   21 0   21 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID float4smaller             - -  700  700 0  700 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID float8smaller             - -  701  701 0  701 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID int4smaller               - -  702  702 0  702 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID date_smaller              - - 1082 1082 0 1082 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID time_smaller              - - 1083 1083 0 1083 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID timetz_smaller    - - 1266 1266 0 1266 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID cashsmaller               - -  790  790 0  790 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID timestamp_smaller - - 1184 1184 0 1184 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID interval_smaller  - - 1186 1186 0 1186 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID text_smaller              - -   25   25 0   25 _null_ _null_ ));
-DATA(insert OID = 0 ( min      PGUID numeric_smaller   - - 1700 1700 0 1700 _null_ _null_ ));
-
-DATA(insert OID = 0 ( count PGUID - int4inc - 0 0 23 23 _null_ 0 ));
+DATA(insert OID = 0 ( avg      PGUID int8_accum        numeric_avg             20       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( avg      PGUID int4_accum        numeric_avg             23       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( avg      PGUID int2_accum        numeric_avg             21       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( avg      PGUID numeric_accum  numeric_avg        1700 1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( avg      PGUID float4_accum      float8_avg              700      1022 701 "{0,0,0}" ));
+DATA(insert OID = 0 ( avg      PGUID float8_accum      float8_avg              701      1022 701 "{0,0,0}" ));
+DATA(insert OID = 0 ( avg      PGUID interval_accum interval_avg       1186 1187 1186 "{0,0}" ));
+
+DATA(insert OID = 0 ( sum      PGUID int8_sum                  -   20 1700 1700 _null_ ));
+DATA(insert OID = 0 ( sum      PGUID int4_sum                  -   23 1700 1700 _null_ ));
+DATA(insert OID = 0 ( sum      PGUID int2_sum                  -   21 1700 1700 _null_ ));
+DATA(insert OID = 0 ( sum      PGUID float4pl                  -  700  700  700 _null_ ));
+DATA(insert OID = 0 ( sum      PGUID float8pl                  -  701  701  701 _null_ ));
+DATA(insert OID = 0 ( sum      PGUID cash_pl                   -  790  790  790 _null_ ));
+DATA(insert OID = 0 ( sum      PGUID interval_pl               - 1186 1186 1186 _null_ ));
+DATA(insert OID = 0 ( sum      PGUID numeric_add               - 1700 1700 1700 _null_ ));
+
+DATA(insert OID = 0 ( max      PGUID int8larger                -   20   20   20 _null_ ));
+DATA(insert OID = 0 ( max      PGUID int4larger                -   23   23   23 _null_ ));
+DATA(insert OID = 0 ( max      PGUID int2larger                -   21   21   21 _null_ ));
+DATA(insert OID = 0 ( max      PGUID float4larger              -  700  700  700 _null_ ));
+DATA(insert OID = 0 ( max      PGUID float8larger              -  701  701  701 _null_ ));
+DATA(insert OID = 0 ( max      PGUID int4larger                -  702  702  702 _null_ ));
+DATA(insert OID = 0 ( max      PGUID date_larger               - 1082 1082 1082 _null_ ));
+DATA(insert OID = 0 ( max      PGUID time_larger               - 1083 1083 1083 _null_ ));
+DATA(insert OID = 0 ( max      PGUID timetz_larger             - 1266 1266 1266 _null_ ));
+DATA(insert OID = 0 ( max      PGUID cashlarger                -  790  790  790 _null_ ));
+DATA(insert OID = 0 ( max      PGUID timestamp_larger  - 1184 1184 1184 _null_ ));
+DATA(insert OID = 0 ( max      PGUID interval_larger   - 1186 1186 1186 _null_ ));
+DATA(insert OID = 0 ( max      PGUID text_larger               -   25   25   25 _null_ ));
+DATA(insert OID = 0 ( max      PGUID numeric_larger    - 1700 1700 1700 _null_ ));
+
+DATA(insert OID = 0 ( min      PGUID int8smaller               -   20   20   20 _null_ ));
+DATA(insert OID = 0 ( min      PGUID int4smaller               -   23   23   23 _null_ ));
+DATA(insert OID = 0 ( min      PGUID int2smaller               -   21   21   21 _null_ ));
+DATA(insert OID = 0 ( min      PGUID float4smaller             -  700  700  700 _null_ ));
+DATA(insert OID = 0 ( min      PGUID float8smaller             -  701  701  701 _null_ ));
+DATA(insert OID = 0 ( min      PGUID int4smaller               -  702  702  702 _null_ ));
+DATA(insert OID = 0 ( min      PGUID date_smaller              - 1082 1082 1082 _null_ ));
+DATA(insert OID = 0 ( min      PGUID time_smaller              - 1083 1083 1083 _null_ ));
+DATA(insert OID = 0 ( min      PGUID timetz_smaller    - 1266 1266 1266 _null_ ));
+DATA(insert OID = 0 ( min      PGUID cashsmaller               -  790  790  790 _null_ ));
+DATA(insert OID = 0 ( min      PGUID timestamp_smaller - 1184 1184 1184 _null_ ));
+DATA(insert OID = 0 ( min      PGUID interval_smaller  - 1186 1186 1186 _null_ ));
+DATA(insert OID = 0 ( min      PGUID text_smaller              -   25   25   25 _null_ ));
+DATA(insert OID = 0 ( min      PGUID numeric_smaller   - 1700 1700 1700 _null_ ));
+
+/*
+ * Using int4inc for count() is cheating a little, since it really only
+ * takes 1 parameter not 2, but nodeAgg.c won't complain ...
+ */
+DATA(insert OID = 0 ( count PGUID int4inc           - 0 23 23 0 ));
+
+DATA(insert OID = 0 ( variance PGUID int8_accum        numeric_variance        20       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( variance PGUID int4_accum        numeric_variance        23       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( variance PGUID int2_accum        numeric_variance        21       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( variance PGUID float4_accum      float8_variance         700      1022 701 "{0,0,0}" ));
+DATA(insert OID = 0 ( variance PGUID float8_accum      float8_variance         701      1022 701 "{0,0,0}" ));
+DATA(insert OID = 0 ( variance PGUID numeric_accum  numeric_variance   1700 1231 1700 "{0,0,0}" ));
+
+DATA(insert OID = 0 ( stddev   PGUID int8_accum        numeric_stddev          20       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( stddev   PGUID int4_accum        numeric_stddev          23       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( stddev   PGUID int2_accum        numeric_stddev          21       1231 1700 "{0,0,0}" ));
+DATA(insert OID = 0 ( stddev   PGUID float4_accum      float8_stddev           700      1022 701 "{0,0,0}" ));
+DATA(insert OID = 0 ( stddev   PGUID float8_accum      float8_stddev           701      1022 701 "{0,0,0}" ));
+DATA(insert OID = 0 ( stddev   PGUID numeric_accum  numeric_stddev             1700 1231 1700 "{0,0,0}" ));
 
 /*
  * prototypes for functions in pg_aggregate.c
  */
 extern void AggregateCreate(char *aggName,
-                               char *aggtransfn1Name,
-                               char *aggtransfn2Name,
+                               char *aggtransfnName,
                                char *aggfinalfnName,
                                char *aggbasetypeName,
-                               char *aggtransfn1typeName,
-                               char *aggtransfn2typeName,
-                               char *agginitval1,
-                               char *agginitval2);
+                               char *aggtranstypeName,
+                               char *agginitval);
 
 extern Datum AggNameGetInitVal(char *aggName, Oid basetype,
-                                                          int xfuncno, bool *isNull);
+                                                          bool *isNull);
 
 #endif  /* PG_AGGREGATE_H */
index 06bb7546cd8dbb175a3f10f3a6f8345b55e6cd7f..20ea41ec0fbf9ca9ab5d35cb86900ada4085f3f0 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_operator.h,v 1.76 2000/06/05 07:28:59 tgl Exp $
+ * $Id: pg_operator.h,v 1.77 2000/07/17 03:05:23 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -323,12 +323,12 @@ DATA(insert OID = 636 (  "-"         PGUID 0 b t f  18  18  18 0 0  0 0 charmi - - ))
 DATA(insert OID = 637 (  "*"      PGUID 0 b t f  18  18  18 0 0  0 0 charmul - - ));
 DATA(insert OID = 638 (  "/"      PGUID 0 b t f  18  18  18 0 0  0 0 chardiv - - ));
 
-DATA(insert OID = 639 (  "~"      PGUID 0 b t f  19  25  16 0 640      0 0 nameregexeq eqsel eqjoinsel ));
+DATA(insert OID = 639 (  "~"      PGUID 0 b t f  19  25  16 0 640      0 0 nameregexeq regexeqsel regexeqjoinsel ));
 #define OID_NAME_REGEXEQ_OP            639
-DATA(insert OID = 640 (  "!~"     PGUID 0 b t f  19  25  16 0 639      0 0 nameregexne neqsel neqjoinsel ));
-DATA(insert OID = 641 (  "~"      PGUID 0 b t f  25  25  16 0 642      0 0 textregexeq eqsel eqjoinsel ));
+DATA(insert OID = 640 (  "!~"     PGUID 0 b t f  19  25  16 0 639      0 0 nameregexne regexnesel regexnejoinsel ));
+DATA(insert OID = 641 (  "~"      PGUID 0 b t f  25  25  16 0 642      0 0 textregexeq regexeqsel regexeqjoinsel ));
 #define OID_TEXT_REGEXEQ_OP            641
-DATA(insert OID = 642 (  "!~"     PGUID 0 b t f  25  25  16 0 641      0 0 textregexne neqsel neqjoinsel ));
+DATA(insert OID = 642 (  "!~"     PGUID 0 b t f  25  25  16 0 641      0 0 textregexne regexnesel regexnejoinsel ));
 DATA(insert OID = 643 (  "<>"     PGUID 0 b t f  19  19  16 643 93 0 0 namene neqsel neqjoinsel ));
 DATA(insert OID = 654 (  "||"     PGUID 0 b t f  25  25  25   0 0      0 0 textcat - - ));
 
@@ -449,9 +449,9 @@ DATA(insert OID =  974 (  "||"         PGUID 0 b t f 1042 1042 1042    0  0 0 0 textc
 DATA(insert OID =  979 (  "||"    PGUID 0 b t f 1043 1043 1043    0  0 0 0 textcat - - ));
 
 DATA(insert OID = 1054 ( "="      PGUID 0 b t f 1042 1042       16 1054 1057 1058 1058 bpchareq eqsel eqjoinsel ));
-DATA(insert OID = 1055 ( "~"      PGUID 0 b t f 1042   25       16    0 1056  0 0 textregexeq eqsel eqjoinsel ));
+DATA(insert OID = 1055 ( "~"      PGUID 0 b t f 1042   25       16    0 1056  0 0 textregexeq regexeqsel regexeqjoinsel ));
 #define OID_BPCHAR_REGEXEQ_OP          1055
-DATA(insert OID = 1056 ( "!~"     PGUID 0 b t f 1042   25       16    0 1055  0 0 textregexne neqsel neqjoinsel ));
+DATA(insert OID = 1056 ( "!~"     PGUID 0 b t f 1042   25       16    0 1055  0 0 textregexne regexnesel regexnejoinsel ));
 DATA(insert OID = 1057 ( "<>"     PGUID 0 b t f 1042 1042       16 1057 1054  0 0 bpcharne neqsel neqjoinsel ));
 DATA(insert OID = 1058 ( "<"      PGUID 0 b t f 1042 1042       16 1060 1061  0 0 bpcharlt scalarltsel scalarltjoinsel ));
 DATA(insert OID = 1059 ( "<="     PGUID 0 b t f 1042 1042       16 1061 1060  0 0 bpcharle scalarltsel scalarltjoinsel ));
@@ -459,9 +459,9 @@ DATA(insert OID = 1060 ( ">"           PGUID 0 b t f 1042 1042       16 1058 1059  0 0 bpcha
 DATA(insert OID = 1061 ( ">="     PGUID 0 b t f 1042 1042       16 1059 1058  0 0 bpcharge scalargtsel scalargtjoinsel ));
 
 DATA(insert OID = 1062 ( "="      PGUID 0 b t t 1043 1043      16      1062 1065 1066 1066 varchareq eqsel eqjoinsel ));
-DATA(insert OID = 1063 ( "~"      PGUID 0 b t f 1043   25      16 0 1064  0 0 textregexeq eqsel eqjoinsel ));
+DATA(insert OID = 1063 ( "~"      PGUID 0 b t f 1043   25      16 0 1064  0 0 textregexeq regexeqsel regexeqjoinsel ));
 #define OID_VARCHAR_REGEXEQ_OP         1063
-DATA(insert OID = 1064 ( "!~"     PGUID 0 b t f 1043   25      16 0 1063  0 0 textregexne neqsel neqjoinsel ));
+DATA(insert OID = 1064 ( "!~"     PGUID 0 b t f 1043   25      16 0 1063  0 0 textregexne regexnesel regexnejoinsel ));
 DATA(insert OID = 1065 ( "<>"     PGUID 0 b t f 1043 1043      16 1065 1062  0 0 varcharne neqsel neqjoinsel ));
 DATA(insert OID = 1066 ( "<"      PGUID 0 b t f 1043 1043      16 1068 1069  0 0 varcharlt scalarltsel scalarltjoinsel ));
 DATA(insert OID = 1067 ( "<="     PGUID 0 b t f 1043 1043      16 1069 1068  0 0 varcharle scalarltsel scalarltjoinsel ));
@@ -527,32 +527,32 @@ DATA(insert OID = 1158 (  "!"             PGUID 0 r t f   21        0   23 0 0 0 0 int2fac - - ));
 DATA(insert OID = 1175 (  "!!"         PGUID 0 l t f    0       21   23 0 0 0 0 int2fac - - ));
 
 /* LIKE hacks by Keith Parks. */
-DATA(insert OID = 1207 (  "~~"   PGUID 0 b t f  19   25  16 0 1208 0 0 namelike eqsel eqjoinsel ));
+DATA(insert OID = 1207 (  "~~"   PGUID 0 b t f  19   25  16 0 1208 0 0 namelike likesel likejoinsel ));
 #define OID_NAME_LIKE_OP               1207
-DATA(insert OID = 1208 (  "!~~"   PGUID 0 b t f  19   25  16 0 1207 0 0 namenlike neqsel neqjoinsel ));
-DATA(insert OID = 1209 (  "~~"   PGUID 0 b t f  25   25  16 0 1210 0 0 textlike eqsel eqjoinsel ));
+DATA(insert OID = 1208 (  "!~~"   PGUID 0 b t f  19   25  16 0 1207 0 0 namenlike nlikesel nlikejoinsel ));
+DATA(insert OID = 1209 (  "~~"   PGUID 0 b t f  25   25  16 0 1210 0 0 textlike likesel likejoinsel ));
 #define OID_TEXT_LIKE_OP               1209
-DATA(insert OID = 1210 (  "!~~"   PGUID 0 b t f  25   25  16 0 1209 0 0 textnlike neqsel neqjoinsel ));
-DATA(insert OID = 1211 (  "~~"   PGUID 0 b t f  1042 25  16 0 1212 0 0 textlike eqsel eqjoinsel ));
+DATA(insert OID = 1210 (  "!~~"   PGUID 0 b t f  25   25  16 0 1209 0 0 textnlike nlikesel nlikejoinsel ));
+DATA(insert OID = 1211 (  "~~"   PGUID 0 b t f  1042 25  16 0 1212 0 0 textlike likesel likejoinsel ));
 #define OID_BPCHAR_LIKE_OP             1211
-DATA(insert OID = 1212 (  "!~~"   PGUID 0 b t f  1042 25  16 0 1211 0 0 textnlike neqsel neqjoinsel ));
-DATA(insert OID = 1213 (  "~~"   PGUID 0 b t f  1043 25  16 0 1214 0 0 textlike eqsel eqjoinsel ));
+DATA(insert OID = 1212 (  "!~~"   PGUID 0 b t f  1042 25  16 0 1211 0 0 textnlike nlikesel nlikejoinsel ));
+DATA(insert OID = 1213 (  "~~"   PGUID 0 b t f  1043 25  16 0 1214 0 0 textlike likesel likejoinsel ));
 #define OID_VARCHAR_LIKE_OP            1213
-DATA(insert OID = 1214 (  "!~~"   PGUID 0 b t f  1043 25  16 0 1213 0 0 textnlike neqsel neqjoinsel ));
+DATA(insert OID = 1214 (  "!~~"   PGUID 0 b t f  1043 25  16 0 1213 0 0 textnlike nlikesel nlikejoinsel ));
 
 /* case-insensitive LIKE hacks */
-DATA(insert OID = 1226 (  "~*"          PGUID 0 b t f  19      25      16 0 1227  0 0 nameicregexeq eqsel eqjoinsel ));
+DATA(insert OID = 1226 (  "~*"          PGUID 0 b t f  19      25      16 0 1227  0 0 nameicregexeq icregexeqsel icregexeqjoinsel ));
 #define OID_NAME_ICREGEXEQ_OP          1226
-DATA(insert OID = 1227 (  "!~*"                 PGUID 0 b t f  19      25      16 0 1226  0 0 nameicregexne neqsel neqjoinsel ));
-DATA(insert OID = 1228 (  "~*"          PGUID 0 b t f  25      25      16 0 1229  0 0 texticregexeq eqsel eqjoinsel ));
+DATA(insert OID = 1227 (  "!~*"                 PGUID 0 b t f  19      25      16 0 1226  0 0 nameicregexne icregexnesel icregexnejoinsel ));
+DATA(insert OID = 1228 (  "~*"          PGUID 0 b t f  25      25      16 0 1229  0 0 texticregexeq icregexeqsel icregexeqjoinsel ));
 #define OID_TEXT_ICREGEXEQ_OP          1228
-DATA(insert OID = 1229 (  "!~*"                 PGUID 0 b t f  25      25      16 0 1228  0 0 texticregexne neqsel neqjoinsel ));
-DATA(insert OID = 1232 (  "~*"         PGUID 0 b t f  1043  25  16 0 1233      0 0 texticregexeq eqsel eqjoinsel ));
+DATA(insert OID = 1229 (  "!~*"                 PGUID 0 b t f  25      25      16 0 1228  0 0 texticregexne icregexnesel icregexnejoinsel ));
+DATA(insert OID = 1232 (  "~*"         PGUID 0 b t f  1043  25  16 0 1233      0 0 texticregexeq icregexeqsel icregexeqjoinsel ));
 #define OID_VARCHAR_ICREGEXEQ_OP               1232
-DATA(insert OID = 1233 ( "!~*"         PGUID 0 b t f  1043  25  16 0 1232      0 0 texticregexne neqsel neqjoinsel ));
-DATA(insert OID = 1234 (  "~*"         PGUID 0 b t f  1042  25  16 0 1235      0 0 texticregexeq eqsel eqjoinsel ));
+DATA(insert OID = 1233 ( "!~*"         PGUID 0 b t f  1043  25  16 0 1232      0 0 texticregexne icregexnesel icregexnejoinsel ));
+DATA(insert OID = 1234 (  "~*"         PGUID 0 b t f  1042  25  16 0 1235      0 0 texticregexeq icregexeqsel icregexeqjoinsel ));
 #define OID_BPCHAR_ICREGEXEQ_OP                1234
-DATA(insert OID = 1235 ( "!~*"         PGUID 0 b t f  1042  25  16 0 1234      0 0 texticregexne neqsel neqjoinsel ));
+DATA(insert OID = 1235 ( "!~*"         PGUID 0 b t f  1042  25  16 0 1234      0 0 texticregexne icregexnesel icregexnejoinsel ));
 
 /* timestamp operators */
 /* name, owner, prec, kind, isleft, canhash, left, right, result, com, negate, lsortop, rsortop, oprcode, operrest, oprjoin */
index 538299773d96afc37d658779ff64758b926b9f50..c92ce065fb38d2b8609e47d3bee66726ab4beaa5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.147 2000/07/14 22:17:56 tgl Exp $
+ * $Id: pg_proc.h,v 1.148 2000/07/17 03:05:25 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -433,8 +433,8 @@ DATA(insert OID = 206 (  float4um              PGUID 11 f t t t 1 f 700 "700" 100 0 0 100
 DESCR("negate");
 DATA(insert OID = 207 (  float4abs                PGUID 11 f t t t 1 f 700 "700" 100 0 0 100  float4abs - ));
 DESCR("absolute value");
-DATA(insert OID = 208 (  float4inc                PGUID 11 f t t t 1 f 700 "700" 100 0 0 100  float4inc - ));
-DESCR("increment");
+DATA(insert OID = 208 (  float4_accum     PGUID 12 f t t t 2 f 1022 "1022 700" 100 0 0 100  float4_accum - ));
+DESCR("aggregate transition function");
 DATA(insert OID = 209 (  float4larger     PGUID 11 f t t t 2 f 700 "700 700" 100 0 0 100  float4larger - ));
 DESCR("larger of two");
 DATA(insert OID = 211 (  float4smaller    PGUID 11 f t t t 2 f 700 "700 700" 100 0 0 100  float4smaller - ));
@@ -461,8 +461,8 @@ DATA(insert OID = 220 (  float8um              PGUID 11 f t t t 1 f 701 "701" 100 0 0 100
 DESCR("negate");
 DATA(insert OID = 221 (  float8abs                PGUID 11 f t t t 1 f 701 "701" 100 0 0 100  float8abs - ));
 DESCR("absolute value");
-DATA(insert OID = 222 (  float8inc                PGUID 11 f t t t 1 f 701 "701" 100 0 0 100  float8inc - ));
-DESCR("increment");
+DATA(insert OID = 222 (  float8_accum     PGUID 12 f t t t 2 f 1022 "1022 701" 100 0 0 100  float8_accum - ));
+DESCR("aggregate transition function");
 DATA(insert OID = 223 (  float8larger     PGUID 11 f t t t 2 f 701 "701 701" 100 0 0 100  float8larger - ));
 DESCR("larger of two");
 DATA(insert OID = 224 (  float8smaller    PGUID 11 f t t t 2 f 701 "701 701" 100 0 0 100  float8smaller - ));
@@ -1004,8 +1004,6 @@ DESCR("large object export");
 
 DATA(insert OID = 766 (  int4inc                  PGUID 12 f t t t 1 f 23 "23" 100 0 0 100  int4inc - ));
 DESCR("increment");
-DATA(insert OID = 767 (  int2inc                  PGUID 12 f t t t 1 f 21 "21" 100 0 0 100  int2inc - ));
-DESCR("increment");
 DATA(insert OID = 768 (  int4larger               PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4larger - ));
 DESCR("larger of two");
 DATA(insert OID = 769 (  int4smaller      PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4smaller - ));
@@ -1181,8 +1179,6 @@ DATA(insert OID = 944 (  char                        PGUID 12 f t t t 1 f 18 "25" 100 0 0 100  tex
 DESCR("convert text to char");
 DATA(insert OID = 946 (  text                     PGUID 12 f t t t 1 f 25 "18" 100 0 0 100  char_text - ));
 DESCR("convert char to text");
-DATA(insert OID = 948 (  varchar                  PGUID 12 f t t t 1 f 25 "1043" 100 0 0 100  bpchar_char - ));
-DESCR("convert varchar() to text");
 
 DATA(insert OID = 950 (  istrue                           PGUID 12 f t t f 1 f 16 "16" 100 0 0 100  istrue - ));
 DESCR("bool is true (not false or unknown)");
@@ -2395,8 +2391,6 @@ DATA(insert OID = 1746 ( float8                                   PGUID 11 f t t t 1 f 701 "1700" 100 0 0 100
 DESCR("(internal)");
 DATA(insert OID = 1764 ( numeric_inc                   PGUID 11 f t t t 1 f 1700 "1700" 100 0 0 100    numeric_inc - ));
 DESCR("increment by one");
-DATA(insert OID = 1765 ( numeric_dec                   PGUID 11 f t t t 1 f 1700 "1700" 100 0 0 100    numeric_dec - ));
-DESCR("decrement by one");
 DATA(insert OID = 1766 ( numeric_smaller               PGUID 11 f t t t 2 f 1700 "1700 1700" 100 0 0 100  numeric_smaller - ));
 DESCR("smaller of two numbers");
 DATA(insert OID = 1767 ( numeric_larger                        PGUID 11 f t t t 2 f 1700 "1700 1700" 100 0 0 100  numeric_larger - ));
@@ -2407,7 +2401,7 @@ DATA(insert OID = 1771 ( numeric_uminus                   PGUID 11 f t t t 1 f 1700 "1700" 100 0
 DESCR("negate");
 DATA(insert OID = 1779 ( int8                                  PGUID 11 f t t t 1 f 20 "1700" 100 0 0 100  numeric_int8 - ));
 DESCR("(internal)");
-DATA(insert OID = 1781 ( numeric                               PGUID 11 f t t t 1 f 1700 "20" 100 0 0 100  int8_numeric - ));
+DATA(insert OID = 1781 ( numeric                               PGUID 12 f t t t 1 f 1700 "20" 100 0 0 100  int8_numeric - ));
 DESCR("(internal)");
 DATA(insert OID = 1782 ( numeric                               PGUID 12 f t t t 1 f 1700 "21" 100 0 0 100  int2_numeric - ));
 DESCR("(internal)");
@@ -2465,6 +2459,38 @@ DESCR("join selectivity of NOT LIKE");
 DATA(insert OID = 1829 ( icregexnejoinsel      PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   icregexnejoinsel - ));
 DESCR("join selectivity of case-insensitive regex non-match");
 
+/* Aggregate-related functions */
+DATA(insert OID = 1830 (  float8_avg      PGUID 12 f t t t 1 f 701 "1022" 100 0 0 100  float8_avg - ));
+DESCR("AVG aggregate final function");
+DATA(insert OID = 1831 (  float8_variance  PGUID 12 f t t t 1 f 701 "1022" 100 0 0 100  float8_variance - ));
+DESCR("VARIANCE aggregate final function");
+DATA(insert OID = 1832 (  float8_stddev           PGUID 12 f t t t 1 f 701 "1022" 100 0 0 100  float8_stddev - ));
+DESCR("STDDEV aggregate final function");
+DATA(insert OID = 1833 (  numeric_accum           PGUID 12 f t t t 2 f 1231 "1231 1700" 100 0 0 100  numeric_accum - ));
+DESCR("aggregate transition function");
+DATA(insert OID = 1834 (  int2_accum      PGUID 12 f t t t 2 f 1231 "1231 21" 100 0 0 100  int2_accum - ));
+DESCR("aggregate transition function");
+DATA(insert OID = 1835 (  int4_accum      PGUID 12 f t t t 2 f 1231 "1231 23" 100 0 0 100  int4_accum - ));
+DESCR("aggregate transition function");
+DATA(insert OID = 1836 (  int8_accum      PGUID 12 f t t t 2 f 1231 "1231 20" 100 0 0 100  int8_accum - ));
+DESCR("aggregate transition function");
+DATA(insert OID = 1837 (  numeric_avg     PGUID 12 f t t t 1 f 1700 "1231" 100 0 0 100  numeric_avg - ));
+DESCR("AVG aggregate final function");
+DATA(insert OID = 1838 (  numeric_variance PGUID 12 f t t t 1 f 1700 "1231" 100 0 0 100  numeric_variance - ));
+DESCR("VARIANCE aggregate final function");
+DATA(insert OID = 1839 (  numeric_stddev   PGUID 12 f t t t 1 f 1700 "1231" 100 0 0 100  numeric_stddev - ));
+DESCR("STDDEV aggregate final function");
+DATA(insert OID = 1840 (  int2_sum                PGUID 12 f t t f 2 f 1700 "1700 21" 100 0 0 100  int2_sum - ));
+DESCR("SUM(int2) transition function");
+DATA(insert OID = 1841 (  int4_sum                PGUID 12 f t t f 2 f 1700 "1700 23" 100 0 0 100  int4_sum - ));
+DESCR("SUM(int4) transition function");
+DATA(insert OID = 1842 (  int8_sum                PGUID 12 f t t f 2 f 1700 "1700 20" 100 0 0 100  int8_sum - ));
+DESCR("SUM(int8) transition function");
+DATA(insert OID = 1843 (  interval_accum   PGUID 12 f t t t 2 f 1187 "1187 1186" 100 0 0 100  interval_accum - ));
+DESCR("aggregate transition function");
+DATA(insert OID = 1844 (  interval_avg    PGUID 12 f t t t 1 f 1186 "1187" 100 0 0 100  interval_avg - ));
+DESCR("AVG aggregate final function");
+
 
 /*
  * prototypes for functions pg_proc.c
index 6f675873cc8558a4c34c832f6568452dc5566916..2cf59ca50c21641c134ce31be436f9337990a1ae 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.43 2000/06/12 19:40:49 momjian Exp $
+ * $Id: primnodes.h,v 1.44 2000/07/17 03:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -301,10 +301,9 @@ typedef struct Iter
  *             basetype                - base type Oid of the aggregate (ie, input type)
  *             aggtype                 - type Oid of final result of the aggregate
  *             target                  - attribute or expression we are aggregating on
- *             usenulls                - TRUE to accept null values as inputs
  *             aggstar                 - TRUE if argument was really '*'
- *             aggdistinct             - TRUE if arguments were labeled DISTINCT
- *             aggno                   - workspace for nodeAgg.c executor
+ *             aggdistinct             - TRUE if it's agg(DISTINCT ...)
+ *             aggno                   - workspace for executor (see nodeAgg.c)
  * ----------------
  */
 typedef struct Aggref
@@ -314,7 +313,6 @@ typedef struct Aggref
        Oid                     basetype;
        Oid                     aggtype;
        Node       *target;
-       bool            usenulls;
        bool            aggstar;
        bool            aggdistinct;
        int                     aggno;
index 7ec383abe7d51300539242b798f983053304155d..195842811afd8eb60a4524986099a97cc1a29f72 100644 (file)
@@ -7,18 +7,16 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lock.h,v 1.38 2000/05/31 00:28:38 petere Exp $
+ * $Id: lock.h,v 1.39 2000/07/17 03:05:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef LOCK_H_
 #define LOCK_H_
 
-#include "postgres.h"
 #include "storage/ipc.h"
 #include "storage/itemptr.h"
 #include "storage/shmem.h"
-#include "utils/array.h"
 
 extern SPINLOCK LockMgrLock;
 typedef int LOCKMASK;
index 4fb296671d77f162ded89999597bd9082c745f84..4d915e0665fef49eb8172ddd92a3f889364fd309 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: array.h,v 1.25 2000/06/13 07:35:30 tgl Exp $
+ * $Id: array.h,v 1.26 2000/07/17 03:05:32 tgl Exp $
  *
  * NOTES
  *       XXX the data array should be MAXALIGN'd -- notice that the array
 #define ARRAY_H
 
 #include "fmgr.h"
-#include "utils/memutils.h"
 
+/*
+ * Arrays are varlena objects, so must meet the varlena convention that
+ * the first int32 of the object contains the total object size in bytes.
+ */
 typedef struct
 {
-       int                     size;                   /* total array size (in bytes) */
+       int32           size;                   /* total array size (varlena requirement) */
        int                     ndim;                   /* # of dimensions */
        int                     flags;                  /* implementation flags */
 } ArrayType;
 
+/*
+ * fmgr macros for array objects
+ */
+#define DatumGetArrayTypeP(X)         ((ArrayType *) PG_DETOAST_DATUM(X))
+#define DatumGetArrayTypePCopy(X)     ((ArrayType *) PG_DETOAST_DATUM_COPY(X))
+#define PG_GETARG_ARRAYTYPE_P(n)      DatumGetArrayTypeP(PG_GETARG_DATUM(n))
+#define PG_GETARG_ARRAYTYPE_P_COPY(n) DatumGetArrayTypePCopy(PG_GETARG_DATUM(n))
+#define PG_RETURN_ARRAYTYPE_P(x)      PG_RETURN_POINTER(x)
+
 /*
  * bitmask of ArrayType flags field:
  * 1st bit - large object flag
@@ -43,11 +55,9 @@ typedef struct
 #define ARR_CHK_FLAG   (0x2)
 #define ARR_OBJ_MASK   (0x1c)
 
-#define ARR_FLAGS(a)                   ((ArrayType *) a)->flags
 #define ARR_SIZE(a)                            (((ArrayType *) a)->size)
-
 #define ARR_NDIM(a)                            (((ArrayType *) a)->ndim)
-#define ARR_NDIM_PTR(a)                        (&(((ArrayType *) a)->ndim))
+#define ARR_FLAGS(a)                   (((ArrayType *) a)->flags)
 
 #define ARR_IS_LO(a) \
                (((ArrayType *) a)->flags & ARR_LOB_FLAG)
@@ -102,7 +112,6 @@ typedef struct
 #define RETURN_NULL(type)  do { *isNull = true; return (type) 0; } while (0)
 
 #define NAME_LEN       30
-#define MAX_BUFF_SIZE BLCKSZ
 
 typedef struct
 {
@@ -134,6 +143,12 @@ extern ArrayType *array_assgn(ArrayType *array, int nSubscripts,
                                                          bool elmbyval, int elmlen, bool *isNull);
 extern Datum array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType);
 
+extern ArrayType *construct_array(Datum *elems, int nelems,
+                                                                 bool elmbyval, int elmlen, char elmalign);
+extern void deconstruct_array(ArrayType *array,
+                                                         bool elmbyval, int elmlen, char elmalign,
+                                                         Datum **elemsp, int *nelemsp);
+
 extern int _LOtransfer(char **destfd, int size, int nitems, char **srcfd,
                        int isSrcLO, int isDestLO);
 extern char *_array_newLO(int *fd, int flag);
index 07e732f1e8645c25618c1d269c9a5f34479213ed..db772d6ecf2b69538fa88f20b192893127defa4d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.123 2000/07/09 21:30:21 petere Exp $
+ * $Id: builtins.h,v 1.124 2000/07/17 03:05:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,7 +110,6 @@ extern Datum int2mi(PG_FUNCTION_ARGS);
 extern Datum int2mul(PG_FUNCTION_ARGS);
 extern Datum int2div(PG_FUNCTION_ARGS);
 extern Datum int2abs(PG_FUNCTION_ARGS);
-extern Datum int2inc(PG_FUNCTION_ARGS);
 extern Datum int24pl(PG_FUNCTION_ARGS);
 extern Datum int24mi(PG_FUNCTION_ARGS);
 extern Datum int24mul(PG_FUNCTION_ARGS);
@@ -207,12 +206,10 @@ extern float32 float4pl(float32 arg1, float32 arg2);
 extern float32 float4mi(float32 arg1, float32 arg2);
 extern float32 float4mul(float32 arg1, float32 arg2);
 extern float32 float4div(float32 arg1, float32 arg2);
-extern float32 float4inc(float32 arg1);
 extern float64 float8pl(float64 arg1, float64 arg2);
 extern float64 float8mi(float64 arg1, float64 arg2);
 extern float64 float8mul(float64 arg1, float64 arg2);
 extern float64 float8div(float64 arg1, float64 arg2);
-extern float64 float8inc(float64 arg1);
 extern bool float4eq(float32 arg1, float32 arg2);
 extern bool float4ne(float32 arg1, float32 arg2);
 extern bool float4lt(float32 arg1, float32 arg2);
@@ -261,6 +258,11 @@ extern float64 radians(float64 arg1);
 extern float64 dtan(float64 arg1);
 extern float64 drandom(void);
 extern int32 setseed(float64 seed);
+extern Datum float8_accum(PG_FUNCTION_ARGS);
+extern Datum float4_accum(PG_FUNCTION_ARGS);
+extern Datum float8_avg(PG_FUNCTION_ARGS);
+extern Datum float8_variance(PG_FUNCTION_ARGS);
+extern Datum float8_stddev(PG_FUNCTION_ARGS);
 
 extern float64 float48pl(float32 arg1, float64 arg2);
 extern float64 float48mi(float32 arg1, float64 arg2);
@@ -545,7 +547,6 @@ extern Numeric numeric_mul(Numeric num1, Numeric num2);
 extern Numeric numeric_div(Numeric num1, Numeric num2);
 extern Numeric numeric_mod(Numeric num1, Numeric num2);
 extern Numeric numeric_inc(Numeric num);
-extern Numeric numeric_dec(Numeric num);
 extern Numeric numeric_smaller(Numeric num1, Numeric num2);
 extern Numeric numeric_larger(Numeric num1, Numeric num2);
 extern Numeric numeric_sqrt(Numeric num);
@@ -555,14 +556,24 @@ extern Numeric numeric_log(Numeric num1, Numeric num2);
 extern Numeric numeric_power(Numeric num1, Numeric num2);
 extern Datum int4_numeric(PG_FUNCTION_ARGS);
 extern int32 numeric_int4(Numeric num);
-extern Numeric int8_numeric(int64 *val);
+extern Datum int8_numeric(PG_FUNCTION_ARGS);
 extern int64 *numeric_int8(Numeric num);
 extern Datum int2_numeric(PG_FUNCTION_ARGS);
 extern Datum numeric_int2(PG_FUNCTION_ARGS);
-extern Numeric float4_numeric(float32 val);
-extern float32 numeric_float4(Numeric num);
 extern Numeric float8_numeric(float64 val);
 extern float64 numeric_float8(Numeric num);
+extern Numeric float4_numeric(float32 val);
+extern float32 numeric_float4(Numeric num);
+extern Datum numeric_accum(PG_FUNCTION_ARGS);
+extern Datum int2_accum(PG_FUNCTION_ARGS);
+extern Datum int4_accum(PG_FUNCTION_ARGS);
+extern Datum int8_accum(PG_FUNCTION_ARGS);
+extern Datum numeric_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_variance(PG_FUNCTION_ARGS);
+extern Datum numeric_stddev(PG_FUNCTION_ARGS);
+extern Datum int2_sum(PG_FUNCTION_ARGS);
+extern Datum int4_sum(PG_FUNCTION_ARGS);
+extern Datum int8_sum(PG_FUNCTION_ARGS);
 
 /* lztext.c */
 extern lztext  *lztextin(char *str);
index 1a0dd692dbd7dea35546bfc1914113c67dfbe9a0..8e6412eabeeff7e863abb2cd103d6bb5cf4b3897 100644 (file)
@@ -5,7 +5,7 @@
  *
  *     1998 Jan Wieck
  *
- * $Header: /cvsroot/pgsql/src/include/utils/numeric.h,v 1.10 2000/06/13 07:35:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/include/utils/numeric.h,v 1.11 2000/07/17 03:05:32 tgl Exp $
  *
  * ----------
  */
@@ -55,7 +55,7 @@
  * all leading and trailing zeroes (except there will be a trailing zero
  * in the last byte, if the number of digits is odd).  In particular,
  * if the value is zero, there will be no digits at all!  The weight is
- * arbitrary in this case, but we normally set it to zero.
+ * arbitrary in that case, but we normally set it to zero.
  * ----------
  */
 typedef struct NumericData
@@ -75,9 +75,11 @@ typedef NumericData *Numeric;
  * fmgr interface macros
  */
 
-#define DatumGetNumeric(X)    ((Numeric) PG_DETOAST_DATUM(X))
-#define NumericGetDatum(X)    PointerGetDatum(X)
-#define PG_GETARG_NUMERIC(n)  DatumGetNumeric(PG_GETARG_DATUM(n))
-#define PG_RETURN_NUMERIC(x)  return NumericGetDatum(x)
+#define DatumGetNumeric(X)        ((Numeric) PG_DETOAST_DATUM(X))
+#define DatumGetNumericCopy(X)    ((Numeric) PG_DETOAST_DATUM_COPY(X))
+#define NumericGetDatum(X)        PointerGetDatum(X)
+#define PG_GETARG_NUMERIC(n)      DatumGetNumeric(PG_GETARG_DATUM(n))
+#define PG_GETARG_NUMERIC_COPY(n) DatumGetNumericCopy(PG_GETARG_DATUM(n))
+#define PG_RETURN_NUMERIC(x)      return NumericGetDatum(x)
 
 #endif  /* _PG_NUMERIC_H_ */
index 61db8e7d2064d4b107ed7b081e8e66ef23f8d841..b848c894a0414b86bb26119fc835bc79f4f6136a 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: timestamp.h,v 1.8 2000/06/19 03:54:48 tgl Exp $
+ * $Id: timestamp.h,v 1.9 2000/07/17 03:05:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -171,6 +171,8 @@ extern Datum interval_mi(PG_FUNCTION_ARGS);
 extern Datum interval_mul(PG_FUNCTION_ARGS);
 extern Datum mul_d_interval(PG_FUNCTION_ARGS);
 extern Datum interval_div(PG_FUNCTION_ARGS);
+extern Datum interval_accum(PG_FUNCTION_ARGS);
+extern Datum interval_avg(PG_FUNCTION_ARGS);
 
 extern Datum timestamp_mi(PG_FUNCTION_ARGS);
 extern Datum timestamp_pl_span(PG_FUNCTION_ARGS);
index fe71584e1a1ceb13322ff8460fec4a055745fdac..7faabc129613df677e82c021aa5eb9c1d17c3f4b 100644 (file)
@@ -386,28 +386,33 @@ create function tcl_int4add(int4,int4) returns int4 as '
     return [expr $1 + $2]
 ' language 'pltcl';
 
-create function tcl_int4div(int4,int4) returns int4 as '
-    return [expr $1 / $2]
+-- We use split(n) as a quick-and-dirty way of parsing the input array
+-- value, which comes in as a string like '{1,2}'.  There are better ways...
+
+create function tcl_int4_accum(_int4,int4) returns _int4 as '
+    set state [split $1 "{,}"]
+    set newsum [expr {[lindex $state 1] + $2}]
+    set newcnt [expr {[lindex $state 2] + 1}]
+    return "{$newsum,$newcnt}"
 ' language 'pltcl';
 
-create function tcl_int4inc(int4) returns int4 as '
-    return [expr $1 + 1]
+create function tcl_int4_avg(_int4) returns int4 as '
+    set state [split $1 "{,}"]
+    return [expr {[lindex $state 1] / [lindex $state 2]}]
 ' language 'pltcl';
 
 create aggregate tcl_avg (
-               sfunc1 = tcl_int4add,
+               sfunc = tcl_int4_accum,
                basetype = int4,
-               stype1 = int4,
-               sfunc2 = tcl_int4inc,
-               stype2 = int4,
-               finalfunc = tcl_int4div,
-               initcond2 = '0'
+               stype = _int4,
+               finalfunc = tcl_int4_avg,
+               initcond = '{0,0}'
        );
 
 create aggregate tcl_sum (
-               sfunc1 = tcl_int4add,
+               sfunc = tcl_int4add,
                basetype = int4,
-               stype1 = int4,
+               stype = int4,
                initcond1 = '0'
        );
 
index 92936e3414a6df44e65eb7dfd9668d3c871ffb5f..aaee72c01abdacc6520ba49a573041799875d226 100644 (file)
@@ -2,18 +2,20 @@
 -- AGGREGATES
 --
 SELECT avg(four) AS avg_1 FROM onek;
- avg_1 
--------
-     1
+    avg_1     
+--------------
+ 1.5000000000
 (1 row)
 
 SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
- avg_32 
---------
-     32
+    avg_32     
+---------------
+ 32.6666666667
 (1 row)
 
-SELECT avg(b) AS avg_107_943 FROM aggtest;
+-- In 7.1, avg(float4) is computed using float8 arithmetic.
+-- Round the result to 3 digits to avoid platform-specific results.
+SELECT avg(b)::numeric(10,3) AS avg_107_943 FROM aggtest;
  avg_107_943 
 -------------
      107.943
@@ -116,9 +118,9 @@ select ten, count(four), sum(DISTINCT four) from onek group by ten;
 (10 rows)
 
 SELECT newavg(four) AS avg_1 FROM onek;
- avg_1 
--------
-     1
+    avg_1     
+--------------
+ 1.5000000000
 (1 row)
 
 SELECT newsum(four) AS sum_1500 FROM onek;
index d7e46fffac58a40a37539ef653e6038ac530d989..ef83c886a11454511cff793b2458e83fde3263f3 100644 (file)
@@ -3,18 +3,17 @@
 --
 -- all functions CREATEd
 CREATE AGGREGATE newavg (
-   sfunc1 = int4pl, basetype = int4, stype1 = int4, 
-   sfunc2 = int4inc, stype2 = int4,
-   finalfunc = int4div,
-   initcond1 = '0', initcond2 = '0'
+   sfunc = int4_accum, basetype = int4, stype = _numeric, 
+   finalfunc = numeric_avg,
+   initcond1 = '{0,0,0}'
 );
--- sfunc1 (value-dependent) only 
+-- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4, 
    initcond1 = '0'
 );
--- sfunc2 (value-independent) only 
+-- value-independent transition function
 CREATE AGGREGATE newcnt (
-   sfunc2 = int4inc, basetype = int4, stype2 = int4, 
-   initcond2 = '0'
+   sfunc = int4inc, basetype = 'any', stype = int4,
+   initcond = '0'
 );
index 8332d4d89499e43bd63e56e2ce6a4e0678243fc3..66a5c3a5c8d202546ff5b22b431afb7638080df7 100644 (file)
@@ -99,46 +99,18 @@ end;
 NOTICE:  COMMIT: no transaction in progress
 --
 -- DEFINE AGGREGATE
--- left out finalfunc 
-create aggregate newavg1 (sfunc1 = int4pl,
-                         basetype = int4,
-                         stype1 = int4,
-                         sfunc2 = int4inc,
-                         stype2 = int4, 
-                         initcond1 = '0',
-                         initcond2 = '0');
-ERROR:  AggregateCreate: Aggregate must have final function with both transition functions
--- sfunc return type disagreement 
-create aggregate newavg2 (sfunc1 = int4pl,
-                         basetype = int4,
-                         stype1 = int4,
-                         sfunc2 = int2inc,
-                         stype2 = int2,
-                         finalfunc = int4div,
-                         initcond1 = '0',
-                         initcond2 = '0');
-ERROR:  AggregateCreate: 'int4div'('int4','int2') does not exist
 -- sfunc/finalfunc type disagreement 
-create aggregate newavg3 (sfunc1 = int4pl,
+create aggregate newavg2 (sfunc = int4pl,
                          basetype = int4,
-                         stype1 = int4,
-                         sfunc2 = int4inc,
-                         stype2 = int4,
-                         finalfunc = int2div,
-                         initcond1 = '0',
-                         initcond2 = '0');
-ERROR:  AggregateCreate: 'int2div'('int4','int4') does not exist
+                         stype = int4,
+                         finalfunc = int2um,
+                         initcond = '0');
+ERROR:  AggregateCreate: function 'int2um(int4)' does not exist
 -- left out basetype
-create aggregate newcnt1 (sfunc2 = int4inc,
-                         stype2 = int4,
-                       initcond2 = '0');
+create aggregate newcnt1 (sfunc = int4inc,
+                         stype = int4,
+                         initcond = '0');
 ERROR:  Define: "basetype" unspecified
--- left out initcond2 (for sfunc2) 
-create aggregate newcnt1 (sfunc2 = int4inc,
-                         basetype = int4,
-                         stype2 = int4);
-ERROR:  AggregateCreate: transition function 2 MUST have an initial value
 --
 -- REMOVE INDEX
  
index a42d3d89f02747434ab61441915c6fce983bd677..a2b0ad9e3e722827117e707ae7033a210771e9b4 100644 (file)
@@ -1,20 +1,12 @@
 --
 -- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
 --
-SELECT oid, pg_aggregate.aggtransfn1 
+SELECT oid, pg_aggregate.aggtransfn 
 FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtransfn1 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn1);
- oid | aggtransfn1 
------+-------------
-(0 rows)
-
-SELECT oid, pg_aggregate.aggtransfn2 
-FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtransfn2 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn2);
- oid | aggtransfn2 
------+-------------
+WHERE  pg_aggregate.aggtransfn != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn);
+ oid | aggtransfn 
+-----+------------
 (0 rows)
 
 SELECT oid, pg_aggregate.aggfinalfn 
@@ -33,20 +25,12 @@ WHERE       pg_aggregate.aggbasetype != 0 AND
 -----+-------------
 (0 rows)
 
-SELECT oid, pg_aggregate.aggtranstype1 
-FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtranstype1 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype1);
- oid | aggtranstype1 
------+---------------
-(0 rows)
-
-SELECT oid, pg_aggregate.aggtranstype2 
+SELECT oid, pg_aggregate.aggtranstype 
 FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtranstype2 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype2);
- oid | aggtranstype2 
------+---------------
+WHERE  pg_aggregate.aggtranstype != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype);
+ oid | aggtranstype 
+-----+--------------
 (0 rows)
 
 SELECT oid, pg_aggregate.aggfinaltype 
@@ -217,6 +201,22 @@ WHERE      pg_class.relam != 0 AND
 -----+-------
 (0 rows)
 
+SELECT oid, pg_class.reltoastrelid 
+FROM   pg_class 
+WHERE  pg_class.reltoastrelid != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastrelid);
+ oid | reltoastrelid 
+-----+---------------
+(0 rows)
+
+SELECT oid, pg_class.reltoastidxid 
+FROM   pg_class 
+WHERE  pg_class.reltoastidxid != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastidxid);
+ oid | reltoastidxid 
+-----+---------------
+(0 rows)
+
 SELECT oid, pg_index.indexrelid 
 FROM   pg_index 
 WHERE  pg_index.indexrelid != 0 AND 
index 893b4bca83f76367f5cec08eb267b65c174cc2e6..70f0134693e39de6eaa842826cc18646ed409157 100644 (file)
@@ -84,9 +84,8 @@ WHERE p1.oid != p2.oid AND
     (p1.prorettype < p2.prorettype);
  prorettype | prorettype 
 ------------+------------
-         18 |         25
          25 |       1043
-(2 rows)
+(1 row)
 
 SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
 FROM pg_proc AS p1, pg_proc AS p2
@@ -98,8 +97,7 @@ WHERE p1.oid != p2.oid AND
  proargtypes | proargtypes 
 -------------+-------------
           25 |        1043
-        1042 |        1043
-(2 rows)
+(1 row)
 
 SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
 FROM pg_proc AS p1, pg_proc AS p2
@@ -434,83 +432,40 @@ WHERE p1.oprjoin = p2.oid AND
 
 -- **************** pg_aggregate ****************
 -- Look for illegal values in pg_aggregate fields.
--- aggbasetype can only be 0 if transfn1 is not present (eg, count(*))
--- or itself takes a wild-card input; we check the latter case below.
-SELECT p1.oid, p1.aggname
-FROM pg_aggregate as p1
-WHERE (p1.aggbasetype = 0 AND p1.aggtransfn1 != 0) OR aggfinaltype = 0;
- oid | aggname 
------+---------
-(0 rows)
-
--- Check combinations of transfer functions.
--- Although either transfn1 or transfn2 can be null,
--- it makes no sense for both to be.  And if both are defined,
--- presumably there should be a finalfn to combine their results.
--- We also check that transtypes are null just when corresponding
--- transfns are.  Also, if there is no finalfn then the output type
--- must be the transtype the result will be taken from.
-SELECT p1.oid, p1.aggname
-FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 = 0;
- oid | aggname 
------+---------
-(0 rows)
-
-SELECT p1.oid, p1.aggname
-FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 = 0 AND
-    (p1.aggtranstype1 = 0 OR p1.aggtranstype2 != 0 OR
-     (p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype1));
- oid | aggname 
------+---------
-(0 rows)
-
 SELECT p1.oid, p1.aggname
 FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 != 0 AND
-    (p1.aggtranstype1 != 0 OR p1.aggtranstype2 = 0 OR
-     (p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype2));
+WHERE aggtransfn = 0 OR aggtranstype = 0 OR aggfinaltype = 0;
  oid | aggname 
 -----+---------
 (0 rows)
 
+-- If there is no finalfn then the output type must be the transtype.
 SELECT p1.oid, p1.aggname
 FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 != 0 AND
-    (p1.aggtranstype1 = 0 OR p1.aggtranstype2 = 0 OR
-     p1.aggfinalfn = 0);
+WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
  oid | aggname 
 -----+---------
 (0 rows)
 
--- Cross-check transfn1 (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.aggtransfn1 = p2.oid AND
-    (p2.proretset OR p2.pronargs != 2
--- diked out until we find a way of marking binary-compatible types
--- OR
---     p1.aggtranstype1 != p2.prorettype OR
---     p1.aggtranstype1 != p2.proargtypes[0] OR
---     p1.aggbasetype != p2.proargtypes[1]
-);
- oid | aggname | oid | proname 
------+---------+-----+---------
-(0 rows)
-
--- Cross-check transfn2 (if present) against its entry in pg_proc.
+-- Cross-check transfn against its entry in pg_proc.
 -- FIXME: what about binary-compatible types?
+-- NOTE: in 7.1, this search finds max and min on abstime, which are
+-- implemented using int4larger/int4smaller.  Until we have
+-- some cleaner way of dealing with binary-equivalent types, just leave
+-- those two tuples in the expected output.
 SELECT p1.oid, p1.aggname, p2.oid, p2.proname
 FROM pg_aggregate AS p1, pg_proc AS p2
-WHERE p1.aggtransfn2 = p2.oid AND
-    (p2.proretset OR p1.aggtranstype2 != p2.prorettype OR
-     p2.pronargs != 1 OR
-     p1.aggtranstype2 != p2.proargtypes[0]);
- oid | aggname | oid | proname 
------+---------+-----+---------
-(0 rows)
+WHERE p1.aggtransfn = p2.oid AND
+    (p2.proretset OR
+     p1.aggtranstype != p2.prorettype OR
+     p1.aggtranstype != p2.proargtypes[0] OR
+     NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
+          (p2.pronargs = 1 AND p1.aggbasetype = 0)));
+  oid  | aggname | oid |   proname   
+-------+---------+-----+-------------
+ 16978 | max     | 768 | int4larger
+ 16992 | min     | 769 | int4smaller
+(2 rows)
 
 -- Cross-check finalfn (if present) against its entry in pg_proc.
 -- FIXME: what about binary-compatible types?
@@ -518,9 +473,8 @@ SELECT p1.oid, p1.aggname, p2.oid, p2.proname
 FROM pg_aggregate AS p1, pg_proc AS p2
 WHERE p1.aggfinalfn = p2.oid AND
     (p2.proretset OR p1.aggfinaltype != p2.prorettype OR
-     p2.pronargs != 2 OR
-     p1.aggtranstype1 != p2.proargtypes[0] OR
-     p1.aggtranstype2 != p2.proargtypes[1]);
+     p2.pronargs != 1 OR
+     p1.aggtranstype != p2.proargtypes[0]);
  oid | aggname | oid | proname 
 -----+---------+-----+---------
 (0 rows)
index 45b8dd990fcef7df99bb9a635756f58f76b42b04..33c8fb5f35155113d2be664c0fac6ac5b0d71070 100644 (file)
@@ -6,7 +6,10 @@ SELECT avg(four) AS avg_1 FROM onek;
 
 SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
 
-SELECT avg(b) AS avg_107_943 FROM aggtest;
+-- In 7.1, avg(float4) is computed using float8 arithmetic.
+-- Round the result to 3 digits to avoid platform-specific results.
+
+SELECT avg(b)::numeric(10,3) AS avg_107_943 FROM aggtest;
 
 SELECT avg(gpa) AS avg_3_4 FROM ONLY student;
 
index 046f945738b8008a6b2cb96cc40be237eafe92ee..5d42ed057e3d9a9fb7c9d3f44bae4846d2579176 100644 (file)
@@ -4,21 +4,20 @@
 
 -- all functions CREATEd
 CREATE AGGREGATE newavg (
-   sfunc1 = int4pl, basetype = int4, stype1 = int4, 
-   sfunc2 = int4inc, stype2 = int4,
-   finalfunc = int4div,
-   initcond1 = '0', initcond2 = '0'
+   sfunc = int4_accum, basetype = int4, stype = _numeric, 
+   finalfunc = numeric_avg,
+   initcond1 = '{0,0,0}'
 );
 
--- sfunc1 (value-dependent) only 
+-- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4, 
    initcond1 = '0'
 );
 
--- sfunc2 (value-independent) only 
+-- value-independent transition function
 CREATE AGGREGATE newcnt (
-   sfunc2 = int4inc, basetype = int4, stype2 = int4, 
-   initcond2 = '0'
+   sfunc = int4inc, basetype = 'any', stype = int4,
+   initcond = '0'
 );
 
index ffcb5fcdb7428dafb5a8e4f44bb7983f61e24d95..86c4e4fe60f0d45787ebf934da15ce1d59708b48 100644 (file)
@@ -114,45 +114,18 @@ end;
 
 --
 -- DEFINE AGGREGATE
--- left out finalfunc 
-create aggregate newavg1 (sfunc1 = int4pl,
-                         basetype = int4,
-                         stype1 = int4,
-                         sfunc2 = int4inc,
-                         stype2 = int4, 
-                         initcond1 = '0',
-                         initcond2 = '0');
-
--- sfunc return type disagreement 
-create aggregate newavg2 (sfunc1 = int4pl,
-                         basetype = int4,
-                         stype1 = int4,
-                         sfunc2 = int2inc,
-                         stype2 = int2,
-                         finalfunc = int4div,
-                         initcond1 = '0',
-                         initcond2 = '0');
 
 -- sfunc/finalfunc type disagreement 
-create aggregate newavg3 (sfunc1 = int4pl,
+create aggregate newavg2 (sfunc = int4pl,
                          basetype = int4,
-                         stype1 = int4,
-                         sfunc2 = int4inc,
-                         stype2 = int4,
-                         finalfunc = int2div,
-                         initcond1 = '0',
-                         initcond2 = '0');
+                         stype = int4,
+                         finalfunc = int2um,
+                         initcond = '0');
 
 -- left out basetype
-create aggregate newcnt1 (sfunc2 = int4inc,
-                         stype2 = int4,
-                       initcond2 = '0');
-
--- left out initcond2 (for sfunc2) 
-create aggregate newcnt1 (sfunc2 = int4inc,
-                         basetype = int4,
-                         stype2 = int4);
+create aggregate newcnt1 (sfunc = int4inc,
+                         stype = int4,
+                         initcond = '0');
 
 
 --
index 7c6b4d99efb2c81acb11f3eb4d92c4c1a49e1bcc..b7ea1f63eaa8268d3583a670e9f3985619be0453 100644 (file)
@@ -1,14 +1,10 @@
 --
 -- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
 --
-SELECT oid, pg_aggregate.aggtransfn1 
+SELECT oid, pg_aggregate.aggtransfn 
 FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtransfn1 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn1);
-SELECT oid, pg_aggregate.aggtransfn2 
-FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtransfn2 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn2);
+WHERE  pg_aggregate.aggtransfn != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggtransfn);
 SELECT oid, pg_aggregate.aggfinalfn 
 FROM   pg_aggregate 
 WHERE  pg_aggregate.aggfinalfn != 0 AND 
@@ -17,14 +13,10 @@ SELECT      oid, pg_aggregate.aggbasetype
 FROM   pg_aggregate 
 WHERE  pg_aggregate.aggbasetype != 0 AND 
        NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggbasetype);
-SELECT oid, pg_aggregate.aggtranstype1 
-FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtranstype1 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype1);
-SELECT oid, pg_aggregate.aggtranstype2 
+SELECT oid, pg_aggregate.aggtranstype 
 FROM   pg_aggregate 
-WHERE  pg_aggregate.aggtranstype2 != 0 AND 
-       NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype2);
+WHERE  pg_aggregate.aggtranstype != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype);
 SELECT oid, pg_aggregate.aggfinaltype 
 FROM   pg_aggregate 
 WHERE  pg_aggregate.aggfinaltype != 0 AND 
@@ -109,6 +101,14 @@ SELECT     oid, pg_class.relam
 FROM   pg_class 
 WHERE  pg_class.relam != 0 AND 
        NOT EXISTS(SELECT * FROM pg_am AS t1 WHERE t1.oid = pg_class.relam);
+SELECT oid, pg_class.reltoastrelid 
+FROM   pg_class 
+WHERE  pg_class.reltoastrelid != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastrelid);
+SELECT oid, pg_class.reltoastidxid 
+FROM   pg_class 
+WHERE  pg_class.reltoastidxid != 0 AND 
+       NOT EXISTS(SELECT * FROM pg_class AS t1 WHERE t1.oid = pg_class.reltoastidxid);
 SELECT oid, pg_index.indexrelid 
 FROM   pg_index 
 WHERE  pg_index.indexrelid != 0 AND 
index 40fa91bf46ce108f10e985f8372ec7f1422516fb..d655e02eb89c70cb656ba242fc32b3a2d9a090c3 100644 (file)
@@ -363,66 +363,32 @@ WHERE p1.oprjoin = p2.oid AND
 -- **************** pg_aggregate ****************
 
 -- Look for illegal values in pg_aggregate fields.
--- aggbasetype can only be 0 if transfn1 is not present (eg, count(*))
--- or itself takes a wild-card input; we check the latter case below.
 
 SELECT p1.oid, p1.aggname
 FROM pg_aggregate as p1
-WHERE (p1.aggbasetype = 0 AND p1.aggtransfn1 != 0) OR aggfinaltype = 0;
+WHERE aggtransfn = 0 OR aggtranstype = 0 OR aggfinaltype = 0;
 
--- Check combinations of transfer functions.
--- Although either transfn1 or transfn2 can be null,
--- it makes no sense for both to be.  And if both are defined,
--- presumably there should be a finalfn to combine their results.
--- We also check that transtypes are null just when corresponding
--- transfns are.  Also, if there is no finalfn then the output type
--- must be the transtype the result will be taken from.
+-- If there is no finalfn then the output type must be the transtype.
 
 SELECT p1.oid, p1.aggname
 FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 = 0;
+WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
 
-SELECT p1.oid, p1.aggname
-FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 = 0 AND
-    (p1.aggtranstype1 = 0 OR p1.aggtranstype2 != 0 OR
-     (p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype1));
-
-SELECT p1.oid, p1.aggname
-FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 = 0 AND p1.aggtransfn2 != 0 AND
-    (p1.aggtranstype1 != 0 OR p1.aggtranstype2 = 0 OR
-     (p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype2));
-
-SELECT p1.oid, p1.aggname
-FROM pg_aggregate as p1
-WHERE p1.aggtransfn1 != 0 AND p1.aggtransfn2 != 0 AND
-    (p1.aggtranstype1 = 0 OR p1.aggtranstype2 = 0 OR
-     p1.aggfinalfn = 0);
-
--- Cross-check transfn1 (if present) against its entry in pg_proc.
--- 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.aggtransfn1 = p2.oid AND
-    (p2.proretset OR p2.pronargs != 2
--- diked out until we find a way of marking binary-compatible types
--- OR
---     p1.aggtranstype1 != p2.prorettype OR
---     p1.aggtranstype1 != p2.proargtypes[0] OR
---     p1.aggbasetype != p2.proargtypes[1]
-);
-
--- Cross-check transfn2 (if present) against its entry in pg_proc.
+-- Cross-check transfn against its entry in pg_proc.
 -- FIXME: what about binary-compatible types?
+-- NOTE: in 7.1, this search finds max and min on abstime, which are
+-- implemented using int4larger/int4smaller.  Until we have
+-- some cleaner way of dealing with binary-equivalent types, just leave
+-- those two tuples in the expected output.
 
 SELECT p1.oid, p1.aggname, p2.oid, p2.proname
 FROM pg_aggregate AS p1, pg_proc AS p2
-WHERE p1.aggtransfn2 = p2.oid AND
-    (p2.proretset OR p1.aggtranstype2 != p2.prorettype OR
-     p2.pronargs != 1 OR
-     p1.aggtranstype2 != p2.proargtypes[0]);
+WHERE p1.aggtransfn = p2.oid AND
+    (p2.proretset OR
+     p1.aggtranstype != p2.prorettype OR
+     p1.aggtranstype != p2.proargtypes[0] OR
+     NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
+          (p2.pronargs = 1 AND p1.aggbasetype = 0)));
 
 -- Cross-check finalfn (if present) against its entry in pg_proc.
 -- FIXME: what about binary-compatible types?
@@ -431,9 +397,8 @@ SELECT p1.oid, p1.aggname, p2.oid, p2.proname
 FROM pg_aggregate AS p1, pg_proc AS p2
 WHERE p1.aggfinalfn = p2.oid AND
     (p2.proretset OR p1.aggfinaltype != p2.prorettype OR
-     p2.pronargs != 2 OR
-     p1.aggtranstype1 != p2.proargtypes[0] OR
-     p1.aggtranstype2 != p2.proargtypes[1]);
+     p2.pronargs != 1 OR
+     p1.aggtranstype != p2.proargtypes[0]);
 
 -- **************** pg_opclass ****************
 
index 361007ced9db65df2ca681967f560ebaa490a42d..e0859a67976bc96528fdfb6617f2b13c2c658d6b 100644 (file)
@@ -7,7 +7,7 @@
 --
 -- Copyright (c) 1994, Regents of the University of California
 --
--- $Id: complex.source,v 1.7 2000/03/28 02:49:19 tgl Exp $
+-- $Id: complex.source,v 1.8 2000/07/17 03:05:41 tgl Exp $
 --
 ---------------------------------------------------------------------------
 
@@ -111,10 +111,10 @@ SELECT  a + '(1.0,1.0)'::complex AS aa,
 -----------------------------
 
 CREATE AGGREGATE complex_sum (
-   sfunc1 = complex_add,
+   sfunc = complex_add,
    basetype = complex,
-   stype1 = complex,
-   initcond1 = '(0,0)'
+   stype = complex,
+   initcond = '(0,0)'
 );
 
 SELECT complex_sum(a) FROM test_complex;