1. Andrew Dunstan
  2. pgdevel

Commits

Tom Lane  committed 8d65da1

Support ordered-set (WITHIN GROUP) aggregates.

This patch introduces generic support for ordered-set and hypothetical-set
aggregate functions, as well as implementations of the instances defined in
SQL:2008 (percentile_cont(), percentile_disc(), rank(), dense_rank(),
percent_rank(), cume_dist()). We also added mode() though it is not in the
spec, as well as versions of percentile_cont() and percentile_disc() that
can compute multiple percentile values in one pass over the data.

Unlike the original submission, this patch puts full control of the sorting
process in the hands of the aggregate's support functions. To allow the
support functions to find out how they're supposed to sort, a new API
function AggGetAggref() is added to nodeAgg.c. This allows retrieval of
the aggregate call's Aggref node, which may have other uses beyond the
immediate need. There is also support for ordered-set aggregates to
install cleanup callback functions, so that they can be sure that
infrastructure such as tuplesort objects gets cleaned up.

In passing, make some fixes in the recently-added support for variadic
aggregates, and make some editorial adjustments in the recent FILTER
additions for aggregates. Also, simplify use of IsBinaryCoercible() by
allowing it to succeed whenever the target type is ANY or ANYELEMENT.
It was inconsistent that it dealt with other polymorphic target types
but not these.

Atri Sharma and Andrew Gierth; reviewed by Pavel Stehule and Vik Fearing,
and rather heavily editorialized upon by Tom Lane

  • Participants
  • Parent commits 37484ad
  • Branches master

Comments (0)

Files changed (64)

File contrib/pg_stat_statements/pg_stat_statements.c

View file
  • Ignore whitespace
 				Aggref	   *expr = (Aggref *) node;
 
 				APP_JUMB(expr->aggfnoid);
+				JumbleExpr(jstate, (Node *) expr->aggdirectargs);
 				JumbleExpr(jstate, (Node *) expr->args);
 				JumbleExpr(jstate, (Node *) expr->aggorder);
 				JumbleExpr(jstate, (Node *) expr->aggdistinct);

File doc/src/sgml/catalogs.sgml

View file
  • Ignore whitespace
       <entry><structname>pg_proc</structname> OID of the aggregate function</entry>
      </row>
      <row>
+      <entry><structfield>aggkind</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>Aggregate kind:
+       <literal>n</literal> for <quote>normal</> aggregates,
+       <literal>o</literal> for <quote>ordered-set</> aggregates, or
+       <literal>h</literal> for <quote>hypothetical-set</> aggregates
+      </entry>
+     </row>
+     <row>
+      <entry><structfield>aggnumdirectargs</structfield></entry>
+      <entry><type>int2</type></entry>
+      <entry></entry>
+      <entry>Number of direct (non-aggregated) arguments of an ordered-set or
+       hypothetical-set aggregate, counting a variadic array as one argument.
+       If equal to <structfield>pronargs</>, the aggregate must be variadic
+       and the variadic array describes the aggregated arguments as well as
+       the final direct arguments.
+       Always zero for normal aggregates.</entry>
+     </row>
+     <row>
       <entry><structfield>aggtransfn</structfield></entry>
       <entry><type>regproc</type></entry>
       <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>

File doc/src/sgml/func.sgml

View file
  • Ignore whitespace
 
   <para>
    <firstterm>Aggregate functions</firstterm> compute a single result
-   from a set of input values.  The built-in aggregate functions
+   from a set of input values.  The built-in normal aggregate functions
    are listed in
    <xref linkend="functions-aggregate-table"> and
    <xref linkend="functions-aggregate-statistics-table">.
+   The built-in ordered-set aggregate functions
+   are listed in <xref linkend="functions-orderedset-table"> and
+   <xref linkend="functions-hypothetical-table">.
    The special syntax considerations for aggregate
    functions are explained in <xref linkend="syntax-aggregates">.
    Consult <xref linkend="tutorial-agg"> for additional introductory
    </tgroup>
   </table>
 
+  <para>
+   <xref linkend="functions-orderedset-table"> shows some
+   aggregate functions that use the <firstterm>ordered-set aggregate</>
+   syntax.  These functions are sometimes referred to as <quote>inverse
+   distribution</> functions.
+  </para>
+
+  <indexterm>
+   <primary>ordered-set aggregate</primary>
+   <secondary>built-in</secondary>
+  </indexterm>
+  <indexterm>
+   <primary>inverse distribution</primary>
+  </indexterm>
+
+  <table id="functions-orderedset-table">
+   <title>Ordered-Set Aggregate Functions</title>
+
+   <tgroup cols="5">
+    <thead>
+     <row>
+      <entry>Function</entry>
+      <entry>Direct Argument Type(s)</entry>
+      <entry>Aggregated Argument Type(s)</entry>
+      <entry>Return Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+
+     <row>
+      <entry>
+       <indexterm>
+        <primary>mode</primary>
+        <secondary>statistical</secondary>
+       </indexterm>
+       <function>mode() WITHIN GROUP (ORDER BY <replaceable class="parameter">sort_expression</replaceable>)</function>
+      </entry>
+      <entry>
+      </entry>
+      <entry>
+       any sortable type
+      </entry>
+      <entry>
+       same as sort expression
+      </entry>
+      <entry>
+       returns the most frequent input value (arbitrarily choosing the first
+       one if there are multiple equally-frequent results)
+      </entry>
+     </row>
+
+     <row>
+      <entry>
+       <indexterm>
+        <primary>percentile</primary>
+        <secondary>continuous</secondary>
+       </indexterm>
+       <indexterm>
+        <primary>median</primary>
+       </indexterm>
+       <function>percentile_cont(<replaceable class="parameter">fraction</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sort_expression</replaceable>)</function>
+      </entry>
+      <entry>
+       <type>double precision</type>
+      </entry>
+      <entry>
+       <type>double precision</type> or <type>interval</type>
+      </entry>
+      <entry>
+       same as sort expression
+      </entry>
+      <entry>
+       continuous percentile: returns a value corresponding to the specified
+       fraction in the ordering, interpolating between adjacent input items if
+       needed
+      </entry>
+     </row>
+
+     <row>
+      <entry>
+       <function>percentile_cont(<replaceable class="parameter">fractions</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sort_expression</replaceable>)</function>
+      </entry>
+      <entry>
+       <type>double precision[]</type>
+      </entry>
+      <entry>
+       <type>double precision</type> or <type>interval</type>
+      </entry>
+      <entry>
+       array of sort expression's type
+      </entry>
+      <entry>
+       multiple continuous percentile: returns an array of results matching
+       the shape of the <literal>fractions</literal> parameter, with each
+       non-null element replaced by the value corresponding to that percentile
+      </entry>
+     </row>
+
+     <row>
+      <entry>
+       <indexterm>
+        <primary>percentile</primary>
+        <secondary>discrete</secondary>
+       </indexterm>
+       <function>percentile_disc(<replaceable class="parameter">fraction</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sort_expression</replaceable>)</function>
+      </entry>
+      <entry>
+       <type>double precision</type>
+      </entry>
+      <entry>
+       any sortable type
+      </entry>
+      <entry>
+       same as sort expression
+      </entry>
+      <entry>
+       discrete percentile: returns the first input value whose position in
+       the ordering equals or exceeds the specified fraction
+      </entry>
+     </row>
+
+     <row>
+      <entry>
+       <function>percentile_disc(<replaceable class="parameter">fractions</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sort_expression</replaceable>)</function>
+      </entry>
+      <entry>
+       <type>double precision[]</type>
+      </entry>
+      <entry>
+       any sortable type
+      </entry>
+      <entry>
+       array of sort expression's type
+      </entry>
+      <entry>
+       multiple discrete percentile: returns an array of results matching the
+       shape of the <literal>fractions</literal> parameter, with each non-null
+       element replaced by the input value corresponding to that percentile
+      </entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   All the aggregates listed in <xref linkend="functions-orderedset-table">
+   ignore null values in their sorted input.  For those that take
+   a <replaceable>fraction</replaceable> parameter, the fraction value must be
+   between 0 and 1; an error is thrown if not.  However, a null fraction value
+   simply produces a null result.
+  </para>
+
+  <para>
+   Each of the aggregates listed in
+   <xref linkend="functions-hypothetical-table"> is associated with a
+   window function of the same name defined in
+   <xref linkend="functions-window">.  In each case, the aggregate result
+   is the value that the associated window function would have
+   returned for the <quote>hypothetical</> row constructed from
+   <replaceable>args</replaceable>, if such a row had been added to the sorted
+   group of rows computed from the <replaceable>sorted_args</replaceable>.
+  </para>
+
+  <table id="functions-hypothetical-table">
+   <title>Hypothetical-Set Aggregate Functions</title>
+
+   <tgroup cols="5">
+    <thead>
+     <row>
+      <entry>Function</entry>
+      <entry>Direct Argument Type(s)</entry>
+      <entry>Aggregated Argument Type(s)</entry>
+      <entry>Return Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+
+     <row>
+      <entry>
+       <indexterm>
+        <primary>rank</primary>
+        <secondary>hypothetical</secondary>
+       </indexterm>
+       <function>rank(<replaceable class="parameter">args</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sorted_args</replaceable>)</function>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <type>bigint</type>
+      </entry>
+      <entry>
+       rank of the hypothetical row, with gaps for duplicate rows
+      </entry>
+     </row>
+
+     <row>
+      <entry>
+       <indexterm>
+        <primary>dense_rank</primary>
+        <secondary>hypothetical</secondary>
+       </indexterm>
+       <function>dense_rank(<replaceable class="parameter">args</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sorted_args</replaceable>)</function>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <type>bigint</type>
+      </entry>
+      <entry>
+       rank of the hypothetical row, without gaps
+      </entry>
+     </row>
+
+     <row>
+      <entry>
+       <indexterm>
+        <primary>percent_rank</primary>
+        <secondary>hypothetical</secondary>
+       </indexterm>
+       <function>percent_rank(<replaceable class="parameter">args</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sorted_args</replaceable>)</function>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <type>double precision</type>
+      </entry>
+      <entry>
+       relative rank of the hypothetical row, ranging from 0 to 1
+      </entry>
+     </row>
+
+     <row>
+      <entry>
+       <indexterm>
+        <primary>cume_dist</primary>
+        <secondary>hypothetical</secondary>
+       </indexterm>
+       <function>cume_dist(<replaceable class="parameter">args</replaceable>) WITHIN GROUP (ORDER BY <replaceable class="parameter">sorted_args</replaceable>)</function>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <literal>VARIADIC</> <type>"any"</type>
+      </entry>
+      <entry>
+       <type>double precision</type>
+      </entry>
+      <entry>
+       relative rank of the hypothetical row, ranging from
+       1/<replaceable>N</> to 1
+      </entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   For each of these hypothetical-set aggregates, the list of direct arguments
+   given in <replaceable>args</replaceable> must match the number and types of
+   the aggregated arguments given in <replaceable>sorted_args</replaceable>.
+   Unlike most built-in aggregates, these aggregates are not strict, that is
+   they do not drop input rows containing nulls.  Null values sort according
+   to the rule specified in the <literal>ORDER BY</> clause.
+  </para>
+
  </sect1>
 
  <sect1 id="functions-window">
   </para>
 
   <para>
