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/memutils.h"
#include "utils/timestamp.h"
#include "utils/tuplesort.h"
Include dependency graph for orderedsetaggs.c:

Go to the source code of this file.

Data Structures

struct  OSAPerQueryState
 
struct  OSAPerGroupState
 
struct  pct_info
 

Typedefs

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

Functions

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

Typedef Documentation

◆ LerpFunc

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

Definition at line 498 of file orderedsetaggs.c.

◆ OSAPerGroupState

◆ OSAPerQueryState

Function Documentation

◆ float8_lerp()

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

Definition at line 501 of file orderedsetaggs.c.

References DatumGetFloat8, and Float8GetDatum().

Referenced by percentile_cont_float8_final(), and percentile_cont_float8_multi_final().

502 {
503  double loval = DatumGetFloat8(lo);
504  double hival = DatumGetFloat8(hi);
505 
506  return Float8GetDatum(loval + (pct * (hival - loval)));
507 }
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1810
#define DatumGetFloat8(X)
Definition: postgres.h:711

◆ hypothetical_check_argtypes()

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

Definition at line 1138 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().

1140 {
1141  int i;
1142 
1143  /* check that we have an int4 flag column */
1144  if (!tupdesc ||
1145  (nargs + 1) != tupdesc->natts ||
1146  TupleDescAttr(tupdesc, nargs)->atttypid != INT4OID)
1147  elog(ERROR, "type mismatch in hypothetical-set function");
1148 
1149  /* check that direct args match in type with aggregated args */
1150  for (i = 0; i < nargs; i++)
1151  {
1152  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1153 
1154  if (get_fn_expr_argtype(fcinfo->flinfo, i + 1) != attr->atttypid)
1155  elog(ERROR, "type mismatch in hypothetical-set function");
1156  }
1157 }
#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 1274 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

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

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

