Thread: [HACKERS] Aggregate transition state merging vs. hypothetical set functions
I started to look into fixing orderedsetaggs.c so that we could revert 52328727b, and soon found a rather nasty problem. Although the plain OSAs seem amenable to supporting multiple finalfn calls on the same transition state, the "hypothetical set" functions are not at all. What they do is to accumulate all the regular aggregate input into a tuplesort, then add the direct arguments as an additional "hypothetical" row, and finally sort the result. There's no realistic way of undoing the addition of the hypothetical row, so these finalfns simply can't share tuplesort state. You could imagine accumulating the regular input into a tuplestore and then copying it into a tuplesort in each finalfn call. But that seems pretty icky, and I'm not sure it'd really be any more performant than just keeping separate tuplesort objects for each aggregate. So my conclusion is that we *must* teach nodeAgg.c not to merge transition states for these functions. But I do not want some hard-wired rule that all and only hypothetical-set aggregates are nonmergeable. Our notion of an AGGKIND_HYPOTHETICAL aggregate is mostly a syntactical one about requiring there to be direct argument(s) matching the aggregated argument(s) in type. I do not think that that should translate to an assumption about how the aggregate implementation works (indeed, the CREATE AGGREGATE man page says in so many words that HYPOTHETICAL affects only type matching, not runtime behavior). Moreover, having seen this example, I think it's likely that there are other cases in which it's more trouble than it's worth for an aggregate to support merging of transition states. Therefore, I think we need to bite the bullet and provide an aggregate property (CREATE AGGREGATE argument / pg_aggregate column) that tells whether the aggregate supports transition state merging. Likely this should have been in the state-merging patch to begin with, but better late than never. The main thing that probably has to be hashed out before we can write that patch is what the default should be for user-created aggregates. I am inclined to think that we should err on the side of safety and default it to false (no merge support). You could argue that the lack of complaints since 9.6 came out is sufficient evidence that defaulting to true would be all right, but I'm not sure. Comments? regards, tom lane -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Aggregate transition state merging vs. hypothetical set functions
From
David Rowley
Date:
On 13 October 2017 at 12:08, Tom Lane <tgl@sss.pgh.pa.us> wrote: > Therefore, I think we need to bite the bullet and provide an aggregate > property (CREATE AGGREGATE argument / pg_aggregate column) that tells > whether the aggregate supports transition state merging. Likely this > should have been in the state-merging patch to begin with, but better > late than never. > > The main thing that probably has to be hashed out before we can write > that patch is what the default should be for user-created aggregates. > I am inclined to think that we should err on the side of safety and > default it to false (no merge support). You could argue that the > lack of complaints since 9.6 came out is sufficient evidence that > defaulting to true would be all right, but I'm not sure. Are you considering that this is an option only for ordered-set aggregates or for all? If the user defines their normal aggregate as not safe for merging, then surely it'll not be suitable to be used as a window function either, since the final function will also be called there multiple times per state. -- David Rowley http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training & Services -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
David Rowley <david.rowley@2ndquadrant.com> writes: > On 13 October 2017 at 12:08, Tom Lane <tgl@sss.pgh.pa.us> wrote: >> Therefore, I think we need to bite the bullet and provide an aggregate >> property (CREATE AGGREGATE argument / pg_aggregate column) that tells >> whether the aggregate supports transition state merging. Likely this >> should have been in the state-merging patch to begin with, but better >> late than never. > Are you considering that this is an option only for ordered-set > aggregates or for all? All. > If the user defines their normal aggregate as not safe for merging, > then surely it'll not be suitable to be used as a window function > either, since the final function will also be called there multiple > times per state. Yeah, we would probably also want to check the flag in nodeWindowAgg. Not sure exactly how that should play out --- maybe we end up with a tri-valued property "works as normal agg without merging, works as normal agg with merging, works as window agg". But this would arguably be an improvement over the current situation. Right now I'm sure there are user-written aggs out there that will just crash if used as a window agg, and the authors don't have much choice because the performance costs of not modifying the transition state in the finalfn are higher than they're willing to bear. At least with a flag they could ensure that the case will fail cleanly. regards, tom lane -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Aggregate transition state merging vs. hypothetical set functions
From
David Rowley
Date:
On 13 October 2017 at 12:41, Tom Lane <tgl@sss.pgh.pa.us> wrote: > David Rowley <david.rowley@2ndquadrant.com> writes: >> If the user defines their normal aggregate as not safe for merging, >> then surely it'll not be suitable to be used as a window function >> either, since the final function will also be called there multiple >> times per state. > > Yeah, we would probably also want to check the flag in nodeWindowAgg. > Not sure exactly how that should play out --- maybe we end up with > a tri-valued property "works as normal agg without merging, works > as normal agg with merging, works as window agg". But this would > arguably be an improvement over the current situation. Right now > I'm sure there are user-written aggs out there that will just crash > if used as a window agg, and the authors don't have much choice because > the performance costs of not modifying the transition state in the > finalfn are higher than they're willing to bear. At least with a > flag they could ensure that the case will fail cleanly. hmm, maybe I'm lacking imagination here, but surely the final function is either destructive or it's not? I can't understand what the difference between nodeAgg.c calling the finalfn multiple times on the same state and nodeWindowAgg.c doing it. Maybe there's something I'm not accounting for that you are? -- David Rowley http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training & Services -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
David Rowley <david.rowley@2ndquadrant.com> writes: > On 13 October 2017 at 12:41, Tom Lane <tgl@sss.pgh.pa.us> wrote: >> Yeah, we would probably also want to check the flag in nodeWindowAgg. >> Not sure exactly how that should play out --- maybe we end up with >> a tri-valued property "works as normal agg without merging, works >> as normal agg with merging, works as window agg". > hmm, maybe I'm lacking imagination here, but surely the final function > is either destructive or it's not? I can't understand what the > difference between nodeAgg.c calling the finalfn multiple times on the > same state and nodeWindowAgg.c doing it. Maybe there's something I'm > not accounting for that you are? nodeWindowAgg is doing something more: not only is it calling the finalfn repeatedly, but it's continuing to mutate the transition state in between. The ordered-set aggs provide a counterexample to considering that to be equivalent to state merging. The OSAs can cope with state merging as long as they have a flag to make sure only the first finalfn does tuplesort_performsort ... but that's not good enough to make them workable as window aggs. Once we sort, we can't absorb more rows into the tuplesort object. regards, tom lane -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Aggregate transition state merging vs. hypothetical set functions
From
Heikki Linnakangas
Date:
On 10/13/2017 02:41 AM, Tom Lane wrote: > David Rowley <david.rowley@2ndquadrant.com> writes: >> On 13 October 2017 at 12:08, Tom Lane <tgl@sss.pgh.pa.us> wrote: >>> Therefore, I think we need to bite the bullet and provide an aggregate >>> property (CREATE AGGREGATE argument / pg_aggregate column) that tells >>> whether the aggregate supports transition state merging. Likely this >>> should have been in the state-merging patch to begin with, but better >>> late than never. > >> Are you considering that this is an option only for ordered-set >> aggregates or for all? > > All. > >> If the user defines their normal aggregate as not safe for merging, >> then surely it'll not be suitable to be used as a window function >> either, since the final function will also be called there multiple >> times per state. > > Yeah, we would probably also want to check the flag in nodeWindowAgg. > Not sure exactly how that should play out --- maybe we end up with > a tri-valued property "works as normal agg without merging, works > as normal agg with merging, works as window agg". But this would > arguably be an improvement over the current situation. Right now > I'm sure there are user-written aggs out there that will just crash > if used as a window agg, and the authors don't have much choice because > the performance costs of not modifying the transition state in the > finalfn are higher than they're willing to bear. At least with a > flag they could ensure that the case will fail cleanly. Sounds right to me. I'm not so sure there really are aggregates out there that would crash today if used as a window aggregate, but it sure would be nice to give some control on that. We've been doing that window agg thing for a long time, so I think "works as window agg" should be the default for regular aggregates. For ordered-set aggregates, "no merging, no more transfn() calls after finalfn()" seems safest. It's a bit of a shame to have different defaults for regular and ordered-set aggregates. But that is what we implicitly assume today, anyway, and it's not too that hard to document. - Heikki -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Aggregate transition state merging vs. hypothetical set functions
From
Heikki Linnakangas
Date:
On 10/13/2017 02:08 AM, Tom Lane wrote: > I started to look into fixing orderedsetaggs.c so that we could revert > 52328727b, and soon found a rather nasty problem. Although the plain > OSAs seem amenable to supporting multiple finalfn calls on the same > transition state, the "hypothetical set" functions are not at all. > What they do is to accumulate all the regular aggregate input into > a tuplesort, then add the direct arguments as an additional "hypothetical" > row, and finally sort the result. There's no realistic way of undoing > the addition of the hypothetical row, so these finalfns simply can't > share tuplesort state. > > You could imagine accumulating the regular input into a tuplestore > and then copying it into a tuplesort in each finalfn call. But that > seems pretty icky, and I'm not sure it'd really be any more performant > than just keeping separate tuplesort objects for each aggregate. The current implementation, with the extra flag column, is quite naive. We could add some support to tuplesort to find a row with given attributes, and call that instead of actually adding the hypothetical row to the tuplesort and iterating to re-find it after performsort. For a result set that fits in memory, you could even do a binary search instead of linearly iterating through the result set. I'm not suggesting that we do that right now, though. And even if we did, there might be other aggregates out there that are not safe to merge, so we should still add the option to CREATE AGGREGATE. But that'd be nice little project, if someone wanted to make those functions faster. - Heikki -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Heikki Linnakangas <hlinnaka@iki.fi> writes: > On 10/13/2017 02:08 AM, Tom Lane wrote: >> I started to look into fixing orderedsetaggs.c so that we could revert >> 52328727b, and soon found a rather nasty problem. Although the plain >> OSAs seem amenable to supporting multiple finalfn calls on the same >> transition state, the "hypothetical set" functions are not at all. >> What they do is to accumulate all the regular aggregate input into >> a tuplesort, then add the direct arguments as an additional "hypothetical" >> row, and finally sort the result. There's no realistic way of undoing >> the addition of the hypothetical row, so these finalfns simply can't >> share tuplesort state. > The current implementation, with the extra flag column, is quite naive. > We could add some support to tuplesort to find a row with given > attributes, and call that instead of actually adding the hypothetical > row to the tuplesort and iterating to re-find it after performsort. For > a result set that fits in memory, you could even do a binary search > instead of linearly iterating through the result set. I'd had some idle thoughts about using a heap to support window aggregation of an OSA, rather than ever performing a full sort. It'd probably work well as long as the window doesn't get wide enough that the heap stops fitting in memory. But in any case, the immediate point is that we shouldn't just assume that every aggregate implementation is capable of supporting state merging, and while we're at it, it'd be better to have a non-syntax-based distinction between aggs that can support use as window functions and aggs that can't. Moving on to the exact color of the bikeshed: it seems like the right way to present this to users of CREATE AGGREGATE is in terms of "does the final function modify the transition state?". So maybe the values could be spelled SMODIFY = READ_ONLY ffunc never touches state, ok as window agg SMODIFY = SHARABLE ffunc does some one-time change like sorting, so state merging is OK but not windowagg SMODIFY = READ_WRITE ffunc trashes state, can't do merging either I'm not set on these names by any means; anyone have a better idea? Also, I'm not sure whether we'd need a separate MMODIFY flag for the moving-aggregate sub-implementation, but it seems possible. regards, tom lane -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Heikki Linnakangas <hlinnaka@iki.fi> writes: > We've been doing that window agg thing for a long time, so I think > "works as window agg" should be the default for regular aggregates. For > ordered-set aggregates, "no merging, no more transfn() calls after > finalfn()" seems safest. > It's a bit of a shame to have different defaults for regular and > ordered-set aggregates. But that is what we implicitly assume today, > anyway, and it's not too that hard to document. It's kind of a pain in the rear, really, especially for purposes like pg_dump, which will have to know the rule to decide whether it can omit an SMODIFY clause. (Which it should do if the value is default, so as not to make back-porting of dumps harder than necessary.) On reflection though I see little choice. Right now it's impossible to use an OSA as a window agg at all because the parser doesn't support that combination of options, and nodeWindowAgg is lacking necessary support too. If we ever get around to relaxing that, it would really be necessary that the default for user-created OSAs be "not safe as window agg", because almost certainly they wouldn't be. So I think there's no option but to have different default safety levels for OSA and normal aggs. As long as we're forced into that anyway, it does make sense to default to "not safe to merge" as well. We don't know for sure whether there are any user-created OSAs in the wild, but if there are, they likely borrowed code from orderedsetaggs.c. regards, tom lane -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
I wrote: > Moving on to the exact color of the bikeshed: it seems like the right > way to present this to users of CREATE AGGREGATE is in terms of "does > the final function modify the transition state?". So maybe the values > could be spelled > SMODIFY = READ_ONLY ffunc never touches state, ok as window agg > SMODIFY = SHARABLE ffunc does some one-time change like sorting, > so state merging is OK but not window agg > SMODIFY = READ_WRITE ffunc trashes state, can't do merging either > I'm not set on these names by any means; anyone have a better idea? After contemplating the existing CREATE AGGREGATE parameters, particularly [M]FINALFUNC_EXTRA, it seemed to me that better nomenclature is [M]FINALFUNC_MODIFY = READ_ONLY [M]FINALFUNC_MODIFY = STOP_UPDATES [M]FINALFUNC_MODIFY = READ_WRITE where "stop updates" is intended to imply "you can't call the transfn anymore after the first finalfn call". I'm still not that much in love with that terminology, but don't have a better idea now. Attached is a WIP patch; I believe it's code-complete but the SGML docs are lacking. Barring objections I'll finish up the docs and push this. regards, tom lane diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 9af77c1..cfec246 100644 *** a/doc/src/sgml/catalogs.sgml --- b/doc/src/sgml/catalogs.sgml *************** *** 487,492 **** --- 487,512 ---- <entry>True to pass extra dummy arguments to <structfield>aggmfinalfn</structfield></entry> </row> <row> + <entry><structfield>aggfinalmodify</structfield></entry> + <entry><type>char</type></entry> + <entry></entry> + <entry>Whether <structfield>aggfinalfn</structfield> modifies the + transition state value: + <literal>r</literal> if it is read-only, + <literal>s</literal> if the <structfield>aggtransfn</structfield> + cannot be applied after the <structfield>aggfinalfn</structfield>, or + <literal>w</literal> if it writes on the value + </entry> + </row> + <row> + <entry><structfield>aggmfinalmodify</structfield></entry> + <entry><type>char</type></entry> + <entry></entry> + <entry>Like <structfield>aggfinalmodify</structfield>, but for + the <structfield>aggmfinalfn</structfield> + </entry> + </row> + <row> <entry><structfield>aggsortop</structfield></entry> <entry><type>oid</type></entry> <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry> diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index a920450..ca3fd81 100644 *** a/src/backend/catalog/pg_aggregate.c --- b/src/backend/catalog/pg_aggregate.c *************** *** 19,24 **** --- 19,25 ---- #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_aggregate.h" + #include "catalog/pg_aggregate_fn.h" #include "catalog/pg_language.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" *************** AggregateCreate(const char *aggName, *** 65,70 **** --- 66,73 ---- List *aggmfinalfnName, bool finalfnExtraArgs, bool mfinalfnExtraArgs, + char finalfnModify, + char mfinalfnModify, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, *************** AggregateCreate(const char *aggName, *** 656,661 **** --- 659,666 ---- values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn); values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs); values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs); + values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify); + values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify); values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop); values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType); values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace); diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index a63539a..07ef4c5 100644 *** a/src/backend/commands/aggregatecmds.c --- b/src/backend/commands/aggregatecmds.c *************** *** 26,31 **** --- 26,32 ---- #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_aggregate.h" + #include "catalog/pg_aggregate_fn.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/alter.h" *************** *** 39,44 **** --- 40,48 ---- #include "utils/syscache.h" + static char extractModify(DefElem *defel); + + /* * DefineAggregate * *************** DefineAggregate(ParseState *pstate, List *** 67,72 **** --- 71,78 ---- List *mfinalfuncName = NIL; bool finalfuncExtraArgs = false; bool mfinalfuncExtraArgs = false; + char finalfuncModify = 0; + char mfinalfuncModify = 0; List *sortoperatorName = NIL; TypeName *baseType = NULL; TypeName *transType = NULL; *************** DefineAggregate(ParseState *pstate, List *** 143,148 **** --- 149,158 ---- finalfuncExtraArgs = defGetBoolean(defel); else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0) mfinalfuncExtraArgs = defGetBoolean(defel); + else if (pg_strcasecmp(defel->defname, "finalfunc_modify") == 0) + finalfuncModify = extractModify(defel); + else if (pg_strcasecmp(defel->defname, "mfinalfunc_modify") == 0) + mfinalfuncModify = extractModify(defel); else if (pg_strcasecmp(defel->defname, "sortop") == 0) sortoperatorName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "basetype") == 0) *************** DefineAggregate(ParseState *pstate, List *** 236,241 **** --- 246,260 ---- } /* + * Default values for modify flags can only be determined once we know the + * aggKind. + */ + if (finalfuncModify == 0) + finalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE; + if (mfinalfuncModify == 0) + mfinalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE; + + /* * look up the aggregate's input datatype(s). */ if (oldstyle) *************** DefineAggregate(ParseState *pstate, List *** 437,442 **** --- 456,463 ---- mfinalfuncName, /* final function name */ finalfuncExtraArgs, mfinalfuncExtraArgs, + finalfuncModify, + mfinalfuncModify, sortoperatorName, /* sort operator name */ transTypeId, /* transition data type */ transSpace, /* transition space */ *************** DefineAggregate(ParseState *pstate, List *** 446,448 **** --- 467,490 ---- minitval, /* initial condition */ proparallel); /* parallel safe? */ } + + /* + * Convert the string form of [m]finalfunc_modify to the catalog representation + */ + static char + extractModify(DefElem *defel) + { + char *val = defGetString(defel); + + if (strcmp(val, "read_only") == 0) + return AGGMODIFY_READ_ONLY; + if (strcmp(val, "stop_updates") == 0) + return AGGMODIFY_STOP_UPDATES; + if (strcmp(val, "read_write") == 0) + return AGGMODIFY_READ_WRITE; + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("parameter \"%s\" must be READ_ONLY, STOP_UPDATES, or READ_WRITE", + defel->defname))); + return 0; /* keep compiler quiet */ + } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 6543ece..36c6ecb 100644 *** a/src/backend/executor/nodeAgg.c --- b/src/backend/executor/nodeAgg.c *************** typedef struct AggStatePerTransData *** 248,256 **** /* * Link to an Aggref expr this state value is for. * ! * There can be multiple Aggref's sharing the same state value, as long as ! * the inputs and transition function are identical. This points to the ! * first one of them. */ Aggref *aggref; --- 248,256 ---- /* * Link to an Aggref expr this state value is for. * ! * There can be multiple Aggref's sharing the same state value, so long as ! * the inputs and transition functions are identical and the final ! * functions are not read-write. This points to the first one of them. */ Aggref *aggref; *************** typedef struct AggStatePerAggData *** 419,426 **** Oid finalfn_oid; /* ! * fmgr lookup data for final function --- only valid when finalfn_oid oid ! * is not InvalidOid. */ FmgrInfo finalfn; --- 419,426 ---- Oid finalfn_oid; /* ! * fmgr lookup data for final function --- only valid when finalfn_oid is ! * not InvalidOid. */ FmgrInfo finalfn; *************** typedef struct AggStatePerAggData *** 439,444 **** --- 439,449 ---- int16 resulttypeLen; bool resulttypeByVal; + /* + * "sharable" is false if this agg cannot share state values with other + * aggregates because the final function is read-write. + */ + bool sharable; } AggStatePerAggData; /* *************** static void build_pertrans_for_aggref(Ag *** 572,577 **** --- 577,583 ---- static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos); static int find_compatible_pertrans(AggState *aggstate, Aggref *newagg, + bool sharable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, *************** ExecInitAgg(Agg *node, EState *estate, i *** 3105,3110 **** --- 3111,3117 ---- AclResult aclresult; Oid transfn_oid, finalfn_oid; + bool sharable; Oid serialfn_oid, deserialfn_oid; Expr *finalfnexpr; *************** ExecInitAgg(Agg *node, EState *estate, i *** 3177,3182 **** --- 3184,3198 ---- else peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn; + /* + * If finalfn is marked read-write, we can't share transition states; + * but it is okay to share for AGGMODIFY_STOP_UPDATES aggs. Also, if + * we're not executing the finalfn here, we can share regardless. + */ + sharable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) || + (finalfn_oid == InvalidOid); + peragg->sharable = sharable; + serialfn_oid = InvalidOid; deserialfn_oid = InvalidOid; *************** ExecInitAgg(Agg *node, EState *estate, i *** 3315,3325 **** * 2. Build working state for invoking the transition function, or * look up previously initialized working state, if we can share it. * ! * find_compatible_peragg() already collected a list of per-Trans's ! * with the same inputs. Check if any of them have the same transition ! * function and initial value. */ existing_transno = find_compatible_pertrans(aggstate, aggref, transfn_oid, aggtranstype, serialfn_oid, deserialfn_oid, initValue, initValueIsNull, --- 3331,3342 ---- * 2. Build working state for invoking the transition function, or * look up previously initialized working state, if we can share it. * ! * find_compatible_peragg() already collected a list of sharable ! * per-Trans's with the same inputs. Check if any of them have the ! * same transition function and initial value. */ existing_transno = find_compatible_pertrans(aggstate, aggref, + sharable, transfn_oid, aggtranstype, serialfn_oid, deserialfn_oid, initValue, initValueIsNull, *************** GetAggInitVal(Datum textInitVal, Oid tra *** 3724,3733 **** * with this one, with the same input parameters. If no compatible aggregate * can be found, returns -1. * ! * As a side-effect, this also collects a list of existing per-Trans structs ! * with matching inputs. If no identical Aggref is found, the list is passed ! * later to find_compatible_pertrans, to see if we can at least reuse the ! * state value of another aggregate. */ static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, --- 3741,3750 ---- * with this one, with the same input parameters. If no compatible aggregate * can be found, returns -1. * ! * As a side-effect, this also collects a list of existing, sharable per-Trans ! * structs with matching inputs. If no identical Aggref is found, the list is ! * passed later to find_compatible_pertrans, to see if we can at least reuse ! * the state value of another aggregate. */ static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, *************** find_compatible_peragg(Aggref *newagg, A *** 3785,3795 **** } /* ! * Not identical, but it had the same inputs. Return it to the caller, ! * in case we can re-use its per-trans state. */ ! *same_input_transnos = lappend_int(*same_input_transnos, ! peragg->transno); } return -1; --- 3802,3816 ---- } /* ! * Not identical, but it had the same inputs. If the final function ! * permits sharing, return its transno to the caller, in case we can ! * re-use its per-trans state. (If there's already sharing going on, ! * we can report a transno more than once. find_compatible_pertrans ! * is cheap enough that it's not worth working hard to avoid that.) */ ! if (peragg->sharable) ! *same_input_transnos = lappend_int(*same_input_transnos, ! peragg->transno); } return -1; *************** find_compatible_peragg(Aggref *newagg, A *** 3804,3810 **** * verified to match.) */ static int ! find_compatible_pertrans(AggState *aggstate, Aggref *newagg, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, --- 3825,3831 ---- * verified to match.) */ static int ! find_compatible_pertrans(AggState *aggstate, Aggref *newagg, bool sharable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, *************** find_compatible_pertrans(AggState *aggst *** 3812,3825 **** { ListCell *lc; ! /* ! * For the moment, never try to share transition states between different ! * ordered-set aggregates. This is necessary because the finalfns of the ! * built-in OSAs (see orderedsetaggs.c) are destructive of their ! * transition states. We should fix them so we can allow this, but not ! * losing performance in the normal non-shared case will take some work. ! */ ! if (AGGKIND_IS_ORDERED_SET(newagg->aggkind)) return -1; foreach(lc, transnos) --- 3833,3840 ---- { ListCell *lc; ! /* If this aggregate can't share transition states, give up */ ! if (!sharable) return -1; foreach(lc, transnos) diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 80be460..35174fe 100644 *** a/src/backend/executor/nodeWindowAgg.c --- b/src/backend/executor/nodeWindowAgg.c *************** *** 49,54 **** --- 49,55 ---- #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" + #include "utils/regproc.h" #include "utils/syscache.h" #include "windowapi.h" *************** initialize_peragg(WindowAggState *winsta *** 2100,2105 **** --- 2101,2107 ---- invtransfn_oid, finalfn_oid; bool finalextra; + char finalmodify; Expr *transfnexpr, *invtransfnexpr, *finalfnexpr; *************** initialize_peragg(WindowAggState *winsta *** 2139,2144 **** --- 2141,2147 ---- peraggstate->invtransfn_oid = invtransfn_oid = aggform->aggminvtransfn; peraggstate->finalfn_oid = finalfn_oid = aggform->aggmfinalfn; finalextra = aggform->aggmfinalextra; + finalmodify = aggform->aggmfinalmodify; aggtranstype = aggform->aggmtranstype; initvalAttNo = Anum_pg_aggregate_aggminitval; } *************** initialize_peragg(WindowAggState *winsta *** 2148,2153 **** --- 2151,2157 ---- peraggstate->invtransfn_oid = invtransfn_oid = InvalidOid; peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn; finalextra = aggform->aggfinalextra; + finalmodify = aggform->aggfinalmodify; aggtranstype = aggform->aggtranstype; initvalAttNo = Anum_pg_aggregate_agginitval; } *************** initialize_peragg(WindowAggState *winsta *** 2198,2203 **** --- 2202,2218 ---- } } + /* + * If the selected finalfn isn't read-only, we can't run this aggregate as + * a window function. This is a user-facing error, so we take a bit more + * care with the error message than elsewhere in this function. + */ + if (finalmodify != AGGMODIFY_READ_ONLY) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("aggregate function %s does not support use as a window function", + format_procedure(wfunc->winfnoid)))); + /* Detect how many arguments to pass to the finalfn */ if (finalextra) peraggstate->numFinalArgs = numArguments + 1; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index e34c83a..898abd7 100644 *** a/src/bin/pg_dump/pg_dump.c --- b/src/bin/pg_dump/pg_dump.c *************** *** 42,47 **** --- 42,48 ---- #include "access/attnum.h" #include "access/sysattr.h" #include "access/transam.h" + #include "catalog/pg_aggregate.h" #include "catalog/pg_am.h" #include "catalog/pg_attribute.h" #include "catalog/pg_cast.h" *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13433,13440 **** int i_aggmfinalfn; int i_aggfinalextra; int i_aggmfinalextra; int i_aggsortop; ! int i_hypothetical; int i_aggtranstype; int i_aggtransspace; int i_aggmtranstype; --- 13434,13443 ---- int i_aggmfinalfn; int i_aggfinalextra; int i_aggmfinalextra; + int i_aggfinalmodify; + int i_aggmfinalmodify; int i_aggsortop; ! int i_aggkind; int i_aggtranstype; int i_aggtransspace; int i_aggmtranstype; *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13453,13461 **** const char *aggmfinalfn; bool aggfinalextra; bool aggmfinalextra; const char *aggsortop; char *aggsortconvop; ! bool hypothetical; const char *aggtranstype; const char *aggtransspace; const char *aggmtranstype; --- 13456,13466 ---- const char *aggmfinalfn; bool aggfinalextra; bool aggmfinalextra; + char aggfinalmodify; + char aggmfinalmodify; const char *aggsortop; char *aggsortconvop; ! char aggkind; const char *aggtranstype; const char *aggtransspace; const char *aggmtranstype; *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13464,13469 **** --- 13469,13475 ---- const char *aggminitval; bool convertok; const char *proparallel; + char defaultfinalmodify; /* Skip if not to be dumped */ if (!agginfo->aggfn.dobj.dump || dopt->dataOnly) *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13479,13493 **** selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name); /* Get aggregate-specific details */ ! if (fout->remoteVersion >= 90600) { appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, " "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, " "aggfinalextra, aggmfinalextra, " "aggsortop::pg_catalog.regoperator, " ! "(aggkind = 'h') AS hypothetical, " "aggtransspace, agginitval, " "aggmtransspace, aggminitval, " "true AS convertok, " --- 13485,13521 ---- selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name); /* Get aggregate-specific details */ ! if (fout->remoteVersion >= 110000) { appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, " "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, " "aggfinalextra, aggmfinalextra, " + "aggfinalmodify, aggmfinalmodify, " "aggsortop::pg_catalog.regoperator, " ! "aggkind, " ! "aggtransspace, agginitval, " ! "aggmtransspace, aggminitval, " ! "true AS convertok, " ! "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, " ! "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, " ! "p.proparallel " ! "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " ! "WHERE a.aggfnoid = p.oid " ! "AND p.oid = '%u'::pg_catalog.oid", ! agginfo->aggfn.dobj.catId.oid); ! } ! else if (fout->remoteVersion >= 90600) ! { ! appendPQExpBuffer(query, "SELECT aggtransfn, " ! "aggfinalfn, aggtranstype::pg_catalog.regtype, " ! "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, " ! "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, " ! "aggfinalextra, aggmfinalextra, " ! "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, " ! "aggsortop::pg_catalog.regoperator, " ! "aggkind, " "aggtransspace, agginitval, " "aggmtransspace, aggminitval, " "true AS convertok, " *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13507,13514 **** "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, " "aggmfinalfn, aggmtranstype::pg_catalog.regtype, " "aggfinalextra, aggmfinalextra, " "aggsortop::pg_catalog.regoperator, " ! "(aggkind = 'h') AS hypothetical, " "aggtransspace, agginitval, " "aggmtransspace, aggminitval, " "true AS convertok, " --- 13535,13543 ---- "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, " "aggmfinalfn, aggmtranstype::pg_catalog.regtype, " "aggfinalextra, aggmfinalextra, " + "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, " "aggsortop::pg_catalog.regoperator, " ! "aggkind, " "aggtransspace, agginitval, " "aggmtransspace, aggminitval, " "true AS convertok, " *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13528,13535 **** "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " "0 AS aggmtranstype, false AS aggfinalextra, " "false AS aggmfinalextra, " "aggsortop::pg_catalog.regoperator, " ! "false AS hypothetical, " "0 AS aggtransspace, agginitval, " "0 AS aggmtransspace, NULL AS aggminitval, " "true AS convertok, " --- 13557,13565 ---- "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " "0 AS aggmtranstype, false AS aggfinalextra, " "false AS aggmfinalextra, " + "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, " "aggsortop::pg_catalog.regoperator, " ! "'n' AS aggkind, " "0 AS aggtransspace, agginitval, " "0 AS aggmtransspace, NULL AS aggminitval, " "true AS convertok, " *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13549,13556 **** "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " "0 AS aggmtranstype, false AS aggfinalextra, " "false AS aggmfinalextra, " "aggsortop::pg_catalog.regoperator, " ! "false AS hypothetical, " "0 AS aggtransspace, agginitval, " "0 AS aggmtransspace, NULL AS aggminitval, " "true AS convertok " --- 13579,13587 ---- "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " "0 AS aggmtranstype, false AS aggfinalextra, " "false AS aggmfinalextra, " + "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, " "aggsortop::pg_catalog.regoperator, " ! "'n' AS aggkind, " "0 AS aggtransspace, agginitval, " "0 AS aggmtransspace, NULL AS aggminitval, " "true AS convertok " *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13567,13574 **** "'-' AS aggdeserialfn, '-' AS aggmtransfn, " "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " "0 AS aggmtranstype, false AS aggfinalextra, " ! "false AS aggmfinalextra, 0 AS aggsortop, " ! "false AS hypothetical, " "0 AS aggtransspace, agginitval, " "0 AS aggmtransspace, NULL AS aggminitval, " "true AS convertok " --- 13598,13607 ---- "'-' AS aggdeserialfn, '-' AS aggmtransfn, " "'-' AS aggminvtransfn, '-' AS aggmfinalfn, " "0 AS aggmtranstype, false AS aggfinalextra, " ! "false AS aggmfinalextra, " ! "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, " ! "0 AS aggsortop, " ! "'n' AS aggkind, " "0 AS aggtransspace, agginitval, " "0 AS aggmtransspace, NULL AS aggminitval, " "true AS convertok " *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13590,13597 **** i_aggmfinalfn = PQfnumber(res, "aggmfinalfn"); i_aggfinalextra = PQfnumber(res, "aggfinalextra"); i_aggmfinalextra = PQfnumber(res, "aggmfinalextra"); i_aggsortop = PQfnumber(res, "aggsortop"); ! i_hypothetical = PQfnumber(res, "hypothetical"); i_aggtranstype = PQfnumber(res, "aggtranstype"); i_aggtransspace = PQfnumber(res, "aggtransspace"); i_aggmtranstype = PQfnumber(res, "aggmtranstype"); --- 13623,13632 ---- i_aggmfinalfn = PQfnumber(res, "aggmfinalfn"); i_aggfinalextra = PQfnumber(res, "aggfinalextra"); i_aggmfinalextra = PQfnumber(res, "aggmfinalextra"); + i_aggfinalmodify = PQfnumber(res, "aggfinalmodify"); + i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify"); i_aggsortop = PQfnumber(res, "aggsortop"); ! i_aggkind = PQfnumber(res, "aggkind"); i_aggtranstype = PQfnumber(res, "aggtranstype"); i_aggtransspace = PQfnumber(res, "aggtransspace"); i_aggmtranstype = PQfnumber(res, "aggmtranstype"); *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13611,13618 **** aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn); aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't'); aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't'); aggsortop = PQgetvalue(res, 0, i_aggsortop); ! hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't'); aggtranstype = PQgetvalue(res, 0, i_aggtranstype); aggtransspace = PQgetvalue(res, 0, i_aggtransspace); aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype); --- 13646,13655 ---- aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn); aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't'); aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't'); + aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0]; + aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0]; aggsortop = PQgetvalue(res, 0, i_aggsortop); ! aggkind = PQgetvalue(res, 0, i_aggkind)[0]; aggtranstype = PQgetvalue(res, 0, i_aggtranstype); aggtransspace = PQgetvalue(res, 0, i_aggtransspace); aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype); *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13656,13661 **** --- 13693,13706 ---- return; } + /* identify default modify flag for aggkind (must match DefineAggregate) */ + defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE; + /* replace omitted flags for old versions */ + if (aggfinalmodify == '0') + aggfinalmodify = defaultfinalmodify; + if (aggmfinalmodify == '0') + aggmfinalmodify = defaultfinalmodify; + /* regproc and regtype output is already sufficiently quoted */ appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s", aggtransfn, aggtranstype); *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13678,13683 **** --- 13723,13747 ---- aggfinalfn); if (aggfinalextra) appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA"); + if (aggfinalmodify != defaultfinalmodify) + { + switch (aggfinalmodify) + { + case AGGMODIFY_READ_ONLY: + appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY"); + break; + case AGGMODIFY_STOP_UPDATES: + appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = STOP_UPDATES"); + break; + case AGGMODIFY_READ_WRITE: + appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE"); + break; + default: + exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n", + agginfo->aggfn.dobj.name); + break; + } + } } if (strcmp(aggcombinefn, "-") != 0) *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13715,13720 **** --- 13779,13803 ---- aggmfinalfn); if (aggmfinalextra) appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA"); + if (aggmfinalmodify != defaultfinalmodify) + { + switch (aggmfinalmodify) + { + case AGGMODIFY_READ_ONLY: + appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY"); + break; + case AGGMODIFY_STOP_UPDATES: + appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = STOP_UPDATES"); + break; + case AGGMODIFY_READ_WRITE: + appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE"); + break; + default: + exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n", + agginfo->aggfn.dobj.name); + break; + } + } } aggsortconvop = convertOperatorReference(fout, aggsortop); *************** dumpAgg(Archive *fout, AggInfo *agginfo) *** 13725,13731 **** free(aggsortconvop); } ! if (hypothetical) appendPQExpBufferStr(details, ",\n HYPOTHETICAL"); if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE) --- 13808,13814 ---- free(aggsortconvop); } ! if (aggkind == AGGKIND_HYPOTHETICAL) appendPQExpBufferStr(details, ",\n HYPOTHETICAL"); if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE) diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index c492fbd..df87fb5 100644 *** a/src/bin/pg_dump/t/002_pg_dump.pl --- b/src/bin/pg_dump/t/002_pg_dump.pl *************** qr/CREATE CAST \(timestamp with time zon *** 2784,2789 **** --- 2784,2790 ---- basetype = int4, stype = _int8, finalfunc = int8_avg, + finalfunc_modify = stop_updates, initcond1 = \'{0,0}\' );', regexp => qr/^ *************** qr/CREATE CAST \(timestamp with time zon *** 2791,2797 **** \n\s+\QSFUNC = int4_avg_accum,\E \n\s+\QSTYPE = bigint[],\E \n\s+\QINITCOND = '{0,0}',\E ! \n\s+\QFINALFUNC = int8_avg\E \n\);/xm, like => { binary_upgrade => 1, --- 2792,2799 ---- \n\s+\QSFUNC = int4_avg_accum,\E \n\s+\QSTYPE = bigint[],\E \n\s+\QINITCOND = '{0,0}',\E ! \n\s+\QFINALFUNC = int8_avg,\E ! \n\s+\QFINALFUNC_MODIFY = STOP_UPDATES\E \n\);/xm, like => { binary_upgrade => 1, diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 4d5b9bb..5fd68d3 100644 *** a/src/include/catalog/pg_aggregate.h --- b/src/include/catalog/pg_aggregate.h *************** *** 20,27 **** #define PG_AGGREGATE_H #include "catalog/genbki.h" - #include "catalog/objectaddress.h" - #include "nodes/pg_list.h" /* ---------------------------------------------------------------- * pg_aggregate definition. --- 20,25 ---- *************** *** 41,46 **** --- 39,46 ---- * aggmfinalfn final function for moving-aggregate mode (0 if none) * aggfinalextra true to pass extra dummy arguments to aggfinalfn * aggmfinalextra true to pass extra dummy arguments to aggmfinalfn + * aggfinalmodify tells whether aggfinalfn modifies transition state + * aggmfinalmodify tells whether aggmfinalfn modifies transition state * aggsortop associated sort operator (0 if none) * aggtranstype type of aggregate's transition (state) data * aggtransspace estimated size of state data (0 for default estimate) *************** CATALOG(pg_aggregate,2600) BKI_WITHOUT_O *** 67,72 **** --- 67,74 ---- regproc aggmfinalfn; bool aggfinalextra; bool aggmfinalextra; + char aggfinalmodify; + char aggmfinalmodify; Oid aggsortop; Oid aggtranstype; int32 aggtransspace; *************** typedef FormData_pg_aggregate *Form_pg_a *** 91,97 **** * ---------------- */ ! #define Natts_pg_aggregate 20 #define Anum_pg_aggregate_aggfnoid 1 #define Anum_pg_aggregate_aggkind 2 #define Anum_pg_aggregate_aggnumdirectargs 3 --- 93,99 ---- * ---------------- */ ! #define Natts_pg_aggregate 22 #define Anum_pg_aggregate_aggfnoid 1 #define Anum_pg_aggregate_aggkind 2 #define Anum_pg_aggregate_aggnumdirectargs 3 *************** typedef FormData_pg_aggregate *Form_pg_a *** 105,117 **** #define Anum_pg_aggregate_aggmfinalfn 11 #define Anum_pg_aggregate_aggfinalextra 12 #define Anum_pg_aggregate_aggmfinalextra 13 ! #define Anum_pg_aggregate_aggsortop 14 ! #define Anum_pg_aggregate_aggtranstype 15 ! #define Anum_pg_aggregate_aggtransspace 16 ! #define Anum_pg_aggregate_aggmtranstype 17 ! #define Anum_pg_aggregate_aggmtransspace 18 ! #define Anum_pg_aggregate_agginitval 19 ! #define Anum_pg_aggregate_aggminitval 20 /* * Symbolic values for aggkind column. We distinguish normal aggregates --- 107,121 ---- #define Anum_pg_aggregate_aggmfinalfn 11 #define Anum_pg_aggregate_aggfinalextra 12 #define Anum_pg_aggregate_aggmfinalextra 13 ! #define Anum_pg_aggregate_aggfinalmodify 14 ! #define Anum_pg_aggregate_aggmfinalmodify 15 ! #define Anum_pg_aggregate_aggsortop 16 ! #define Anum_pg_aggregate_aggtranstype 17 ! #define Anum_pg_aggregate_aggtransspace 18 ! #define Anum_pg_aggregate_aggmtranstype 19 ! #define Anum_pg_aggregate_aggmtransspace 20 ! #define Anum_pg_aggregate_agginitval 21 ! #define Anum_pg_aggregate_aggminitval 22 /* * Symbolic values for aggkind column. We distinguish normal aggregates *************** typedef FormData_pg_aggregate *Form_pg_a *** 128,133 **** --- 132,149 ---- /* Use this macro to test for "ordered-set agg including hypothetical case" */ #define AGGKIND_IS_ORDERED_SET(kind) ((kind) != AGGKIND_NORMAL) + /* + * Symbolic values for aggfinalmodify and aggmfinalmodify columns. + * Preferably, finalfns do not modify the transition state value at all, + * but in some cases that would cost too much performance. We distinguish + * "pure read only" and "trashes it arbitrarily" cases, as well as the + * intermediate case where the finalfn can be applied multiple times but + * the transfn cannot be applied anymore after the first finalfn call. + */ + #define AGGMODIFY_READ_ONLY 'r' + #define AGGMODIFY_STOP_UPDATES 's' + #define AGGMODIFY_READ_WRITE 'w' + /* ---------------- * initial contents of pg_aggregate *************** typedef FormData_pg_aggregate *Form_pg_a *** 135,351 **** */ /* avg */ ! DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_combine int8_avg_serialize int8_avg_deserialize int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f 0 2281 48 2281 48 _null__null_ )); ! DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_combine - - int4_avg_accum int4_avg_accum_inv int8_avg f f 0 1016 0 1016 0 "{0,0}""{0,0}" )); ! DATA(insert ( 2102 n 0 int2_avg_accum int8_avg int4_avg_combine - - int2_avg_accum int2_avg_accum_inv int8_avg f f 0 1016 0 1016 0 "{0,0}""{0,0}" )); ! DATA(insert ( 2103 n 0 numeric_avg_accum numeric_avg numeric_avg_combine numeric_avg_serialize numeric_avg_deserializenumeric_avg_accum numeric_accum_inv numeric_avg f f 0 2281 128 2281 128 _null__null_ )); ! DATA(insert ( 2104 n 0 float4_accum float8_avg float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}"_null_ )); ! DATA(insert ( 2105 n 0 float8_accum float8_avg float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}"_null_ )); ! DATA(insert ( 2106 n 0 interval_accum interval_avg interval_combine - - interval_accum interval_accum_inv interval_avg f f 0 1187 0 1187 0 "{0 second,0second}" "{0 second,0 second}" )); /* sum */ ! DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_combine int8_avg_serialize int8_avg_deserialize int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f 0 2281 48 2281 48 _null__null_ )); ! DATA(insert ( 2108 n 0 int4_sum - int8pl - - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_"{0,0}" )); ! DATA(insert ( 2109 n 0 int2_sum - int8pl - - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_"{0,0}" )); ! DATA(insert ( 2110 n 0 float4pl - float4pl - - - - - f f 0 700 0 0 0 _null__null_ )); ! DATA(insert ( 2111 n 0 float8pl - float8pl - - - - - f f 0 701 0 0 0 _null__null_ )); ! DATA(insert ( 2112 n 0 cash_pl - cash_pl - - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ )); ! DATA(insert ( 2113 n 0 interval_pl - interval_pl - - interval_pl interval_mi - f f 0 1186 0 1186 0 _null_ _null_ )); ! DATA(insert ( 2114 n 0 numeric_avg_accum numeric_sum numeric_avg_combine numeric_avg_serialize numeric_avg_deserializenumeric_avg_accum numeric_accum_inv numeric_sum f f 0 2281 128 2281 128 _null__null_ )); /* max */ ! DATA(insert ( 2115 n 0 int8larger - int8larger - - - - - f f 413 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2116 n 0 int4larger - int4larger - - - - - f f 521 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2117 n 0 int2larger - int2larger - - - - - f f 520 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2118 n 0 oidlarger - oidlarger - - - - - f f 610 26 0 0 0 _null_ _null_ )); ! DATA(insert ( 2119 n 0 float4larger - float4larger - - - - - f f 623 700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2120 n 0 float8larger - float8larger - - - - - f f 674 701 0 0 0 _null_ _null_ )); ! DATA(insert ( 2121 n 0 int4larger - int4larger - - - - - f f 563 702 0 0 0 _null_ _null_ )); ! DATA(insert ( 2122 n 0 date_larger - date_larger - - - - - f f 1097 1082 0 0 0 _null_ _null_ )); ! DATA(insert ( 2123 n 0 time_larger - time_larger - - - - - f f 1112 1083 0 0 0 _null_ _null_ )); ! DATA(insert ( 2124 n 0 timetz_larger - timetz_larger - - - - - f f 1554 1266 0 0 0 _null_ _null_ )); ! DATA(insert ( 2125 n 0 cashlarger - cashlarger - - - - - f f 903 790 0 0 0 _null_ _null_ )); ! DATA(insert ( 2126 n 0 timestamp_larger - timestamp_larger - - - - - f f 2064 1114 0 0 0 _null_ _null_ )); ! DATA(insert ( 2127 n 0 timestamptz_larger - timestamptz_larger - - - - - f f 1324 1184 0 0 0 _null_ _null_ )); ! DATA(insert ( 2128 n 0 interval_larger - interval_larger - - - - - f f 1334 1186 0 0 0 _null_ _null_ )); ! DATA(insert ( 2129 n 0 text_larger - text_larger - - - - - f f 666 25 0 0 0 _null_ _null_ )); ! DATA(insert ( 2130 n 0 numeric_larger - numeric_larger - - - - - f f 1756 1700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2050 n 0 array_larger - array_larger - - - - - f f 1073 2277 0 0 0 _null_ _null_ )); ! DATA(insert ( 2244 n 0 bpchar_larger - bpchar_larger - - - - - f f 1060 1042 0 0 0 _null_ _null_ )); ! DATA(insert ( 2797 n 0 tidlarger - tidlarger - - - - - f f 2800 27 0 0 0 _null_ _null_ )); ! DATA(insert ( 3526 n 0 enum_larger - enum_larger - - - - - f f 3519 3500 0 0 0 _null_ _null_ )); ! DATA(insert ( 3564 n 0 network_larger - network_larger - - - - - f f 1205 869 0 0 0 _null_ _null_ )); /* min */ ! DATA(insert ( 2131 n 0 int8smaller - int8smaller - - - - - f f 412 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2132 n 0 int4smaller - int4smaller - - - - - f f 97 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2133 n 0 int2smaller - int2smaller - - - - - f f 95 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2134 n 0 oidsmaller - oidsmaller - - - - - f f 609 26 0 0 0 _null_ _null_ )); ! DATA(insert ( 2135 n 0 float4smaller - float4smaller - - - - - f f 622 700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2136 n 0 float8smaller - float8smaller - - - - - f f 672 701 0 0 0 _null_ _null_ )); ! DATA(insert ( 2137 n 0 int4smaller - int4smaller - - - - - f f 562 702 0 0 0 _null_ _null_ )); ! DATA(insert ( 2138 n 0 date_smaller - date_smaller - - - - - f f 1095 1082 0 0 0 _null_ _null_ )); ! DATA(insert ( 2139 n 0 time_smaller - time_smaller - - - - - f f 1110 1083 0 0 0 _null_ _null_ )); ! DATA(insert ( 2140 n 0 timetz_smaller - timetz_smaller - - - - - f f 1552 1266 0 0 0 _null_ _null_ )); ! DATA(insert ( 2141 n 0 cashsmaller - cashsmaller - - - - - f f 902 790 0 0 0 _null_ _null_ )); ! DATA(insert ( 2142 n 0 timestamp_smaller - timestamp_smaller - - - - - f f 2062 1114 0 0 0 _null_ _null_ )); ! DATA(insert ( 2143 n 0 timestamptz_smaller - timestamptz_smaller - - - - - f f 1322 1184 0 0 0 _null_ _null_ )); ! DATA(insert ( 2144 n 0 interval_smaller - interval_smaller - - - - - f f 1332 1186 0 0 0 _null_ _null_ )); ! DATA(insert ( 2145 n 0 text_smaller - text_smaller - - - - - f f 664 25 0 0 0 _null_ _null_ )); ! DATA(insert ( 2146 n 0 numeric_smaller - numeric_smaller - - - - - f f 1754 1700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2051 n 0 array_smaller - array_smaller - - - - - f f 1072 2277 0 0 0 _null_ _null_ )); ! DATA(insert ( 2245 n 0 bpchar_smaller - bpchar_smaller - - - - - f f 1058 1042 0 0 0 _null_ _null_ )); ! DATA(insert ( 2798 n 0 tidsmaller - tidsmaller - - - - - f f 2799 27 0 0 0 _null_ _null_ )); ! DATA(insert ( 3527 n 0 enum_smaller - enum_smaller - - - - - f f 3518 3500 0 0 0 _null_ _null_ )); ! DATA(insert ( 3565 n 0 network_smaller - network_smaller - - - - - f f 1203 869 0 0 0 _null_ _null_ )); /* count */ ! DATA(insert ( 2147 n 0 int8inc_any - int8pl - - int8inc_any int8dec_any - f f 0 20 0 20 0 "0" "0" )); ! DATA(insert ( 2803 n 0 int8inc - int8pl - - int8inc int8dec - f f 0 20 0 20 0 "0" "0" )); /* var_pop */ ! DATA(insert ( 2718 n 0 int8_accum numeric_var_pop numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2721 n 0 float4_accum float8_var_pop float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2722 n 0 float8_accum float8_var_pop float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2723 n 0 numeric_accum numeric_var_pop numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ )); /* var_samp */ ! DATA(insert ( 2641 n 0 int8_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2644 n 0 float4_accum float8_var_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2645 n 0 float8_accum float8_var_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2646 n 0 numeric_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_var_samp f f 0 2281 128 2281 128_null_ _null_ )); /* variance: historical Postgres syntax for var_samp */ ! DATA(insert ( 2148 n 0 int8_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2151 n 0 float4_accum float8_var_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2152 n 0 float8_accum float8_var_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2153 n 0 numeric_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_var_samp f f 0 2281 128 2281 128_null_ _null_ )); /* stddev_pop */ ! DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2729 n 0 numeric_accum numeric_stddev_pop numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128_null_ _null_ )); /* stddev_samp */ ! DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_stddev_samp f f0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2717 n 0 numeric_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ )); /* stddev: historical Postgres syntax for stddev_samp */ ! DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_stddev_samp f f0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_stddev_samp f f0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp float8_combine - - - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2159 n 0 numeric_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_stddev_samp f f0 2281 128 2281 128 _null_ _null_ )); /* SQL2003 binary regression aggregates */ ! DATA(insert ( 2818 n 0 int8inc_float8_float8 - int8pl - - - - - f f 0 20 0 0 0 "0" _null_ )); ! DATA(insert ( 2819 n 0 float8_regr_accum float8_regr_sxx float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2820 n 0 float8_regr_accum float8_regr_syy float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2821 n 0 float8_regr_accum float8_regr_sxy float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2822 n 0 float8_regr_accum float8_regr_avgx float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2823 n 0 float8_regr_accum float8_regr_avgy float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2824 n 0 float8_regr_accum float8_regr_r2 float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2825 n 0 float8_regr_accum float8_regr_slope float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2826 n 0 float8_regr_accum float8_regr_intercept float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2827 n 0 float8_regr_accum float8_covar_pop float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2829 n 0 float8_regr_accum float8_corr float8_regr_combine - - - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); /* boolean-and and boolean-or */ ! DATA(insert ( 2517 n 0 booland_statefunc - booland_statefunc - - bool_accum bool_accum_inv bool_alltrue f f 58 16 0 2281 16 _null_ _null_ )); ! DATA(insert ( 2518 n 0 boolor_statefunc - boolor_statefunc - - bool_accum bool_accum_inv bool_anytrue f f 59 16 0 2281 16 _null_ _null_ )); ! DATA(insert ( 2519 n 0 booland_statefunc - booland_statefunc - - bool_accum bool_accum_inv bool_alltrue f f 58 16 0 2281 16 _null_ _null_ )); /* bitwise integer */ ! DATA(insert ( 2236 n 0 int2and - int2and - - - - - f f 0 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2237 n 0 int2or - int2or - - - - - f f 0 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2238 n 0 int4and - int4and - - - - - f f 0 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2239 n 0 int4or - int4or - - - - - f f 0 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2240 n 0 int8and - int8and - - - - - f f 0 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2241 n 0 int8or - int8or - - - - - f f 0 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2242 n 0 bitand - bitand - - - - - f f 0 1560 0 0 0 _null_ _null_ )); ! DATA(insert ( 2243 n 0 bitor - bitor - - - - - f f 0 1560 0 0 0 _null_ _null_ )); /* xml */ ! DATA(insert ( 2901 n 0 xmlconcat2 - - - - - - - f f 0 142 0 0 0 _null_ _null_ )); /* array */ ! DATA(insert ( 2335 n 0 array_agg_transfn array_agg_finalfn - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 4053 n 0 array_agg_array_transfn array_agg_array_finalfn - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); /* text */ ! DATA(insert ( 3538 n 0 string_agg_transfn string_agg_finalfn - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); /* bytea */ ! DATA(insert ( 3545 n 0 bytea_string_agg_transfn bytea_string_agg_finalfn - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); /* json */ ! DATA(insert ( 3175 n 0 json_agg_transfn json_agg_finalfn - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3197 n 0 json_object_agg_transfn json_object_agg_finalfn - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); /* jsonb */ ! DATA(insert ( 3267 n 0 jsonb_agg_transfn jsonb_agg_finalfn - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3270 n 0 jsonb_object_agg_transfn jsonb_object_agg_finalfn - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); /* ordered-set and hypothetical-set aggregates */ ! DATA(insert ( 3972 o 1 ordered_set_transition percentile_disc_final - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3974 o 1 ordered_set_transition percentile_cont_float8_final - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3976 o 1 ordered_set_transition percentile_cont_interval_final - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3978 o 1 ordered_set_transition percentile_disc_multi_final - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3980 o 1 ordered_set_transition percentile_cont_float8_multi_final - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3982 o 1 ordered_set_transition percentile_cont_interval_multi_final - - - - - - f f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3984 o 0 ordered_set_transition mode_final - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3986 h 1 ordered_set_transition_multi rank_final - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3988 h 1 ordered_set_transition_multi percent_rank_final - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3990 h 1 ordered_set_transition_multi cume_dist_final - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3992 h 1 ordered_set_transition_multi dense_rank_final - - - - - - t f 0 2281 0 0 0 _null_ _null_ )); ! ! ! /* ! * prototypes for functions in pg_aggregate.c ! */ ! extern ObjectAddress 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 *aggcombinefnName, ! List *aggserialfnName, ! List *aggdeserialfnName, ! List *aggmtransfnName, ! List *aggminvtransfnName, ! List *aggmfinalfnName, ! bool finalfnExtraArgs, ! bool mfinalfnExtraArgs, ! List *aggsortopName, ! Oid aggTransType, ! int32 aggTransSpace, ! Oid aggmTransType, ! int32 aggmTransSpace, ! const char *agginitval, ! const char *aggminitval, ! char proparallel); #endif /* PG_AGGREGATE_H */ --- 151,333 ---- */ /* avg */ ! DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_combine int8_avg_serialize int8_avg_deserialize int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_combine - - int4_avg_accum int4_avg_accum_inv int8_avg f f r r 0 1016 0 1016 0 "{0,0}""{0,0}" )); ! DATA(insert ( 2102 n 0 int2_avg_accum int8_avg int4_avg_combine - - int2_avg_accum int2_avg_accum_inv int8_avg f f r r 0 1016 0 1016 0 "{0,0}""{0,0}" )); ! DATA(insert ( 2103 n 0 numeric_avg_accum numeric_avg numeric_avg_combine numeric_avg_serialize numeric_avg_deserializenumeric_avg_accum numeric_accum_inv numeric_avg f f r r 0 2281 128 2281 128 _null__null_ )); ! DATA(insert ( 2104 n 0 float4_accum float8_avg float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}"_null_ )); ! DATA(insert ( 2105 n 0 float8_accum float8_avg float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}"_null_ )); ! DATA(insert ( 2106 n 0 interval_accum interval_avg interval_combine - - interval_accum interval_accum_inv interval_avg f f r r 0 1187 0 1187 0 "{0second,0 second}" "{0 second,0 second}" )); /* sum */ ! DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_combine int8_avg_serialize int8_avg_deserialize int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2108 n 0 int4_sum - int8pl - - int4_avg_accum int4_avg_accum_inv int2int4_sum f f r r 0 20 0 1016 0 _null_ "{0,0}" )); ! DATA(insert ( 2109 n 0 int2_sum - int8pl - - int2_avg_accum int2_avg_accum_inv int2int4_sum f f r r 0 20 0 1016 0 _null_ "{0,0}" )); ! DATA(insert ( 2110 n 0 float4pl - float4pl - - - - - f f r r 0 700 0 0 0 _null__null_ )); ! DATA(insert ( 2111 n 0 float8pl - float8pl - - - - - f f r r 0 701 0 0 0 _null__null_ )); ! DATA(insert ( 2112 n 0 cash_pl - cash_pl - - cash_pl cash_mi - f f r r 0 790 0 790 0 _null_ _null_ )); ! DATA(insert ( 2113 n 0 interval_pl - interval_pl - - interval_pl interval_mi - f f r r 0 1186 0 1186 0 _null_ _null_ )); ! DATA(insert ( 2114 n 0 numeric_avg_accum numeric_sum numeric_avg_combine numeric_avg_serialize numeric_avg_deserializenumeric_avg_accum numeric_accum_inv numeric_sum f f r r 0 2281 128 2281 128 _null__null_ )); /* max */ ! DATA(insert ( 2115 n 0 int8larger - int8larger - - - - - f f r r 413 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2116 n 0 int4larger - int4larger - - - - - f f r r 521 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2117 n 0 int2larger - int2larger - - - - - f f r r 520 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2118 n 0 oidlarger - oidlarger - - - - - f f r r 610 26 0 0 0 _null_ _null_ )); ! DATA(insert ( 2119 n 0 float4larger - float4larger - - - - - f f r r 623 700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2120 n 0 float8larger - float8larger - - - - - f f r r 674 701 0 0 0 _null_ _null_ )); ! DATA(insert ( 2121 n 0 int4larger - int4larger - - - - - f f r r 563 702 0 0 0 _null_ _null_ )); ! DATA(insert ( 2122 n 0 date_larger - date_larger - - - - - f f r r 1097 1082 0 0 0 _null_ _null_ )); ! DATA(insert ( 2123 n 0 time_larger - time_larger - - - - - f f r r 1112 1083 0 0 0 _null_ _null_ )); ! DATA(insert ( 2124 n 0 timetz_larger - timetz_larger - - - - - f f r r 1554 1266 0 0 0 _null_ _null_ )); ! DATA(insert ( 2125 n 0 cashlarger - cashlarger - - - - - f f r r 903 790 0 0 0 _null_ _null_ )); ! DATA(insert ( 2126 n 0 timestamp_larger - timestamp_larger - - - - - f f r r 2064 1114 0 0 0 _null_ _null_ )); ! DATA(insert ( 2127 n 0 timestamptz_larger - timestamptz_larger - - - - - f f r r 1324 1184 0 0 0 _null_ _null_ )); ! DATA(insert ( 2128 n 0 interval_larger - interval_larger - - - - - f f r r 1334 1186 0 0 0 _null_ _null_ )); ! DATA(insert ( 2129 n 0 text_larger - text_larger - - - - - f f r r 666 25 0 0 0 _null_ _null_ )); ! DATA(insert ( 2130 n 0 numeric_larger - numeric_larger - - - - - f f r r 1756 1700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2050 n 0 array_larger - array_larger - - - - - f f r r 1073 2277 0 0 0 _null_ _null_ )); ! DATA(insert ( 2244 n 0 bpchar_larger - bpchar_larger - - - - - f f r r 1060 1042 0 0 0 _null_ _null_ )); ! DATA(insert ( 2797 n 0 tidlarger - tidlarger - - - - - f f r r 2800 27 0 0 0 _null_ _null_ )); ! DATA(insert ( 3526 n 0 enum_larger - enum_larger - - - - - f f r r 3519 3500 0 0 0 _null_ _null_ )); ! DATA(insert ( 3564 n 0 network_larger - network_larger - - - - - f f r r 1205 869 0 0 0 _null_ _null_ )); /* min */ ! DATA(insert ( 2131 n 0 int8smaller - int8smaller - - - - - f f r r 412 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2132 n 0 int4smaller - int4smaller - - - - - f f r r 97 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2133 n 0 int2smaller - int2smaller - - - - - f f r r 95 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2134 n 0 oidsmaller - oidsmaller - - - - - f f r r 609 26 0 0 0 _null_ _null_ )); ! DATA(insert ( 2135 n 0 float4smaller - float4smaller - - - - - f f r r 622 700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2136 n 0 float8smaller - float8smaller - - - - - f f r r 672 701 0 0 0 _null_ _null_ )); ! DATA(insert ( 2137 n 0 int4smaller - int4smaller - - - - - f f r r 562 702 0 0 0 _null_ _null_ )); ! DATA(insert ( 2138 n 0 date_smaller - date_smaller - - - - - f f r r 1095 1082 0 0 0 _null_ _null_ )); ! DATA(insert ( 2139 n 0 time_smaller - time_smaller - - - - - f f r r 1110 1083 0 0 0 _null_ _null_ )); ! DATA(insert ( 2140 n 0 timetz_smaller - timetz_smaller - - - - - f f r r 1552 1266 0 0 0 _null_ _null_ )); ! DATA(insert ( 2141 n 0 cashsmaller - cashsmaller - - - - - f f r r 902 790 0 0 0 _null_ _null_ )); ! DATA(insert ( 2142 n 0 timestamp_smaller - timestamp_smaller - - - - - f f r r 2062 1114 0 0 0 _null_ _null_ )); ! DATA(insert ( 2143 n 0 timestamptz_smaller - timestamptz_smaller - - - - - f f r r 1322 1184 0 0 0 _null_ _null_ )); ! DATA(insert ( 2144 n 0 interval_smaller - interval_smaller - - - - - f f r r 1332 1186 0 0 0 _null_ _null_ )); ! DATA(insert ( 2145 n 0 text_smaller - text_smaller - - - - - f f r r 664 25 0 0 0 _null_ _null_ )); ! DATA(insert ( 2146 n 0 numeric_smaller - numeric_smaller - - - - - f f r r 1754 1700 0 0 0 _null_ _null_ )); ! DATA(insert ( 2051 n 0 array_smaller - array_smaller - - - - - f f r r 1072 2277 0 0 0 _null_ _null_ )); ! DATA(insert ( 2245 n 0 bpchar_smaller - bpchar_smaller - - - - - f f r r 1058 1042 0 0 0 _null_ _null_ )); ! DATA(insert ( 2798 n 0 tidsmaller - tidsmaller - - - - - f f r r 2799 27 0 0 0 _null_ _null_ )); ! DATA(insert ( 3527 n 0 enum_smaller - enum_smaller - - - - - f f r r 3518 3500 0 0 0 _null_ _null_ )); ! DATA(insert ( 3565 n 0 network_smaller - network_smaller - - - - - f f r r 1203 869 0 0 0 _null_ _null_ )); /* count */ ! DATA(insert ( 2147 n 0 int8inc_any - int8pl - - int8inc_any int8dec_any - f f r r 0 20 0 20 0 "0" "0" )); ! DATA(insert ( 2803 n 0 int8inc - int8pl - - int8inc int8dec - f f r r 0 20 0 20 0 "0" "0" )); /* var_pop */ ! DATA(insert ( 2718 n 0 int8_accum numeric_var_pop numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_var_pop f f r r 0 2281 1282281 128 _null_ _null_ )); ! DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_var_pop f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_var_pop f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2721 n 0 float4_accum float8_var_pop float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2722 n 0 float8_accum float8_var_pop float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2723 n 0 numeric_accum numeric_var_pop numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_var_pop f f r r 0 2281 128 2281 128 _null_ _null_ )); /* var_samp */ ! DATA(insert ( 2641 n 0 int8_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_var_samp f f r r 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_var_samp f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_var_samp f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2644 n 0 float4_accum float8_var_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2645 n 0 float8_accum float8_var_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2646 n 0 numeric_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_var_samp f f r r 0 2281 128 2281 128 _null_ _null_ )); /* variance: historical Postgres syntax for var_samp */ ! DATA(insert ( 2148 n 0 int8_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_var_samp f f r r 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_var_samp f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_var_samp f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2151 n 0 float4_accum float8_var_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2152 n 0 float8_accum float8_var_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2153 n 0 numeric_accum numeric_var_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_var_samp f f r r 0 2281 128 2281 128 _null_ _null_ )); /* stddev_pop */ ! DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_stddev_pop f f r r 0 2281 1282281 128 _null_ _null_ )); ! DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_stddev_pop f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_stddev_pop f f r r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2729 n 0 numeric_accum numeric_stddev_pop numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_stddev_pop f f r r 0 2281 128 2281 128 _null_ _null_ )); /* stddev_samp */ ! DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_stddev_samp f fr r 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_stddev_samp f f r r0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_stddev_samp f f r r0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2717 n 0 numeric_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_stddev_samp f f r r0 2281 128 2281 128 _null_ _null_ )); /* stddev: historical Postgres syntax for stddev_samp */ ! DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize int8_accum int8_accum_inv numeric_stddev_samp f f r r 0 2281 128 2281 128 _null_ _null_ )); ! DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int4_accum int4_accum_inv numeric_poly_stddev_samp f fr r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp numeric_poly_combine numeric_poly_serialize numeric_poly_deserialize int2_accum int2_accum_inv numeric_poly_stddev_samp f fr r 0 2281 48 2281 48 _null_ _null_ )); ! DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp float8_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ )); ! DATA(insert ( 2159 n 0 numeric_accum numeric_stddev_samp numeric_combine numeric_serialize numeric_deserialize numeric_accum numeric_accum_inv numeric_stddev_samp f fr r 0 2281 128 2281 128 _null_ _null_ )); /* SQL2003 binary regression aggregates */ ! DATA(insert ( 2818 n 0 int8inc_float8_float8 - int8pl - - - - - f f r r 0 20 0 0 0 "0" _null_ )); ! DATA(insert ( 2819 n 0 float8_regr_accum float8_regr_sxx float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2820 n 0 float8_regr_accum float8_regr_syy float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2821 n 0 float8_regr_accum float8_regr_sxy float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2822 n 0 float8_regr_accum float8_regr_avgx float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2823 n 0 float8_regr_accum float8_regr_avgy float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2824 n 0 float8_regr_accum float8_regr_r2 float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2825 n 0 float8_regr_accum float8_regr_slope float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2826 n 0 float8_regr_accum float8_regr_intercept float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2827 n 0 float8_regr_accum float8_covar_pop float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); ! DATA(insert ( 2829 n 0 float8_regr_accum float8_corr float8_regr_combine - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); /* boolean-and and boolean-or */ ! DATA(insert ( 2517 n 0 booland_statefunc - booland_statefunc - - bool_accum bool_accum_inv bool_alltrue f f r r 58 16 0 2281 16 _null_ _null_ )); ! DATA(insert ( 2518 n 0 boolor_statefunc - boolor_statefunc - - bool_accum bool_accum_inv bool_anytrue f f r r 59 16 0 2281 16 _null_ _null_ )); ! DATA(insert ( 2519 n 0 booland_statefunc - booland_statefunc - - bool_accum bool_accum_inv bool_alltrue f f r r 58 16 0 2281 16 _null_ _null_ )); /* bitwise integer */ ! DATA(insert ( 2236 n 0 int2and - int2and - - - - - f f r r 0 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2237 n 0 int2or - int2or - - - - - f f r r 0 21 0 0 0 _null_ _null_ )); ! DATA(insert ( 2238 n 0 int4and - int4and - - - - - f f r r 0 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2239 n 0 int4or - int4or - - - - - f f r r 0 23 0 0 0 _null_ _null_ )); ! DATA(insert ( 2240 n 0 int8and - int8and - - - - - f f r r 0 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2241 n 0 int8or - int8or - - - - - f f r r 0 20 0 0 0 _null_ _null_ )); ! DATA(insert ( 2242 n 0 bitand - bitand - - - - - f f r r 0 1560 0 0 0 _null_ _null_ )); ! DATA(insert ( 2243 n 0 bitor - bitor - - - - - f f r r 0 1560 0 0 0 _null_ _null_ )); /* xml */ ! DATA(insert ( 2901 n 0 xmlconcat2 - - - - - - - f f r r 0 142 0 0 0 _null_ _null_ )); /* array */ ! DATA(insert ( 2335 n 0 array_agg_transfn array_agg_finalfn - - - - - - t f r r 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 4053 n 0 array_agg_array_transfn array_agg_array_finalfn - - - - - - t f r r 0 2281 0 0 0 _null_ _null_ )); /* text */ ! DATA(insert ( 3538 n 0 string_agg_transfn string_agg_finalfn - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ )); /* bytea */ ! DATA(insert ( 3545 n 0 bytea_string_agg_transfn bytea_string_agg_finalfn - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ )); /* json */ ! DATA(insert ( 3175 n 0 json_agg_transfn json_agg_finalfn - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3197 n 0 json_object_agg_transfn json_object_agg_finalfn - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ )); /* jsonb */ ! DATA(insert ( 3267 n 0 jsonb_agg_transfn jsonb_agg_finalfn - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3270 n 0 jsonb_object_agg_transfn jsonb_object_agg_finalfn - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ )); /* ordered-set and hypothetical-set aggregates */ ! DATA(insert ( 3972 o 1 ordered_set_transition percentile_disc_final - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3974 o 1 ordered_set_transition percentile_cont_float8_final - - - - - - f f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3976 o 1 ordered_set_transition percentile_cont_interval_final - - - - - - f f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3978 o 1 ordered_set_transition percentile_disc_multi_final - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3980 o 1 ordered_set_transition percentile_cont_float8_multi_final - - - - - - f f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3982 o 1 ordered_set_transition percentile_cont_interval_multi_final - - - - - - f f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3984 o 0 ordered_set_transition mode_final - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3986 h 1 ordered_set_transition_multi rank_final - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3988 h 1 ordered_set_transition_multi percent_rank_final - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3990 h 1 ordered_set_transition_multi cume_dist_final - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ )); ! DATA(insert ( 3992 h 1 ordered_set_transition_multi dense_rank_final - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ )); #endif /* PG_AGGREGATE_H */ diff --git a/src/include/catalog/pg_aggregate_fn.h b/src/include/catalog/pg_aggregate_fn.h index ...a323aab . *** a/src/include/catalog/pg_aggregate_fn.h --- b/src/include/catalog/pg_aggregate_fn.h *************** *** 0 **** --- 1,52 ---- + /*------------------------------------------------------------------------- + * + * pg_aggregate_fn.h + * prototypes for functions in catalog/pg_aggregate.c + * + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_aggregate_fn.h + * + *------------------------------------------------------------------------- + */ + #ifndef PG_AGGREGATE_FN_H + #define PG_AGGREGATE_FN_H + + #include "catalog/objectaddress.h" + #include "nodes/pg_list.h" + + extern ObjectAddress 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 *aggcombinefnName, + List *aggserialfnName, + List *aggdeserialfnName, + List *aggmtransfnName, + List *aggminvtransfnName, + List *aggmfinalfnName, + bool finalfnExtraArgs, + bool mfinalfnExtraArgs, + char finalfnModify, + char mfinalfnModify, + List *aggsortopName, + Oid aggTransType, + int32 aggTransSpace, + Oid aggmTransType, + int32 aggmTransSpace, + const char *agginitval, + const char *aggminitval, + char proparallel); + + #endif /* PG_AGGREGATE_FN_H */ diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out index 341ba52..723d0b1 100644 *** a/src/test/regress/expected/create_aggregate.out --- b/src/test/regress/expected/create_aggregate.out *************** create aggregate my_percentile_disc(floa *** 71,77 **** stype = internal, sfunc = ordered_set_transition, finalfunc = percentile_disc_final, ! finalfunc_extra = true ); create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( stype = internal, --- 71,78 ---- stype = internal, sfunc = ordered_set_transition, finalfunc = percentile_disc_final, ! finalfunc_extra = true, ! finalfunc_modify = read_write ); create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( stype = internal, *************** CREATE AGGREGATE myavg (numeric) *** 146,160 **** finalfunc = numeric_avg, serialfunc = numeric_avg_serialize, deserialfunc = numeric_avg_deserialize, ! combinefunc = numeric_avg_combine ); -- Ensure all these functions made it into the catalog ! SELECT aggfnoid,aggtransfn,aggcombinefn,aggtranstype,aggserialfn,aggdeserialfn FROM pg_aggregate WHERE aggfnoid = 'myavg'::REGPROC; ! aggfnoid | aggtransfn | aggcombinefn | aggtranstype | aggserialfn | aggdeserialfn ! ----------+-------------------+---------------------+--------------+-----------------------+------------------------- ! myavg | numeric_avg_accum | numeric_avg_combine | 2281 | numeric_avg_serialize | numeric_avg_deserialize (1 row) DROP AGGREGATE myavg (numeric); --- 147,163 ---- finalfunc = numeric_avg, serialfunc = numeric_avg_serialize, deserialfunc = numeric_avg_deserialize, ! combinefunc = numeric_avg_combine, ! finalfunc_modify = stop_updates -- just to test a non-default setting ); -- Ensure all these functions made it into the catalog ! SELECT aggfnoid, aggtransfn, aggcombinefn, aggtranstype::regtype, ! aggserialfn, aggdeserialfn, aggfinalmodify FROM pg_aggregate WHERE aggfnoid = 'myavg'::REGPROC; ! aggfnoid | aggtransfn | aggcombinefn | aggtranstype | aggserialfn | aggdeserialfn |aggfinalmodify ! ----------+-------------------+---------------------+--------------+-----------------------+-------------------------+---------------- ! myavg | numeric_avg_accum | numeric_avg_combine | internal | numeric_avg_serialize | numeric_avg_deserialize |s (1 row) DROP AGGREGATE myavg (numeric); diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index fcf8bd7..684f7f2 100644 *** a/src/test/regress/expected/opr_sanity.out --- b/src/test/regress/expected/opr_sanity.out *************** WHERE aggfnoid = 0 OR aggtransfn = 0 OR *** 1275,1280 **** --- 1275,1282 ---- aggkind NOT IN ('n', 'o', 'h') OR aggnumdirectargs < 0 OR (aggkind = 'n' AND aggnumdirectargs > 0) OR + aggfinalmodify NOT IN ('r', 's', 'w') OR + aggmfinalmodify NOT IN ('r', 's', 'w') OR aggtranstype = 0 OR aggtransspace < 0 OR aggmtransspace < 0; ctid | aggfnoid ------+---------- diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql index ae3a6c0..6e3651c 100644 *** a/src/test/regress/sql/create_aggregate.sql --- b/src/test/regress/sql/create_aggregate.sql *************** create aggregate my_percentile_disc(floa *** 86,92 **** stype = internal, sfunc = ordered_set_transition, finalfunc = percentile_disc_final, ! finalfunc_extra = true ); create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( --- 86,93 ---- stype = internal, sfunc = ordered_set_transition, finalfunc = percentile_disc_final, ! finalfunc_extra = true, ! finalfunc_modify = read_write ); create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( *************** CREATE AGGREGATE myavg (numeric) *** 161,171 **** finalfunc = numeric_avg, serialfunc = numeric_avg_serialize, deserialfunc = numeric_avg_deserialize, ! combinefunc = numeric_avg_combine ); -- Ensure all these functions made it into the catalog ! SELECT aggfnoid,aggtransfn,aggcombinefn,aggtranstype,aggserialfn,aggdeserialfn FROM pg_aggregate WHERE aggfnoid = 'myavg'::REGPROC; --- 162,174 ---- finalfunc = numeric_avg, serialfunc = numeric_avg_serialize, deserialfunc = numeric_avg_deserialize, ! combinefunc = numeric_avg_combine, ! finalfunc_modify = stop_updates -- just to test a non-default setting ); -- Ensure all these functions made it into the catalog ! SELECT aggfnoid, aggtransfn, aggcombinefn, aggtranstype::regtype, ! aggserialfn, aggdeserialfn, aggfinalmodify FROM pg_aggregate WHERE aggfnoid = 'myavg'::REGPROC; diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 2945966..e8fdf84 100644 *** a/src/test/regress/sql/opr_sanity.sql --- b/src/test/regress/sql/opr_sanity.sql *************** WHERE aggfnoid = 0 OR aggtransfn = 0 OR *** 795,800 **** --- 795,802 ---- aggkind NOT IN ('n', 'o', 'h') OR aggnumdirectargs < 0 OR (aggkind = 'n' AND aggnumdirectargs > 0) OR + aggfinalmodify NOT IN ('r', 's', 'w') OR + aggmfinalmodify NOT IN ('r', 's', 'w') OR aggtranstype = 0 OR aggtransspace < 0 OR aggmtransspace < 0; -- Make sure the matching pg_proc entry is sensible, too. -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Aggregate transition state merging vs. hypothetical setfunctions
From
Peter Eisentraut
Date:
On 10/13/17 19:01, Tom Lane wrote: >> Moving on to the exact color of the bikeshed: it seems like the right >> way to present this to users of CREATE AGGREGATE is in terms of "does >> the final function modify the transition state?". So maybe the values >> could be spelled >> SMODIFY = READ_ONLY ffunc never touches state, ok as window agg >> SMODIFY = SHARABLE ffunc does some one-time change like sorting, >> so state merging is OK but not window agg >> SMODIFY = READ_WRITE ffunc trashes state, can't do merging either >> I'm not set on these names by any means; anyone have a better idea? Is "sharable" the preferred spelling, as opposed to "shareable"? -- Peter Eisentraut http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes: > On 10/13/17 19:01, Tom Lane wrote: > SMODIFY = SHARABLE ffunc does some one-time change like sorting, > so state merging is OK but not window agg > Is "sharable" the preferred spelling, as opposed to "shareable"? Hmm ... I looked in two different dictionaries, and they both say sharable is a variant of shareable. So while it's not wrong exactly, I seem to have picked the less preferred spelling. I could run around and change it, but I'd have to do so *right now* I think --- once we release beta1 the costs of changing this would go up. Will do so if there's not objections in an hour or so. regards, tom lane