Skip to content

Commit 42667ca

Browse files
Fix off-by-one in split_chunk upper bound
split_chunk() splits a chunk [start, end) into [start, split_at) and [split_at, end). Per the invariant documented in the code, both resulting ranges must have length at least 1, so the valid split points are [start + 1, end - 1]. The lower bound was correct, but the upper bound required the right range to have length at least 2. This rejected split_at = end - 1 (a valid length-1 right range) and made a chunk of width 2 unsplittable via an explicit split_at, even though the default midpoint path picks and accepts that same point for a width-2 chunk. Allow split points up to end - 1 so the bounds are symmetric and match the documented invariant. Empty-range splits remain rejected.
1 parent 35b093b commit 42667ca

4 files changed

Lines changed: 26 additions & 1 deletion

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes: #10342 split_chunk() rejected a valid split point at the end of a chunk's range

tsl/src/chunk_split.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ chunk_split_chunk(PG_FUNCTION_ARGS)
11251125
* split_at value needs to produce partition ranges of at least length
11261126
* 1.
11271127
*/
1128-
if (split_at < (slice->fd.range_start + 1) || split_at > (slice->fd.range_end - 2))
1128+
if (split_at < (slice->fd.range_start + 1) || split_at > (slice->fd.range_end - 1))
11291129
{
11301130
ereport(ERROR,
11311131
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),

tsl/test/expected/split_chunk.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,3 +1175,19 @@ ORDER BY schemaname, tablename;
11751175
-- Cleanup
11761176
DROP PUBLICATION test_split_pub CASCADE;
11771177
DROP TABLE pub_split_test CASCADE;
1178+
-- Split at range_end - 1 (last valid split point)
1179+
create table splitme_edge (time int not null, v int);
1180+
select create_hypertable('splitme_edge', 'time', chunk_time_interval => 10::int);
1181+
create_hypertable
1182+
---------------------------
1183+
(6,public,splitme_edge,t)
1184+
1185+
insert into splitme_edge values (1, 1);
1186+
select ch as edge_chunk from show_chunks('splitme_edge') ch order by ch limit 1 \gset
1187+
call split_chunk(:'edge_chunk', split_at => 9);
1188+
select * from chunk_slices where hypertable_name = 'splitme_edge';
1189+
hypertable_name | chunk_name | range_start | range_end
1190+
-----------------+-----------------------------------------+-------------------------------------+-------------------------------------
1191+
splitme_edge | _timescaledb_internal._hyper_6_24_chunk | Wed Dec 31 16:00:00 1969 PST | Wed Dec 31 16:00:00.000009 1969 PST
1192+
splitme_edge | _timescaledb_internal._hyper_6_25_chunk | Wed Dec 31 16:00:00.000009 1969 PST | Wed Dec 31 16:00:00.00001 1969 PST
1193+

tsl/test/sql/split_chunk.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,3 +748,11 @@ ORDER BY schemaname, tablename;
748748
-- Cleanup
749749
DROP PUBLICATION test_split_pub CASCADE;
750750
DROP TABLE pub_split_test CASCADE;
751+
752+
-- Split at range_end - 1 (last valid split point)
753+
create table splitme_edge (time int not null, v int);
754+
select create_hypertable('splitme_edge', 'time', chunk_time_interval => 10::int);
755+
insert into splitme_edge values (1, 1);
756+
select ch as edge_chunk from show_chunks('splitme_edge') ch order by ch limit 1 \gset
757+
call split_chunk(:'edge_chunk', split_at => 9);
758+
select * from chunk_slices where hypertable_name = 'splitme_edge';

0 commit comments

Comments
 (0)