PostgreSQL Source Code git master
Loading...
Searching...
No Matches
orderedsetaggs.c File Reference
#include "postgres.h"
#include <math.h>
#include "catalog/pg_aggregate.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/fmgrprotos.h"
#include "utils/lsyscache.h"
#include "utils/tuplesort.h"
Include dependency graph for orderedsetaggs.c:

Go to the source code of this file.

Data Structures

struct  OSAPerQueryState
 
struct  OSAPerGroupState
 
struct  pct_info
 

Typedefs

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

Functions

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

Typedef Documentation

◆ LerpFunc

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

Definition at line 501 of file orderedsetaggs.c.

◆ OSAPerGroupState

◆ OSAPerQueryState

Function Documentation

◆ float8_lerp()

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

Definition at line 504 of file orderedsetaggs.c.

505{
506 double loval = DatumGetFloat8(lo);
507 double hival = DatumGetFloat8(hi);
508
509 return Float8GetDatum(loval + (pct * (hival - loval)));
510}
static float8 DatumGetFloat8(Datum X)
Definition postgres.h:485
static Datum Float8GetDatum(float8 X)
Definition postgres.h:502
static int fb(int x)

References DatumGetFloat8(), fb(), and Float8GetDatum().

Referenced by percentile_cont_float8_final(), and percentile_cont_float8_multi_final().

◆ hypothetical_check_argtypes()

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

Definition at line 1143 of file orderedsetaggs.c.

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

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

Referenced by hypothetical_dense_rank_final(), and hypothetical_rank_common().

◆ hypothetical_cume_dist_final()

Datum hypothetical_cume_dist_final ( PG_FUNCTION_ARGS  )

Definition at line 1279 of file orderedsetaggs.c.

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

References fb(), hypothetical_rank_common(), and PG_RETURN_FLOAT8.

◆ hypothetical_dense_rank_final()

