PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
windowfuncs.c File Reference
#include "postgres.h"
#include "nodes/parsenodes.h"
#include "nodes/supportnodes.h"
#include "utils/fmgrprotos.h"
#include "windowapi.h"
Include dependency graph for windowfuncs.c:

Go to the source code of this file.

Data Structures

struct  rank_context
 
struct  ntile_context
 

Typedefs

typedef struct rank_context rank_context
 

Functions

static bool rank_up (WindowObject winobj)
 
static Datum leadlag_common (FunctionCallInfo fcinfo, bool forward, bool withoffset, bool withdefault)
 
Datum window_row_number (PG_FUNCTION_ARGS)
 
Datum window_row_number_support (PG_FUNCTION_ARGS)
 
Datum window_rank (PG_FUNCTION_ARGS)
 
Datum window_rank_support (PG_FUNCTION_ARGS)
 
Datum window_dense_rank (PG_FUNCTION_ARGS)
 
Datum window_dense_rank_support (PG_FUNCTION_ARGS)
 
Datum window_percent_rank (PG_FUNCTION_ARGS)
 
Datum window_percent_rank_support (PG_FUNCTION_ARGS)
 
Datum window_cume_dist (PG_FUNCTION_ARGS)
 
Datum window_cume_dist_support (PG_FUNCTION_ARGS)
 
Datum window_ntile (PG_FUNCTION_ARGS)
 
Datum window_ntile_support (PG_FUNCTION_ARGS)
 
Datum window_lag (PG_FUNCTION_ARGS)
 
Datum window_lag_with_offset (PG_FUNCTION_ARGS)
 
Datum window_lag_with_offset_and_default (PG_FUNCTION_ARGS)
 
Datum window_lead (PG_FUNCTION_ARGS)
 
Datum window_lead_with_offset (PG_FUNCTION_ARGS)
 
Datum window_lead_with_offset_and_default (PG_FUNCTION_ARGS)
 
Datum window_first_value (PG_FUNCTION_ARGS)
 
Datum window_last_value (PG_FUNCTION_ARGS)
 
Datum window_nth_value (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ rank_context

typedef struct rank_context rank_context

Function Documentation

◆ leadlag_common()

static Datum leadlag_common ( FunctionCallInfo  fcinfo,
bool  forward,
bool  withoffset,
bool  withdefault 
)
static

Definition at line 528 of file windowfuncs.c.

530{
532 int32 offset;
533 bool const_offset;
534 Datum result;
535 bool isnull;
536 bool isout;
537
538 if (withoffset)
539 {
540 offset = DatumGetInt32(WinGetFuncArgCurrent(winobj, 1, &isnull));
541 if (isnull)
543 const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
544 }
545 else
546 {
547 offset = 1;
548 const_offset = true;
549 }
550
551 result = WinGetFuncArgInPartition(winobj, 0,
552 (forward ? offset : -offset),
554 const_offset,
555 &isnull, &isout);
556
557 if (isout)
558 {
559 /*
560 * target row is out of the partition; supply default value if
561 * provided. otherwise it'll stay NULL
562 */
563 if (withdefault)
564 result = WinGetFuncArgCurrent(winobj, 2, &isnull);
565 }
566
567 if (isnull)
569
570 PG_RETURN_DATUM(result);
571}
int32_t int32
Definition: c.h:498
bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1975
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
Datum WinGetFuncArgInPartition(WindowObject winobj, int argno, int relpos, int seektype, bool set_mark, bool *isnull, bool *isout)
Datum WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull)
uintptr_t Datum
Definition: postgres.h:69
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
FmgrInfo * flinfo
Definition: fmgr.h:87
#define PG_WINDOW_OBJECT()
Definition: windowapi.h:39
#define WINDOW_SEEK_CURRENT
Definition: windowapi.h:32

References DatumGetInt32(), FunctionCallInfoBaseData::flinfo, get_fn_expr_arg_stable(), PG_RETURN_DATUM, PG_RETURN_NULL, PG_WINDOW_OBJECT, WINDOW_SEEK_CURRENT, WinGetFuncArgCurrent(), and WinGetFuncArgInPartition().

Referenced by window_lag(), window_lag_with_offset(), window_lag_with_offset_and_default(), window_lead(), window_lead_with_offset(), and window_lead_with_offset_and_default().

◆ rank_up()

static bool rank_up ( WindowObject  winobj)
static

Definition at line 49 of file windowfuncs.c.

