PostgreSQL Source Code  git master
orderedsetaggs.c File Reference
#include "postgres.h"
#include <float.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/tlist.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.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 493 of file orderedsetaggs.c.

◆ OSAPerGroupState

◆ OSAPerQueryState

Function Documentation

◆ float8_lerp()

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

Definition at line 496 of file orderedsetaggs.c.

References DatumGetFloat8, and Float8GetDatum().

Referenced by percentile_cont_float8_final(), and percentile_cont_float8_multi_final().

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

◆ hypothetical_check_argtypes()

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

Definition at line 1133 of file orderedsetaggs.c.

References elog, ERROR, FunctionCallInfoData::flinfo, get_fn_expr_argtype(), i, INT4OID, tupleDesc::natts, and TupleDescAttr.

Referenced by hypothetical_dense_rank_final(), and hypothetical_rank_common().

1135 {
1136  int i;
1137 
1138  /* check that we have an int4 flag column */
1139  if (!tupdesc ||
1140  (nargs + 1) != tupdesc->natts ||
1141  TupleDescAttr(tupdesc, nargs)->atttypid != INT4OID)
1142  elog(ERROR, "type mismatch in hypothetical-set function");
1143 
1144  /* check that direct args match in type with aggregated args */
1145  for (i = 0; i < nargs; i++)
1146  {
1147  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1148 
1149  if (get_fn_expr_argtype(fcinfo->flinfo, i + 1) != attr->atttypid)
1150  elog(ERROR, "type mismatch in hypothetical-set function");
1151  }
1152 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
#define INT4OID
Definition: pg_type.h:316
int natts
Definition: tupdesc.h:79
FmgrInfo * flinfo
Definition: fmgr.h:79
#define ERROR
Definition: elog.h:43
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1904
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
int i
#define elog
Definition: elog.h:219

◆ hypothetical_cume_dist_final()

Datum hypothetical_cume_dist_final ( PG_FUNCTION_ARGS  )

Definition at line 1269 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

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

◆ hypothetical_dense_rank_final()

Datum hypothetical_dense_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1286 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), AggGetTempMemoryContext(), Assert, CHECK_FOR_INTERRUPTS, DatumGetInt32, elog, OSAPerQueryState::eqOperators, OSAPerQueryState::equalfns, ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), execTuplesMatch(), fmgr_info_cxt(), get_opcode(), hypothetical_check_argtypes(), i, Int32GetDatum, MakeSingleTupleTableSlot(), MemoryContextAlloc(), 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, OSAPerGroupState::sortstate, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, OSAPerQueryState::tupdesc, TupIsNull, tuplesort_gettupleslot(), tuplesort_performsort(), tuplesort_puttupleslot(), and OSAPerQueryState::tupslot.

