PostgreSQL Source Code  git master
orderedsetaggs.c File Reference
#include "postgres.h"
#include <math.h>
#include "catalog/pg_aggregate.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
#include "utils/tuplesort.h"
Include dependency graph for orderedsetaggs.c:

Go to the source code of this file.

Data Structures

struct  OSAPerQueryState
 
struct  OSAPerGroupState
 
struct  pct_info
 

Typedefs

typedef struct OSAPerQueryState OSAPerQueryState
 
typedef struct OSAPerGroupState OSAPerGroupState
 
typedef Datum(* LerpFunc) (Datum lo, Datum hi, double pct)
 

Functions

static void ordered_set_shutdown (Datum arg)
 
static OSAPerGroupStateordered_set_startup (FunctionCallInfo fcinfo, bool use_tuples)
 
Datum ordered_set_transition (PG_FUNCTION_ARGS)
 
Datum ordered_set_transition_multi (PG_FUNCTION_ARGS)
 
Datum percentile_disc_final (PG_FUNCTION_ARGS)
 
static Datum float8_lerp (Datum lo, Datum hi, double pct)
 
static Datum interval_lerp (Datum lo, Datum hi, double pct)
 
static Datum percentile_cont_final_common (FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)
 
Datum percentile_cont_float8_final (PG_FUNCTION_ARGS)
 
Datum percentile_cont_interval_final (PG_FUNCTION_ARGS)
 
static int pct_info_cmp (const void *pa, const void *pb)
 
static struct pct_infosetup_pct_info (int num_percentiles, Datum *percentiles_datum, bool *percentiles_null, int64 rowcount, bool continuous)
 
Datum percentile_disc_multi_final (PG_FUNCTION_ARGS)
 
static Datum percentile_cont_multi_final_common (FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)
 
Datum percentile_cont_float8_multi_final (PG_FUNCTION_ARGS)
 
Datum percentile_cont_interval_multi_final (PG_FUNCTION_ARGS)
 
Datum mode_final (PG_FUNCTION_ARGS)
 
static void hypothetical_check_argtypes (FunctionCallInfo fcinfo, int nargs, TupleDesc tupdesc)
 
static int64 hypothetical_rank_common (FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)
 
Datum hypothetical_rank_final (PG_FUNCTION_ARGS)
 
Datum hypothetical_percent_rank_final (PG_FUNCTION_ARGS)
 
Datum hypothetical_cume_dist_final (PG_FUNCTION_ARGS)
 
Datum hypothetical_dense_rank_final (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ LerpFunc

typedef Datum(* LerpFunc) (Datum lo, Datum hi, double pct)

Definition at line 495 of file orderedsetaggs.c.

◆ OSAPerGroupState

◆ OSAPerQueryState

Function Documentation

◆ float8_lerp()

static Datum float8_lerp ( Datum  lo,
Datum  hi,
double  pct 
)
static

Definition at line 498 of file orderedsetaggs.c.

References DatumGetFloat8, and Float8GetDatum().

Referenced by percentile_cont_float8_final(), and percentile_cont_float8_multi_final().

499 {
500  double loval = DatumGetFloat8(lo);
501  double hival = DatumGetFloat8(hi);
502 
503  return Float8GetDatum(loval + (pct * (hival - loval)));
504 }
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1710
#define DatumGetFloat8(X)
Definition: postgres.h:714

◆ hypothetical_check_argtypes()

static void hypothetical_check_argtypes ( FunctionCallInfo  fcinfo,
int  nargs,
TupleDesc  tupdesc 
)
static

Definition at line 1137 of file orderedsetaggs.c.

References atttypid, elog, ERROR, FunctionCallInfoBaseData::flinfo, get_fn_expr_argtype(), i, TupleDescData::natts, and TupleDescAttr.

Referenced by hypothetical_dense_rank_final(), and hypothetical_rank_common().

1139 {
1140  int i;
1141 
1142  /* check that we have an int4 flag column */
1143  if (!tupdesc ||
1144  (nargs + 1) != tupdesc->natts ||
1145  TupleDescAttr(tupdesc, nargs)->atttypid != INT4OID)
1146  elog(ERROR, "type mismatch in hypothetical-set function");
1147 
1148  /* check that direct args match in type with aggregated args */
1149  for (i = 0; i < nargs; i++)
1150  {
1151  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1152 
1153  if (get_fn_expr_argtype(fcinfo->flinfo, i + 1) != attr->atttypid)
1154  elog(ERROR, "type mismatch in hypothetical-set function");
1155  }
1156 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define ERROR
Definition: elog.h:43
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1804
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Oid atttypid
Definition: pg_attribute.h:49
FmgrInfo * flinfo
Definition: fmgr.h:87
#define elog(elevel,...)
Definition: elog.h:214
int i

◆ hypothetical_cume_dist_final()

Datum hypothetical_cume_dist_final ( PG_FUNCTION_ARGS  )

Definition at line 1273 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

1274 {
1275  int64 rank;
1276  int64 rowcount;
1277  double result_val;
1278 
1279  rank = hypothetical_rank_common(fcinfo, 1, &rowcount);
1280 
1281  result_val = (double) (rank) / (double) (rowcount + 1);
1282 
1283  PG_RETURN_FLOAT8(result_val);
1284 }
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:365
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)

◆ hypothetical_dense_rank_final()

Datum hypothetical_dense_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1290 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, CHECK_FOR_INTERRUPTS, OSAPerQueryState::compareTuple, CreateStandaloneExprContext(), DatumGetInt32, OSAPerQueryState::econtext, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, elog, OSAPerQueryState::eqOperators, ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecQualAndReset(), ExecStoreVirtualTuple(), execTuplesMatchPrepare(), hypothetical_check_argtypes(), i, Int32GetDatum, MakeSingleTupleTableSlot(), MemoryContextSwitchTo(), OSAPerQueryState::numSortCols, PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_NARGS, PG_RETURN_INT64, OSAPerQueryState::qcontext, OSAPerGroupState::qstate, slot_getattr(), OSAPerGroupState::sort_done, OSAPerQueryState::sortColIdx, OSAPerQueryState::sortCollations, OSAPerGroupState::sortstate, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TTSOpsMinimalTuple, OSAPerQueryState::tupdesc, TupIsNull, tuplesort_gettupleslot(), tuplesort_performsort(), tuplesort_puttupleslot(), and OSAPerQueryState::tupslot.

1291 {
1292  ExprContext *econtext;
1293  ExprState *compareTuple;
1294  int nargs = PG_NARGS() - 1;
1295  int64 rank = 1;
1296  int64 duplicate_count = 0;
1297  OSAPerGroupState *osastate;
1298  int numDistinctCols;
1299  Datum abbrevVal = (Datum) 0;
1300  Datum abbrevOld = (Datum) 0;
1301  TupleTableSlot *slot;
1302  TupleTableSlot *extraslot;
1303  TupleTableSlot *slot2;
1304  int i;
1305 
1307 
1308  /* If there were no regular rows, the rank is always 1 */
1309  if (PG_ARGISNULL(0))
1310  PG_RETURN_INT64(rank);
1311 
1312  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1313  econtext = osastate->qstate->econtext;
1314  if (!econtext)
1315  {
1316  MemoryContext oldcontext;
1317 
1318  /* Make sure to we create econtext under correct parent context. */
1319  oldcontext = MemoryContextSwitchTo(osastate->qstate->qcontext);
1321  econtext = osastate->qstate->econtext;
1322  MemoryContextSwitchTo(oldcontext);
1323  }
1324 
1325  /* Adjust nargs to be the number of direct (or aggregated) args */
1326  if (nargs % 2 != 0)
1327  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1328  nargs /= 2;
1329 
1330  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1331 
1332  /*
1333  * When comparing tuples, we can omit the flag column since we will only
1334  * compare rows with flag == 0.
1335  */
1336  numDistinctCols = osastate->qstate->numSortCols - 1;
1337 
1338  /* Build tuple comparator, if we didn't already */
1339  compareTuple = osastate->qstate->compareTuple;
1340  if (compareTuple == NULL)
1341  {
1342  AttrNumber *sortColIdx = osastate->qstate->sortColIdx;
1343  MemoryContext oldContext;
1344 
1345  oldContext = MemoryContextSwitchTo(osastate->qstate->qcontext);
1346  compareTuple = execTuplesMatchPrepare(osastate->qstate->tupdesc,
1347  numDistinctCols,
1348  sortColIdx,
1349  osastate->qstate->eqOperators,
1350  osastate->qstate->sortCollations,
1351  NULL);
1352  MemoryContextSwitchTo(oldContext);
1353  osastate->qstate->compareTuple = compareTuple;
1354  }
1355 
1356  /* because we need a hypothetical row, we can't share transition state */
1357  Assert(!osastate->sort_done);
1358 
1359  /* insert the hypothetical row into the sort */
1360  slot = osastate->qstate->tupslot;
1361  ExecClearTuple(slot);
1362  for (i = 0; i < nargs; i++)
1363  {
1364  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1365  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1366  }
1367  slot->tts_values[i] = Int32GetDatum(-1);
1368  slot->tts_isnull[i] = false;
1369  ExecStoreVirtualTuple(slot);
1370 
1371  tuplesort_puttupleslot(osastate->sortstate, slot);
1372 
1373  /* finish the sort */
1374  tuplesort_performsort(osastate->sortstate);
1375  osastate->sort_done = true;
1376 
1377  /*
1378  * We alternate fetching into tupslot and extraslot so that we have the
1379  * previous row available for comparisons. This is accomplished by
1380  * swapping the slot pointer variables after each row.
1381  */
1382  extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc,
1384  slot2 = extraslot;
1385 
1386  /* iterate till we find the hypothetical row */
1387  while (tuplesort_gettupleslot(osastate->sortstate, true, true, slot,
1388  &abbrevVal))
1389  {
1390  bool isnull;
1391  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1392  TupleTableSlot *tmpslot;
1393 
1394  if (!isnull && DatumGetInt32(d) != 0)
1395  break;
1396 
1397  /* count non-distinct tuples */
1398  econtext->ecxt_outertuple = slot;
1399  econtext->ecxt_innertuple = slot2;
1400 
1401  if (!TupIsNull(slot2) &&
1402  abbrevVal == abbrevOld &&
1403  ExecQualAndReset(compareTuple, econtext))
1404  duplicate_count++;
1405 
1406  tmpslot = slot2;
1407  slot2 = slot;
1408  slot = tmpslot;
1409  /* avoid ExecQual() calls by reusing abbreviated keys */
1410  abbrevOld = abbrevVal;
1411 
1412  rank++;
1413 
1415  }
1416 
1417  ExecClearTuple(slot);
1418  ExecClearTuple(slot2);
1419 
1420  ExecDropSingleTupleTableSlot(extraslot);
1421 
1422  rank = rank - duplicate_count;
1423 
1424  PG_RETURN_INT64(rank);
1425 }
ExprContext * CreateStandaloneExprContext(void)
Definition: execUtils.c:357
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1964
OSAPerQueryState * qstate
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define DatumGetInt32(X)
Definition: postgres.h:472
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1208
#define PG_RETURN_INT64(x)
Definition: fmgr.h:366
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
TupleTableSlot * tupslot
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Datum * tts_values
Definition: tuptable.h:126
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
MemoryContext qcontext
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2332
bool * tts_isnull
Definition: tuptable.h:128
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:228
#define TupIsNull(slot)
Definition: tuptable.h:292
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:397
uintptr_t Datum
Definition: postgres.h:367
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:381
ExprContext * econtext
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:745
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
#define PG_NARGS()
Definition: fmgr.h:203
ExprState * compareTuple
#define Int32GetDatum(X)
Definition: postgres.h:479
#define elog(elevel,...)
Definition: elog.h:214
int i
static void hypothetical_check_argtypes(FunctionCallInfo fcinfo, int nargs, TupleDesc tupdesc)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
AttrNumber * sortColIdx
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1608

◆ hypothetical_percent_rank_final()

Datum hypothetical_percent_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1253 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

1254 {
1255  int64 rank;
1256  int64 rowcount;
1257  double result_val;
1258 
1259  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1260 
1261  if (rowcount == 0)
1262  PG_RETURN_FLOAT8(0);
1263 
1264  result_val = (double) (rank - 1) / (double) (rowcount);
1265 
1266  PG_RETURN_FLOAT8(result_val);
1267 }
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:365
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)