-   In addition to these functions, any built-in or user-defined aggregate
-   function can be used as a window function (see
-   <xref linkend="functions-aggregate"> for a list of the built-in aggregates).
+   In addition to these functions, any built-in or user-defined normal
+   aggregate function (but not ordered-set or hypothetical-set aggregates)
+   can be used as a window function; see
+   <xref linkend="functions-aggregate"> for a list of the built-in aggregates.
    Aggregate functions act as window functions only when an <literal>OVER</>
    clause follows the call; otherwise they act as regular aggregates.
   </para>

File doc/src/sgml/ref/alter_aggregate.sgml

View file
  • Ignore whitespace
 
  <refsynopsisdiv>
 <synopsis>
-ALTER AGGREGATE <replaceable>name</replaceable> ( [ <replaceable>argmode</replaceable> ] [ <replaceable>arg_name</replaceable> ] <replaceable>arg_data_type</replaceable> [ , ... ] )
-  RENAME TO <replaceable>new_name</replaceable>
-ALTER AGGREGATE <replaceable>name</replaceable> ( [ <replaceable>argmode</replaceable> ] [ <replaceable>arg_name</replaceable> ] <replaceable>arg_data_type</replaceable> [ , ... ] )
-  OWNER TO <replaceable>new_owner</replaceable>
-ALTER AGGREGATE <replaceable>name</replaceable> ( [ <replaceable>argmode</replaceable> ] [ <replaceable>arg_name</replaceable> ] <replaceable>arg_data_type</replaceable> [ , ... ] )
-  SET SCHEMA <replaceable>new_schema</replaceable>
+ALTER AGGREGATE <replaceable>name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) RENAME TO <replaceable>new_name</replaceable>
+ALTER AGGREGATE <replaceable>name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) OWNER TO <replaceable>new_owner</replaceable>
+ALTER AGGREGATE <replaceable>name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) SET SCHEMA <replaceable>new_schema</replaceable>
+
+<phrase>where <replaceable>aggregate_signature</replaceable> is:</phrase>
+
+* |
+[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
+[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
 </synopsis>
  </refsynopsisdiv>
 
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">arg_name</replaceable></term>
+    <term><replaceable class="parameter">argname</replaceable></term>
 
     <listitem>
      <para>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">arg_data_type</replaceable></term>
+    <term><replaceable class="parameter">argtype</replaceable></term>
     <listitem>
      <para>
       An input data type on which the aggregate function operates.
       To reference a zero-argument aggregate function, write <literal>*</>
       in place of the list of argument specifications.
+      To reference an ordered-set aggregate function, write
+      <literal>ORDER BY</> between the direct and aggregated argument
+      specifications.
      </para>
     </listitem>
    </varlistentry>
  </refsect1>
 
  <refsect1>
+  <title>Notes</title>
+
+   <para>
+    The recommended syntax for referencing an ordered-set aggregate
+    is to write <literal>ORDER BY</> between the direct and aggregated
+    argument specifications, in the same style as in
+    <xref linkend="sql-createaggregate">.  However, it will also work to
+    omit <literal>ORDER BY</> and just run the direct and aggregated
+    argument specifications into a single list.  In this abbreviated form,
+    if <literal>VARIADIC "any"</> was used in both the direct and
+    aggregated argument lists, write <literal>VARIADIC "any"</> only once.
+   </para>
+ </refsect1>
+
+ <refsect1>
   <title>Examples</title>
 
   <para>
   </para>
 
   <para>
-   To move the aggregate function <literal>myavg</literal> for type
-   <type>integer</type> into schema <literal>myschema</literal>:
+   To move the ordered-set aggregate <literal>mypercentile</literal> with
+   direct argument of type <type>float8</type> and aggregated argument
+   of type <type>integer</type> into schema <literal>myschema</literal>:
 <programlisting>
-ALTER AGGREGATE myavg(integer) SET SCHEMA myschema;
-</programlisting></para>
+ALTER AGGREGATE mypercentile(float8 ORDER BY integer) SET SCHEMA myschema;
+</programlisting>
+   This will work too:
+<programlisting>
+ALTER AGGREGATE mypercentile(float8, integer) SET SCHEMA myschema;
+</programlisting>
+  </para>
  </refsect1>
 
  <refsect1>

File doc/src/sgml/ref/alter_extension.sgml

View file
  • Ignore whitespace
 
 <phrase>where <replaceable class="PARAMETER">member_object</replaceable> is:</phrase>
 
-  AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">agg_type</replaceable> [, ...] ) |
+  AGGREGATE <replaceable class="PARAMETER">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
   CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>) |
   COLLATION <replaceable class="PARAMETER">object_name</replaceable> |
   CONVERSION <replaceable class="PARAMETER">object_name</replaceable> |
   TEXT SEARCH TEMPLATE <replaceable class="PARAMETER">object_name</replaceable> |
   TYPE <replaceable class="PARAMETER">object_name</replaceable> |
   VIEW <replaceable class="PARAMETER">object_name</replaceable>
+
+<phrase>and <replaceable>aggregate_signature</replaceable> is:</phrase>
+
+* |
+[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
+[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
 </synopsis>
  </refsynopsisdiv>
 
 
     <varlistentry>
      <term><replaceable class="parameter">object_name</replaceable></term>
-     <term><replaceable class="parameter">agg_name</replaceable></term>
+     <term><replaceable class="parameter">aggregate_name</replaceable></term>
      <term><replaceable class="parameter">function_name</replaceable></term>
      <term><replaceable class="parameter">operator_name</replaceable></term>
      <listitem>
     </varlistentry>
 
     <varlistentry>
-     <term><replaceable class="parameter">agg_type</replaceable></term>
-     <listitem>
-      <para>
-       An input data type on which the aggregate function operates.
-       To reference a zero-argument aggregate function, write <literal>*</>
-       in place of the list of argument specifications.
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
      <term><replaceable>source_type</replaceable></term>
      <listitem>
       <para>
 
      <listitem>
       <para>
-       The mode of a function argument: <literal>IN</>, <literal>OUT</>,
+       The mode of a function or aggregate
+       argument: <literal>IN</>, <literal>OUT</>,
        <literal>INOUT</>, or <literal>VARIADIC</>.
        If omitted, the default is <literal>IN</>.
        Note that <command>ALTER EXTENSION</command> does not actually pay
 
      <listitem>
       <para>
-       The name of a function argument.
+       The name of a function or aggregate argument.
        Note that <command>ALTER EXTENSION</command> does not actually pay
        any attention to argument names, since only the argument data
        types are needed to determine the function's identity.
 
      <listitem>
       <para>
-       The data type(s) of the function's arguments (optionally
-       schema-qualified), if any.
+       The data type of a function or aggregate argument.
       </para>
      </listitem>
     </varlistentry>

File doc/src/sgml/ref/comment.sgml

View file
  • Ignore whitespace
 <synopsis>
 COMMENT ON
 {
-  AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">agg_type</replaceable> [, ...] ) |
+  AGGREGATE <replaceable class="PARAMETER">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
   CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>) |
   COLLATION <replaceable class="PARAMETER">object_name</replaceable> |
   COLUMN <replaceable class="PARAMETER">relation_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
   TYPE <replaceable class="PARAMETER">object_name</replaceable> |
   VIEW <replaceable class="PARAMETER">object_name</replaceable>
 } IS '<replaceable class="PARAMETER">text</replaceable>'
+
+<phrase>where <replaceable>aggregate_signature</replaceable> is:</phrase>
+
+* |
+[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
+[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
 </synopsis>
  </refsynopsisdiv>
 
    <varlistentry>
     <term><replaceable class="parameter">object_name</replaceable></term>
     <term><replaceable class="parameter">relation_name</replaceable>.<replaceable>column_name</replaceable></term>
-    <term><replaceable class="parameter">agg_name</replaceable></term>
+    <term><replaceable class="parameter">aggregate_name</replaceable></term>
     <term><replaceable class="parameter">constraint_name</replaceable></term>
     <term><replaceable class="parameter">function_name</replaceable></term>
     <term><replaceable class="parameter">operator_name</replaceable></term>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">agg_type</replaceable></term>
-    <listitem>
-     <para>
-      An input data type on which the aggregate function operates.
-      To reference a zero-argument aggregate function, write <literal>*</>
-      in place of the list of argument specifications.
-     </para>
-    </listitem>
-   </varlistentry>
-
-   <varlistentry>
      <term><replaceable>source_type</replaceable></term>
      <listitem>
       <para>
     <term><replaceable class="parameter">argmode</replaceable></term>
     <listitem>
      <para>
-      The mode of a function argument: <literal>IN</>, <literal>OUT</>,
+      The mode of a function or aggregate
+      argument: <literal>IN</>, <literal>OUT</>,
       <literal>INOUT</>, or <literal>VARIADIC</>.
       If omitted, the default is <literal>IN</>.
       Note that <command>COMMENT</command> does not actually pay
     <term><replaceable class="parameter">argname</replaceable></term>
     <listitem>
      <para>
-      The name of a function argument.
+      The name of a function or aggregate argument.
       Note that <command>COMMENT</command> does not actually pay
       any attention to argument names, since only the argument data
       types are needed to determine the function's identity.
     <term><replaceable class="parameter">argtype</replaceable></term>
     <listitem>
      <para>
-      The data type(s) of the function's arguments (optionally
-      schema-qualified), if any.
+      The data type of a function or aggregate argument.
      </para>
     </listitem>
    </varlistentry>

File doc/src/sgml/ref/create_aggregate.sgml

View file
  • Ignore whitespace
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
     [ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
 )
 
+CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ]
+                        ORDER BY [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ) (
+    SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
+    STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
+    [ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
+    [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
+    [ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
+    [ , HYPOTHETICAL ]
+)
+
 <phrase>or the old syntax</phrase>
 
 CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
    name and input data type(s) of an aggregate must also be distinct from
    the name and input data type(s) of every ordinary function in the same
    schema.
+   This behavior is identical to overloading of ordinary function names
+   (see <xref linkend="sql-createfunction">).
   </para>
 
   <para>
   <para>
    If the state transition function is not strict, then it will be called
    unconditionally at each input row, and must deal with null inputs
-   and null transition values for itself.  This allows the aggregate
+   and null state values for itself.  This allows the aggregate
    author to have full control over the aggregate's handling of null values.
   </para>
 
   </para>
 
   <para>
+   The syntax with <literal>ORDER BY</literal> in the parameter list creates
+   a special type of aggregate called an <firstterm>ordered-set
+   aggregate</firstterm>; or if <literal>HYPOTHETICAL</> is specified, then
+   a <firstterm>hypothetical-set aggregate</firstterm> is created.  These
+   aggregates operate over groups of sorted values in order-dependent ways,
+   so that specification of an input sort order is an essential part of a
+   call.  Also, they can have <firstterm>direct</> arguments, which are
+   arguments that are evaluated only once per aggregation rather than once
+   per input row.  Hypothetical-set aggregates are a subclass of ordered-set
+   aggregates in which some of the direct arguments are required to match,
+   in number and datatypes, the aggregated argument columns.  This allows
+   the values of those direct arguments to be added to the collection of
+   aggregate-input rows as an additional <quote>hypothetical</> row.
+  </para>
+
+  <para>
    Aggregates that behave like <function>MIN</> or <function>MAX</> can
    sometimes be optimized by looking into an index instead of scanning every
    input row.  If this aggregate can be so optimized, indicate it by
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">arg_name</replaceable></term>
+    <term><replaceable class="parameter">argname</replaceable></term>
 
     <listitem>
      <para>
       only one input parameter.  To define a zero-argument aggregate function
       with this syntax, specify the <literal>basetype</> as
       <literal>"ANY"</> (not <literal>*</>).
+      Ordered-set aggregates cannot be defined with the old syntax.
      </para>
     </listitem>
    </varlistentry>
     <listitem>
      <para>
       The name of the state transition function to be called for each
-      input row.  For an <replaceable class="PARAMETER">N</>-argument
+      input row.  For a normal <replaceable class="PARAMETER">N</>-argument
       aggregate function, the <replaceable class="PARAMETER">sfunc</>
       must take <replaceable class="PARAMETER">N</>+1 arguments,
       the first being of type <replaceable
       takes the current state value and the current input data value(s),
       and returns the next state value.
      </para>
+
+     <para>
+      For ordered-set (including hypothetical-set) aggregates, the state
+      transition function receives only the current state value and the
+      aggregated arguments, not the direct arguments.  Otherwise it is the
+      same.
+     </para>
     </listitem>
    </varlistentry>
 
     <listitem>
      <para>
       The name of the final function called to compute the aggregate's
-      result after all input rows have been traversed.  The function
+      result after all input rows have been traversed.
+      For a normal aggregate, this function
       must take a single argument of type <replaceable
       class="PARAMETER">state_data_type</replaceable>.  The return
       data type of the aggregate is defined as the return type of this
       aggregate's result, and the return type is <replaceable
       class="PARAMETER">state_data_type</replaceable>.
      </para>
+
+     <para>
+      For ordered-set (including hypothetical-set) aggregates, the
+      final function receives not only the final state value,
+      but also the values of all the direct arguments, followed by
+      null values corresponding to each aggregated argument.
+      (The reason for including the aggregated arguments in the function
+      signature is that this may be necessary to allow correct resolution
+      of the aggregate result type, when a polymorphic aggregate is
+      being defined.)
+     </para>
     </listitem>
    </varlistentry>
 
       <function>MAX</>-like aggregate.
       This is just an operator name (possibly schema-qualified).
       The operator is assumed to have the same input data types as
-      the aggregate (which must be a single-argument aggregate).
+      the aggregate (which must be a single-argument normal aggregate).
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>HYPOTHETICAL</literal></term>
+    <listitem>
+     <para>
+      For ordered-set aggregates only, this flag specifies that the aggregate
+      arguments are to be processed according to the requirements for
+      hypothetical-set aggregates: that is, the last few direct arguments must
+      match the data types of the aggregated (<literal>WITHIN GROUP</>)
+      arguments.  The <literal>HYPOTHETICAL</literal> flag has no effect on
+      run-time behavior, only on parse-time resolution of the data types and
+      collations of the aggregate's arguments.
      </para>
     </listitem>
    </varlistentry>
  </refsect1>
 
  <refsect1>
+  <title>Notes</title>
+
+   <para>
+    The syntax for ordered-set aggregates allows <literal>VARIADIC</>
+    to be specified for both the last direct parameter and the last
+    aggregated (<literal>WITHIN GROUP</>) parameter.  However, the
+    current implementation restricts use of <literal>VARIADIC</>
+    in two ways.  First, ordered-set aggregates can only use
+    <literal>VARIADIC "any"</>, not other variadic array types.
+    Second, if the last direct parameter is <literal>VARIADIC "any"</>,
+    then there can be only one aggregated parameter and it must also
+    be <literal>VARIADIC "any"</>.  (In the representation used in the
+    system catalogs, these two parameters are merged into a single
+    <literal>VARIADIC "any"</> item, since <structname>pg_proc</> cannot
+    represent functions with more than one <literal>VARIADIC</> parameter.)
+    If the aggregate is a hypothetical-set aggregate, the direct arguments
+    that match the <literal>VARIADIC "any"</> parameter are the hypothetical
+    ones; any preceding parameters represent additional direct arguments
+    that are not constrained to match the aggregated arguments.
+   </para>
+ </refsect1>
+
+ <refsect1>
   <title>Examples</title>
 
   <para>

File doc/src/sgml/ref/drop_aggregate.sgml

View file
  • Ignore whitespace
 
  <refsynopsisdiv>
 <synopsis>
-DROP AGGREGATE [ IF EXISTS ]
-  <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] )
-  [ CASCADE | RESTRICT ]
+DROP AGGREGATE [ IF EXISTS ] <replaceable>name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) [ CASCADE | RESTRICT ]
+
+<phrase>where <replaceable>aggregate_signature</replaceable> is:</phrase>
+
+* |
+[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
+[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
 </synopsis>
  </refsynopsisdiv>
 
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">arg_name</replaceable></term>
+    <term><replaceable class="parameter">argname</replaceable></term>
 
     <listitem>
      <para>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">arg_data_type</replaceable></term>
+    <term><replaceable class="parameter">argtype</replaceable></term>
     <listitem>
      <para>
       An input data type on which the aggregate function operates.
       To reference a zero-argument aggregate function, write <literal>*</>
       in place of the list of argument specifications.
+      To reference an ordered-set aggregate function, write
+      <literal>ORDER BY</> between the direct and aggregated argument
+      specifications.
      </para>
     </listitem>
    </varlistentry>
  </refsect1>
 
  <refsect1>
+  <title>Notes</title>
+
+   <para>
+    Alternative syntaxes for referencing ordered-set aggregates
+    are described under <xref linkend="sql-alteraggregate">.
+   </para>
+ </refsect1>
+
+ <refsect1>
   <title>Examples</title>
 
   <para>
    <type>integer</type>:
 <programlisting>
 DROP AGGREGATE myavg(integer);
-</programlisting></para>
+</programlisting>
+  </para>
+
+  <para>
+   To remove the hypothetical-set aggregate function <literal>myrank</>,
+   which takes an arbitrary list of ordering columns and a matching list
+   of direct arguments:
+<programlisting>
+DROP AGGREGATE myrank(VARIADIC "any" ORDER BY VARIADIC "any");
+</programlisting>
+  </para>
  </refsect1>
 
  <refsect1>

File doc/src/sgml/ref/security_label.sgml

View file
  • Ignore whitespace
 {
   TABLE <replaceable class="PARAMETER">object_name</replaceable> |
   COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
-  AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">agg_type</replaceable> [, ...] ) |
+  AGGREGATE <replaceable class="PARAMETER">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
   DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
   DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
   EVENT TRIGGER <replaceable class="PARAMETER">object_name</replaceable> |
   TYPE <replaceable class="PARAMETER">object_name</replaceable> |
   VIEW <replaceable class="PARAMETER">object_name</replaceable>
 } IS '<replaceable class="PARAMETER">label</replaceable>'
+
+<phrase>where <replaceable>aggregate_signature</replaceable> is:</phrase>
+
+* |
+[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
+[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
 </synopsis>
  </refsynopsisdiv>
 
    <varlistentry>
     <term><replaceable class="parameter">object_name</replaceable></term>
     <term><replaceable class="parameter">table_name.column_name</replaceable></term>
-    <term><replaceable class="parameter">agg_name</replaceable></term>
+    <term><replaceable class="parameter">aggregate_name</replaceable></term>
     <term><replaceable class="parameter">function_name</replaceable></term>
     <listitem>
      <para>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">agg_type</replaceable></term>
-    <listitem>
-     <para>
-      An input data type on which the aggregate function operates.
-      To reference a zero-argument aggregate function, write <literal>*</>
-      in place of the list of argument specifications.
-     </para>
-    </listitem>
-   </varlistentry>
-
-   <varlistentry>
     <term><replaceable class="parameter">argmode</replaceable></term>
 
     <listitem>
      <para>
-      The mode of a function argument: <literal>IN</>, <literal>OUT</>,
+      The mode of a function or aggregate
+      argument: <literal>IN</>, <literal>OUT</>,
       <literal>INOUT</>, or <literal>VARIADIC</>.
       If omitted, the default is <literal>IN</>.
       Note that <command>SECURITY LABEL</command> does not actually
 
     <listitem>
      <para>
-      The name of a function argument.
+      The name of a function or aggregate argument.
       Note that <command>SECURITY LABEL</command> does not actually
       pay any attention to argument names, since only the argument data
       types are needed to determine the function's identity.
 
     <listitem>
      <para>
-      The data type(s) of the function's arguments (optionally
-      schema-qualified), if any.
+      The data type of a function or aggregate argument.
      </para>
     </listitem>
    </varlistentry>

File doc/src/sgml/syntax.sgml

View file
  • Ignore whitespace
    </indexterm>
 
    <indexterm zone="syntax-aggregates">
-    <primary>filter</primary>
+    <primary>ordered-set aggregate</primary>
+   </indexterm>
+
+   <indexterm zone="syntax-aggregates">
+    <primary>WITHIN GROUP</primary>
+   </indexterm>
+
+   <indexterm zone="syntax-aggregates">
+    <primary>FILTER</primary>
    </indexterm>
 
    <para>
 <replaceable>aggregate_name</replaceable> (ALL <replaceable>expression</replaceable> [ , ... ] [ <replaceable>order_by_clause</replaceable> ] ) [ FILTER ( WHERE <replaceable>filter_clause</replaceable> ) ]
 <replaceable>aggregate_name</replaceable> (DISTINCT <replaceable>expression</replaceable> [ , ... ] [ <replaceable>order_by_clause</replaceable> ] ) [ FILTER ( WHERE <replaceable>filter_clause</replaceable> ) ]
 <replaceable>aggregate_name</replaceable> ( * ) [ FILTER ( WHERE <replaceable>filter_clause</replaceable> ) ]
+<replaceable>aggregate_name</replaceable> ( [ <replaceable>expression</replaceable> [ , ... ] ] ) WITHIN GROUP ( <replaceable>order_by_clause</replaceable> ) [ FILTER ( WHERE <replaceable>filter_clause</replaceable> ) ]
 </synopsis>
 
     where <replaceable>aggregate_name</replaceable> is a previously
     The third form invokes the aggregate once for each distinct value
     of the expression (or distinct set of values, for multiple expressions)
     found in the input rows.
-    The last form invokes the aggregate once for each input row; since no
+    The fourth form invokes the aggregate once for each input row; since no
     particular input value is specified, it is generally only useful
     for the <function>count(*)</function> aggregate function.
+    The last form is used with <firstterm>ordered-set</> aggregate
+    functions, which are described below.
    </para>
 
    <para>
    </para>
 
    <para>
-    If <literal>FILTER</literal> is specified, then only the input
-    rows for which the <replaceable>filter_clause</replaceable>
-    evaluates to true are fed to the aggregate function; other rows
-    are discarded.  For example:
-<programlisting>
-SELECT
-    count(*) AS unfiltered,
-    count(*) FILTER (WHERE i < 5) AS filtered
-FROM generate_series(1,10) AS s(i);
- unfiltered | filtered
-------------+----------
-         10 |        4
-(1 row)
-</programlisting>
-   </para>
-
-   <para>
     Ordinarily, the input rows are fed to the aggregate function in an
     unspecified order.  In many cases this does not matter; for example,
     <function>min</> produces the same result no matter what order it
    </note>
 
    <para>
+    Placing <literal>ORDER BY</> within the aggregate's regular argument
+    list, as described so far, is used when ordering the input rows for
+    a <quote>normal</> aggregate for which ordering is optional.  There is a
+    subclass of aggregate functions called <firstterm>ordered-set
+    aggregates</> for which an <replaceable>order_by_clause</replaceable>
+    is <emphasis>required</>, usually because the aggregate's computation is
+    only sensible in terms of a specific ordering of its input rows.
+    Typical examples of ordered-set aggregates include rank and percentile
+    calculations.  For an ordered-set aggregate,
+    the <replaceable>order_by_clause</replaceable> is written
+    inside <literal>WITHIN GROUP (...)</>, as shown in the final syntax
+    alternative above.  The expressions in
+    the <replaceable>order_by_clause</replaceable> are evaluated once per
+    input row just like normal aggregate arguments, sorted as per
+    the <replaceable>order_by_clause</replaceable>'s requirements, and fed
+    to the aggregate function as input arguments.  (This is unlike the case
+    for a non-<literal>WITHIN GROUP</> <replaceable>order_by_clause</>,
+    which is not treated as argument(s) to the aggregate function.)  The
+    argument expressions preceding <literal>WITHIN GROUP</>, if any, are
+    called <firstterm>direct arguments</> to distinguish them from
+    the <firstterm>aggregated arguments</> listed in
+    the <replaceable>order_by_clause</replaceable>.  Unlike normal aggregate
+    arguments, direct arguments are evaluated only once per aggregate call,
+    not once per input row.  This means that they can contain variables only
+    if those variables are grouped by <literal>GROUP BY</>; this restriction
+    is the same as if the direct arguments were not inside an aggregate
+    expression at all.  Direct arguments are typically used for things like
+    percentile fractions, which only make sense as a single value per
+    aggregation calculation.  The direct argument list can be empty; in this
+    case, write just <literal>()</> not <literal>(*)</>.
+    (<productname>PostgreSQL</> will actually accept either spelling, but
+    only the first way conforms to the SQL standard.)
+    An example of an ordered-set aggregate call is:
+
+<programlisting>
+SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
+ percentile_disc
+-----------------
+           50489
+</programlisting>
+
+   which obtains the 50th percentile, or median, value of
+   the <structfield>income</> column from table <structname>households</>.
+   Here, <literal>0.5</> is a direct argument; it would make no sense
+   for the percentile fraction to be a value varying across rows.
+   </para>
+
+   <para>
+    If <literal>FILTER</literal> is specified, then only the input
+    rows for which the <replaceable>filter_clause</replaceable>
+    evaluates to true are fed to the aggregate function; other rows
+    are discarded.  For example:
+<programlisting>
+SELECT
+    count(*) AS unfiltered,
+    count(*) FILTER (WHERE i < 5) AS filtered
+FROM generate_series(1,10) AS s(i);
+ unfiltered | filtered
+------------+----------
+         10 |        4
+(1 row)
+</programlisting>
+   </para>
+
+   <para>
     The predefined aggregate functions are described in <xref
     linkend="functions-aggregate">.  Other aggregate functions can be added
     by the user.
     <xref linkend="sql-syntax-scalar-subqueries"> and
     <xref linkend="functions-subquery">), the aggregate is normally
     evaluated over the rows of the subquery.  But an exception occurs
-    if the aggregate's arguments contain only outer-level variables:
+    if the aggregate's arguments (and <replaceable>filter_clause</replaceable>
+    if any) contain only outer-level variables:
     the aggregate then belongs to the nearest such outer level, and is
     evaluated over the rows of that query.  The aggregate expression
     as a whole is then an outer reference for the subquery it appears in,
     If <literal>FILTER</literal> is specified, then only the input
     rows for which the <replaceable>filter_clause</replaceable>
     evaluates to true are fed to the window function; other rows
-    are discarded.  Only aggregate window functions accept
+    are discarded.  Only window functions that are aggregates accept
     a <literal>FILTER</literal> clause.
    </para>
 
    <para>
     The built-in window functions are described in <xref
     linkend="functions-window-table">.  Other window functions can be added by
-    the user.  Also, any built-in or user-defined aggregate function can be
-    used as a window function.
+    the user.  Also, any built-in or user-defined normal aggregate function
+    can be used as a window function.  Ordered-set aggregates presently
+    cannot be used as window functions, however.
    </para>
 
    <para>
    <para>
     More information about window functions can be found in
     <xref linkend="tutorial-window">,
-    <xref linkend="functions-window">,
+    <xref linkend="functions-window">, and
     <xref linkend="queries-window">.
    </para>
   </sect2>

File doc/src/sgml/xaggr.sgml

View file
  • Ignore whitespace
   </indexterm>
 
   <para>
-   Aggregate functions  in <productname>PostgreSQL</productname>
-   are expressed in terms of <firstterm>state values</firstterm>
+   Aggregate functions in <productname>PostgreSQL</productname>
+   are defined in terms of <firstterm>state values</firstterm>
    and <firstterm>state transition functions</firstterm>.
    That is, an aggregate operates using a state value that is updated
    as each successive input row is processed.
    To define a new aggregate
    function, one selects a data type for the state value,
    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.  A <firstterm>final function</firstterm>
+   function.  The state transition function takes the previous state
+   value and the aggregate's input value(s) for the current row, and
+   returns a new state value.
+   A <firstterm>final function</firstterm>
    can also be specified, in case the desired result of the aggregate
    is different from the data that needs to be kept in the running
-   state value.
+   state value.  The final function takes the last state value
+   and returns whatever is wanted as the aggregate result.
+   In principle, the transition and final functions are just ordinary
+   functions that could also be used outside the context of the
+   aggregate.  (In practice, it's often helpful for performance reasons
+   to create specialized transition functions that can only work when
+   called as part of an aggregate.)
   </para>
 
   <para>
    we only need the addition function for that data type.
    The aggregate definition would be:
 
-<screen>
+<programlisting>
 CREATE AGGREGATE sum (complex)
 (
     sfunc = complex_add,
     stype = complex,
     initcond = '(0,0)'
 );
+</programlisting>
+
+   which we might use like this:
 
+<programlisting>
 SELECT sum(a) FROM test_complex;
 
    sum
 -----------
  (34,53.9)
-</screen>
+</programlisting>
 
    (Notice that we are relying on function overloading: there is more than
     one aggregate named <function>sum</>, but
   </para>
 
   <para>
-   The above definition of <function>sum</function> will return zero (the initial
-   state condition) if there are no nonnull input values.
+   The above definition of <function>sum</function> will return zero
+   (the initial state value) if there are no nonnull input values.
    Perhaps we want to return null in that case instead &mdash; the SQL standard
    expects <function>sum</function> to behave that way.  We can do this simply by
    omitting the <literal>initcond</literal> phrase, so that the initial state
-   condition is null.  Ordinarily this would mean that the <literal>sfunc</literal>
-   would need to check for a null state-condition input.  But for
+   value is null.  Ordinarily this would mean that the <literal>sfunc</literal>
+   would need to check for a null state-value input.  But for
    <function>sum</function> and some other simple aggregates like
    <function>max</> and <function>min</>,
    it is sufficient to insert the first nonnull input value into
    the state variable and then start applying the transition function
    at the second nonnull input value.  <productname>PostgreSQL</productname>
-   will do that automatically if the initial condition is null and
+   will do that automatically if the initial state value is null and
    the transition function is marked <quote>strict</> (i.e., not to be called
    for null inputs).
   </para>
     initcond = '{0,0,0}'
 );
 </programlisting>
+  </para>
 
-   (<function>float8_accum</> requires a three-element array, not just
+  <note>
+   <para>
+   <function>float8_accum</> requires a three-element array, not just
    two elements, because it accumulates the sum of squares as well as
    the sum and count of the inputs.  This is so that it can be used for
-   some other aggregates besides <function>avg</>.)
-  </para>
+   some other aggregates besides <function>avg</>.
+   </para>
+  </note>
 
   <para>
    Aggregate functions can use polymorphic
 );
 </programlisting>
 
-   Here, the actual state type for any aggregate call is the array type
+   Here, the actual state type for any given aggregate call is the array type
    having the actual input type as elements.  The behavior of the aggregate
    is to concatenate all the inputs into an array of that type.
    (Note: the built-in aggregate <function>array_agg</> provides similar
   </note>
 
   <para>
+   Aggregate function calls in SQL allow <literal>DISTINCT</>
+   and <literal>ORDER BY</> options that control which rows are fed
+   to the aggregate's transition function and in what order.  These
+   options are implemented behind the scenes and are not the concern
+   of the aggregate's support functions.
+  </para>
+
+  <para>
+   The aggregates we have been describing so far are <quote>normal</>
+   aggregates.  <productname>PostgreSQL</> also
+   supports <firstterm>ordered-set aggregates</>, which differ from
+   normal aggregates in two key ways.  First, in addition to ordinary
+   aggregated arguments that are evaluated once per input row, an
+   ordered-set aggregate can have <quote>direct</> arguments that are
+   evaluated only once per aggregation operation.  Second, the syntax
+   for the ordinary aggregated arguments specifies a sort ordering
+   for them explicitly.  An ordered-set aggregate is usually
+   used to implement a computation that depends on a specific row
+   ordering, for instance rank or percentile, so that the sort ordering
+   is a required aspect of any call.  For example, the built-in
+   definition of <function>percentile_disc</> is equivalent to:
+
+<programlisting>
+CREATE AGGREGATE percentile_disc (float8 ORDER BY anyelement)
+(
+    sfunc = ordered_set_transition,
+    stype = internal,
+    finalfunc = percentile_disc_final
+);
+</programlisting>
+
+   which could be used to obtain a median household income like this:
+
+<programlisting>
+SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
+ percentile_disc
+-----------------
+           50489
+</programlisting>
+
+   Here, <literal>0.5</> is a direct argument; it would make no sense
+   for the percentile fraction to be a value varying across rows.
+  </para>
+
+  <para>
+   Unlike the case for normal aggregates, the sorting of input rows for
+   an ordered-set aggregate is <emphasis>not</> done behind the scenes,
+   but is the responsibility of the aggregate's support functions.
+   The typical implementation approach is to keep a reference to
+   a <quote>tuplesort</> object in the aggregate's state value, feed the
+   incoming rows into that object, and then complete the sorting and
+   read out the data in the final function.  This design allows the
+   final function to perform special operations such as injecting
+   additional <quote>hypothetical</> rows into the data to be sorted.
+   While normal aggregates can often be implemented with support
+   functions written in <application>PL/pgSQL</application> or another
+   PL language, ordered-set aggregates generally have to be written in
+   C, since their state values aren't definable as any SQL datatype.
+   (In the above example, notice that the state value is declared as
+   type <type>internal</> &mdash; this is typical.)
+  </para>
+
+  <para>
+   The state transition function for an ordered-set aggregate receives
+   the current state value plus the aggregated input values for
+   each row, and returns the updated state value.  This is the
+   same definition as for normal aggregates, but note that the direct
+   arguments (if any) are not provided.  The final function receives
+   the last state value, the values of the direct arguments if any,
+   and null values corresponding to the aggregated input(s).  While the
+   null values seem useless at first sight, they are important because
+   they make it possible to include the data types of the aggregated
+   input(s) in the final function's signature, which may be necessary
+   to resolve the output type of a polymorphic aggregate.  For example,
+   the built-in <function>mode()</> ordered-set aggregate takes a
+   single aggregated column of any sortable data type and returns a
+   value of that same type.  This is possible because the final function
+   is declared as <literal>mode_final(internal, anyelement) returns
+   anyelement</>, with the <type>anyelement</> parameter corresponding
+   to the dummy null argument that represents the aggregated column.
+   The actual data is conveyed in the <type>internal</>-type state
+   value, but type resolution needs a parse-time indication of what the
+   result data type will be, and the dummy argument provides that.
+   In the example of <function>percentile_disc</>, the support functions
+   are respectively declared as
+   <literal>ordered_set_transition(internal, "any") returns internal</>
+   and <literal>percentile_disc_final(internal, float8, anyelement)
+   returns anyelement</>.
+  </para>
+
+  <para>
    A function written in C can detect that it is being called as an
    aggregate transition or final function by calling
    <function>AggCheckCallContext</>, for example:
 </programlisting>
    One reason for checking this is that when it is true for a transition
    function, the first input
-   must be a temporary transition value and can therefore safely be modified
+   must be a temporary state value and can therefore safely be modified
    in-place rather than allocating a new copy.
    See <literal>int8inc()</> for an example.
    (This is the <emphasis>only</>
    case where it is safe for a function to modify a pass-by-reference input.
-   In particular, aggregate final functions should not modify their inputs in
-   any case, because in some cases they will be re-executed on the same
-   final transition value.)
+   In particular, final functions for normal aggregates must not
+   modify their inputs in any case, because in some cases they will be
+   re-executed on the same final state value.)
+  </para>
+
+  <para>
+   Another support routine available to aggregate functions written in C
+   is <function>AggGetAggref</>, which returns the <literal>Aggref</>
+   parse node that defines the aggregate call.  This is mainly useful
+   for ordered-set aggregates, which can inspect the substructure of
+   the <literal>Aggref</> node to find out what sort ordering they are
+   supposed to implement.  Examples can be found
+   in <filename>orderedsetaggs.c</> in the <productname>PostgreSQL</>
+   source code.
   </para>
 
   <para>

File src/backend/catalog/pg_aggregate.c

View file
  • Ignore whitespace
 
 
 static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
+					Oid variadicArgType,
 					Oid *rettype);
 
 
 Oid
 AggregateCreate(const char *aggName,
 				Oid aggNamespace,
+				char aggKind,
 				int numArgs,
+				int numDirectArgs,
 				oidvector *parameterTypes,
 				Datum allParameterTypes,
 				Datum parameterModes,
 				Datum parameterNames,
 				List *parameterDefaults,
+				Oid variadicArgType,
 				List *aggtransfnName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 	bool		hasInternalArg;
 	Oid			rettype;
 	Oid			finaltype;
-	Oid		   *fnArgs;
+	Oid			fnArgs[FUNC_MAX_ARGS];
 	int			nargs_transfn;
 	Oid			procOid;
 	TupleDesc	tupDesc;
 	if (!aggtransfnName)
 		elog(ERROR, "aggregate must have a transition function");
 
+	if (numDirectArgs < 0 || numDirectArgs > numArgs)
+		elog(ERROR, "incorrect number of direct args for aggregate");
+
+	/*
+	 * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
+	 * and/or finalfn will be unrepresentable in pg_proc.  We must check now
+	 * to protect fixed-size arrays here and possibly in called functions.
+	 */
+	if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
+		ereport(ERROR,
+				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+				 errmsg_plural("aggregates cannot have more than %d argument",
+							 "aggregates cannot have more than %d arguments",
+							   FUNC_MAX_ARGS - 1,
+							   FUNC_MAX_ARGS - 1)));
+
 	/* check for polymorphic and INTERNAL arguments */
 	hasPolyArg = false;
 	hasInternalArg = false;
 				 errmsg("cannot determine transition data type"),
 				 errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
 
