@@ -55,18 +55,16 @@ callConsistentFn(RumState *rumstate, RumScanKey key)
5555if (key -> searchMode == GIN_SEARCH_MODE_EVERYTHING )
5656{
5757key -> recheckCurItem = false;
58- return true;
59- }
60-
61- /*
62- * Initialize recheckCurItem in case the consistentFn doesn't know it
63- * should set it. The safe assumption in that case is to force recheck.
64- */
65- key -> recheckCurItem = true;
66-
67- if (key -> searchMode == GIN_SEARCH_MODE_INCLUDE_EMPTY )
6858res = true;
59+ }
6960else
61+ {
62+ /*
63+ * Initialize recheckCurItem in case the consistentFn doesn't know it
64+ * should set it. The safe assumption in that case is to force recheck.
65+ */
66+ key -> recheckCurItem = true;
67+
7068res = DatumGetBool (FunctionCall10Coll (& rumstate -> consistentFn [key -> attnum - 1 ],
7169rumstate -> supportCollation [key -> attnum - 1 ],
7270PointerGetDatum (key -> entryRes ),
@@ -80,6 +78,7 @@ callConsistentFn(RumState *rumstate, RumScanKey key)
8078PointerGetDatum (key -> addInfo ),
8179PointerGetDatum (key -> addInfoIsNull )
8280));
81+ }
8382
8483if (res && key -> attnum == rumstate -> attrnAddToColumn )
8584{
@@ -415,6 +414,208 @@ collectMatchBitmap(RumBtreeData *btree, RumBtreeStack *stack,
415414}
416415}
417416
417+ static void
418+ collectMatchRumKey (RumBtreeData * btree ,RumBtreeStack * stack ,
419+ RumScanEntry entry )
420+ {
421+ OffsetNumber attnum ;
422+
423+ /* Null query cannot partial-match anything */
424+ if (entry -> isPartialMatch &&
425+ entry -> queryCategory != RUM_CAT_NORM_KEY )
426+ return ;
427+
428+ /* Locate tupdesc entry for key column (for attbyval/attlen data) */
429+ attnum = entry -> attnum ;
430+
431+ for (;;)
432+ {
433+ Page page ;
434+ IndexTuple itup ;
435+ Datum idatum ;
436+ RumNullCategory icategory ;
437+
438+ /*
439+ * stack->off points to the interested entry, buffer is already locked
440+ */
441+ if (moveRightIfItNeeded (btree ,stack )== false)
442+ return ;
443+
444+ page = BufferGetPage (stack -> buffer );
445+ itup = (IndexTuple )PageGetItem (page ,PageGetItemId (page ,stack -> off ));
446+
447+ /*
448+ * If tuple stores another attribute then stop scan
449+ */
450+ if (rumtuple_get_attrnum (btree -> rumstate ,itup )!= attnum )
451+ return ;
452+
453+ /* Safe to fetch attribute value */
454+ idatum = rumtuple_get_key (btree -> rumstate ,itup ,& icategory );
455+
456+ /*
457+ * Check for appropriate scan stop conditions
458+ */
459+ if (entry -> isPartialMatch )
460+ {
461+ int32 cmp ;
462+
463+ /*
464+ * In partial match, stop scan at any null (including
465+ * placeholders); partial matches never match nulls
466+ */
467+ if (icategory != RUM_CAT_NORM_KEY )
468+ return ;
469+
470+ /*----------
471+ * Check of partial match.
472+ * case cmp == 0 => match
473+ * case cmp > 0 => not match and finish scan
474+ * case cmp < 0 => not match and continue scan
475+ *----------
476+ */
477+ cmp = DatumGetInt32 (FunctionCall4Coll (& btree -> rumstate -> comparePartialFn [attnum - 1 ],
478+ btree -> rumstate -> supportCollation [attnum - 1 ],
479+ entry -> queryKey ,
480+ idatum ,
481+ UInt16GetDatum (entry -> strategy ),
482+ PointerGetDatum (entry -> extra_data )));
483+
484+ if (cmp > 0 )
485+ return ;
486+ else if (cmp < 0 )
487+ {
488+ stack -> off ++ ;
489+ continue ;
490+ }
491+ }
492+ else if (entry -> searchMode == GIN_SEARCH_MODE_ALL )
493+ {
494+ /*
495+ * In ALL mode, we are not interested in null items, so we can
496+ * stop if we get to a null-item placeholder (which will be the
497+ * last entry for a given attnum). We do want to include NULL_KEY
498+ * and EMPTY_ITEM entries, though.
499+ */
500+ if (icategory == RUM_CAT_NULL_ITEM )
501+ return ;
502+ }
503+
504+ if (RumIsPostingTree (itup ))
505+ {
506+ BlockNumber rootPostingTree = RumGetPostingTree (itup );
507+ RumPostingTreeScan * gdi ;
508+ Page page ;
509+ OffsetNumber maxoff ,i ,j ;
510+ Pointer ptr ;
511+ RumKey item ;
512+
513+ ItemPointerSetMin (& item .iptr );
514+
515+ /*
516+ * We should unlock entry page before touching posting tree to
517+ * prevent deadlocks with vacuum processes. Because entry is never
518+ * deleted from page and posting tree is never reduced to the
519+ * posting list, we can unlock page after getting BlockNumber of
520+ * root of posting tree.
521+ */
522+ LockBuffer (stack -> buffer ,RUM_UNLOCK );
523+ gdi = rumPrepareScanPostingTree (btree -> rumstate -> index ,
524+ rootPostingTree , TRUE,
525+ entry -> attnum ,btree -> rumstate );
526+
527+ /*
528+ * We lock again the entry page and while it was unlocked insert
529+ * might have occurred, so we need to re-find our position.
530+ */
531+ LockBuffer (stack -> buffer ,RUM_SHARE );
532+ page = BufferGetPage (stack -> buffer );
533+ if (!RumPageIsLeaf (page ))
534+ {
535+ /*
536+ * Root page becomes non-leaf while we unlock it. We will
537+ * start again, this situation doesn't occur often - root can
538+ * became a non-leaf only once per life of index.
539+ */
540+ return ;
541+ }
542+
543+ entry -> buffer = rumScanBeginPostingTree (gdi );
544+ entry -> gdi = gdi ;
545+ entry -> context = AllocSetContextCreate (CurrentMemoryContext ,
546+ "GiST temporary context" ,
547+ ALLOCSET_DEFAULT_MINSIZE ,
548+ ALLOCSET_DEFAULT_INITSIZE ,
549+ ALLOCSET_DEFAULT_MAXSIZE );
550+
551+ /*
552+ * We keep buffer pinned because we need to prevent deletion of
553+ * page during scan. See RUM's vacuum implementation. RefCount is
554+ * increased to keep buffer pinned after freeRumBtreeStack() call.
555+ */
556+ page = BufferGetPage (entry -> buffer );
557+ entry -> predictNumberResult = gdi -> stack -> predictNumber * RumPageGetOpaque (page )-> maxoff ;
558+
559+ /*
560+ * Keep page content in memory to prevent durable page locking
561+ */
562+ maxoff = RumPageGetOpaque (page )-> maxoff ;
563+ j = entry -> nlist ;
564+ entry -> nlist += maxoff ;
565+ if (entry -> nalloc == 0 )
566+ {
567+ entry -> nalloc = Max (maxoff ,32 );
568+ entry -> list = (RumKey * )palloc (entry -> nalloc * sizeof (RumKey ));
569+ }
570+ else if (entry -> nlist > entry -> nalloc )
571+ {
572+ entry -> nalloc *=2 ;
573+ entry -> list = (RumKey * )
574+ repalloc (entry -> list ,entry -> nalloc * sizeof (RumKey ));
575+ }
576+
577+ ptr = RumDataPageGetData (page );
578+
579+ for (i = FirstOffsetNumber ;i <=maxoff ;i = OffsetNumberNext (i ))
580+ {
581+ ptr = rumDataPageLeafRead (ptr ,entry -> attnum ,& item ,
582+ btree -> rumstate );
583+ entry -> list [i - FirstOffsetNumber + j ]= item ;
584+ }
585+
586+ LockBuffer (entry -> buffer ,RUM_UNLOCK );
587+ entry -> isFinished = FALSE;
588+ }
589+ else if (RumGetNPosting (itup )> 0 )
590+ {
591+ uint32 j ;
592+
593+ j = entry -> nlist ;
594+ entry -> nlist += RumGetNPosting (itup );
595+ entry -> predictNumberResult += RumGetNPosting (itup );
596+ if (entry -> nalloc == 0 )
597+ {
598+ entry -> nalloc = Max (RumGetNPosting (itup ),32 );
599+ entry -> list = (RumKey * )palloc (entry -> nalloc * sizeof (RumKey ));
600+ }
601+ else if (entry -> nlist > entry -> nalloc )
602+ {
603+ entry -> nalloc *=2 ;
604+ entry -> list = (RumKey * )
605+ repalloc (entry -> list ,entry -> nalloc * sizeof (RumKey ));
606+ }
607+
608+ rumReadTuple (btree -> rumstate ,entry -> attnum ,itup ,entry -> list + j );
609+ entry -> isFinished = FALSE;
610+ }
611+
612+ /*
613+ * Done with this entry, go to the next
614+ */
615+ stack -> off ++ ;
616+ }
617+ }
618+
418619/*
419620 * Start* functions setup beginning state of searches: finds correct buffer and pins it.
420621 */
@@ -453,7 +654,8 @@ startScanEntry(RumState *rumstate, RumScanEntry entry)
453654entry -> isFinished = TRUE;
454655
455656if (entry -> isPartialMatch ||
456- entry -> queryCategory == RUM_CAT_EMPTY_QUERY )
657+ (entry -> queryCategory == RUM_CAT_EMPTY_QUERY &&
658+ entry -> searchMode != GIN_SEARCH_MODE_EVERYTHING ))
457659{
458660/*
459661 * btreeEntry.findItem locates the first item >= given search key.
@@ -489,6 +691,11 @@ startScanEntry(RumState *rumstate, RumScanEntry entry)
489691entry -> isFinished = FALSE;
490692}
491693}
694+ else if (entry -> searchMode == GIN_SEARCH_MODE_EVERYTHING )
695+ {
696+ btreeEntry .findItem (& btreeEntry ,stackEntry );
697+ collectMatchRumKey (& btreeEntry ,stackEntry ,entry );
698+ }
492699else if (btreeEntry .findItem (& btreeEntry ,stackEntry ))
493700{
494701IndexTuple itup = (IndexTuple )PageGetItem (page ,PageGetItemId (page ,stackEntry -> off ));