◆ hypothetical_rank_common()

static int64 hypothetical_rank_common ( FunctionCallInfo  fcinfo,
int  flag,
int64 *  number_of_rows 
)
static

Definition at line 1166 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, CHECK_FOR_INTERRUPTS, DatumGetInt32, elog, ERROR, ExecClearTuple(), ExecStoreVirtualTuple(), hypothetical_check_argtypes(), i, Int32GetDatum, OSAPerGroupState::number_of_rows, PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_NARGS, OSAPerGroupState::qstate, slot_getattr(), OSAPerGroupState::sort_done, OSAPerGroupState::sortstate, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, OSAPerQueryState::tupdesc, tuplesort_gettupleslot(), tuplesort_performsort(), tuplesort_puttupleslot(), and OSAPerQueryState::tupslot.

Referenced by hypothetical_cume_dist_final(), hypothetical_percent_rank_final(), and hypothetical_rank_final().

1168 {
1169  int nargs = PG_NARGS() - 1;
1170  int64 rank = 1;
1171  OSAPerGroupState *osastate;
1172  TupleTableSlot *slot;
1173  int i;
1174 
1176 
1177  /* If there were no regular rows, the rank is always 1 */
1178  if (PG_ARGISNULL(0))
1179  {
1180  *number_of_rows = 0;
1181  return 1;
1182  }
1183 
1184  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1185  *number_of_rows = osastate->number_of_rows;
1186 
1187  /* Adjust nargs to be the number of direct (or aggregated) args */
1188  if (nargs % 2 != 0)
1189  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1190  nargs /= 2;
1191 
1192  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1193 
1194  /* because we need a hypothetical row, we can't share transition state */
1195  Assert(!osastate->sort_done);
1196 
1197  /* insert the hypothetical row into the sort */
1198  slot = osastate->qstate->tupslot;
1199  ExecClearTuple(slot);
1200  for (i = 0; i < nargs; i++)
1201  {
1202  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1203  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1204  }
1205  slot->tts_values[i] = Int32GetDatum(flag);
1206  slot->tts_isnull[i] = false;
1207  ExecStoreVirtualTuple(slot);
1208 
1209  tuplesort_puttupleslot(osastate->sortstate, slot);
1210 
1211  /* finish the sort */
1212  tuplesort_performsort(osastate->sortstate);
1213  osastate->sort_done = true;
1214 
1215  /* iterate till we find the hypothetical row */
1216  while (tuplesort_gettupleslot(osastate->sortstate, true, true, slot, NULL))
1217  {
1218  bool isnull;
1219  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1220 
1221  if (!isnull && DatumGetInt32(d) != 0)
1222  break;
1223 
1224  rank++;
1225 
1227  }
1228 
1229  ExecClearTuple(slot);
1230 
1231  return rank;
1232 }
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1964
OSAPerQueryState * qstate
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define DatumGetInt32(X)
Definition: postgres.h:472
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
TupleTableSlot * tupslot
Datum * tts_values
Definition: tuptable.h:126
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2332
bool * tts_isnull
Definition: tuptable.h:128
char * flag(int b)
Definition: test-ctype.c:33
uintptr_t Datum
Definition: postgres.h:367
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:381
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:745
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
#define PG_NARGS()
Definition: fmgr.h:203
#define Int32GetDatum(X)
Definition: postgres.h:479
#define elog(elevel,...)
Definition: elog.h:214
int i
static void hypothetical_check_argtypes(FunctionCallInfo fcinfo, int nargs, TupleDesc tupdesc)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1608