-	/* find the transfn */
-	nargs_transfn = numArgs + 1;
-	fnArgs = (Oid *) palloc(nargs_transfn * sizeof(Oid));
-	fnArgs[0] = aggTransType;
-	memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
-	transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
+	/*
+	 * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY.	In
+	 * principle we could support regular variadic types, but it would make
+	 * things much more complicated because we'd have to assemble the correct
+	 * subsets of arguments into array values.	Since no standard aggregates
+	 * have use for such a case, we aren't bothering for now.
+	 */
+	if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
+		variadicArgType != ANYOID)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
+
+	/*
+	 * If it's a hypothetical-set aggregate, there must be at least as many
+	 * direct arguments as aggregated ones, and the last N direct arguments
+	 * must match the aggregated ones in type.	(We have to check this again
+	 * when the aggregate is called, in case ANY is involved, but it makes
+	 * sense to reject the aggregate definition now if the declared arg types
+	 * don't match up.)  It's unconditionally OK if numDirectArgs == numArgs,
+	 * indicating that the grammar merged identical VARIADIC entries from both
+	 * lists.  Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
+	 * the aggregated side, which is not OK.  Otherwise, insist on the last N
+	 * parameter types on each side matching exactly.
+	 */
+	if (aggKind == AGGKIND_HYPOTHETICAL &&
+		numDirectArgs < numArgs)
+	{
+		int			numAggregatedArgs = numArgs - numDirectArgs;
+
+		if (OidIsValid(variadicArgType) ||
+			numDirectArgs < numAggregatedArgs ||
+			memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
+				   aggArgTypes + numDirectArgs,
+				   numAggregatedArgs * sizeof(Oid)) != 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+					 errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
+	}
+
+	/*
+	 * Find the transfn.  For ordinary aggs, it takes the transtype plus all
+	 * aggregate arguments.  For ordered-set aggs, it takes the transtype plus
+	 * all aggregated args, but not direct args.  However, we have to treat
+	 * specially the case where a trailing VARIADIC item is considered to
+	 * cover both direct and aggregated args.
+	 */
+	if (AGGKIND_IS_ORDERED_SET(aggKind))
+	{
+		if (numDirectArgs < numArgs)
+			nargs_transfn = numArgs - numDirectArgs + 1;
+		else
+		{
+			/* special case with VARIADIC last arg */
+			Assert(variadicArgType != InvalidOid);
+			nargs_transfn = 2;
+		}
+		fnArgs[0] = aggTransType;
+		memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
+			   (nargs_transfn - 1) * sizeof(Oid));
+	}
+	else
+	{
+		nargs_transfn = numArgs + 1;
+		fnArgs[0] = aggTransType;
+		memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
+	}
+	transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
+								  fnArgs, variadicArgType,
 								  &rettype);
 
 	/*
 	/* handle finalfn, if supplied */
 	if (aggfinalfnName)
 	{
+		int			nargs_finalfn;
+
+		/*
+		 * For ordinary aggs, the finalfn just takes the transtype.  For
+		 * ordered-set aggs, it takes the transtype plus all args.	(The
+		 * aggregated args are useless at runtime, and are actually passed as
+		 * NULLs, but we may need them in the function signature to allow
+		 * resolution of a polymorphic agg's result type.)
+		 */
 		fnArgs[0] = aggTransType;
-		finalfn = lookup_agg_function(aggfinalfnName, 1, fnArgs,
+		if (AGGKIND_IS_ORDERED_SET(aggKind))
+		{
+			nargs_finalfn = numArgs + 1;
+			memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
+		}
+		else
+		{
+			nargs_finalfn = 1;
+			/* variadic-ness of the aggregate doesn't affect finalfn */
+			variadicArgType = InvalidOid;
+		}
+		finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
+									  fnArgs, variadicArgType,
 									  &finaltype);
+
+		/*
+		 * The finalfn of an ordered-set agg will certainly be passed at least
+		 * one null argument, so complain if it's strict.  Nothing bad would
+		 * happen at runtime (you'd just get a null result), but it's surely
+		 * not what the user wants, so let's complain now.
+		 *
+		 * Note: it's likely that a strict transfn would also be a mistake,
+		 * but the case isn't quite so airtight, so we let that pass.
+		 */
+		if (AGGKIND_IS_ORDERED_SET(aggKind) && func_strict(finalfn))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+					 errmsg("final function of an ordered-set aggregate must not be declared STRICT")));
 	}
 	else
 	{
 		values[i] = (Datum) NULL;
 	}
 	values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
