PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
orderedsetaggs.c File Reference
#include "postgres.h"
#include <math.h>
#include "catalog/pg_aggregate.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/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

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

Definition at line 479 of file orderedsetaggs.c.

Function Documentation

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

Definition at line 482 of file orderedsetaggs.c.

References DatumGetFloat8, and Float8GetDatum().

Referenced by percentile_cont_float8_final(), and percentile_cont_float8_multi_final().

483 {
484  double loval = DatumGetFloat8(lo);
485  double hival = DatumGetFloat8(hi);
486 
487  return Float8GetDatum(loval + (pct * (hival - loval)));
488 }
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:2126
#define DatumGetFloat8(X)
Definition: postgres.h:736
static void hypothetical_check_argtypes ( FunctionCallInfo  fcinfo,
int  nargs,
TupleDesc  tupdesc 
)
static

Definition at line 1119 of file orderedsetaggs.c.

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

Referenced by hypothetical_dense_rank_final(), and hypothetical_rank_common().

1121 {
1122  int i;
1123 
1124  /* check that we have an int4 flag column */
1125  if (!tupdesc ||
1126  (nargs + 1) != tupdesc->natts ||
1127  tupdesc->attrs[nargs]->atttypid != INT4OID)
1128  elog(ERROR, "type mismatch in hypothetical-set function");
1129 
1130  /* check that direct args match in type with aggregated args */
1131  for (i = 0; i < nargs; i++)
1132  {
1133  if (get_fn_expr_argtype(fcinfo->flinfo, i + 1) != tupdesc->attrs[i]->atttypid)
1134  elog(ERROR, "type mismatch in hypothetical-set function");
1135  }
1136 }
Form_pg_attribute * attrs
Definition: tupdesc.h:74
#define INT4OID
Definition: pg_type.h:316
int natts
Definition: tupdesc.h:73
FmgrInfo * flinfo
Definition: fmgr.h:71
#define ERROR
Definition: elog.h:43
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:2220
int i
#define elog
Definition: elog.h:219
Datum hypothetical_cume_dist_final ( PG_FUNCTION_ARGS  )

Definition at line 1253 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

1254 {
1255  int64 rank;
1256  int64 rowcount;
1257  double result_val;
1258 
1259  rank = hypothetical_rank_common(fcinfo, 1, &rowcount);
1260 
1261  result_val = (double) (rank) / (double) (rowcount + 1);
1262 
1263  PG_RETURN_FLOAT8(result_val);
1264 }
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:310
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)
Datum hypothetical_dense_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1270 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(), NULL, OSAPerQueryState::numSortCols, PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_NARGS, PG_RETURN_INT64, OSAPerQueryState::qcontext, OSAPerGroupState::qstate, slot_getattr(), OSAPerQueryState::sortColIdx, OSAPerGroupState::sortstate, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, OSAPerQueryState::tupdesc, TupIsNull, tuplesort_end(), tuplesort_gettupleslot(), tuplesort_performsort(), tuplesort_puttupleslot(), and OSAPerQueryState::tupslot.

