mirror of
https://github.com/postgres/postgres.git
synced 2025-08-30 06:01:21 +03:00
Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
14
src/backend/access/index/Makefile.inc
Normal file
14
src/backend/access/index/Makefile.inc
Normal file
@@ -0,0 +1,14 @@
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile.inc--
|
||||
# Makefile for access/index
|
||||
#
|
||||
# Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/index/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:11 scrappy Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SUBSRCS+= genam.c indexam.c istrat.c
|
275
src/backend/access/index/genam.c
Normal file
275
src/backend/access/index/genam.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* 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.1.1.1 1996/07/09 06:21:11 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 "access/attnum.h"
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/itup.h"
|
||||
#include "access/relscan.h"
|
||||
#include "access/sdir.h"
|
||||
#include "access/skey.h"
|
||||
|
||||
#include "storage/bufmgr.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/rel.h"
|
||||
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/pg_attribute.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
|
||||
#include "catalog/index.h"
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* 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 */
|
||||
}
|
411
src/backend/access/index/indexam.c
Normal file
411
src/backend/access/index/indexam.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* indexam.c--
|
||||
* general index access method routines
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.1.1.1 1996/07/09 06:21:11 scrappy Exp $
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
* index_open - open an index relation by relationId
|
||||
* index_openr - open a index relation by name
|
||||
* index_close - close a index relation
|
||||
* index_beginscan - start a scan of an index
|
||||
* index_rescan - restart a scan of an index
|
||||
* index_endscan - end a scan
|
||||
* index_insert - insert an index tuple into a relation
|
||||
* index_delete - delete an item from an index relation
|
||||
* index_markpos - mark a scan position
|
||||
* index_restrpos - restore a scan position
|
||||
* index_getnext - get the next tuple from a scan
|
||||
* ** index_fetch - retrieve tuple with tid
|
||||
* ** index_replace - replace a tuple
|
||||
* ** index_getattr - get an attribute from an index tuple
|
||||
* index_getprocid - get a support procedure id from the rel tuple
|
||||
*
|
||||
* IndexScanIsValid - check index scan
|
||||
*
|
||||
* NOTES
|
||||
* This file contains the index_ routines which used
|
||||
* to be a scattered collection of stuff in access/genam.
|
||||
*
|
||||
* The ** routines: index_fetch, index_replace, and index_getattr
|
||||
* have not yet been implemented. They may not be needed.
|
||||
*
|
||||
* 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 "access/attnum.h"
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/itup.h"
|
||||
#include "access/relscan.h"
|
||||
#include "access/sdir.h"
|
||||
#include "access/skey.h"
|
||||
#include "access/funcindex.h"
|
||||
|
||||
#include "storage/lmgr.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/relcache.h"
|
||||
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/pg_attribute.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
|
||||
#include "catalog/index.h"
|
||||
|
||||
#include "fmgr.h"
|
||||
|
||||
/* ----------------
|
||||
* undefine macros we aren't going to use that would otherwise
|
||||
* get in our way.. delete is defined in c.h and the am's are
|
||||
* defined in heapam.h
|
||||
* ----------------
|
||||
*/
|
||||
#undef delete
|
||||
#undef aminsert
|
||||
#undef amdelete
|
||||
#undef ambeginscan
|
||||
#undef amrescan
|
||||
#undef amendscan
|
||||
#undef ammarkpos
|
||||
#undef amrestrpos
|
||||
#undef amgettuple
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* macros used in index_ routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
#define RELATION_CHECKS \
|
||||
Assert(RelationIsValid(relation)); \
|
||||
Assert(PointerIsValid(relation->rd_am))
|
||||
|
||||
#define SCAN_CHECKS \
|
||||
Assert(IndexScanIsValid(scan)); \
|
||||
Assert(RelationIsValid(scan->relation)); \
|
||||
Assert(PointerIsValid(scan->relation->rd_am))
|
||||
|
||||
#define GET_REL_PROCEDURE(x,y) \
|
||||
CppConcat(procedure = relation->rd_am->,y); \
|
||||
if (! RegProcedureIsValid(procedure)) \
|
||||
elog(WARN, "index_%s: invalid %s regproc", \
|
||||
CppAsString(x), CppAsString(y))
|
||||
|
||||
#define GET_SCAN_PROCEDURE(x,y) \
|
||||
CppConcat(procedure = scan->relation->rd_am->,y); \
|
||||
if (! RegProcedureIsValid(procedure)) \
|
||||
elog(WARN, "index_%s: invalid %s regproc", \
|
||||
CppAsString(x), CppAsString(y))
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* index_ interface functions
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
/* ----------------
|
||||
* index_open - open an index relation by relationId
|
||||
*
|
||||
* presently the relcache routines do all the work we need
|
||||
* to open/close index relations.
|
||||
* ----------------
|
||||
*/
|
||||
Relation
|
||||
index_open(Oid relationId)
|
||||
{
|
||||
return RelationIdGetRelation(relationId);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_openr - open a index relation by name
|
||||
*
|
||||
* presently the relcache routines do all the work we need
|
||||
* to open/close index relations.
|
||||
* ----------------
|
||||
*/
|
||||
Relation
|
||||
index_openr(char *relationName)
|
||||
{
|
||||
return RelationNameGetRelation(relationName);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_close - close a index relation
|
||||
*
|
||||
* presently the relcache routines do all the work we need
|
||||
* to open/close index relations.
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
index_close(Relation relation)
|
||||
{
|
||||
(void) RelationClose(relation);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_insert - insert an index tuple into a relation
|
||||
* ----------------
|
||||
*/
|
||||
InsertIndexResult
|
||||
index_insert(Relation relation,
|
||||
IndexTuple indexTuple)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
InsertIndexResult specificResult;
|
||||
|
||||
RELATION_CHECKS;
|
||||
GET_REL_PROCEDURE(insert,aminsert);
|
||||
|
||||
/* ----------------
|
||||
* have the am's insert proc do all the work.
|
||||
* ----------------
|
||||
*/
|
||||
specificResult = (InsertIndexResult)
|
||||
fmgr(procedure, relation, indexTuple, NULL);
|
||||
|
||||
/* ----------------
|
||||
* the insert proc is supposed to return a "specific result" and
|
||||
* this routine has to return a "general result" so after we get
|
||||
* something back from the insert proc, we allocate a
|
||||
* "general result" and copy some crap between the two.
|
||||
*
|
||||
* As far as I'm concerned all this result shit is needlessly c
|
||||
* omplicated and should be eliminated. -cim 1/19/91
|
||||
*
|
||||
* mao concurs. regardless of how we feel here, however, it is
|
||||
* important to free memory we don't intend to return to anyone.
|
||||
* 2/28/91
|
||||
*
|
||||
* this "general result" crap is now gone. -ay 3/6/95
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
return (specificResult);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_delete - delete an item from an index relation
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
index_delete(Relation relation, ItemPointer indexItem)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
|
||||
RELATION_CHECKS;
|
||||
GET_REL_PROCEDURE(delete,amdelete);
|
||||
|
||||
(void) fmgr(procedure, relation, indexItem);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_beginscan - start a scan of an index
|
||||
* ----------------
|
||||
*/
|
||||
IndexScanDesc
|
||||
index_beginscan(Relation relation,
|
||||
bool scanFromEnd,
|
||||
uint16 numberOfKeys,
|
||||
ScanKey key)
|
||||
{
|
||||
IndexScanDesc scandesc;
|
||||
RegProcedure procedure;
|
||||
|
||||
RELATION_CHECKS;
|
||||
GET_REL_PROCEDURE(beginscan,ambeginscan);
|
||||
|
||||
RelationSetRIntentLock(relation);
|
||||
|
||||
scandesc = (IndexScanDesc)
|
||||
fmgr(procedure, relation, scanFromEnd, numberOfKeys, key);
|
||||
|
||||
return scandesc;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_rescan - restart a scan of an index
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
index_rescan(IndexScanDesc scan, bool scanFromEnd, ScanKey key)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
|
||||
SCAN_CHECKS;
|
||||
GET_SCAN_PROCEDURE(rescan,amrescan);
|
||||
|
||||
(void) fmgr(procedure, scan, scanFromEnd, key);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_endscan - end a scan
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
index_endscan(IndexScanDesc scan)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
|
||||
SCAN_CHECKS;
|
||||
GET_SCAN_PROCEDURE(endscan,amendscan);
|
||||
|
||||
(void) fmgr(procedure, scan);
|
||||
|
||||
RelationUnsetRIntentLock(scan->relation);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_markpos - mark a scan position
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
index_markpos(IndexScanDesc scan)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
|
||||
SCAN_CHECKS;
|
||||
GET_SCAN_PROCEDURE(markpos,ammarkpos);
|
||||
|
||||
(void) fmgr(procedure, scan);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_restrpos - restore a scan position
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
index_restrpos(IndexScanDesc scan)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
|
||||
SCAN_CHECKS;
|
||||
GET_SCAN_PROCEDURE(restrpos,amrestrpos);
|
||||
|
||||
(void) fmgr(procedure, scan);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_getnext - get the next tuple from a scan
|
||||
*
|
||||
* A RetrieveIndexResult is a index tuple/heap tuple pair
|
||||
* ----------------
|
||||
*/
|
||||
RetrieveIndexResult
|
||||
index_getnext(IndexScanDesc scan,
|
||||
ScanDirection direction)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
RetrieveIndexResult result;
|
||||
|
||||
SCAN_CHECKS;
|
||||
GET_SCAN_PROCEDURE(getnext,amgettuple);
|
||||
|
||||
/* ----------------
|
||||
* have the am's gettuple proc do all the work.
|
||||
* ----------------
|
||||
*/
|
||||
result = (RetrieveIndexResult)
|
||||
fmgr(procedure, scan, direction);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* index_getprocid
|
||||
*
|
||||
* Some indexed access methods may require support routines that are
|
||||
* not in the operator class/operator model imposed by pg_am. These
|
||||
* access methods may store the OIDs of registered procedures they
|
||||
* need in pg_amproc. These registered procedure OIDs are ordered in
|
||||
* a way that makes sense to the access method, and used only by the
|
||||
* access method. The general index code doesn't know anything about
|
||||
* the routines involved; it just builds an ordered list of them for
|
||||
* each attribute on which an index is defined.
|
||||
*
|
||||
* This routine returns the requested procedure OID for a particular
|
||||
* indexed attribute.
|
||||
* ----------------
|
||||
*/
|
||||
RegProcedure
|
||||
index_getprocid(Relation irel,
|
||||
AttrNumber attnum,
|
||||
uint16 procnum)
|
||||
{
|
||||
RegProcedure *loc;
|
||||
int natts;
|
||||
|
||||
natts = irel->rd_rel->relnatts;
|
||||
|
||||
loc = irel->rd_support;
|
||||
|
||||
Assert(loc != NULL);
|
||||
|
||||
return (loc[(natts * (procnum - 1)) + (attnum - 1)]);
|
||||
}
|
||||
|
||||
Datum
|
||||
GetIndexValue(HeapTuple tuple,
|
||||
TupleDesc hTupDesc,
|
||||
int attOff,
|
||||
AttrNumber attrNums[],
|
||||
FuncIndexInfo *fInfo,
|
||||
bool *attNull,
|
||||
Buffer buffer)
|
||||
{
|
||||
Datum returnVal;
|
||||
bool isNull;
|
||||
|
||||
if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid) {
|
||||
int i;
|
||||
Datum *attData = (Datum *)palloc(FIgetnArgs(fInfo)*sizeof(Datum));
|
||||
|
||||
for (i = 0; i < FIgetnArgs(fInfo); i++) {
|
||||
attData[i] = (Datum) heap_getattr(tuple,
|
||||
buffer,
|
||||
attrNums[i],
|
||||
hTupDesc,
|
||||
attNull);
|
||||
}
|
||||
returnVal = (Datum)fmgr_array_args(FIgetProcOid(fInfo),
|
||||
FIgetnArgs(fInfo),
|
||||
(char **) attData,
|
||||
&isNull);
|
||||
pfree(attData);
|
||||
*attNull = FALSE;
|
||||
}else {
|
||||
returnVal = (Datum) heap_getattr(tuple, buffer, attrNums[attOff],
|
||||
hTupDesc, attNull);
|
||||
}
|
||||
return returnVal;
|
||||
}
|
679
src/backend/access/index/istrat.c
Normal file
679
src/backend/access/index/istrat.c
Normal file
@@ -0,0 +1,679 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* istrat.c--
|
||||
* index scan strategy manipulation code and index strategy manipulation
|
||||
* operator code.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.1.1.1 1996/07/09 06:21:11 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/attnum.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/istrat.h"
|
||||
#include "access/itup.h" /* for MaxIndexAttributeNumber */
|
||||
#include "access/skey.h"
|
||||
#include "utils/tqual.h" /* for NowTimeQual */
|
||||
|
||||
#include "fmgr.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/rel.h"
|
||||
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_amproc.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* misc strategy support routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* StrategyNumberIsValid
|
||||
* StrategyNumberIsInBounds
|
||||
* StrategyMapIsValid
|
||||
* StrategyTransformMapIsValid
|
||||
* IndexStrategyIsValid
|
||||
*
|
||||
* ... are now macros in istrat.h -cim 4/27/91
|
||||
*/
|
||||
|
||||
/*
|
||||
* StrategyMapGetScanKeyEntry --
|
||||
* Returns a scan key entry of a index strategy mapping member.
|
||||
*
|
||||
* Note:
|
||||
* Assumes that the index strategy mapping is valid.
|
||||
* Assumes that the index strategy number is valid.
|
||||
* Bounds checking should be done outside this routine.
|
||||
*/
|
||||
ScanKey
|
||||
StrategyMapGetScanKeyEntry(StrategyMap map,
|
||||
StrategyNumber strategyNumber)
|
||||
{
|
||||
Assert(StrategyMapIsValid(map));
|
||||
Assert(StrategyNumberIsValid(strategyNumber));
|
||||
return (&map->entry[strategyNumber - 1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* IndexStrategyGetStrategyMap --
|
||||
* Returns an index strategy mapping of an index strategy.
|
||||
*
|
||||
* Note:
|
||||
* Assumes that the index strategy is valid.
|
||||
* Assumes that the number of index strategies is valid.
|
||||
* Bounds checking should be done outside this routine.
|
||||
*/
|
||||
StrategyMap
|
||||
IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
|
||||
StrategyNumber maxStrategyNum,
|
||||
AttrNumber attrNum)
|
||||
{
|
||||
Assert(IndexStrategyIsValid(indexStrategy));
|
||||
Assert(StrategyNumberIsValid(maxStrategyNum));
|
||||
Assert(AttributeNumberIsValid(attrNum));
|
||||
|
||||
maxStrategyNum = AMStrategies(maxStrategyNum); /* XXX */
|
||||
return
|
||||
&indexStrategy->strategyMapData[maxStrategyNum * (attrNum - 1)];
|
||||
}
|
||||
|
||||
/*
|
||||
* AttributeNumberGetIndexStrategySize --
|
||||
* Computes the size of an index strategy.
|
||||
*/
|
||||
Size
|
||||
AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber,
|
||||
StrategyNumber maxStrategyNumber)
|
||||
{
|
||||
maxStrategyNumber = AMStrategies(maxStrategyNumber); /* XXX */
|
||||
return
|
||||
maxAttributeNumber * maxStrategyNumber * sizeof (ScanKeyData);
|
||||
}
|
||||
|
||||
/*
|
||||
* StrategyTransformMapIsValid is now a macro in istrat.h -cim 4/27/91
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* StrategyOperatorIsValid
|
||||
* ----------------
|
||||
*/
|
||||
bool
|
||||
StrategyOperatorIsValid(StrategyOperator operator,
|
||||
StrategyNumber maxStrategy)
|
||||
{
|
||||
return (bool)
|
||||
(PointerIsValid(operator) &&
|
||||
StrategyNumberIsInBounds(operator->strategy, maxStrategy) &&
|
||||
!(operator->flags & ~(SK_NEGATE | SK_COMMUTE)));
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* StrategyTermIsValid
|
||||
* ----------------
|
||||
*/
|
||||
bool
|
||||
StrategyTermIsValid(StrategyTerm term,
|
||||
StrategyNumber maxStrategy)
|
||||
{
|
||||
Index index;
|
||||
|
||||
if (! PointerIsValid(term) || term->degree == 0)
|
||||
return false;
|
||||
|
||||
for (index = 0; index < term->degree; index += 1) {
|
||||
if (! StrategyOperatorIsValid(&term->operatorData[index],
|
||||
maxStrategy)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* StrategyExpressionIsValid
|
||||
* ----------------
|
||||
*/
|
||||
bool
|
||||
StrategyExpressionIsValid(StrategyExpression expression,
|
||||
StrategyNumber maxStrategy)
|
||||
{
|
||||
StrategyTerm *termP;
|
||||
|
||||
if (!PointerIsValid(expression))
|
||||
return true;
|
||||
|
||||
if (!StrategyTermIsValid(expression->term[0], maxStrategy))
|
||||
return false;
|
||||
|
||||
termP = &expression->term[1];
|
||||
while (StrategyTermIsValid(*termP, maxStrategy))
|
||||
termP += 1;
|
||||
|
||||
return (bool)
|
||||
(! PointerIsValid(*termP));
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* StrategyEvaluationIsValid
|
||||
* ----------------
|
||||
*/
|
||||
bool
|
||||
StrategyEvaluationIsValid(StrategyEvaluation evaluation)
|
||||
{
|
||||
Index index;
|
||||
|
||||
if (! PointerIsValid(evaluation) ||
|
||||
! StrategyNumberIsValid(evaluation->maxStrategy) ||
|
||||
! StrategyTransformMapIsValid(evaluation->negateTransform) ||
|
||||
! StrategyTransformMapIsValid(evaluation->commuteTransform) ||
|
||||
! StrategyTransformMapIsValid(evaluation->negateCommuteTransform)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (index = 0; index < evaluation->maxStrategy; index += 1) {
|
||||
if (! StrategyExpressionIsValid(evaluation->expression[index],
|
||||
evaluation->maxStrategy)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* StrategyTermEvaluate
|
||||
* ----------------
|
||||
*/
|
||||
static bool
|
||||
StrategyTermEvaluate(StrategyTerm term,
|
||||
StrategyMap map,
|
||||
Datum left,
|
||||
Datum right)
|
||||
{
|
||||
Index index;
|
||||
long tmpres;
|
||||
bool result;
|
||||
StrategyOperator operator;
|
||||
ScanKey entry;
|
||||
|
||||
for (index = 0, operator = &term->operatorData[0];
|
||||
index < term->degree; index += 1, operator += 1) {
|
||||
|
||||
entry = &map->entry[operator->strategy - 1];
|
||||
|
||||
Assert(RegProcedureIsValid(entry->sk_procedure));
|
||||
|
||||
switch (operator->flags ^ entry->sk_flags) {
|
||||
case 0x0:
|
||||
tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
|
||||
left, right);
|
||||
break;
|
||||
|
||||
case SK_NEGATE:
|
||||
tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure,
|
||||
left, right);
|
||||
break;
|
||||
|
||||
case SK_COMMUTE:
|
||||
tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
|
||||
right, left);
|
||||
break;
|
||||
|
||||
case SK_NEGATE | SK_COMMUTE:
|
||||
tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure,
|
||||
right, left);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(FATAL, "StrategyTermEvaluate: impossible case %d",
|
||||
operator->flags ^ entry->sk_flags);
|
||||
}
|
||||
|
||||
result = (bool) tmpres;
|
||||
if (!result)
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------
|
||||
* RelationGetStrategy
|
||||
* ----------------
|
||||
*/
|
||||
StrategyNumber
|
||||
RelationGetStrategy(Relation relation,
|
||||
AttrNumber attributeNumber,
|
||||
StrategyEvaluation evaluation,
|
||||
RegProcedure procedure)
|
||||
{
|
||||
StrategyNumber strategy;
|
||||
StrategyMap strategyMap;
|
||||
ScanKey entry;
|
||||
Index index;
|
||||
int numattrs;
|
||||
|
||||
Assert(RelationIsValid(relation));
|
||||
numattrs = RelationGetNumberOfAttributes(relation);
|
||||
|
||||
Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
|
||||
Assert(AttributeNumberIsValid(attributeNumber));
|
||||
Assert( (attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
|
||||
|
||||
Assert(StrategyEvaluationIsValid(evaluation));
|
||||
Assert(RegProcedureIsValid(procedure));
|
||||
|
||||
strategyMap =
|
||||
IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||
evaluation->maxStrategy,
|
||||
attributeNumber);
|
||||
|
||||
/* get a strategy number for the procedure ignoring flags for now */
|
||||
for (index = 0; index < evaluation->maxStrategy; index += 1) {
|
||||
if (strategyMap->entry[index].sk_procedure == procedure) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == evaluation->maxStrategy)
|
||||
return InvalidStrategy;
|
||||
|
||||
strategy = 1 + index;
|
||||
entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
|
||||
|
||||
Assert(!(entry->sk_flags & ~(SK_NEGATE | SK_COMMUTE)));
|
||||
|
||||
switch (entry->sk_flags & (SK_NEGATE | SK_COMMUTE)) {
|
||||
case 0x0:
|
||||
return strategy;
|
||||
|
||||
case SK_NEGATE:
|
||||
strategy = evaluation->negateTransform->strategy[strategy - 1];
|
||||
break;
|
||||
|
||||
case SK_COMMUTE:
|
||||
strategy = evaluation->commuteTransform->strategy[strategy - 1];
|
||||
break;
|
||||
|
||||
case SK_NEGATE | SK_COMMUTE:
|
||||
strategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(FATAL, "RelationGetStrategy: impossible case %d", entry->sk_flags);
|
||||
}
|
||||
|
||||
|
||||
if (! StrategyNumberIsInBounds(strategy, evaluation->maxStrategy)) {
|
||||
if (! StrategyNumberIsValid(strategy)) {
|
||||
elog(WARN, "RelationGetStrategy: corrupted evaluation");
|
||||
}
|
||||
}
|
||||
|
||||
return strategy;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* RelationInvokeStrategy
|
||||
* ----------------
|
||||
*/
|
||||
bool /* XXX someday, this may return Datum */
|
||||
RelationInvokeStrategy(Relation relation,
|
||||
StrategyEvaluation evaluation,
|
||||
AttrNumber attributeNumber,
|
||||
StrategyNumber strategy,
|
||||
Datum left,
|
||||
Datum right)
|
||||
{
|
||||
StrategyNumber newStrategy;
|
||||
StrategyMap strategyMap;
|
||||
ScanKey entry;
|
||||
StrategyTermData termData;
|
||||
int numattrs;
|
||||
|
||||
Assert(RelationIsValid(relation));
|
||||
Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
|
||||
numattrs = RelationGetNumberOfAttributes(relation);
|
||||
|
||||
Assert(StrategyEvaluationIsValid(evaluation));
|
||||
Assert(AttributeNumberIsValid(attributeNumber));
|
||||
Assert( (attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
|
||||
|
||||
Assert(StrategyNumberIsInBounds(strategy, evaluation->maxStrategy));
|
||||
|
||||
termData.degree = 1;
|
||||
|
||||
strategyMap =
|
||||
IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||
evaluation->maxStrategy,
|
||||
attributeNumber);
|
||||
|
||||
entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
|
||||
|
||||
if (RegProcedureIsValid(entry->sk_procedure)) {
|
||||
termData.operatorData[0].strategy = strategy;
|
||||
termData.operatorData[0].flags = 0x0;
|
||||
|
||||
return
|
||||
StrategyTermEvaluate(&termData, strategyMap, left, right);
|
||||
}
|
||||
|
||||
|
||||
newStrategy = evaluation->negateTransform->strategy[strategy - 1];
|
||||
if (newStrategy != strategy && StrategyNumberIsValid(newStrategy)) {
|
||||
|
||||
entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
|
||||
|
||||
if (RegProcedureIsValid(entry->sk_procedure)) {
|
||||
termData.operatorData[0].strategy = newStrategy;
|
||||
termData.operatorData[0].flags = SK_NEGATE;
|
||||
|
||||
return
|
||||
StrategyTermEvaluate(&termData, strategyMap, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
newStrategy = evaluation->commuteTransform->strategy[strategy - 1];
|
||||
if (newStrategy != strategy && StrategyNumberIsValid(newStrategy)) {
|
||||
|
||||
entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
|
||||
|
||||
if (RegProcedureIsValid(entry->sk_procedure)) {
|
||||
termData.operatorData[0].strategy = newStrategy;
|
||||
termData.operatorData[0].flags = SK_COMMUTE;
|
||||
|
||||
return
|
||||
StrategyTermEvaluate(&termData, strategyMap, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
newStrategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
|
||||
if (newStrategy != strategy && StrategyNumberIsValid(newStrategy)) {
|
||||
|
||||
entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
|
||||
|
||||
if (RegProcedureIsValid(entry->sk_procedure)) {
|
||||
termData.operatorData[0].strategy = newStrategy;
|
||||
termData.operatorData[0].flags = SK_NEGATE | SK_COMMUTE;
|
||||
|
||||
return
|
||||
StrategyTermEvaluate(&termData, strategyMap, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
if (PointerIsValid(evaluation->expression[strategy - 1])) {
|
||||
StrategyTerm *termP;
|
||||
|
||||
termP = &evaluation->expression[strategy - 1]->term[0];
|
||||
while (PointerIsValid(*termP)) {
|
||||
Index index;
|
||||
|
||||
for (index = 0; index < (*termP)->degree; index += 1) {
|
||||
entry = StrategyMapGetScanKeyEntry(strategyMap,
|
||||
(*termP)->operatorData[index].strategy);
|
||||
|
||||
if (! RegProcedureIsValid(entry->sk_procedure)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == (*termP)->degree) {
|
||||
return
|
||||
StrategyTermEvaluate(*termP, strategyMap, left, right);
|
||||
}
|
||||
|
||||
termP += 1;
|
||||
}
|
||||
}
|
||||
|
||||
elog(WARN, "RelationInvokeStrategy: cannot evaluate strategy %d",
|
||||
strategy);
|
||||
|
||||
/* not reached, just to make compiler happy */
|
||||
return FALSE;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* OperatorRelationFillScanKeyEntry
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
OperatorRelationFillScanKeyEntry(Relation operatorRelation,
|
||||
Oid operatorObjectId,
|
||||
ScanKey entry)
|
||||
{
|
||||
HeapScanDesc scan;
|
||||
ScanKeyData scanKeyData;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&scanKeyData, 0,
|
||||
ObjectIdAttributeNumber,
|
||||
ObjectIdEqualRegProcedure,
|
||||
ObjectIdGetDatum(operatorObjectId));
|
||||
|
||||
scan = heap_beginscan(operatorRelation, false, NowTimeQual,
|
||||
1, &scanKeyData);
|
||||
|
||||
tuple = heap_getnext(scan, false, (Buffer *)NULL);
|
||||
if (! HeapTupleIsValid(tuple)) {
|
||||
elog(WARN, "OperatorObjectIdFillScanKeyEntry: unknown operator %lu",
|
||||
(uint32) operatorObjectId);
|
||||
}
|
||||
|
||||
entry->sk_flags = 0;
|
||||
entry->sk_procedure =
|
||||
((OperatorTupleForm) GETSTRUCT(tuple))->oprcode;
|
||||
fmgr_info(entry->sk_procedure, &entry->sk_func, &entry->sk_nargs);
|
||||
|
||||
if (! RegProcedureIsValid(entry->sk_procedure)) {
|
||||
elog(WARN,
|
||||
"OperatorObjectIdFillScanKeyEntry: no procedure for operator %lu",
|
||||
(uint32) operatorObjectId);
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IndexSupportInitialize --
|
||||
* Initializes an index strategy and associated support procedures.
|
||||
*/
|
||||
void
|
||||
IndexSupportInitialize(IndexStrategy indexStrategy,
|
||||
RegProcedure *indexSupport,
|
||||
Oid indexObjectId,
|
||||
Oid accessMethodObjectId,
|
||||
StrategyNumber maxStrategyNumber,
|
||||
StrategyNumber maxSupportNumber,
|
||||
AttrNumber maxAttributeNumber)
|
||||
{
|
||||
Relation relation;
|
||||
Relation operatorRelation;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
ScanKeyData entry[2];
|
||||
StrategyMap map;
|
||||
AttrNumber attributeNumber;
|
||||
int attributeIndex;
|
||||
Oid operatorClassObjectId[ MaxIndexAttributeNumber ];
|
||||
|
||||
maxStrategyNumber = AMStrategies(maxStrategyNumber);
|
||||
|
||||
ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
|
||||
ObjectIdEqualRegProcedure,
|
||||
ObjectIdGetDatum(indexObjectId));
|
||||
|
||||
relation = heap_openr(IndexRelationName);
|
||||
scan = heap_beginscan(relation, false, NowTimeQual, 1, entry);
|
||||
tuple = heap_getnext(scan, 0, (Buffer *)NULL);
|
||||
if (! HeapTupleIsValid(tuple))
|
||||
elog(WARN, "IndexSupportInitialize: corrupted catalogs");
|
||||
|
||||
/*
|
||||
* XXX note that the following assumes the INDEX tuple is well formed and
|
||||
* that the key[] and class[] are 0 terminated.
|
||||
*/
|
||||
for (attributeIndex=0; attributeIndex<maxAttributeNumber; attributeIndex++)
|
||||
{
|
||||
IndexTupleForm iform;
|
||||
|
||||
iform = (IndexTupleForm) GETSTRUCT(tuple);
|
||||
|
||||
if (!OidIsValid(iform->indkey[attributeIndex])) {
|
||||
if (attributeIndex == 0) {
|
||||
elog(WARN, "IndexSupportInitialize: no pg_index tuple");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
operatorClassObjectId[attributeIndex]
|
||||
= iform->indclass[attributeIndex];
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
heap_close(relation);
|
||||
|
||||
/* if support routines exist for this access method, load them */
|
||||
if (maxSupportNumber > 0) {
|
||||
|
||||
ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_amproc_amid,
|
||||
ObjectIdEqualRegProcedure,
|
||||
ObjectIdGetDatum(accessMethodObjectId));
|
||||
|
||||
ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
|
||||
ObjectIdEqualRegProcedure, 0);
|
||||
|
||||
/* relation = heap_openr(Name_pg_amproc); */
|
||||
relation = heap_openr(AccessMethodProcedureRelationName);
|
||||
|
||||
|
||||
for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
|
||||
attributeNumber--) {
|
||||
|
||||
int16 support;
|
||||
Form_pg_amproc form;
|
||||
RegProcedure *loc;
|
||||
|
||||
loc = &indexSupport[((attributeNumber - 1) * maxSupportNumber)];
|
||||
|
||||
for (support = maxSupportNumber; --support >= 0; ) {
|
||||
loc[support] = InvalidOid;
|
||||
}
|
||||
|
||||
entry[1].sk_argument =
|
||||
ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
|
||||
|
||||
scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
|
||||
|
||||
while (tuple = heap_getnext(scan, 0, (Buffer *)NULL),
|
||||
HeapTupleIsValid(tuple)) {
|
||||
|
||||
form = (Form_pg_amproc) GETSTRUCT(tuple);
|
||||
loc[(form->amprocnum - 1)] = form->amproc;
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
}
|
||||
heap_close(relation);
|
||||
}
|
||||
|
||||
ScanKeyEntryInitialize(&entry[0], 0,
|
||||
Anum_pg_amop_amopid,
|
||||
ObjectIdEqualRegProcedure,
|
||||
ObjectIdGetDatum(accessMethodObjectId));
|
||||
|
||||
ScanKeyEntryInitialize(&entry[1], 0,
|
||||
Anum_pg_amop_amopclaid,
|
||||
ObjectIdEqualRegProcedure, 0);
|
||||
|
||||
relation = heap_openr(AccessMethodOperatorRelationName);
|
||||
operatorRelation = heap_openr(OperatorRelationName);
|
||||
|
||||
for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
|
||||
attributeNumber--) {
|
||||
|
||||
StrategyNumber strategy;
|
||||
|
||||
entry[1].sk_argument =
|
||||
ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
|
||||
|
||||
map = IndexStrategyGetStrategyMap(indexStrategy,
|
||||
maxStrategyNumber,
|
||||
attributeNumber);
|
||||
|
||||
for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
|
||||
ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));
|
||||
|
||||
scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
|
||||
|
||||
while (tuple = heap_getnext(scan, 0, (Buffer *)NULL),
|
||||
HeapTupleIsValid(tuple)) {
|
||||
Form_pg_amop form;
|
||||
|
||||
form = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
|
||||
OperatorRelationFillScanKeyEntry(operatorRelation,
|
||||
form->amopopr,
|
||||
StrategyMapGetScanKeyEntry(map, form->amopstrategy));
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
}
|
||||
|
||||
heap_close(operatorRelation);
|
||||
heap_close(relation);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* IndexStrategyDisplay
|
||||
* ----------------
|
||||
*/
|
||||
#ifdef ISTRATDEBUG
|
||||
int
|
||||
IndexStrategyDisplay(IndexStrategy indexStrategy,
|
||||
StrategyNumber numberOfStrategies,
|
||||
int numberOfAttributes)
|
||||
{
|
||||
StrategyMap strategyMap;
|
||||
AttrNumber attributeNumber;
|
||||
StrategyNumber strategyNumber;
|
||||
|
||||
for (attributeNumber = 1; attributeNumber <= numberOfAttributes;
|
||||
attributeNumber += 1) {
|
||||
|
||||
strategyMap = IndexStrategyGetStrategyMap(indexStrategy,
|
||||
numberOfStrategies,
|
||||
attributeNumber);
|
||||
|
||||
for (strategyNumber = 1;
|
||||
strategyNumber <= AMStrategies(numberOfStrategies);
|
||||
strategyNumber += 1) {
|
||||
|
||||
printf(":att %d\t:str %d\t:opr 0x%x(%d)\n",
|
||||
attributeNumber, strategyNumber,
|
||||
strategyMap->entry[strategyNumber - 1].sk_procedure,
|
||||
strategyMap->entry[strategyNumber - 1].sk_procedure);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(ISTRATDEBUG) */
|
||||
|
||||
|
Reference in New Issue
Block a user