+	values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
+	values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
 	values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
 	values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
 	values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
 lookup_agg_function(List *fnName,
 					int nargs,
 					Oid *input_types,
+					Oid variadicArgType,
 					Oid *rettype)
 {
 	Oid			fnOid;
 											  NIL, input_types))));
 
 	/*
+	 * If the agg is declared to take VARIADIC ANY, the underlying functions
+	 * had better be declared that way too, else they may receive too many
+	 * parameters; but func_get_detail would have been happy with plain ANY.
+	 * (Probably nothing very bad would happen, but it wouldn't work as the
+	 * user expects.)  Other combinations should work without any special
+	 * pushups, given that we told func_get_detail not to expand VARIADIC.
+	 */
+	if (variadicArgType == ANYOID && vatype != ANYOID)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
+						func_signature_string(fnName, nargs,
+											  NIL, input_types))));
+
+	/*
 	 * If there are any polymorphic types involved, enforce consistency, and
 	 * possibly refine the result type.  It's OK if the result is still
 	 * polymorphic at this point, though.
 	 */
 	for (i = 0; i < nargs; i++)
 	{
-		if (!IsPolymorphicType(true_oid_array[i]) &&
-			!IsBinaryCoercible(input_types[i], true_oid_array[i]))
+		if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
 					 errmsg("function %s requires run-time type coercion",

File src/backend/commands/aggregatecmds.c

View file
  • Ignore whitespace
  *
  * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
  * is specified by a BASETYPE element in the parameters.  Otherwise,
- * "args" is a list of FunctionParameter structs defining the agg's arguments.
+ * "args" is a pair, whose first element is a list of FunctionParameter structs
+ * defining the agg's arguments (both direct and aggregated), and whose second
+ * element is an Integer node with the number of direct args, or -1 if this
+ * isn't an ordered-set aggregate.
  * "parameters" is a list of DefElem representing the agg's definition clauses.
  */
 Oid
 	char	   *aggName;
 	Oid			aggNamespace;
 	AclResult	aclresult;
+	char		aggKind = AGGKIND_NORMAL;
 	List	   *transfuncName = NIL;
 	List	   *finalfuncName = NIL;
 	List	   *sortoperatorName = NIL;
 	int32		transSpace = 0;
 	char	   *initval = NULL;
 	int			numArgs;
+	int			numDirectArgs = 0;
 	oidvector  *parameterTypes;
 	ArrayType  *allParameterTypes;
 	ArrayType  *parameterModes;
 	ArrayType  *parameterNames;
 	List	   *parameterDefaults;
+	Oid			variadicArgType;
 	Oid			transTypeId;
 	char		transTypeType;
 	ListCell   *pl;
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
 					   get_namespace_name(aggNamespace));
 
+	/* Deconstruct the output of the aggr_args grammar production */
+	if (!oldstyle)
+	{
+		Assert(list_length(args) == 2);
+		numDirectArgs = intVal(lsecond(args));
+		if (numDirectArgs >= 0)
+			aggKind = AGGKIND_ORDERED_SET;
+		else
+			numDirectArgs = 0;
+		args = (List *) linitial(args);
+	}
+
+	/* Examine aggregate's definition clauses */
 	foreach(pl, parameters)
 	{
 		DefElem    *defel = (DefElem *) lfirst(pl);
 			sortoperatorName = defGetQualifiedName(defel);
 		else if (pg_strcasecmp(defel->defname, "basetype") == 0)
 			baseType = defGetTypeName(defel);
+		else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
+		{
+			if (defGetBoolean(defel))
+			{
+				if (aggKind == AGGKIND_NORMAL)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+							 errmsg("only ordered-set aggregates can be hypothetical")));
+				aggKind = AGGKIND_HYPOTHETICAL;
+			}
+		}
 		else if (pg_strcasecmp(defel->defname, "stype") == 0)
 			transType = defGetTypeName(defel);
 		else if (pg_strcasecmp(defel->defname, "stype1") == 0)
 		parameterModes = NULL;
 		parameterNames = NULL;
 		parameterDefaults = NIL;
