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/fmgrprotos.h"
#include "utils/lsyscache.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 500 of file orderedsetaggs.c.

◆ OSAPerGroupState

◆ OSAPerQueryState

Function Documentation

◆ float8_lerp()

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

Definition at line 503 of file orderedsetaggs.c.

504 {
505  double loval = DatumGetFloat8(lo);
506  double hival = DatumGetFloat8(hi);
507 
508  return Float8GetDatum(loval + (pct * (hival - loval)));
509 }
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1816
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:494

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

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

1279 {
1280  int64 rank;
1281  int64 rowcount;
1282  double result_val;
1283 
1284  rank = hypothetical_rank_common(fcinfo, 1, &rowcount);
1285 
1286  result_val = (double) (rank) / (double) (rowcount + 1);
1287 
1288  PG_RETURN_FLOAT8(result_val);
1289 }
#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 1295 of file orderedsetaggs.c.

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

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

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

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

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

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

References hypothetical_rank_common(), and PG_RETURN_INT64.

◆ interval_lerp()

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

Definition at line 512 of file orderedsetaggs.c.

513 {
514  Datum diff_result = DirectFunctionCall2(interval_mi, hi, lo);
516  diff_result,
517  Float8GetDatumFast(pct));
518 
519  return DirectFunctionCall2(interval_pl, mul_result, lo);
520 }
Datum interval_mi(PG_FUNCTION_ARGS)
Definition: timestamp.c:3506
Datum interval_pl(PG_FUNCTION_ARGS)
Definition: timestamp.c:3450
Datum interval_mul(PG_FUNCTION_ARGS)
Definition: timestamp.c:3555
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define Float8GetDatumFast(X)
Definition: postgres.h:556

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

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

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

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

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

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

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), AggGetAggref(), 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 358 of file orderedsetaggs.c.

359 {
360  OSAPerGroupState *osastate;
361 
362  /* If first call, create the transition state workspace */
363  if (PG_ARGISNULL(0))
364  osastate = ordered_set_startup(fcinfo, false);
365  else
366  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
367 
368  /* Load the datum into the tuplesort object, but only if it's not null */
369  if (!PG_ARGISNULL(1))
370  {
371  tuplesort_putdatum(osastate->sortstate, PG_GETARG_DATUM(1), false);
372  osastate->number_of_rows++;
373  }
374 
375  PG_RETURN_POINTER(osastate);
376 }
#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)

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

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

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

647 {
648  const struct pct_info *a = (const struct pct_info *) pa;
649  const struct pct_info *b = (const struct pct_info *) pb;
650 
651  if (a->first_row != b->first_row)
652  return (a->first_row < b->first_row) ? -1 : 1;
653  if (a->second_row != b->second_row)
654  return (a->second_row < b->second_row) ? -1 : 1;
655  return 0;
656 }
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 526 of file orderedsetaggs.c.

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

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

614 {
615  return percentile_cont_final_common(fcinfo, FLOAT8OID, float8_lerp);
616 }
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 1004 of file orderedsetaggs.c.

1005 {
1006  return percentile_cont_multi_final_common(fcinfo,
1007  FLOAT8OID,
1008  /* hard-wired info on type float8 */
1009  sizeof(float8),
1011  TYPALIGN_DOUBLE,
1012  float8_lerp);
1013 }
double float8
Definition: c.h:630
#define FLOAT8PASSBYVAL
Definition: c.h:635
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 622 of file orderedsetaggs.c.

623 {
624  return percentile_cont_final_common(fcinfo, INTERVALOID, interval_lerp);
625 }
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 1019 of file orderedsetaggs.c.

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

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

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

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

732 {
733  OSAPerGroupState *osastate;
734  ArrayType *param;
735  Datum *percentiles_datum;
736  bool *percentiles_null;
737  int num_percentiles;
738  struct pct_info *pct_info;
739  Datum *result_datum;
740  bool *result_isnull;
741  int64 rownum = 0;
742  Datum val = (Datum) 0;
743  bool isnull = true;
744  int i;
745 
747 
748  /* If there were no regular rows, the result is NULL */
749  if (PG_ARGISNULL(0))
750  PG_RETURN_NULL();
751 
752  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
753 
754  /* number_of_rows could be zero if we only saw NULL input values */
755  if (osastate->number_of_rows == 0)
756  PG_RETURN_NULL();
757 
758  /* Deconstruct the percentile-array input */
759  if (PG_ARGISNULL(1))
760  PG_RETURN_NULL();
761  param = PG_GETARG_ARRAYTYPE_P(1);
762 
763  deconstruct_array_builtin(param, FLOAT8OID,
764  &percentiles_datum,
765  &percentiles_null,
766  &num_percentiles);
767 
768  if (num_percentiles == 0)
770 
771  pct_info = setup_pct_info(num_percentiles,
772  percentiles_datum,
773  percentiles_null,
774  osastate->number_of_rows,
775  false);
776 
777  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
778  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
779 
780  /*
781  * Start by dealing with any nulls in the param array - those are sorted
782  * to the front on row=0, so set the corresponding result indexes to null
783  */
784  for (i = 0; i < num_percentiles; i++)
785  {
786  int idx = pct_info[i].idx;
787 
788  if (pct_info[i].first_row > 0)
789  break;
790 
791  result_datum[idx] = (Datum) 0;
792  result_isnull[idx] = true;
793  }
794 
795  /*
796  * If there's anything left after doing the nulls, then grind the input
797  * and extract the needed values
798  */
799  if (i < num_percentiles)
800  {
801  /* Finish the sort, or rescan if we already did */
802  if (!osastate->sort_done)
803  {
804  tuplesort_performsort(osastate->sortstate);
805  osastate->sort_done = true;
806  }
807  else
808  tuplesort_rescan(osastate->sortstate);
809 
810  for (; i < num_percentiles; i++)
811  {
812  int64 target_row = pct_info[i].first_row;
813  int idx = pct_info[i].idx;
814 
815  /* Advance to target row, if not already there */
816  if (target_row > rownum)
817  {
818  if (!tuplesort_skiptuples(osastate->sortstate, target_row - rownum - 1, true))
819  elog(ERROR, "missing row in percentile_disc");
820 
821  if (!tuplesort_getdatum(osastate->sortstate, true, true, &val,
822  &isnull, NULL))
823  elog(ERROR, "missing row in percentile_disc");
824 
825  rownum = target_row;
826  }
827 
828  result_datum[idx] = val;
829  result_isnull[idx] = isnull;
830  }
831  }
832 
833  /* We make the output array the same shape as the input */
834  PG_RETURN_POINTER(construct_md_array(result_datum, result_isnull,
835  ARR_NDIM(param),
836  ARR_DIMS(param),
837  ARR_LBOUND(param),
838  osastate->qstate->sortColType,
839  osastate->qstate->typLen,
840  osastate->qstate->typByVal,
841  osastate->qstate->typAlign));
842 }

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array_builtin(), elog, ERROR, pct_info::first_row, 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 662 of file orderedsetaggs.c.

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

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