/* * Read only item pointers from leaf data page. * Information is stored in the same manner as in leaf data pages. */ void rumReadTuplePointers(RumState * rumstate, OffsetNumber attnum, IndexTuple itup, ItemPointerData *ipd) { Pointer ptr = RumGetPosting(itup); int nipd = RumGetNPosting(itup), i; RumItem item; ItemPointerSetMin(&item.iptr); for (i = 0; i < nipd; i++) { ptr = rumDataPageLeafReadPointer(ptr, attnum, &item, rumstate); ipd[i] = item.iptr; } }
/* * Read item pointers with additional information from leaf data page. * Information is stored in the same manner as in leaf data pages. */ void rumReadTuple(RumState * rumstate, OffsetNumber attnum, IndexTuple itup, RumItem * items, bool copyAddInfo) { Pointer ptr = RumGetPosting(itup); RumItem item; int nipd = RumGetNPosting(itup), i; ItemPointerSetMin(&item.iptr); for (i = 0; i < nipd; i++) { ptr = rumDataPageLeafRead(ptr, attnum, &item, copyAddInfo, rumstate); items[i] = item; } }
/* * Get heap item pointer from scan * returns true if found */ static bool scanGetItem(IndexScanDesc scan, ItemPointerData *item) { uint32 i; GinScanOpaque so = (GinScanOpaque) scan->opaque; ItemPointerSetMin(item); for (i = 0; i < so->nkeys; i++) { GinScanKey key = so->keys + i; if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == FALSE) { if (compareItemPointers(item, &key->curItem) < 0) *item = key->curItem; } else return FALSE; /* finished one of keys */ } for (i = 1; i <= so->nkeys; i++) { GinScanKey key = so->keys + i - 1; for (;;) { int cmp = compareItemPointers(item, &key->curItem); if (cmp == 0) break; else if (cmp > 0) { if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == TRUE) return FALSE; /* finished one of keys */ } else { /* returns to begin */ *item = key->curItem; i = 0; break; } } } return TRUE; }
/* * Create a new GinScanEntry, unless an equivalent one already exists, * in which case just return it */ static GinScanEntry ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum, StrategyNumber strategy, int32 searchMode, Datum queryKey, GinNullCategory queryCategory, bool isPartialMatch, Pointer extra_data) { GinState *ginstate = &so->ginstate; GinScanEntry scanEntry; uint32 i; /* * Look for an existing equivalent entry. * * Entries with non-null extra_data are never considered identical, since * we can't know exactly what the opclass might be doing with that. */ if (extra_data == NULL) { for (i = 0; i < so->totalentries; i++) { GinScanEntry prevEntry = so->entries[i]; if (prevEntry->extra_data == NULL && prevEntry->isPartialMatch == isPartialMatch && prevEntry->strategy == strategy && prevEntry->searchMode == searchMode && prevEntry->attnum == attnum && ginCompareEntries(ginstate, attnum, prevEntry->queryKey, prevEntry->queryCategory, queryKey, queryCategory) == 0) { /* Successful match */ return prevEntry; } } } /* Nope, create a new entry */ scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData)); scanEntry->queryKey = queryKey; scanEntry->queryCategory = queryCategory; scanEntry->isPartialMatch = isPartialMatch; scanEntry->extra_data = extra_data; scanEntry->strategy = strategy; scanEntry->searchMode = searchMode; scanEntry->attnum = attnum; scanEntry->buffer = InvalidBuffer; ItemPointerSetMin(&scanEntry->curItem); scanEntry->matchBitmap = NULL; scanEntry->matchIterator = NULL; scanEntry->matchResult = NULL; scanEntry->list = NULL; scanEntry->nlist = 0; scanEntry->offset = InvalidOffsetNumber; scanEntry->isFinished = false; scanEntry->reduceResult = false; /* Add it to so's array */ if (so->totalentries >= so->allocentries) { so->allocentries *= 2; so->entries = (GinScanEntry *) repalloc(so->entries, so->allocentries * sizeof(GinScanEntry)); } so->entries[so->totalentries++] = scanEntry; return scanEntry; }
/* * Initialize the next GinScanKey using the output from the extractQueryFn */ static void ginFillScanKey(GinScanOpaque so, OffsetNumber attnum, StrategyNumber strategy, int32 searchMode, Datum query, uint32 nQueryValues, Datum *queryValues, GinNullCategory *queryCategories, bool *partial_matches, Pointer *extra_data) { GinScanKey key = &(so->keys[so->nkeys++]); GinState *ginstate = &so->ginstate; uint32 nUserQueryValues = nQueryValues; uint32 i; /* Non-default search modes add one "hidden" entry to each key */ if (searchMode != GIN_SEARCH_MODE_DEFAULT) nQueryValues++; key->nentries = nQueryValues; key->nuserentries = nUserQueryValues; key->scanEntry = (GinScanEntry *) palloc(sizeof(GinScanEntry) * nQueryValues); key->entryRes = (bool *) palloc0(sizeof(bool) * nQueryValues); key->query = query; key->queryValues = queryValues; key->queryCategories = queryCategories; key->extra_data = extra_data; key->strategy = strategy; key->searchMode = searchMode; key->attnum = attnum; ItemPointerSetMin(&key->curItem); key->curItemMatches = false; key->recheckCurItem = false; key->isFinished = false; key->nrequired = 0; key->nadditional = 0; key->requiredEntries = NULL; key->additionalEntries = NULL; ginInitConsistentFunction(ginstate, key); for (i = 0; i < nQueryValues; i++) { Datum queryKey; GinNullCategory queryCategory; bool isPartialMatch; Pointer this_extra; if (i < nUserQueryValues) { /* set up normal entry using extractQueryFn's outputs */ queryKey = queryValues[i]; queryCategory = queryCategories[i]; isPartialMatch = (ginstate->canPartialMatch[attnum - 1] && partial_matches) ? partial_matches[i] : false; this_extra = (extra_data) ? extra_data[i] : NULL; } else { /* set up hidden entry */ queryKey = (Datum) 0; switch (searchMode) { case GIN_SEARCH_MODE_INCLUDE_EMPTY: queryCategory = GIN_CAT_EMPTY_ITEM; break; case GIN_SEARCH_MODE_ALL: queryCategory = GIN_CAT_EMPTY_QUERY; break; case GIN_SEARCH_MODE_EVERYTHING: queryCategory = GIN_CAT_EMPTY_QUERY; break; default: elog(ERROR, "unexpected searchMode: %d", searchMode); queryCategory = 0; /* keep compiler quiet */ break; } isPartialMatch = false; this_extra = NULL; /* * We set the strategy to a fixed value so that ginFillScanEntry * can combine these entries for different scan keys. This is * safe because the strategy value in the entry struct is only * used for partial-match cases. It's OK to overwrite our local * variable here because this is the last loop iteration. */ strategy = InvalidStrategy; } key->scanEntry[i] = ginFillScanEntry(so, attnum, strategy, searchMode, queryKey, queryCategory, isPartialMatch, this_extra); } }