1271 {
1272  int nargs = PG_NARGS() - 1;
1273  int64 rank = 1;
1274  int64 duplicate_count = 0;
1275  OSAPerGroupState *osastate;
1276  int numDistinctCols;
1277  Datum abbrevVal = (Datum) 0;
1278  Datum abbrevOld = (Datum) 0;
1279  AttrNumber *sortColIdx;
1280  FmgrInfo *equalfns;
1281  TupleTableSlot *slot;
1282  TupleTableSlot *extraslot;
1283  TupleTableSlot *slot2;
1284  MemoryContext tmpcontext;
1285  int i;
1286 
1288 
1289  /* If there were no regular rows, the rank is always 1 */
1290  if (PG_ARGISNULL(0))
1291  PG_RETURN_INT64(rank);
1292 
1293  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1294 
1295  /* Adjust nargs to be the number of direct (or aggregated) args */
1296  if (nargs % 2 != 0)
1297  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1298  nargs /= 2;
1299 
1300  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1301 
1302  /*
1303  * When comparing tuples, we can omit the flag column since we will only
1304  * compare rows with flag == 0.
1305  */
1306  numDistinctCols = osastate->qstate->numSortCols - 1;
1307 
1308  /* Look up the equality function(s), if we didn't already */
1309  equalfns = osastate->qstate->equalfns;
1310  if (equalfns == NULL)
1311  {
1312  MemoryContext qcontext = osastate->qstate->qcontext;
1313 
1314  equalfns = (FmgrInfo *)
1315  MemoryContextAlloc(qcontext, numDistinctCols * sizeof(FmgrInfo));
1316  for (i = 0; i < numDistinctCols; i++)
1317  {
1318  fmgr_info_cxt(get_opcode(osastate->qstate->eqOperators[i]),
1319  &equalfns[i],
1320  qcontext);
1321  }
1322  osastate->qstate->equalfns = equalfns;
1323  }
1324  sortColIdx = osastate->qstate->sortColIdx;
1325 
1326  /* Get short-term context we can use for execTuplesMatch */
1327  tmpcontext = AggGetTempMemoryContext(fcinfo);
1328 
1329  /* insert the hypothetical row into the sort */
1330  slot = osastate->qstate->tupslot;
1331  ExecClearTuple(slot);
1332  for (i = 0; i < nargs; i++)
1333  {
1334  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1335  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1336  }
1337  slot->tts_values[i] = Int32GetDatum(-1);
1338  slot->tts_isnull[i] = false;
1339  ExecStoreVirtualTuple(slot);
1340 
1341  tuplesort_puttupleslot(osastate->sortstate, slot);
1342 
1343  /* finish the sort */
1344  tuplesort_performsort(osastate->sortstate);
1345 
1346  /*
1347  * We alternate fetching into tupslot and extraslot so that we have the
1348  * previous row available for comparisons. This is accomplished by
1349  * swapping the slot pointer variables after each row.
1350  */
1351  extraslot = MakeSingleTupleTableSlot(osastate->qstate->tupdesc);
1352  slot2 = extraslot;
1353 
1354  /* iterate till we find the hypothetical row */
1355  while (tuplesort_gettupleslot(osastate->sortstate, true, slot, &abbrevVal))
1356  {
1357  bool isnull;
1358  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1359  TupleTableSlot *tmpslot;
1360 
1361  if (!isnull && DatumGetInt32(d) != 0)
1362  break;
1363 
1364  /* count non-distinct tuples */
1365  if (!TupIsNull(slot2) &&
1366  abbrevVal == abbrevOld &&
1367  execTuplesMatch(slot, slot2,
1368  numDistinctCols,
1369  sortColIdx,
1370  equalfns,
1371  tmpcontext))
1372  duplicate_count++;
1373 
1374  tmpslot = slot2;
1375  slot2 = slot;
1376  slot = tmpslot;
1377  /* avoid execTuplesMatch() calls by reusing abbreviated keys */
1378  abbrevOld = abbrevVal;
1379 
1380  rank++;
1381 
1383  }
1384 
1385  ExecClearTuple(slot);
1386  ExecClearTuple(slot2);
1387 
1388  ExecDropSingleTupleTableSlot(extraslot);
1389 
1390  /* Might as well clean up the tuplesort object immediately */
1391  tuplesort_end(osastate->sortstate);
1392  osastate->sortstate = NULL;
1393 
1394  rank = rank - duplicate_count;
1395 
1396  PG_RETURN_INT64(rank);
1397 }
Definition: fmgr.h:53
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1763
OSAPerQueryState * qstate
#define DatumGetInt32(X)
Definition: postgres.h:480
#define PG_RETURN_INT64(x)
Definition: fmgr.h:311
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:224
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:232
MemoryContext qcontext
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:664
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:169
MemoryContext AggGetTempMemoryContext(FunctionCallInfo fcinfo)
Definition: nodeAgg.c:3722
uintptr_t Datum
Definition: postgres.h:374
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1062
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3660
#define PG_NARGS()
Definition: fmgr.h:160
FmgrInfo * equalfns
#define Int32GetDatum(X)
Definition: postgres.h:487
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1143
static void hypothetical_check_argtypes(FunctionCallInfo fcinfo, int nargs, TupleDesc tupdesc)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
#define elog
Definition: elog.h:219
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1157
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:1354
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2099
Datum hypothetical_percent_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1233 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_FLOAT8.

1234 {
1235  int64 rank;
1236  int64 rowcount;
1237  double result_val;
1238 
1239  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1240 
1241  if (rowcount == 0)
1242  PG_RETURN_FLOAT8(0);
1243 
1244  result_val = (double) (rank - 1) / (double) (rowcount);
1245 
1246  PG_RETURN_FLOAT8(result_val);
1247 }
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:310
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)
static int64 hypothetical_rank_common ( FunctionCallInfo  fcinfo,
int  flag,
int64 *  number_of_rows 
)
static

Definition at line 1146 of file orderedsetaggs.c.

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

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