1292 {
1293  ExprContext *econtext;
1294  ExprState *compareTuple;
1295  int nargs = PG_NARGS() - 1;
1296  int64 rank = 1;
1297  int64 duplicate_count = 0;
1298  OSAPerGroupState *osastate;
1299  int numDistinctCols;
1300  Datum abbrevVal = (Datum) 0;
1301  Datum abbrevOld = (Datum) 0;
1302  TupleTableSlot *slot;
1303  TupleTableSlot *extraslot;
1304  TupleTableSlot *slot2;
1305  int i;
1306 
1308 
1309  /* If there were no regular rows, the rank is always 1 */
1310  if (PG_ARGISNULL(0))
1311  PG_RETURN_INT64(rank);
1312 
1313  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1314  econtext = osastate->qstate->econtext;
1315  if (!econtext)
1316  osastate->qstate->econtext = econtext = CreateStandaloneExprContext();
1317 
1318  /* Adjust nargs to be the number of direct (or aggregated) args */
1319  if (nargs % 2 != 0)
1320  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1321  nargs /= 2;
1322 
1323  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1324 
1325  /*
1326  * When comparing tuples, we can omit the flag column since we will only
1327  * compare rows with flag == 0.
1328  */
1329  numDistinctCols = osastate->qstate->numSortCols - 1;
1330 
1331  /* Build tuple comparator, if we didn't already */
1332  compareTuple = osastate->qstate->compareTuple;
1333  if (compareTuple == NULL)
1334  {
1335  AttrNumber *sortColIdx = osastate->qstate->sortColIdx;
1336  MemoryContext oldContext;
1337 
1338  oldContext = MemoryContextSwitchTo(osastate->qstate->qcontext);
1339  compareTuple = execTuplesMatchPrepare(osastate->qstate->tupdesc,
1340  numDistinctCols,
1341  sortColIdx,
1342  osastate->qstate->eqOperators,
1343  NULL);
1344  MemoryContextSwitchTo(oldContext);
1345  osastate->qstate->compareTuple = compareTuple;
1346  }
1347 
1348  /* because we need a hypothetical row, we can't share transition state */
1349  Assert(!osastate->sort_done);
1350 
1351  /* insert the hypothetical row into the sort */
1352  slot = osastate->qstate->tupslot;
1353  ExecClearTuple(slot);
1354  for (i = 0; i < nargs; i++)
1355  {
1356  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1357  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1358  }
1359  slot->tts_values[i] = Int32GetDatum(-1);
1360  slot->tts_isnull[i] = false;
1361  ExecStoreVirtualTuple(slot);
1362 
1363  tuplesort_puttupleslot(osastate->sortstate, slot);
1364 
1365  /* finish the sort */
1366  tuplesort_performsort(osastate->sortstate);
1367  osastate->sort_done = true;
1368 
1369  /*
1370  * We alternate fetching into tupslot and extraslot so that we have the
1371  * previous row available for comparisons. This is accomplished by
1372  * swapping the slot pointer variables after each row.
1373  */
1374  extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc);
1375  slot2 = extraslot;
1376 
1377  /* iterate till we find the hypothetical row */
1378  while (tuplesort_gettupleslot(osastate->sortstate, true, true, slot,
1379  &abbrevVal))
1380  {
1381  bool isnull;
1382  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1383  TupleTableSlot *tmpslot;
1384 
1385  if (!isnull && DatumGetInt32(d) != 0)
1386  break;
1387 
1388  /* count non-distinct tuples */
1389  econtext->ecxt_outertuple = slot;
1390  econtext->ecxt_innertuple = slot2;
1391 
1392  if (!TupIsNull(slot2) &&
1393  abbrevVal == abbrevOld &&
1394  ExecQualAndReset(compareTuple, econtext))
1395  duplicate_count++;
1396 
1397  tmpslot = slot2;
1398  slot2 = slot;
1399  slot = tmpslot;
1400  /* avoid ExecQual() calls by reusing abbreviated keys */
1401  abbrevOld = abbrevVal;
1402 
1403  rank++;
1404 
1406  }
1407 
1408  ExecClearTuple(slot);
1409  ExecClearTuple(slot2);
1410 
1411  ExecDropSingleTupleTableSlot(extraslot);
1412 
1413  rank = rank - duplicate_count;
1414 
1415  PG_RETURN_INT64(rank);
1416 }
ExprContext * CreateStandaloneExprContext(void)
Definition: execUtils.c:297
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1791
OSAPerQueryState * qstate
#define DatumGetInt32(X)
Definition: postgres.h:455
#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:475
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
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:2158
bool * tts_isnull
Definition: tuptable.h:126
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:247
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:212
#define TupIsNull(slot)
Definition: tuptable.h:139
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:232
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:389
uintptr_t Datum
Definition: postgres.h:365
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, AttrNumber *keyColIdx, Oid *eqOperators, PlanState *parent)
Definition: execGrouping.c:60
ExprContext * econtext
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:213
#define PG_ARGISNULL(n)
Definition: fmgr.h:174
#define Assert(condition)
Definition: c.h:688
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3492
#define PG_NARGS()
Definition: fmgr.h:168
ExprState * compareTuple
#define Int32GetDatum(X)
Definition: postgres.h:462
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:524
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1435

◆ hypothetical_percent_rank_final()

Datum hypothetical_percent_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1254 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

1255 {
1256  int64 rank;
1257  int64 rowcount;
1258  double result_val;
1259 
1260  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1261 
1262  if (rowcount == 0)
1263  PG_RETURN_FLOAT8(0);
1264 
1265  result_val = (double) (rank - 1) / (double) (rowcount);
1266 
1267  PG_RETURN_FLOAT8(result_val);
1268 }
#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 1167 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().

