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 501 of file orderedsetaggs.c.

◆ OSAPerGroupState

◆ OSAPerQueryState

Function Documentation

◆ float8_lerp()

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

Definition at line 504 of file orderedsetaggs.c.

505 {
506  double loval = DatumGetFloat8(lo);
507  double hival = DatumGetFloat8(hi);
508 
509  return Float8GetDatum(loval + (pct * (hival - loval)));
510 }
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1692
#define DatumGetFloat8(X)
Definition: postgres.h:758

References DatumGetFloat8, and Float8GetDatum().

Referenced by percentile_cont_float8_final(), and percentile_cont_float8_multi_final().

◆ hypothetical_check_argtypes()

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

Definition at line 1143 of file orderedsetaggs.c.

1145 {
1146  int i;
1147 
1148  /* check that we have an int4 flag column */
1149  if (!tupdesc ||
1150  (nargs + 1) != tupdesc->natts ||
1151  TupleDescAttr(tupdesc, nargs)->atttypid != INT4OID)
1152  elog(ERROR, "type mismatch in hypothetical-set function");
1153 
1154  /* check that direct args match in type with aggregated args */
1155  for (i = 0; i < nargs; i++)
1156  {
1157  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1158 
1159  if (get_fn_expr_argtype(fcinfo->flinfo, i + 1) != attr->atttypid)
1160  elog(ERROR, "type mismatch in hypothetical-set function");
1161  }
1162 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1786
int i
Definition: isn.c:73
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
FmgrInfo * flinfo
Definition: fmgr.h:87
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

Referenced by hypothetical_dense_rank_final(), and hypothetical_rank_common().

◆ hypothetical_cume_dist_final()

Datum hypothetical_cume_dist_final ( PG_FUNCTION_ARGS  )

Definition at line 1279 of file orderedsetaggs.c.

1280 {
1281  int64 rank;
1282  int64 rowcount;
1283  double result_val;
1284 
1285  rank = hypothetical_rank_common(fcinfo, 1, &rowcount);
1286 
1287  result_val = (double) (rank) / (double) (rowcount + 1);
1288 
1289  PG_RETURN_FLOAT8(result_val);
1290 }
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:367
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

◆ hypothetical_dense_rank_final()

Datum hypothetical_dense_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1296 of file orderedsetaggs.c.

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

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.

◆ hypothetical_percent_rank_final()

Datum hypothetical_percent_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1259 of file orderedsetaggs.c.

1260 {
1261  int64 rank;
1262  int64 rowcount;
1263  double result_val;
1264 
1265  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1266 
1267  if (rowcount == 0)
1268  PG_RETURN_FLOAT8(0);
1269 
1270  result_val = (double) (rank - 1) / (double) (rowcount);
1271 
1272  PG_RETURN_FLOAT8(result_val);
1273 }

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

◆ hypothetical_rank_common()

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

Definition at line 1172 of file orderedsetaggs.c.

1174 {
1175  int nargs = PG_NARGS() - 1;
1176  int64 rank = 1;
1177  OSAPerGroupState *osastate;
1178  TupleTableSlot *slot;
1179  int i;
1180 
1182 
1183  /* If there were no regular rows, the rank is always 1 */
1184  if (PG_ARGISNULL(0))
1185  {
1186  *number_of_rows = 0;
1187  return 1;
1188  }
1189 
1190  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1191  *number_of_rows = osastate->number_of_rows;
1192 
1193  /* Adjust nargs to be the number of direct (or aggregated) args */
1194  if (nargs % 2 != 0)
1195  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1196  nargs /= 2;
1197 
1198  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1199 
1200  /* because we need a hypothetical row, we can't share transition state */
1201  Assert(!osastate->sort_done);
1202 
1203  /* insert the hypothetical row into the sort */
1204  slot = osastate->qstate->tupslot;
1205  ExecClearTuple(slot);
1206  for (i = 0; i < nargs; i++)
1207  {
1208  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1209  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1210  }
1211  slot->tts_values[i] = Int32GetDatum(flag);
1212  slot->tts_isnull[i] = false;
1213  ExecStoreVirtualTuple(slot);
1214 
1215  tuplesort_puttupleslot(osastate->sortstate, slot);
1216 
1217  /* finish the sort */
1218  tuplesort_performsort(osastate->sortstate);
1219  osastate->sort_done = true;
1220 
1221  /* iterate till we find the hypothetical row */
1222  while (tuplesort_gettupleslot(osastate->sortstate, true, true, slot, NULL))
1223  {
1224  bool isnull;
1225  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1226 
1227  if (!isnull && DatumGetInt32(d) != 0)
1228  break;
1229 
1230  rank++;
1231 
1233  }
1234 
1235  ExecClearTuple(slot);
1236 
1237  return rank;
1238 }
char * flag(int b)
Definition: test-ctype.c:33

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert(), CHECK_FOR_INTERRUPTS, DatumGetInt32, elog, ERROR, ExecClearTuple(), ExecStoreVirtualTuple(), flag(), 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().

◆ hypothetical_rank_final()

Datum hypothetical_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1245 of file orderedsetaggs.c.

1246 {
1247  int64 rank;
1248  int64 rowcount;
1249 
1250  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1251 
1252  PG_RETURN_INT64(rank);
1253 }

References hypothetical_rank_common(), and PG_RETURN_INT64.

◆ interval_lerp()

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

Definition at line 513 of file orderedsetaggs.c.

514 {
515  Datum diff_result = DirectFunctionCall2(interval_mi, hi, lo);
517  diff_result,
518  Float8GetDatumFast(pct));
519 
520  return DirectFunctionCall2(interval_pl, mul_result, lo);
521 }
Datum interval_mi(PG_FUNCTION_ARGS)
Definition: timestamp.c:3195
Datum interval_pl(PG_FUNCTION_ARGS)
Definition: timestamp.c:3161
Datum interval_mul(PG_FUNCTION_ARGS)
Definition: timestamp.c:3235
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:633
#define Float8GetDatumFast(X)
Definition: postgres.h:805

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

