0002-Add-tests-for-maximum-tuple-and-index-entry-sizes-REL14.patch

application/x-patch

Filename: 0002-Add-tests-for-maximum-tuple-and-index-entry-sizes-REL14.patch
Type: application/x-patch
Part: 1
Message: [PATCH] Add tests for maximum tuple and index entry sizes
From 052c14eee9525d34958525241c1b910f432f14e1 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Wed, 12 Nov 2025 20:30:47 +0900
Subject: [PATCH] Add tests for maximum tuple and index entry sizes.

Add regression tests that verify size limit enforcement for heap
tuples and index entries at their boundaries.  These tests ensure
that the limits are correctly applied and appropriate error messages
are shown when exceeded.

For heap tuples, test the maximum size of 8160 bytes by inserting
8128-byte and 8129-byte text values.  The former succeeds while the
latter fails because MAXALIGN rounds the 8161-byte tuple to 8168
bytes, exceeding the limit.

For B-tree indexes, test the maximum entry size of about 2704 bytes
(1/3 of page size to ensure proper page splits) by indexing 2692-byte
and 2693-byte text values.

For GiST indexes, test the maximum siglen parameter value of 2024 by
creating indexes with siglen=2024 and siglen=2025.  The limit comes
from the page size constraints for GiST index tuples.

These boundary tests use values that differ by only 1 byte or unit
to clearly demonstrate the exact limits, making it easier to catch
regressions if these limits change in the future.
---
 src/test/regress/expected/btree_index.out | 13 +++++++++++++
 src/test/regress/expected/insert.out      | 11 +++++++++++
 src/test/regress/expected/tsearch.out     |  8 ++++++--
 src/test/regress/sql/btree_index.sql      | 10 ++++++++++
 src/test/regress/sql/insert.sql           | 14 ++++++++++++++
 src/test/regress/sql/tsearch.sql          |  7 +++++--
 6 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/src/test/regress/expected/btree_index.out b/src/test/regress/expected/btree_index.out
index c7328b1dc4f..5c705902a10 100644
--- a/src/test/regress/expected/btree_index.out
+++ b/src/test/regress/expected/btree_index.out
@@ -341,3 +341,16 @@ CREATE INDEX btree_part_idx ON btree_part(id);
 ALTER INDEX btree_part_idx ALTER COLUMN id SET (n_distinct=100);
 ERROR:  "btree_part_idx" is not a table, materialized view, or foreign table
 DROP TABLE btree_part;
+-- Test B-tree index maximum entry size boundary
+CREATE TABLE btree_max_entry_test (i INT PRIMARY KEY, t TEXT);
+CREATE INDEX btree_max_entry_idx ON btree_max_entry_test(t);
+ALTER TABLE btree_max_entry_test ALTER COLUMN t SET STORAGE EXTERNAL;
+-- should succeed
+INSERT INTO btree_max_entry_test VALUES (1, repeat('a', 2692));
+-- should fail
+INSERT INTO btree_max_entry_test VALUES (2, repeat('a', 2693));
+ERROR:  index row size 2712 exceeds btree version 4 maximum 2704 for index "btree_max_entry_idx"
+DETAIL:  Index row references tuple (0,2) in relation "btree_max_entry_test".
+HINT:  Values larger than 1/3 of a buffer page cannot be indexed.
+Consider a function index of an MD5 hash of the value, or use full text indexing.
+DROP TABLE btree_max_entry_test;
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index 4e90fe5686f..16c650791c0 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -103,6 +103,17 @@ INSERT INTO large_tuple_test (select 3, NULL);
 INSERT INTO large_tuple_test (select 4, repeat('a', 8126));
 DROP TABLE large_tuple_test;
 --
+-- test maximum tuple size
+--
+CREATE TABLE max_tuple_test (a int, b text);
+ALTER TABLE max_tuple_test ALTER COLUMN b SET STORAGE plain;
+-- should succeed
+INSERT INTO max_tuple_test VALUES (1, repeat('x', 8128));
+-- should fail
+INSERT INTO max_tuple_test VALUES (2, repeat('x', 8129));
+ERROR:  row is too big: size 8168, maximum size 8160
+DROP TABLE max_tuple_test;
+--
 -- check indirection (field/array assignment), cf bug #14265
 --
 -- these tests are aware that transformInsertStmt has 3 separate code paths
diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out
index 629147c5b11..96ed0bae9d4 100644
--- a/src/test/regress/expected/tsearch.out
+++ b/src/test/regress/expected/tsearch.out
@@ -518,9 +518,13 @@ ERROR:  unrecognized parameter "foo"
 CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=0));
 ERROR:  value 0 out of bounds for option "siglen"
 DETAIL:  Valid values are between "1" and "2024".
-CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=2048));
-ERROR:  value 2048 out of bounds for option "siglen"
+-- should fail
+CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=2025));
+ERROR:  value 2025 out of bounds for option "siglen"
 DETAIL:  Valid values are between "1" and "2024".
+-- should succeed
+CREATE INDEX wowidx2 ON test_tsvector USING gist (a tsvector_ops(siglen=2024));
+DROP INDEX wowidx2;
 CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=100,foo='bar'));
 ERROR:  unrecognized parameter "foo"
 CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=100, siglen = 200));
diff --git a/src/test/regress/sql/btree_index.sql b/src/test/regress/sql/btree_index.sql
index c34502249f3..3541fc9a527 100644
--- a/src/test/regress/sql/btree_index.sql
+++ b/src/test/regress/sql/btree_index.sql
@@ -183,3 +183,13 @@ CREATE TABLE btree_part (id int4) PARTITION BY RANGE (id);
 CREATE INDEX btree_part_idx ON btree_part(id);
 ALTER INDEX btree_part_idx ALTER COLUMN id SET (n_distinct=100);
 DROP TABLE btree_part;
+
+-- Test B-tree index maximum entry size boundary
+CREATE TABLE btree_max_entry_test (i INT PRIMARY KEY, t TEXT);
+CREATE INDEX btree_max_entry_idx ON btree_max_entry_test(t);
+ALTER TABLE btree_max_entry_test ALTER COLUMN t SET STORAGE EXTERNAL;
+-- should succeed
+INSERT INTO btree_max_entry_test VALUES (1, repeat('a', 2692));
+-- should fail
+INSERT INTO btree_max_entry_test VALUES (2, repeat('a', 2693));
+DROP TABLE btree_max_entry_test;
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index b40a1b99cc6..daf424c02dc 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -59,6 +59,20 @@ INSERT INTO large_tuple_test (select 4, repeat('a', 8126));
 
 DROP TABLE large_tuple_test;
 
+--
+-- test maximum tuple size
+--
+CREATE TABLE max_tuple_test (a int, b text);
+ALTER TABLE max_tuple_test ALTER COLUMN b SET STORAGE plain;
+
+-- should succeed
+INSERT INTO max_tuple_test VALUES (1, repeat('x', 8128));
+
+-- should fail
+INSERT INTO max_tuple_test VALUES (2, repeat('x', 8129));
+
+DROP TABLE max_tuple_test;
+
 --
 -- check indirection (field/array assignment), cf bug #14265
 --
diff --git a/src/test/regress/sql/tsearch.sql b/src/test/regress/sql/tsearch.sql
index 0a90c1b539d..fc832f9743a 100644
--- a/src/test/regress/sql/tsearch.sql
+++ b/src/test/regress/sql/tsearch.sql
@@ -132,10 +132,13 @@ SELECT count(*) FROM test_tsvector WHERE a @@ '!wd:D';
 -- Test siglen parameter of GiST tsvector_ops
 CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(foo=1));
 CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=0));
-CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=2048));
+-- should fail
+CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=2025));
+-- should succeed
+CREATE INDEX wowidx2 ON test_tsvector USING gist (a tsvector_ops(siglen=2024));
+DROP INDEX wowidx2;
 CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=100,foo='bar'));
 CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(siglen=100, siglen = 200));
-
 CREATE INDEX wowidx2 ON test_tsvector USING gist (a tsvector_ops(siglen=1));
 
 \d test_tsvector
-- 
2.50.1 (Apple Git-155)