A bunch of changes aimed at reducing backend startup time...

Improve 'pg_internal.init' relcache entry preload mechanism so that it is
safe to use for all system catalogs, and arrange to preload a realistic
set of system-catalog entries instead of only the three nailed-in-cache
indexes that were formerly loaded this way.  Fix mechanism for deleting
out-of-date pg_internal.init files: this must be synchronized with transaction
commit, not just done at random times within transactions.  Drive it off
relcache invalidation mechanism so that no special-case tests are needed.

Cache additional information in relcache entries for indexes (their pg_index
tuples and index-operator OIDs) to eliminate repeated lookups.  Also cache
index opclass info at the per-opclass level to avoid repeated lookups during
relcache load.

Generalize 'systable scan' utilities originally developed by Hiroshi,
move them into genam.c, use in a number of places where there was formerly
ugly code for choosing either heap or index scan.  In particular this allows
simplification of the logic that prevents infinite recursion between syscache
and relcache during startup: we can easily switch to heapscans in relcache.c
when and where needed to avoid recursion, so IndexScanOK becomes simpler and
does not need any expensive initialization.

Eliminate useless opening of a heapscan data structure while doing an indexscan
(this saves an mdnblocks call and thus at least one kernel call).
This commit is contained in:
Tom Lane 2002-02-19 20:11:20 +00:00
parent 8e2998d8a6
commit 7863404417
33 changed files with 1997 additions and 2220 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.30 2001/10/28 06:25:41 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.31 2002/02/19 20:11:10 tgl Exp $
*
* NOTES
* many of the old access method routines have been turned into
@ -44,12 +44,14 @@
* next item pointer using the flags.
* ----------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "miscadmin.h"
#include "pgstat.h"
/* ----------------------------------------------------------------
* general access method routines
*
@ -242,3 +244,156 @@ IndexScanRestorePosition(IndexScanDesc scan)
}
#endif
/* ----------------------------------------------------------------
* heap-or-index-scan access to system catalogs
*
* These functions support system catalog accesses that normally use
* an index but need to be capable of being switched to heap scans
* if the system indexes are unavailable. The interface is
* as easy to use as a heap scan, and hides all the extra cruft of
* the present indexscan API.
*
* The specified scan keys must be compatible with the named index.
* Generally this means that they must constrain either all columns
* of the index, or the first K columns of an N-column index.
*
* These routines would work fine with non-system tables, actually,
* but they're only useful when there is a known index to use with
* the given scan keys, so in practice they're only good for
* predetermined types of scans of system catalogs.
* ----------------------------------------------------------------
*/
/*
* systable_beginscan --- set up for heap-or-index scan
*
* rel: catalog to scan, already opened and suitably locked
* indexRelname: name of index to conditionally use
* indexOK: if false, forces a heap scan (see notes below)
* snapshot: time qual to use (usually should be SnapshotNow)
* nkeys, key: scan keys
*
* The attribute numbers in the scan key should be set for the heap case.
* If we choose to index, we reset them to 1..n to reference the index
* columns. Note this means there must be one scankey qualification per
* index column! This is checked by the Asserts in the normal, index-using
* case, but won't be checked if the heapscan path is taken.
*
* The routine checks the normal cases for whether an indexscan is safe,
* but caller can make additional checks and pass indexOK=false if needed.
* In standard case indexOK can simply be constant TRUE.
*/
SysScanDesc
systable_beginscan(Relation rel,
const char *indexRelname,
bool indexOK,
Snapshot snapshot,
unsigned nkeys, ScanKey key)
{
SysScanDesc sysscan;
sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
sysscan->heap_rel = rel;
sysscan->snapshot = snapshot;
sysscan->tuple.t_datamcxt = NULL;
sysscan->tuple.t_data = NULL;
sysscan->buffer = InvalidBuffer;
if (indexOK &&
rel->rd_rel->relhasindex &&
!IsIgnoringSystemIndexes())
{
Relation irel;
unsigned i;
sysscan->irel = irel = index_openr(indexRelname);
/*
* Change attribute numbers to be index column numbers.
*
* This code could be generalized to search for the index key numbers
* to substitute, but for now there's no need.
*/
for (i = 0; i < nkeys; i++)
{
Assert(key[i].sk_attno == irel->rd_index->indkey[i]);
key[i].sk_attno = i+1;
}
sysscan->iscan = index_beginscan(irel, false, nkeys, key);
sysscan->scan = NULL;
}
else
{
sysscan->irel = (Relation) NULL;
sysscan->scan = heap_beginscan(rel, false, snapshot, nkeys, key);
sysscan->iscan = NULL;
}
return sysscan;
}
/*
* systable_getnext --- get next tuple in a heap-or-index scan
*
* Returns NULL if no more tuples available.
*
* Note that returned tuple is a reference to data in a disk buffer;
* it must not be modified, and should be presumed inaccessible after
* next getnext() or endscan() call.
*/
HeapTuple
systable_getnext(SysScanDesc sysscan)
{
HeapTuple htup = (HeapTuple) NULL;
if (sysscan->irel)
{
RetrieveIndexResult indexRes;
if (BufferIsValid(sysscan->buffer))
{
ReleaseBuffer(sysscan->buffer);
sysscan->buffer = InvalidBuffer;
}
while ((indexRes = index_getnext(sysscan->iscan, ForwardScanDirection)) != NULL)
{
sysscan->tuple.t_self = indexRes->heap_iptr;
pfree(indexRes);
heap_fetch(sysscan->heap_rel, sysscan->snapshot,
&sysscan->tuple, &sysscan->buffer,
sysscan->iscan);
if (sysscan->tuple.t_data != NULL)
{
htup = &sysscan->tuple;
break;
}
}
}
else
htup = heap_getnext(sysscan->scan, 0);
return htup;
}
/*
* systable_endscan --- close scan, release resources
*
* Note that it's still up to the caller to close the heap relation.
*/
void
systable_endscan(SysScanDesc sysscan)
{
if (sysscan->irel)
{
if (BufferIsValid(sysscan->buffer))
ReleaseBuffer(sysscan->buffer);
index_endscan(sysscan->iscan);
index_close(sysscan->irel);
}
else
heap_endscan(sysscan->scan);
pfree(sysscan);
}

View File