1148 {
1149  int nargs = PG_NARGS() - 1;
1150  int64 rank = 1;
1151  OSAPerGroupState *osastate;
1152  TupleTableSlot *slot;
1153  int i;
1154 
1156 
1157  /* If there were no regular rows, the rank is always 1 */
1158  if (PG_ARGISNULL(0))
1159  {
1160  *number_of_rows = 0;
1161  return 1;
1162  }
1163 
1164  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1165  *number_of_rows = osastate->number_of_rows;
1166 
1167  /* Adjust nargs to be the number of direct (or aggregated) args */
1168  if (nargs % 2 != 0)
1169  elog(ERROR, "wrong number of arguments in hypothetical-set function");
1170  nargs /= 2;
1171 
1172  hypothetical_check_argtypes(fcinfo, nargs, osastate->qstate->tupdesc);
1173 
1174  /* insert the hypothetical row into the sort */
1175  slot = osastate->qstate->tupslot;
1176  ExecClearTuple(slot);
1177  for (i = 0; i < nargs; i++)
1178  {
1179  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
1180  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
1181  }
1182  slot->tts_values[i] = Int32GetDatum(flag);
1183  slot->tts_isnull[i] = false;
1184  ExecStoreVirtualTuple(slot);
1185 
1186  tuplesort_puttupleslot(osastate->sortstate, slot);
1187 
1188  /* finish the sort */
1189  tuplesort_performsort(osastate->sortstate);
1190 
1191  /* iterate till we find the hypothetical row */
1192  while (tuplesort_gettupleslot(osastate->sortstate, true, slot, NULL))
1193  {
1194  bool isnull;
1195  Datum d = slot_getattr(slot, nargs + 1, &isnull);
1196 
1197  if (!isnull && DatumGetInt32(d) != 0)
1198  break;
1199 
1200  rank++;
1201 
1203  }
1204 
1205  ExecClearTuple(slot);
1206 
1207  /* Might as well clean up the tuplesort object immediately */
1208  tuplesort_end(osastate->sortstate);
1209  osastate->sortstate = NULL;
1210 
1211  return rank;
1212 }
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1763
OSAPerQueryState * qstate
#define DatumGetInt32(X)
Definition: postgres.h:480
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:224
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:232
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:664
bool * tts_isnull
Definition: tuptable.h:126
char * flag(int b)
Definition: test-ctype.c:33
uintptr_t Datum
Definition: postgres.h:374
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3660
#define PG_NARGS()
Definition: fmgr.h:160
#define Int32GetDatum(X)
Definition: postgres.h:487
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1143
static void hypothetical_check_argtypes(FunctionCallInfo fcinfo, int nargs, TupleDesc tupdesc)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
#define elog
Definition: elog.h:219
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1157
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1354
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2099
Datum hypothetical_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1219 of file orderedsetaggs.c.

References hypothetical_rank_common(), and PG_RETURN_INT64.

1220 {
1221  int64 rank;
1222  int64 rowcount;
1223 
1224  rank = hypothetical_rank_common(fcinfo, -1, &rowcount);
1225 
1226  PG_RETURN_INT64(rank);
1227 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:311
static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, int64 *number_of_rows)
static Datum interval_lerp ( Datum  lo,
Datum  hi,
double  pct 
)
static

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

492 {
493  Datum diff_result = DirectFunctionCall2(interval_mi, hi, lo);
495  diff_result,
496  Float8GetDatumFast(pct));
497 
498  return DirectFunctionCall2(interval_pl, mul_result, lo);
499 }
Datum interval_mi(PG_FUNCTION_ARGS)
Definition: timestamp.c:3044
Datum interval_pl(PG_FUNCTION_ARGS)
Definition: timestamp.c:3010
uintptr_t Datum
Definition: postgres.h:374
#define Float8GetDatumFast(X)
Definition: postgres.h:784
Datum interval_mul(PG_FUNCTION_ARGS)
Definition: timestamp.c:3084
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:557
Datum mode_final ( PG_FUNCTION_ARGS  )

Definition at line 1010 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(), NULL, OSAPerGroupState::number_of_rows, OidIsValid, pfree(), PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_DATUM, PG_RETURN_NULL, OSAPerQueryState::qcontext, OSAPerGroupState::qstate, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), OSAPerQueryState::typByVal, and val.

