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