50{
51 bool up = false; /* should rank increase? */
52 int64 curpos = WinGetCurrentPosition(winobj);
53 rank_context *context;
54
55 context = (rank_context *)
57
58 if (context->rank == 0)
59 {
60 /* first call: rank of first row is always 1 */
61 Assert(curpos == 0);
62 context->rank = 1;
63 }
64 else
65 {
66 Assert(curpos > 0);
67 /* do current and prior tuples match by ORDER BY clause? */
68 if (!WinRowsArePeers(winobj, curpos - 1, curpos))
69 up = true;
70 }
71
72 /* We can advance the mark, but only *after* access to prior row */
73 WinSetMarkPosition(winobj, curpos);
74
75 return up;
76}
int64_t int64
Definition: c.h:499
Assert(PointerIsAligned(start, uint64))
void * WinGetPartitionLocalMemory(WindowObject winobj, Size sz)
int64 WinGetCurrentPosition(WindowObject winobj)
bool WinRowsArePeers(WindowObject winobj, int64 pos1, int64 pos2)
void WinSetMarkPosition(WindowObject winobj, int64 markpos)

References Assert(), rank_context::rank, WinGetCurrentPosition(), WinGetPartitionLocalMemory(), WinRowsArePeers(), and WinSetMarkPosition().

Referenced by window_cume_dist(), window_dense_rank(), window_percent_rank(), and window_rank().

◆ window_cume_dist()

Datum window_cume_dist ( PG_FUNCTION_ARGS  )

Definition at line 330 of file windowfuncs.c.

331{
333 rank_context *context;
334 bool up;
335 int64 totalrows = WinGetPartitionRowCount(winobj);
336
337 Assert(totalrows > 0);
338
339 up = rank_up(winobj);
340 context = (rank_context *)
342 if (up || context->rank == 1)
343 {
344 /*
345 * The current row is not peer to prior row or is just the first, so
346 * count up the number of rows that are peer to the current.
347 */
348 int64 row;
349
350 context->rank = WinGetCurrentPosition(winobj) + 1;
351
352 /*
353 * start from current + 1
354 */
355 for (row = context->rank; row < totalrows; row++)
356 {
357 if (!WinRowsArePeers(winobj, row - 1, row))
358 break;
359 context->rank++;
360 }
361 }
362
363 PG_RETURN_FLOAT8((float8) context->rank / (float8) totalrows);
364}
double float8
Definition: c.h:601
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:367
int64 WinGetPartitionRowCount(WindowObject winobj)
static bool rank_up(WindowObject winobj)
Definition: windowfuncs.c:49

References Assert(), PG_RETURN_FLOAT8, PG_WINDOW_OBJECT, rank_context::rank, rank_up(), WinGetCurrentPosition(), WinGetPartitionLocalMemory(), WinGetPartitionRowCount(), and WinRowsArePeers().

◆ window_cume_dist_support()

Datum window_cume_dist_support ( PG_FUNCTION_ARGS  )

Definition at line 371 of file windowfuncs.c.

372{
373 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
374
376 {
378
379 /* cume_dist() is monotonically increasing */
382 }
383
385 {
387
388 /*
389 * cume_dist() is unaffected by the frame options. Here we set the
390 * frame options to match what's done in row_number's support
391 * function. Using ROWS instead of RANGE (the default) saves the
392 * executor from having to check for peer rows.
393 */
398
400 }
401
402 PG_RETURN_POINTER(NULL);
403}
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:602
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:597
#define FRAMEOPTION_NONDEFAULT
Definition: parsenodes.h:592
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:594
@ MONOTONICFUNC_INCREASING
Definition: plannodes.h:1769
Definition: nodes.h:135
MonotonicFunction monotonic
Definition: supportnodes.h:299

References FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_NONDEFAULT, FRAMEOPTION_ROWS, FRAMEOPTION_START_UNBOUNDED_PRECEDING, SupportRequestOptimizeWindowClause::frameOptions, IsA, SupportRequestWFuncMonotonic::monotonic, MONOTONICFUNC_INCREASING, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ window_dense_rank()

Datum window_dense_rank ( PG_FUNCTION_ARGS  )

Definition at line 200 of file windowfuncs.c.

201{
203 rank_context *context;
204 bool up;
205
206 up = rank_up(winobj);
207 context = (rank_context *)
209 if (up)
210 context->rank++;
211
212 PG_RETURN_INT64(context->rank);
213}
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368

References PG_RETURN_INT64, PG_WINDOW_OBJECT, rank_context::rank, rank_up(), and WinGetPartitionLocalMemory().

◆ window_dense_rank_support()

