From 3c3c9195392073640c7f81b8dcfec34b7925eeed Mon Sep 17 00:00:00 2001 From: Arseniy Mukhin Date: Wed, 2 Jul 2025 22:00:31 +0300 Subject: [PATCH] Add check for compressed posting list items number in GIN Current code doesn't check if compressed posting list contains all 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 a posting list always too large. This commit adds check for compressed items number. --- src/backend/access/gin/gininsert.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index e9d4b27427e5..1d3ab22556d8 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); - pfree(newItems); - if (compressedList) + compressedList = ginCompressPostingList(newItems, newNPosting, GinMaxItemSize, &nwritten); + if (nwritten == newNPosting) { res = GinFormTuple(ginstate, attnum, key, category, (char *) compressedList, SizeOfGinPostingList(compressedList), newNPosting, false); - pfree(compressedList); } + + pfree(newItems); + 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 */