Support ordered-set (WITHIN GROUP) aggregates.
authorTom Lane
Mon, 23 Dec 2013 21:11:35 +0000 (16:11 -0500)
committerTom Lane
Mon, 23 Dec 2013 21:11:35 +0000 (16:11 -0500)
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

64 files changed:
contrib/pg_stat_statements/pg_stat_statements.c
doc/src/sgml/catalogs.sgml
doc/src/sgml/func.sgml
doc/src/sgml/ref/alter_aggregate.sgml
doc/src/sgml/ref/alter_extension.sgml
doc/src/sgml/ref/comment.sgml
doc/src/sgml/ref/create_aggregate.sgml
doc/src/sgml/ref/drop_aggregate.sgml
doc/src/sgml/ref/security_label.sgml
doc/src/sgml/syntax.sgml
doc/src/sgml/xaggr.sgml
src/backend/catalog/pg_aggregate.c
src/backend/commands/aggregatecmds.c
src/backend/commands/functioncmds.c
src/backend/executor/execQual.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeWindowAgg.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/clauses.c
src/backend/parser/gram.y
src/backend/parser/parse_agg.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_collate.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/utils/adt/Makefile
src/backend/utils/adt/orderedsetaggs.c [new file with mode: 0644]
src/backend/utils/adt/ri_triggers.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/sort/tuplesort.c
src/bin/pg_dump/pg_dump.c
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/commands/defrem.h
src/include/fmgr.h
src/include/nodes/execnodes.h
src/include/nodes/parsenodes.h
src/include/nodes/primnodes.h
src/include/nodes/relation.h
src/include/parser/kwlist.h
src/include/parser/parse_agg.h
src/include/parser/parse_clause.h
src/include/parser/parse_func.h
src/include/utils/builtins.h
src/include/utils/lsyscache.h
src/include/utils/tuplesort.h
src/test/regress/expected/aggregates.out
src/test/regress/expected/create_aggregate.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/opr_sanity.sql

index 9f3e376300c35d816c465c2cf27476eb69af3cf4..6ec7540cc17ef12605aa8c08a6970491f5c944c9 100644 (file)
@@ -1586,6 +1586,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
                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);
index acc261ca516cd91368ad19dd4750c4bbb0294809..558b41b9bc57040d7e9fe889c8281b7f6a1a1dfd 100644 (file)
       pg_proc.oid
       pg_proc OID of the aggregate function
      
+     
+      aggkind
+      char
+      
+      Aggregate kind:
+       n for normal aggregates,
+       o for ordered-set aggregates, or
+       h for hypothetical-set aggregates
+      
+     
+     
+      aggnumdirectargs
+      int2
+      
+      Number of direct (non-aggregated) arguments of an ordered-set or
+       hypothetical-set aggregate, counting a variadic array as one argument.
+       If equal to 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.
+     
      
       aggtransfn
       regproc
index a411e3a0cc94e4b75923caae8ba199ec027cb610..8579bdd9480e8069f7ce2c1f9d02dc19ca61b95c 100644 (file)
@@ -11560,10 +11560,13 @@ NULL baz(3 rows)
 
   
    Aggregate functions 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
     and
    .
+   The built-in ordered-set aggregate functions
+   are listed in  and
+   .
    The special syntax considerations for aggregate
    functions are explained in .
    Consult  for additional introductory
@@ -12307,6 +12310,290 @@ SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
    
   
 