Referenced by percentile_cont_interval_final(), and percentile_cont_interval_multi_final().

◆ mode_final()

Datum mode_final ( PG_FUNCTION_ARGS  )

Definition at line 1035 of file orderedsetaggs.c.

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

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.

◆ ordered_set_shutdown()

static void ordered_set_shutdown ( Datum  arg)
static

Definition at line 341 of file orderedsetaggs.c.

342 {
344 
345  /* Tuplesort object might have temp files. */
346  if (osastate->sortstate)
347  tuplesort_end(osastate->sortstate);
348  osastate->sortstate = NULL;
349  /* The tupleslot probably can't be holding a pin, but let's be safe. */
350  if (osastate->qstate->tupslot)
351  ExecClearTuple(osastate->qstate->tupslot);
352 }
void * arg
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1620

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

Referenced by ordered_set_startup().

◆ ordered_set_startup()

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

Definition at line 115 of file orderedsetaggs.c.

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

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, if(), 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(), TUPLESORT_NONE, TUPLESORT_RANDOMACCESS, OSAPerQueryState::tupslot, OSAPerQueryState::typAlign, OSAPerQueryState::typByVal, OSAPerQueryState::typLen, and work_mem.

Referenced by ordered_set_transition(), and ordered_set_transition_multi().

◆ ordered_set_transition()

Datum ordered_set_transition ( PG_FUNCTION_ARGS  )

Definition at line 360 of file orderedsetaggs.c.

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

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

◆ ordered_set_transition_multi()

Datum ordered_set_transition_multi ( PG_FUNCTION_ARGS  )

Definition at line 385 of file orderedsetaggs.c.

386 {
387  OSAPerGroupState *osastate;
388  TupleTableSlot *slot;
389  int nargs;
390  int i;
391 
392  /* If first call, create the transition state workspace */
393  if (PG_ARGISNULL(0))
394  osastate = ordered_set_startup(fcinfo, true);
395  else
396  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
397 
398  /* Form a tuple from all the other inputs besides the transition value */
399  slot = osastate->qstate->tupslot;
400  ExecClearTuple(slot);
401  nargs = PG_NARGS() - 1;
402  for (i = 0; i < nargs; i++)
403  {
404  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
405  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
406  }
407  if (osastate->qstate->aggref->aggkind == AGGKIND_HYPOTHETICAL)
408  {
409  /* Add a zero flag value to mark this row as a normal input row */
410  slot->tts_values[i] = Int32GetDatum(0);
411  slot->tts_isnull[i] = false;
412  i++;
413  }
414  Assert(i == slot->tts_tupleDescriptor->natts);
415  ExecStoreVirtualTuple(slot);
416 
417  /* Load the row into the tuplesort object */
418  tuplesort_puttupleslot(osastate->sortstate, slot);
419  osastate->number_of_rows++;
420 
421  PG_RETURN_POINTER(osastate);
422 }
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124

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.

◆ pct_info_cmp()

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

Definition at line 645 of file orderedsetaggs.c.