◆ hypothetical_rank_final()

Datum hypothetical_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1239 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_INT64.

1240 {
1241  int64 rank;
1242  int64 rowcount;
1243 
1244  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1245 
1246  PG_RETURN_INT64(rank);
1247 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:366
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)

◆ interval_lerp()

static Datum interval_lerp ( Datum  lo,
Datum  hi,
double  pct 
)
static

Definition at line 507 of file orderedsetaggs.c.

References DirectFunctionCall2, Float8GetDatumFast, interval_mi(), interval_mul(), and interval_pl().

Referenced by percentile_cont_interval_final(), and percentile_cont_interval_multi_final().

508 {
509  Datum diff_result = DirectFunctionCall2(interval_mi, hi, lo);
511  diff_result,
512  Float8GetDatumFast(pct));
513 
514  return DirectFunctionCall2(interval_pl, mul_result, lo);
515 }
Datum interval_mi(PG_FUNCTION_ARGS)
Definition: timestamp.c:3122
Datum interval_pl(PG_FUNCTION_ARGS)
Definition: timestamp.c:3088
uintptr_t Datum
Definition: postgres.h:367
#define Float8GetDatumFast(X)
Definition: postgres.h:761
Datum interval_mul(PG_FUNCTION_ARGS)
Definition: timestamp.c:3162
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:626

◆ mode_final()

Datum mode_final ( PG_FUNCTION_ARGS  )

Definition at line 1029 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, CHECK_FOR_INTERRUPTS, DatumGetBool, DatumGetPointer, OSAPerQueryState::eqOperator, OSAPerQueryState::equalfn, fmgr_info_cxt(), FmgrInfo::fn_oid, FunctionCall2Coll(), get_opcode(), OSAPerGroupState::number_of_rows, OidIsValid, pfree(), PG_ARGISNULL, PG_GET_COLLATION, PG_GETARG_POINTER, PG_RETURN_DATUM, PG_RETURN_NULL, OSAPerQueryState::qcontext, OSAPerGroupState::qstate, OSAPerGroupState::sort_done, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), OSAPerQueryState::typByVal, and val.

1030 {
1031  OSAPerGroupState *osastate;
1032  Datum val;
1033  bool isnull;
1034  Datum mode_val = (Datum) 0;
1035  int64 mode_freq = 0;
1036  Datum last_val = (Datum) 0;
1037  int64 last_val_freq = 0;
1038  bool last_val_is_mode = false;
1039  FmgrInfo *equalfn;
1040  Datum abbrev_val = (Datum) 0;
1041  Datum last_abbrev_val = (Datum) 0;
1042  bool shouldfree;
1043 
1045 
1046  /* If there were no regular rows, the result is NULL */
1047  if (PG_ARGISNULL(0))
1048  PG_RETURN_NULL();
1049 
1050  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1051 
1052  /* number_of_rows could be zero if we only saw NULL input values */
1053  if (osastate->number_of_rows == 0)
1054  PG_RETURN_NULL();
1055 
1056  /* Look up the equality function for the datatype, if we didn't already */
1057  equalfn = &(osastate->qstate->equalfn);
1058  if (!OidIsValid(equalfn->fn_oid))
1059  fmgr_info_cxt(get_opcode(osastate->qstate->eqOperator), equalfn,
1060  osastate->qstate->qcontext);
1061 
1062  shouldfree = !(osastate->qstate->typByVal);
1063 
1064  /* Finish the sort, or rescan if we already did */
1065  if (!osastate->sort_done)
1066  {
1067  tuplesort_performsort(osastate->sortstate);
1068  osastate->sort_done = true;
1069  }
1070  else
1071  tuplesort_rescan(osastate->sortstate);
1072 
1073  /* Scan tuples and count frequencies */
1074  while (tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, &abbrev_val))
1075  {
1076  /* we don't expect any nulls, but ignore them if found */
1077  if (isnull)
1078  continue;
1079 
1080  if (last_val_freq == 0)
1081  {
1082  /* first nonnull value - it's the mode for now */
1083  mode_val = last_val = val;
1084  mode_freq = last_val_freq = 1;
1085  last_val_is_mode = true;
1086  last_abbrev_val = abbrev_val;
1087  }
1088  else if (abbrev_val == last_abbrev_val &&
1089  DatumGetBool(FunctionCall2Coll(equalfn, PG_GET_COLLATION(), val, last_val)))
1090  {
1091  /* value equal to previous value, count it */
1092  if (last_val_is_mode)
1093  mode_freq++; /* needn't maintain last_val_freq */
1094  else if (++last_val_freq > mode_freq)
1095  {
1096  /* last_val becomes new mode */
1097  if (shouldfree)
1098  pfree(DatumGetPointer(mode_val));
1099  mode_val = last_val;
1100  mode_freq = last_val_freq;
1101  last_val_is_mode = true;
1102  }
1103  if (shouldfree)
1104  pfree(DatumGetPointer(val));
1105  }
1106  else
1107  {
1108  /* val should replace last_val */
1109  if (shouldfree && !last_val_is_mode)
1110  pfree(DatumGetPointer(last_val));
1111  last_val = val;
1112  /* avoid equality function calls by reusing abbreviated keys */
1113  last_abbrev_val = abbrev_val;
1114  last_val_freq = 1;
1115  last_val_is_mode = false;
1116  }
1117 
1119  }
1120 
1121  if (shouldfree && !last_val_is_mode)
1122  pfree(DatumGetPointer(last_val));
1123 
1124  if (mode_freq)
1125  PG_RETURN_DATUM(mode_val);
1126  else
1127  PG_RETURN_NULL();
1128 }
Definition: fmgr.h:56
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2418
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1964
OSAPerQueryState * qstate
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1152
#define OidIsValid(objectId)
Definition: c.h:651
#define PG_GET_COLLATION()
Definition: fmgr.h:198
MemoryContext qcontext
void pfree(void *pointer)
Definition: mcxt.c:1056
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
void tuplesort_rescan(Tuplesortstate *state)
Definition: tuplesort.c:3201
#define DatumGetBool(X)
Definition: postgres.h:393
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
uintptr_t Datum
Definition: postgres.h:367
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:352
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1202
Oid fn_oid
Definition: fmgr.h:59
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:745
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
#define DatumGetPointer(X)
Definition: postgres.h:549
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
long val
Definition: informix.c:664
#define PG_RETURN_NULL()
Definition: fmgr.h:344

◆ ordered_set_shutdown()

static void ordered_set_shutdown ( Datum  arg)
static

Definition at line 335 of file orderedsetaggs.c.

References DatumGetPointer, ExecClearTuple(), OSAPerGroupState::qstate, OSAPerGroupState::sortstate, tuplesort_end(), and OSAPerQueryState::tupslot.

Referenced by ordered_set_startup().

