diff options
Diffstat (limited to 'doc/src/sgml/xaggr.sgml')
-rw-r--r-- | doc/src/sgml/xaggr.sgml | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/doc/src/sgml/xaggr.sgml b/doc/src/sgml/xaggr.sgml new file mode 100644 index 0000000..bdad8d3 --- /dev/null +++ b/doc/src/sgml/xaggr.sgml @@ -0,0 +1,670 @@ +<!-- doc/src/sgml/xaggr.sgml --> + + <sect1 id="xaggr"> + <title>User-Defined Aggregates</title> + + <indexterm zone="xaggr"> + <primary>aggregate function</primary> + <secondary>user-defined</secondary> + </indexterm> + + <para> + 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 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. The final function takes the ending 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> + Thus, in addition to the argument and result data types seen by a user + of the aggregate, there is an internal state-value data type that + might be different from both the argument and result types. + </para> + + <para> + If we define an aggregate that does not use a final function, + we have an aggregate that computes a running function of + the column values from each row. <function>sum</function> is an + example of this kind of aggregate. <function>sum</function> starts at + zero and always adds the current row's value to + its running total. For example, if we want to make a <function>sum</function> + aggregate to work on a data type for complex numbers, + we only need the addition function for that data type. + The aggregate definition would be: + +<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) +</programlisting> + + (Notice that we are relying on function overloading: there is more than + one aggregate named <function>sum</function>, but + <productname>PostgreSQL</productname> can figure out which kind + of sum applies to a column of type <type>complex</type>.) + </para> + + <para> + 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 — 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 + 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</function> and <function>min</function>, + 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 state value is null and + the transition function is marked <quote>strict</quote> (i.e., not to be called + for null inputs). + </para> + + <para> + Another bit of default behavior for a <quote>strict</quote> transition function + is that the previous state value is retained unchanged whenever a + null input value is encountered. Thus, null values are ignored. If you + need some other behavior for null inputs, do not declare your + transition function as strict; instead code it to test for null inputs and + do whatever is needed. + </para> + + <para> + <function>avg</function> (average) is a more complex example of an aggregate. + It requires + two pieces of running state: the sum of the inputs and the count + of the number of inputs. The final result is obtained by dividing + these quantities. Average is typically implemented by using an + array as the state value. For example, + the built-in implementation of <function>avg(float8)</function> + looks like: + +<programlisting> +CREATE AGGREGATE avg (float8) +( + sfunc = float8_accum, + stype = float8[], + finalfunc = float8_avg, + initcond = '{0,0,0}' +); +</programlisting> + </para> + + <note> + <para> + <function>float8_accum</function> 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 as well as <function>avg</function>. + </para> + </note> + + <para> + Aggregate function calls in SQL allow <literal>DISTINCT</literal> + and <literal>ORDER BY</literal> 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> + For further details see the + <xref linkend="sql-createaggregate"/> + command. + </para> + + <sect2 id="xaggr-moving-aggregates"> + <title>Moving-Aggregate Mode</title> + + <indexterm> + <primary>moving-aggregate mode</primary> + </indexterm> + + <indexterm> + <primary>aggregate function</primary> + <secondary>moving aggregate</secondary> + </indexterm> + + <para> + Aggregate functions can optionally support <firstterm>moving-aggregate + mode</firstterm>, which allows substantially faster execution of aggregate + functions within windows with moving frame starting points. + (See <xref linkend="tutorial-window"/> + and <xref linkend="syntax-window-functions"/> for information about use of + aggregate functions as window functions.) + The basic idea is that in addition to a normal <quote>forward</quote> + transition function, the aggregate provides an <firstterm>inverse + transition function</firstterm>, which allows rows to be removed from the + aggregate's running state value when they exit the window frame. + For example a <function>sum</function> aggregate, which uses addition as the + forward transition function, would use subtraction as the inverse + transition function. Without an inverse transition function, the window + function mechanism must recalculate the aggregate from scratch each time + the frame starting point moves, resulting in run time proportional to the + number of input rows times the average frame length. With an inverse + transition function, the run time is only proportional to the number of + input rows. + </para> + + <para> + The inverse transition function is passed the current state value and the + aggregate input value(s) for the earliest row included in the current + state. It must reconstruct what the state value would have been if the + given input row had never been aggregated, but only the rows following + it. This sometimes requires that the forward transition function keep + more state than is needed for plain aggregation mode. Therefore, the + moving-aggregate mode uses a completely separate implementation from the + plain mode: it has its own state data type, its own forward transition + function, and its own final function if needed. These can be the same as + the plain mode's data type and functions, if there is no need for extra + state. + </para> + + <para> + As an example, we could extend the <function>sum</function> aggregate given above + to support moving-aggregate mode like this: + +<programlisting> +CREATE AGGREGATE sum (complex) +( + sfunc = complex_add, + stype = complex, + initcond = '(0,0)', + msfunc = complex_add, + minvfunc = complex_sub, + mstype = complex, + minitcond = '(0,0)' +); +</programlisting> + + The parameters whose names begin with <literal>m</literal> define the + moving-aggregate implementation. Except for the inverse transition + function <literal>minvfunc</literal>, they correspond to the plain-aggregate + parameters without <literal>m</literal>. + </para> + + <para> + The forward transition function for moving-aggregate mode is not allowed + to return null as the new state value. If the inverse transition + function returns null, this is taken as an indication that the inverse + function cannot reverse the state calculation for this particular input, + and so the aggregate calculation will be redone from scratch for the + current frame starting position. This convention allows moving-aggregate + mode to be used in situations where there are some infrequent cases that + are impractical to reverse out of the running state value. The inverse + transition function can <quote>punt</quote> on these cases, and yet still come + out ahead so long as it can work for most cases. As an example, an + aggregate working with floating-point numbers might choose to punt when + a <literal>NaN</literal> (not a number) input has to be removed from the running + state value. + </para> + + <para> + When writing moving-aggregate support functions, it is important to be + sure that the inverse transition function can reconstruct the correct + state value exactly. Otherwise there might be user-visible differences + in results depending on whether the moving-aggregate mode is used. + An example of an aggregate for which adding an inverse transition + function seems easy at first, yet where this requirement cannot be met + is <function>sum</function> over <type>float4</type> or <type>float8</type> inputs. A + naive declaration of <function>sum(<type>float8</type>)</function> could be + +<programlisting> +CREATE AGGREGATE unsafe_sum (float8) +( + stype = float8, + sfunc = float8pl, + mstype = float8, + msfunc = float8pl, + minvfunc = float8mi +); +</programlisting> + + This aggregate, however, can give wildly different results than it would + have without the inverse transition function. For example, consider + +<programlisting> +SELECT + unsafe_sum(x) OVER (ORDER BY n ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) +FROM (VALUES (1, 1.0e20::float8), + (2, 1.0::float8)) AS v (n,x); +</programlisting> + + This query returns <literal>0</literal> as its second result, rather than the + expected answer of <literal>1</literal>. The cause is the limited precision of + floating-point values: adding <literal>1</literal> to <literal>1e20</literal> results + in <literal>1e20</literal> again, and so subtracting <literal>1e20</literal> from that + yields <literal>0</literal>, not <literal>1</literal>. Note that this is a limitation + of floating-point arithmetic in general, not a limitation + of <productname>PostgreSQL</productname>. + </para> + + </sect2> + + <sect2 id="xaggr-polymorphic-aggregates"> + <title>Polymorphic and Variadic Aggregates</title> + + <indexterm> + <primary>aggregate function</primary> + <secondary>polymorphic</secondary> + </indexterm> + + <indexterm> + <primary>aggregate function</primary> + <secondary>variadic</secondary> + </indexterm> + + <para> + Aggregate functions can use polymorphic + state transition functions or final functions, so that the same functions + can be used to implement multiple aggregates. + See <xref linkend="extend-types-polymorphic"/> + for an explanation of polymorphic functions. + Going a step further, the aggregate function itself can be specified + with polymorphic input type(s) and state type, allowing a single + aggregate definition to serve for multiple input data types. + Here is an example of a polymorphic aggregate: + +<programlisting> +CREATE AGGREGATE array_accum (anycompatible) +( + sfunc = array_append, + stype = anycompatiblearray, + initcond = '{}' +); +</programlisting> + + 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</function> provides similar + functionality, with better performance than this definition would have.) + </para> + + <para> + Here's the output using two different actual data types as arguments: + +<programlisting> +SELECT attrelid::regclass, array_accum(attname) + FROM pg_attribute + WHERE attnum > 0 AND attrelid = 'pg_tablespace'::regclass + GROUP BY attrelid; + + attrelid | array_accum +---------------+--------------------------------------- + pg_tablespace | {spcname,spcowner,spcacl,spcoptions} +(1 row) + +SELECT attrelid::regclass, array_accum(atttypid::regtype) + FROM pg_attribute + WHERE attnum > 0 AND attrelid = 'pg_tablespace'::regclass + GROUP BY attrelid; + + attrelid | array_accum +---------------+--------------------------- + pg_tablespace | {name,oid,aclitem[],text[]} +(1 row) +</programlisting> + </para> + + <para> + Ordinarily, an aggregate function with a polymorphic result type has a + polymorphic state type, as in the above example. This is necessary + because otherwise the final function cannot be declared sensibly: it + would need to have a polymorphic result type but no polymorphic argument + type, which <command>CREATE FUNCTION</command> will reject on the grounds that + the result type cannot be deduced from a call. But sometimes it is + inconvenient to use a polymorphic state type. The most common case is + where the aggregate support functions are to be written in C and the + state type should be declared as <type>internal</type> because there is + no SQL-level equivalent for it. To address this case, it is possible to + declare the final function as taking extra <quote>dummy</quote> arguments + that match the input arguments of the aggregate. Such dummy arguments + are always passed as null values since no specific value is available when the + final function is called. Their only use is to allow a polymorphic + final function's result type to be connected to the aggregate's input + type(s). For example, the definition of the built-in + aggregate <function>array_agg</function> is equivalent to + +<programlisting> +CREATE FUNCTION array_agg_transfn(internal, anynonarray) + RETURNS internal ...; +CREATE FUNCTION array_agg_finalfn(internal, anynonarray) + RETURNS anyarray ...; + +CREATE AGGREGATE array_agg (anynonarray) +( + sfunc = array_agg_transfn, + stype = internal, + finalfunc = array_agg_finalfn, + finalfunc_extra +); +</programlisting> + + Here, the <literal>finalfunc_extra</literal> option specifies that the final + function receives, in addition to the state value, extra dummy + argument(s) corresponding to the aggregate's input argument(s). + The extra <type>anynonarray</type> argument allows the declaration + of <function>array_agg_finalfn</function> to be valid. + </para> + + <para> + An aggregate function can be made to accept a varying number of arguments + by declaring its last argument as a <literal>VARIADIC</literal> array, in much + the same fashion as for regular functions; see + <xref linkend="xfunc-sql-variadic-functions"/>. The aggregate's transition + function(s) must have the same array type as their last argument. The + transition function(s) typically would also be marked <literal>VARIADIC</literal>, + but this is not strictly required. + </para> + + <note> + <para> + Variadic aggregates are easily misused in connection with + the <literal>ORDER BY</literal> option (see <xref linkend="syntax-aggregates"/>), + since the parser cannot tell whether the wrong number of actual arguments + have been given in such a combination. Keep in mind that everything to + the right of <literal>ORDER BY</literal> is a sort key, not an argument to the + aggregate. For example, in +<programlisting> +SELECT myaggregate(a ORDER BY a, b, c) FROM ... +</programlisting> + the parser will see this as a single aggregate function argument and + three sort keys. However, the user might have intended +<programlisting> +SELECT myaggregate(a, b, c ORDER BY a) FROM ... +</programlisting> + If <literal>myaggregate</literal> is variadic, both these calls could be + perfectly valid. + </para> + + <para> + For the same reason, it's wise to think twice before creating aggregate + functions with the same names and different numbers of regular arguments. + </para> + </note> + + </sect2> + + <sect2 id="xaggr-ordered-set-aggregates"> + <title>Ordered-Set Aggregates</title> + + <indexterm> + <primary>aggregate function</primary> + <secondary>ordered set</secondary> + </indexterm> + + <para> + The aggregates we have been describing so far are <quote>normal</quote> + aggregates. <productname>PostgreSQL</productname> also + supports <firstterm>ordered-set aggregates</firstterm>, 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</quote> 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</function> is equivalent to: + +<programlisting> +CREATE FUNCTION ordered_set_transition(internal, anyelement) + RETURNS internal ...; +CREATE FUNCTION percentile_disc_final(internal, float8, anyelement) + RETURNS anyelement ...; + +CREATE AGGREGATE percentile_disc (float8 ORDER BY anyelement) +( + sfunc = ordered_set_transition, + stype = internal, + finalfunc = percentile_disc_final, + finalfunc_extra +); +</programlisting> + + This aggregate takes a <type>float8</type> direct argument (the percentile + fraction) and an aggregated input that can be of any sortable data type. + It 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</literal> 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</emphasis> 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</quote> 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</quote> 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 data type. + (In the above example, notice that the state value is declared as + type <type>internal</type> — this is typical.) + Also, because the final function performs the sort, it is not possible + to continue adding input rows by executing the transition function again + later. This means the final function is not <literal>READ_ONLY</literal>; + it must be declared in <link linkend="sql-createaggregate"><command>CREATE AGGREGATE</command></link> + as <literal>READ_WRITE</literal>, or as <literal>SHAREABLE</literal> if + it's possible for additional final-function calls to make use of the + already-sorted state. + </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 (if <literal>finalfunc_extra</literal> is specified) null values + corresponding to the aggregated input(s). As with normal + aggregates, <literal>finalfunc_extra</literal> is only really useful if the + aggregate is polymorphic; then the extra dummy argument(s) are needed + to connect the final function's result type to the aggregate's input + type(s). + </para> + + <para> + Currently, ordered-set aggregates cannot be used as window functions, + and therefore there is no need for them to support moving-aggregate mode. + </para> + + </sect2> + + <sect2 id="xaggr-partial-aggregates"> + <title>Partial Aggregation</title> + + <indexterm> + <primary>aggregate function</primary> + <secondary>partial aggregation</secondary> + </indexterm> + + <para> + Optionally, an aggregate function can support <firstterm>partial + aggregation</firstterm>. The idea of partial aggregation is to run the aggregate's + state transition function over different subsets of the input data + independently, and then to combine the state values resulting from those + subsets to produce the same state value that would have resulted from + scanning all the input in a single operation. This mode can be used for + parallel aggregation by having different worker processes scan different + portions of a table. Each worker produces a partial state value, and at + the end those state values are combined to produce a final state value. + (In the future this mode might also be used for purposes such as combining + aggregations over local and remote tables; but that is not implemented + yet.) + </para> + + <para> + To support partial aggregation, the aggregate definition must provide + a <firstterm>combine function</firstterm>, which takes two values of the + aggregate's state type (representing the results of aggregating over two + subsets of the input rows) and produces a new value of the state type, + representing what the state would have been after aggregating over the + combination of those sets of rows. It is unspecified what the relative + order of the input rows from the two sets would have been. This means + that it's usually impossible to define a useful combine function for + aggregates that are sensitive to input row order. + </para> + + <para> + As simple examples, <literal>MAX</literal> and <literal>MIN</literal> aggregates can be + made to support partial aggregation by specifying the combine function as + the same greater-of-two or lesser-of-two comparison function that is used + as their transition function. <literal>SUM</literal> aggregates just need an + addition function as combine function. (Again, this is the same as their + transition function, unless the state value is wider than the input data + type.) + </para> + + <para> + The combine function is treated much like a transition function that + happens to take a value of the state type, not of the underlying input + type, as its second argument. In particular, the rules for dealing + with null values and strict functions are similar. Also, if the aggregate + definition specifies a non-null <literal>initcond</literal>, keep in mind that + that will be used not only as the initial state for each partial + aggregation run, but also as the initial state for the combine function, + which will be called to combine each partial result into that state. + </para> + + <para> + If the aggregate's state type is declared as <type>internal</type>, it is + the combine function's responsibility that its result is allocated in + the correct memory context for aggregate state values. This means in + particular that when the first input is <literal>NULL</literal> it's invalid + to simply return the second input, as that value will be in the wrong + context and will not have sufficient lifespan. + </para> + + <para> + When the aggregate's state type is declared as <type>internal</type>, it is + usually also appropriate for the aggregate definition to provide a + <firstterm>serialization function</firstterm> and a <firstterm>deserialization + function</firstterm>, which allow such a state value to be copied from one process + to another. Without these functions, parallel aggregation cannot be + performed, and future applications such as local/remote aggregation will + probably not work either. + </para> + + <para> + A serialization function must take a single argument of + type <type>internal</type> and return a result of type <type>bytea</type>, which + represents the state value packaged up into a flat blob of bytes. + Conversely, a deserialization function reverses that conversion. It must + take two arguments of types <type>bytea</type> and <type>internal</type>, and + return a result of type <type>internal</type>. (The second argument is unused + and is always zero, but it is required for type-safety reasons.) The + result of the deserialization function should simply be allocated in the + current memory context, as unlike the combine function's result, it is not + long-lived. + </para> + + <para> + Worth noting also is that for an aggregate to be executed in parallel, + the aggregate itself must be marked <literal>PARALLEL SAFE</literal>. The + parallel-safety markings on its support functions are not consulted. + </para> + + </sect2> + + <sect2 id="xaggr-support-functions"> + <title>Support Functions for Aggregates</title> + + <indexterm> + <primary>aggregate function</primary> + <secondary>support functions for</secondary> + </indexterm> + + <para> + A function written in C can detect that it is being called as an + aggregate support function by calling + <function>AggCheckCallContext</function>, for example: +<programlisting> +if (AggCheckCallContext(fcinfo, NULL)) +</programlisting> + One reason for checking this is that when it is true, the first input + must be a temporary state value and can therefore safely be modified + in-place rather than allocating a new copy. + See <function>int8inc()</function> for an example. + (While aggregate transition functions are always allowed to modify + the transition value in-place, aggregate final functions are generally + discouraged from doing so; if they do so, the behavior must be declared + when creating the aggregate. See <xref linkend="sql-createaggregate"/> + for more detail.) + </para> + + <para> + The second argument of <function>AggCheckCallContext</function> can be used to + retrieve the memory context in which aggregate state values are being kept. + This is useful for transition functions that wish to use <quote>expanded</quote> + objects (see <xref linkend="xtypes-toast"/>) as their state values. + On first call, the transition function should return an expanded object + whose memory context is a child of the aggregate state context, and then + keep returning the same expanded object on subsequent calls. See + <function>array_append()</function> for an example. (<function>array_append()</function> + is not the transition function of any built-in aggregate, but it is written + to behave efficiently when used as transition function of a custom + aggregate.) + </para> + + <para> + Another support routine available to aggregate functions written in C + is <function>AggGetAggref</function>, which returns the <literal>Aggref</literal> + parse node that defines the aggregate call. This is mainly useful + for ordered-set aggregates, which can inspect the substructure of + the <literal>Aggref</literal> node to find out what sort ordering they are + supposed to implement. Examples can be found + in <filename>orderedsetaggs.c</filename> in the <productname>PostgreSQL</productname> + source code. + </para> + + </sect2> + + </sect1> |