646 {
647  const struct pct_info *a = (const struct pct_info *) pa;
648  const struct pct_info *b = (const struct pct_info *) pb;
649 
650  if (a->first_row != b->first_row)
651  return (a->first_row < b->first_row) ? -1 : 1;
652  if (a->second_row != b->second_row)
653  return (a->second_row < b->second_row) ? -1 : 1;
654  return 0;
655 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, and b.

Referenced by setup_pct_info().

◆ percentile_cont_final_common()

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

Definition at line 527 of file orderedsetaggs.c.

530 {
531  OSAPerGroupState *osastate;
532  double percentile;
533  int64 first_row = 0;
534  int64 second_row = 0;
535  Datum val;
536  Datum first_val;
537  Datum second_val;
538  double proportion;
539  bool isnull;
540 
542 
543  /* Get and check the percentile argument */
544  if (PG_ARGISNULL(1))
545  PG_RETURN_NULL();
546 
547  percentile = PG_GETARG_FLOAT8(1);
548 
549  if (percentile < 0 || percentile > 1 || isnan(percentile))
550  ereport(ERROR,
551  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
552  errmsg("percentile value %g is not between 0 and 1",
553  percentile)));
554 
555  /* If there were no regular rows, the result is NULL */
556  if (PG_ARGISNULL(0))
557  PG_RETURN_NULL();
558 
559  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
560 
561  /* number_of_rows could be zero if we only saw NULL input values */
562  if (osastate->number_of_rows == 0)
563  PG_RETURN_NULL();
564 
565  Assert(expect_type == osastate->qstate->sortColType);
566 
567  /* Finish the sort, or rescan if we already did */
568  if (!osastate->sort_done)
569  {
570  tuplesort_performsort(osastate->sortstate);
571  osastate->sort_done = true;
572  }
573  else
574  tuplesort_rescan(osastate->sortstate);
575 
576  first_row = floor(percentile * (osastate->number_of_rows - 1));
577  second_row = ceil(percentile * (osastate->number_of_rows - 1));
578 
579  Assert(first_row < osastate->number_of_rows);
580 
581  if (!tuplesort_skiptuples(osastate->sortstate, first_row, true))
582  elog(ERROR, "missing row in percentile_cont");
583 
584  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val, &isnull, NULL))
585  elog(ERROR, "missing row in percentile_cont");
586  if (isnull)
587  PG_RETURN_NULL();
588 
589  if (first_row == second_row)
590  {
591  val = first_val;
592  }
593  else
594  {
595  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val, &isnull, NULL))
596  elog(ERROR, "missing row in percentile_cont");
597 
598  if (isnull)
599  PG_RETURN_NULL();
600 
601  proportion = (percentile * (osastate->number_of_rows - 1)) - first_row;
602  val = lerpfunc(first_val, second_val, proportion);
603  }
604 
606 }
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ereport(elevel,...)
Definition: elog.h:143
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
Definition: tuplesort.c:2687

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().

◆ percentile_cont_float8_final()

Datum percentile_cont_float8_final ( PG_FUNCTION_ARGS  )

Definition at line 612 of file orderedsetaggs.c.

613 {
614  return percentile_cont_final_common(fcinfo, FLOAT8OID, float8_lerp);
615 }
static Datum float8_lerp(Datum lo, Datum hi, double pct)
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)

References float8_lerp(), and percentile_cont_final_common().

◆ percentile_cont_float8_multi_final()

Datum percentile_cont_float8_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 1006 of file orderedsetaggs.c.

1007 {
1008  return percentile_cont_multi_final_common(fcinfo,
1009  FLOAT8OID,
1010  /* hard-wired info on type float8 */
1011  sizeof(float8),
1013  TYPALIGN_DOUBLE,
1014  float8_lerp);
1015 }
double float8
Definition: c.h:565
#define FLOAT8PASSBYVAL
Definition: c.h:570
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)

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

◆ percentile_cont_interval_final()

Datum percentile_cont_interval_final ( PG_FUNCTION_ARGS  )

Definition at line 621 of file orderedsetaggs.c.

622 {
623  return percentile_cont_final_common(fcinfo, INTERVALOID, interval_lerp);
624 }
static Datum interval_lerp(Datum lo, Datum hi, double pct)

References interval_lerp(), and percentile_cont_final_common().

◆ percentile_cont_interval_multi_final()

Datum percentile_cont_interval_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 1021 of file orderedsetaggs.c.

1022 {
1023  return percentile_cont_multi_final_common(fcinfo,
1024  INTERVALOID,
1025  /* hard-wired info on type interval */
1026  16, false, TYPALIGN_DOUBLE,
1027  interval_lerp);
1028 }

References interval_lerp(), and percentile_cont_multi_final_common().