1011 {
1012  OSAPerGroupState *osastate;
1013  Datum val;
1014  bool isnull;
1015  Datum mode_val = (Datum) 0;
1016  int64 mode_freq = 0;
1017  Datum last_val = (Datum) 0;
1018  int64 last_val_freq = 0;
1019  bool last_val_is_mode = false;
1020  FmgrInfo *equalfn;
1021  Datum abbrev_val = (Datum) 0;
1022  Datum last_abbrev_val = (Datum) 0;
1023  bool shouldfree;
1024 
1026 
1027  /* If there were no regular rows, the result is NULL */
1028  if (PG_ARGISNULL(0))
1029  PG_RETURN_NULL();
1030 
1031  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
1032 
1033  /* number_of_rows could be zero if we only saw NULL input values */
1034  if (osastate->number_of_rows == 0)
1035  PG_RETURN_NULL();
1036 
1037  /* Look up the equality function for the datatype, if we didn't already */
1038  equalfn = &(osastate->qstate->equalfn);
1039  if (!OidIsValid(equalfn->fn_oid))
1040  fmgr_info_cxt(get_opcode(osastate->qstate->eqOperator), equalfn,
1041  osastate->qstate->qcontext);
1042 
1043  shouldfree = !(osastate->qstate->typByVal);
1044 
1045  /* Finish the sort */
1046  tuplesort_performsort(osastate->sortstate);
1047 
1048  /* Scan tuples and count frequencies */
1049  while (tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, &abbrev_val))
1050  {
1051  /* we don't expect any nulls, but ignore them if found */
1052  if (isnull)
1053  continue;
1054 
1055  if (last_val_freq == 0)
1056  {
1057  /* first nonnull value - it's the mode for now */
1058  mode_val = last_val = val;
1059  mode_freq = last_val_freq = 1;
1060  last_val_is_mode = true;
1061  last_abbrev_val = abbrev_val;
1062  }
1063  else if (abbrev_val == last_abbrev_val &&
1064  DatumGetBool(FunctionCall2(equalfn, val, last_val)))
1065  {
1066  /* value equal to previous value, count it */
1067  if (last_val_is_mode)
1068  mode_freq++; /* needn't maintain last_val_freq */
1069  else if (++last_val_freq > mode_freq)
1070  {
1071  /* last_val becomes new mode */
1072  if (shouldfree)
1073  pfree(DatumGetPointer(mode_val));
1074  mode_val = last_val;
1075  mode_freq = last_val_freq;
1076  last_val_is_mode = true;
1077  }
1078  if (shouldfree)
1079  pfree(DatumGetPointer(val));
1080  }
1081  else
1082  {
1083  /* val should replace last_val */
1084  if (shouldfree && !last_val_is_mode)
1085  pfree(DatumGetPointer(last_val));
1086  last_val = val;
1087  /* avoid equality function calls by reusing abbreviated keys */
1088  last_abbrev_val = abbrev_val;
1089  last_val_freq = 1;
1090  last_val_is_mode = false;
1091  }
1092 
1094  }
1095 
1096  if (shouldfree && !last_val_is_mode)
1097  pfree(DatumGetPointer(last_val));
1098 
1099  /*
1100  * Note: we *cannot* clean up the tuplesort object here, because the value
1101  * to be returned is allocated inside its sortcontext. We could use
1102  * datumCopy to copy it out of there, but it doesn't seem worth the
1103  * trouble, since the cleanup callback will clear the tuplesort later.
1104  */
1105 
1106  if (mode_freq)
1107  PG_RETURN_DATUM(mode_val);
1108  else
1109  PG_RETURN_NULL();
1110 }
Definition: fmgr.h:53
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2183
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1763
OSAPerQueryState * qstate
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:575
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:232
#define OidIsValid(objectId)
Definition: c.h:534
MemoryContext qcontext
void pfree(void *pointer)
Definition: mcxt.c:992
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:664
#define DatumGetBool(X)
Definition: postgres.h:401
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:169
uintptr_t Datum
Definition: postgres.h:374
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:297
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1062
Oid fn_oid
Definition: fmgr.h:56
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3660
#define DatumGetPointer(X)
Definition: postgres.h:557
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
long val
Definition: informix.c:689
#define PG_RETURN_NULL()
Definition: fmgr.h:289
static void ordered_set_shutdown ( Datum  arg)
static

Definition at line 318 of file orderedsetaggs.c.

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

Referenced by ordered_set_startup().

319 {
321 
322  /* Tuplesort object might have temp files. */
323  if (osastate->sortstate)
324  tuplesort_end(osastate->sortstate);
325  osastate->sortstate = NULL;
326  /* The tupleslot probably can't be holding a pin, but let's be safe. */
327  if (osastate->qstate->tupslot)
328  ExecClearTuple(osastate->qstate->tupslot);
329 }
OSAPerQueryState * qstate
TupleTableSlot * tupslot
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define NULL
Definition: c.h:226
Tuplesortstate * sortstate
#define DatumGetPointer(X)
Definition: postgres.h:557
void * arg
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1157
static OSAPerGroupState* ordered_set_startup ( FunctionCallInfo  fcinfo,
bool  use_tuples 
)
static

Definition at line 102 of file orderedsetaggs.c.

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), AggGetAggref(), Aggref::aggkind, AGGKIND_HYPOTHETICAL, AGGKIND_IS_ORDERED_SET, Aggref::aggorder, OSAPerQueryState::aggref, AggRegisterCallback(), 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, NULL, SortGroupClause::nulls_first, OSAPerGroupState::number_of_rows, OSAPerQueryState::numSortCols, OidIsValid, ordered_set_shutdown(), palloc(), palloc0(), PointerGetDatum, OSAPerQueryState::qcontext, OSAPerGroupState::qstate, TargetEntry::resno, 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().

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

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

338 {
339  OSAPerGroupState *osastate;
340 
341  /* If first call, create the transition state workspace */
342  if (PG_ARGISNULL(0))
343  osastate = ordered_set_startup(fcinfo, false);
344  else
345  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
346 
347  /* Load the datum into the tuplesort object, but only if it's not null */
348  if (!PG_ARGISNULL(1))
349  {
350  tuplesort_putdatum(osastate->sortstate, PG_GETARG_DATUM(1), false);
351  osastate->number_of_rows++;
352  }
353 
354  PG_RETURN_POINTER(osastate);
355 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:305
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Definition: tuplesort.c:1475
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:224
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:232
static OSAPerGroupState * ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples)
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
Tuplesortstate * sortstate
Datum ordered_set_transition_multi ( PG_FUNCTION_ARGS  )

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

363 {
364  OSAPerGroupState *osastate;
365  TupleTableSlot *slot;
366  int nargs;
367  int i;
368 
369  /* If first call, create the transition state workspace */
370  if (PG_ARGISNULL(0))
371  osastate = ordered_set_startup(fcinfo, true);
372  else
373  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
374 
375  /* Form a tuple from all the other inputs besides the transition value */
376  slot = osastate->qstate->tupslot;
377  ExecClearTuple(slot);
378  nargs = PG_NARGS() - 1;
379  for (i = 0; i < nargs; i++)
380  {
381  slot->tts_values[i] = PG_GETARG_DATUM(i + 1);
382  slot->tts_isnull[i] = PG_ARGISNULL(i + 1);
383  }
384  if (osastate->qstate->aggref->aggkind == AGGKIND_HYPOTHETICAL)
385  {
386  /* Add a zero flag value to mark this row as a normal input row */
387  slot->tts_values[i] = Int32GetDatum(0);
388  slot->tts_isnull[i] = false;
389  i++;
390  }
391  Assert(i == slot->tts_tupleDescriptor->natts);
392  ExecStoreVirtualTuple(slot);
393 
394  /* Load the row into the tuplesort object */
395  tuplesort_puttupleslot(osastate->sortstate, slot);
396  osastate->number_of_rows++;
397 
398  PG_RETURN_POINTER(osastate);
399 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:305
OSAPerQueryState * qstate
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:224
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:232
int natts
Definition: tupdesc.h:73
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:166
#define Assert(condition)
Definition: c.h:671
Tuplesortstate * sortstate
#define PG_NARGS()
Definition: fmgr.h:160
#define Int32GetDatum(X)
Definition: postgres.h:487
int i
char aggkind
Definition: primnodes.h:286
#define AGGKIND_HYPOTHETICAL
Definition: pg_aggregate.h:126
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1354
static int pct_info_cmp ( const void *  pa,
const void *  pb 
)
static

Definition at line 624 of file orderedsetaggs.c.

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

Referenced by setup_pct_info().

625 {
626  const struct pct_info *a = (const struct pct_info *) pa;
627  const struct pct_info *b = (const struct pct_info *) pb;
628 
629  if (a->first_row != b->first_row)
630  return (a->first_row < b->first_row) ? -1 : 1;
631  if (a->second_row != b->second_row)
632  return (a->second_row < b->second_row) ? -1 : 1;
633  return 0;
634 }
int64 second_row
int64 first_row
static Datum percentile_cont_final_common ( FunctionCallInfo  fcinfo,
Oid  expect_type,
LerpFunc  lerpfunc 
)
static

Definition at line 505 of file orderedsetaggs.c.

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

Referenced by percentile_cont_float8_final(), and percentile_cont_interval_final().

508 {
509  OSAPerGroupState *osastate;
510  double percentile;
511  int64 first_row = 0;
512  int64 second_row = 0;
513  Datum val;
514  Datum first_val;
515  Datum second_val;
516  double proportion;
517  bool isnull;
518 
520 
521  /* Get and check the percentile argument */
522  if (PG_ARGISNULL(1))
523  PG_RETURN_NULL();
524 
525  percentile = PG_GETARG_FLOAT8(1);
526 
527  if (percentile < 0 || percentile > 1 || isnan(percentile))
528  ereport(ERROR,
529  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
530  errmsg("percentile value %g is not between 0 and 1",
531  percentile)));
532 
533  /* If there were no regular rows, the result is NULL */
534  if (PG_ARGISNULL(0))
535  PG_RETURN_NULL();
536 
537  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
538 
539  /* number_of_rows could be zero if we only saw NULL input values */
540  if (osastate->number_of_rows == 0)
541  PG_RETURN_NULL();
542 
543  Assert(expect_type == osastate->qstate->sortColType);
544 
545  /* Finish the sort */
546  tuplesort_performsort(osastate->sortstate);
547 
548  first_row = floor(percentile * (osastate->number_of_rows - 1));
549  second_row = ceil(percentile * (osastate->number_of_rows - 1));
550 
551  Assert(first_row < osastate->number_of_rows);
552 
553  if (!tuplesort_skiptuples(osastate->sortstate, first_row, true))
554  elog(ERROR, "missing row in percentile_cont");
555 
556  if (!tuplesort_getdatum(osastate->sortstate, true, &first_val, &isnull, NULL))
557  elog(ERROR, "missing row in percentile_cont");
558  if (isnull)
559  PG_RETURN_NULL();
560 
561  if (first_row == second_row)
562  {
563  val = first_val;
564  }
565  else
566  {
567  if (!tuplesort_getdatum(osastate->sortstate, true, &second_val, &isnull, NULL))
568  elog(ERROR, "missing row in percentile_cont");
569 
570  if (isnull)
571  PG_RETURN_NULL();
572 
573  proportion = (percentile * (osastate->number_of_rows - 1)) - first_row;
574  val = lerpfunc(first_val, second_val, proportion);
575  }
576 
577  /*
578  * Note: we *cannot* clean up the tuplesort object here, because the value
579  * to be returned may be allocated inside its sortcontext. We could use
580  * datumCopy to copy it out of there, but it doesn't seem worth the
581  * trouble, since the cleanup callback will clear the tuplesort later.
582  */
583 
584  PG_RETURN_DATUM(val);
585 }
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:237
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2183
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1763
OSAPerQueryState * qstate
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:232
int64 second_row
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:664
#define ereport(elevel, rest)
Definition: elog.h:122
int64 first_row
uintptr_t Datum
Definition: postgres.h:374
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:297
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3660
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:2222
long val
Definition: informix.c:689
#define PG_RETURN_NULL()
Definition: fmgr.h:289
Datum percentile_cont_float8_final ( PG_FUNCTION_ARGS  )

