From c660297094c2b06f08f27e5de6a69207ea5366a6 Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@percona.com>
Date: Tue, 11 Aug 2026 22:09:46 +0000
Subject: [PATCH 1/2] Allow maximum-length lexemes in array_to_tsvector again

Commit 23d9ad77181 added a length check to array_to_tsvector() that
rejects lexemes of MAXSTRLEN (2047) bytes, one byte short of what the
tsvector format can represent: MAXSTRLEN is the maximum value of
WordEntry.len, and tsvectorrecv() accepts lexemes of exactly that
length.  As a result, converting such a tsvector to an array and back
with tsvector_to_array()/array_to_tsvector() started to fail.

Relax the check to reject only lexemes longer than MAXSTRLEN, and
report the correct maximum in the error message.
---
 src/backend/utils/adt/tsvector_op.c   | 4 ++--
 src/test/regress/expected/tstypes.out | 9 +++++++++
 src/test/regress/sql/tstypes.sql      | 3 +++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 782b91f701e..d5336774b22 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -776,12 +776,12 @@ array_to_tsvector(PG_FUNCTION_ARGS)
 			ereport(ERROR,
 					(errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
 					 errmsg("lexeme array may not contain empty strings")));
-		if (toklen >= MAXSTRLEN)
+		if (toklen > MAXSTRLEN)
 			ereport(ERROR,
 					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 					 errmsg("word is too long (%d bytes, max %d bytes)",
 							toklen,
-							MAXSTRLEN - 1)));
+							MAXSTRLEN)));
 	}
 
 	/* Sort and de-dup, because this is required for a valid tsvector. */
diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out
index 4cfc3b9dc04..33d30cd6a09 100644
--- a/src/test/regress/expected/tstypes.out
+++ b/src/test/regress/expected/tstypes.out
@@ -1385,6 +1385,15 @@ SELECT array_to_tsvector(ARRAY['base','hidden','rebel','spaceship', NULL]);
 ERROR:  lexeme array may not contain nulls
 SELECT array_to_tsvector(ARRAY['base','hidden','rebel','spaceship', '']);
 ERROR:  lexeme array may not contain empty strings
+-- lexeme of exactly the maximum length is accepted, one byte more is not
+SELECT tsvector_to_array(array_to_tsvector(ARRAY[repeat('x', 2047)])) = ARRAY[repeat('x', 2047)];
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT array_to_tsvector(ARRAY[repeat('x', 2048)]);
+ERROR:  word is too long (2048 bytes, max 2047 bytes)
 -- array_to_tsvector must sort and de-dup
 SELECT array_to_tsvector(ARRAY['foo','bar','baz','bar']);
  array_to_tsvector 
diff --git a/src/test/regress/sql/tstypes.sql b/src/test/regress/sql/tstypes.sql
index dfb7a1466e0..0361e359044 100644
--- a/src/test/regress/sql/tstypes.sql
+++ b/src/test/regress/sql/tstypes.sql
@@ -266,6 +266,9 @@ SELECT array_to_tsvector(ARRAY['base','hidden','rebel','spaceship','strike']);
 -- null and empty string are disallowed, since we mustn't make an empty lexeme
 SELECT array_to_tsvector(ARRAY['base','hidden','rebel','spaceship', NULL]);
 SELECT array_to_tsvector(ARRAY['base','hidden','rebel','spaceship', '']);
+-- lexeme of exactly the maximum length is accepted, one byte more is not
+SELECT tsvector_to_array(array_to_tsvector(ARRAY[repeat('x', 2047)])) = ARRAY[repeat('x', 2047)];
+SELECT array_to_tsvector(ARRAY[repeat('x', 2048)]);
 -- array_to_tsvector must sort and de-dup
 SELECT array_to_tsvector(ARRAY['foo','bar','baz','bar']);
 
-- 
2.54.0

