/* ---------------- * index_endscan - end a scan * ---------------- */ void index_endscan(IndexScanDesc scan) { SCAN_CHECKS; CHECK_SCAN_PROCEDURE(amendscan); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } /* End the AM's scan */ scan->indexRelation->rd_indam->amendscan(scan); /* Release index refcount acquired by index_beginscan */ RelationDecrementReferenceCount(scan->indexRelation); if (scan->xs_temp_snap) UnregisterSnapshot(scan->xs_snapshot); /* Release the scan data structure itself */ IndexScanEnd(scan); }
/* ---------------- * index_rescan - (re)start a scan of an index * * During a restart, the caller may specify a new set of scankeys and/or * orderbykeys; but the number of keys cannot differ from what index_beginscan * was told. (Later we might relax that to "must not exceed", but currently * the index AMs tend to assume that scan->numberOfKeys is what to believe.) * To restart the scan without changing keys, pass NULL for the key arrays. * (Of course, keys *must* be passed on the first call, unless * scan->numberOfKeys is zero.) * ---------------- */ void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys) { SCAN_CHECKS; CHECK_SCAN_PROCEDURE(amrescan); Assert(nkeys == scan->numberOfKeys); Assert(norderbys == scan->numberOfOrderBys); /* Release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } scan->xs_continue_hot = false; scan->kill_prior_tuple = false; /* for safety */ scan->indexRelation->rd_indam->amrescan(scan, keys, nkeys, orderbys, norderbys); }
/* ---------------- * index_markpos - mark a scan position * ---------------- */ void index_markpos(IndexScanDesc scan) { SCAN_CHECKS; CHECK_SCAN_PROCEDURE(ammarkpos); scan->indexRelation->rd_amroutine->ammarkpos(scan); }
/* ---------------- * index_restrpos - restore a scan position * * NOTE: this only restores the internal scan state of the index AM. * The current result tuple (scan->xs_ctup) doesn't change. See comments * for ExecRestrPos(). * * NOTE: in the presence of HOT chains, mark/restore only works correctly * if the scan's snapshot is MVCC-safe; that ensures that there's at most one * returnable tuple in each HOT chain, and so restoring the prior state at the * granularity of the index AM is sufficient. Since the only current user * of mark/restore functionality is nodeMergejoin.c, this effectively means * that merge-join plans only work for MVCC snapshots. This could be fixed * if necessary, but for now it seems unimportant. * ---------------- */ void index_restrpos(IndexScanDesc scan) { Assert(IsMVCCSnapshot(scan->xs_snapshot)); SCAN_CHECKS; CHECK_SCAN_PROCEDURE(amrestrpos); scan->xs_continue_hot = false; scan->kill_prior_tuple = false; /* for safety */ scan->indexRelation->rd_amroutine->amrestrpos(scan); }
/* ---------------- * index_getbitmap - get all tuples at once from an index scan * * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap. * Since there's no interlock between the index scan and the eventual heap * access, this is only safe to use with MVCC-based snapshots: the heap * item slot could have been replaced by a newer tuple by the time we get * to it. * * Returns the number of matching tuples found. (Note: this might be only * approximate, so it should only be used for statistical purposes.) * ---------------- */ int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap) { int64 ntids; SCAN_CHECKS; CHECK_SCAN_PROCEDURE(amgetbitmap); /* just make sure this is false... */ scan->kill_prior_tuple = false; /* * have the am's getbitmap proc do all the work. */ ntids = scan->indexRelation->rd_amroutine->amgetbitmap(scan, bitmap); pgstat_count_index_tuples(scan->indexRelation, ntids); return ntids; }
/* ---------------- * index_getnext_tid - get the next TID from a scan * * The result is the next TID satisfying the scan keys, * or NULL if no more matching tuples exist. * ---------------- */ ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction) { bool found; SCAN_CHECKS; CHECK_SCAN_PROCEDURE(amgettuple); Assert(TransactionIdIsValid(RecentGlobalXmin)); /* * The AM's amgettuple proc finds the next index entry matching the scan * keys, and puts the TID into scan->xs_ctup.t_self. It should also set * scan->xs_recheck and possibly scan->xs_itup/scan->xs_hitup, though we * pay no attention to those fields here. */ found = scan->indexRelation->rd_amroutine->amgettuple(scan, direction); /* Reset kill flag immediately for safety */ scan->kill_prior_tuple = false; /* If we're out of index entries, we're done */ if (!found) { /* ... but first, release any held pin on a heap page */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } return NULL; } pgstat_count_index_tuples(scan->indexRelation, 1); /* Return the TID of the tuple we found. */ return &scan->xs_ctup.t_self; }