Hi!

Here is a new version. I added a commit message. I will add it to PG19-2.


Best regards,
Arseniy Mukhin
From 0b5a1fce01dd2bb9ef43febeb497dae4eb274405 Mon Sep 17 00:00:00 2001
From: Arseniy Mukhin <arseniy.mukhin....@gmail.com>
Date: Wed, 2 Jul 2025 22:00:31 +0300
Subject: [PATCH v2] Add check for compressed posting list items number in GIN

Current code doesn't check if compressed posting list contains all
new items during index tuple creation which potentially can lead to
lost of data. It doesn't happen now because the size limit of compressed
posting list is the same as gin index tuple size limit, so when compressed
posting list reaches its limit, index tuple size with such data always
too large to be inserted. This commit adds check for compressed items number.

Also, in case of adding items to an existing index tuple we can use more
precise size limit for compressed posting list as we have old index tuple
and can say how many space we have for posting list. It helps to avoid
redundant calls to GinFormTuple.
---
 src/backend/access/gin/gininsert.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index a65acd89104..2d474838a0f 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -218,7 +218,8 @@ addItemPointersToLeafTuple(GinState *ginstate,
 	ItemPointerData *newItems,
 			   *oldItems;
 	int			oldNPosting,
-				newNPosting;
+				newNPosting,
+				nwritten;
 	GinPostingList *compressedList;
 
 	Assert(!GinIsPostingTree(old));
@@ -235,18 +236,19 @@ addItemPointersToLeafTuple(GinState *ginstate,
 
 	/* Compress the posting list, and try to a build tuple with room for it */
 	res = NULL;
-	compressedList = ginCompressPostingList(newItems, newNPosting, GinMaxItemSize,
-											NULL);
+	compressedList = ginCompressPostingList(newItems, newNPosting, GinMaxItemSize - GinGetPostingOffset(old),
+											&nwritten);
 	pfree(newItems);
-	if (compressedList)
+	if (nwritten == newNPosting)
 	{
 		res = GinFormTuple(ginstate, attnum, key, category,
 						   (char *) compressedList,
 						   SizeOfGinPostingList(compressedList),
 						   newNPosting,
 						   false);
-		pfree(compressedList);
 	}
+	pfree(compressedList);
+
 	if (!res)
 	{
 		/* posting list would be too big, convert to posting tree */
@@ -293,17 +295,19 @@ buildFreshLeafTuple(GinState *ginstate,
 {
 	IndexTuple	res = NULL;
 	GinPostingList *compressedList;
+	int			nwritten;
 
 	/* try to build a posting list tuple with all the items */
-	compressedList = ginCompressPostingList(items, nitem, GinMaxItemSize, NULL);
-	if (compressedList)
+	compressedList = ginCompressPostingList(items, nitem, GinMaxItemSize, &nwritten);
+	if (nwritten == nitem)
 	{
 		res = GinFormTuple(ginstate, attnum, key, category,
 						   (char *) compressedList,
 						   SizeOfGinPostingList(compressedList),
 						   nitem, false);
-		pfree(compressedList);
 	}
+	pfree(compressedList);
+
 	if (!res)
 	{
 		/* posting list would be too big, build posting tree */
-- 
2.43.0

Reply via email to