Datum window_dense_rank_support ( PG_FUNCTION_ARGS  )

Definition at line 220 of file windowfuncs.c.

221{
222 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
223
225 {
227
228 /* dense_rank() is monotonically increasing */
231 }
232
234 {
236
237 /*
238 * dense_rank() is unaffected by the frame options. Here we set the
239 * frame options to match what's done in row_number's support
240 * function. Using ROWS instead of RANGE (the default) saves the
241 * executor from having to check for peer rows.
242 */
247
249 }
250
251 PG_RETURN_POINTER(NULL);
252}

References FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_NONDEFAULT, FRAMEOPTION_ROWS, FRAMEOPTION_START_UNBOUNDED_PRECEDING, SupportRequestOptimizeWindowClause::frameOptions, IsA, SupportRequestWFuncMonotonic::monotonic, MONOTONICFUNC_INCREASING, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ window_first_value()

Datum window_first_value ( PG_FUNCTION_ARGS  )

Definition at line 649 of file windowfuncs.c.

650{
652 Datum result;
653 bool isnull;
654
655 result = WinGetFuncArgInFrame(winobj, 0,
656 0, WINDOW_SEEK_HEAD, true,
657 &isnull, NULL);
658 if (isnull)
660
661 PG_RETURN_DATUM(result);
662}
Datum WinGetFuncArgInFrame(WindowObject winobj, int argno, int relpos, int seektype, bool set_mark, bool *isnull, bool *isout)
#define WINDOW_SEEK_HEAD
Definition: windowapi.h:33

References PG_RETURN_DATUM, PG_RETURN_NULL, PG_WINDOW_OBJECT, WINDOW_SEEK_HEAD, and WinGetFuncArgInFrame().

◆ window_lag()

Datum window_lag ( PG_FUNCTION_ARGS  )

Definition at line 580 of file windowfuncs.c.

581{
582 return leadlag_common(fcinfo, false, false, false);
583}
static Datum leadlag_common(FunctionCallInfo fcinfo, bool forward, bool withoffset, bool withdefault)
Definition: windowfuncs.c:528

References leadlag_common().

◆ window_lag_with_offset()

Datum window_lag_with_offset ( PG_FUNCTION_ARGS  )

Definition at line 592 of file windowfuncs.c.

593{
594 return leadlag_common(fcinfo, false, true, false);
595}

References leadlag_common().

◆ window_lag_with_offset_and_default()

Datum window_lag_with_offset_and_default ( PG_FUNCTION_ARGS  )

Definition at line 603 of file windowfuncs.c.

604{
605 return leadlag_common(fcinfo, false, true, true);
606}

References leadlag_common().

◆ window_last_value()

Datum window_last_value ( PG_FUNCTION_ARGS  )

Definition at line 670 of file windowfuncs.c.

671{
673 Datum result;
674 bool isnull;
675
676 result = WinGetFuncArgInFrame(winobj, 0,
677 0, WINDOW_SEEK_TAIL, true,
678 &isnull, NULL);
679 if (isnull)
681
682 PG_RETURN_DATUM(result);
683}
#define WINDOW_SEEK_TAIL
Definition: windowapi.h:34

References PG_RETURN_DATUM, PG_RETURN_NULL, PG_WINDOW_OBJECT, WINDOW_SEEK_TAIL, and WinGetFuncArgInFrame().

◆ window_lead()

Datum window_lead ( PG_FUNCTION_ARGS  )

Definition at line 615 of file windowfuncs.c.

616{
617 return leadlag_common(fcinfo, true, false, false);
618}

References leadlag_common().

◆ window_lead_with_offset()

Datum window_lead_with_offset ( PG_FUNCTION_ARGS  )

Definition at line 627 of file windowfuncs.c.

628{
629 return leadlag_common(fcinfo, true, true, false);
630}

References leadlag_common().

◆ window_lead_with_offset_and_default()

Datum window_lead_with_offset_and_default ( PG_FUNCTION_ARGS  )

Definition at line 638 of file windowfuncs.c.

639{
640 return leadlag_common(fcinfo, true, true, true);
641}

References leadlag_common().

◆ window_nth_value()

Datum window_nth_value ( PG_FUNCTION_ARGS  )

Definition at line 691 of file windowfuncs.c.