336 {
338 
339  /* Tuplesort object might have temp files. */
340  if (osastate->sortstate)
341  tuplesort_end(osastate->sortstate);
342  osastate->sortstate = NULL;
343  /* The tupleslot probably can't be holding a pin, but let's be safe. */
344  if (osastate->qstate->tupslot)
345  ExecClearTuple(osastate->qstate->tupslot);
346 }
OSAPerQueryState * qstate
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
TupleTableSlot * tupslot
Tuplesortstate * sortstate
#define DatumGetPointer(X)
Definition: postgres.h:549
void * arg
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1388

◆ ordered_set_startup()

static OSAPerGroupState* ordered_set_startup ( FunctionCallInfo  fcinfo,
bool  use_tuples 
)
static

Definition at line 115 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), AggGetAggref(), Aggref::aggkind, Aggref::aggorder, OSAPerQueryState::aggref, AggRegisterCallback(), AggStateIsShared(), Aggref::args, Assert, CreateTemplateTupleDesc(), elog, SortGroupClause::eqop, OSAPerQueryState::eqOperator, OSAPerQueryState::eqOperators, ERROR, ExecTypeFromTL(), TargetEntry::expr, exprCollation(), exprType(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, FreeTupleDesc(), OSAPerGroupState::gcontext, get_sortgroupclause_tle(), get_typlenbyvalalign(), i, InvalidOid, lfirst, linitial, list_length(), MakeSingleTupleTableSlot(), MemoryContextSwitchTo(), TupleDescData::natts, SortGroupClause::nulls_first, OSAPerGroupState::number_of_rows, OSAPerQueryState::numSortCols, OidIsValid, ordered_set_shutdown(), palloc(), palloc0(), PointerGetDatum, OSAPerQueryState::qcontext, OSAPerGroupState::qstate, OSAPerQueryState::rescan_needed, TargetEntry::resno, OSAPerGroupState::sort_done, OSAPerQueryState::sortColIdx, OSAPerQueryState::sortCollation, OSAPerQueryState::sortCollations, OSAPerQueryState::sortColType, OSAPerQueryState::sortNullsFirst, OSAPerQueryState::sortNullsFirsts, SortGroupClause::sortop, OSAPerQueryState::sortOperator, OSAPerQueryState::sortOperators, OSAPerGroupState::sortstate, TTSOpsMinimalTuple, OSAPerQueryState::tupdesc, TupleDescCopyEntry(), TupleDescInitEntry(), tuplesort_begin_datum(), tuplesort_begin_heap(), OSAPerQueryState::tupslot, OSAPerQueryState::typAlign, OSAPerQueryState::typByVal, OSAPerQueryState::typLen, and work_mem.

Referenced by ordered_set_transition(), and ordered_set_transition_multi().

116 {
117  OSAPerGroupState *osastate;
118  OSAPerQueryState *qstate;
119  MemoryContext gcontext;
120  MemoryContext oldcontext;
121 
122  /*
123  * Check we're called as aggregate (and not a window function), and get
124  * the Agg node's group-lifespan context (which might change from group to
125  * group, so we shouldn't cache it in the per-query state).
126  */
127  if (AggCheckCallContext(fcinfo, &gcontext) != AGG_CONTEXT_AGGREGATE)
128  elog(ERROR, "ordered-set aggregate called in non-aggregate context");
129 
130  /*
131  * We keep a link to the per-query state in fn_extra; if it's not there,
132  * create it, and do the per-query setup we need.
133  */
134  qstate = (OSAPerQueryState *) fcinfo->flinfo->fn_extra;
135  if (qstate == NULL)
136  {
137  Aggref *aggref;
138  MemoryContext qcontext;
139  List *sortlist;
140  int numSortCols;
141 
142  /* Get the Aggref so we can examine aggregate's arguments */
143  aggref = AggGetAggref(fcinfo);
144  if (!aggref)
145  elog(ERROR, "ordered-set aggregate called in non-aggregate context");
146  if (!AGGKIND_IS_ORDERED_SET(aggref->aggkind))
147  elog(ERROR, "ordered-set aggregate support function called for non-ordered-set aggregate");
148 
149  /*
150  * Prepare per-query structures in the fn_mcxt, which we assume is the
151  * executor's per-query context; in any case it's the right place to
152  * keep anything found via fn_extra.
153  */
154  qcontext = fcinfo->flinfo->fn_mcxt;
155  oldcontext = MemoryContextSwitchTo(qcontext);
156 
157  qstate = (OSAPerQueryState *) palloc0(sizeof(OSAPerQueryState));
158  qstate->aggref = aggref;
159  qstate->qcontext = qcontext;
160 
161  /* We need to support rescans if the trans state is shared */
162  qstate->rescan_needed = AggStateIsShared(fcinfo);
163 
164  /* Extract the sort information */
165  sortlist = aggref->aggorder;
166  numSortCols = list_length(sortlist);
167 
168  if (use_tuples)
169  {
170  bool ishypothetical = (aggref->aggkind == AGGKIND_HYPOTHETICAL);
171  ListCell *lc;
172  int i;
173 
174  if (ishypothetical)
175  numSortCols++; /* make space for flag column */
176  qstate->numSortCols = numSortCols;
177  qstate->sortColIdx = (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
178  qstate->sortOperators = (Oid *) palloc(numSortCols * sizeof(Oid));
179  qstate->eqOperators = (Oid *) palloc(numSortCols * sizeof(Oid));
180  qstate->sortCollations = (Oid *) palloc(numSortCols * sizeof(Oid));
181  qstate->sortNullsFirsts = (bool *) palloc(numSortCols * sizeof(bool));
182 
183  i = 0;
184  foreach(lc, sortlist)
185  {
186  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
187  TargetEntry *tle = get_sortgroupclause_tle(sortcl,
188  aggref->args);
189 
190  /* the parser should have made sure of this */
191  Assert(OidIsValid(sortcl->sortop));
192 
193  qstate->sortColIdx[i] = tle->resno;
194  qstate->sortOperators[i] = sortcl->sortop;
195  qstate->eqOperators[i] = sortcl->eqop;
196  qstate->sortCollations[i] = exprCollation((Node *) tle->expr);
197  qstate->sortNullsFirsts[i] = sortcl->nulls_first;
198  i++;
199  }
200 
201  if (ishypothetical)
202  {
203  /* Add an integer flag column as the last sort column */
204  qstate->sortColIdx[i] = list_length(aggref->args) + 1;
205  qstate->sortOperators[i] = Int4LessOperator;
206  qstate->eqOperators[i] = Int4EqualOperator;
207  qstate->sortCollations[i] = InvalidOid;
208  qstate->sortNullsFirsts[i] = false;
209  i++;
210  }
211 
212  Assert(i == numSortCols);
213 
214  /*
215  * Get a tupledesc corresponding to the aggregated inputs
216  * (including sort expressions) of the agg.
217  */
218  qstate->tupdesc = ExecTypeFromTL(aggref->args);
219 
220  /* If we need a flag column, hack the tupledesc to include that */
221  if (ishypothetical)
222  {
223  TupleDesc newdesc;
224  int natts = qstate->tupdesc->natts;
225 
226  newdesc = CreateTemplateTupleDesc(natts + 1);
227  for (i = 1; i <= natts; i++)
228  TupleDescCopyEntry(newdesc, i, qstate->tupdesc, i);
229 
230  TupleDescInitEntry(newdesc,
231  (AttrNumber) ++natts,
232  "flag",
233  INT4OID,
234  -1,
235  0);
236 
237  FreeTupleDesc(qstate->tupdesc);
238  qstate->tupdesc = newdesc;
239  }
240 
241  /* Create slot we'll use to store/retrieve rows */
242  qstate->tupslot = MakeSingleTupleTableSlot(qstate->tupdesc,
244  }
245  else
246  {
247  /* Sort single datums */
248  SortGroupClause *sortcl;
249  TargetEntry *tle;
250 
251  if (numSortCols != 1 || aggref->aggkind == AGGKIND_HYPOTHETICAL)
252  elog(ERROR, "ordered-set aggregate support function does not support multiple aggregated columns");
253 
254  sortcl = (SortGroupClause *) linitial(sortlist);
255  tle = get_sortgroupclause_tle(sortcl, aggref->args);
256 
257  /* the parser should have made sure of this */
258  Assert(OidIsValid(sortcl->sortop));
259 
260  /* Save sort ordering info */
261  qstate->sortColType = exprType((Node *) tle->expr);
262  qstate->sortOperator = sortcl->sortop;
263  qstate->eqOperator = sortcl->eqop;
264  qstate->sortCollation = exprCollation((Node *) tle->expr);
265  qstate->sortNullsFirst = sortcl->nulls_first;
266 
267  /* Save datatype info */
269  &qstate->typLen,
270  &qstate->typByVal,
271  &qstate->typAlign);
272  }
273 
274  fcinfo->flinfo->fn_extra = (void *) qstate;
275 
276  MemoryContextSwitchTo(oldcontext);
277  }
278 
279  /* Now build the stuff we need in group-lifespan context */
280  oldcontext = MemoryContextSwitchTo(gcontext);
281 
282  osastate = (OSAPerGroupState *) palloc(sizeof(OSAPerGroupState));
283  osastate->qstate = qstate;
284  osastate->gcontext = gcontext;
285 
286  /*
287  * Initialize tuplesort object.
288  */
289  if (use_tuples)
290  osastate->sortstate = tuplesort_begin_heap(qstate->tupdesc,
291  qstate->numSortCols,
292  qstate->sortColIdx,
293  qstate->sortOperators,
294  qstate->sortCollations,
295  qstate->sortNullsFirsts,
296  work_mem,
297  NULL,
298  qstate->rescan_needed);
299  else
300  osastate->sortstate = tuplesort_begin_datum(qstate->sortColType,
301  qstate->sortOperator,
302  qstate->sortCollation,
303  qstate->sortNullsFirst,
304  work_mem,
305  NULL,
306  qstate->rescan_needed);
307 
308  osastate->number_of_rows = 0;
309  osastate->sort_done = false;
310 
311  /* Now register a shutdown callback to clean things up at end of group */
312  AggRegisterCallback(fcinfo,
314  PointerGetDatum(osastate));
315 
316  MemoryContextSwitchTo(oldcontext);
317 
318  return osastate;
319 }
MemoryContext gcontext
OSAPerQueryState * qstate
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:389
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, bool randomAccess)
Definition: tuplesort.c:1171
MemoryContext fn_mcxt
Definition: fmgr.h:65
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1208
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2159
#define PointerGetDatum(X)
Definition: postgres.h:556
TupleTableSlot * tupslot
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Definition: nodes.h:529
List * args
Definition: primnodes.h:319
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, SortCoordinate coordinate, bool randomAccess)
Definition: tuplesort.c:878
MemoryContext qcontext
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
static void ordered_set_shutdown(Datum arg)
void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, TupleDesc src, AttrNumber srcAttno)
Definition: tupdesc.c:271
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
bool AggStateIsShared(FunctionCallInfo fcinfo)
Definition: nodeAgg.c:4878
List * aggorder
Definition: primnodes.h:320
AttrNumber resno
Definition: primnodes.h:1408
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
void * palloc0(Size size)
Definition: mcxt.c:980
FmgrInfo * flinfo
Definition: fmgr.h:87
int work_mem
Definition: globals.c:121
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
Tuplesortstate * sortstate
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:169
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:719
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
void * fn_extra
Definition: fmgr.h:64
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:313
void AggRegisterCallback(FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
Definition: nodeAgg.c:4917
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int i
char aggkind
Definition: primnodes.h:326
Definition: pg_list.h:50
AttrNumber * sortColIdx
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
Aggref * AggGetAggref(FunctionCallInfo fcinfo)
Definition: nodeAgg.c:4818

◆ ordered_set_transition()

Datum ordered_set_transition ( PG_FUNCTION_ARGS  )

Definition at line 354 of file orderedsetaggs.c.

References OSAPerGroupState::number_of_rows, ordered_set_startup(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_RETURN_POINTER, OSAPerGroupState::sortstate, and tuplesort_putdatum().

355 {
356  OSAPerGroupState *osastate;
357 
358  /* If first call, create the transition state workspace */
359  if (PG_ARGISNULL(0))
360  osastate = ordered_set_startup(fcinfo, false);
361  else
362  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
363 
364  /* Load the datum into the tuplesort object, but only if it's not null */
365  if (!PG_ARGISNULL(1))
366  {
367  tuplesort_putdatum(osastate->sortstate, PG_GETARG_DATUM(1), false);
368  osastate->number_of_rows++;
369  }
370 
371  PG_RETURN_POINTER(osastate);
372 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:360
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Definition: tuplesort.c:1729
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
static OSAPerGroupState * ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples)
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
Tuplesortstate * sortstate

◆ ordered_set_transition_multi()

Datum ordered_set_transition_multi ( PG_FUNCTION_ARGS  )

Definition at line 379 of file orderedsetaggs.c.

References Aggref::aggkind, OSAPerQueryState::aggref, Assert, ExecClearTuple(), ExecStoreVirtualTuple(), i, Int32GetDatum, TupleDescData::natts, OSAPerGroupState::number_of_rows, ordered_set_startup(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_NARGS, PG_RETURN_POINTER, OSAPerGroupState::qstate, OSAPerGroupState::sortstate, TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, TupleTableSlot::tts_values, tuplesort_puttupleslot(), and OSAPerQueryState::tupslot.

380 {
381  OSAPerGroupState *osastate;
382  TupleTableSlot *slot;
383  int nargs;
384  int i;
385 
386  /* If first call, create the transition state workspace */
387  if (PG_ARGISNULL(0))
388  osastate = ordered_set_startup(fcinfo, true);
389  else
390  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
391 
392  /* Form a tuple from all the other inputs besides the transition value */
393  slot = osastate->qstate->tupslot;
394  ExecClearTuple(slot);
395  nargs = PG_NARGS() - 1;
396  for (i = 0; i < nargs; i++)
397  {
398  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
399  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
400  }
401  if (osastate->qstate->aggref->aggkind == AGGKIND_HYPOTHETICAL)
402  {
403  /* Add a zero flag value to mark this row as a normal input row */
404  slot->tts_values[i] = Int32GetDatum(0);
405  slot->tts_isnull[i] = false;
406  i++;
407  }
408  Assert(i == slot->tts_tupleDescriptor->natts);
409  ExecStoreVirtualTuple(slot);
410 
411  /* Load the row into the tuplesort object */
412  tuplesort_puttupleslot(osastate->sortstate, slot);
413  osastate->number_of_rows++;
414 
415  PG_RETURN_POINTER(osastate);
416 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:360
OSAPerQueryState * qstate
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
TupleTableSlot * tupslot
Datum * tts_values
Definition: tuptable.h:126
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
static OSAPerGroupState * ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples)
bool * tts_isnull
Definition: tuptable.h:128
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:745
Tuplesortstate * sortstate
#define PG_NARGS()
Definition: fmgr.h:203
#define Int32GetDatum(X)
Definition: postgres.h:479
int i
char aggkind
Definition: primnodes.h:326
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1608

◆ pct_info_cmp()

static int pct_info_cmp ( const void *  pa,
const void *  pb 
)
static

Definition at line 639 of file orderedsetaggs.c.

References pct_info::first_row, and pct_info::second_row.

Referenced by setup_pct_info().

640 {
641  const struct pct_info *a = (const struct pct_info *) pa;
642  const struct pct_info *b = (const struct pct_info *) pb;
643 
644  if (a->first_row != b->first_row)
645  return (a->first_row < b->first_row) ? -1 : 1;
646  if (a->second_row != b->second_row)
647  return (a->second_row < b->second_row) ? -1 : 1;
648  return 0;
649 }
int64 second_row
int64 first_row

◆ percentile_cont_final_common()

static Datum percentile_cont_final_common ( FunctionCallInfo  fcinfo,
Oid  expect_type,
LerpFunc  lerpfunc 
)
static

Definition at line 521 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, elog, ereport, errcode(), errmsg(), ERROR, OSAPerGroupState::number_of_rows, PG_ARGISNULL, PG_GETARG_FLOAT8, PG_GETARG_POINTER, PG_RETURN_DATUM, PG_RETURN_NULL, OSAPerGroupState::qstate, OSAPerGroupState::sort_done, OSAPerQueryState::sortColType, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), tuplesort_skiptuples(), and val.

Referenced by percentile_cont_float8_final(), and percentile_cont_interval_final().

524 {
525  OSAPerGroupState *osastate;
526  double percentile;
527  int64 first_row = 0;
528  int64 second_row = 0;
529  Datum val;
530  Datum first_val;
531  Datum second_val;
532  double proportion;
533  bool isnull;
534 
536 
537  /* Get and check the percentile argument */
538  if (PG_ARGISNULL(1))
539  PG_RETURN_NULL();
540 
541  percentile = PG_GETARG_FLOAT8(1);
542 
543  if (percentile < 0 || percentile > 1 || isnan(percentile))
544  ereport(ERROR,
545  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
546  errmsg("percentile value %g is not between 0 and 1",
547  percentile)));
548 
549  /* If there were no regular rows, the result is NULL */
550  if (PG_ARGISNULL(0))
551  PG_RETURN_NULL();
552 
553  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
554 
555  /* number_of_rows could be zero if we only saw NULL input values */
556  if (osastate->number_of_rows == 0)
557  PG_RETURN_NULL();
558 
559  Assert(expect_type == osastate->qstate->sortColType);
560 
561  /* Finish the sort, or rescan if we already did */
562  if (!osastate->sort_done)
563  {
564  tuplesort_performsort(osastate->sortstate);
565  osastate->sort_done = true;
566  }
567  else
568  tuplesort_rescan(osastate->sortstate);
569 
570  first_row = floor(percentile * (osastate->number_of_rows - 1));
571  second_row = ceil(percentile * (osastate->number_of_rows - 1));
572 
573  Assert(first_row < osastate->number_of_rows);
574 
575  if (!tuplesort_skiptuples(osastate->sortstate, first_row, true))
576  elog(ERROR, "missing row in percentile_cont");
577 
578  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val, &isnull, NULL))
579  elog(ERROR, "missing row in percentile_cont");
580  if (isnull)
581  PG_RETURN_NULL();
582 
583  if (first_row == second_row)
584  {
585  val = first_val;
586  }
587  else
588  {
589  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val, &isnull, NULL))
590  elog(ERROR, "missing row in percentile_cont");
591 
592  if (isnull)
593  PG_RETURN_NULL();
594 
595  proportion = (percentile * (osastate->number_of_rows - 1)) - first_row;
596  val = lerpfunc(first_val, second_val, proportion);
597  }
598 
599  PG_RETURN_DATUM(val);
600 }
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:281
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2418
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1964
OSAPerQueryState * qstate
int errcode(int sqlerrcode)
Definition: elog.c:610
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
int64 second_row
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
void tuplesort_rescan(Tuplesortstate *state)
Definition: tuplesort.c:3201
int64 first_row
uintptr_t Datum
Definition: postgres.h:367
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:352
#define ereport(elevel,...)
Definition: elog.h:144
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:745
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
double proportion
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
Definition: tuplesort.c:2458
long val
Definition: informix.c:664
#define PG_RETURN_NULL()
Definition: fmgr.h:344

