/* * gistgetbitmap() -- Get a bitmap of all heap tuple locations */ Datum gistgetbitmap(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); Node *n = (Node *) PG_GETARG_POINTER(1); TIDBitmap *tbm; GISTScanOpaque so = (GISTScanOpaque) scan->opaque; int64 ntids = 0; GISTSearchItem fakeItem; if (n == NULL) tbm = tbm_create(work_mem * 1024L); else if (!IsA(n, TIDBitmap)) elog(ERROR, "non hash bitmap"); else tbm = (TIDBitmap *) n; if (!so->qual_ok) PG_RETURN_POINTER(tbm); pgstat_count_index_scan(scan->indexRelation); /* Begin the scan by processing the root page */ so->curTreeItem = NULL; so->curPageData = so->nPageData = 0; fakeItem.blkno = GIST_ROOT_BLKNO; memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN)); gistScanPage(scan, &fakeItem, NULL, tbm, &ntids); /* * While scanning a leaf page, ItemPointers of matching heap tuples will * be stored directly into tbm, so we don't need to deal with them here. */ for (;;) { GISTSearchItem *item = getNextGISTSearchItem(so); if (!item) break; CHECK_FOR_INTERRUPTS(); gistScanPage(scan, item, so->curTreeItem->distances, tbm, &ntids); pfree(item); } PG_RETURN_POINTER(tbm); }
Datum gistgetmulti(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); Node *n = (Node *) PG_GETARG_POINTER(1); HashBitmap *hashBitmap; ItemPointer tids; int ntids; if (n == NULL) hashBitmap = tbm_create(work_mem * 1024L); else if (!IsA(n, HashBitmap)) elog(ERROR, "non hash bitmap"); else hashBitmap = (HashBitmap *)n; #define MAX_TIDS 1024 tids = (ItemPointer)palloc0(MAX_TIDS * sizeof(ItemPointerData)); while ((ntids = gistnext(scan, ForwardScanDirection, tids, MAX_TIDS, false)) > 0) tbm_add_tuples(hashBitmap, tids, ntids); PG_RETURN_POINTER(hashBitmap); }
/* ---------------------------------------------------------------- * MultiExecBitmapIndexScan(node) * ---------------------------------------------------------------- */ Node * MultiExecBitmapIndexScan(BitmapIndexScanState *node) { TIDBitmap *tbm; IndexScanDesc scandesc; double nTuples = 0; bool doscan; /* must provide our own instrumentation support */ if (node->ss.ps.instrument) InstrStartNode(node->ss.ps.instrument); /* * extract necessary information from index scan node */ scandesc = node->biss_ScanDesc; /* * If we have runtime keys and they've not already been set up, do it now. * Array keys are also treated as runtime keys; note that if ExecReScan * returns with biss_RuntimeKeysReady still false, then there is an empty * array key so we should do nothing. */ if (!node->biss_RuntimeKeysReady && (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0)) { ExecReScan((PlanState *) node); doscan = node->biss_RuntimeKeysReady; } else doscan = true; /* * Prepare the result bitmap. Normally we just create a new one to pass * back; however, our parent node is allowed to store a pre-made one into * node->biss_result, in which case we just OR our tuple IDs into the * existing bitmap. (This saves needing explicit UNION steps.) */ if (node->biss_result) { tbm = node->biss_result; node->biss_result = NULL; /* reset for next time */ } else { /* XXX should we use less than work_mem for this? */ tbm = tbm_create(work_mem * 1024L); } /* * Get TIDs from index and insert into bitmap */ while (doscan) { nTuples += (double) index_getbitmap(scandesc, tbm); CHECK_FOR_INTERRUPTS(); doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys, node->biss_NumArrayKeys); if (doscan) /* reset index scan */ index_rescan(node->biss_ScanDesc, node->biss_ScanKeys, node->biss_NumScanKeys, NULL, 0); } /* must provide our own instrumentation support */ if (node->ss.ps.instrument) InstrStopNode(node->ss.ps.instrument, nTuples); return (Node *) tbm; }
/* * btgetmulti() -- construct a HashBitmap. */ Datum btgetmulti(PG_FUNCTION_ARGS) { MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_DECLARE; IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); Node *n = (Node *)PG_GETARG_POINTER(1); HashBitmap *hashBitmap; BTScanOpaque so = (BTScanOpaque) scan->opaque; bool res = true; MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_ENTER; if (n == NULL || IsA(n, StreamBitmap)) { /* XXX should we use less than work_mem for this? */ hashBitmap = tbm_create(work_mem * 1024L); } else { hashBitmap = (HashBitmap *)n; } /* If we haven't started the scan yet, fetch the first page & tuple. */ if (!BTScanPosIsValid(so->currPos)) { res = _bt_first(scan, ForwardScanDirection); if (res) { /* Save tuple ID, and continue scanning */ tbm_add_tuples(hashBitmap, &(scan->xs_ctup.t_self), 1); } } while (res) { /* * Advance to next tuple within page. This is the same as the * easy case in _bt_next(). */ if (++so->currPos.itemIndex > so->currPos.lastItem) { /* let _bt_next do the heavy lifting */ res = _bt_next(scan, ForwardScanDirection); if (!res) break; } /* Save tuple ID, and continue scanning */ tbm_add_tuples(hashBitmap, &(so->currPos.items[so->currPos.itemIndex].heapTid), 1); } if(n && IsA(n, StreamBitmap)) { stream_add_node((StreamBitmap *)n, tbm_create_stream_node(hashBitmap), BMS_OR); PG_RETURN_POINTER(n); } MIRROREDLOCK_BUFMGR_VERIFY_NO_LOCK_LEAK_EXIT; PG_RETURN_POINTER(hashBitmap); }
/* ---------------------------------------------------------------- * MultiExecBitmapIndexScan(node) * ---------------------------------------------------------------- */ Node * MultiExecBitmapIndexScan(BitmapIndexScanState *node) { #define MAX_TIDS 1024 TIDBitmap *tbm = NULL; IndexScanDesc scandesc; IndexScanDesc odScanDesc; ItemPointerData tids[MAX_TIDS]; int32 ntids; double nTuples = 0; OnDiskBitmapWords *odbm = NULL; bool inmem = false; /* must provide our own instrumentation support */ if (node->ss.ps.instrument) InstrStartNode(node->ss.ps.instrument); /* * extract necessary information from index scan node */ scandesc = node->biss_ScanDesc; odScanDesc = node->odbiss_ScanDesc; /* * If we have runtime keys and they've not already been set up, do it * now. */ if (node->biss_RuntimeKeyInfo && !node->biss_RuntimeKeysReady) ExecReScan((PlanState *) node, NULL); inmem = ((BitmapIndexScan*)((PlanState*)node)->plan)->inmem; if (inmem) { node->odbiss_result = NULL; /* * Prepare the result bitmap. Normally we just create a new one to pass * back; however, our parent node is allowed to store a pre-made one * into node->biss_result, in which case we just OR our tuple IDs into * the existing bitmap. (This saves needing explicit UNION steps.) */ if (node->biss_result) { tbm = node->biss_result; node->biss_result = NULL; /* reset for next time */ } else { /* XXX should we use less than work_mem for this? */ tbm = tbm_create(work_mem * 1024L); } /* * Get TIDs from index and insert into bitmap */ for (;;) { bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids); if (ntids > 0) { tbm_add_tuples(tbm, tids, ntids); nTuples += ntids; } if (!more) break; CHECK_FOR_INTERRUPTS(); } } else { node->biss_result = NULL; if (node->odbiss_result == NULL) node->odbiss_result = odbm_create(ODBM_MAX_WORDS); odbm = node->odbiss_result; index_getbitmapwords(odScanDesc, odbm->maxNumOfWords, &(odbm->numOfWords), odbm->bitmapHeaderWords, odbm->bitmapContentWords); } /* must provide our own instrumentation support */ if (node->ss.ps.instrument) InstrStopNodeMulti(node->ss.ps.instrument, nTuples); if (tbm != NULL) return (Node *) tbm; else return (Node *) odbm; }