Definition at line 591 of file orderedsetaggs.c.

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

592 {
594 }
#define FLOAT8OID
Definition: pg_type.h:411
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)
static Datum float8_lerp(Datum lo, Datum hi, double pct)
Datum percentile_cont_float8_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 983 of file orderedsetaggs.c.

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

984 {
986  FLOAT8OID,
987  /* hard-wired info on type float8 */
988  8, FLOAT8PASSBYVAL, 'd',
989  float8_lerp);
990 }
#define FLOAT8OID
Definition: pg_type.h:411
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)
Datum percentile_cont_interval_final ( PG_FUNCTION_ARGS  )

Definition at line 600 of file orderedsetaggs.c.

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

601 {
603 }
static Datum interval_lerp(Datum lo, Datum hi, double pct)
#define INTERVALOID
Definition: pg_type.h:517
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)
Datum percentile_cont_interval_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 996 of file orderedsetaggs.c.

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

997 {
999  INTERVALOID,
1000  /* hard-wired info on type interval */
1001  16, false, 'd',
1002  interval_lerp);
1003 }
static Datum interval_lerp(Datum lo, Datum hi, double pct)
#define INTERVALOID
Definition: pg_type.h:517
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)
static Datum percentile_cont_multi_final_common ( FunctionCallInfo  fcinfo,
Oid  expect_type,
int16  typLen,
bool  typByVal,
char  typAlign,
LerpFunc  lerpfunc 
)
static

Definition at line 826 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, NULL, 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(), OSAPerQueryState::sortColType, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), and tuplesort_skiptuples().

Referenced by percentile_cont_float8_multi_final(), and percentile_cont_interval_multi_final().

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