◆ percentile_cont_float8_final()

Datum percentile_cont_float8_final ( PG_FUNCTION_ARGS  )

Definition at line 606 of file orderedsetaggs.c.

References float8_lerp(), and percentile_cont_final_common().

607 {
608  return percentile_cont_final_common(fcinfo, FLOAT8OID, float8_lerp);
609 }
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)
static Datum float8_lerp(Datum lo, Datum hi, double pct)

◆ percentile_cont_float8_multi_final()

Datum percentile_cont_float8_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 1000 of file orderedsetaggs.c.

References float8_lerp(), FLOAT8PASSBYVAL, and percentile_cont_multi_final_common().

1001 {
1002  return percentile_cont_multi_final_common(fcinfo,
1003  FLOAT8OID,
1004  /* hard-wired info on type float8 */
1005  sizeof(float8),
1007  TYPALIGN_DOUBLE,
1008  float8_lerp);
1009 }
double float8
Definition: c.h:498
#define FLOAT8PASSBYVAL
Definition: c.h:503
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)
static Datum float8_lerp(Datum lo, Datum hi, double pct)

◆ percentile_cont_interval_final()

Datum percentile_cont_interval_final ( PG_FUNCTION_ARGS  )

Definition at line 615 of file orderedsetaggs.c.

References interval_lerp(), and percentile_cont_final_common().

