v0-0001-Sort-offsets-in-test_tidstore-s-do_set_block_offs.patch

text/plain

Filename: v0-0001-Sort-offsets-in-test_tidstore-s-do_set_block_offs.patch
Type: text/plain
Part: 0
Message: TRAP: failed Assert("offsets[i] > offsets[i - 1]"), File: "tidstore.c"

Patch

Format: format-patch
Series: patch v0-0001
Subject: Sort offsets in test_tidstore's do_set_block_offsets().
File+
src/test/modules/test_tidstore/test_tidstore.c 16 0
From 99c9abb3b751ec3603b6ad8248fb94ec529d2932 Mon Sep 17 00:00:00 2001
From: "Andrei V. Lepikhov" <lepihov@gmail.com>
Date: Wed, 15 Apr 2026 14:41:51 +0200
Subject: [PATCH v0] Sort offsets in test_tidstore's do_set_block_offsets().

TidStoreSetBlockOffsets() requires its offsets[] argument to be
strictly ascending, and asserts the precondition.

The test harness was forwarding the OffsetNumber array straight from
SQL, which works only because the current planner happens to present
array_agg() input in the order the VALUES clause was written.  That
ordering is not a SQL guarantee: array_agg() without ORDER BY is
unordered by specification, and any plan change that reshuffles the
Cartesian product used in test_tidstore.sql -- parallel aggregation,
a different join order, or a randomised planner -- can deliver the
offsets out of order and cause the Assert.

Fix by sorting offs in place inside do_set_block_offsets() before
calling TidStoreSetBlockOffsets(). Duplicates are intentionally left to fail
the strict-inequality Assert.
---
 src/test/modules/test_tidstore/test_tidstore.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/test/modules/test_tidstore/test_tidstore.c b/src/test/modules/test_tidstore/test_tidstore.c
index c9a035fa494..bfc40bce24c 100644
--- a/src/test/modules/test_tidstore/test_tidstore.c
+++ b/src/test/modules/test_tidstore/test_tidstore.c
@@ -75,6 +75,19 @@ itemptr_cmp(const void *left, const void *right)
 	return 0;
 }
 
+static int
+offsetnumber_cmp(const void *a, const void *b)
+{
+	OffsetNumber l = *(const OffsetNumber *) a;
+	OffsetNumber r = *(const OffsetNumber *) b;
+
+	if (l < r)
+		return -1;
+	else if (l > r)
+		return 1;
+	return 0;
+}
+
 /*
  * Create a TidStore. If shared is false, the tidstore is created
  * on TopMemoryContext, otherwise on DSA. Although the tidstore
@@ -178,6 +191,9 @@ do_set_block_offsets(PG_FUNCTION_ARGS)
 	noffs = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta));
 	offs = ((OffsetNumber *) ARR_DATA_PTR(ta));
 
+	/* TidStoreSetBlockOffsets() requires offsets to be strictly ascending. */
+	qsort(offs, noffs, sizeof(OffsetNumber), offsetnumber_cmp);
+
 	/* Set TIDs in the store */
 	TidStoreLockExclusive(tidstore);
 	TidStoreSetBlockOffsets(tidstore, blkno, offs, noffs);
-- 
2.53.0