Definition at line 406 of file orderedsetaggs.c.

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

407 {
408  OSAPerGroupState *osastate;
409  double percentile;
410  Datum val;
411  bool isnull;
412  int64 rownum;
413 
415 
416  /* Get and check the percentile argument */
417  if (PG_ARGISNULL(1))
418  PG_RETURN_NULL();
419 
420  percentile = PG_GETARG_FLOAT8(1);
421 
422  if (percentile < 0 || percentile > 1 || isnan(percentile))
423  ereport(ERROR,
424  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
425  errmsg("percentile value %g is not between 0 and 1",
426  percentile)));
427 
428  /* If there were no regular rows, the result is NULL */
429  if (PG_ARGISNULL(0))
430  PG_RETURN_NULL();
431 
432  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
433 
434  /* number_of_rows could be zero if we only saw NULL input values */
435  if (osastate->number_of_rows == 0)
436  PG_RETURN_NULL();
437 
438  /* Finish the sort */
439  tuplesort_performsort(osastate->sortstate);
440 
441  /*----------
442  * We need the smallest K such that (K/N) >= percentile.
443  * N>0, therefore K >= N*percentile, therefore K = ceil(N*percentile).
444  * So we skip K-1 rows (if K>0) and return the next row fetched.
445  *----------
446  */
447  rownum = (int64) ceil(percentile * osastate->number_of_rows);
448  Assert(rownum <= osastate->number_of_rows);
449 
450  if (rownum > 1)
451  {
452  if (!tuplesort_skiptuples(osastate->sortstate, rownum - 1, true))
453  elog(ERROR, "missing row in percentile_disc");
454  }
455 
456  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
457  elog(ERROR, "missing row in percentile_disc");
458 
459  /*
460  * Note: we *cannot* clean up the tuplesort object here, because the value
461  * to be returned is allocated inside its sortcontext. We could use
462  * datumCopy to copy it out of there, but it doesn't seem worth the
463  * trouble, since the cleanup callback will clear the tuplesort later.
464  */
465 
466  /* We shouldn't have stored any nulls, but do the right thing anyway */
467  if (isnull)
468  PG_RETURN_NULL();
469  else
470  PG_RETURN_DATUM(val);
471 }
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:237
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2183
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1763
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:232
#define ERROR
Definition: elog.h:43
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:664
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:374
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:297
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Tuplesortstate * sortstate
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3660
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:2222
long val
Definition: informix.c:689
#define PG_RETURN_NULL()
Definition: fmgr.h:289
Datum percentile_disc_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 709 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, NULL, 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(), OSAPerQueryState::sortColType, OSAPerGroupState::sortstate, tuplesort_getdatum(), tuplesort_performsort(), tuplesort_skiptuples(), OSAPerQueryState::typAlign, OSAPerQueryState::typByVal, OSAPerQueryState::typLen, and val.