616 {
617  return percentile_cont_final_common(fcinfo, INTERVALOID, interval_lerp);
618 }
static Datum interval_lerp(Datum lo, Datum hi, double pct)
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)

◆ percentile_cont_interval_multi_final()

Datum percentile_cont_interval_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 1015 of file orderedsetaggs.c.

References interval_lerp(), and percentile_cont_multi_final_common().

1016 {
1017  return percentile_cont_multi_final_common(fcinfo,
1018  INTERVALOID,
1019  /* hard-wired info on type interval */
1020  16, false, TYPALIGN_DOUBLE,
1021  interval_lerp);
1022 }
static Datum interval_lerp(Datum lo, Datum hi, double pct)
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)

◆ percentile_cont_multi_final_common()

static Datum percentile_cont_multi_final_common ( FunctionCallInfo  fcinfo,
Oid  expect_type,
int16  typLen,
bool  typByVal,
char  typAlign,
LerpFunc  lerpfunc 
)
static

Definition at line 842 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array(), elog, ERROR, pct_info::first_row, FLOAT8PASSBYVAL, i, idx(), pct_info::idx, OSAPerGroupState::number_of_rows, palloc(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_POINTER, PG_RETURN_NULL, PG_RETURN_POINTER, pct_info::proportion, OSAPerGroupState::qstate, pct_info::second_row, setup_pct_info(), OSAPerGroupState::sort_done, OSAPerQueryState::sortColType, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), and tuplesort_skiptuples().

Referenced by percentile_cont_float8_multi_final(), and percentile_cont_interval_multi_final().