692{
694 bool const_offset;
695 Datum result;
696 bool isnull;
697 int32 nth;
698
699 nth = DatumGetInt32(WinGetFuncArgCurrent(winobj, 1, &isnull));
700 if (isnull)
702 const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
703
704 if (nth <= 0)
706 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_NTH_VALUE),
707 errmsg("argument of nth_value must be greater than zero")));
708
709 result = WinGetFuncArgInFrame(winobj, 0,
710 nth - 1, WINDOW_SEEK_HEAD, const_offset,
711 &isnull, NULL);
712 if (isnull)
714
715 PG_RETURN_DATUM(result);
716}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149

References DatumGetInt32(), ereport, errcode(), errmsg(), ERROR, get_fn_expr_arg_stable(), PG_RETURN_DATUM, PG_RETURN_NULL, PG_WINDOW_OBJECT, WINDOW_SEEK_HEAD, WinGetFuncArgCurrent(), and WinGetFuncArgInFrame().

◆ window_ntile()

Datum window_ntile ( PG_FUNCTION_ARGS  )

Definition at line 411 of file windowfuncs.c.

412{
414 ntile_context *context;
415
416 context = (ntile_context *)
418
419 if (context->ntile == 0)
420 {
421 /* first call */
422 int64 total;
423 int32 nbuckets;
424 bool isnull;
425
426 total = WinGetPartitionRowCount(winobj);
427 nbuckets = DatumGetInt32(WinGetFuncArgCurrent(winobj, 0, &isnull));
428
429 /*
430 * per spec: If NT is the null value, then the result is the null
431 * value.
432 */
433 if (isnull)
435
436 /*
437 * per spec: If NT is less than or equal to 0 (zero), then an
438 * exception condition is raised.
439 */
440 if (nbuckets <= 0)
442 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_NTILE),
443 errmsg("argument of ntile must be greater than zero")));
444
445 context->ntile = 1;
446 context->rows_per_bucket = 0;
447 context->boundary = total / nbuckets;
448 if (context->boundary <= 0)
449 context->boundary = 1;
450 else
451 {
452 /*
453 * If the total number is not divisible, add 1 row to leading
454 * buckets.
455 */
456 context->remainder = total % nbuckets;
457 if (context->remainder != 0)
458 context->boundary++;
459 }
460 }
461
462 context->rows_per_bucket++;
463 if (context->boundary < context->rows_per_bucket)
464 {
465 /* ntile up */
466 if (context->remainder != 0 && context->ntile == context->remainder)
467 {
468 context->remainder = 0;
469 context->boundary -= 1;
470 }
471 context->ntile += 1;
472 context->rows_per_bucket = 1;
473 }
474
475 PG_RETURN_INT32(context->ntile);
476}
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
int64 rows_per_bucket
Definition: windowfuncs.c:35
int64 remainder
Definition: windowfuncs.c:37
int64 boundary
Definition: windowfuncs.c:36

References ntile_context::boundary, DatumGetInt32(), ereport, errcode(), errmsg(), ERROR, ntile_context::ntile, PG_RETURN_INT32, PG_RETURN_NULL, PG_WINDOW_OBJECT, ntile_context::remainder, ntile_context::rows_per_bucket, WinGetFuncArgCurrent(), WinGetPartitionLocalMemory(), and WinGetPartitionRowCount().

◆ window_ntile_support()

Datum window_ntile_support ( PG_FUNCTION_ARGS  )

Definition at line 483 of file windowfuncs.c.

484{
485 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
486
488 {
490
491 /*
492 * ntile() is monotonically increasing as the number of buckets cannot
493 * change after the first call
494 */
497 }
498
500 {
502
503 /*
504 * ntile() is unaffected by the frame options. Here we set the frame
505 * options to match what's done in row_number's support function.
506 * Using ROWS instead of RANGE (the default) saves the executor from
507 * having to check for peer rows.
508 */
513
515 }
516
517 PG_RETURN_POINTER(NULL);
518}

References FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_NONDEFAULT, FRAMEOPTION_ROWS, FRAMEOPTION_START_UNBOUNDED_PRECEDING, SupportRequestOptimizeWindowClause::frameOptions, IsA, SupportRequestWFuncMonotonic::monotonic, MONOTONICFUNC_INCREASING, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ window_percent_rank()

Datum window_percent_rank ( PG_FUNCTION_ARGS  )

Definition at line 261 of file windowfuncs.c.

262{
264 rank_context *context;
265 bool up;
266 int64 totalrows = WinGetPartitionRowCount(winobj);
267
268 Assert(totalrows > 0);
269
270 up = rank_up(winobj);
271 context = (rank_context *)
273 if (up)
274 context->rank = WinGetCurrentPosition(winobj) + 1;
275
276 /* return zero if there's only one row, per spec */
277 if (totalrows <= 1)
278 PG_RETURN_FLOAT8(0.0);
279
280 PG_RETURN_FLOAT8((float8) (context->rank - 1) / (float8) (totalrows - 1));
281}