710 {
711  OSAPerGroupState *osastate;
712  ArrayType *param;
713  Datum *percentiles_datum;
714  bool *percentiles_null;
715  int num_percentiles;
716  struct pct_info *pct_info;
717  Datum *result_datum;
718  bool *result_isnull;
719  int64 rownum = 0;
720  Datum val = (Datum) 0;
721  bool isnull = true;
722  int i;
723 
725 
726  /* If there were no regular rows, the result is NULL */
727  if (PG_ARGISNULL(0))
728  PG_RETURN_NULL();
729 
730  osastate = (OSAPerGroupState *) PG_GETARG_POINTER(0);
731 
732  /* number_of_rows could be zero if we only saw NULL input values */
733  if (osastate->number_of_rows == 0)
734  PG_RETURN_NULL();
735 
736  /* Deconstruct the percentile-array input */
737  if (PG_ARGISNULL(1))
738  PG_RETURN_NULL();
739  param = PG_GETARG_ARRAYTYPE_P(1);
740 
742  /* hard-wired info on type float8 */
743  8, FLOAT8PASSBYVAL, 'd',
744  &percentiles_datum,
745  &percentiles_null,
746  &num_percentiles);
747 
748  if (num_percentiles == 0)
750 
751  pct_info = setup_pct_info(num_percentiles,
752  percentiles_datum,
753  percentiles_null,
754  osastate->number_of_rows,
755  false);
756 
757  result_datum = (Datum *) palloc(num_percentiles * sizeof(Datum));
758  result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
759 
760  /*
761  * Start by dealing with any nulls in the param array - those are sorted
762  * to the front on row=0, so set the corresponding result indexes to null
763  */
764  for (i = 0; i < num_percentiles; i++)
765  {
766  int idx = pct_info[i].idx;
767 
768  if (pct_info[i].first_row > 0)
769  break;
770 
771  result_datum[idx] = (Datum) 0;
772  result_isnull[idx] = true;
773  }
774 
775  /*
776  * If there's anything left after doing the nulls, then grind the input
777  * and extract the needed values
778  */
779  if (i < num_percentiles)
780  {
781  /* Finish the sort */
782  tuplesort_performsort(osastate->sortstate);
783 
784  for (; i < num_percentiles; i++)
785  {
786  int64 target_row = pct_info[i].first_row;
787  int idx = pct_info[i].idx;
788 
789  /* Advance to target row, if not already there */
790  if (target_row > rownum)
791  {
792  if (!tuplesort_skiptuples(osastate->sortstate, target_row - rownum - 1, true))
793  elog(ERROR, "missing row in percentile_disc");
794 
795  if (!tuplesort_getdatum(osastate->sortstate, true, &val, &isnull, NULL))
796  elog(ERROR, "missing row in percentile_disc");
797 
798  rownum = target_row;
799  }
800 
801  result_datum[idx] = val;
802  result_isnull[idx] = isnull;
803  }
804  }
805 
806  /*
807  * We could clean up the tuplesort object after forming the array, but
808  * probably not worth the trouble.
809  */
810 
811  /* We make the output array the same shape as the input */
812  PG_RETURN_POINTER(construct_md_array(result_datum, result_isnull,
813  ARR_NDIM(param),
814  ARR_DIMS(param),
815  ARR_LBOUND(param),
816  osastate->qstate->sortColType,
817  osastate->qstate->typLen,
818  osastate->qstate->typByVal,
819  osastate->qstate->typAlign));
820 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:305
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2183
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1763
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:232
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3424
#define ARR_LBOUND(a)
Definition: array.h:277
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:244
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:275
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:664
int64 first_row
uintptr_t Datum
Definition: postgres.h:374
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Tuplesortstate * sortstate
#define FLOAT8OID
Definition: pg_type.h:411
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:3660
#define ARR_NDIM(a)
Definition: array.h:271
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3475
void * palloc(Size size)
Definition: mcxt.c:891
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:3340
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
Definition: tuplesort.c:2222
long val
Definition: informix.c:689
#define PG_RETURN_NULL()
Definition: fmgr.h:289
static struct pct_info* setup_pct_info ( int  num_percentiles,
Datum percentiles_datum,
bool percentiles_null,
int64  rowcount,
bool  continuous 
)
static

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

645 {
646  struct pct_info *pct_info;
647  int i;
648 
649  pct_info = (struct pct_info *) palloc(num_percentiles * sizeof(struct pct_info));
650 
651  for (i = 0; i < num_percentiles; i++)
652  {
653  pct_info[i].idx = i;
654 
655  if (percentiles_null[i])
656  {
657  /* dummy entry for any NULL in array */
658  pct_info[i].first_row = 0;
659  pct_info[i].second_row = 0;
660  pct_info[i].proportion = 0;
661  }
662  else
663  {
664  double p = DatumGetFloat8(percentiles_datum[i]);
665 
666  if (p < 0 || p > 1 || isnan(p))
667  ereport(ERROR,
668  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
669  errmsg("percentile value %g is not between 0 and 1",
670  p)));
671 
672  if (continuous)
673  {
674  pct_info[i].first_row = 1 + floor(p * (rowcount - 1));
675  pct_info[i].second_row = 1 + ceil(p * (rowcount - 1));
676  pct_info[i].proportion = (p * (rowcount - 1)) - floor(p * (rowcount - 1));
677  }
678  else
679  {
680  /*----------
681  * We need the smallest K such that (K/N) >= percentile.
682  * N>0, therefore K >= N*percentile, therefore
683  * K = ceil(N*percentile); but not less than 1.
684  *----------
685  */
686  int64 row = (int64) ceil(p * rowcount);
687 
688  row = Max(1, row);
689  pct_info[i].first_row = row;
690  pct_info[i].second_row = row;
691  pct_info[i].proportion = 0;
692  }
693  }
694  }
695 
696  /*
697  * The parameter array wasn't necessarily in sorted order, but we need to
698  * visit the rows in order, so sort by first_row/second_row.
699  */
700  qsort(pct_info, num_percentiles, sizeof(struct pct_info), pct_info_cmp);
701 
702  return pct_info;
703 }
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:736
#define Max(x, y)
Definition: c.h:796
double proportion
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define qsort(a, b, c, d)
Definition: port.h:440
static int pct_info_cmp(const void *pa, const void *pb)