846 {
847  OSAPerGroupState *osastate;
848  ArrayType *param;
849  Datum *percentiles_datum;
850  bool *percentiles_null;
851  int num_percentiles;
852  struct pct_info *pct_info;
853  Datum *result_datum;
854  bool *result_isnull;
855  int64 rownum = 0;
856  Datum first_val = (Datum) 0;
857  Datum second_val = (Datum) 0;
858  bool isnull;
859  int i;
860 
862 
863  /* If there were no regular rows, the result is NULL */
864  if (PG_ARGISNULL(0))
865  PG_RETURN_NULL();
866 
867  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
868 
869  /* number_of_rows could be zero if we only saw NULL input values */
870  if (osastate->number_of_rows == 0)
871  PG_RETURN_NULL();
872 
873  Assert(expect_type == osastate->qstate->sortColType);
874 
875  /* Deconstruct the percentile-array input */
876  if (PG_ARGISNULL(1))
877  PG_RETURN_NULL();
878  param = PG_GETARG_ARRAYTYPE_P(1);
879 
880  deconstruct_array(param, FLOAT8OID,
881  /* hard-wired info on type float8 */
882  sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE,
883  &percentiles_datum,
884  &percentiles_null,
885  &num_percentiles);
886 
887  if (num_percentiles == 0)
889 
890  pct_info = setup_pct_info(num_percentiles,
891  percentiles_datum,
892  percentiles_null,
893  osastate->number_of_rows,
894  true);
895 
896  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
897  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
898 
899  /*
900  * Start by dealing with any nulls in the param array - those are sorted
901  * to the front on row=0, so set the corresponding result indexes to null
902  */
903  for (i = 0; i < num_percentiles; i++)
904  {
905  int idx = pct_info[i].idx;
906 
907  if (pct_info[i].first_row > 0)
908  break;
909 
910  result_datum[idx] = (Datum) 0;
911  result_isnull[idx] = true;
912  }
913 
914  /*
915  * If there's anything left after doing the nulls, then grind the input
916  * and extract the needed values
917  */
918  if (i < num_percentiles)
919  {
920  /* Finish the sort, or rescan if we already did */
921  if (!osastate->sort_done)
922  {
923  tuplesort_performsort(osastate->sortstate);
924  osastate->sort_done = true;
925  }
926  else
927  tuplesort_rescan(osastate->sortstate);
928 
929  for (; i < num_percentiles; i++)
930  {
931  int64 first_row = pct_info[i].first_row;
932  int64 second_row = pct_info[i].second_row;
933  int idx = pct_info[i].idx;
934 
935  /*
936  * Advance to first_row, if not already there. Note that we might
937  * already have rownum beyond first_row, in which case first_val
938  * is already correct. (This occurs when interpolating between
939  * the same two input rows as for the previous percentile.)
940  */
941  if (first_row > rownum)
942  {
943  if (!tuplesort_skiptuples(osastate->sortstate, first_row - rownum - 1, true))
944  elog(ERROR, "missing row in percentile_cont");
945 
946  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val,
947  &isnull, NULL) || isnull)
948  elog(ERROR, "missing row in percentile_cont");
949 
950  rownum = first_row;
951  /* Always advance second_val to be latest input value */
952  second_val = first_val;
953  }
954  else if (first_row == rownum)
955  {
956  /*
957  * We are already at the desired row, so we must previously
958  * have read its value into second_val (and perhaps first_val
959  * as well, but this assignment is harmless in that case).
960  */
961  first_val = second_val;
962  }
963 
964  /* Fetch second_row if needed */
965  if (second_row > rownum)
966  {
967  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val,
968  &isnull, NULL) || isnull)
969  elog(ERROR, "missing row in percentile_cont");
970  rownum++;
971  }
972  /* We should now certainly be on second_row exactly */
973  Assert(second_row == rownum);
974 
975  /* Compute appropriate result */
976  if (second_row > first_row)
977  result_datum[idx] = lerpfunc(first_val, second_val,
978  pct_info[i].proportion);
979  else
980  result_datum[idx] = first_val;
981 
982  result_isnull[idx] = false;
983  }
984  }
985 
986  /* We make the output array the same shape as the input */
987  PG_RETURN_POINTER(construct_md_array(result_datum, result_isnull,
988  ARR_NDIM(param),
989  ARR_DIMS(param), ARR_LBOUND(param),
990  expect_type,
991  typLen,
992  typByVal,
993  typAlign));
994 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:360
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2418
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1964
OSAPerQueryState * qstate
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:259
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3432
#define ARR_LBOUND(a)
Definition: array.h:284
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
int64 second_row
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:498
#define ARR_DIMS(a)
Definition: array.h:282
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
void tuplesort_rescan(Tuplesortstate *state)
Definition: tuplesort.c:3201
int64 first_row
uintptr_t Datum
Definition: postgres.h:367
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define FLOAT8PASSBYVAL
Definition: c.h:503
#define Assert(condition)
Definition: c.h:745
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
#define ARR_NDIM(a)
Definition: array.h:278
double proportion
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3483
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int i
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:3348
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
Definition: tuplesort.c:2458
#define PG_RETURN_NULL()
Definition: fmgr.h:344

◆ percentile_disc_final()

Datum percentile_disc_final ( PG_FUNCTION_ARGS  )

Definition at line 423 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, elog, ereport, errcode(), errmsg(), ERROR, OSAPerGroupState::number_of_rows, PG_ARGISNULL, PG_GETARG_FLOAT8, PG_GETARG_POINTER, PG_RETURN_DATUM, PG_RETURN_NULL, OSAPerGroupState::sort_done, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), tuplesort_skiptuples(), and val.

424 {
425  OSAPerGroupState *osastate;
426  double percentile;
427  Datum val;
428  bool isnull;
429  int64 rownum;
430 
432 
433  /* Get and check the percentile argument */
434  if (PG_ARGISNULL(1))
435  PG_RETURN_NULL();
436 
437  percentile = PG_GETARG_FLOAT8(1);
438 
439  if (percentile < 0 || percentile > 1 || isnan(percentile))
440  ereport(ERROR,
441  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
442  errmsg("percentile value %g is not between 0 and 1",
443  percentile)));
444 
445  /* If there were no regular rows, the result is NULL */
446  if (PG_ARGISNULL(0))
447  PG_RETURN_NULL();
448 
449  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
450 
451  /* number_of_rows could be zero if we only saw NULL input values */
452  if (osastate->number_of_rows == 0)
453  PG_RETURN_NULL();
454 
455  /* Finish the sort, or rescan if we already did */
456  if (!osastate->sort_done)
457  {
458  tuplesort_performsort(osastate->sortstate);
459  osastate->sort_done = true;
460  }
461  else
462  tuplesort_rescan(osastate->sortstate);
463 
464  /*----------
465  * We need the smallest K such that (K/N) >= percentile.
466  * N>0, therefore K >= N*percentile, therefore K = ceil(N*percentile).
467  * So we skip K-1 rows (if K>0) and return the next row fetched.
468  *----------
469  */
470  rownum = (int64) ceil(percentile * osastate->number_of_rows);
471  Assert(rownum <= osastate->number_of_rows);
472 
473  if (rownum > 1)
474  {
475  if (!tuplesort_skiptuples(osastate->sortstate, rownum - 1, true))
476  elog(ERROR, "missing row in percentile_disc");
477  }
478 
479  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
480  elog(ERROR, "missing row in percentile_disc");
481 
482  /* We shouldn't have stored any nulls, but do the right thing anyway */
483  if (isnull)
484  PG_RETURN_NULL();
485  else
486  PG_RETURN_DATUM(val);
487 }
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:281
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2418
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1964
int errcode(int sqlerrcode)
Definition: elog.c:610
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
void tuplesort_rescan(Tuplesortstate *state)
Definition: tuplesort.c:3201
uintptr_t Datum
Definition: postgres.h:367
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:352
#define ereport(elevel,...)
Definition: elog.h:144
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:745
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
Definition: tuplesort.c:2458
long val
Definition: informix.c:664
#define PG_RETURN_NULL()
Definition: fmgr.h:344

