]> granicus.if.org Git - postgresql/commitdiff
Fix bug in compressed GIN data leaf page splitting code.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 29 Aug 2014 11:19:34 +0000 (14:19 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
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);
                        }
                }