+  
+    shows some
+   aggregate functions that use the ordered-set aggregate
+   syntax.  These functions are sometimes referred to as inverse
+   distribution functions.
+  
+
+  
+   ordered-set aggregate
+   built-in
+  
+  
+   inverse distribution
+  
+
+  
+   Ordered-Set Aggregate Functions
+
+   
+    
+     
+      Function
+      Direct Argument Type(s)
+      Aggregated Argument Type(s)
+      Return Type
+      Description
+     
+    
+
+    
+
+     
+      
+       
+        mode
+        statistical
+       
+       mode() WITHIN GROUP (ORDER BY sort_expression)
+      
+      
+      
+      
+       any sortable type
+      
+      
+       same as sort expression
+      
+      
+       returns the most frequent input value (arbitrarily choosing the first
+       one if there are multiple equally-frequent results)
+      
+     
+
+     
+      
+       
+        percentile
+        continuous
+       
+       
+        median
+       
+       percentile_cont(fraction) WITHIN GROUP (ORDER BY sort_expression)
+      
+      
+       double precision
+      
+      
+       double precision or interval
+      
+      
+       same as sort expression
+      
+      
+       continuous percentile: returns a value corresponding to the specified
+       fraction in the ordering, interpolating between adjacent input items if
+       needed
+      
+     
+
+     
+      
+       percentile_cont(fractions) WITHIN GROUP (ORDER BY sort_expression)
+      
+      
+       double precision[]
+      
+      
+       double precision or interval
+      
+      
+       array of sort expression's type
+      
+      
+       multiple continuous percentile: returns an array of results matching
+       the shape of the fractions parameter, with each
+       non-null element replaced by the value corresponding to that percentile
+      
+     
+
+     
+      
+       
+        percentile
+        discrete
+       
+       percentile_disc(fraction) WITHIN GROUP (ORDER BY sort_expression)
+      
+      
+       double precision
+      
+      
+       any sortable type
+      
+      
+       same as sort expression
+      
+      
+       discrete percentile: returns the first input value whose position in
+       the ordering equals or exceeds the specified fraction
+      
+     
+
+     
+      
+       percentile_disc(fractions) WITHIN GROUP (ORDER BY sort_expression)
+      
+      
+       double precision[]
+      
+      
+       any sortable type
+      
+      
+       array of sort expression's type
+      
+      
+       multiple discrete percentile: returns an array of results matching the
+       shape of the fractions parameter, with each non-null
+       element replaced by the input value corresponding to that percentile
+      
+     
+
+    
+   
+  
+
+  
+   All the aggregates listed in 
+   ignore null values in their sorted input.  For those that take
+   a fraction 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.
+  
+
+  
+   Each of the aggregates listed in
+    is associated with a
+   window function of the same name defined in
+   .  In each case, the aggregate result
+   is the value that the associated window function would have
+   returned for the hypothetical row constructed from
+   args, if such a row had been added to the sorted
+   group of rows computed from the sorted_args.
+  
+
+  
+   Hypothetical-Set Aggregate Functions
+
+   
+    
+     
+      Function
+      Direct Argument Type(s)
+      Aggregated Argument Type(s)
+      Return Type
+      Description
+     
+    
+
+    
+
+     
+      
+       
+        rank
+        hypothetical
+       
+       rank(args) WITHIN GROUP (ORDER BY sorted_args)
+      
+      
+       VARIADIC "any"
+      
+      
+       VARIADIC "any"
+      
+      
+       bigint
+      
+      
+       rank of the hypothetical row, with gaps for duplicate rows
+      
+     
+
+     
+      
+       
+        dense_rank
+        hypothetical
+       
+       dense_rank(args) WITHIN GROUP (ORDER BY sorted_args)
+      
+      
+       VARIADIC "any"
+      
+      
+       VARIADIC "any"
+      
+      
+       bigint
+      
+      
+       rank of the hypothetical row, without gaps
+      
+     
+
+     
+      
+       
+        percent_rank
+        hypothetical
+       
+       percent_rank(args) WITHIN GROUP (ORDER BY sorted_args)
+      
+      
+       VARIADIC "any"
+      
+      
+       VARIADIC "any"
+      
+      
+       double precision
+      
+      
+       relative rank of the hypothetical row, ranging from 0 to 1
+      
+     
+
+     
+      
+       
+        cume_dist
+        hypothetical
+       
+       cume_dist(args) WITHIN GROUP (ORDER BY sorted_args)
+      
+      
+       VARIADIC "any"
+      
+      
+       VARIADIC "any"
+      
+      
+       double precision
+      
+      
+       relative rank of the hypothetical row, ranging from
+       1/N to 1
+      
+     
+
+    
+   
+  
+
+  
+   For each of these hypothetical-set aggregates, the list of direct arguments
+   given in args must match the number and types of
+   the aggregated arguments given in sorted_args.
+   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 ORDER BY clause.
+  
+
  
 
  