◆ 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 848 of file orderedsetaggs.c.

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))
871  PG_RETURN_NULL();
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)
877  PG_RETURN_NULL();
878 
879  Assert(expect_type == osastate->qstate->sortColType);
880 
881  /* Deconstruct the percentile-array input */
882  if (PG_ARGISNULL(1))
883  PG_RETURN_NULL();
884  param = PG_GETARG_ARRAYTYPE_P(1);
885 
886  deconstruct_array(param, FLOAT8OID,
887  /* hard-wired info on type float8 */
888  sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE,
889  &percentiles_datum,
890  &percentiles_null,
891  &num_percentiles);
892 
893  if (num_percentiles == 0)
895 
896  pct_info = setup_pct_info(num_percentiles,
897  percentiles_datum,
898  percentiles_null,
899  osastate->number_of_rows,
900  true);
901 
902  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
903  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
904 
905  /*
906  * Start by dealing with any nulls in the param array - those are sorted
907  * to the front on row=0, so set the corresponding result indexes to null
908  */
909  for (i = 0; i < num_percentiles; i++)
910  {
911  int idx = pct_info[i].idx;
912 
913  if (pct_info[i].first_row > 0)
914  break;
915 
916  result_datum[idx] = (Datum) 0;
917  result_isnull[idx] = true;
918  }
919 
920  /*
921  * If there's anything left after doing the nulls, then grind the input
922  * and extract the needed values
923  */
924  if (i < num_percentiles)
925  {
926  /* Finish the sort, or rescan if we already did */
927  if (!osastate->sort_done)
928  {
929  tuplesort_performsort(osastate->sortstate);
930  osastate->sort_done = true;
931  }
932  else
933  tuplesort_rescan(osastate->sortstate);
934 
935  for (; i < num_percentiles; i++)
936  {
937  int64 first_row = pct_info[i].first_row;
938  int64 second_row = pct_info[i].second_row;
939  int idx = pct_info[i].idx;
940 
941  /*
942  * Advance to first_row, if not already there. Note that we might
943  * already have rownum beyond first_row, in which case first_val
944  * is already correct. (This occurs when interpolating between
945  * the same two input rows as for the previous percentile.)
946  */
947  if (first_row > rownum)
948  {
949  if (!tuplesort_skiptuples(osastate->sortstate, first_row - rownum - 1, true))
950  elog(ERROR, "missing row in percentile_cont");
951 
952  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val,
953  &isnull, NULL) || isnull)
954  elog(ERROR, "missing row in percentile_cont");
955 
956  rownum = first_row;
957  /* Always advance second_val to be latest input value */
958  second_val = first_val;
959  }
960  else if (first_row == rownum)
961  {
962  /*
963  * We are already at the desired row, so we must previously
964  * have read its value into second_val (and perhaps first_val
965  * as well, but this assignment is harmless in that case).
966  */
967  first_val = second_val;
968  }
969 
970  /* Fetch second_row if needed */
971  if (second_row > rownum)
972  {
973  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val,
974  &isnull, NULL) || isnull)
975  elog(ERROR, "missing row in percentile_cont");
976  rownum++;
977  }
978  /* We should now certainly be on second_row exactly */
979  Assert(second_row == rownum);
980 
981  /* Compute appropriate result */
982  if (second_row > first_row)
983  result_datum[idx] = lerpfunc(first_val, second_val,
985  else
986  result_datum[idx] = first_val;
987 
988  result_isnull[idx] = false;
989  }
990  }
991 
992  /* We make the output array the same shape as the input */
993  PG_RETURN_POINTER(construct_md_array(result_datum, result_isnull,
994  ARR_NDIM(param),
995  ARR_DIMS(param), ARR_LBOUND(param),
996  expect_type,
997  typLen,
998  typByVal,
999  typAlign));
1000 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
#define ARR_NDIM(a)
Definition: array.h:283
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_LBOUND(a)
Definition: array.h:289
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3440
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3491
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:3354
static struct pct_info * setup_pct_info(int num_percentiles, Datum *percentiles_datum, bool *percentiles_null, int64 rowcount, bool continuous)
int64 first_row
int64 second_row
double proportion

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().

◆ percentile_disc_final()

Datum percentile_disc_final ( PG_FUNCTION_ARGS  )

Definition at line 429 of file orderedsetaggs.c.

