Skip to content

Commit 9038ba2

Browse files
author
Zakirov Artur
committed
orderby without where works
1 parent b3a93b7 commit 9038ba2

File tree

3 files changed

+236
-19
lines changed

3 files changed

+236
-19
lines changed

rum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ typedef struct RumScanEntryData
616616
RumKey *list;
617617
MemoryContext context;
618618
uint32 nlist;
619+
uint32 nalloc;
619620
OffsetNumber offset;
620621

621622
bool isFinished;

rumget.c

Lines changed: 218 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,16 @@ callConsistentFn(RumState *rumstate, RumScanKey key)
5555
if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
5656
{
5757
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)
6858
res = true;
59+
}
6960
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+
7068
res = DatumGetBool(FunctionCall10Coll(&rumstate->consistentFn[key->attnum - 1],
7169
rumstate->supportCollation[key->attnum - 1],
7270
PointerGetDatum(key->entryRes),
@@ -80,6 +78,7 @@ callConsistentFn(RumState *rumstate, RumScanKey key)
8078
PointerGetDatum(key->addInfo),
8179
PointerGetDatum(key->addInfoIsNull)
8280
));
81+
}
8382

8483
if (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)
453654
entry->isFinished = TRUE;
454655

455656
if (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)
489691
entry->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+
}
492699
else if (btreeEntry.findItem(&btreeEntry, stackEntry))
493700
{
494701
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off));

rumscan.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ rumFillScanEntry(RumScanOpaque so, OffsetNumber attnum,
113113
scanEntry->matchResult = NULL;
114114
scanEntry->list = NULL;
115115
scanEntry->nlist = 0;
116+
scanEntry->nalloc = 0;
116117
scanEntry->offset = InvalidOffsetNumber;
117118
scanEntry->isFinished = false;
118119
scanEntry->reduceResult = false;
@@ -386,8 +387,6 @@ rumNewScanKey(IndexScanDesc scan)
386387
{
387388
RumScanOpaque so = (RumScanOpaque) scan->opaque;
388389
int i;
389-
uint32 nkeys,
390-
norderbys;
391390
bool hasNullQuery = false;
392391
MemoryContext oldCtx;
393392

@@ -400,7 +399,7 @@ rumNewScanKey(IndexScanDesc scan)
400399

401400
/* if no scan keys provided, allocate extra EVERYTHING RumScanKey */
402401
so->keys = (RumScanKey)
403-
palloc(Max(scan->numberOfKeys + scan->numberOfOrderBys, 1) *
402+
palloc((Max(scan->numberOfKeys, 1) + scan->numberOfOrderBys) *
404403
sizeof(RumScanKeyData));
405404
so->nkeys = 0;
406405

@@ -419,15 +418,26 @@ rumNewScanKey(IndexScanDesc scan)
419418
if (so->isVoidRes)
420419
break;
421420
}
422-
nkeys = so->nkeys;
421+
/*
422+
* If there are no regular scan keys, generate an EMPTY scankey to
423+
* drive a full-index scan.
424+
*/
425+
if (so->nkeys == 0 && scan->numberOfOrderBys > 0 && !so->isVoidRes)
426+
{
427+
hasNullQuery = true;
428+
rumFillScanKey(so, FirstOffsetNumber,
429+
InvalidStrategy,
430+
GIN_SEARCH_MODE_EVERYTHING,
431+
(Datum) 0, 0,
432+
NULL, NULL, NULL, NULL, false);
433+
}
423434

424435
for (i = 0; i < scan->numberOfOrderBys; i++)
425436
{
426437
initScanKey(so, &scan->orderByData[i], &hasNullQuery);
427438
if (so->isVoidRes)
428439
break;
429440
}
430-
norderbys = so->nkeys - nkeys;
431441

432442
if (scan->numberOfOrderBys > 0)
433443
{
@@ -441,13 +451,12 @@ rumNewScanKey(IndexScanDesc scan)
441451
* If there are no regular scan keys, generate an EVERYTHING scankey to
442452
* drive a full-index scan.
443453
*/
444-
if (nkeys == 0 && !so->isVoidRes)
454+
if (so->nkeys == 0 && !so->isVoidRes)
445455
{
446456
hasNullQuery = true;
447457
rumFillScanKey(so, FirstOffsetNumber,
448458
InvalidStrategy,
449-
(norderbys > 0) ? GIN_SEARCH_MODE_INCLUDE_EMPTY :
450-
GIN_SEARCH_MODE_EVERYTHING,
459+
GIN_SEARCH_MODE_EVERYTHING,
451460
(Datum) 0, 0,
452461
NULL, NULL, NULL, NULL, false);
453462
}

0 commit comments

Comments
 (0)