References Assert(), PG_RETURN_FLOAT8, PG_WINDOW_OBJECT, rank_context::rank, rank_up(), WinGetCurrentPosition(), WinGetPartitionLocalMemory(), and WinGetPartitionRowCount().

◆ window_percent_rank_support()

Datum window_percent_rank_support ( PG_FUNCTION_ARGS  )

Definition at line 288 of file windowfuncs.c.

289{
290 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
291
293 {
295
296 /* percent_rank() is monotonically increasing */
299 }
300
302 {
304
305 /*
306 * percent_rank() is unaffected by the frame options. Here we set the
307 * frame options to match what's done in row_number's support
308 * function. Using ROWS instead of RANGE (the default) saves the
309 * executor from having to check for peer rows.
310 */
315
317 }
318
319 PG_RETURN_POINTER(NULL);
320}

References FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_NONDEFAULT, FRAMEOPTION_ROWS, FRAMEOPTION_START_UNBOUNDED_PRECEDING, SupportRequestOptimizeWindowClause::frameOptions, IsA, SupportRequestWFuncMonotonic::monotonic, MONOTONICFUNC_INCREASING, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ window_rank()

Datum window_rank ( PG_FUNCTION_ARGS  )

Definition at line 138 of file windowfuncs.c.

139{
141 rank_context *context;
142 bool up;
143
144 up = rank_up(winobj);
145 context = (rank_context *)
147 if (up)
148 context->rank = WinGetCurrentPosition(winobj) + 1;
149
150 PG_RETURN_INT64(context->rank);
151}

References PG_RETURN_INT64, PG_WINDOW_OBJECT, rank_context::rank, rank_up(), WinGetCurrentPosition(), and WinGetPartitionLocalMemory().

◆ window_rank_support()

Datum window_rank_support ( PG_FUNCTION_ARGS  )

Definition at line 158 of file windowfuncs.c.

159{
160 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
161
163 {
165
166 /* rank() is monotonically increasing */
169 }
170
172 {
174
175 /*
176 * rank() is coded in such a way that it returns "(COUNT (*) OVER
177 * (<opt> RANGE UNBOUNDED PRECEDING) - COUNT (*) OVER (<opt> RANGE
178 * CURRENT ROW) + 1)" regardless of the frame options. We'll set the
179 * frame options to "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"
180 * so they agree with what window_row_number_support() optimized the
181 * frame options to be. Using ROWS instead of RANGE saves from doing
182 * peer row checks during execution.
183 */
188
190 }
191
192 PG_RETURN_POINTER(NULL);
193}

References FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_NONDEFAULT, FRAMEOPTION_ROWS, FRAMEOPTION_START_UNBOUNDED_PRECEDING, SupportRequestOptimizeWindowClause::frameOptions, IsA, SupportRequestWFuncMonotonic::monotonic, MONOTONICFUNC_INCREASING, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ window_row_number()

Datum window_row_number ( PG_FUNCTION_ARGS  )

Definition at line 84 of file windowfuncs.c.

85{
87 int64 curpos = WinGetCurrentPosition(winobj);
88
89 WinSetMarkPosition(winobj, curpos);
90 PG_RETURN_INT64(curpos + 1);
91}

References PG_RETURN_INT64, PG_WINDOW_OBJECT, WinGetCurrentPosition(), and WinSetMarkPosition().

◆ window_row_number_support()

Datum window_row_number_support ( PG_FUNCTION_ARGS  )

Definition at line 98 of file windowfuncs.c.

99{
100 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
101
103 {
105
106 /* row_number() is monotonically increasing */
109 }
110
112 {
114
115 /*
116 * The frame options can always become "ROWS BETWEEN UNBOUNDED
117 * PRECEDING AND CURRENT ROW". row_number() always just increments by
118 * 1 with each row in the partition. Using ROWS instead of RANGE
119 * saves effort checking peer rows during execution.
120 */
125
127 }
128
129 PG_RETURN_POINTER(NULL);
130}

References FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_NONDEFAULT, FRAMEOPTION_ROWS, FRAMEOPTION_START_UNBOUNDED_PRECEDING, SupportRequestOptimizeWindowClause::frameOptions, IsA, SupportRequestWFuncMonotonic::monotonic, MONOTONICFUNC_INCREASING, PG_GETARG_POINTER, and PG_RETURN_POINTER.