◆ percentile_disc_multi_final()

Datum percentile_disc_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 724 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array(), elog, ERROR, pct_info::first_row, FLOAT8PASSBYVAL, i, idx(), pct_info::idx, OSAPerGroupState::number_of_rows, palloc(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_POINTER, PG_RETURN_NULL, PG_RETURN_POINTER, OSAPerGroupState::qstate, setup_pct_info(), OSAPerGroupState::sort_done, OSAPerQueryState::sortColType, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), tuplesort_skiptuples(), OSAPerQueryState::typAlign, OSAPerQueryState::typByVal, OSAPerQueryState::typLen, and val.

725 {
726  OSAPerGroupState *osastate;
727  ArrayType *param;
728  Datum *percentiles_datum;
729  bool *percentiles_null;
730  int num_percentiles;
731  struct pct_info *pct_info;
732  Datum *result_datum;
733  bool *result_isnull;
734  int64 rownum = 0;
735  Datum val = (Datum) 0;
736  bool isnull = true;
737  int i;
738 
740 
741  /* If there were no regular rows, the result is NULL */
742  if (PG_ARGISNULL(0))
743  PG_RETURN_NULL();
744 
745  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
746 
747  /* number_of_rows could be zero if we only saw NULL input values */
748  if (osastate->number_of_rows == 0)
749  PG_RETURN_NULL();
750 
751  /* Deconstruct the percentile-array input */
752  if (PG_ARGISNULL(1))
753  PG_RETURN_NULL();
754  param = PG_GETARG_ARRAYTYPE_P(1);
755 
756  deconstruct_array(param, FLOAT8OID,
757  /* hard-wired info on type float8 */
758  sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE,
759  &percentiles_datum,
760  &percentiles_null,
761  &num_percentiles);
762 
763  if (num_percentiles == 0)
765 
766  pct_info = setup_pct_info(num_percentiles,
767  percentiles_datum,
768  percentiles_null,
769  osastate->number_of_rows,
770  false);
771 
772  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
773  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
774 
775  /*
776  * Start by dealing with any nulls in the param array - those are sorted
777  * to the front on row=0, so set the corresponding result indexes to null
778  */
779  for (i = 0; i < num_percentiles; i++)
780  {
781  int idx = pct_info[i].idx;
782 
783  if (pct_info[i].first_row > 0)
784  break;
785 
786  result_datum[idx] = (Datum) 0;
787  result_isnull[idx] = true;
788  }
789 
790  /*
791  * If there's anything left after doing the nulls, then grind the input
792  * and extract the needed values
793  */
794  if (i < num_percentiles)
795  {
796  /* Finish the sort, or rescan if we already did */
797  if (!osastate->sort_done)
798  {
799  tuplesort_performsort(osastate->sortstate);
800  osastate->sort_done = true;
801  }
802  else
803  tuplesort_rescan(osastate->sortstate);
804 
805  for (; i < num_percentiles; i++)
806  {
807  int64 target_row = pct_info[i].first_row;
808  int idx = pct_info[i].idx;
809 
810  /* Advance to target row, if not already there */
811  if (target_row > rownum)
812  {
813  if (!tuplesort_skiptuples(osastate->sortstate, target_row - rownum - 1, true))
814  elog(ERROR, "missing row in percentile_disc");
815 
816  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
817  elog(ERROR, "missing row in percentile_disc");
818 
819  rownum = target_row;
820  }
821 
822  result_datum[idx] = val;
823  result_isnull[idx] = isnull;
824  }
825  }
826 
827  /* We make the output array the same shape as the input */
828  PG_RETURN_POINTER(construct_md_array(result_datum, result_isnull,
829  ARR_NDIM(param),
830  ARR_DIMS(param),
831  ARR_LBOUND(param),
832  osastate->qstate->sortColType,
833  osastate->qstate->typLen,
834  osastate->qstate->typByVal,
835  osastate->qstate->typAlign));
836 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:360
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2418
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1964
OSAPerQueryState * qstate
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:259
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3432
#define ARR_LBOUND(a)
Definition: array.h:284
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:498
#define ARR_DIMS(a)
Definition: array.h:282
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
void tuplesort_rescan(Tuplesortstate *state)
Definition: tuplesort.c:3201
int64 first_row
uintptr_t Datum
Definition: postgres.h:367
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define FLOAT8PASSBYVAL
Definition: c.h:503
#define Assert(condition)
Definition: c.h:745
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4774
#define ARR_NDIM(a)
Definition: array.h:278
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3483
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int i
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:3348
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
Definition: tuplesort.c:2458
long val
Definition: informix.c:664
#define PG_RETURN_NULL()
Definition: fmgr.h:344

◆ setup_pct_info()

static struct pct_info* setup_pct_info ( int  num_percentiles,
Datum percentiles_datum,
bool percentiles_null,
int64  rowcount,
bool  continuous 
)
static

Definition at line 655 of file orderedsetaggs.c.

References DatumGetFloat8, ereport, errcode(), errmsg(), ERROR, pct_info::first_row, i, pct_info::idx, Max, palloc(), pct_info_cmp(), pct_info::proportion, qsort, and pct_info::second_row.

Referenced by percentile_cont_multi_final_common(), and percentile_disc_multi_final().

660 {
661  struct pct_info *pct_info;
662  int i;
663 
664  pct_info = (struct pct_info *) palloc(num_percentiles * sizeof(struct pct_info));
665 
666  for (i = 0; i < num_percentiles; i++)
667  {
668  pct_info[i].idx = i;
669 
670  if (percentiles_null[i])
671  {
672  /* dummy entry for any NULL in array */
673  pct_info[i].first_row = 0;
674  pct_info[i].second_row = 0;
675  pct_info[i].proportion = 0;
676  }
677  else
678  {
679  double p = DatumGetFloat8(percentiles_datum[i]);
680 
681  if (p < 0 || p > 1 || isnan(p))
682  ereport(ERROR,
683  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
684  errmsg("percentile value %g is not between 0 and 1",
685  p)));
686 
687  if (continuous)
688  {
689  pct_info[i].first_row = 1 + floor(p * (rowcount - 1));
690  pct_info[i].second_row = 1 + ceil(p * (rowcount - 1));
691  pct_info[i].proportion = (p * (rowcount - 1)) - floor(p * (rowcount - 1));
692  }
693  else
694  {
695  /*----------
696  * We need the smallest K such that (K/N) >= percentile.
697  * N>0, therefore K >= N*percentile, therefore
698  * K = ceil(N*percentile); but not less than 1.
699  *----------
700  */
701  int64 row = (int64) ceil(p * rowcount);
702 
703  row = Max(1, row);
704  pct_info[i].first_row = row;
705  pct_info[i].second_row = row;
706  pct_info[i].proportion = 0;
707  }
708  }
709  }
710 
711  /*
712  * The parameter array wasn't necessarily in sorted order, but we need to
713  * visit the rows in order, so sort by first_row/second_row.
714  */
715  qsort(pct_info, num_percentiles, sizeof(struct pct_info), pct_info_cmp);
716 
717  return pct_info;
718 }
int errcode(int sqlerrcode)
Definition: elog.c:610
int64 second_row
#define ERROR
Definition: elog.h:43
int64 first_row
#define DatumGetFloat8(X)
Definition: postgres.h:714
#define ereport(elevel,...)
Definition: elog.h:144
#define Max(x, y)
Definition: c.h:921
double proportion
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
int i
#define qsort(a, b, c, d)
Definition: port.h:479
static int pct_info_cmp(const void *pa, const void *pb)