1287 {
1288  int nargs = PG_NARGS() - 1;
1289  int64 rank = 1;
1290  int64 duplicate_count = 0;
1291  OSAPerGroupState *osastate;
1292  int numDistinctCols;
1293  Datum abbrevVal = (Datum) 0;
1294  Datum abbrevOld = (Datum) 0;
1295  AttrNumber *sortColIdx;
1296  FmgrInfo *equalfns;
1297  TupleTableSlot *slot;
1298  TupleTableSlot *extraslot;
1299  TupleTableSlot *slot2;
1300  MemoryContext tmpcontext;
1301  int i;
1302 
1304 
1305  /* If there were no regular rows, the rank is always 1 */
1306  if (PG_ARGISNULL(0))
1307  PG_RETURN_INT64(rank);
1308 
1309  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1310 
1311  /* Adjust nargs to be the number of direct (or aggregated) args */
1312  if (nargs % 2 != 0)
1313  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1314  nargs /= 2;
1315 
1316  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1317 
1318  /*
1319  * When comparing tuples, we can omit the flag column since we will only
1320  * compare rows with flag == 0.
1321  */
1322  numDistinctCols = osastate->qstate->numSortCols - 1;
1323 
1324  /* Look up the equality function(s), if we didn't already */
1325  equalfns = osastate->qstate->equalfns;
1326  if (equalfns == NULL)
1327  {
1328  MemoryContext qcontext = osastate->qstate->qcontext;
1329 
1330  equalfns = (FmgrInfo *)
1331  MemoryContextAlloc(qcontext, numDistinctCols * sizeof(FmgrInfo));
1332  for (i = 0; i < numDistinctCols; i++)
1333  {
1334  fmgr_info_cxt(get_opcode(osastate->qstate->eqOperators[i]),
1335  &equalfns[i],
1336  qcontext);
1337  }
1338  osastate->qstate->equalfns = equalfns;
1339  }
1340  sortColIdx = osastate->qstate->sortColIdx;
1341 
1342  /* Get short-term context we can use for execTuplesMatch */
1343  tmpcontext = AggGetTempMemoryContext(fcinfo);
1344 
1345  /* because we need a hypothetical row, we can't share transition state */
1346  Assert(!osastate->sort_done);
1347 
1348  /* insert the hypothetical row into the sort */
1349  slot = osastate->qstate->tupslot;
1350  ExecClearTuple(slot);
1351  for (i = 0; i < nargs; i++)
1352  {
1353  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1354  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1355  }
1356  slot->tts_values[i] = Int32GetDatum(-1);
1357  slot->tts_isnull[i] = false;
1358  ExecStoreVirtualTuple(slot);
1359 
1360  tuplesort_puttupleslot(osastate->sortstate, slot);
1361 
1362  /* finish the sort */
1363  tuplesort_performsort(osastate->sortstate);
1364  osastate->sort_done = true;
1365 
1366  /*
1367  * We alternate fetching into tupslot and extraslot so that we have the
1368  * previous row available for comparisons. This is accomplished by
1369  * swapping the slot pointer variables after each row.
1370  */
1371  extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc);
1372  slot2 = extraslot;
1373 
1374  /* iterate till we find the hypothetical row */
1375  while (tuplesort_gettupleslot(osastate->sortstate, true, true, slot,
1376  &abbrevVal))
1377  {
1378  bool isnull;
1379  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1380  TupleTableSlot *tmpslot;
1381 
1382  if (!isnull && DatumGetInt32(d) != 0)
1383  break;
1384 
1385  /* count non-distinct tuples */
1386  if (!TupIsNull(slot2) &&
1387  abbrevVal == abbrevOld &&
1388  execTuplesMatch(slot, slot2,
1389  numDistinctCols,
1390  sortColIdx,
1391  equalfns,
1392  tmpcontext))
1393  duplicate_count++;
1394 
1395  tmpslot = slot2;
1396  slot2 = slot;
1397  slot = tmpslot;
1398  /* avoid execTuplesMatch() calls by reusing abbreviated keys */
1399  abbrevOld = abbrevVal;
1400 
1401  rank++;
1402 
1404  }
1405 
1406  ExecClearTuple(slot);
1407  ExecClearTuple(slot2);
1408 
1409  ExecDropSingleTupleTableSlot(extraslot);
1410 
1411  rank = rank - duplicate_count;
1412 
1413  PG_RETURN_INT64(rank);
1414 }
Definition: fmgr.h:56
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1656
OSAPerQueryState * qstate
#define DatumGetInt32(X)
Definition: postgres.h:478
#define PG_RETURN_INT64(x)
Definition: fmgr.h:327
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:233
TupleTableSlot * tupslot
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:69
Datum * tts_values
Definition: tuptable.h:125
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:241
MemoryContext qcontext
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:694
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:1996
bool * tts_isnull
Definition: tuptable.h:126
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
#define TupIsNull(slot)
Definition: tuptable.h:138
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:132
MemoryContext AggGetTempMemoryContext(FunctionCallInfo fcinfo)
Definition: nodeAgg.c:4194
uintptr_t Datum
Definition: postgres.h:372
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1094
#define PG_ARGISNULL(n)
Definition: fmgr.h:174
#define Assert(condition)
Definition: c.h:670
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4116
#define PG_NARGS()
Definition: fmgr.h:168
FmgrInfo * equalfns
#define Int32GetDatum(X)
Definition: postgres.h:485
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1142
static void hypothetical_check_argtypes(FunctionCallInfo fcinfo, int nargs, TupleDesc tupdesc)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
AttrNumber * sortColIdx
int16 AttrNumber
Definition: attnum.h:21
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1301

◆ hypothetical_percent_rank_final()

Datum hypothetical_percent_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1249 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

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

◆ hypothetical_rank_common()

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

Definition at line 1162 of file orderedsetaggs.c.

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

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

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

◆ hypothetical_rank_final()

Datum hypothetical_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1235 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_INT64.

1236 {
1237  int64 rank;
1238  int64 rowcount;
1239 
1240  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1241 
1242  PG_RETURN_INT64(rank);
1243 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:327
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)

◆ interval_lerp()

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

Definition at line 505 of file orderedsetaggs.c.

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

Referenced by percentile_cont_interval_final(), and percentile_cont_interval_multi_final().

506 {
507  Datum diff_result = DirectFunctionCall2(interval_mi, hi, lo);
509  diff_result,
510  Float8GetDatumFast(pct));
511 
512  return DirectFunctionCall2(interval_pl, mul_result, lo);
513 }
Datum interval_mi(PG_FUNCTION_ARGS)
Definition: timestamp.c:3093
Datum interval_pl(PG_FUNCTION_ARGS)
Definition: timestamp.c:3059
uintptr_t Datum
Definition: postgres.h:372
#define Float8GetDatumFast(X)
Definition: postgres.h:782
Datum interval_mul(PG_FUNCTION_ARGS)
Definition: timestamp.c:3133
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:587

◆ mode_final()

Datum mode_final ( PG_FUNCTION_ARGS  )

Definition at line 1025 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, CHECK_FOR_INTERRUPTS, DatumGetBool, DatumGetPointer, OSAPerQueryState::eqOperator, OSAPerQueryState::equalfn, fmgr_info_cxt(), FmgrInfo::fn_oid, FunctionCall2, get_opcode(), OSAPerGroupState::number_of_rows, OidIsValid, pfree(), PG_ARGISNULL, 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.

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