1169 {
1170  int nargs = PG_NARGS() - 1;
1171  int64 rank = 1;
1172  OSAPerGroupState *osastate;
1173  TupleTableSlot *slot;
1174  int i;
1175 
1177 
1178  /* If there were no regular rows, the rank is always 1 */
1179  if (PG_ARGISNULL(0))
1180  {
1181  *number_of_rows = 0;
1182  return 1;
1183  }
1184 
1185  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1186  *number_of_rows = osastate->number_of_rows;
1187 
1188  /* Adjust nargs to be the number of direct (or aggregated) args */
1189  if (nargs % 2 != 0)
1190  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1191  nargs /= 2;
1192 
1193  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1194 
1195  /* because we need a hypothetical row, we can't share transition state */
1196  Assert(!osastate->sort_done);
1197 
1198  /* insert the hypothetical row into the sort */
1199  slot = osastate->qstate->tupslot;
1200  ExecClearTuple(slot);
1201  for (i = 0; i < nargs; i++)
1202  {
1203  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1204  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1205  }
1206  slot->tts_values[i] = Int32GetDatum(flag);
1207  slot->tts_isnull[i] = false;
1208  ExecStoreVirtualTuple(slot);
1209 
1210  tuplesort_puttupleslot(osastate->sortstate, slot);
1211 
1212  /* finish the sort */
1213  tuplesort_performsort(osastate->sortstate);
1214  osastate->sort_done = true;
1215 
1216  /* iterate till we find the hypothetical row */
1217  while (tuplesort_gettupleslot(osastate->sortstate, true, true, slot, NULL))
1218  {
1219  bool isnull;
1220  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1221 
1222  if (!isnull && DatumGetInt32(d) != 0)
1223  break;
1224 
1225  rank++;
1226 
1228  }
1229 
1230  ExecClearTuple(slot);
1231 
1232  return rank;
1233 }
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1791
OSAPerQueryState * qstate
#define DatumGetInt32(X)
Definition: postgres.h:455
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:233
TupleTableSlot * tupslot
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
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:2158
bool * tts_isnull
Definition: tuptable.h:126
char * flag(int b)
Definition: test-ctype.c:33
uintptr_t Datum
Definition: postgres.h:365
#define PG_ARGISNULL(n)
Definition: fmgr.h:174
#define Assert(condition)
Definition: c.h:688
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3492
#define PG_NARGS()
Definition: fmgr.h:168
#define Int32GetDatum(X)
Definition: postgres.h:462
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:524
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1435

◆ hypothetical_rank_final()

Datum hypothetical_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1240 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_INT64.

1241 {
1242  int64 rank;
1243  int64 rowcount;
1244 
1245  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1246 
1247  PG_RETURN_INT64(rank);
1248 }
#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 510 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().

511 {
512  Datum diff_result = DirectFunctionCall2(interval_mi, hi, lo);
514  diff_result,
515  Float8GetDatumFast(pct));
516 
517  return DirectFunctionCall2(interval_pl, mul_result, lo);
518 }
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:365
#define Float8GetDatumFast(X)
Definition: postgres.h:759
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 1030 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.

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

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

Referenced by ordered_set_startup().

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

◆ ordered_set_startup()

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

Definition at line 116 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().

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

◆ ordered_set_transition()

Datum ordered_set_transition ( PG_FUNCTION_ARGS  )

Definition at line 357 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().

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

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

◆ pct_info_cmp()

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

Definition at line 642 of file orderedsetaggs.c.

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

Referenced by setup_pct_info().

643 {
644  const struct pct_info *a = (const struct pct_info *) pa;
645  const struct pct_info *b = (const struct pct_info *) pb;
646 
647  if (a->first_row != b->first_row)
648  return (a->first_row < b->first_row) ? -1 : 1;
649  if (a->second_row != b->second_row)
650  return (a->second_row < b->second_row) ? -1 : 1;
651  return 0;
652 }
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 524 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().

527 {
528  OSAPerGroupState *osastate;
529  double percentile;
530  int64 first_row = 0;
531  int64 second_row = 0;
532  Datum val;
533  Datum first_val;
534  Datum second_val;
535  double proportion;
536  bool isnull;
537 
539 
540  /* Get and check the percentile argument */
541  if (PG_ARGISNULL(1))
542  PG_RETURN_NULL();
543 
544  percentile = PG_GETARG_FLOAT8(1);
545 
546  if (percentile < 0 || percentile > 1 || isnan(percentile))
547  ereport(ERROR,
548  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
549  errmsg("percentile value %g is not between 0 and 1",
550  percentile)));
551 
552  /* If there were no regular rows, the result is NULL */
553  if (PG_ARGISNULL(0))
554  PG_RETURN_NULL();
555 
556  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
557 
558  /* number_of_rows could be zero if we only saw NULL input values */
559  if (osastate->number_of_rows == 0)
560  PG_RETURN_NULL();
561 
562  Assert(expect_type == osastate->qstate->sortColType);
563 
564  /* Finish the sort, or rescan if we already did */
565  if (!osastate->sort_done)
566  {
567  tuplesort_performsort(osastate->sortstate);
568  osastate->sort_done = true;
569  }
570  else
571  tuplesort_rescan(osastate->sortstate);
572 
573  first_row = floor(percentile * (osastate->number_of_rows - 1));
574  second_row = ceil(percentile * (osastate->number_of_rows - 1));
575 
576  Assert(first_row < osastate->number_of_rows);
577 
578  if (!tuplesort_skiptuples(osastate->sortstate, first_row, true))
579  elog(ERROR, "missing row in percentile_cont");
580 
581  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val, &isnull, NULL))
582  elog(ERROR, "missing row in percentile_cont");
583  if (isnull)
584  PG_RETURN_NULL();
585 
586  if (first_row == second_row)
587  {
588  val = first_val;
589  }
590  else
591  {
592  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val, &isnull, NULL))
593  elog(ERROR, "missing row in percentile_cont");
594 
595  if (isnull)
596  PG_RETURN_NULL();
597 
598  proportion = (percentile * (osastate->number_of_rows - 1)) - first_row;
599  val = lerpfunc(first_val, second_val, proportion);
600  }
601 
602  PG_RETURN_DATUM(val);
603 }
#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:2244
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1791
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:3027
#define ereport(elevel, rest)
Definition: elog.h:122
int64 first_row
uintptr_t Datum
Definition: postgres.h:365
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:313
#define PG_ARGISNULL(n)
Definition: fmgr.h:174
#define Assert(condition)
Definition: c.h:688
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3492
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:2283
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 609 of file orderedsetaggs.c.

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

