mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-02 20:36:52 +02:00
267 lines
7.0 KiB
C
267 lines
7.0 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* genam.c--
|
|
* general index access method routines
|
|
*
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.6 1996/11/05 10:02:02 scrappy Exp $
|
|
*
|
|
* NOTES
|
|
* many of the old access method routines have been turned into
|
|
* macros and moved to genam.h -cim 4/30/91
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
/*
|
|
* OLD COMMENTS
|
|
* Scans are implemented as follows:
|
|
*
|
|
* `0' represents an invalid item pointer.
|
|
* `-' represents an unknown item pointer.
|
|
* `X' represents a known item pointers.
|
|
* `+' represents known or invalid item pointers.
|
|
* `*' represents any item pointers.
|
|
*
|
|
* State is represented by a triple of these symbols in the order of
|
|
* previous, current, next. Note that the case of reverse scans works
|
|
* identically.
|
|
*
|
|
* State Result
|
|
* (1) + + - + 0 0 (if the next item pointer is invalid)
|
|
* (2) + X - (otherwise)
|
|
* (3) * 0 0 * 0 0 (no change)
|
|
* (4) + X 0 X 0 0 (shift)
|
|
* (5) * + X + X - (shift, add unknown)
|
|
*
|
|
* All other states cannot occur.
|
|
*
|
|
* Note:
|
|
*It would be possible to cache the status of the previous and
|
|
* next item pointer using the flags.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
|
|
#include <postgres.h>
|
|
|
|
#include <utils/catcache.h>
|
|
#include <access/genam.h>
|
|
#include <storage/bufmgr.h>
|
|
|
|
#ifndef HAVE_MEMMOVE
|
|
# include <regex/utils.h>
|
|
#else
|
|
# include <string.h>
|
|
#endif
|
|
|
|
/* ----------------------------------------------------------------
|
|
* general access method routines
|
|
*
|
|
* All indexed access methods use an identical scan structure.
|
|
* We don't know how the various AMs do locking, however, so we don't
|
|
* do anything about that here.
|
|
*
|
|
* The intent is that an AM implementor will define a front-end routine
|
|
* that calls this one, to fill in the scan, and then does whatever kind
|
|
* of locking he wants.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
|
|
/* ----------------
|
|
* RelationGetIndexScan -- Create and fill an IndexScanDesc.
|
|
*
|
|
* This routine creates an index scan structure and sets its contents
|
|
* up correctly. This routine calls AMrescan to set up the scan with
|
|
* the passed key.
|
|
*
|
|
* Parameters:
|
|
* relation -- index relation for scan.
|
|
* scanFromEnd -- if true, begin scan at one of the index's
|
|
* endpoints.
|
|
* numberOfKeys -- count of scan keys (more than one won't
|
|
* necessarily do anything useful, yet).
|
|
* key -- the ScanKey for the starting position of the scan.
|
|
*
|
|
* Returns:
|
|
* An initialized IndexScanDesc.
|
|
*
|
|
* Side Effects:
|
|
* Bumps the ref count on the relation to keep it in the cache.
|
|
*
|
|
* ----------------
|
|
*/
|
|
IndexScanDesc
|
|
RelationGetIndexScan(Relation relation,
|
|
bool scanFromEnd,
|
|
uint16 numberOfKeys,
|
|
ScanKey key)
|
|
{
|
|
IndexScanDesc scan;
|
|
|
|
if (! RelationIsValid(relation))
|
|
elog(WARN, "RelationGetIndexScan: relation invalid");
|
|
|
|
scan = (IndexScanDesc) palloc(sizeof(IndexScanDescData));
|
|
|
|
scan->relation = relation;
|
|
scan->opaque = NULL;
|
|
scan->numberOfKeys = numberOfKeys;
|
|
|
|
ItemPointerSetInvalid(&scan->previousItemData);
|
|
ItemPointerSetInvalid(&scan->currentItemData);
|
|
ItemPointerSetInvalid(&scan->nextItemData);
|
|
ItemPointerSetInvalid(&scan->previousMarkData);
|
|
ItemPointerSetInvalid(&scan->currentMarkData);
|
|
ItemPointerSetInvalid(&scan->nextMarkData);
|
|
|
|
if (numberOfKeys > 0) {
|
|
scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * numberOfKeys);
|
|
} else {
|
|
scan->keyData = NULL;
|
|
}
|
|
|
|
index_rescan(scan, scanFromEnd, key);
|
|
|
|
return (scan);
|
|
}
|
|
|
|
/* ----------------
|
|
* IndexScanRestart -- Restart an index scan.
|
|
*
|
|
* This routine isn't used by any existing access method. It's
|
|
* appropriate if relation level locks are what you want.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
* ----------------
|
|
*/
|
|
void
|
|
IndexScanRestart(IndexScanDesc scan,
|
|
bool scanFromEnd,
|
|
ScanKey key)
|
|
{
|
|
if (! IndexScanIsValid(scan))
|
|
elog(WARN, "IndexScanRestart: invalid scan");
|
|
|
|
ItemPointerSetInvalid(&scan->previousItemData);
|
|
ItemPointerSetInvalid(&scan->currentItemData);
|
|
ItemPointerSetInvalid(&scan->nextItemData);
|
|
|
|
if (RelationGetNumberOfBlocks(scan->relation) == 0)
|
|
scan->flags = ScanUnmarked;
|
|
else if (scanFromEnd)
|
|
scan->flags = ScanUnmarked | ScanUncheckedPrevious;
|
|
else
|
|
scan->flags = ScanUnmarked | ScanUncheckedNext;
|
|
|
|
scan->scanFromEnd = (bool) scanFromEnd;
|
|
|
|
if (scan->numberOfKeys > 0)
|
|
memmove(scan->keyData,
|
|
key,
|
|
scan->numberOfKeys * sizeof(ScanKeyData));
|
|
}
|
|
|
|
/* ----------------
|
|
* IndexScanEnd -- End and index scan.
|
|
*
|
|
* This routine is not used by any existing access method, but is
|
|
* suitable for use if you don't want to do sophisticated locking.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
* ----------------
|
|
*/
|
|
void
|
|
IndexScanEnd(IndexScanDesc scan)
|
|
{
|
|
if (! IndexScanIsValid(scan))
|
|
elog(WARN, "IndexScanEnd: invalid scan");
|
|
|
|
pfree(scan);
|
|
}
|
|
|
|
/* ----------------
|
|
* IndexScanMarkPosition -- Mark current position in a scan.
|
|
*
|
|
* This routine isn't used by any existing access method, but is the
|
|
* one that AM implementors should use, if they don't want to do any
|
|
* special locking. If relation-level locking is sufficient, this is
|
|
* the routine for you.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
* ----------------
|
|
*/
|
|
void
|
|
IndexScanMarkPosition(IndexScanDesc scan)
|
|
{
|
|
RetrieveIndexResult result;
|
|
|
|
if (scan->flags & ScanUncheckedPrevious) {
|
|
result =
|
|
index_getnext(scan, BackwardScanDirection);
|
|
|
|
if (result != NULL) {
|
|
scan->previousItemData = result->index_iptr;
|
|
} else {
|
|
ItemPointerSetInvalid(&scan->previousItemData);
|
|
}
|
|
|
|
} else if (scan->flags & ScanUncheckedNext) {
|
|
result = (RetrieveIndexResult)
|
|
index_getnext(scan, ForwardScanDirection);
|
|
|
|
if (result != NULL) {
|
|
scan->nextItemData = result->index_iptr;
|
|
} else {
|
|
ItemPointerSetInvalid(&scan->nextItemData);
|
|
}
|
|
}
|
|
|
|
scan->previousMarkData = scan->previousItemData;
|
|
scan->currentMarkData = scan->currentItemData;
|
|
scan->nextMarkData = scan->nextItemData;
|
|
|
|
scan->flags = 0x0; /* XXX should have a symbolic name */
|
|
}
|
|
|
|
/* ----------------
|
|
* IndexScanRestorePosition -- Restore position on a marked scan.
|
|
*
|
|
* This routine isn't used by any existing access method, but is the
|
|
* one that AM implementors should use if they don't want to do any
|
|
* special locking. If relation-level locking is sufficient, then
|
|
* this is the one you want.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
* ----------------
|
|
*/
|
|
void
|
|
IndexScanRestorePosition(IndexScanDesc scan)
|
|
{
|
|
if (scan->flags & ScanUnmarked)
|
|
elog(WARN, "IndexScanRestorePosition: no mark to restore");
|
|
|
|
scan->previousItemData = scan->previousMarkData;
|
|
scan->currentItemData = scan->currentMarkData;
|
|
scan->nextItemData = scan->nextMarkData;
|
|
|
|
scan->flags = 0x0; /* XXX should have a symbolic name */
|
|
}
|