@ -9,29 +9,19 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.56 2001/11/05 17:46:24 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.57 2002/02/19 20:11:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "access/istrat.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_index.h"
#include "catalog/pg_operator.h"
#include "miscadmin.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
#ifdef USE_ASSERT_CHECKING
static bool StrategyEvaluationIsValid(StrategyEvaluation evaluation);
static bool StrategyExpressionIsValid(StrategyExpression expression,
StrategyNumber maxStrategy);
static ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
StrategyNumber strategyNumber);
static bool StrategyOperatorIsValid(StrategyOperator operator,
StrategyNumber maxStrategy);
static bool StrategyTermIsValid(StrategyTerm term,
@ -63,7 +53,7 @@ static bool StrategyTermIsValid(StrategyTerm term,
* Assumes that the index strategy number is valid.
* Bounds checking should be done outside this routine.
*/
static ScanKey
ScanKey
StrategyMapGetScanKeyEntry(StrategyMap map,
StrategyNumber strategyNumber)
{
@ -453,161 +443,6 @@ RelationInvokeStrategy(Relation relation,
}
#endif
/* ----------------
* FillScanKeyEntry
*
* Initialize a ScanKey entry for the given operator OID.
* ----------------
*/
static void
FillScanKeyEntry(Oid operatorObjectId, ScanKey entry)
{
HeapTuple tuple;
tuple = SearchSysCache(OPEROID,
ObjectIdGetDatum(operatorObjectId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "FillScanKeyEntry: unknown operator %u",
operatorObjectId);
MemSet(entry, 0, sizeof(*entry));
entry->sk_flags = 0;
entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
ReleaseSysCache(tuple);
if (!RegProcedureIsValid(entry->sk_procedure))
elog(ERROR, "FillScanKeyEntry: no procedure for operator %u",
operatorObjectId);
/*
* Mark entry->sk_func invalid, until and unless someone sets it up.
*/
entry->sk_func.fn_oid = InvalidOid;
}
/*
* IndexSupportInitialize
* Initializes an index strategy and associated support procedures.
*
* Data is returned into *indexStrategy, *indexSupport, and *isUnique,
* all of which are objects allocated by the caller.
*
* The primary input keys are indexObjectId and accessMethodObjectId.
* The caller also passes maxStrategyNumber, maxSupportNumber, and
* maxAttributeNumber, since these indicate the size of the indexStrategy
* and indexSupport arrays it has allocated --- but in practice these
* numbers must always match those obtainable from the system catalog
* entries for the index and access method.
*/
void
IndexSupportInitialize(IndexStrategy indexStrategy,
RegProcedure *indexSupport,
bool *isUnique,
Oid indexObjectId,
Oid accessMethodObjectId,
StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber)
{
HeapTuple tuple;
Form_pg_index iform;
int attIndex;
Oid operatorClassObjectId[INDEX_MAX_KEYS];
maxStrategyNumber = AMStrategies(maxStrategyNumber);
tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexObjectId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "IndexSupportInitialize: no pg_index entry for index %u",
indexObjectId);
iform = (Form_pg_index) GETSTRUCT(tuple);
*isUnique = iform->indisunique;
/*
* XXX note that the following assumes the INDEX tuple is well formed
* and that the *key and *class are 0 terminated.
*/
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
{
if (iform->indkey[attIndex] == InvalidAttrNumber ||
!OidIsValid(iform->indclass[attIndex]))
elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
operatorClassObjectId[attIndex] = iform->indclass[attIndex];
}
ReleaseSysCache(tuple);
/* if support routines exist for this access method, load them */
if (maxSupportNumber > 0)
{
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
{
Oid opclass = operatorClassObjectId[attIndex];
RegProcedure *loc;
StrategyNumber support;
loc = &indexSupport[attIndex * maxSupportNumber];
for (support = 0; support < maxSupportNumber; ++support)
{
tuple = SearchSysCache(AMPROCNUM,
ObjectIdGetDatum(opclass),
Int16GetDatum(support + 1),
0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_amproc amprocform;
amprocform = (Form_pg_amproc) GETSTRUCT(tuple);
loc[support] = amprocform->amproc;
ReleaseSysCache(tuple);
}
else
loc[support] = InvalidOid;
}
}
}
/* Now load the strategy information for the index operators */
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
{
Oid opclass = operatorClassObjectId[attIndex];
StrategyMap map;
StrategyNumber strategy;
map = IndexStrategyGetStrategyMap(indexStrategy,
maxStrategyNumber,
attIndex + 1);
for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
{
ScanKey mapentry = StrategyMapGetScanKeyEntry(map, strategy);
tuple = SearchSysCache(AMOPSTRATEGY,
ObjectIdGetDatum(opclass),
Int16GetDatum(strategy),
0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_amop amopform;
amopform = (Form_pg_amop) GETSTRUCT(tuple);
FillScanKeyEntry(amopform->amopopr, mapentry);
ReleaseSysCache(tuple);
}
else
ScanKeyEntrySetIllegal(mapentry);
}
}
}
/* ----------------
* IndexStrategyDisplay
* ----------------

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.181 2001/11/12 00:00:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.182 2002/02/19 20:11:11 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -912,32 +912,21 @@ RelationRemoveInheritance(Relation relation)
static void
RelationRemoveIndexes(Relation relation)
{
Relation indexRelation;
HeapTuple tuple;
HeapScanDesc scan;
ScanKeyData entry;
List *indexoidlist,
*indexoidscan;
indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
indexoidlist = RelationGetIndexList(relation);
ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid,
F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation)));
scan = heap_beginscan(indexRelation,
false,
SnapshotNow,
1,
&entry);
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
foreach(indexoidscan, indexoidlist)
{
index_drop(((Form_pg_index) GETSTRUCT(tuple))->indexrelid);
Oid indexoid = lfirsti(indexoidscan);
index_drop(indexoid);
/* advance cmd counter to make catalog changes visible */
CommandCounterIncrement();
}
heap_endscan(scan);
heap_close(indexRelation, RowExclusiveLock);
freeList(indexoidlist);
}
/* --------------------------------
@ -984,17 +973,21 @@ RelationTruncateIndexes(Oid heapId)
{
Relation indexRelation;
ScanKeyData entry;
HeapScanDesc scan;
SysScanDesc scan;
HeapTuple indexTuple;
/* Scan pg_index to find indexes on specified heap */
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
ScanKeyEntryInitialize(&entry, 0,
Anum_pg_index_indrelid,
F_OIDEQ,
ObjectIdGetDatum(heapId));
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
scan = systable_beginscan(indexRelation, IndexIndrelidIndex, true,
SnapshotNow, 1, &entry);
while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
while (HeapTupleIsValid(indexTuple = systable_getnext(scan)))
{
Form_pg_index indexform = (Form_pg_index) GETSTRUCT(indexTuple);
Oid indexId;
IndexInfo *indexInfo;
Relation heapRelation,
@ -1003,8 +996,8 @@ RelationTruncateIndexes(Oid heapId)
/*
* For each index, fetch info needed for index_build
*/
indexId = ((Form_pg_index) GETSTRUCT(indexTuple))->indexrelid;
indexInfo = BuildIndexInfo(indexTuple);
indexId = indexform->indexrelid;
indexInfo = BuildIndexInfo(indexform);
/*
* We have to re-open the heap rel each time through this loop
@ -1041,7 +1034,7 @@ RelationTruncateIndexes(Oid heapId)
}
/* Complete the scan and close pg_index */
heap_endscan(scan);
systable_endscan(scan);
heap_close(indexRelation, AccessShareLock);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.171 2002/01/06 00:37:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.172 2002/02/19 20:11:11 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -333,67 +333,6 @@ ConstructTupleDescriptor(Relation heapRelation,
return indexTupDesc;
}
/* ----------------------------------------------------------------
* AccessMethodObjectIdGetForm
* Returns an access method tuple given its object identifier,
* or NULL if no such AM tuple can be found.
*
* Scanning is done using CurrentMemoryContext as working storage,
* but the returned tuple will be allocated in resultCxt (which is
* typically CacheMemoryContext).
*
* There was a note here about adding indexing, but I don't see a need
* for it. There are so few tuples in pg_am that an indexscan would
* surely be slower.
* ----------------------------------------------------------------
*/
Form_pg_am
AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
MemoryContext resultCxt)
{
Relation pg_am_desc;
HeapScanDesc pg_am_scan;
HeapTuple pg_am_tuple;
ScanKeyData key;
Form_pg_am aform;
/*
* form a scan key for the pg_am relation
*/
ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
F_OIDEQ,
ObjectIdGetDatum(accessMethodObjectId));
/*
* fetch the desired access method tuple
*/
pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
pg_am_tuple = heap_getnext(pg_am_scan, 0);
/*
* return NULL if not found
*/
if (!HeapTupleIsValid(pg_am_tuple))
{
heap_endscan(pg_am_scan);
heap_close(pg_am_desc, AccessShareLock);
return NULL;
}
/*
* if found AM tuple, then copy it into resultCxt and return the copy
*/
aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
heap_endscan(pg_am_scan);
heap_close(pg_am_desc, AccessShareLock);
return aform;
}
/* ----------------------------------------------------------------
* ConstructIndexReldesc
* ----------------------------------------------------------------
@ -401,12 +340,6 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
static void
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
{
/*
* Fill in a copy of relevant pg_am entry
*/
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
CacheMemoryContext);
/*
* Set up some additional fields of the index' pg_class entry. In
* particular, initialize knowledge of whether the index is shared.
@ -953,9 +886,8 @@ index_drop(Oid indexId)
* ----------------
*/
IndexInfo *
BuildIndexInfo(HeapTuple indexTuple)
BuildIndexInfo(Form_pg_index indexStruct)
{
Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
IndexInfo *ii = makeNode(IndexInfo);
int i;
int numKeys;
@ -1337,9 +1269,6 @@ setNewRelfilenode(Relation relation)
}
/* schedule unlinking old relfilenode */
smgrunlink(DEFAULT_SMGR, relation);
/* cleanup pg_internal.init if necessary */
if (relation->rd_isnailed)
unlink(RELCACHE_INIT_FILENAME);
/* create another storage file. Is it a little ugly ? */
memcpy((char *) &workrel, relation, sizeof(RelationData));
workrel.rd_node.relNode = newrelfilenode;
@ -1863,11 +1792,7 @@ bool
reindex_index(Oid indexId, bool force, bool inplace)
{
Relation iRel,
indexRelation,
heapRelation;
ScanKeyData entry;
HeapScanDesc scan;
HeapTuple indexTuple;
IndexInfo *indexInfo;
Oid heapId;
bool old;
@ -1899,23 +1824,10 @@ reindex_index(Oid indexId, bool force, bool inplace)
old = SetReindexProcessing(true);
/* Scan pg_index to find the index's pg_index entry */
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
ObjectIdGetDatum(indexId));
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
indexTuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
/* Get OID of index's parent table */
heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
heapId = iRel->rd_index->indrelid;
/* Fetch info needed for index_build */
indexInfo = BuildIndexInfo(indexTuple);
/* Complete the scan and close pg_index */
heap_endscan(scan);
heap_close(indexRelation, AccessShareLock);
indexInfo = BuildIndexInfo(iRel->rd_index);
/* Open the parent heap relation */
heapRelation = heap_open(heapId, ExclusiveLock);

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.82 2001/08/21 16:36:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.83 2002/02/19 20:11:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -80,12 +80,6 @@ char *Name_pg_description_indices[Num_pg_description_indices] =
static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
Relation idesc,
ScanKey skey,
int16 num_keys);
/*
* Changes (appends) to catalogs can and do happen at various places
* throughout the code. We need a generic routine that will open all of
@ -151,18 +145,10 @@ CatalogIndexInsert(Relation *idescs,
for (i = 0; i < nIndices; i++)
{
HeapTuple index_tup;
IndexInfo *indexInfo;
InsertIndexResult indexRes;
index_tup = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(idescs[i]->rd_id),
0, 0, 0);
if (!HeapTupleIsValid(index_tup))
elog(ERROR, "CatalogIndexInsert: index %u not found",
idescs[i]->rd_id);
indexInfo = BuildIndexInfo(index_tup);
ReleaseSysCache(index_tup);
indexInfo = BuildIndexInfo(idescs[i]->rd_index);
FormIndexDatum(indexInfo,
heapTuple,
@ -178,127 +164,3 @@ CatalogIndexInsert(Relation *idescs,
pfree(indexInfo);
}
}
/*
* CatalogIndexFetchTuple() -- Get a tuple that satisfies a scan key
* from a catalog relation.
*
* Since the index may contain pointers to dead tuples, we need to
* iterate until we find a tuple that's valid and satisfies the scan
* key.
*/
static HeapTuple
CatalogIndexFetchTuple(Relation heapRelation,
Relation idesc,
ScanKey skey,
int16 num_keys)
{
IndexScanDesc sd;
RetrieveIndexResult indexRes;
HeapTupleData tuple;
HeapTuple result = NULL;
Buffer buffer;
sd = index_beginscan(idesc, false, num_keys, skey);
tuple.t_datamcxt = CurrentMemoryContext;
tuple.t_data = NULL;
while ((indexRes = index_getnext(sd, ForwardScanDirection)))
{
tuple.t_self = indexRes->heap_iptr;
heap_fetch(heapRelation, SnapshotNow, &tuple, &buffer, sd);
pfree(indexRes);
if (tuple.t_data != NULL)
break;
}
if (tuple.t_data != NULL)
{
result = heap_copytuple(&tuple);
ReleaseBuffer(buffer);
}
index_endscan(sd);
return result;
}
/*---------------------------------------------------------------------
* Class-specific index lookups
*---------------------------------------------------------------------
*/
/*
* The remainder of the file is for individual index scan routines.
* These routines provide canned scanning code for certain widely-used
* indexes. Most indexes don't need one of these.
*/
HeapTuple
AttributeRelidNumIndexScan(Relation heapRelation,
Datum relid,
Datum attnum)
{
Relation idesc;
ScanKeyData skey[2];
HeapTuple tuple;
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_OIDEQ,
relid);
ScanKeyEntryInitialize(&skey[1],
(bits16) 0x0,
(AttrNumber) 2,
(RegProcedure) F_INT2EQ,
attnum);
idesc = index_openr(AttributeRelidNumIndex);
tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 2);
index_close(idesc);
return tuple;
}
HeapTuple
ClassNameIndexScan(Relation heapRelation, Datum relName)
{
Relation idesc;
ScanKeyData skey[1];
HeapTuple tuple;
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_NAMEEQ,
relName);
idesc = index_openr(ClassNameIndex);
tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 1);
index_close(idesc);
return tuple;
}
HeapTuple
ClassOidIndexScan(Relation heapRelation, Datum relId)
{
Relation idesc;
ScanKeyData skey[1];
HeapTuple tuple;
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_OIDEQ,
relId);
idesc = index_openr(ClassOidIndex);
tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 1);
index_close(idesc);
return tuple;
}

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.71 2002/01/06 00:37:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.72 2002/02/19 20:11:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -61,7 +61,6 @@ cluster(char *oldrelname, char *oldindexname)
OIDNewHeap;
Relation OldHeap,
OldIndex;
HeapTuple tuple;
bool istemp;
char NewHeapName[NAMEDATALEN];
char NewIndexName[NAMEDATALEN];
@ -90,16 +89,9 @@ cluster(char *oldrelname, char *oldindexname)
/*
* Check that index is in fact an index on the given relation
*/
tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(OIDOldIndex),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "CLUSTER: no pg_index entry for index %u",
OIDOldIndex);
if (((Form_pg_index) GETSTRUCT(tuple))->indrelid != OIDOldHeap)
if (OldIndex->rd_index->indrelid != OIDOldHeap)
elog(ERROR, "CLUSTER: \"%s\" is not an index for table \"%s\"",
saveoldindexname, saveoldrelname);
ReleaseSysCache(tuple);
/* Drop relcache refcnts, but do NOT give up the locks */
heap_close(OldHeap, NoLock);
@ -188,10 +180,6 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
{
Relation OldIndex,
NewHeap;
HeapTuple Old_pg_index_Tuple,
Old_pg_index_relation_Tuple;
Form_pg_index Old_pg_index_Form;
Form_pg_class Old_pg_index_relation_Form;
IndexInfo *indexInfo;
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
@ -206,33 +194,18 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
* its parent table is, so we don't need to do anything special for
* the temp-table case here.
*/
Old_pg_index_Tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(OIDOldIndex),
0, 0, 0);
Assert(Old_pg_index_Tuple);
Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
indexInfo = BuildIndexInfo(Old_pg_index_Tuple);
Old_pg_index_relation_Tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(OIDOldIndex),
0, 0, 0);
Assert(Old_pg_index_relation_Tuple);
Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
indexInfo = BuildIndexInfo(OldIndex->rd_index);
index_create(RelationGetRelationName(NewHeap),
NewIndexName,
indexInfo,
Old_pg_index_relation_Form->relam,
Old_pg_index_Form->indclass,
Old_pg_index_Form->indisprimary,
OldIndex->rd_rel->relam,
OldIndex->rd_index->indclass,
OldIndex->rd_index->indisprimary,
allowSystemTableMods);
setRelhasindex(OIDNewHeap, true,
Old_pg_index_Form->indisprimary, InvalidOid);
ReleaseSysCache(Old_pg_index_Tuple);
ReleaseSysCache(Old_pg_index_relation_Tuple);
OldIndex->rd_index->indisprimary, InvalidOid);
index_close(OldIndex);
heap_close(NewHeap, NoLock);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.153 2002/02/14 15:24:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.154 2002/02/19 20:11:12 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
@ -29,6 +29,7 @@
#include "catalog/pg_attrdef.h"
#include "catalog/pg_index.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_relcheck.h"
#include "catalog/pg_type.h"
#include "commands/command.h"
#include "commands/trigger.h"
@ -820,92 +821,8 @@ AlterTableAlterColumnStatistics(const char *relationName,
#ifdef _DROP_COLUMN_HACK__
/*
* ALTER TABLE DROP COLUMN trial implementation
*
*/
/*
* system table scan(index scan/sequential scan)
*/
typedef struct SysScanDescData
{
Relation heap_rel;
Relation irel;
HeapScanDesc scan;
IndexScanDesc iscan;
HeapTupleData tuple;
Buffer buffer;
} SysScanDescData, *SysScanDesc;
static void *
systable_beginscan(Relation rel, const char *indexRelname, int nkeys, ScanKey entry)
{
bool hasindex = (rel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
SysScanDesc sysscan;
sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
sysscan->heap_rel = rel;
sysscan->irel = (Relation) NULL;
sysscan->tuple.t_datamcxt = NULL;
sysscan->tuple.t_data = NULL;
sysscan->buffer = InvalidBuffer;
if (hasindex)
{
sysscan->irel = index_openr((char *) indexRelname);
sysscan->iscan = index_beginscan(sysscan->irel, false, nkeys, entry);
}
else
sysscan->scan = heap_beginscan(rel, false, SnapshotNow, nkeys, entry);
return (void *) sysscan;
}
static void
systable_endscan(void *scan)
{
SysScanDesc sysscan = (SysScanDesc) scan;
if (sysscan->irel)
{
if (BufferIsValid(sysscan->buffer))
ReleaseBuffer(sysscan->buffer);
index_endscan(sysscan->iscan);
index_close(sysscan->irel);
}
else
heap_endscan(sysscan->scan);
pfree(scan);
}
static HeapTuple
systable_getnext(void *scan)
{
SysScanDesc sysscan = (SysScanDesc) scan;
HeapTuple htup = (HeapTuple) NULL;
RetrieveIndexResult indexRes;
if (sysscan->irel)
{
if (BufferIsValid(sysscan->buffer))
{
ReleaseBuffer(sysscan->buffer);
sysscan->buffer = InvalidBuffer;
}
while (indexRes = index_getnext(sysscan->iscan, ForwardScanDirection), indexRes != NULL)
{
sysscan->tuple.t_self = indexRes->heap_iptr;
heap_fetch(sysscan->heap_rel, SnapshotNow, &sysscan->tuple, &(sysscan->buffer));
pfree(indexRes);
if (sysscan->tuple.t_data != NULL)
{
htup = &sysscan->tuple;
break;
}
}
}
else
htup = heap_getnext(sysscan->scan, 0);
return htup;
}
/*
* find a specified attribute in a node entry
*/
@ -957,10 +874,15 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
/*
* Remove/check constraints here
*/
ScanKeyEntryInitialize(&entry, (bits16) 0x0, Anum_pg_relcheck_rcrelid,
(RegProcedure) F_OIDEQ, ObjectIdGetDatum(reloid));
ScanKeyEntryInitialize(&entry, (bits16) 0x0,
Anum_pg_relcheck_rcrelid,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(reloid));
rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
sysscan = systable_beginscan(rcrel, RelCheckIndex, 1, &entry);
sysscan = systable_beginscan(rcrel, RelCheckIndex, true,
SnapshotNow,
1, &entry);
while (HeapTupleIsValid(htup = systable_getnext(sysscan)))
{
@ -987,6 +909,7 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
}
}
}
systable_endscan(sysscan);
heap_close(rcrel, NoLock);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.101 2002/01/15 16:52:47 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.102 2002/02/19 20:11:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -56,7 +56,7 @@ CreateTrigger(CreateTrigStmt *stmt)
char nulls[Natts_pg_trigger];
Relation rel;
Relation tgrel;
HeapScanDesc tgscan;
SysScanDesc tgscan;
ScanKeyData key;
Relation pgrel;
HeapTuple tuple;
@ -151,8 +151,9 @@ CreateTrigger(CreateTrigStmt *stmt)
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
SnapshotNow, 1, &key);
while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
{
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
@ -161,7 +162,7 @@ CreateTrigger(CreateTrigStmt *stmt)
stmt->trigname, stmt->relname);
found++;
}
heap_endscan(tgscan);
systable_endscan(tgscan);
/*
* Find and validate the trigger function.
@ -311,7 +312,7 @@ DropTrigger(DropTrigStmt *stmt)
{
Relation rel;
Relation tgrel;
HeapScanDesc tgscan;
SysScanDesc tgscan;
ScanKeyData key;
Relation pgrel;
HeapTuple tuple;
@ -343,8 +344,9 @@ DropTrigger(DropTrigStmt *stmt)
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0)))
tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
SnapshotNow, 1, &key);
while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
{
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
@ -359,14 +361,15 @@ DropTrigger(DropTrigStmt *stmt)
else
found++;
}
systable_endscan(tgscan);
heap_close(tgrel, RowExclusiveLock);
if (tgfound == 0)
elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
stmt->trigname, stmt->relname);
if (tgfound > 1)
elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
tgfound, stmt->trigname, stmt->relname);
heap_endscan(tgscan);
heap_close(tgrel, RowExclusiveLock);
/*
* Update relation's pg_class entry. Crucial side-effect: other
@ -406,7 +409,7 @@ void
RelationRemoveTriggers(Relation rel)
{
Relation tgrel;
HeapScanDesc tgscan;
SysScanDesc tgscan;
ScanKeyData key;
HeapTuple tup;
bool found = false;
@ -415,10 +418,10 @@ RelationRemoveTriggers(Relation rel)
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
SnapshotNow, 1, &key);
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
{
/* Delete any comments associated with this trigger */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(tgrel));
@ -428,7 +431,7 @@ RelationRemoveTriggers(Relation rel)
found = true;
}
heap_endscan(tgscan);
systable_endscan(tgscan);
/*
* If we deleted any triggers, must update pg_class entry and advance
@ -468,9 +471,10 @@ RelationRemoveTriggers(Relation rel)
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
tgscan = systable_beginscan(tgrel, TriggerConstrRelidIndex, true,
SnapshotNow, 1, &key);
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key);
while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0)))
while (HeapTupleIsValid(tup = systable_getnext(tgscan)))
{
Form_pg_trigger pg_trigger;
Relation refrel;
@ -500,7 +504,7 @@ RelationRemoveTriggers(Relation rel)
pfree(stmt.relname);
pfree(stmt.trigname);
}
heap_endscan(tgscan);
systable_endscan(tgscan);
heap_close(tgrel, RowExclusiveLock);
}
@ -518,69 +522,33 @@ RelationBuildTriggers(Relation relation)
TriggerDesc *trigdesc;
int ntrigs = relation->rd_rel->reltriggers;
Trigger *triggers = NULL;
Trigger *build;
int found = 0;
Relation tgrel;
Form_pg_trigger pg_trigger;
Relation irel = (Relation) NULL;
ScanKeyData skey;
HeapTupleData tuple;
IndexScanDesc sd = (IndexScanDesc) NULL;
HeapScanDesc tgscan = (HeapScanDesc) NULL;
SysScanDesc tgscan;
HeapTuple htup;
RetrieveIndexResult indexRes;
Buffer buffer;
struct varlena *val;
bool isnull;
int found;
bool hasindex;
trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
sizeof(TriggerDesc));
MemSet(trigdesc, 0, sizeof(TriggerDesc));
ScanKeyEntryInitialize(&skey,
(bits16) 0x0,
(AttrNumber) 1,
(AttrNumber) Anum_pg_trigger_tgrelid,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation)));
tgrel = heap_openr(TriggerRelationName, AccessShareLock);
hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
if (hasindex)
{
irel = index_openr(TriggerRelidIndex);
sd = index_beginscan(irel, false, 1, &skey);
}
else
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true,
SnapshotNow, 1, &skey);
for (found = 0;;)
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
{
if (hasindex)
{
indexRes = index_getnext(sd, ForwardScanDirection);
if (!indexRes)
break;
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
Trigger *build;
tuple.t_self = indexRes->heap_iptr;
heap_fetch(tgrel, SnapshotNow, &tuple, &buffer, sd);
pfree(indexRes);
if (!tuple.t_data)
continue;
htup = &tuple;
}
else
{
htup = heap_getnext(tgscan, 0);
if (!HeapTupleIsValid(htup))
break;
}
if (found == ntrigs)
elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s",
RelationGetRelationName(relation));
pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
if (triggers == NULL)
triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
sizeof(Trigger));
@ -628,25 +596,20 @@ RelationBuildTriggers(Relation relation)
build->tgargs = NULL;
found++;
if (hasindex)
ReleaseBuffer(buffer);
}
if (found < ntrigs)
systable_endscan(tgscan);
heap_close(tgrel, AccessShareLock);
if (found != ntrigs)
elog(ERROR, "RelationBuildTriggers: %d record(s) not found for rel %s",
ntrigs - found,
RelationGetRelationName(relation));
if (hasindex)
{
index_endscan(sd);
index_close(irel);
}
else
heap_endscan(tgscan);
heap_close(tgrel, AccessShareLock);
/* Build trigdesc */
trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
sizeof(TriggerDesc));
MemSet(trigdesc, 0, sizeof(TriggerDesc));
trigdesc->triggers = triggers;
trigdesc->numtriggers = ntrigs;
for (found = 0; found < ntrigs; found++)
@ -1741,14 +1704,12 @@ void
DeferredTriggerSetState(ConstraintsSetStmt *stmt)
{
Relation tgrel;
Relation irel = (Relation) NULL;
List *l;
List *ls;
List *loid = NIL;
MemoryContext oldcxt;
bool found;
DeferredTriggerStatus state;
bool hasindex;
/*
* Handle SET CONSTRAINTS ALL ...
@ -1817,21 +1778,12 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ----------
*/
tgrel = heap_openr(TriggerRelationName, AccessShareLock);
hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
if (hasindex)
irel = index_openr(TriggerConstrNameIndex);
foreach(l, stmt->constraints)
{
ScanKeyData skey;
HeapTupleData tuple;
IndexScanDesc sd = (IndexScanDesc) NULL;
HeapScanDesc tgscan = (HeapScanDesc) NULL;
SysScanDesc tgscan;
HeapTuple htup;
RetrieveIndexResult indexRes;
Buffer buffer;
Form_pg_trigger pg_trigger;
Oid constr_oid;
/*
* Check that only named constraints are set explicitly
@ -1844,47 +1796,28 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
*/
ScanKeyEntryInitialize(&skey,
(bits16) 0x0,
(AttrNumber) 1,
(AttrNumber) Anum_pg_trigger_tgconstrname,
(RegProcedure) F_NAMEEQ,
PointerGetDatum((char *) lfirst(l)));
if (hasindex)
sd = index_beginscan(irel, false, 1, &skey);
else
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
tgscan = systable_beginscan(tgrel, TriggerConstrNameIndex, true,
SnapshotNow, 1, &skey);
/*
* ... and search for the constraint trigger row
*/
found = false;
for (;;)
{
if (hasindex)
{
indexRes = index_getnext(sd, ForwardScanDirection);
if (!indexRes)
break;
tuple.t_self = indexRes->heap_iptr;
heap_fetch(tgrel, SnapshotNow, &tuple, &buffer, sd);
pfree(indexRes);
if (!tuple.t_data)
continue;
htup = &tuple;
}
else
{
htup = heap_getnext(tgscan, 0);
if (!HeapTupleIsValid(htup))
break;
}
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
{
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
Oid constr_oid;
/*
* If we found some, check that they fit the deferrability but
* skip ON <event> RESTRICT ones, since they are silently
* never deferrable.
*/
pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
if (stmt->deferred && !pg_trigger->tgdeferrable &&
pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL)
@ -1894,24 +1827,16 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
constr_oid = htup->t_data->t_oid;
loid = lappendi(loid, constr_oid);
found = true;
if (hasindex)
ReleaseBuffer(buffer);
}
systable_endscan(tgscan);
/*
* Not found ?
*/
if (!found)
elog(ERROR, "Constraint '%s' does not exist", (char *) lfirst(l));
if (hasindex)
index_endscan(sd);
else
heap_endscan(tgscan);
}
if (hasindex)
index_close(irel);
heap_close(tgrel, AccessShareLock);
if (!IsTransactionBlock())

View File

@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.213 2002/01/06 00:37:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.214 2002/02/19 20:11:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -315,20 +315,6 @@ vacuum_shutdown(VacuumStmt *vacstmt)
vac_truncate_clog(initialOldestXmin, initialFreezeLimit);
}
/*
* If we did a complete vacuum or analyze, then flush the init file
* that relcache.c uses to save startup time. The next backend startup
* will rebuild the init file with up-to-date information from
* pg_class. This lets the optimizer see the stats that we've
* collected for certain critical system indexes. See relcache.c for
* more details.
*
* Ignore any failure to unlink the file, since it might not be there if
* no backend has been started since the last vacuum.
*/
if (vacstmt->vacrel == NULL)
unlink(RELCACHE_INIT_FILENAME);
/*
* Clean up working storage --- note we must do this after
* StartTransactionCommand, else we might be trying to delete the
@ -535,8 +521,15 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
if (!hasindex)
pgcform->relhaspkey = false;
/* invalidate the tuple in the cache and write the buffer */
/*
* Invalidate the tuple in the catcaches; this also arranges to flush
* the relation's relcache entry. (If we fail to commit for some reason,
* no flush will occur, but no great harm is done since there are no
* noncritical state updates here.)
*/
RelationInvalidateHeapTuple(rd, &rtup);
/* Write the buffer */
WriteBuffer(buffer);
heap_close(rd, RowExclusiveLock);
@ -2816,10 +2809,6 @@ vac_close_indexes(int nindexes, Relation *Irel)
bool
vac_is_partial_index(Relation indrel)
{
bool result;
HeapTuple cachetuple;
Form_pg_index indexStruct;
/*
* If the index's AM doesn't support nulls, it's partial for our
* purposes
@ -2828,18 +2817,7 @@ vac_is_partial_index(Relation indrel)
return true;
/* Otherwise, look to see if there's a partial-index predicate */
cachetuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(RelationGetRelid(indrel)),
0, 0, 0);
if (!HeapTupleIsValid(cachetuple))
elog(ERROR, "vac_is_partial_index: index %u not found",
RelationGetRelid(indrel));
indexStruct = (Form_pg_index) GETSTRUCT(cachetuple);
result = (VARSIZE(&indexStruct->indpred) > VARHDRSZ);
ReleaseSysCache(cachetuple);
return result;
return (VARSIZE(&indrel->rd_index->indpred) > VARHDRSZ);
}