Datum hypothetical_dense_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1296 of file orderedsetaggs.c.

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

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, CHECK_FOR_INTERRUPTS, CreateStandaloneExprContext(), DatumGetInt32(), ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, elog, ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecQualAndReset(), ExecStoreVirtualTuple(), execTuplesMatchPrepare(), fb(), hypothetical_check_argtypes(), i, Int32GetDatum(), MakeSingleTupleTableSlot(), MemoryContextSwitchTo(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_NARGS, PG_RETURN_INT64, slot_getattr(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TTSOpsMinimalTuple, TupIsNull, tuplesort_gettupleslot(), tuplesort_performsort(), and tuplesort_puttupleslot().

◆ hypothetical_percent_rank_final()

Datum hypothetical_percent_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1259 of file orderedsetaggs.c.

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

References fb(), hypothetical_rank_common(), and PG_RETURN_FLOAT8.

◆ hypothetical_rank_common()

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

Definition at line 1172 of file orderedsetaggs.c.

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

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, CHECK_FOR_INTERRUPTS, DatumGetInt32(), elog, ERROR, ExecClearTuple(), ExecStoreVirtualTuple(), fb(), flag(), hypothetical_check_argtypes(), i, Int32GetDatum(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_NARGS, slot_getattr(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, tuplesort_gettupleslot(), tuplesort_performsort(), and tuplesort_puttupleslot().

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

◆ hypothetical_rank_final()

Datum hypothetical_rank_final ( PG_FUNCTION_ARGS  )

Definition at line 1245 of file orderedsetaggs.c.

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

References hypothetical_rank_common(), and PG_RETURN_INT64.

◆ interval_lerp()

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

Definition at line 513 of file orderedsetaggs.c.

514{
519
521}
Datum interval_mi(PG_FUNCTION_ARGS)
Definition timestamp.c:3553
Datum interval_pl(PG_FUNCTION_ARGS)
Definition timestamp.c:3497
Datum interval_mul(PG_FUNCTION_ARGS)
Definition timestamp.c:3602
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:686
#define Float8GetDatumFast(X)
Definition postgres.h:527

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

Referenced by percentile_cont_interval_final(), and percentile_cont_interval_multi_final().

◆ mode_final()

Datum mode_final ( PG_FUNCTION_ARGS  )

Definition at line 1034 of file orderedsetaggs.c.

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

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), Assert, CHECK_FOR_INTERRUPTS, DatumGetBool(), DatumGetPointer(), fb(), fmgr_info_cxt(), FmgrInfo::fn_oid, FunctionCall2Coll(), get_opcode(), OidIsValid, pfree(), PG_ARGISNULL, PG_GET_COLLATION, PG_GETARG_POINTER, PG_RETURN_DATUM, PG_RETURN_NULL, tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), and val.

◆ ordered_set_shutdown()

static void ordered_set_shutdown ( Datum  arg)
static

Definition at line 340 of file orderedsetaggs.c.

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

References arg, DatumGetPointer(), ExecClearTuple(), fb(), and tuplesort_end().

Referenced by ordered_set_startup().

◆ ordered_set_startup()

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

Definition at line 113 of file orderedsetaggs.c.

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

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), AggGetAggref(), Aggref::aggorder, OSAPerQueryState::aggref, AggRegisterCallback(), AggStateIsShared(), Aggref::args, Assert, CreateTemplateTupleDesc(), elog, OSAPerQueryState::eqOperator, OSAPerQueryState::eqOperators, ERROR, ExecTypeFromTL(), exprCollation(), exprType(), fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, FreeTupleDesc(), get_sortgroupclause_tle(), get_typlenbyvalalign(), i, InvalidOid, lfirst, linitial, list_length(), MakeSingleTupleTableSlot(), MemoryContextSwitchTo(), TupleDescData::natts, OSAPerQueryState::numSortCols, OidIsValid, ordered_set_shutdown(), palloc(), palloc0_object, palloc_object, PointerGetDatum(), OSAPerQueryState::qcontext, OSAPerQueryState::rescan_needed, OSAPerQueryState::sortColIdx, OSAPerQueryState::sortCollation, OSAPerQueryState::sortCollations, OSAPerQueryState::sortColType, OSAPerQueryState::sortNullsFirst, OSAPerQueryState::sortNullsFirsts, OSAPerQueryState::sortOperator, OSAPerQueryState::sortOperators, TTSOpsMinimalTuple, OSAPerQueryState::tupdesc, TupleDescCopyEntry(), TupleDescFinalize(), TupleDescInitEntry(), tuplesort_begin_datum(), tuplesort_begin_heap(), TUPLESORT_NONE, TUPLESORT_RANDOMACCESS, OSAPerQueryState::tupslot, OSAPerQueryState::typAlign, OSAPerQueryState::typByVal, OSAPerQueryState::typLen, and work_mem.

Referenced by ordered_set_transition(), and ordered_set_transition_multi().

◆ ordered_set_transition()

Datum ordered_set_transition ( PG_FUNCTION_ARGS  )

Definition at line 359 of file orderedsetaggs.c.

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

References fb(), ordered_set_startup(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_RETURN_POINTER, and tuplesort_putdatum().

◆ ordered_set_transition_multi()

Datum ordered_set_transition_multi ( PG_FUNCTION_ARGS  )

Definition at line 384 of file orderedsetaggs.c.

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

References Assert, ExecClearTuple(), ExecStoreVirtualTuple(), fb(), i, Int32GetDatum(), TupleDescData::natts, ordered_set_startup(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_NARGS, PG_RETURN_POINTER, TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, TupleTableSlot::tts_values, and tuplesort_puttupleslot().

◆ pct_info_cmp()

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

Definition at line 647 of file orderedsetaggs.c.

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

References a, b, and fb().

Referenced by setup_pct_info().

◆ percentile_cont_final_common()

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

Definition at line 527 of file orderedsetaggs.c.

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

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

Referenced by percentile_cont_float8_final(), and percentile_cont_interval_final().

◆ percentile_cont_float8_final()

Datum percentile_cont_float8_final ( PG_FUNCTION_ARGS  )

Definition at line 614 of file orderedsetaggs.c.

615{
617}
static Datum float8_lerp(Datum lo, Datum hi, double pct)
static Datum percentile_cont_final_common(FunctionCallInfo fcinfo, Oid expect_type, LerpFunc lerpfunc)

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

◆ percentile_cont_float8_multi_final()

Datum percentile_cont_float8_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 1005 of file orderedsetaggs.c.

1006{
1008 FLOAT8OID,
1009 /* hard-wired info on type float8 */
1010 sizeof(float8),
1011 true,
1013 float8_lerp);
1014}
double float8
Definition c.h:714
static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, int16 typLen, bool typByVal, char typAlign, LerpFunc lerpfunc)

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

◆ percentile_cont_interval_final()

Datum percentile_cont_interval_final ( PG_FUNCTION_ARGS  )

Definition at line 623 of file orderedsetaggs.c.

624{
626}
static Datum interval_lerp(Datum lo, Datum hi, double pct)

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

◆ percentile_cont_interval_multi_final()

Datum percentile_cont_interval_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 1020 of file orderedsetaggs.c.

1021{
1024 /* hard-wired info on type interval */
1025 16, false, TYPALIGN_DOUBLE,
1027}

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

◆ percentile_cont_multi_final_common()

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

Definition at line 849 of file orderedsetaggs.c.

853{
855 ArrayType *param;
857 bool *percentiles_null;
858 int num_percentiles;
859 struct pct_info *pct_info;
861 bool *result_isnull;
862 int64 rownum = 0;
863 Datum first_val = (Datum) 0;
864 Datum second_val = (Datum) 0;
865 bool isnull;
866 int i;
867
869
870 /* If there were no regular rows, the result is NULL */
871 if (PG_ARGISNULL(0))
873
875
876 /* number_of_rows could be zero if we only saw NULL input values */
877 if (osastate->number_of_rows == 0)
879
880 Assert(expect_type == osastate->qstate->sortColType);
881
882 /* Deconstruct the percentile-array input */
883 if (PG_ARGISNULL(1))
885 param = PG_GETARG_ARRAYTYPE_P(1);
886
891
892 if (num_percentiles == 0)
893 PG_RETURN_POINTER(construct_empty_array(osastate->qstate->sortColType));
894
898 osastate->number_of_rows,
899 true);
900
902 result_isnull = (bool *) palloc(num_percentiles * sizeof(bool));
903
904 /*
905 * Start by dealing with any nulls in the param array - those are sorted
906 * to the front on row=0, so set the corresponding result indexes to null
907 */
908 for (i = 0; i < num_percentiles; i++)
909 {
910 int idx = pct_info[i].idx;
911
912 if (pct_info[i].first_row > 0)
913 break;
914
915 result_datum[idx] = (Datum) 0;
916 result_isnull[idx] = true;
917 }
918
919 /*
920 * If there's anything left after doing the nulls, then grind the input
921 * and extract the needed values
922 */
923 if (i < num_percentiles)
924 {
925 /* Finish the sort, or rescan if we already did */
926 if (!osastate->sort_done)
927 {
929 osastate->sort_done = true;
930 }
931 else
932 tuplesort_rescan(osastate->sortstate);
933
934 for (; i < num_percentiles; i++)
935 {
938 int idx = pct_info[i].idx;
939
940 /*
941 * Advance to first_row, if not already there. Note that we might
942 * already have rownum beyond first_row, in which case first_val
943 * is already correct. (This occurs when interpolating between
944 * the same two input rows as for the previous percentile.)
945 */
946 if (first_row > rownum)
947 {
948 if (!tuplesort_skiptuples(osastate->sortstate, first_row - rownum - 1, true))
949 elog(ERROR, "missing row in percentile_cont");
950
951 if (!tuplesort_getdatum(osastate->sortstate, true, true,
952 &first_val, &isnull, NULL) || isnull)
953 elog(ERROR, "missing row in percentile_cont");
954
955 rownum = first_row;
956 /* Always advance second_val to be latest input value */
958 }
959 else if (first_row == rownum)
960 {
961 /*
962 * We are already at the desired row, so we must previously
963 * have read its value into second_val (and perhaps first_val
964 * as well, but this assignment is harmless in that case).
965 */
967 }
968
969 /* Fetch second_row if needed */
970 if (second_row > rownum)
971 {
972 if (!tuplesort_getdatum(osastate->sortstate, true, true,
973 &second_val, &isnull, NULL) || isnull)
974 elog(ERROR, "missing row in percentile_cont");
975 rownum++;
976 }
977 /* We should now certainly be on second_row exactly */
978 Assert(second_row == rownum);
979
980 /* Compute appropriate result */
981 if (second_row > first_row)
984 else
986
987 result_isnull[idx] = false;
988 }
989 }
990
991 /* We make the output array the same shape as the input */
993 ARR_NDIM(param),
994 ARR_DIMS(param), ARR_LBOUND(param),
996 typLen,
997 typByVal,
998 typAlign));
999}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
#define ARR_NDIM(a)
Definition array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
#define ARR_DIMS(a)
Definition array.h:294
#define ARR_LBOUND(a)
Definition array.h:296
ArrayType * construct_empty_array(Oid elmtype)
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
static struct pct_info * setup_pct_info(int num_percentiles, const Datum *percentiles_datum, const bool *percentiles_null, int64 rowcount, bool continuous)
int64 first_row
int64 second_row
double proportion

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array_builtin(), elog, ERROR, fb(), pct_info::first_row, i, idx(), pct_info::idx, palloc(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_POINTER, PG_RETURN_NULL, PG_RETURN_POINTER, pct_info::proportion, pct_info::second_row, setup_pct_info(), tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), and tuplesort_skiptuples().

Referenced by percentile_cont_float8_multi_final(), and percentile_cont_interval_multi_final().

◆ percentile_disc_final()

Datum percentile_disc_final ( PG_FUNCTION_ARGS  )

Definition at line 428 of file orderedsetaggs.c.

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

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

◆ percentile_disc_multi_final()

Datum percentile_disc_multi_final ( PG_FUNCTION_ARGS  )

Definition at line 732 of file orderedsetaggs.c.

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

References AGG_CONTEXT_AGGREGATE, AggCheckCallContext(), ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array_builtin(), elog, ERROR, fb(), pct_info::first_row, i, idx(), pct_info::idx, palloc(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_POINTER, PG_RETURN_NULL, PG_RETURN_POINTER, setup_pct_info(), tuplesort_getdatum(), tuplesort_performsort(), tuplesort_rescan(), tuplesort_skiptuples(), and val.

◆ setup_pct_info()

static struct pct_info * setup_pct_info ( int  num_percentiles,
const Datum percentiles_datum,
const bool percentiles_null,
int64  rowcount,
bool  continuous 
)
static

Definition at line 663 of file orderedsetaggs.c.

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

References DatumGetFloat8(), ereport, errcode(), errmsg, ERROR, fb(), 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().