430 {
431  OSAPerGroupState *osastate;
432  double percentile;
433  Datum val;
434  bool isnull;
435  int64 rownum;
436 
438 
439  /* Get and check the percentile argument */
440  if (PG_ARGISNULL(1))
441  PG_RETURN_NULL();
442 
443  percentile = PG_GETARG_FLOAT8(1);
444 
445  if (percentile < 0 || percentile > 1 || isnan(percentile))
446  ereport(ERROR,
447  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
448  errmsg("percentile value %g is not between 0 and 1",
449  percentile)));
450 
451  /* If there were no regular rows, the result is NULL */
452  if (PG_ARGISNULL(0))
453  PG_RETURN_NULL();
454 
455  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
456 
457  /* number_of_rows could be zero if we only saw NULL input values */
458  if (osastate->number_of_rows == 0)
459  PG_RETURN_NULL();
460 
461  /* Finish the sort, or rescan if we already did */
462  if (!osastate->sort_done)
463  {
464  tuplesort_performsort(osastate->sortstate);
465  osastate->sort_done = true;
466  }
467  else
468  tuplesort_rescan(osastate->sortstate);
469 
470  /*----------
471  * We need the smallest K such that (K/N) >= percentile.
472  * N>0, therefore K >= N*percentile, therefore K = ceil(N*percentile).
473  * So we skip K-1 rows (if K>0) and return the next row fetched.
474  *----------
475  */
476  rownum = (int64) ceil(percentile * osastate->number_of_rows);
477  Assert(rownum <= osastate->number_of_rows);
478 
479  if (rownum > 1)
480  {
481  if (!tuplesort_skiptuples(osastate->sortstate, rownum - 1, true))
482  elog(ERROR, "missing row in percentile_disc");
483  }
484 
485  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
486  elog(ERROR, "missing row in percentile_disc");
487 
488  /* We shouldn't have stored any nulls, but do the right thing anyway */
489  if (isnull)
490  PG_RETURN_NULL();
491  else
493 }

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.

◆ percentile_disc_multi_final()

Datum percentile_disc_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 730 of file orderedsetaggs.c.

731 {
732  OSAPerGroupState *osastate;
733  ArrayType *param;
734  Datum *percentiles_datum;
735  bool *percentiles_null;
736  int num_percentiles;
737  struct pct_info *pct_info;
738  Datum *result_datum;
739  bool *result_isnull;
740  int64 rownum = 0;
741  Datum val = (Datum) 0;
742  bool isnull = true;
743  int i;
744 
746 
747  /* If there were no regular rows, the result is NULL */
748  if (PG_ARGISNULL(0))
749  PG_RETURN_NULL();
750 
751  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
752 
753  /* number_of_rows could be zero if we only saw NULL input values */
754  if (osastate->number_of_rows == 0)
755  PG_RETURN_NULL();
756 
757  /* Deconstruct the percentile-array input */
758  if (PG_ARGISNULL(1))
759  PG_RETURN_NULL();
760  param = PG_GETARG_ARRAYTYPE_P(1);
761 
762  deconstruct_array(param, FLOAT8OID,
763  /* hard-wired info on type float8 */
764  sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE,
765  &percentiles_datum,
766  &percentiles_null,
767  &num_percentiles);
768 
769  if (num_percentiles == 0)
771 
772  pct_info = setup_pct_info(num_percentiles,
773  percentiles_datum,
774  percentiles_null,
775  osastate->number_of_rows,
776  false);
777 
778  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
779  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
780 
781  /*
782  * Start by dealing with any nulls in the param array - those are sorted
783  * to the front on row=0, so set the corresponding result indexes to null
784  */
785  for (i = 0; i < num_percentiles; i++)
786  {
787  int idx = pct_info[i].idx;
788 
789  if (pct_info[i].first_row > 0)
790  break;
791 
792  result_datum[idx] = (Datum) 0;
793  result_isnull[idx] = true;
794  }
795 
796  /*
797  * If there's anything left after doing the nulls, then grind the input
798  * and extract the needed values
799  */
800  if (i < num_percentiles)
801  {
802  /* Finish the sort, or rescan if we already did */
803  if (!osastate->sort_done)
804  {
805  tuplesort_performsort(osastate->sortstate);
806  osastate->sort_done = true;
807  }
808  else
809  tuplesort_rescan(osastate->sortstate);
810 
811  for (; i < num_percentiles; i++)
812  {
813  int64 target_row = pct_info[i].first_row;
814  int idx = pct_info[i].idx;
815 
816  /* Advance to target row, if not already there */
817  if (target_row > rownum)
818  {
819  if (!tuplesort_skiptuples(osastate->sortstate, target_row - rownum - 1, true))
820  elog(ERROR, "missing row in percentile_disc");
821 
822  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &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 }

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.

◆ 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 661 of file orderedsetaggs.c.

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

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().