View File

@ -6,25 +6,12 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execAmi.c,v 1.60 2001/10/25 05:49:27 momjian Exp $
* $Id: execAmi.c,v 1.61 2002/02/19 20:11:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
*
* ExecOpenScanR \ / amopen
* ExecBeginScan \ / ambeginscan
* ExecCloseR \ / amclose
* ExecInsert \ executor interface / aminsert
* ExecReScanR / to access methods \ amrescan
* ExecMarkPos / \ ammarkpos
* ExecRestrPos / \ amrestpos
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/heap.h"
@ -50,202 +37,6 @@
#include "executor/nodeSubqueryscan.h"
#include "executor/nodeUnique.h"
static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
bool isindex, ScanDirection dir, Snapshot snapshot);
/* ----------------------------------------------------------------
* ExecOpenScanR
*
* old comments:
* Parameters:
* relation -- relation to be opened and scanned.
* nkeys -- number of keys
* skeys -- keys to restrict scanning
* isindex -- if this is true, the relation is the relid of
* an index relation, else it is a heap relation.
* Returns the relation as(relDesc scanDesc)
* ----------------------------------------------------------------
*/
void
ExecOpenScanR(Oid relOid,
int nkeys,
ScanKey skeys,
bool isindex,
ScanDirection dir,
Snapshot snapshot,
Relation *returnRelation, /* return */
Pointer *returnScanDesc) /* return */
{
Relation relation;
Pointer scanDesc;
/*
* note: scanDesc returned by ExecBeginScan can be either a
* HeapScanDesc or an IndexScanDesc so for now we make it a Pointer.
* There should be a better scan abstraction someday -cim 9/9/89
*/
/*
* Open the relation with the correct call depending on whether this
* is a heap relation or an index relation.
*
* For a table, acquire AccessShareLock for the duration of the query
* execution. For indexes, acquire no lock here; the index machinery
* does its own locks and unlocks. (We rely on having some kind of
* lock on the parent table to ensure the index won't go away!)
*/
if (isindex)
relation = index_open(relOid);
else
relation = heap_open(relOid, AccessShareLock);
scanDesc = ExecBeginScan(relation,
nkeys,
skeys,
isindex,
dir,
snapshot);
if (returnRelation != NULL)
*returnRelation = relation;
if (scanDesc != NULL)
*returnScanDesc = scanDesc;
}
/* ----------------------------------------------------------------
* ExecBeginScan
*
* beginscans a relation in current direction.
*
* XXX fix parameters to AMbeginscan (and btbeginscan)
* currently we need to pass a flag stating whether
* or not the scan should begin at an endpoint of
* the relation.. Right now we always pass false
* -cim 9/14/89
* ----------------------------------------------------------------
*/
static Pointer
ExecBeginScan(Relation relation,
int nkeys,
ScanKey skeys,
bool isindex,
ScanDirection dir,
Snapshot snapshot)
{
Pointer scanDesc;
/*
* open the appropriate type of scan.
*
* Note: ambeginscan()'s second arg is a boolean indicating that the scan
* should be done in reverse.. That is, if you pass it true, then the
* scan is backward.
*/
if (isindex)
{
scanDesc = (Pointer) index_beginscan(relation,
false, /* see above comment */
nkeys,
skeys);
}
else
{
scanDesc = (Pointer) heap_beginscan(relation,
ScanDirectionIsBackward(dir),
snapshot,
nkeys,
skeys);
}
if (scanDesc == NULL)
elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
return scanDesc;
}
/* ----------------------------------------------------------------
* ExecCloseR
*
* closes the relation and scan descriptor for a scan node.
* Also closes index relations and scans for index scans.
* ----------------------------------------------------------------
*/
void
ExecCloseR(Plan *node)
{
CommonScanState *state;
Relation relation;
HeapScanDesc scanDesc;
/*
* get state for node and shut down the heap scan, if any
*/
switch (nodeTag(node))
{
case T_SeqScan:
state = ((SeqScan *) node)->scanstate;
break;
case T_IndexScan:
state = ((IndexScan *) node)->scan.scanstate;
break;
case T_TidScan:
state = ((TidScan *) node)->scan.scanstate;
break;
default:
elog(DEBUG, "ExecCloseR: not a scan node!");
return;
}
relation = state->css_currentRelation;
scanDesc = state->css_currentScanDesc;
if (scanDesc != NULL)
heap_endscan(scanDesc);
/*
* if this is an index scan then we have to take care of the index
* relations as well.
*/
if (IsA(node, IndexScan))
{
IndexScan *iscan = (IndexScan *) node;
IndexScanState *indexstate = iscan->indxstate;
int numIndices;
RelationPtr indexRelationDescs;
IndexScanDescPtr indexScanDescs;
int i;
numIndices = indexstate->iss_NumIndices;
indexRelationDescs = indexstate->iss_RelationDescs;
indexScanDescs = indexstate->iss_ScanDescs;
for (i = 0; i < numIndices; i++)
{
/*
* shut down each of the index scans and close each of the
* index relations
*/
if (indexScanDescs[i] != NULL)
index_endscan(indexScanDescs[i]);
if (indexRelationDescs[i] != NULL)
index_close(indexRelationDescs[i]);
}
}
/*
* Finally, close the heap relation.
*
* Currently, we do not release the AccessShareLock acquired by
* ExecOpenScanR. This lock should be held till end of transaction.
* (There is a faction that considers this too much locking, however.)
*/
if (relation != NULL)
heap_close(relation, NoLock);
}
/* ----------------------------------------------------------------
* ExecReScan
@ -374,27 +165,6 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
}
}
/* ----------------------------------------------------------------
* ExecReScanR
*
* XXX this does not do the right thing with indices yet.
* ----------------------------------------------------------------
*/
HeapScanDesc
ExecReScanR(Relation relDesc, /* LLL relDesc unused */
HeapScanDesc scanDesc,
ScanDirection direction,
int nkeys, /* LLL nkeys unused */
ScanKey skeys)
{
if (scanDesc != NULL)
heap_rescan(scanDesc, /* scan desc */
ScanDirectionIsBackward(direction), /* backward flag */
skeys); /* scan keys */
return scanDesc;
}
/* ----------------------------------------------------------------
* ExecMarkPos
*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.78 2001/10/25 05:49:27 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.79 2002/02/19 20:11:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -496,7 +496,6 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
{
Oid indexOid = lfirsti(indexoidscan);
Relation indexDesc;
HeapTuple indexTuple;
IndexInfo *ii;
/*
@ -525,20 +524,9 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
LockRelation(indexDesc, AccessExclusiveLock);
/*
* Get the pg_index tuple for the index
* extract index key information from the index's pg_index tuple
*/
indexTuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexOid),
0, 0, 0);
if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
/*
* extract the index key information from the tuple
*/
ii = BuildIndexInfo(indexTuple);
ReleaseSysCache(indexTuple);
ii = BuildIndexInfo(indexDesc->rd_index);
relationDescs[i] = indexDesc;
indexInfoArray[i] = ii;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.66 2002/02/11 20:10:48 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.67 2002/02/19 20:11:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -359,14 +359,20 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
int n_keys;
ScanKey scan_keys;
int *run_keys;
List *listscan;
indxqual = lnext(indxqual);
n_keys = numScanKeys[i];
scan_keys = scanKeys[i];
run_keys = runtimeKeyInfo[i];
listscan = qual;
for (j = 0; j < n_keys; j++)
{
Expr *clause = lfirst(listscan);
listscan = lnext(listscan);
/*
* If we have a run-time key, then extract the run-time
* expression and evaluate it with respect to the current
@ -382,7 +388,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
*/
if (run_keys[j] != NO_OP)
{
Expr *clause = nth(j, qual);
Node *scanexpr;
Datum scanvalue;
bool isNull;
@ -448,6 +453,9 @@ ExecEndIndexScan(IndexScan *node)
List *indxqual;
int *numScanKeys;
int numIndices;
Relation relation;
RelationPtr indexRelationDescs;
IndexScanDescPtr indexScanDescs;
int i;
scanstate = node->scan.scanstate;
@ -461,6 +469,9 @@ ExecEndIndexScan(IndexScan *node)
numIndices = indexstate->iss_NumIndices;
scanKeys = indexstate->iss_ScanKeys;
numScanKeys = indexstate->iss_NumScanKeys;
indexRelationDescs = indexstate->iss_RelationDescs;
indexScanDescs = indexstate->iss_ScanDescs;
relation = scanstate->css_currentRelation;
/*
* Free the projection info and the scan attribute info
@ -475,9 +486,25 @@ ExecEndIndexScan(IndexScan *node)
FreeExprContext(indexstate->iss_RuntimeContext);
/*
* close the heap and index relations
* close the index relations
*/
ExecCloseR((Plan *) node);
for (i = 0; i < numIndices; i++)
{
if (indexScanDescs[i] != NULL)
index_endscan(indexScanDescs[i]);
if (indexRelationDescs[i] != NULL)
index_close(indexRelationDescs[i]);
}
/*
* close the heap relation.
*
* Currently, we do not release the AccessShareLock acquired by
* ExecInitIndexScan. This lock should be held till end of transaction.
* (There is a faction that considers this too much locking, however.)
*/
heap_close(relation, NoLock);
/*
* free the scan keys used in scanning the indices
@ -589,6 +616,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
CommonScanState *scanstate;
List *indxqual;
List *indxid;
List *listscan;
int i;
int numIndices;
int indexPtr;
@ -603,7 +631,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
Index relid;
Oid reloid;
Relation currentRelation;
HeapScanDesc currentScanDesc;
ScanDirection direction;
/*
@ -709,6 +736,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
* for each opclause in the given qual, convert each qual's
* opclause into a single scan key
*/
listscan = qual;
for (j = 0; j < n_keys; j++)
{
Expr *clause; /* one clause of index qual */
@ -725,7 +753,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
/*
* extract clause information from the qualification
*/
clause = nth(j, qual);
clause = lfirst(listscan);
listscan = lnext(listscan);
op = (Oper *) clause->oper;
if (!IsA(clause, Expr) ||!IsA(op, Oper))
@ -989,25 +1018,19 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
direction = estate->es_direction;
/*
* open the base relation
* open the base relation and acquire AccessShareLock on it.
*/
relid = node->scan.scanrelid;
rtentry = rt_fetch(relid, rangeTable);
reloid = rtentry->relid;
ExecOpenScanR(reloid, /* relation */
0, /* nkeys */
(ScanKey) NULL, /* scan key */
false, /* is index */
direction, /* scan direction */
estate->es_snapshot, /* */
&currentRelation, /* return: rel desc */
(Pointer *) &currentScanDesc); /* return: scan desc */
currentRelation = heap_open(reloid, AccessShareLock);
if (!RelationGetForm(currentRelation)->relhasindex)
elog(ERROR, "indexes of the relation %u was inactivated", reloid);
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = currentScanDesc;
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
/*
* get the scan type from the relation descriptor.
@ -1017,24 +1040,30 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
/*
* open the index relations and initialize relation and scan
* descriptors.
* descriptors. Note we acquire no locks here; the index machinery
* does its own locks and unlocks. (We rely on having AccessShareLock
* on the parent table to ensure the index won't go away!)
*/
listscan = indxid;
for (i = 0; i < numIndices; i++)
{
Oid indexOid = (Oid) nthi(i, indxid);
Oid indexOid = (Oid) lfirsti(listscan);
if (indexOid != 0)
{
ExecOpenScanR(indexOid, /* relation */
numScanKeys[i], /* nkeys */
scanKeys[i], /* scan key */
true, /* is index */
direction, /* scan direction */
estate->es_snapshot,
&(relationDescs[i]), /* return: rel desc */
(Pointer *) &(scanDescs[i]));
/* return: scan desc */
relationDescs[i] = index_open(indexOid);
/*
* Note: index_beginscan()'s second arg is a boolean indicating
* that the scan should be done in reverse. That is, if you pass
* it true, then the scan is backward.
*/
scanDescs[i] = index_beginscan(relationDescs[i],
false, /* see above comment */
numScanKeys[i],
scanKeys[i]);
}
listscan = lnext(listscan);
}
indexstate->iss_RelationDescs = relationDescs;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.33 2001/10/28 06:25:43 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.34 2002/02/19 20:11:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -154,7 +154,9 @@ InitScanRelation(SeqScan *node, EState *estate,
/*
* get the relation object id from the relid'th entry in the range
* table, open that relation and initialize the scan state...
* table, open that relation and initialize the scan state.
*
* We acquire AccessShareLock for the duration of the scan.
*/
relid = node->scanrelid;
rangeTable = estate->es_range_table;
@ -162,14 +164,13 @@ InitScanRelation(SeqScan *node, EState *estate,
reloid = rtentry->relid;
direction = estate->es_direction;
ExecOpenScanR(reloid, /* relation */
0, /* nkeys */
NULL, /* scan key */
false, /* is index */
direction, /* scan direction */
estate->es_snapshot,
&currentRelation, /* return: rel desc */
(Pointer *) &currentScanDesc); /* return: scan desc */
currentRelation = heap_open(reloid, AccessShareLock);
currentScanDesc = heap_beginscan(currentRelation,
ScanDirectionIsBackward(direction),
estate->es_snapshot,
0,
NULL);
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = currentScanDesc;
@ -189,7 +190,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
{
CommonScanState *scanstate;
Oid reloid;
HeapScanDesc scandesc;
/*
* Once upon a time it was possible to have an outerPlan of a SeqScan,
@ -229,7 +229,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
*/
reloid = InitScanRelation(node, estate, scanstate);
scandesc = scanstate->css_currentScanDesc;
scanstate->cstate.cs_TupFromTlist = false;
/*
@ -259,11 +258,15 @@ void
ExecEndSeqScan(SeqScan *node)
{
CommonScanState *scanstate;
Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
scanstate = node->scanstate;
relation = scanstate->css_currentRelation;
scanDesc = scanstate->css_currentScanDesc;
/*
* Free the projection info and the scan attribute info
@ -276,9 +279,18 @@ ExecEndSeqScan(SeqScan *node)
ExecFreeExprContext(&scanstate->cstate);
/*
* close scan relation
* close heap scan
*/
ExecCloseR((Plan *) node);
heap_endscan(scanDesc);
/*
* close the heap relation.
*
* Currently, we do not release the AccessShareLock acquired by
* InitScanRelation. This lock should be held till end of transaction.
* (There is a faction that considers this too much locking, however.)
*/
heap_close(relation, NoLock);
/*
* clean out the tuple table
@ -303,7 +315,6 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
{
CommonScanState *scanstate;
EState *estate;
Relation rel;
HeapScanDesc scan;
ScanDirection direction;
@ -317,11 +328,13 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
estate->es_evTupleNull[node->scanrelid - 1] = false;
return;
}
rel = scanstate->css_currentRelation;
scan = scanstate->css_currentScanDesc;
direction = estate->es_direction;
scan = ExecReScanR(rel, scan, direction, 0, NULL);
scanstate->css_currentScanDesc = scan;
heap_rescan(scan, /* scan desc */
ScanDirectionIsBackward(direction), /* backward flag */
NULL); /* new scan keys */
}
/* ----------------------------------------------------------------

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.22 2002/02/11 20:10:50 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.23 2002/02/19 20:11:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -300,15 +300,14 @@ ExecEndTidScan(TidScan *node)
CommonScanState *scanstate;
TidScanState *tidstate;
/*
* extract information from the node
*/
scanstate = node->scan.scanstate;
tidstate = node->tidstate;
if (tidstate && tidstate->tss_TidList)
pfree(tidstate->tss_TidList);
/*
* extract information from the node
*/
/*
* Free the projection info and the scan attribute info
*
@ -320,9 +319,13 @@ ExecEndTidScan(TidScan *node)
ExecFreeExprContext(&scanstate->cstate);
/*
* close the heap and tid relations
* close the heap relation.
*
* Currently, we do not release the AccessShareLock acquired by
* ExecInitTidScan. This lock should be held till end of transaction.
* (There is a faction that considers this too much locking, however.)
*/
ExecCloseR((Plan *) node);
heap_close(scanstate->css_currentRelation, NoLock);
/*
* clear out tuple table slots
@ -460,14 +463,17 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
/*
* open the base relation
*
* We acquire AccessShareLock for the duration of the scan.
*/
relid = node->scan.scanrelid;
rtentry = rt_fetch(relid, rangeTable);
reloid = rtentry->relid;
currentRelation = heap_open(reloid, AccessShareLock);
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = 0;
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
/*
* get the scan type from the relation descriptor.

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.69 2001/10/25 05:49:34 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.70 2002/02/19 20:11:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -98,20 +98,15 @@ find_secondary_indexes(Oid relationObjectId)
foreach(indexoidscan, indexoidlist)
{
Oid indexoid = lfirsti(indexoidscan);
HeapTuple indexTuple;
Relation indexRelation;
Form_pg_index index;
IndexOptInfo *info;
int i;
Relation indexRelation;
int16 amorderstrategy;
indexTuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexoid),
0, 0, 0);
if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "find_secondary_indexes: index %u not found",
indexoid);
index = (Form_pg_index) GETSTRUCT(indexTuple);
/* Extract info from the relation descriptor for the index */
indexRelation = index_open(indexoid);
info = makeNode(IndexOptInfo);
/*
@ -123,6 +118,7 @@ find_secondary_indexes(Oid relationObjectId)
info->ordering = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1));
/* Extract info from the pg_index tuple */
index = indexRelation->rd_index;
info->indexoid = index->indexrelid;
info->indproc = index->indproc; /* functional index ?? */
if (VARSIZE(&index->indpred) > VARHDRSZ) /* partial index ?? */
@ -156,14 +152,11 @@ find_secondary_indexes(Oid relationObjectId)
info->indexkeys[i] = 0;
info->nkeys = i;
/* Extract info from the relation descriptor for the index */
indexRelation = index_open(index->indexrelid);
info->relam = indexRelation->rd_rel->relam;
info->pages = indexRelation->rd_rel->relpages;
info->tuples = indexRelation->rd_rel->reltuples;
info->amcostestimate = index_cost_estimator(indexRelation);
amorderstrategy = indexRelation->rd_am->amorderstrategy;
index_close(indexRelation);
/*
* Fetch the ordering operators associated with the index, if any.
@ -171,26 +164,16 @@ find_secondary_indexes(Oid relationObjectId)
MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS + 1));
if (amorderstrategy != 0)
{
int oprindex = amorderstrategy - 1;
for (i = 0; i < info->ncolumns; i++)
{
HeapTuple amopTuple;
Form_pg_amop amop;
amopTuple =
SearchSysCache(AMOPSTRATEGY,
ObjectIdGetDatum(index->indclass[i]),
Int16GetDatum(amorderstrategy),
0, 0);
if (!HeapTupleIsValid(amopTuple))
elog(ERROR, "find_secondary_indexes: no amop %u %d",
index->indclass[i], (int) amorderstrategy);
amop = (Form_pg_amop) GETSTRUCT(amopTuple);
info->ordering[i] = amop->amopopr;
ReleaseSysCache(amopTuple);
info->ordering[i] = indexRelation->rd_operator[oprindex];
oprindex += indexRelation->rd_am->amstrategies;
}
}
ReleaseSysCache(indexTuple);
index_close(indexRelation);
indexinfos = lcons(info, indexinfos);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.115 2001/12/12 03:28:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.116 2002/02/19 20:11:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -547,11 +547,9 @@ agg_get_candidates(char *aggname,
Oid typeId,
CandidateList *candidates)
{
CandidateList current_candidate;
Relation pg_aggregate_desc;
HeapScanDesc pg_aggregate_scan;
SysScanDesc pg_aggregate_scan;
HeapTuple tup;
Form_pg_aggregate agg;
int ncandidates = 0;
ScanKeyData aggKey[1];
@ -563,15 +561,15 @@ agg_get_candidates(char *aggname,
NameGetDatum(aggname));
pg_aggregate_desc = heap_openr(AggregateRelationName, AccessShareLock);
pg_aggregate_scan = heap_beginscan(pg_aggregate_desc,
0,
SnapshotSelf, /* ??? */
1,
aggKey);
pg_aggregate_scan = systable_beginscan(pg_aggregate_desc,
AggregateNameTypeIndex, true,
SnapshotNow,
1, aggKey);
while (HeapTupleIsValid(tup = heap_getnext(pg_aggregate_scan, 0)))
while (HeapTupleIsValid(tup = systable_getnext(pg_aggregate_scan)))
{
agg = (Form_pg_aggregate) GETSTRUCT(tup);
Form_pg_aggregate agg = (Form_pg_aggregate) GETSTRUCT(tup);
CandidateList current_candidate;
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(sizeof(Oid));
@ -582,7 +580,7 @@ agg_get_candidates(char *aggname,
ncandidates++;
}
heap_endscan(pg_aggregate_scan);
systable_endscan(pg_aggregate_scan);
heap_close(pg_aggregate_desc, AccessShareLock);
return ncandidates;
@ -680,62 +678,46 @@ static CandidateList
func_get_candidates(char *funcname, int nargs)
{
Relation heapRelation;
Relation idesc;
ScanKeyData skey;
HeapTupleData tuple;
IndexScanDesc sd;
RetrieveIndexResult indexRes;
Form_pg_proc pgProcP;
ScanKeyData skey[2];
HeapTuple tuple;
SysScanDesc funcscan;
CandidateList candidates = NULL;
CandidateList current_candidate;
int i;
heapRelation = heap_openr(ProcedureRelationName, AccessShareLock);
ScanKeyEntryInitialize(&skey,
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) Anum_pg_proc_proname,
(RegProcedure) F_NAMEEQ,
PointerGetDatum(funcname));
ScanKeyEntryInitialize(&skey[1],
(bits16) 0x0,
(AttrNumber) Anum_pg_proc_pronargs,
(RegProcedure) F_INT2EQ,
Int16GetDatum(nargs));
idesc = index_openr(ProcedureNameIndex);
funcscan = systable_beginscan(heapRelation, ProcedureNameIndex, true,
SnapshotNow, 2, skey);
sd = index_beginscan(idesc, false, 1, &skey);
do
while (HeapTupleIsValid(tuple = systable_getnext(funcscan)))
{
indexRes = index_getnext(sd, ForwardScanDirection);
if (indexRes)
{
Buffer buffer;
Form_pg_proc pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
CandidateList current_candidate;
tuple.t_datamcxt = NULL;
tuple.t_data = NULL;
tuple.t_self = indexRes->heap_iptr;
heap_fetch(heapRelation, SnapshotNow, &tuple, &buffer, sd);
pfree(indexRes);
if (tuple.t_data != NULL)
{
pgProcP = (Form_pg_proc) GETSTRUCT(&tuple);
if (pgProcP->pronargs == nargs)
{
current_candidate = (CandidateList)
palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *)
palloc(FUNC_MAX_ARGS * sizeof(Oid));
MemSet(current_candidate->args, 0, FUNC_MAX_ARGS * sizeof(Oid));
for (i = 0; i < nargs; i++)
current_candidate->args[i] = pgProcP->proargtypes[i];
current_candidate = (CandidateList)
palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *)
palloc(FUNC_MAX_ARGS * sizeof(Oid));
MemSet(current_candidate->args, 0, FUNC_MAX_ARGS * sizeof(Oid));
for (i = 0; i < nargs; i++)
current_candidate->args[i] = pgProcP->proargtypes[i];
current_candidate->next = candidates;
candidates = current_candidate;
}
ReleaseBuffer(buffer);
}
}
} while (indexRes);
current_candidate->next = candidates;
candidates = current_candidate;
}
index_endscan(sd);
index_close(idesc);
systable_endscan(funcscan);
heap_close(heapRelation, AccessShareLock);
return candidates;

View File

@ -8,15 +8,17 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.51 2001/10/25 05:49:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.52 2002/02/19 20:11:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_operator.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
@ -80,13 +82,11 @@ static int
binary_oper_get_candidates(char *opname,
CandidateList *candidates)
{
CandidateList current_candidate;
Relation pg_operator_desc;
HeapScanDesc pg_operator_scan;
SysScanDesc pg_operator_scan;
HeapTuple tup;
Form_pg_operator oper;
int ncandidates = 0;
ScanKeyData opKey[2];
ScanKeyData opKey[1];
*candidates = NULL;
@ -95,38 +95,94 @@ binary_oper_get_candidates(char *opname,
F_NAMEEQ,
NameGetDatum(opname));
ScanKeyEntryInitialize(&opKey[1], 0,
Anum_pg_operator_oprkind,
F_CHAREQ,
CharGetDatum('b'));
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
pg_operator_scan = heap_beginscan(pg_operator_desc,
0,
SnapshotSelf, /* ??? */
2,
opKey);
pg_operator_scan = systable_beginscan(pg_operator_desc,
OperatorNameIndex, true,
SnapshotNow,
1, opKey);
while (HeapTupleIsValid(tup = heap_getnext(pg_operator_scan, 0)))
while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
{
oper = (Form_pg_operator) GETSTRUCT(tup);
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
if (oper->oprkind == 'b')
{
CandidateList current_candidate;
current_candidate->args[0] = oper->oprleft;
current_candidate->args[1] = oper->oprright;
current_candidate->next = *candidates;
*candidates = current_candidate;
ncandidates++;
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
current_candidate->args[0] = oper->oprleft;
current_candidate->args[1] = oper->oprright;
current_candidate->next = *candidates;
*candidates = current_candidate;
ncandidates++;
}
}
heap_endscan(pg_operator_scan);
systable_endscan(pg_operator_scan);
heap_close(pg_operator_desc, AccessShareLock);
return ncandidates;
} /* binary_oper_get_candidates() */
/* unary_oper_get_candidates()
* given opname, find all possible types for which
* a right/left unary operator named opname exists.
* Build a list of the candidate input types.
* Returns number of candidates found.
*/
static int
unary_oper_get_candidates(char *opname,
CandidateList *candidates,
char rightleft)
{
Relation pg_operator_desc;
SysScanDesc pg_operator_scan;
HeapTuple tup;
int ncandidates = 0;
ScanKeyData opKey[1];
*candidates = NULL;
ScanKeyEntryInitialize(&opKey[0], 0,
Anum_pg_operator_oprname,
F_NAMEEQ,
NameGetDatum(opname));
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
pg_operator_scan = systable_beginscan(pg_operator_desc,
OperatorNameIndex, true,
SnapshotNow,
1, opKey);
while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
{
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
if (oper->oprkind == rightleft)
{
CandidateList current_candidate;
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(sizeof(Oid));
if (rightleft == 'r')
current_candidate->args[0] = oper->oprleft;
else
current_candidate->args[0] = oper->oprright;
current_candidate->next = *candidates;
*candidates = current_candidate;
ncandidates++;
}
}
systable_endscan(pg_operator_scan);
heap_close(pg_operator_desc, AccessShareLock);
return ncandidates;
} /* unary_oper_get_candidates() */
/* oper_select_candidate()
* Given the input argtype array and one or more candidates
@ -739,66 +795,6 @@ compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
return InvalidOid;
}
/* unary_oper_get_candidates()
* given opname, find all possible types for which
* a right/left unary operator named opname exists.
* Build a list of the candidate input types.
* Returns number of candidates found.
*/
static int
unary_oper_get_candidates(char *opname,
CandidateList *candidates,
char rightleft)
{
CandidateList current_candidate;
Relation pg_operator_desc;
HeapScanDesc pg_operator_scan;
HeapTuple tup;
Form_pg_operator oper;
int ncandidates = 0;
ScanKeyData opKey[2];
*candidates = NULL;
ScanKeyEntryInitialize(&opKey[0], 0,
Anum_pg_operator_oprname,
F_NAMEEQ,
NameGetDatum(opname));
ScanKeyEntryInitialize(&opKey[1], 0,
Anum_pg_operator_oprkind,
F_CHAREQ,
CharGetDatum(rightleft));
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
pg_operator_scan = heap_beginscan(pg_operator_desc,
0,
SnapshotSelf, /* ??? */
2,
opKey);
while (HeapTupleIsValid(tup = heap_getnext(pg_operator_scan, 0)))
{
oper = (Form_pg_operator) GETSTRUCT(tup);
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(sizeof(Oid));
if (rightleft == 'r')
current_candidate->args[0] = oper->oprleft;
else
current_candidate->args[0] = oper->oprright;
current_candidate->next = *candidates;
*candidates = current_candidate;
ncandidates++;
}
heap_endscan(pg_operator_scan);
heap_close(pg_operator_desc, AccessShareLock);
return ncandidates;
} /* unary_oper_get_candidates() */
/* Given unary right operator (operator on right), return oper struct
*

View File

@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.89 2001/11/26 21:15:14 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.90 2002/02/19 20:11:16 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -341,6 +341,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
HeapTuple ht_idx;
HeapTuple ht_idxrel;
HeapTuple ht_indrel;
HeapTuple ht_am;
Form_pg_index idxrec;
Form_pg_class idxrelrec;
Form_pg_class indrelrec;
@ -383,13 +384,13 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
/*
* Fetch the pg_am tuple of the index' access method
*
* There is no syscache for this, so use index.c subroutine.
*/
amrec = AccessMethodObjectIdGetForm(idxrelrec->relam,
CurrentMemoryContext);
if (!amrec)
elog(ERROR, "lookup for AM %u failed", idxrelrec->relam);
ht_am = SearchSysCache(AMOID,
ObjectIdGetDatum(idxrelrec->relam),
0, 0, 0);
if (!HeapTupleIsValid(ht_am))
elog(ERROR, "syscache lookup for AM %u failed", idxrelrec->relam);
amrec = (Form_pg_am) GETSTRUCT(ht_am);
/*
* Start the index definition
@ -504,10 +505,11 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
pfree(buf.data);
pfree(keybuf.data);
pfree(amrec);
ReleaseSysCache(ht_idx);
ReleaseSysCache(ht_idxrel);
ReleaseSysCache(ht_indrel);
ReleaseSysCache(ht_am);
PG_RETURN_TEXT_P(indexdef);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.86 2001/11/05 17:46:30 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.87 2002/02/19 20:11:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -24,9 +24,13 @@
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "miscadmin.h"
#ifdef CATCACHE_STATS
#include "storage/ipc.h" /* for on_proc_exit */
#endif
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/catcache.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
@ -94,6 +98,9 @@ static Index CatalogCacheComputeTupleHashIndex(CatCache *cache,
HeapTuple tuple);
static void CatalogCacheInitializeCache(CatCache *cache);
static Datum cc_hashname(PG_FUNCTION_ARGS);
#ifdef CATCACHE_STATS
static void CatCachePrintStats(void);
#endif
/*
@ -147,6 +154,46 @@ cc_hashname(PG_FUNCTION_ARGS)
}
#ifdef CATCACHE_STATS
static void
CatCachePrintStats(void)
{
CatCache *cache;
long cc_searches = 0;
long cc_hits = 0;
long cc_newloads = 0;
elog(DEBUG, "Catcache stats dump: %d/%d tuples in catcaches",
CacheHdr->ch_ntup, CacheHdr->ch_maxtup);
for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
{
if (cache->cc_ntup == 0 && cache->cc_searches == 0)
continue; /* don't print unused caches */
elog(DEBUG, "Catcache %s/%s: %d tup, %ld srch, %ld hits, %ld loads, %ld not found",
cache->cc_relname,
cache->cc_indname,
cache->cc_ntup,
cache->cc_searches,
cache->cc_hits,
cache->cc_newloads,
cache->cc_searches - cache->cc_hits - cache->cc_newloads);
cc_searches += cache->cc_searches;
cc_hits += cache->cc_hits;
cc_newloads += cache->cc_newloads;
}
elog(DEBUG, "Catcache totals: %d tup, %ld srch, %ld hits, %ld loads, %ld not found",
CacheHdr->ch_ntup,
cc_searches,
cc_hits,
cc_newloads,
cc_searches - cc_hits - cc_newloads);
}
#endif /* CATCACHE_STATS */
/*
* Standard routine for creating cache context if it doesn't exist yet
*
@ -289,6 +336,30 @@ CatalogCacheInitializeCache(CatCache *cache)
cache->cc_tupdesc = tupdesc;
}
/*
* InitCatCachePhase2 -- external interface for CatalogCacheInitializeCache
*
* The only reason to call this routine is to ensure that the relcache
* has created entries for all the catalogs and indexes referenced by
* catcaches. Therefore, open the index too. An exception is the indexes
* on pg_am, which we don't use (cf. IndexScanOK).
*/
void
InitCatCachePhase2(CatCache *cache)
{
if (cache->cc_tupdesc == NULL)
CatalogCacheInitializeCache(cache);
if (cache->id != AMOID &&
cache->id != AMNAME)
{
Relation idesc;
idesc = index_openr(cache->cc_indname);
index_close(idesc);
}
}
/*
* CatalogCacheComputeHashIndex
*/
@ -644,11 +715,11 @@ CatalogCacheFlushRelation(Oid relId)
{
bool isNull;
tupRelid = DatumGetObjectId(
fastgetattr(&ct->tuple,
cache->cc_reloidattr,
cache->cc_tupdesc,
&isNull));
tupRelid =
DatumGetObjectId(fastgetattr(&ct->tuple,
cache->cc_reloidattr,
cache->cc_tupdesc,
&isNull));
Assert(!isNull);
}
@ -717,20 +788,19 @@ InitCatCache(int id,
CacheHdr->ch_ntup = 0;
CacheHdr->ch_maxtup = MAXCCTUPLES;
DLInitList(&CacheHdr->ch_lrulist);
#ifdef CATCACHE_STATS
on_proc_exit(CatCachePrintStats, 0);
#endif
}
/*
* allocate a new cache structure
*
* Note: we assume zeroing initializes the bucket headers correctly
*/
cp = (CatCache *) palloc(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
MemSet((char *) cp, 0, sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
/*
* initialize the cache buckets (each bucket is a list header)
*/
for (i = 0; i < NCCBUCKETS; ++i)
DLInitList(&cp->cc_bucket[i]);
/*
* initialize the cache's relation information for the relation
* corresponding to this cache, and initialize some of the new cache's
@ -777,57 +847,44 @@ InitCatCache(int id,
* certain system indexes that support critical syscaches.
* We can't use an indexscan to fetch these, else we'll get into
* infinite recursion. A plain heap scan will work, however.
*
* Once we have completed relcache initialization (signaled by
* criticalRelcachesBuilt), we don't have to worry anymore.
*/
static bool
IndexScanOK(CatCache *cache, ScanKey cur_skey)
{
if (cache->id == INDEXRELID)
{
static Oid indexSelfOid = InvalidOid;
/* One-time lookup of the OID of pg_index_indexrelid_index */
if (!OidIsValid(indexSelfOid))
{
Relation rel;
ScanKeyData key;
HeapScanDesc sd;
HeapTuple ntp;
rel = heap_openr(RelationRelationName, AccessShareLock);
ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
F_NAMEEQ,
PointerGetDatum(IndexRelidIndex));
sd = heap_beginscan(rel, false, SnapshotNow, 1, &key);
ntp = heap_getnext(sd, 0);
if (!HeapTupleIsValid(ntp))
elog(ERROR, "IndexScanOK: %s not found in %s",
IndexRelidIndex, RelationRelationName);
indexSelfOid = ntp->t_data->t_oid;
heap_endscan(sd);
heap_close(rel, AccessShareLock);
}
/* Looking for pg_index_indexrelid_index? */
if (DatumGetObjectId(cur_skey[0].sk_argument) == indexSelfOid)
/*
* Since the OIDs of indexes aren't hardwired, it's painful to
* figure out which is which. Just force all pg_index searches
* to be heap scans while building the relcaches.
*/
if (!criticalRelcachesBuilt)
return false;
}
else if (cache->id == AMOPSTRATEGY ||
cache->id == AMPROCNUM)
else if (cache->id == AMOID ||
cache->id == AMNAME)
{
/* Looking for an OID or INT2 btree operator or function? */
Oid lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
if (lookup_oid == OID_BTREE_OPS_OID ||
lookup_oid == INT2_BTREE_OPS_OID)
return false;
/*
* Always do heap scans in pg_am, because it's so small there's
* not much point in an indexscan anyway. We *must* do this when
* initially building critical relcache entries, but we might as
* well just always do it.
*/
return false;
}
else if (cache->id == OPEROID)
{
/* Looking for an OID comparison function? */
Oid lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
if (!criticalRelcachesBuilt)
{
/* Looking for an OID comparison function? */
Oid lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
if (lookup_oid >= MIN_OIDCMP && lookup_oid <= MAX_OIDCMP)
return false;
if (lookup_oid >= MIN_OIDCMP && lookup_oid <= MAX_OIDCMP)
return false;
}
}
/* Normal case, allow index scan */
@ -861,6 +918,10 @@ SearchCatCache(CatCache *cache,
if (cache->cc_tupdesc == NULL)
CatalogCacheInitializeCache(cache);
#ifdef CATCACHE_STATS
cache->cc_searches++;
#endif
/*
* initialize the search key information
*/
@ -919,6 +980,10 @@ SearchCatCache(CatCache *cache,
cache->cc_relname, hash);
#endif /* CACHEDEBUG */
#ifdef CATCACHE_STATS
cache->cc_hits++;
#endif
return &ct->tuple;
}
@ -1046,6 +1111,10 @@ SearchCatCache(CatCache *cache,
DLAddHead(&CacheHdr->ch_lrulist, &ct->lrulist_elem);
DLAddHead(&cache->cc_bucket[hash], &ct->cache_elem);
#ifdef CATCACHE_STATS
cache->cc_newloads++;
#endif
/*
* If we've exceeded the desired size of the caches, try to throw away
* the least recently used entry.

View File

@ -48,6 +48,12 @@
* (XXX is it worth testing likewise for duplicate catcache flush entries?
* Probably not.)
*
* If a relcache flush is issued for a system relation that we preload
* from the relcache init file, we must also delete the init file so that
* it will be rebuilt during the next backend restart. The actual work of
* manipulating the init file is in relcache.c, but we keep track of the
* need for it here.
*
* All the request lists are kept in TopTransactionContext memory, since
* they need not live beyond the end of the current transaction.
*
@ -56,7 +62,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.47 2001/11/16 23:30:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.48 2002/02/19 20:11:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -107,6 +113,8 @@ typedef struct InvalidationListHeader
*/
static InvalidationListHeader GlobalInvalidMsgs;
static bool RelcacheInitFileInval; /* init file must be invalidated? */
/*
* head of invalidation message list for the current command
* eaten by AtCommit_LocalCache() in CommandCounterIncrement()
@ -339,6 +347,13 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId)
dbId, relId);
AddRelcacheInvalidationMessage(&LocalInvalidMsgs,
dbId, relId);
/*
* If the relation being invalidated is one of those cached in the
* relcache init file, mark that we need to zap that file at commit.
*/
if (RelationIdIsInInitFile(relId))
RelcacheInitFileInval = true;
}
/*
@ -418,8 +433,8 @@ InvalidateSystemCaches(void)
/*
* PrepareForTupleInvalidation
* Invoke functions for the tuple which register invalidation
* of catalog/relation cache.
* Detect whether invalidation of this tuple implies invalidation
* of catalog/relation cache entries; if so, register inval events.
*/
static void
PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
@ -525,8 +540,19 @@ AtEOXactInvalidationMessages(bool isCommit)
{
if (isCommit)
{
/*
* Relcache init file invalidation requires processing both
* before and after we send the SI messages. However, we need
* not do anything unless we committed.
*/
if (RelcacheInitFileInval)
RelationCacheInitFileInvalidate(true);
ProcessInvalidationMessages(&GlobalInvalidMsgs,
SendSharedInvalidMessage);
if (RelcacheInitFileInval)
RelationCacheInitFileInvalidate(false);
}
else
{
@ -534,6 +560,8 @@ AtEOXactInvalidationMessages(bool isCommit)
LocalExecuteInvalidationMessage);
}
RelcacheInitFileInval = false;
DiscardInvalidationMessages(&GlobalInvalidMsgs, false);
DiscardInvalidationMessages(&LocalInvalidMsgs, false);
DiscardInvalidationMessages(&RollbackMsgs, false);

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.66 2001/10/25 05:49:46 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.67 2002/02/19 20:11:18 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@ -113,6 +113,16 @@ static struct cachedesc cacheinfo[] = {
0,
0
}},
{AccessMethodRelationName, /* AMOID */
AmOidIndex,
0,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
}},
{AccessMethodOperatorRelationName, /* AMOPOPID */
AccessMethodOperatorIndex,
0,
@ -365,8 +375,7 @@ static struct cachedesc cacheinfo[] = {
}}
};
static CatCache *SysCache[
lengthof(cacheinfo)];
static CatCache *SysCache[lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
@ -383,7 +392,7 @@ IsCacheInitialized(void)
*
* Note that no database access is done here; we only allocate memory
* and initialize the cache structure. Interrogation of the database
* to complete initialization of a cache happens only upon first use
* to complete initialization of a cache happens upon first use
* of that cache.
*/
void
@ -411,6 +420,32 @@ InitCatalogCache(void)
}
/*
* InitCatalogCachePhase2 - finish initializing the caches
*
* Finish initializing all the caches, including necessary database
* access.
*
* This is *not* essential; normally we allow syscaches to be initialized
* on first use. However, it is useful as a mechanism to preload the
* relcache with entries for the most-commonly-used system catalogs.
* Therefore, we invoke this routine when we need to write a new relcache
* init file.
*/
void
InitCatalogCachePhase2(void)
{
int cacheId;
Assert(CacheInitialized);
for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
{
InitCatCachePhase2(SysCache[cacheId]);
}
}
/*
* SearchSysCache
*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.97 2001/11/02 16:30:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.98 2002/02/19 20:11:18 tgl Exp $
*
*
*-------------------------------------------------------------------------
@ -287,16 +287,15 @@ InitPostgres(const char *dbname, const char *username)
AmiTransactionOverride(bootstrap);
/*
* Initialize the relation descriptor cache. The pre-allocated
* reldescs are created here.
* Initialize the relation descriptor cache. This must create
* at least the minimum set of "nailed-in" cache entries. No
* catalog access happens here.
*/
RelationCacheInitialize();
/*
* Initialize all the system catalog caches.
*
* Does not touch files since all routines are builtins (?) - thomas
* 1997-11-01
* Initialize all the system catalog caches. Note that no catalog
* access happens here; we only set up the cache structure.
*/
InitCatalogCache();
@ -313,7 +312,11 @@ InitPostgres(const char *dbname, const char *username)
if (!bootstrap)
StartTransactionCommand();
/* replace faked-up relcache entries with the real info */
/*
* It's now possible to do real access to the system catalogs.
*
* Replace faked-up relcache entries with correct info.
*/
RelationCacheInitializePhase2();
/*
@ -333,8 +336,10 @@ InitPostgres(const char *dbname, const char *username)
}
}
else
{
/* normal multiuser case */
InitializeSessionUserId(username);
}
/*
* Unless we are bootstrapping, double-check that InitMyDatabaseInfo()
@ -349,6 +354,13 @@ InitPostgres(const char *dbname, const char *username)
set_default_client_encoding();
#endif
/*
* Final phase of relation cache startup: write a new cache file
* if necessary. This is done after ReverifyMyDatabase to avoid
* writing a cache file into a dead database.
*/
RelationCacheInitializePhase3();
/*
* Set up process-exit callbacks to remove temp relations and then do
* pre-shutdown cleanup. This should be last because we want

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: genam.h,v 1.31 2001/11/05 17:46:31 momjian Exp $
* $Id: genam.h,v 1.32 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -31,9 +31,23 @@ typedef struct IndexBulkDeleteResult
typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state);
/* ----------------
* generalized index_ interface routines (in indexam.c)
* ----------------
/* Struct for heap-or-index scans of system tables */
typedef struct SysScanDescData
{
Relation heap_rel; /* catalog being scanned */
Snapshot snapshot; /* time qual (normally SnapshotNow) */
Relation irel; /* NULL if doing heap scan */
HeapScanDesc scan; /* only valid in heap-scan case */
IndexScanDesc iscan; /* only valid in index-scan case */
HeapTupleData tuple; /* workspace for indexscan */
Buffer buffer; /* working state for indexscan */
} SysScanDescData;
typedef SysScanDescData *SysScanDesc;
/*
* generalized index_ interface routines (in indexam.c)
*/
extern Relation index_open(Oid relationId);
extern Relation index_openr(const char *relationName);
@ -59,9 +73,22 @@ extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
extern struct FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,
uint16 procnum);
/* in genam.c */
/*
* index access method support routines (in genam.c)
*/
extern IndexScanDesc RelationGetIndexScan(Relation relation, bool scanFromEnd,
uint16 numberOfKeys, ScanKey key);
extern void IndexScanEnd(IndexScanDesc scan);
/*
* heap-or-index access to system catalogs (in genam.c)
*/
extern SysScanDesc systable_beginscan(Relation rel,
const char *indexRelname,
bool indexOK,
Snapshot snapshot,
unsigned nkeys, ScanKey key);
extern HeapTuple systable_getnext(SysScanDesc sysscan);
extern void systable_endscan(SysScanDesc sysscan);
#endif /* GENAM_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: istrat.h,v 1.23 2001/11/05 17:46:31 momjian Exp $
* $Id: istrat.h,v 1.24 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -47,6 +47,8 @@
*/
#define IndexStrategyIsValid(s) PointerIsValid(s)
extern ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
StrategyNumber strategyNumber);
extern StrategyMap IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
StrategyNumber maxStrategyNum, AttrNumber attrNum);
@ -55,13 +57,5 @@ extern Size AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber,
extern StrategyNumber RelationGetStrategy(Relation relation,
AttrNumber attributeNumber, StrategyEvaluation evaluation,
RegProcedure procedure);
extern void IndexSupportInitialize(IndexStrategy indexStrategy,
RegProcedure *indexSupport,
bool *isUnique,
Oid indexObjectId,
Oid accessMethodObjectId,
StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber);
#endif /* ISTRAT_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: index.h,v 1.43 2001/11/05 17:46:31 momjian Exp $
* $Id: index.h,v 1.44 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,6 +15,7 @@
#define INDEX_H
#include "access/itup.h"
#include "catalog/pg_index.h"
#include "nodes/execnodes.h"
@ -27,9 +28,6 @@ typedef void (*IndexBuildCallback) (Relation index,
void *state);
extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
MemoryContext resultCxt);
extern Oid index_create(char *heapRelationName,
char *indexRelationName,
IndexInfo *indexInfo,
@ -40,7 +38,7 @@ extern Oid index_create(char *heapRelationName,
extern void index_drop(Oid indexId);
extern IndexInfo *BuildIndexInfo(HeapTuple indexTuple);
extern IndexInfo *BuildIndexInfo(Form_pg_index indexStruct);
extern void FormIndexDatum(IndexInfo *indexInfo,
HeapTuple heapTuple,

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: indexing.h,v 1.56 2001/11/05 17:46:31 momjian Exp $
* $Id: indexing.h,v 1.57 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -123,15 +123,6 @@ extern void CatalogCloseIndices(int nIndices, Relation *idescs);
extern void CatalogIndexInsert(Relation *idescs, int nIndices,
Relation heapRelation, HeapTuple heapTuple);
/*
* Canned functions for indexscans on certain system indexes.
* All index-value arguments should be passed as Datum for portability!
*/
extern HeapTuple AttributeRelidNumIndexScan(Relation heapRelation,
Datum relid, Datum attnum);
extern HeapTuple ClassNameIndexScan(Relation heapRelation, Datum relName);
extern HeapTuple ClassOidIndexScan(Relation heapRelation, Datum relId);
/*
* These macros are just to keep the C compiler from spitting up on the

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: executor.h,v 1.61 2001/11/05 17:46:33 momjian Exp $
* $Id: executor.h,v 1.62 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,13 +30,7 @@
/*
* prototypes from functions in execAmi.c
*/
extern void ExecOpenScanR(Oid relOid, int nkeys, ScanKey skeys, bool isindex,
ScanDirection dir, Snapshot snapshot,
Relation *returnRelation, Pointer *returnScanDesc);
extern void ExecCloseR(Plan *node);
extern void ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent);
extern HeapScanDesc ExecReScanR(Relation relDesc, HeapScanDesc scanDesc,
ScanDirection direction, int nkeys, ScanKey skeys);
extern void ExecMarkPos(Plan *node);
extern void ExecRestrPos(Plan *node);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: lwlock.h,v 1.4 2001/11/05 17:46:35 momjian Exp $
* $Id: lwlock.h,v 1.5 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -38,6 +38,7 @@ typedef enum LWLockId
ControlFileLock,
CheckpointLock,
CLogControlLock,
RelCacheInitLock,
NumFixedLWLocks, /* must be last except for
* MaxDynamicLWLock */

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catcache.h,v 1.37 2001/11/05 17:46:36 momjian Exp $
* $Id: catcache.h,v 1.38 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -44,6 +44,12 @@ typedef struct catcache
int cc_key[4]; /* AttrNumber of each key */
PGFunction cc_hashfunc[4]; /* hash function to use for each key */
ScanKeyData cc_skey[4]; /* precomputed key info for heap scans */
#ifdef CATCACHE_STATS
long cc_searches; /* total # searches against this cache */
long cc_hits; /* # of matches against existing entry */
long cc_newloads; /* # of successful loads of new entry */
/* cc_searches - (cc_hits + cc_newloads) is # of failed searches */
#endif
Dllist cc_bucket[1]; /* hash buckets --- VARIABLE LENGTH ARRAY */
} CatCache; /* VARIABLE LENGTH STRUCT */
@ -89,6 +95,7 @@ extern void AtEOXact_CatCache(bool isCommit);
extern CatCache *InitCatCache(int id, char *relname, char *indname,
int reloidattr,
int nkeys, int *key);
extern void InitCatCachePhase2(CatCache *cache);
extern HeapTuple SearchCatCache(CatCache *cache,
Datum v1, Datum v2,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: rel.h,v 1.55 2001/11/05 17:46:36 momjian Exp $
* $Id: rel.h,v 1.56 2002/02/19 20:11:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -18,6 +18,7 @@
#include "access/tupdesc.h"
#include "catalog/pg_am.h"
#include "catalog/pg_class.h"
#include "catalog/pg_index.h"
#include "rewrite/prs2lock.h"
#include "storage/block.h"
#include "storage/fd.h"
@ -113,19 +114,23 @@ typedef struct RelationData
bool rd_isnailed; /* rel is nailed in cache */
bool rd_indexfound; /* true if rd_indexlist is valid */
bool rd_uniqueindex; /* true if rel is a UNIQUE index */
Form_pg_am rd_am; /* AM tuple (if an index) */
Form_pg_class rd_rel; /* RELATION tuple */
TupleDesc rd_att; /* tuple descriptor */
Oid rd_id; /* relation's object id */
List *rd_indexlist; /* list of OIDs of indexes on relation */
LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */
TupleDesc rd_att; /* tuple descriptor */
RuleLock *rd_rules; /* rewrite rules */
MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */
TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */
/* These are non-NULL only for an index relation: */
Form_pg_index rd_index; /* pg_index tuple describing this index */
Form_pg_am rd_am; /* pg_am tuple for index's AM */
/* index access support info (used only for an index relation) */
MemoryContext rd_indexcxt; /* private memory cxt for this stuff */
IndexStrategy rd_istrat; /* operator strategy map */
Oid *rd_operator; /* OIDs of index operators */
RegProcedure *rd_support; /* OIDs of support procedures */
struct FmgrInfo *rd_supportinfo; /* lookup info for support
* procedures */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: relcache.h,v 1.29 2001/11/05 17:46:36 momjian Exp $
* $Id: relcache.h,v 1.30 2002/02/19 20:11:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,6 +40,7 @@ extern void RelationInitIndexAccessInfo(Relation relation);
*/
extern void RelationCacheInitialize(void);
extern void RelationCacheInitializePhase2(void);
extern void RelationCacheInitializePhase3(void);
/*
* Routine to create a relcache entry for an about-to-be-created relation
@ -62,15 +63,18 @@ extern void RelationPurgeLocalRelation(bool xactComitted);
extern void RelationCacheAbort(void);
/*
* Routines to help manage rebuilding of relcache init file
*/
extern bool RelationIdIsInInitFile(Oid relationId);
extern void RelationCacheInitFileInvalidate(bool beforeSend);
/* XLOG support */
extern void CreateDummyCaches(void);
extern void DestroyDummyCaches(void);
/*
* both vacuum.c and relcache.c need to know the name of the relcache init file
*/
#define RELCACHE_INIT_FILENAME "pg_internal.init"
/* should be used only by relcache.c and catcache.c */
extern bool criticalRelcachesBuilt;
#endif /* RELCACHE_H */

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: syscache.h,v 1.36 2001/11/05 17:46:36 momjian Exp $
* $Id: syscache.h,v 1.37 2002/02/19 20:11:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,33 +30,35 @@
#define AGGNAME 0
#define AMNAME 1
#define AMOPOPID 2
#define AMOPSTRATEGY 3
#define AMPROCNUM 4
#define ATTNAME 5
#define ATTNUM 6
#define CLAAMNAME 7
#define CLAOID 8
#define GRONAME 9
#define GROSYSID 10
#define INDEXRELID 11
#define INHRELID 12
#define LANGNAME 13
#define LANGOID 14
#define OPERNAME 15
#define OPEROID 16
#define PROCNAME 17
#define PROCOID 18
#define RELNAME 19
#define RELOID 20
#define RULENAME 21
#define SHADOWNAME 22
#define SHADOWSYSID 23
#define STATRELATT 24
#define TYPENAME 25
#define TYPEOID 26
#define AMOID 2
#define AMOPOPID 3
#define AMOPSTRATEGY 4
#define AMPROCNUM 5
#define ATTNAME 6
#define ATTNUM 7
#define CLAAMNAME 8
#define CLAOID 9
#define GRONAME 10
#define GROSYSID 11
#define INDEXRELID 12
#define INHRELID 13
#define LANGNAME 14
#define LANGOID 15
#define OPERNAME 16
#define OPEROID 17
#define PROCNAME 18
#define PROCOID 19
#define RELNAME 20
#define RELOID 21
#define RULENAME 22
#define SHADOWNAME 23
#define SHADOWSYSID 24
#define STATRELATT 25
#define TYPENAME 26
#define TYPEOID 27
extern void InitCatalogCache(void);
extern void InitCatalogCachePhase2(void);
extern HeapTuple SearchSysCache(int cacheId,
Datum key1, Datum key2, Datum key3, Datum key4);