Fix bug in compressed GIN data leaf page splitting code.
authorHeikki Linnakangas
Fri, 29 Aug 2014 11:19:34 +0000 (14:19 +0300)
committerHeikki Linnakangas
Fri, 29 Aug 2014 11:22:36 +0000 (14:22 +0300)
The list of posting lists it's dealing with can contain placeholders for
deleted posting lists. The placeholders are kept around so that they can
be WAL-logged, but we must be careful to not try to access them.

This fixes bug #11280, reported by Mårten Svantesson. Backpatch to 9.4,
where the compressed data leaf page code was added.

src/backend/access/gin/gindatapage.c

index 272a9ca7c09db884e6fd2a7ff38d9d578bfb8e03..0ea4f3fe284b4b544309a7c983d1097ce29449bb 100644 (file)
@@ -642,20 +642,24 @@ dataPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
            {
                lastleftinfo = dlist_container(leafSegmentInfo, node, leaf->lastleft);
 
-               segsize = SizeOfGinPostingList(lastleftinfo->seg);
-               if (append)
+               /* ignore deleted segments */
+               if (lastleftinfo->action != GIN_SEGMENT_DELETE)
                {
-                   if ((leaf->lsize - segsize) - (leaf->lsize - segsize) < BLCKSZ / 4)
-                       break;
+                   segsize = SizeOfGinPostingList(lastleftinfo->seg);
+                   if (append)
+                   {
+                       if ((leaf->lsize - segsize) - (leaf->lsize - segsize) < BLCKSZ / 4)
+                           break;
+                   }
+                   else
+                   {
+                       if ((leaf->lsize - segsize) - (leaf->rsize + segsize) < 0)
+                           break;
+                   }
+
+                   leaf->lsize -= segsize;
+                   leaf->rsize += segsize;
                }
-               else
-               {
-                   if ((leaf->lsize - segsize) - (leaf->rsize + segsize) < 0)
-                       break;
-               }
-
-               leaf->lsize -= segsize;
-               leaf->rsize += segsize;
                leaf->lastleft = dlist_prev_node(&leaf->segments, leaf->lastleft);
            }
        }