@@ -12332,9 +12619,10 @@ SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
   
 
   
-   In addition to these functions, any built-in or user-defined aggregate
-   function can be used as a window function (see
-    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
+    for a list of the built-in aggregates.
    Aggregate functions act as window functions only when an OVER
    clause follows the call; otherwise they act as regular aggregates.
   
index aab5b2b695ec9a2a5b870379398b0a7e5913d0c3..641d19ccebe4eeab50acdfe6f2eabf2d8791ed0c 100644 (file)
@@ -21,12 +21,15 @@ PostgreSQL documentation
 
  
 
-ALTER AGGREGATE name ( [ argmode ] [ arg_name ] arg_data_type [ , ... ] )
-  RENAME TO new_name
-ALTER AGGREGATE name ( [ argmode ] [ arg_name ] arg_data_type [ , ... ] )
-  OWNER TO new_owner
-ALTER AGGREGATE name ( [ argmode ] [ arg_name ] arg_data_type [ , ... ] )
-  SET SCHEMA new_schema
+ALTER AGGREGATE name ( aggregate_signature ) RENAME TO new_name
+ALTER AGGREGATE name ( aggregate_signature ) OWNER TO new_owner
+ALTER AGGREGATE name ( aggregate_signature ) SET SCHEMA new_schema
+
+where aggregate_signature is:
+
+* |
+[ argmode ] [ argname ] argtype [ , ... ] |
+[ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ] argtype [ , ... ]
 
  
 
@@ -76,7 +79,7 @@ ALTER AGGREGATE name ( [ argmode
    
 
    
-    arg_name
+    argname
 
     
      
@@ -89,12 +92,15 @@ ALTER AGGREGATE name ( [ argmode
    
 
    
-    arg_data_type
+    argtype
     
      
       An input data type on which the aggregate function operates.
       To reference a zero-argument aggregate function, write *
       in place of the list of argument specifications.
+      To reference an ordered-set aggregate function, write
+      ORDER BY between the direct and aggregated argument
+      specifications.
      
     
    
@@ -128,6 +134,21 @@ ALTER AGGREGATE name ( [ argmode
   
  
 
+  Notes
+
+   
+    The recommended syntax for referencing an ordered-set aggregate
+    is to write ORDER BY between the direct and aggregated
+    argument specifications, in the same style as in
+    .  However, it will also work to
+    omit ORDER BY and just run the direct and aggregated
+    argument specifications into a single list.  In this abbreviated form,
+    if VARIADIC "any" was used in both the direct and
+    aggregated argument lists, write VARIADIC "any" only once.
+   
+
  
   Examples
 
@@ -148,11 +169,17 @@ ALTER AGGREGATE myavg(integer) OWNER TO joe;
   
 
   
-   To move the aggregate function myavg for type
-   integer into schema myschema:
+   To move the ordered-set aggregate mypercentile with
+   direct argument of type float8 and aggregated argument
+   of type integer into schema myschema:
 
-ALTER AGGREGATE myavg(integer) SET SCHEMA myschema;
-
+ALTER AGGREGATE mypercentile(float8 ORDER BY integer) SET SCHEMA myschema;
+
+   This will work too:
+
+ALTER AGGREGATE mypercentile(float8, integer) SET SCHEMA myschema;
+
+  
  
 
  
index a14fcb4868365ec3759218ace826974806d27083..56fa30d2d3af411df151415dd95a1d64ca74ed45 100644 (file)
@@ -30,7 +30,7 @@ ALTER EXTENSION name DROP 
 
 where member_object is:
 
-  AGGREGATE agg_name ( [ argmode ] [ argname ] agg_type [, ...] ) |
+  AGGREGATE aggregate_name ( aggregate_signature ) |
   CAST (source_type AS target_type) |
   COLLATION object_name |
   CONVERSION object_name |
@@ -54,6 +54,12 @@ ALTER EXTENSION name DROP 
   TEXT SEARCH TEMPLATE object_name |
   TYPE object_name |
   VIEW object_name
+
+and aggregate_signature is:
+
+* |
+[ argmode ] [ argname ] argtype [ , ... ] |
+[ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ] argtype [ , ... ]
 
  
 
@@ -159,7 +165,7 @@ ALTER EXTENSION name DROP 
 
     
      object_name
-     agg_name
+     aggregate_name
      function_name
      operator_name
      
@@ -173,17 +179,6 @@ ALTER EXTENSION name DROP 
      
     
 
-    
-     agg_type
-     
-      
-       An input data type on which the aggregate function operates.
-       To reference a zero-argument aggregate function, write *
-       in place of the list of argument specifications.
-      
-     
-    
-
     
      source_type
      
@@ -207,7 +202,8 @@ ALTER EXTENSION name DROP 
 
      
       
-       The mode of a function argument: IN, OUT,
+       The mode of a function or aggregate
+       argument: IN, OUT,
        INOUT, or VARIADIC.
        If omitted, the default is IN.
        Note that ALTER EXTENSION does not actually pay
@@ -224,7 +220,7 @@ ALTER EXTENSION name DROP 
 
      
       
-       The name of a function argument.
+       The name of a function or aggregate argument.
        Note that ALTER EXTENSION does not actually pay
        any attention to argument names, since only the argument data
        types are needed to determine the function's identity.
@@ -237,8 +233,7 @@ ALTER EXTENSION name DROP 
 
      
       
-       The data type(s) of the function's arguments (optionally
-       schema-qualified), if any.
+       The data type of a function or aggregate argument.
       
      
     
index e55050042a8261bf3160b8cf2b01fb44623d1ba1..1b2949f64f1e00ad2713f66c73580a103a556893 100644 (file)
@@ -23,7 +23,7 @@ PostgreSQL documentation
 
 COMMENT ON
 {
-  AGGREGATE agg_name ( [ argmode ] [ argname ] agg_type [, ...] ) |
+  AGGREGATE aggregate_name ( aggregate_signature ) |
   CAST (source_type AS target_type) |
   COLLATION object_name |
   COLUMN relation_name.column_name |
@@ -58,6 +58,12 @@ COMMENT ON
   TYPE object_name |
   VIEW object_name
 } IS 'text'
+
+where aggregate_signature is:
+
+* |
+[ argmode ] [ argname ] argtype [ , ... ] |
+[ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ] argtype [ , ... ]
 
  
 
@@ -101,7 +107,7 @@ COMMENT ON
    
     object_name
     relation_name.column_name
-    agg_name
+    aggregate_name
     constraint_name
     function_name
     operator_name
@@ -120,17 +126,6 @@ COMMENT ON
     
    
 
-   
-    agg_type
-    
-     
-      An input data type on which the aggregate function operates.
-      To reference a zero-argument aggregate function, write *
-      in place of the list of argument specifications.
-     
-    
-   
-
    
      source_type
      
@@ -153,7 +148,8 @@ COMMENT ON
     argmode
     
      
-      The mode of a function argument: IN, OUT,
+      The mode of a function or aggregate
+      argument: IN, OUT,
       INOUT, or VARIADIC.
       If omitted, the default is IN.
       Note that COMMENT does not actually pay
@@ -169,7 +165,7 @@ COMMENT ON
     argname
     
      
-      The name of a function argument.
+      The name of a function or aggregate argument.
       Note that COMMENT does not actually pay
       any attention to argument names, since only the argument data
       types are needed to determine the function's identity.
@@ -181,8 +177,7 @@ COMMENT ON
     argtype
     
      
-      The data type(s) of the function's arguments (optionally
-      schema-qualified), if any.
+      The data type of a function or aggregate argument.
      
     
    
index 17819dd1a8edf627df699bdc198ffffdfa2a24e2..d15fcbae959c5818100417175140f0cef7ac4f56 100644 (file)
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  
 
-CREATE AGGREGATE name ( [ argmode ] [ arg_name ] arg_data_type [ , ... ] ) (
+CREATE AGGREGATE name ( [ argmode ] [ argname ] arg_data_type [ , ... ] ) (
     SFUNC = sfunc,
     STYPE = state_data_type
     [ , SSPACE = state_data_size ]
@@ -30,6 +30,16 @@ CREATE AGGREGATE name ( [ 
     [ , SORTOP = sort_operator ]
 )
 
+CREATE AGGREGATE name ( [ [ argmode ] [ argname ] arg_data_type [ , ... ] ]
+                        ORDER BY [ argmode ] [ argname ] arg_data_type [ , ... ] ) (
+    SFUNC = sfunc,
+    STYPE = state_data_type
+    [ , SSPACE = state_data_size ]
+    [ , FINALFUNC = ffunc ]
+    [ , INITCOND = initial_condition ]
+    [ , HYPOTHETICAL ]
+)
+
 or the old syntax
 
 CREATE AGGREGATE name (
@@ -69,6 +79,8 @@ CREATE AGGREGATE name (
    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 ).
   
 
   
@@ -128,7 +140,7 @@ CREATE AGGREGATE name (
   
    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.
   
 
@@ -142,6 +154,22 @@ CREATE AGGREGATE name (
    input rows.
   
 
+  
+   The syntax with ORDER BY in the parameter list creates
+   a special type of aggregate called an ordered-set
+   aggregate; or if HYPOTHETICAL is specified, then
+   a hypothetical-set aggregate 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 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 hypothetical row.
+  
+
   
    Aggregates that behave like MIN or MAX can
    sometimes be optimized by looking into an index instead of scanning every
@@ -202,7 +230,7 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
    
 
    
-    arg_name
+    argname
 
     
      
@@ -234,6 +262,7 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
       only one input parameter.  To define a zero-argument aggregate function
       with this syntax, specify the basetype as
       "ANY" (not *).
+      Ordered-set aggregates cannot be defined with the old syntax.
      
     
    
@@ -243,7 +272,7 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
     
      
       The name of the state transition function to be called for each
-      input row.  For an N-argument
+      input row.  For a normal N-argument
       aggregate function, the sfunc
       must take N+1 arguments,
       the first being of type 
@@ -254,6 +283,13 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
       takes the current state value and the current input data value(s),
       and returns the next state value.
      
+
+     
+      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.
+     
     
    
 
@@ -287,7 +323,8 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
     
      
       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 
       class="PARAMETER">state_data_type.  The return
       data type of the aggregate is defined as the return type of this
@@ -296,6 +333,17 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
       aggregate's result, and the return type is 
       class="PARAMETER">state_data_type.
      
+
+     
+      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.)
+     
     
    
 
@@ -319,7 +367,22 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
       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).
+     
+    
+   
+
+   
+    HYPOTHETICAL
+    
+     
+      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 (WITHIN GROUP)
+      arguments.  The HYPOTHETICAL flag has no effect on
+      run-time behavior, only on parse-time resolution of the data types and
+      collations of the aggregate's arguments.
      
     
    
@@ -331,6 +394,29 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
   
  
 
+  Notes
+
+   
+    The syntax for ordered-set aggregates allows VARIADIC
+    to be specified for both the last direct parameter and the last
+    aggregated (WITHIN GROUP) parameter.  However, the
+    current implementation restricts use of VARIADIC
+    in two ways.  First, ordered-set aggregates can only use
+    VARIADIC "any", not other variadic array types.
+    Second, if the last direct parameter is VARIADIC "any",
+    then there can be only one aggregated parameter and it must also
+    be VARIADIC "any".  (In the representation used in the
+    system catalogs, these two parameters are merged into a single
+    VARIADIC "any" item, since pg_proc cannot
+    represent functions with more than one VARIADIC parameter.)
+    If the aggregate is a hypothetical-set aggregate, the direct arguments
+    that match the VARIADIC "any" parameter are the hypothetical
+    ones; any preceding parameters represent additional direct arguments
+    that are not constrained to match the aggregated arguments.
+   
+
  
   Examples
 
index 06060fb4f7bd02c428dbfca65090e6bf20ff9351..e89e76268fe938fd3b9c28bbcf44a132ffc57f6d 100644 (file)
@@ -21,9 +21,13 @@ PostgreSQL documentation
 
  
 
-DROP AGGREGATE [ IF EXISTS ]
-  name ( [ argmode ] [ arg_name ] arg_data_type [ , ... ] )
-  [ CASCADE | RESTRICT ]
+DROP AGGREGATE [ IF EXISTS ] name ( aggregate_signature ) [ CASCADE | RESTRICT ]
+
+where aggregate_signature is:
+
+* |
+[ argmode ] [ argname ] argtype [ , ... ] |
+[ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ] argtype [ , ... ]
 
  
 
@@ -73,7 +77,7 @@ DROP AGGREGATE [ IF EXISTS ]
    
 
    
-    arg_name
+    argname
 
     
      
@@ -86,12 +90,15 @@ DROP AGGREGATE [ IF EXISTS ]
    
 
    
-    arg_data_type
+    argtype
     
      
       An input data type on which the aggregate function operates.
       To reference a zero-argument aggregate function, write *
       in place of the list of argument specifications.
+      To reference an ordered-set aggregate function, write
+      ORDER BY between the direct and aggregated argument
+      specifications.
      
     
    
@@ -117,6 +124,15 @@ DROP AGGREGATE [ IF EXISTS ]
   
  
 
+  Notes
+
+   
+    Alternative syntaxes for referencing ordered-set aggregates
+    are described under .
+   
+
  
   Examples
 
@@ -125,7 +141,17 @@ DROP AGGREGATE [ IF EXISTS ]
    integer:
 
 DROP AGGREGATE myavg(integer);
-
+
+  
+
+  
+   To remove the hypothetical-set aggregate function myrank,
+   which takes an arbitrary list of ordering columns and a matching list
+   of direct arguments:
+
+DROP AGGREGATE myrank(VARIADIC "any" ORDER BY VARIADIC "any");
+
+  
  
 
  
index 76c131f94ee1c74c68cee0e5549988dba8599d1d..d7595654e4d7a5a329786583577e51eca9ddac71 100644 (file)
@@ -25,7 +25,7 @@ SECURITY LABEL [ FOR provider ] ON
 {
   TABLE object_name |
   COLUMN table_name.column_name |
-  AGGREGATE agg_name ( [ argmode ] [ argname ] agg_type [, ...] ) |
+  AGGREGATE aggregate_name ( aggregate_signature ) |
   DATABASE object_name |
   DOMAIN object_name |
   EVENT TRIGGER object_name |
@@ -41,6 +41,12 @@ SECURITY LABEL [ FOR provider ] ON
   TYPE object_name |
   VIEW object_name
 } IS 'label'
+
+where aggregate_signature is:
+
+* |
+[ argmode ] [ argname ] argtype [ , ... ] |
+[ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ] argtype [ , ... ]
 
  
 
@@ -83,7 +89,7 @@ SECURITY LABEL [ FOR provider ] ON
    
     object_name
     table_name.column_name
-    agg_name
+    aggregate_name
     function_name
     
      
@@ -106,23 +112,13 @@ SECURITY LABEL [ FOR provider ] ON
     
    
 
-   
-    agg_type
-    
-     
-      An input data type on which the aggregate function operates.
-      To reference a zero-argument aggregate function, write *
-      in place of the list of argument specifications.
-     
-    
-   
-
    
     argmode
 
     
      
-      The mode of a function argument: IN, OUT,
+      The mode of a function or aggregate
+      argument: IN, OUT,
       INOUT, or VARIADIC.
       If omitted, the default is IN.
       Note that SECURITY LABEL does not actually
@@ -139,7 +135,7 @@ SECURITY LABEL [ FOR provider ] ON
 
     
      
-      The name of a function argument.
+      The name of a function or aggregate argument.
       Note that SECURITY LABEL does not actually
       pay any attention to argument names, since only the argument data
       types are needed to determine the function's identity.
@@ -152,8 +148,7 @@ SECURITY LABEL [ FOR provider ] ON
 
     
      
-      The data type(s) of the function's arguments (optionally
-      schema-qualified), if any.
+      The data type of a function or aggregate argument.
      
     
    
index 4f50f431475d673bfa6e6602a2471e47a2d7d251..434a894157712dd1cf5560d2e672549d7aa1f69f 100644 (file)
@@ -1555,7 +1555,15 @@ sqrt(2)
    
 
    
-    filter
+    ordered-set aggregate
+   
+
+   
+    WITHIN GROUP
+   
+
+   
+    FILTER
    
 
    
@@ -1570,6 +1578,7 @@ sqrt(2)
 aggregate_name (ALL expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ]
 aggregate_name (DISTINCT expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ]
 aggregate_name ( * ) [ FILTER ( WHERE filter_clause ) ]
+aggregate_name ( [ expression [ , ... ] ] ) WITHIN GROUP ( order_by_clause ) [ FILTER ( WHERE filter_clause ) ]
 
 
     where aggregate_name is a previously
@@ -1589,9 +1598,11 @@ sqrt(2)
     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 count(*) aggregate function.
+    The last form is used with ordered-set aggregate
+    functions, which are described below.
    
 
    
@@ -1610,23 +1621,6 @@ sqrt(2)
     distinct non-null values of f1.
    
 
-   
-    If FILTER is specified, then only the input
-    rows for which the filter_clause
-    evaluates to true are fed to the aggregate function; other rows
-    are discarded.  For example:
-
-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)
-
-   
-
    
     Ordinarily, the input rows are fed to the aggregate function in an
     unspecified order.  In many cases this does not matter; for example,
@@ -1676,6 +1670,71 @@ SELECT string_agg(a ORDER BY a, ',') FROM table;  -- incorrect
     
    
 
+   
+    Placing ORDER BY within the aggregate's regular argument
+    list, as described so far, is used when ordering the input rows for
+    a normal aggregate for which ordering is optional.  There is a
+    subclass of aggregate functions called ordered-set
+    aggregates for which an order_by_clause
+    is 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 order_by_clause is written
+    inside WITHIN GROUP (...), as shown in the final syntax
+    alternative above.  The expressions in
+    the order_by_clause are evaluated once per
+    input row just like normal aggregate arguments, sorted as per
+    the order_by_clause's requirements, and fed
+    to the aggregate function as input arguments.  (This is unlike the case
+    for a non-WITHIN GROUP order_by_clause,
+    which is not treated as argument(s) to the aggregate function.)  The
+    argument expressions preceding WITHIN GROUP, if any, are
+    called direct arguments to distinguish them from
+    the aggregated arguments listed in
+    the order_by_clause.  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 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 () not (*).
+    (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:
+
+
+SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
+ percentile_disc
+-----------------
+           50489
+
+
+   which obtains the 50th percentile, or median, value of
+   the income column from table households.
+   Here, 0.5 is a direct argument; it would make no sense
+   for the percentile fraction to be a value varying across rows.
+   
+
+   
+    If FILTER is specified, then only the input
+    rows for which the filter_clause
+    evaluates to true are fed to the aggregate function; other rows
+    are discarded.  For example:
+
+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)
+
+   
+
    
     The predefined aggregate functions are described in 
     linkend="functions-aggregate">.  Other aggregate functions can be added
@@ -1695,7 +1754,8 @@ SELECT string_agg(a ORDER BY a, ',') FROM table;  -- incorrect
      and
     ), 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 filter_clause
+    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,
@@ -1856,15 +1916,16 @@ UNBOUNDED FOLLOWING
     If FILTER is specified, then only the input
     rows for which the filter_clause
     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 FILTER clause.
    
 
    
     The built-in window functions are described in 
     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.
    
 
    
@@ -1885,7 +1946,7 @@ UNBOUNDED FOLLOWING
    
     More information about window functions can be found in
     ,
-    ,
+    , and
     .
    
   
index 9ed7d99f7c0e11ccaef6c7e519773d38c791c8b9..e77ef12e5c36441128bd1127eb6234d8535de8ca 100644 (file)
@@ -9,20 +9,27 @@
   
 
   
-   Aggregate functions  in PostgreSQL
-   are expressed in terms of state values
+   Aggregate functions in PostgreSQL
+   are defined in terms of state values
    and state transition functions.
    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 final function
+   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 final function
    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.)
   
 
   
    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)'
 );
+
+
+   which we might use like this:
 
+
 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 sum, but
@@ -64,19 +75,19 @@ SELECT sum(a) FROM test_complex;
   
 
   
-   The above definition of sum will return zero (the initial
-   state condition) if there are no nonnull input values.
+   The above definition of sum will return zero
+   (the initial state value) if there are no nonnull input values.
    Perhaps we want to return null in that case instead — the SQL standard
    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
+   value is null.  Ordinarily this would mean that the sfunc
+   would need to check for a null state-value input.  But for
    sum and some other simple aggregates like
    max and 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.  PostgreSQL
-   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 strict (i.e., not to be called
    for null inputs).
   
@@ -109,12 +120,16 @@ CREATE AGGREGATE avg (float8)
     initcond = '{0,0,0}'
 );
 
+  
 
-   (float8_accum requires a three-element array, not just
+  
+   
+   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 avg.)
-  
+   some other aggregates besides avg.
+   
+  
 
   
    Aggregate functions can use polymorphic
@@ -136,7 +151,7 @@ CREATE AGGREGATE array_accum (anyelement)
 );
 
 
-   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 array_agg provides similar
@@ -205,6 +220,97 @@ SELECT myaggregate(a, b, c ORDER BY a) FROM ...
    
   
 
+  
+   Aggregate function calls in SQL allow DISTINCT
+   and 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.
+  
+
+  
+   The aggregates we have been describing so far are normal
+   aggregates.  PostgreSQL also
+   supports 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 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 percentile_disc is equivalent to:
+
+
+CREATE AGGREGATE percentile_disc (float8 ORDER BY anyelement)
+(
+    sfunc = ordered_set_transition,
+    stype = internal,
+    finalfunc = percentile_disc_final
+);
+
+
+   which could be used to obtain a median household income like this:
+
+
+SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
+ percentile_disc
+-----------------
+           50489
+
+
+   Here, 0.5 is a direct argument; it would make no sense
+   for the percentile fraction to be a value varying across rows.
+  
+
+  
+   Unlike the case for normal aggregates, the sorting of input rows for
+   an ordered-set aggregate is 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 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 hypothetical rows into the data to be sorted.
+   While normal aggregates can often be implemented with support
+   functions written in PL/pgSQL 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 internal — this is typical.)
+  
+
+  
+   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 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 mode_final(internal, anyelement) returns
+   anyelement, with the anyelement parameter corresponding
+   to the dummy null argument that represents the aggregated column.
+   The actual data is conveyed in the internal-type state
+   value, but type resolution needs a parse-time indication of what the