#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
+#include "common/int.h"
#include "executor/executor.h"
#include "executor/instrument.h"
#include "executor/nodeWindowAgg.h"
if (frameOptions & FRAMEOPTION_ROWS)
{
int64 offset = DatumGetInt64(winstate->endOffsetValue);
+ int64 frameendpos = 0;
/* rows after current row + offset are out of frame */
if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
offset = -offset;
- if (pos > winstate->currentpos + offset)
+ /*
+ * If we have an overflow, it means the frame end is beyond the
+ * range of int64. Since currentpos >= 0, this can only be a
+ * positive overflow. We treat this as meaning that the frame
+ * extends to end of partition.
+ */
+ if (!pg_add_s64_overflow(winstate->currentpos, offset,
+ &frameendpos) &&
+ pos > frameendpos)
return -1;
}
else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
offset = -offset;
- winstate->frameheadpos = winstate->currentpos + offset;
+ /*
+ * If we have an overflow, it means the frame head is beyond the
+ * range of int64. Since currentpos >= 0, this can only be a
+ * positive overflow. We treat this as being beyond end of
+ * partition.
+ */
+ if (pg_add_s64_overflow(winstate->currentpos, offset,
+ &winstate->frameheadpos))
+ winstate->frameheadpos = PG_INT64_MAX;
+
/* frame head can't go before first row */
if (winstate->frameheadpos < 0)
winstate->frameheadpos = 0;
* framehead_slot empty.
*/
int64 offset = DatumGetInt64(winstate->startOffsetValue);
- int64 minheadgroup;
+ int64 minheadgroup = 0;
if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
minheadgroup = winstate->currentgroup - offset;
else
- minheadgroup = winstate->currentgroup + offset;
+ {
+ /*
+ * If we have an overflow, it means the target group is beyond
+ * the range of int64. We treat this as "infinity", which
+ * ensures the loop below advances to end of partition.
+ */
+ if (pg_add_s64_overflow(winstate->currentgroup, offset,
+ &minheadgroup))
+ minheadgroup = PG_INT64_MAX;
+ }
tuplestore_select_read_pointer(winstate->buffer,
winstate->framehead_ptr);
if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
offset = -offset;
- winstate->frametailpos = winstate->currentpos + offset + 1;
+ /*
+ * If we have an overflow, it means the frame tail is beyond the
+ * range of int64. Since currentpos >= 0, this can only be a
+ * positive overflow. We treat this as being beyond end of
+ * partition.
+ */
+ if (pg_add_s64_overflow(winstate->currentpos, offset,
+ &winstate->frametailpos) ||
+ pg_add_s64_overflow(winstate->frametailpos, 1,
+ &winstate->frametailpos))
+ winstate->frametailpos = PG_INT64_MAX;
+
/* smallest allowable value of frametailpos is 0 */
if (winstate->frametailpos < 0)
winstate->frametailpos = 0;
* leave frametailpos = end+1 and frametail_slot empty.
*/
int64 offset = DatumGetInt64(winstate->endOffsetValue);
- int64 maxtailgroup;
+ int64 maxtailgroup = 0;
if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
maxtailgroup = winstate->currentgroup - offset;
else
- maxtailgroup = winstate->currentgroup + offset;
+ {
+ /*
+ * If we have an overflow, it means the target group is beyond
+ * the range of int64. We treat this as "infinity", which
+ * ensures the loop below advances to end of partition.
+ */
+ if (pg_add_s64_overflow(winstate->currentgroup, offset,
+ &maxtailgroup))
+ maxtailgroup = PG_INT64_MAX;
+ }
tuplestore_select_read_pointer(winstate->buffer,
winstate->frametail_ptr);
FROM generate_series(now(), (now() + '@ 100 days'::interval), '@ 1 hour'::interval) i(i);
(1 row)
+-- test overflow frame specifications
+SELECT sum(unique1) over (rows between current row and 9223372036854775807 following exclude current row),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+ sum | unique1 | four
+-----+---------+------
+ 41 | 4 | 0
+ 39 | 2 | 2
+ 38 | 1 | 1
+ 32 | 6 | 2
+ 23 | 9 | 1
+ 15 | 8 | 0
+ 10 | 5 | 1
+ 7 | 3 | 3
+ 0 | 7 | 3
+ | 0 | 0
+(10 rows)
+
+SELECT sum(unique1) over (rows between 9223372036854775807 following and 1 following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+ sum | unique1 | four
+-----+---------+------
+ | 4 | 0
+ | 2 | 2
+ | 1 | 1
+ | 6 | 2
+ | 9 | 1
+ | 8 | 0
+ | 5 | 1
+ | 3 | 3
+ | 7 | 3
+ | 0 | 0
+(10 rows)
+
+SELECT last_value(unique1) over (ORDER BY four rows between current row and 9223372036854775807 following exclude current row),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+ last_value | unique1 | four
+------------+---------+------
+ 7 | 0 | 0
+ 7 | 8 | 0
+ 7 | 4 | 0
+ 7 | 5 | 1
+ 7 | 9 | 1
+ 7 | 1 | 1
+ 7 | 6 | 2
+ 7 | 2 | 2
+ 7 | 3 | 3
+ | 7 | 3
+(10 rows)
+
+-- These test GROUPS mode with an offset large enough to cause overflow when
+-- added to currentgroup. Although the overflow doesn't produce visibly wrong
+-- results (due to the incremental nature of group pointer advancement), we
+-- still need to protect against it as signed integer overflow is undefined
+-- behavior in C.
+SELECT sum(unique1) over (ORDER BY four groups between current row and 9223372036854775807 following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+ sum | unique1 | four
+-----+---------+------
+ 45 | 0 | 0
+ 45 | 8 | 0
+ 45 | 4 | 0
+ 33 | 5 | 1
+ 33 | 9 | 1
+ 33 | 1 | 1
+ 18 | 6 | 2
+ 18 | 2 | 2
+ 10 | 3 | 3
+ 10 | 7 | 3
+(10 rows)
+
+SELECT sum(unique1) over (ORDER BY four groups between 9223372036854775807 following and unbounded following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+ sum | unique1 | four
+-----+---------+------
+ | 0 | 0
+ | 8 | 0
+ | 4 | 0
+ | 5 | 1
+ | 9 | 1
+ | 1 | 1
+ | 6 | 2
+ | 2 | 2
+ | 3 | 3
+ | 7 | 3
+(10 rows)
+
-- RANGE offset PRECEDING/FOLLOWING tests
SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding),
unique1, four
SELECT pg_get_viewdef('v_window');
+-- test overflow frame specifications
+SELECT sum(unique1) over (rows between current row and 9223372036854775807 following exclude current row),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+SELECT sum(unique1) over (rows between 9223372036854775807 following and 1 following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+SELECT last_value(unique1) over (ORDER BY four rows between current row and 9223372036854775807 following exclude current row),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+-- These test GROUPS mode with an offset large enough to cause overflow when
+-- added to currentgroup. Although the overflow doesn't produce visibly wrong
+-- results (due to the incremental nature of group pointer advancement), we
+-- still need to protect against it as signed integer overflow is undefined
+-- behavior in C.
+SELECT sum(unique1) over (ORDER BY four groups between current row and 9223372036854775807 following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+SELECT sum(unique1) over (ORDER BY four groups between 9223372036854775807 following and unbounded following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
-- RANGE offset PRECEDING/FOLLOWING tests
SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding),