PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
orderedsetaggs.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * orderedsetaggs.c
4  * Ordered-set aggregate functions.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/utils/adt/orderedsetaggs.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <math.h>
18 
19 #include "catalog/pg_aggregate.h"
20 #include "catalog/pg_operator.h"
21 #include "catalog/pg_type.h"
22 #include "executor/executor.h"
23 #include "miscadmin.h"
24 #include "nodes/nodeFuncs.h"
25 #include "optimizer/tlist.h"
26 #include "utils/array.h"
27 #include "utils/builtins.h"
28 #include "utils/lsyscache.h"
29 #include "utils/timestamp.h"
30 #include "utils/tuplesort.h"
31 
32 
33 /*
34  * Generic support for ordered-set aggregates
35  *
36  * The state for an ordered-set aggregate is divided into a per-group struct
37  * (which is the internal-type transition state datum returned to nodeAgg.c)
38  * and a per-query struct, which contains data and sub-objects that we can
39  * create just once per query because they will not change across groups.
40  * The per-query struct and subsidiary data live in the executor's per-query
41  * memory context, and go away implicitly at ExecutorEnd().
42  */
43 
44 typedef struct OSAPerQueryState
45 {
46  /* Aggref for this aggregate: */
48  /* Memory context containing this struct and other per-query data: */
50 
51  /* These fields are used only when accumulating tuples: */
52 
53  /* Tuple descriptor for tuples inserted into sortstate: */
55  /* Tuple slot we can use for inserting/extracting tuples: */
57  /* Per-sort-column sorting information */
64  /* Equality operator call info, created only if needed: */
66 
67  /* These fields are used only when accumulating datums: */
68 
69  /* Info about datatype of datums being sorted: */
72  bool typByVal;
73  char typAlign;
74  /* Info about sort ordering: */
79  /* Equality operator call info, created only if needed: */
82 
83 typedef struct OSAPerGroupState
84 {
85  /* Link to the per-query state for this aggregate: */
87  /* Memory context containing per-group data: */
89  /* Sort object we're accumulating data in: */
91  /* Number of normal rows inserted into sortstate: */
94 
95 static void ordered_set_shutdown(Datum arg);
96 
97 
98 /*
99  * Set up working state for an ordered-set aggregate
100  */
101 static OSAPerGroupState *
102 ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples)
103 {
104  OSAPerGroupState *osastate;
105  OSAPerQueryState *qstate;
106  MemoryContext gcontext;
107  MemoryContext oldcontext;
108 
109  /*
110  * Check we're called as aggregate (and not a window function), and get
111  * the Agg node's group-lifespan context (which might change from group to
112  * group, so we shouldn't cache it in the per-query state).
113  */
114  if (AggCheckCallContext(fcinfo, &gcontext) != AGG_CONTEXT_AGGREGATE)
115  elog(ERROR, "ordered-set aggregate called in non-aggregate context");
116 
117  /*
118  * We keep a link to the per-query state in fn_extra; if it's not there,
119  * create it, and do the per-query setup we need.
120  */
121  qstate = (OSAPerQueryState *) fcinfo->flinfo->fn_extra;
122  if (qstate == NULL)
123  {
124  Aggref *aggref;
125  MemoryContext qcontext;
126  List *sortlist;
127  int numSortCols;
128 
129  /* Get the Aggref so we can examine aggregate's arguments */
130  aggref = AggGetAggref(fcinfo);
131  if (!aggref)
132  elog(ERROR, "ordered-set aggregate called in non-aggregate context");
133  if (!AGGKIND_IS_ORDERED_SET(aggref->aggkind))
134  elog(ERROR, "ordered-set aggregate support function called for non-ordered-set aggregate");
135 
136  /*
137  * Prepare per-query structures in the fn_mcxt, which we assume is the
138  * executor's per-query context; in any case it's the right place to
139  * keep anything found via fn_extra.
140  */
141  qcontext = fcinfo->flinfo->fn_mcxt;
142  oldcontext = MemoryContextSwitchTo(qcontext);
143 
144  qstate = (OSAPerQueryState *) palloc0(sizeof(OSAPerQueryState));
145  qstate->aggref = aggref;
146  qstate->qcontext = qcontext;
147 
148  /* Extract the sort information */
149  sortlist = aggref->aggorder;
150  numSortCols = list_length(sortlist);
151 
152  if (use_tuples)
153  {
154  bool ishypothetical = (aggref->aggkind == AGGKIND_HYPOTHETICAL);
155  ListCell *lc;
156  int i;
157 
158  if (ishypothetical)
159  numSortCols++; /* make space for flag column */
160  qstate->numSortCols = numSortCols;
161  qstate->sortColIdx = (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
162  qstate->sortOperators = (Oid *) palloc(numSortCols * sizeof(Oid));
163  qstate->eqOperators = (Oid *) palloc(numSortCols * sizeof(Oid));
164  qstate->sortCollations = (Oid *) palloc(numSortCols * sizeof(Oid));
165  qstate->sortNullsFirsts = (bool *) palloc(numSortCols * sizeof(bool));
166 
167  i = 0;
168  foreach(lc, sortlist)
169  {
170  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
171  TargetEntry *tle = get_sortgroupclause_tle(sortcl,
172  aggref->args);
173 
174  /* the parser should have made sure of this */
175  Assert(OidIsValid(sortcl->sortop));
176 
177  qstate->sortColIdx[i] = tle->resno;
178  qstate->sortOperators[i] = sortcl->sortop;
179  qstate->eqOperators[i] = sortcl->eqop;
180  qstate->sortCollations[i] = exprCollation((Node *) tle->expr);
181  qstate->sortNullsFirsts[i] = sortcl->nulls_first;
182  i++;
183  }
184 
185  if (ishypothetical)
186  {
187  /* Add an integer flag column as the last sort column */
188  qstate->sortColIdx[i] = list_length(aggref->args) + 1;
189  qstate->sortOperators[i] = Int4LessOperator;
190  qstate->eqOperators[i] = Int4EqualOperator;
191  qstate->sortCollations[i] = InvalidOid;
192  qstate->sortNullsFirsts[i] = false;
193  i++;
194  }
195 
196  Assert(i == numSortCols);
197 
198  /*
199  * Get a tupledesc corresponding to the aggregated inputs
200  * (including sort expressions) of the agg.
201  */
202  qstate->tupdesc = ExecTypeFromTL(aggref->args, false);
203 
204  /* If we need a flag column, hack the tupledesc to include that */
205  if (ishypothetical)
206  {
207  TupleDesc newdesc;
208  int natts = qstate->tupdesc->natts;
209 
210  newdesc = CreateTemplateTupleDesc(natts + 1, false);
211  for (i = 1; i <= natts; i++)
212  TupleDescCopyEntry(newdesc, i, qstate->tupdesc, i);
213 
214  TupleDescInitEntry(newdesc,
215  (AttrNumber) ++natts,
216  "flag",
217  INT4OID,
218  -1,
219  0);
220 
221  FreeTupleDesc(qstate->tupdesc);
222  qstate->tupdesc = newdesc;
223  }
224 
225  /* Create slot we'll use to store/retrieve rows */
226  qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc);
227  }
228  else
229  {
230  /* Sort single datums */
231  SortGroupClause *sortcl;
232  TargetEntry *tle;
233 
234  if (numSortCols != 1 || aggref->aggkind == AGGKIND_HYPOTHETICAL)
235  elog(ERROR, "ordered-set aggregate support function does not support multiple aggregated columns");
236 
237  sortcl = (SortGroupClause *) linitial(sortlist);
238  tle = get_sortgroupclause_tle(sortcl, aggref->args);
239 
240  /* the parser should have made sure of this */
241  Assert(OidIsValid(sortcl->sortop));
242 
243  /* Save sort ordering info */
244  qstate->sortColType = exprType((Node *) tle->expr);
245  qstate->sortOperator = sortcl->sortop;
246  qstate->eqOperator = sortcl->eqop;
247  qstate->sortCollation = exprCollation((Node *) tle->expr);
248  qstate->sortNullsFirst = sortcl->nulls_first;
249 
250  /* Save datatype info */
252  &qstate->typLen,
253  &qstate->typByVal,
254  &qstate->typAlign);
255  }
256 
257  fcinfo->flinfo->fn_extra = (void *) qstate;
258 
259  MemoryContextSwitchTo(oldcontext);
260  }
261 
262  /* Now build the stuff we need in group-lifespan context */
263  oldcontext = MemoryContextSwitchTo(gcontext);
264 
265  osastate = (OSAPerGroupState *) palloc(sizeof(OSAPerGroupState));
266  osastate->qstate = qstate;
267  osastate->gcontext = gcontext;
268 
269  /*
270  * Initialize tuplesort object.
271  */
272  if (use_tuples)
273  osastate->sortstate = tuplesort_begin_heap(qstate->tupdesc,
274  qstate->numSortCols,
275  qstate->sortColIdx,
276  qstate->sortOperators,
277  qstate->sortCollations,
278  qstate->sortNullsFirsts,
279  work_mem, false);
280  else
281  osastate->sortstate = tuplesort_begin_datum(qstate->sortColType,
282  qstate->sortOperator,
283  qstate->sortCollation,
284  qstate->sortNullsFirst,
285  work_mem, false);
286 
287  osastate->number_of_rows = 0;
288 
289  /* Now register a shutdown callback to clean things up at end of group */
290  AggRegisterCallback(fcinfo,
292  PointerGetDatum(osastate));
293 
294  MemoryContextSwitchTo(oldcontext);
295 
296  return osastate;
297 }
298 
299 /*
300  * Clean up when evaluation of an ordered-set aggregate is complete.
301  *
302  * We don't need to bother freeing objects in the per-group memory context,
303  * since that will get reset anyway by nodeAgg.c; nor should we free anything
304  * in the per-query context, which will get cleared (if this was the last
305  * group) by ExecutorEnd. But we must take care to release any potential
306  * non-memory resources.
307  *
308  * This callback is arguably unnecessary, since we don't support use of
309  * ordered-set aggs in AGG_HASHED mode and there is currently no non-error
310  * code path in non-hashed modes wherein nodeAgg.c won't call the finalfn
311  * after calling the transfn one or more times. So in principle we could rely
312  * on the finalfn to delete the tuplestore etc. However, it's possible that
313  * such a code path might exist in future, and in any case it'd be
314  * notationally tedious and sometimes require extra data copying to ensure
315  * we always delete the tuplestore in the finalfn.
316  */
317 static void
319 {
321 
322  /* Tuplesort object might have temp files. */
323  if (osastate->sortstate)
324  tuplesort_end(osastate->sortstate);
325  osastate->sortstate = NULL;
326  /* The tupleslot probably can't be holding a pin, but let's be safe. */
327  if (osastate->qstate->tupslot)
328  ExecClearTuple(osastate->qstate->tupslot);
329 }
330 
331 
332 /*
333  * Generic transition function for ordered-set aggregates
334  * with a single input column in which we want to suppress nulls
335  */
336 Datum
338 {
339  OSAPerGroupState *osastate;
340 
341  /* If first call, create the transition state workspace */
342  if (PG_ARGISNULL(0))
343  osastate = ordered_set_startup(fcinfo, false);
344  else
345  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
346 
347  /* Load the datum into the tuplesort object, but only if it's not null */
348  if (!PG_ARGISNULL(1))
349  {
350  tuplesort_putdatum(osastate->sortstate, PG_GETARG_DATUM(1), false);
351  osastate->number_of_rows++;
352  }
353 
354  PG_RETURN_POINTER(osastate);
355 }
356 
357 /*
358  * Generic transition function for ordered-set aggregates
359  * with (potentially) multiple aggregated input columns
360  */
361 Datum
363 {
364  OSAPerGroupState *osastate;
365  TupleTableSlot *slot;
366  int nargs;
367  int i;
368 
369  /* If first call, create the transition state workspace */
370  if (PG_ARGISNULL(0))
371  osastate = ordered_set_startup(fcinfo, true);
372  else
373  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
374 
375  /* Form a tuple from all the other inputs besides the transition value */
376  slot = osastate->qstate->tupslot;
377  ExecClearTuple(slot);
378  nargs = PG_NARGS() - 1;
379  for (i = 0; i < nargs; i++)
380  {
381  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
382  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
383  }
384  if (osastate->qstate->aggref->aggkind == AGGKIND_HYPOTHETICAL)
385  {
386  /* Add a zero flag value to mark this row as a normal input row */
387  slot->tts_values[i] = Int32GetDatum(0);
388  slot->tts_isnull[i] = false;
389  i++;
390  }
391  Assert(i == slot->tts_tupleDescriptor->natts);
392  ExecStoreVirtualTuple(slot);
393 
394  /* Load the row into the tuplesort object */
395  tuplesort_puttupleslot(osastate->sortstate, slot);
396  osastate->number_of_rows++;
397 
398  PG_RETURN_POINTER(osastate);
399 }
400 
401 
402 /*
403  * percentile_disc(float8) within group(anyelement) - discrete percentile
404  */
405 Datum
407 {
408  OSAPerGroupState *osastate;
409  double percentile;
410  Datum val;
411  bool isnull;
412  int64 rownum;
413 
415 
416  /* Get and check the percentile argument */
417  if (PG_ARGISNULL(1))
418  PG_RETURN_NULL();
419 
420  percentile = PG_GETARG_FLOAT8(1);
421 
422  if (percentile < 0 || percentile > 1 || isnan(percentile))
423  ereport(ERROR,
424  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
425  errmsg("percentile value %g is not between 0 and 1",
426  percentile)));
427 
428  /* If there were no regular rows, the result is NULL */
429  if (PG_ARGISNULL(0))
430  PG_RETURN_NULL();
431 
432  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
433 
434  /* number_of_rows could be zero if we only saw NULL input values */
435  if (osastate->number_of_rows == 0)
436  PG_RETURN_NULL();
437 
438  /* Finish the sort */
439  tuplesort_performsort(osastate->sortstate);
440 
441  /*----------
442  * We need the smallest K such that (K/N) >= percentile.
443  * N>0, therefore K >= N*percentile, therefore K = ceil(N*percentile).
444  * So we skip K-1 rows (if K>0) and return the next row fetched.
445  *----------
446  */
447  rownum = (int64) ceil(percentile * osastate->number_of_rows);
448  Assert(rownum <= osastate->number_of_rows);
449 
450  if (rownum > 1)
451  {
452  if (!tuplesort_skiptuples(osastate->sortstate, rownum - 1, true))
453  elog(ERROR, "missing row in percentile_disc");
454  }
455 
456  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
457  elog(ERROR, "missing row in percentile_disc");
458 
459  /*
460  * Note: we *cannot* clean up the tuplesort object here, because the value
461  * to be returned is allocated inside its sortcontext. We could use
462  * datumCopy to copy it out of there, but it doesn't seem worth the
463  * trouble, since the cleanup callback will clear the tuplesort later.
464  */
465 
466  /* We shouldn't have stored any nulls, but do the right thing anyway */
467  if (isnull)
468  PG_RETURN_NULL();
469  else
470  PG_RETURN_DATUM(val);
471 }
472 
473 
474 /*
475  * For percentile_cont, we need a way to interpolate between consecutive
476  * values. Use a helper function for that, so that we can share the rest
477  * of the code between types.
478  */
479 typedef Datum (*LerpFunc) (Datum lo, Datum hi, double pct);
480 
481 static Datum
482 float8_lerp(Datum lo, Datum hi, double pct)
483 {
484  double loval = DatumGetFloat8(lo);
485  double hival = DatumGetFloat8(hi);
486 
487  return Float8GetDatum(loval + (pct * (hival - loval)));
488 }
489 
490 static Datum
491 interval_lerp(Datum lo, Datum hi, double pct)
492 {
493  Datum diff_result = DirectFunctionCall2(interval_mi, hi, lo);
495  diff_result,
496  Float8GetDatumFast(pct));
497 
498  return DirectFunctionCall2(interval_pl, mul_result, lo);
499 }
500 
501 /*
502  * Continuous percentile
503  */
504 static Datum
506  Oid expect_type,
507  LerpFunc lerpfunc)
508 {
509  OSAPerGroupState *osastate;
510  double percentile;
511  int64 first_row = 0;
512  int64 second_row = 0;
513  Datum val;
514  Datum first_val;
515  Datum second_val;
516  double proportion;
517  bool isnull;
518 
520 
521  /* Get and check the percentile argument */
522  if (PG_ARGISNULL(1))
523  PG_RETURN_NULL();
524 
525  percentile = PG_GETARG_FLOAT8(1);
526 
527  if (percentile < 0 || percentile > 1 || isnan(percentile))
528  ereport(ERROR,
529  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
530  errmsg("percentile value %g is not between 0 and 1",
531  percentile)));
532 
533  /* If there were no regular rows, the result is NULL */
534  if (PG_ARGISNULL(0))
535  PG_RETURN_NULL();
536 
537  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
538 
539  /* number_of_rows could be zero if we only saw NULL input values */
540  if (osastate->number_of_rows == 0)
541  PG_RETURN_NULL();
542 
543  Assert(expect_type == osastate->qstate->sortColType);
544 
545  /* Finish the sort */
546  tuplesort_performsort(osastate->sortstate);
547 
548  first_row = floor(percentile * (osastate->number_of_rows - 1));
549  second_row = ceil(percentile * (osastate->number_of_rows - 1));
550 
551  Assert(first_row < osastate->number_of_rows);
552 
553  if (!tuplesort_skiptuples(osastate->sortstate, first_row, true))
554  elog(ERROR, "missing row in percentile_cont");
555 
556  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val, &isnull, NULL))
557  elog(ERROR, "missing row in percentile_cont");
558  if (isnull)
559  PG_RETURN_NULL();
560 
561  if (first_row == second_row)
562  {
563  val = first_val;
564  }
565  else
566  {
567  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val, &isnull, NULL))
568  elog(ERROR, "missing row in percentile_cont");
569 
570  if (isnull)
571  PG_RETURN_NULL();
572 
573  proportion = (percentile * (osastate->number_of_rows - 1)) - first_row;
574  val = lerpfunc(first_val, second_val, proportion);
575  }
576 
577  /*
578  * Note: we *cannot* clean up the tuplesort object here, because the value
579  * to be returned may be allocated inside its sortcontext. We could use
580  * datumCopy to copy it out of there, but it doesn't seem worth the
581  * trouble, since the cleanup callback will clear the tuplesort later.
582  */
583 
584  PG_RETURN_DATUM(val);
585 }
586 
587 /*
588  * percentile_cont(float8) within group (float8) - continuous percentile
589  */
590 Datum
592 {
594 }
595 
596 /*
597  * percentile_cont(float8) within group (interval) - continuous percentile
598  */
599 Datum
601 {
603 }
604 
605 
606 /*
607  * Support code for handling arrays of percentiles
608  *
609  * Note: in each pct_info entry, second_row should be equal to or
610  * exactly one more than first_row.
611  */
612 struct pct_info
613 {
614  int64 first_row; /* first row to sample */
615  int64 second_row; /* possible second row to sample */
616  double proportion; /* interpolation fraction */
617  int idx; /* index of this item in original array */
618 };
619 
620 /*
621  * Sort comparator to sort pct_infos by first_row then second_row
622  */
623 static int
624 pct_info_cmp(const void *pa, const void *pb)
625 {
626  const struct pct_info *a = (const struct pct_info *) pa;
627  const struct pct_info *b = (const struct pct_info *) pb;
628 
629  if (a->first_row != b->first_row)
630  return (a->first_row < b->first_row) ? -1 : 1;
631  if (a->second_row != b->second_row)
632  return (a->second_row < b->second_row) ? -1 : 1;
633  return 0;
634 }
635 
636 /*
637  * Construct array showing which rows to sample for percentiles.
638  */
639 static struct pct_info *
640 setup_pct_info(int num_percentiles,
641  Datum *percentiles_datum,
642  bool *percentiles_null,
643  int64 rowcount,
644  bool continuous)
645 {
646  struct pct_info *pct_info;
647  int i;
648 
649  pct_info = (struct pct_info *) palloc(num_percentiles * sizeof(struct pct_info));
650 
651  for (i = 0; i < num_percentiles; i++)
652  {
653  pct_info[i].idx = i;
654 
655  if (percentiles_null[i])
656  {
657  /* dummy entry for any NULL in array */
658  pct_info[i].first_row = 0;
659  pct_info[i].second_row = 0;
660  pct_info[i].proportion = 0;
661  }
662  else
663  {
664  double p = DatumGetFloat8(percentiles_datum[i]);
665 
666  if (p < 0 || p > 1 || isnan(p))
667  ereport(ERROR,
668  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
669  errmsg("percentile value %g is not between 0 and 1",
670  p)));
671 
672  if (continuous)
673  {
674  pct_info[i].first_row = 1 + floor(p * (rowcount - 1));
675  pct_info[i].second_row = 1 + ceil(p * (rowcount - 1));
676  pct_info[i].proportion = (p * (rowcount - 1)) - floor(p * (rowcount - 1));
677  }
678  else
679  {
680  /*----------
681  * We need the smallest K such that (K/N) >= percentile.
682  * N>0, therefore K >= N*percentile, therefore
683  * K = ceil(N*percentile); but not less than 1.
684  *----------
685  */
686  int64 row = (int64) ceil(p * rowcount);
687 
688  row = Max(1, row);
689  pct_info[i].first_row = row;
690  pct_info[i].second_row = row;
691  pct_info[i].proportion = 0;
692  }
693  }
694  }
695 
696  /*
697  * The parameter array wasn't necessarily in sorted order, but we need to
698  * visit the rows in order, so sort by first_row/second_row.
699  */
700  qsort(pct_info, num_percentiles, sizeof(struct pct_info), pct_info_cmp);
701 
702  return pct_info;
703 }
704 
705 /*
706  * percentile_disc(float8[]) within group (anyelement) - discrete percentiles
707  */
708 Datum
710 {
711  OSAPerGroupState *osastate;
712  ArrayType *param;
713  Datum *percentiles_datum;
714  bool *percentiles_null;
715  int num_percentiles;
716  struct pct_info *pct_info;
717  Datum *result_datum;
718  bool *result_isnull;
719  int64 rownum = 0;
720  Datum val = (Datum) 0;
721  bool isnull = true;
722  int i;
723 
725 
726  /* If there were no regular rows, the result is NULL */
727  if (PG_ARGISNULL(0))
728  PG_RETURN_NULL();
729 
730  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
731 
732  /* number_of_rows could be zero if we only saw NULL input values */
733  if (osastate->number_of_rows == 0)
734  PG_RETURN_NULL();
735 
736  /* Deconstruct the percentile-array input */
737  if (PG_ARGISNULL(1))
738  PG_RETURN_NULL();
739  param = PG_GETARG_ARRAYTYPE_P(1);
740 
742  /* hard-wired info on type float8 */
743  8, FLOAT8PASSBYVAL, 'd',
744  &percentiles_datum,
745  &percentiles_null,
746  &num_percentiles);
747 
748  if (num_percentiles == 0)
750 
751  pct_info = setup_pct_info(num_percentiles,
752  percentiles_datum,
753  percentiles_null,
754  osastate->number_of_rows,
755  false);
756 
757  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
758  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
759 
760  /*
761  * Start by dealing with any nulls in the param array - those are sorted
762  * to the front on row=0, so set the corresponding result indexes to null
763  */
764  for (i = 0; i < num_percentiles; i++)
765  {
766  int idx = pct_info[i].idx;
767 
768  if (pct_info[i].first_row > 0)
769  break;
770 
771  result_datum[idx] = (Datum) 0;
772  result_isnull[idx] = true;
773  }
774 
775  /*
776  * If there's anything left after doing the nulls, then grind the input
777  * and extract the needed values
778  */
779  if (i < num_percentiles)
780  {
781  /* Finish the sort */
782  tuplesort_performsort(osastate->sortstate);
783 
784  for (; i < num_percentiles; i++)
785  {
786  int64 target_row = pct_info[i].first_row;
787  int idx = pct_info[i].idx;
788 
789  /* Advance to target row, if not already there */
790  if (target_row > rownum)
791  {
792  if (!tuplesort_skiptuples(osastate->sortstate, target_row - rownum - 1, true))
793  elog(ERROR, "missing row in percentile_disc");
794 
795  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
796  elog(ERROR, "missing row in percentile_disc");
797 
798  rownum = target_row;
799  }
800 
801  result_datum[idx] = val;
802  result_isnull[idx] = isnull;
803  }
804  }
805 
806  /*
807  * We could clean up the tuplesort object after forming the array, but
808  * probably not worth the trouble.
809  */
810 
811  /* We make the output array the same shape as the input */
812  PG_RETURN_POINTER(construct_md_array(result_datum, result_isnull,
813  ARR_NDIM(param),
814  ARR_DIMS(param),
815  ARR_LBOUND(param),
816  osastate->qstate->sortColType,
817  osastate->qstate->typLen,
818  osastate->qstate->typByVal,
819  osastate->qstate->typAlign));
820 }
821 
822 /*
823  * percentile_cont(float8[]) within group () - continuous percentiles
824  */
825 static Datum
827  Oid expect_type,
828  int16 typLen, bool typByVal, char typAlign,
829  LerpFunc lerpfunc)
830 {
831  OSAPerGroupState *osastate;
832  ArrayType *param;
833  Datum *percentiles_datum;
834  bool *percentiles_null;
835  int num_percentiles;
836  struct pct_info *pct_info;
837  Datum *result_datum;
838  bool *result_isnull;
839  int64 rownum = 0;
840  Datum first_val = (Datum) 0;
841  Datum second_val = (Datum) 0;
842  bool isnull;
843  int i;
844 
846 
847  /* If there were no regular rows, the result is NULL */
848  if (PG_ARGISNULL(0))
849  PG_RETURN_NULL();
850 
851  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
852 
853  /* number_of_rows could be zero if we only saw NULL input values */
854  if (osastate->number_of_rows == 0)
855  PG_RETURN_NULL();
856 
857  Assert(expect_type == osastate->qstate->sortColType);
858 
859  /* Deconstruct the percentile-array input */
860  if (PG_ARGISNULL(1))
861  PG_RETURN_NULL();
862  param = PG_GETARG_ARRAYTYPE_P(1);
863 
865  /* hard-wired info on type float8 */
866  8, FLOAT8PASSBYVAL, 'd',
867  &percentiles_datum,
868  &percentiles_null,
869  &num_percentiles);
870 
871  if (num_percentiles == 0)
873 
874  pct_info = setup_pct_info(num_percentiles,
875  percentiles_datum,
876  percentiles_null,
877  osastate->number_of_rows,
878  true);
879 
880  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
881  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
882 
883  /*
884  * Start by dealing with any nulls in the param array - those are sorted
885  * to the front on row=0, so set the corresponding result indexes to null
886  */
887  for (i = 0; i < num_percentiles; i++)
888  {
889  int idx = pct_info[i].idx;
890 
891  if (pct_info[i].first_row > 0)
892  break;
893 
894  result_datum[idx] = (Datum) 0;
895  result_isnull[idx] = true;
896  }
897 
898  /*
899  * If there's anything left after doing the nulls, then grind the input
900  * and extract the needed values
901  */
902  if (i < num_percentiles)
903  {
904  /* Finish the sort */
905  tuplesort_performsort(osastate->sortstate);
906 
907  for (; i < num_percentiles; i++)
908  {
909  int64 first_row = pct_info[i].first_row;
910  int64 second_row = pct_info[i].second_row;
911  int idx = pct_info[i].idx;
912 
913  /*
914  * Advance to first_row, if not already there. Note that we might
915  * already have rownum beyond first_row, in which case first_val
916  * is already correct. (This occurs when interpolating between
917  * the same two input rows as for the previous percentile.)
918  */
919  if (first_row > rownum)
920  {
921  if (!tuplesort_skiptuples(osastate->sortstate, first_row - rownum - 1, true))
922  elog(ERROR, "missing row in percentile_cont");
923 
924  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val,
925  &isnull, NULL) || isnull)
926  elog(ERROR, "missing row in percentile_cont");
927 
928  rownum = first_row;
929  /* Always advance second_val to be latest input value */
930  second_val = first_val;
931  }
932  else if (first_row == rownum)
933  {
934  /*
935  * We are already at the desired row, so we must previously
936  * have read its value into second_val (and perhaps first_val
937  * as well, but this assignment is harmless in that case).
938  */
939  first_val = second_val;
940  }
941 
942  /* Fetch second_row if needed */
943  if (second_row > rownum)
944  {
945  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val,
946  &isnull, NULL) || isnull)
947  elog(ERROR, "missing row in percentile_cont");
948  rownum++;
949  }
950  /* We should now certainly be on second_row exactly */
951  Assert(second_row == rownum);
952 
953  /* Compute appropriate result */
954  if (second_row > first_row)
955  result_datum[idx] = lerpfunc(first_val, second_val,
956  pct_info[i].proportion);
957  else
958  result_datum[idx] = first_val;
959 
960  result_isnull[idx] = false;
961  }
962  }
963 
964  /*
965  * We could clean up the tuplesort object after forming the array, but
966  * probably not worth the trouble.
967  */
968 
969  /* We make the output array the same shape as the input */
970  PG_RETURN_POINTER(construct_md_array(result_datum, result_isnull,
971  ARR_NDIM(param),
972  ARR_DIMS(param), ARR_LBOUND(param),
973  expect_type,
974  typLen,
975  typByVal,
976  typAlign));
977 }
978 
979 /*
980  * percentile_cont(float8[]) within group (float8) - continuous percentiles
981  */
982 Datum
984 {
986  FLOAT8OID,
987  /* hard-wired info on type float8 */
988  8, FLOAT8PASSBYVAL, 'd',
989  float8_lerp);
990 }
991 
992 /*
993  * percentile_cont(float8[]) within group (interval) - continuous percentiles
994  */
995 Datum
997 {
999  INTERVALOID,
1000  /* hard-wired info on type interval */
1001  16, false, 'd',
1002  interval_lerp);
1003 }
1004 
1005 
1006 /*
1007  * mode() within group (anyelement) - most common value
1008  */
1009 Datum
1011 {
1012  OSAPerGroupState *osastate;
1013  Datum val;
1014  bool isnull;
1015  Datum mode_val = (Datum) 0;
1016  int64 mode_freq = 0;
1017  Datum last_val = (Datum) 0;
1018  int64 last_val_freq = 0;
1019  bool last_val_is_mode = false;
1020  FmgrInfo *equalfn;
1021  Datum abbrev_val = (Datum) 0;
1022  Datum last_abbrev_val = (Datum) 0;
1023  bool shouldfree;
1024 
1026 
1027  /* If there were no regular rows, the result is NULL */
1028  if (PG_ARGISNULL(0))
1029  PG_RETURN_NULL();
1030 
1031  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1032 
1033  /* number_of_rows could be zero if we only saw NULL input values */
1034  if (osastate->number_of_rows == 0)
1035  PG_RETURN_NULL();
1036 
1037  /* Look up the equality function for the datatype, if we didn't already */
1038  equalfn = &(osastate->qstate->equalfn);
1039  if (!OidIsValid(equalfn->fn_oid))
1040  fmgr_info_cxt(get_opcode(osastate->qstate->eqOperator), equalfn,
1041  osastate->qstate->qcontext);
1042 
1043  shouldfree = !(osastate->qstate->typByVal);
1044 
1045  /* Finish the sort */
1046  tuplesort_performsort(osastate->sortstate);
1047 
1048  /* Scan tuples and count frequencies */
1049  while (tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, &abbrev_val))
1050  {
1051  /* we don't expect any nulls, but ignore them if found */
1052  if (isnull)
1053  continue;
1054 
1055  if (last_val_freq == 0)
1056  {
1057  /* first nonnull value - it's the mode for now */
1058  mode_val = last_val = val;
1059  mode_freq = last_val_freq = 1;
1060  last_val_is_mode = true;
1061  last_abbrev_val = abbrev_val;
1062  }
1063  else if (abbrev_val == last_abbrev_val &&
1064  DatumGetBool(FunctionCall2(equalfn, val, last_val)))
1065  {
1066  /* value equal to previous value, count it */
1067  if (last_val_is_mode)
1068  mode_freq++; /* needn't maintain last_val_freq */
1069  else if (++last_val_freq > mode_freq)
1070  {
1071  /* last_val becomes new mode */
1072  if (shouldfree)
1073  pfree(DatumGetPointer(mode_val));
1074  mode_val = last_val;
1075  mode_freq = last_val_freq;
1076  last_val_is_mode = true;
1077  }
1078  if (shouldfree)
1079  pfree(DatumGetPointer(val));
1080  }
1081  else
1082  {
1083  /* val should replace last_val */
1084  if (shouldfree && !last_val_is_mode)
1085  pfree(DatumGetPointer(last_val));
1086  last_val = val;
1087  /* avoid equality function calls by reusing abbreviated keys */
1088  last_abbrev_val = abbrev_val;
1089  last_val_freq = 1;
1090  last_val_is_mode = false;
1091  }
1092 
1094  }
1095 
1096  if (shouldfree && !last_val_is_mode)
1097  pfree(DatumGetPointer(last_val));
1098 
1099  /*
1100  * Note: we *cannot* clean up the tuplesort object here, because the value
1101  * to be returned is allocated inside its sortcontext. We could use
1102  * datumCopy to copy it out of there, but it doesn't seem worth the
1103  * trouble, since the cleanup callback will clear the tuplesort later.
1104  */
1105 
1106  if (mode_freq)
1107  PG_RETURN_DATUM(mode_val);
1108  else
1109  PG_RETURN_NULL();
1110 }
1111 
1112 
1113 /*
1114  * Common code to sanity-check args for hypothetical-set functions. No need
1115  * for friendly errors, these can only happen if someone's messing up the
1116  * aggregate definitions. The checks are needed for security, however.
1117  */
1118 static void
1120  TupleDesc tupdesc)
1121 {
1122  int i;
1123 
1124  /* check that we have an int4 flag column */
1125  if (!tupdesc ||
1126  (nargs + 1) != tupdesc->natts ||
1127  tupdesc->attrs[nargs]->atttypid != INT4OID)
1128  elog(ERROR, "type mismatch in hypothetical-set function");
1129 
1130  /* check that direct args match in type with aggregated args */
1131  for (i = 0; i < nargs; i++)
1132  {
1133  if (get_fn_expr_argtype(fcinfo->flinfo, i + 1) != tupdesc->attrs[i]->atttypid)
1134  elog(ERROR, "type mismatch in hypothetical-set function");
1135  }
1136 }
1137 
1138 /*
1139  * compute rank of hypothetical row
1140  *
1141  * flag should be -1 to sort hypothetical row ahead of its peers, or +1
1142  * to sort behind.
1143  * total number of regular rows is returned into *number_of_rows.
1144  */
1145 static int64
1147  int64 *number_of_rows)
1148 {
1149  int nargs = PG_NARGS() - 1;
1150  int64 rank = 1;
1151  OSAPerGroupState *osastate;
1152  TupleTableSlot *slot;
1153  int i;
1154 
1156 
1157  /* If there were no regular rows, the rank is always 1 */
1158  if (PG_ARGISNULL(0))
1159  {
1160  *number_of_rows = 0;
1161  return 1;
1162  }
1163 
1164  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1165  *number_of_rows = osastate->number_of_rows;
1166 
1167  /* Adjust nargs to be the number of direct (or aggregated) args */
1168  if (nargs % 2 != 0)
1169  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1170  nargs /= 2;
1171 
1172  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1173 
1174  /* insert the hypothetical row into the sort */
1175  slot = osastate->qstate->tupslot;
1176  ExecClearTuple(slot);
1177  for (i = 0; i < nargs; i++)
1178  {
1179  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1180  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1181  }
1182  slot->tts_values[i] = Int32GetDatum(flag);
1183  slot->tts_isnull[i] = false;
1184  ExecStoreVirtualTuple(slot);
1185 
1186  tuplesort_puttupleslot(osastate->sortstate, slot);
1187 
1188  /* finish the sort */
1189  tuplesort_performsort(osastate->sortstate);
1190 
1191  /* iterate till we find the hypothetical row */
1192  while (tuplesort_gettupleslot(osastate->sortstate, true, slot, NULL))
1193  {
1194  bool isnull;
1195  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1196 
1197  if (!isnull && DatumGetInt32(d) != 0)
1198  break;
1199 
1200  rank++;
1201 
1203  }
1204 
1205  ExecClearTuple(slot);
1206 
1207  /* Might as well clean up the tuplesort object immediately */
1208  tuplesort_end(osastate->sortstate);
1209  osastate->sortstate = NULL;
1210 
1211  return rank;
1212 }
1213 
1214 
1215 /*
1216  * rank() - rank of hypothetical row
1217  */
1218 Datum
1220 {
1221  int64 rank;
1222  int64 rowcount;
1223 
1224  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1225 
1226  PG_RETURN_INT64(rank);
1227 }
1228 
1229 /*
1230  * percent_rank() - percentile rank of hypothetical row
1231  */
1232 Datum
1234 {
1235  int64 rank;
1236  int64 rowcount;
1237  double result_val;
1238 
1239  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1240 
1241  if (rowcount == 0)
1242  PG_RETURN_FLOAT8(0);
1243 
1244  result_val = (double) (rank - 1) / (double) (rowcount);
1245 
1246  PG_RETURN_FLOAT8(result_val);
1247 }
1248 
1249 /*
1250  * cume_dist() - cumulative distribution of hypothetical row
1251  */
1252 Datum
1254 {
1255  int64 rank;
1256  int64 rowcount;
1257  double result_val;
1258 
1259  rank = hypothetical_rank_common(fcinfo, 1, &rowcount);
1260 
1261  result_val = (double) (rank) / (double) (rowcount + 1);
1262 
1263  PG_RETURN_FLOAT8(result_val);
1264 }
1265 
1266 /*
1267  * dense_rank() - rank of hypothetical row without gaps in ranking
1268  */
1269 Datum
1271 {
1272  int nargs = PG_NARGS() - 1;
1273  int64 rank = 1;
1274  int64 duplicate_count = 0;
1275  OSAPerGroupState *osastate;
1276  int numDistinctCols;
1277  Datum abbrevVal = (Datum) 0;
1278  Datum abbrevOld = (Datum) 0;
1279  AttrNumber *sortColIdx;
1280  FmgrInfo *equalfns;
1281  TupleTableSlot *slot;
1282  TupleTableSlot *extraslot;
1283  TupleTableSlot *slot2;
1284  MemoryContext tmpcontext;
1285  int i;
1286 
1288 
1289  /* If there were no regular rows, the rank is always 1 */
1290  if (PG_ARGISNULL(0))
1291  PG_RETURN_INT64(rank);
1292 
1293  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1294 
1295  /* Adjust nargs to be the number of direct (or aggregated) args */
1296  if (nargs % 2 != 0)
1297  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1298  nargs /= 2;
1299 
1300  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1301 
1302  /*
1303  * When comparing tuples, we can omit the flag column since we will only
1304  * compare rows with flag == 0.
1305  */
1306  numDistinctCols = osastate->qstate->numSortCols - 1;
1307 
1308  /* Look up the equality function(s), if we didn't already */
1309  equalfns = osastate->qstate->equalfns;
1310  if (equalfns == NULL)
1311  {
1312  MemoryContext qcontext = osastate->qstate->qcontext;
1313 
1314  equalfns = (FmgrInfo *)
1315  MemoryContextAlloc(qcontext, numDistinctCols * sizeof(FmgrInfo));
1316  for (i = 0; i < numDistinctCols; i++)
1317  {
1318  fmgr_info_cxt(get_opcode(osastate->qstate->eqOperators[i]),
1319  &equalfns[i],
1320  qcontext);
1321  }
1322  osastate->qstate->equalfns = equalfns;
1323  }
1324  sortColIdx = osastate->qstate->sortColIdx;
1325 
1326  /* Get short-term context we can use for execTuplesMatch */
1327  tmpcontext = AggGetTempMemoryContext(fcinfo);
1328 
1329  /* insert the hypothetical row into the sort */
1330  slot = osastate->qstate->tupslot;
1331  ExecClearTuple(slot);
1332  for (i = 0; i < nargs; i++)
1333  {
1334  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1335  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1336  }
1337  slot->tts_values[i] = Int32GetDatum(-1);
1338  slot->tts_isnull[i] = false;
1339  ExecStoreVirtualTuple(slot);
1340 
1341  tuplesort_puttupleslot(osastate->sortstate, slot);
1342 
1343  /* finish the sort */
1344  tuplesort_performsort(osastate->sortstate);
1345 
1346  /*
1347  * We alternate fetching into tupslot and extraslot so that we have the
1348  * previous row available for comparisons. This is accomplished by
1349  * swapping the slot pointer variables after each row.
1350  */
1351  extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc);
1352  slot2 = extraslot;
1353 
1354  /* iterate till we find the hypothetical row */
1355  while (tuplesort_gettupleslot(osastate->sortstate, true, slot, &abbrevVal))
1356  {
1357  bool isnull;
1358  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1359  TupleTableSlot *tmpslot;
1360 
1361  if (!isnull && DatumGetInt32(d) != 0)
1362  break;
1363 
1364  /* count non-distinct tuples */
1365  if (!TupIsNull(slot2) &&
1366  abbrevVal == abbrevOld &&
1367  execTuplesMatch(slot, slot2,
1368  numDistinctCols,
1369  sortColIdx,
1370  equalfns,
1371  tmpcontext))
1372  duplicate_count++;
1373 
1374  tmpslot = slot2;
1375  slot2 = slot;
1376  slot = tmpslot;
1377  /* avoid execTuplesMatch() calls by reusing abbreviated keys */
1378  abbrevOld = abbrevVal;
1379 
1380  rank++;
1381 
1383  }
1384 
1385  ExecClearTuple(slot);
1386  ExecClearTuple(slot2);
1387 
1388  ExecDropSingleTupleTableSlot(extraslot);
1389 
1390  /* Might as well clean up the tuplesort object immediately */
1391  tuplesort_end(osastate->sortstate);
1392  osastate->sortstate = NULL;
1393 
1394  rank = rank - duplicate_count;
1395 
1396  PG_RETURN_INT64(rank);
1397 }
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:237
signed short int16
Definition: c.h:252
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:305
MemoryContext gcontext
Definition: fmgr.h:53
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2183
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1763
OSAPerQueryState * qstate
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:370
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Definition: tuplesort.c:1475
struct OSAPerQueryState OSAPerQueryState
MemoryContext fn_mcxt
Definition: fmgr.h:62
Datum percentile_cont_float8_final(PG_FUNCTION_ARGS)
#define DatumGetInt32(X)
Definition: postgres.h:480
Datum percentile_cont_interval_final(PG_FUNCTION_ARGS)
#define PG_RETURN_INT64(x)
Definition: fmgr.h:311
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:1989
#define PointerGetDatum(X)
Definition: postgres.h:564
Datum percentile_disc_final(PG_FUNCTION_ARGS)
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:224
TupleTableSlot * tupslot
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:310
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Form_pg_attribute * attrs
Definition: tupdesc.h:74
#define Int4LessOperator
Definition: pg_operator.h:133
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:575
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:508
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:69
int errcode(int sqlerrcode)
Definition: elog.c:575
List * args
Definition: primnodes.h:279
static struct pct_info * setup_pct_info(int num_percentiles, Datum *percentiles_datum, bool *percentiles_null, int64 rowcount, bool continuous)
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
Datum * tts_values
Definition: tuptable.h:125
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:232
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3424
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
int natts
Definition: tupdesc.h:73
Datum interval_mi(PG_FUNCTION_ARGS)
Definition: timestamp.c:3044
Datum ordered_set_transition(PG_FUNCTION_ARGS)
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:2126
#define ARR_LBOUND(a)
Definition: array.h:277
#define AGGKIND_IS_ORDERED_SET(kind)
Definition: pg_aggregate.h:129
MemoryContext qcontext
FmgrInfo * flinfo
Definition: fmgr.h:71
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:244
Datum interval_pl(PG_FUNCTION_ARGS)
Definition: timestamp.c:3010
Datum hypothetical_dense_rank_final(PG_FUNCTION_ARGS)
void pfree(void *pointer)
Definition: mcxt.c:992
#define linitial(l)
Definition: pg_list.h:110
int64 second_row
#define ERROR
Definition: elog.h:43
static void ordered_set_shutdown(Datum arg)
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:2220
void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, TupleDesc src, AttrNumber srcAttno)
Definition: tupdesc.c:229
static OSAPerGroupState * ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples)
#define ARR_DIMS(a)
Definition: array.h:275
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:664
Datum hypothetical_cume_dist_final(PG_FUNCTION_ARGS)
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, bool randomAccess)
Definition: tuplesort.c:1028
bool * tts_isnull
Definition: tuptable.h:126
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
char * flag(int b)
Definition: test-ctype.c:33
List * aggorder
Definition: primnodes.h:280
static Datum interval_lerp(Datum lo, Datum hi, double pct)
AttrNumber resno
Definition: primnodes.h:1331
#define INTERVALOID
Definition: pg_type.h:517
#define DatumGetBool(X)
Definition: postgres.h:401
#define TupIsNull(slot)
Definition: tuptable.h:138
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:169
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:493
#define ereport(elevel, rest)
Definition: elog.h:122
Datum hypothetical_rank_final(PG_FUNCTION_ARGS)
MemoryContext AggGetTempMemoryContext(FunctionCallInfo fcinfo)
Definition: nodeAgg.c:3722
Datum mode_final(PG_FUNCTION_ARGS)
TupleDesc ExecTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:888
Datum percentile_cont_interval_multi_final(PG_FUNCTION_ARGS)
Datum percentile_disc_multi_final(PG_FUNCTION_ARGS)
int64 first_row
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
struct OSAPerGroupState OSAPerGroupState
void * palloc0(Size size)
Definition: mcxt.c:920
#define DatumGetFloat8(X)
Definition: postgres.h:736
uintptr_t Datum
Definition: postgres.h:374
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:297
int work_mem
Definition: globals.c:112
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1062
Oid fn_oid
Definition: fmgr.h:56
#define Float8GetDatumFast(X)
Definition: postgres.h:784
#define Max(x, y)
Definition: c.h:796
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1330
Tuplesortstate * sortstate
#define Int4EqualOperator
Definition: pg_operator.h:130
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:89
#define FLOAT8OID
Definition: pg_type.h:411
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:745
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3660
#define PG_NARGS()
Definition: fmgr.h:160
void * fn_extra
Definition: fmgr.h:61
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:41
#define ARR_NDIM(a)
Definition: array.h:271
double proportion
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:266
#define DatumGetPointer(X)
Definition: postgres.h:557
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3475
FmgrInfo * equalfns
void AggRegisterCallback(FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
Definition: nodeAgg.c:3749
#define Int32GetDatum(X)
Definition: postgres.h:487
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, bool randomAccess)
Definition: tuplesort.c:753
Datum interval_mul(PG_FUNCTION_ARGS)
Definition: timestamp.c:3084
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
int i
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1143
static void hypothetical_check_argtypes(FunctionCallInfo fcinfo, int nargs, TupleDesc tupdesc)
void * arg
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
char aggkind
Definition: primnodes.h:286
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
#define elog
Definition: elog.h:219
Datum ordered_set_transition_multi(PG_FUNCTION_ARGS)
#define qsort(a, b, c, d)
Definition: port.h:440
static int pct_info_cmp(const void *pa, const void *pb)
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1157
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3340
Datum hypothetical_percent_rank_final(PG_FUNCTION_ARGS)
#define AGGKIND_HYPOTHETICAL
Definition: pg_aggregate.h:126
Datum percentile_cont_float8_multi_final(PG_FUNCTION_ARGS)
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
Definition: tuplesort.c:2222
Definition: pg_list.h:45
AttrNumber * sortColIdx
int16 AttrNumber
Definition: attnum.h:21
long val
Definition: informix.c:689
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:557
#define PG_RETURN_NULL()
Definition: fmgr.h:289
static Datum float8_lerp(Datum lo, Datum hi, double pct)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1354
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2099
Aggref * AggGetAggref(FunctionCallInfo fcinfo)
Definition: nodeAgg.c:3697
Datum(* LerpFunc)(Datum lo, Datum hi, double pct)