+		variadicArgType = InvalidOid;
 	}
 	else
 	{
 										  &parameterModes,
 										  &parameterNames,
 										  &parameterDefaults,
+										  &variadicArgType,
 										  &requiredResultType);
 		/* Parameter defaults are not currently allowed by the grammar */
 		Assert(parameterDefaults == NIL);
 	 */
 	return AggregateCreate(aggName,		/* aggregate name */
 						   aggNamespace,		/* namespace */
+						   aggKind,
 						   numArgs,
+						   numDirectArgs,
 						   parameterTypes,
 						   PointerGetDatum(allParameterTypes),
 						   PointerGetDatum(parameterModes),
 						   PointerGetDatum(parameterNames),
 						   parameterDefaults,
+						   variadicArgType,
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */

File src/backend/commands/functioncmds.c

View file
  • Ignore whitespace
  *
  * Results are stored into output parameters.  parameterTypes must always
  * be created, but the other arrays are set to NULL if not needed.
+ * variadicArgType is set to the variadic array type if there's a VARIADIC
+ * parameter (there can be only one); or to InvalidOid if not.
  * requiredResultType is set to InvalidOid if there are no OUT parameters,
  * else it is set to the OID of the implied result type.
  */
 								  ArrayType **parameterModes,
 								  ArrayType **parameterNames,
 								  List **parameterDefaults,
+								  Oid *variadicArgType,
 								  Oid *requiredResultType)
 {
 	int			parameterCount = list_length(parameters);
 	int			i;
 	ParseState *pstate;
 
+	*variadicArgType = InvalidOid;		/* default result */
 	*requiredResultType = InvalidOid;	/* default result */
 
 	inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
 
 		if (fp->mode == FUNC_PARAM_VARIADIC)
 		{
+			*variadicArgType = toid;
 			varCount++;
 			/* validate variadic parameter type */
 			switch (toid)
 	ArrayType  *parameterModes;
 	ArrayType  *parameterNames;
 	List	   *parameterDefaults;
+	Oid			variadicArgType;
 	Oid			requiredResultType;
 	bool		isWindowFunc,
 				isStrict,
 									  &parameterModes,
 									  &parameterNames,
 									  &parameterDefaults,
+									  &variadicArgType,
 									  &requiredResultType);
 
 	if (stmt->returnType)

File src/backend/executor/execQual.c

View file
  • Ignore whitespace
 					aggstate->aggs = lcons(astate, aggstate->aggs);
 					naggs = ++aggstate->numaggs;
 
+					astate->aggdirectargs = (List *) ExecInitExpr((Expr *) aggref->aggdirectargs,
+																  parent);
 					astate->args = (List *) ExecInitExpr((Expr *) aggref->args,
 														 parent);
 					astate->aggfilter = ExecInitExpr(aggref->aggfilter,

File src/backend/executor/functions.c

View file
  • Ignore whitespace
 		param = ParseFuncOrColumn(pstate,
 								  list_make1(subfield),
 								  list_make1(param),
-								  NIL, NULL, false, false, false,
-								  NULL, true, cref->location);
+								  NULL,
+								  cref->location);
 	}
 
 	return param;

