@@ -55,18 +55,16 @@ callConsistentFn(RumState *rumstate, RumScanKey key)
55
55
if (key -> searchMode == GIN_SEARCH_MODE_EVERYTHING )
56
56
{
57
57
key -> 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 )
68
58
res = true;
59
+ }
69
60
else
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
+
70
68
res = DatumGetBool (FunctionCall10Coll (& rumstate -> consistentFn [key -> attnum - 1 ],
71
69
rumstate -> supportCollation [key -> attnum - 1 ],
72
70
PointerGetDatum (key -> entryRes ),
@@ -80,6 +78,7 @@ callConsistentFn(RumState *rumstate, RumScanKey key)
80
78
PointerGetDatum (key -> addInfo ),
81
79
PointerGetDatum (key -> addInfoIsNull )
82
80
));
81
+ }
83
82
84
83
if (res && key -> attnum == rumstate -> attrnAddToColumn )
85
84
{
@@ -415,6 +414,208 @@ collectMatchBitmap(RumBtreeData *btree, RumBtreeStack *stack,
415
414
}
416
415
}
417
416
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
+
418
619
/*
419
620
* Start* functions setup beginning state of searches: finds correct buffer and pins it.
420
621
*/
@@ -453,7 +654,8 @@ startScanEntry(RumState *rumstate, RumScanEntry entry)
453
654
entry -> isFinished = TRUE;
454
655
455
656
if (entry -> isPartialMatch ||
456
- entry -> queryCategory == RUM_CAT_EMPTY_QUERY )
657
+ (entry -> queryCategory == RUM_CAT_EMPTY_QUERY &&
658
+ entry -> searchMode != GIN_SEARCH_MODE_EVERYTHING ))
457
659
{
458
660
/*
459
661
* btreeEntry.findItem locates the first item >= given search key.
@@ -489,6 +691,11 @@ startScanEntry(RumState *rumstate, RumScanEntry entry)
489
691
entry -> isFinished = FALSE;
490
692
}
491
693
}
694
+ else if (entry -> searchMode == GIN_SEARCH_MODE_EVERYTHING )
695
+ {
696
+ btreeEntry .findItem (& btreeEntry , stackEntry );
697
+ collectMatchRumKey (& btreeEntry , stackEntry , entry );
698
+ }
492
699
else if (btreeEntry .findItem (& btreeEntry , stackEntry ))
493
700
{
494
701
IndexTuple itup = (IndexTuple ) PageGetItem (page , PageGetItemId (page , stackEntry -> off ));
0 commit comments