◆ ordered_set_shutdown()

static void ordered_set_shutdown ( Datum  arg)
static

Definition at line 333 of file orderedsetaggs.c.

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

Referenced by ordered_set_startup().

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

◆ ordered_set_startup()

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

Definition at line 113 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), AggGetAggref(), Aggref::aggkind, AGGKIND_HYPOTHETICAL, AGGKIND_IS_ORDERED_SET, Aggref::aggorder, OSAPerQueryState::aggref, AggRegisterCallback(), AggStateIsShared(), Aggref::args, Assert, CreateTemplateTupleDesc(), elog, SortGroupClause::eqop, OSAPerQueryState::eqOperator, OSAPerQueryState::eqOperators, ERROR, ExecTypeFromTL(), TargetEntry::expr, exprCollation(), exprType(), FunctionCallInfoData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, FreeTupleDesc(), OSAPerGroupState::gcontext, get_sortgroupclause_tle(), get_typlenbyvalalign(), i, Int4EqualOperator, Int4LessOperator, INT4OID, InvalidOid, lfirst, linitial, list_length(), MakeSingleTupleTableSlot(), MemoryContextSwitchTo(), tupleDesc::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, OSAPerQueryState::tupdesc, TupleDescCopyEntry(), TupleDescInitEntry(), tuplesort_begin_datum(), tuplesort_begin_heap(), OSAPerQueryState::tupslot, OSAPerQueryState::typAlign, OSAPerQueryState::typByVal, OSAPerQueryState::typLen, and work_mem.

Referenced by ordered_set_transition(), and ordered_set_transition_multi().

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

◆ ordered_set_transition()

Datum ordered_set_transition ( PG_FUNCTION_ARGS  )

Definition at line 352 of file orderedsetaggs.c.

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

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

◆ ordered_set_transition_multi()

Datum ordered_set_transition_multi ( PG_FUNCTION_ARGS  )

Definition at line 377 of file orderedsetaggs.c.

References Aggref::aggkind, AGGKIND_HYPOTHETICAL, OSAPerQueryState::aggref, Assert, ExecClearTuple(), ExecStoreVirtualTuple(), i, Int32GetDatum, tupleDesc::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.

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

◆ pct_info_cmp()

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

Definition at line 637 of file orderedsetaggs.c.

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

Referenced by setup_pct_info().

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

◆ percentile_cont_final_common()

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

Definition at line 519 of file orderedsetaggs.c.

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

Referenced by percentile_cont_float8_final(), and percentile_cont_interval_final().

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

◆ percentile_cont_float8_final()

Datum percentile_cont_float8_final ( PG_FUNCTION_ARGS  )

Definition at line 604 of file orderedsetaggs.c.

References float8_lerp(), FLOAT8OID, and percentile_cont_final_common().

605 {
607 }
#define FLOAT8OID
Definition: pg_type.h:419
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)
static Datum float8_lerp(Datum lo, Datum hi, double pct)

◆ percentile_cont_float8_multi_final()

Datum percentile_cont_float8_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 998 of file orderedsetaggs.c.

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

999 {
1000  return percentile_cont_multi_final_common(fcinfo,
1001  FLOAT8OID,
1002  /* hard-wired info on type float8 */
1003  8, FLOAT8PASSBYVAL, 'd',
1004  float8_lerp);
1005 }
#define FLOAT8OID
Definition: pg_type.h:419
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)
static Datum float8_lerp(Datum lo, Datum hi, double pct)

◆ percentile_cont_interval_final()

Datum percentile_cont_interval_final ( PG_FUNCTION_ARGS  )

Definition at line 613 of file orderedsetaggs.c.

References interval_lerp(), INTERVALOID, and percentile_cont_final_common().

614 {
616 }
static Datum interval_lerp(Datum lo, Datum hi, double pct)
#define INTERVALOID
Definition: pg_type.h:529
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)

◆ percentile_cont_interval_multi_final()

Datum percentile_cont_interval_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 1011 of file orderedsetaggs.c.

References interval_lerp(), INTERVALOID, and percentile_cont_multi_final_common().

1012 {
1013  return percentile_cont_multi_final_common(fcinfo,
1014  INTERVALOID,
1015  /* hard-wired info on type interval */
1016  16, false, 'd',
1017  interval_lerp);
1018 }
static Datum interval_lerp(Datum lo, Datum hi, double pct)
#define INTERVALOID
Definition: pg_type.h:529
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)

◆ percentile_cont_multi_final_common()

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

Definition at line 840 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array(), elog, ERROR, pct_info::first_row, FLOAT8OID, 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().

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

◆ percentile_disc_final()

Datum percentile_disc_final ( PG_FUNCTION_ARGS  )

Definition at line 421 of file orderedsetaggs.c.

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

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

◆ percentile_disc_multi_final()

Datum percentile_disc_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 722 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array(), elog, ERROR, pct_info::first_row, FLOAT8OID, 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.

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

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

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

Referenced by percentile_cont_multi_final_common(), and percentile_disc_multi_final().

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