mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			271 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			271 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.7 1997/08/19 21:29:26 momjian 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);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef NOT_USED
 | 
						|
/* ----------------
 | 
						|
 *  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));
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef NOT_USED
 | 
						|
/* ----------------
 | 
						|
 *  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);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/* ----------------
 | 
						|
 *  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 */
 | 
						|
}
 |