File src/backend/executor/nodeAgg.c

View file
  • Ignore whitespace
  *		 transvalue = initcond
  *		 foreach input_tuple do
  *			transvalue = transfunc(transvalue, input_value(s))
- *		 result = finalfunc(transvalue)
+ *		 result = finalfunc(transvalue, direct_argument(s))
  *
  *	  If a finalfunc is not supplied then the result is just the ending
  *	  value of transvalue.
  *
- *	  If an aggregate call specifies DISTINCT or ORDER BY, we sort the input
- *	  tuples and eliminate duplicates (if required) before performing the
- *	  above-depicted process.
+ *	  If a normal aggregate call specifies DISTINCT or ORDER BY, we sort the
+ *	  input tuples and eliminate duplicates (if required) before performing
+ *	  the above-depicted process.  (However, we don't do that for ordered-set
+ *	  aggregates; their "ORDER BY" inputs are ordinary aggregate arguments
+ *	  so far as this module is concerned.)
  *
  *	  If transfunc is marked "strict" in pg_proc and initcond is NULL,
  *	  then the first non-NULL input_value is assigned directly to transvalue,
  *	  of course).  A non-strict finalfunc can make its own choice of
  *	  what to return for a NULL ending transvalue.
  *
+ *	  Ordered-set aggregates are treated specially in one other way: we
+ *	  evaluate any "direct" arguments and pass them to the finalfunc along
+ *	  with the transition value.  In addition, NULL placeholders are
+ *	  provided to match the remaining finalfunc arguments, which correspond
+ *	  to the aggregated expressions.  (These arguments have no use at
+ *	  runtime, but may be needed to allow resolution of a polymorphic
+ *	  aggregate's result type.)
+ *
  *	  We compute aggregate input expressions and run the transition functions
  *	  in a temporary econtext (aggstate->tmpcontext).  This is reset at
  *	  least once per input tuple, so when the transvalue datatype is
  *	  memory context, and free the prior value to avoid memory leakage.
  *	  We store transvalues in the memory context aggstate->aggcontext,
  *	  which is also used for the hashtable structures in AGG_HASHED mode.
- *	  The node's regular econtext (aggstate->csstate.cstate.cs_ExprContext)
+ *	  The node's regular econtext (aggstate->ss.ps.ps_ExprContext)
  *	  is used to run finalize functions and compute the output tuple;
  *	  this context can be reset once per output tuple.
  *
  *	  AggState is available as context in earlier releases (back to 8.1),
  *	  but direct examination of the node is needed to use it before 9.0.
  *
+ *	  As of 9.4, aggregate transition functions can also use AggGetAggref()
+ *	  to get hold of the Aggref expression node for their aggregate call.
+ *	  This is mainly intended for ordered-set aggregates, which are not
+ *	  supported as window functions.  (A regular aggregate function would
+ *	  need some fallback logic to use this, since there's no Aggref node
+ *	  for a window function.)
+ *
  *
  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
 #include "catalog/objectaccess.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_proc.h"
-#include "catalog/pg_type.h"
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "miscadmin.h"
 	AggrefExprState *aggrefstate;
 	Aggref	   *aggref;