610 {
612 }
#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 1003 of file orderedsetaggs.c.

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

1004 {
1005  return percentile_cont_multi_final_common(fcinfo,
1006  FLOAT8OID,
1007  /* hard-wired info on type float8 */
1008  8, FLOAT8PASSBYVAL, 'd',
1009  float8_lerp);
1010 }
#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 618 of file orderedsetaggs.c.

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

619 {
621 }
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 1016 of file orderedsetaggs.c.

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

1017 {
1018  return percentile_cont_multi_final_common(fcinfo,
1019  INTERVALOID,
1020  /* hard-wired info on type interval */
1021  16, false, 'd',
1022  interval_lerp);
1023 }
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 845 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().

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

◆ percentile_disc_final()

Datum percentile_disc_final ( PG_FUNCTION_ARGS  )

Definition at line 426 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.

427 {
428  OSAPerGroupState *osastate;
429  double percentile;
430  Datum val;
431  bool isnull;
432  int64 rownum;
433 
435 
436  /* Get and check the percentile argument */
437  if (PG_ARGISNULL(1))
438  PG_RETURN_NULL();
439 
440  percentile = PG_GETARG_FLOAT8(1);
441 
442  if (percentile < 0 || percentile > 1 || isnan(percentile))
443  ereport(ERROR,
444  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
445  errmsg("percentile value %g is not between 0 and 1",
446  percentile)));
447 
448  /* If there were no regular rows, the result is NULL */
449  if (PG_ARGISNULL(0))
450  PG_RETURN_NULL();
451 
452  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
453 
454  /* number_of_rows could be zero if we only saw NULL input values */
455  if (osastate->number_of_rows == 0)
456  PG_RETURN_NULL();
457 
458  /* Finish the sort, or rescan if we already did */
459  if (!osastate->sort_done)
460  {
461  tuplesort_performsort(osastate->sortstate);
462  osastate->sort_done = true;
463  }
464  else
465  tuplesort_rescan(osastate->sortstate);
466 
467  /*----------
468  * We need the smallest K such that (K/N) >= percentile.
469  * N>0, therefore K >= N*percentile, therefore K = ceil(N*percentile).
470  * So we skip K-1 rows (if K>0) and return the next row fetched.
471  *----------
472  */
473  rownum = (int64) ceil(percentile * osastate->number_of_rows);
474  Assert(rownum <= osastate->number_of_rows);
475 
476  if (rownum > 1)
477  {
478  if (!tuplesort_skiptuples(osastate->sortstate, rownum - 1, true))
479  elog(ERROR, "missing row in percentile_disc");
480  }
481 
482  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
483  elog(ERROR, "missing row in percentile_disc");
484 
485  /* We shouldn't have stored any nulls, but do the right thing anyway */
486  if (isnull)
487  PG_RETURN_NULL();
488  else
489  PG_RETURN_DATUM(val);
490 }
#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:2244
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1791
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:3027
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:365
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:313
#define PG_ARGISNULL(n)
Definition: fmgr.h:174
#define Assert(condition)
Definition: c.h:688
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3492
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:2283
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 727 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.

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

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