*
*
* 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
* 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
*
}
#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);
+}
*
*
* 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,
* Assumes that the index strategy number is valid.
* Bounds checking should be done outside this routine.
*/
-static ScanKey
+ScanKey
StrategyMapGetScanKeyEntry(StrategyMap map,
StrategyNumber strategyNumber)
{
}
#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
* ----------------
*
*
* 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
static void
RelationRemoveIndexes(Relation relation)
{
- Relation indexRelation;
- HeapTuple tuple;
- HeapScanDesc scan;
- ScanKeyData entry;
-
- indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
+ List *indexoidlist,
+ *indexoidscan;
- ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid,
- F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(relation)));
-
- scan = heap_beginscan(indexRelation,
- false,
- SnapshotNow,
- 1,
- &entry);
+ indexoidlist = RelationGetIndexList(relation);
- 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);
}
/* --------------------------------
{
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,
/*
* 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
}
/* Complete the scan and close pg_index */
- heap_endscan(scan);
+ systable_endscan(scan);
heap_close(indexRelation, AccessShareLock);
}
*
*
* 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
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
* ----------------------------------------------------------------
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.
* ----------------
*/
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;
}
/* 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;
reindex_index(Oid indexId, bool force, bool inplace)
{
Relation iRel,
- indexRelation,
heapRelation;
- ScanKeyData entry;
- HeapScanDesc scan;
- HeapTuple indexTuple;
IndexInfo *indexInfo;
Oid heapId;
bool old;
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
-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
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,
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;
-}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
OIDNewHeap;
Relation OldHeap,
OldIndex;
- HeapTuple tuple;
bool istemp;
char NewHeapName[NAMEDATALEN];
char NewIndexName[NAMEDATALEN];
/*
* 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);
{
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);
* 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);
*
*
* 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
#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"
#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
*/
/*
* 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)))
{
}
}
}
+
systable_endscan(sysscan);
heap_close(rcrel, NoLock);
* 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 $
*
*-------------------------------------------------------------------------
*/
char nulls[Natts_pg_trigger];
Relation rel;
Relation tgrel;
- HeapScanDesc tgscan;
+ SysScanDesc tgscan;
ScanKeyData key;
Relation pgrel;
HeapTuple tuple;
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);
stmt->trigname, stmt->relname);
found++;
}
- heap_endscan(tgscan);
+ systable_endscan(tgscan);
/*
* Find and validate the trigger function.
{
Relation rel;
Relation tgrel;
- HeapScanDesc tgscan;
+ SysScanDesc tgscan;
ScanKeyData key;
Relation pgrel;
HeapTuple tuple;
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);
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
RelationRemoveTriggers(Relation rel)
{
Relation tgrel;
- HeapScanDesc tgscan;
+ SysScanDesc tgscan;
ScanKeyData key;
HeapTuple tup;
bool found = false;
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));
found = true;
}
- heap_endscan(tgscan);
+ systable_endscan(tgscan);
/*
* If we deleted any triggers, must update pg_class entry and advance
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;
pfree(stmt.relname);
pfree(stmt.trigname);
}
- heap_endscan(tgscan);
+ systable_endscan(tgscan);
heap_close(tgrel, RowExclusiveLock);
}
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));
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++)
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 ...
* ----------
*/
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
*/
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)
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())
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
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);
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
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);
}
* 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"
#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
}
}
-/* ----------------------------------------------------------------
- * 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
*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
Oid indexOid = lfirsti(indexoidscan);
Relation indexDesc;
- HeapTuple indexTuple;
IndexInfo *ii;
/*
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
*/
if (run_keys[j] != NO_OP)
{
- Expr *clause = nth(j, qual);
Node *scanexpr;
Datum scanvalue;
bool isNull;
List *indxqual;
int *numScanKeys;
int numIndices;
+ Relation relation;
+ RelationPtr indexRelationDescs;
+ IndexScanDescPtr indexScanDescs;
int i;
scanstate = node->scan.scanstate;
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
FreeExprContext(indexstate->iss_RuntimeContext);
/*
- * close the heap and index relations
+ * close the index relations
+ */
+ 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.)
*/
- ExecCloseR((Plan *) node);
+ heap_close(relation, NoLock);
/*
* free the scan keys used in scanning the indices
CommonScanState *scanstate;
List *indxqual;
List *indxid;
+ List *listscan;
int i;
int numIndices;
int indexPtr;
Index relid;
Oid reloid;
Relation currentRelation;
- HeapScanDesc currentScanDesc;
ScanDirection direction;
/*
* 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 */
/*
* 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))
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, /* */
- ¤tRelation, /* return: rel desc */
- (Pointer *) ¤tScanDesc); /* 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.
/*
* 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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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;
reloid = rtentry->relid;
direction = estate->es_direction;
- ExecOpenScanR(reloid, /* relation */
- 0, /* nkeys */
- NULL, /* scan key */
- false, /* is index */
- direction, /* scan direction */
- estate->es_snapshot,
- ¤tRelation, /* return: rel desc */
- (Pointer *) ¤tScanDesc); /* 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;
{
CommonScanState *scanstate;
Oid reloid;
- HeapScanDesc scandesc;
/*
* Once upon a time it was possible to have an outerPlan of a SeqScan,
*/
reloid = InitScanRelation(node, estate, scanstate);
- scandesc = scanstate->css_currentScanDesc;
scanstate->cstate.cs_TupFromTlist = false;
/*
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
ExecFreeExprContext(&scanstate->cstate);
/*
- * close scan relation
+ * close heap scan
+ */
+ 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.)
*/
- ExecCloseR((Plan *) node);
+ heap_close(relation, NoLock);
/*
* clean out the tuple table
{
CommonScanState *scanstate;
EState *estate;
- Relation rel;
HeapScanDesc scan;
ScanDirection direction;
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 */
}
/* ----------------------------------------------------------------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
*
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
/*
* 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.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
/*
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 ?? */
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.
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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];
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));
ncandidates++;
}
- heap_endscan(pg_aggregate_scan);
+ systable_endscan(pg_aggregate_scan);
heap_close(pg_aggregate_desc, AccessShareLock);
return ncandidates;
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);
-
- sd = index_beginscan(idesc, false, 1, &skey);
+ funcscan = systable_beginscan(heapRelation, ProcedureNameIndex, true,
+ SnapshotNow, 2, skey);
- do
+ while (HeapTupleIsValid(tuple = systable_getnext(funcscan)))
{
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (indexRes)
- {
- Buffer buffer;
-
- 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->next = candidates;
- candidates = current_candidate;
- }
- ReleaseBuffer(buffer);
- }
- }
- } while (indexRes);
+ Form_pg_proc pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
+ CandidateList current_candidate;
+
+ 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;
+ }
- index_endscan(sd);
- index_close(idesc);
+ systable_endscan(funcscan);
heap_close(heapRelation, AccessShareLock);
return candidates;
*
*
* 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"
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;
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);
+
+ if (oper->oprkind == 'b')
+ {
+ CandidateList current_candidate;
- current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
- current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
+ 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++;
+ 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
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
*
* 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.
*
HeapTuple ht_idx;
HeapTuple ht_idxrel;
HeapTuple ht_indrel;
+ HeapTuple ht_am;
Form_pg_index idxrec;
Form_pg_class idxrelrec;
Form_pg_class indrelrec;
/*
* 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
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
HeapTuple tuple);
static void CatalogCacheInitializeCache(CatCache *cache);
static Datum cc_hashname(PG_FUNCTION_ARGS);
+#ifdef CATCACHE_STATS
+static void CatCachePrintStats(void);
+#endif
/*
}
+#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
*
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
*/
{
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);
}
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
* 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 */
if (cache->cc_tupdesc == NULL)
CatalogCacheInitializeCache(cache);
+#ifdef CATCACHE_STATS
+ cache->cc_searches++;
+#endif
+
/*
* initialize the search key information
*/
cache->cc_relname, hash);
#endif /* CACHEDEBUG */
+#ifdef CATCACHE_STATS
+ cache->cc_hits++;
+#endif
+
return &ct->tuple;
}
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.
* (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.
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
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()
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;
}
/*
/*
* 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,
{
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
{
LocalExecuteInvalidationMessage);
}
+ RelcacheInitFileInval = false;
+
DiscardInvalidationMessages(&GlobalInvalidMsgs, false);
DiscardInvalidationMessages(&LocalInvalidMsgs, false);
DiscardInvalidationMessages(&RollbackMsgs, false);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.151 2002/01/16 17:34:42 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.152 2002/02/19 20:11:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/catname.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
+#include "catalog/pg_attribute.h"
#include "catalog/pg_index.h"
+#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_relcheck.h"
#include "catalog/pg_rewrite.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
-#include "utils/hsearch.h"
-#include "utils/memutils.h"
+#include "utils/inval.h"
+#include "utils/lsyscache.h"
#include "utils/relcache.h"
+#include "utils/syscache.h"
#include "utils/temprel.h"
+/*
+ * name of relcache init file, used to speed up backend startup
+ */
+#define RELCACHE_INIT_FILENAME "pg_internal.init"
+
/*
* hardcoded tuple descriptors. see lib/backend/catalog/pg_attribute.h
*/
* relations created during this transaction. We need to keep track of
* these.
*/
-static List *newlyCreatedRelns = NULL;
+static List *newlyCreatedRelns = NIL;
/*
* This flag is false until we have prepared the critical relcache entries
* that are needed to do indexscans on the tables read by relcache building.
*/
-static bool criticalRelcachesBuilt = false;
+bool criticalRelcachesBuilt = false;
+
+/*
+ * This flag is set if we discover that we need to write a new relcache
+ * cache file at the end of startup.
+ */
+static bool needNewCacheFile = false;
+
+/*
+ * This counter counts relcache inval events received since backend startup
+ * (but only for rels that are actually in cache). Presently, we use it only
+ * to detect whether data about to be written by write_relcache_init_file()
+ * might already be obsolete.
+ */
+static long relcacheInvalsReceived = 0L;
+/*
+ * This list remembers the OIDs of the relations cached in the relcache
+ * init file.
+ */
+static List *initFileRelationIds = NIL;
/*
* RelationBuildDescInfo exists so code can be shared
elog(NOTICE, "trying to delete a reldesc that does not exist."); \
} while(0)
+
+/*
+ * Special cache for opclass-related information
+ */
+typedef struct opclasscacheent
+{
+ Oid opclassoid; /* lookup key: OID of opclass */
+ bool valid; /* set TRUE after successful fill-in */
+ StrategyNumber numStrats; /* max # of strategies (from pg_am) */
+ StrategyNumber numSupport; /* max # of support procs (from pg_am) */
+ Oid *operatorOids; /* strategy operators' OIDs */
+ RegProcedure *operatorProcs; /* strategy operators' procs */
+ RegProcedure *supportProcs; /* support procs */
+} OpClassCacheEnt;
+
+static HTAB *OpClassCache = NULL;
+
+
/* non-export function prototypes */
static void RelationClearRelation(Relation relation, bool rebuildIt);
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
static void RelationFlushRelation(Relation relation);
static Relation RelationNameCacheGetRelation(const char *relationName);
-static void init_irels(void);
-static void write_irels(void);
+static bool load_relcache_init_file(void);
+static void write_relcache_init_file(void);
static void formrdesc(char *relationName, int natts,
FormData_pg_attribute *att);
-static void fixrdesc(char *relationName);
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
-static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
-static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
Relation relation);
-static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
- Relation relation);
-static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
- Relation relation);
static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
Relation oldrelation);
static void AttrDefaultFetch(Relation relation);
static void RelCheckFetch(Relation relation);
static List *insert_ordered_oid(List *list, Oid datum);
+static void IndexSupportInitialize(Form_pg_index iform,
+ IndexStrategy indexStrategy,
+ Oid *indexOperator,
+ RegProcedure *indexSupport,
+ StrategyNumber maxStrategyNumber,
+ StrategyNumber maxSupportNumber,
+ AttrNumber maxAttributeNumber);
+static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
+ StrategyNumber numStrats,
+ StrategyNumber numSupport);
/*
*/
static HeapTuple
ScanPgRelation(RelationBuildDescInfo buildinfo)
-{
- /*
- * If this is bootstrap time (initdb), then we can't use the system
- * catalog indices, because they may not exist yet. Otherwise, we
- * can, and do.
- */
-
- if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
- return scan_pg_rel_seq(buildinfo);
- else
- return scan_pg_rel_ind(buildinfo);
-}
-
-static HeapTuple
-scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
{
HeapTuple pg_class_tuple;
- HeapTuple return_tuple;
Relation pg_class_desc;
- HeapScanDesc pg_class_scan;
+ const char *indexRelname;
+ SysScanDesc pg_class_scan;
ScanKeyData key;
/*
ObjectIdAttributeNumber,
F_OIDEQ,
ObjectIdGetDatum(buildinfo.i.info_id));
+ indexRelname = ClassOidIndex;
break;
case INFO_RELNAME:
Anum_pg_class_relname,
F_NAMEEQ,
NameGetDatum(buildinfo.i.info_name));
+ indexRelname = ClassNameIndex;
break;
default:
elog(ERROR, "ScanPgRelation: bad buildinfo");
- return NULL;
+ return NULL; /* keep compiler quiet */
}
/*
- * open pg_class and fetch a tuple
+ * Open pg_class and fetch a tuple. Force heap scan if we haven't
+ * yet built the critical relcache entries (this includes initdb
+ * and startup without a pg_internal.init file).
*/
pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
- pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key);
- pg_class_tuple = heap_getnext(pg_class_scan, 0);
-
- /*
- * get set to return tuple
- */
- if (!HeapTupleIsValid(pg_class_tuple))
- return_tuple = pg_class_tuple;
- else
- {
- /*
- * a satanic bug used to live here: pg_class_tuple used to be
- * returned here without having the corresponding buffer pinned.
- * so when the buffer gets replaced, all hell breaks loose. this
- * bug is discovered and killed by wei on 9/27/91.
- */
- return_tuple = heap_copytuple(pg_class_tuple);
- }
-
- /* all done */
- heap_endscan(pg_class_scan);
- heap_close(pg_class_desc, AccessShareLock);
-
- return return_tuple;
-}
+ pg_class_scan = systable_beginscan(pg_class_desc, indexRelname,
+ criticalRelcachesBuilt,
+ SnapshotNow,
+ 1, &key);
-static HeapTuple
-scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
-{
- Relation pg_class_desc;
- HeapTuple return_tuple;
-
- pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
+ pg_class_tuple = systable_getnext(pg_class_scan);
/*
- * If the indexes of pg_class are deactivated we have to call
- * scan_pg_rel_seq() instead.
+ * Must copy tuple before releasing buffer.
*/
- if (!pg_class_desc->rd_rel->relhasindex)
- {
- heap_close(pg_class_desc, AccessShareLock);
- return scan_pg_rel_seq(buildinfo);
- }
-
- switch (buildinfo.infotype)
- {
- case INFO_RELID:
- return_tuple = ClassOidIndexScan(pg_class_desc,
- ObjectIdGetDatum(buildinfo.i.info_id));
- break;
-
- case INFO_RELNAME:
- return_tuple = ClassNameIndexScan(pg_class_desc,
- PointerGetDatum(buildinfo.i.info_name));
- break;
-
- default:
- elog(ERROR, "ScanPgRelation: bad buildinfo");
- return_tuple = NULL; /* keep compiler quiet */
- }
+ if (HeapTupleIsValid(pg_class_tuple))
+ pg_class_tuple = heap_copytuple(pg_class_tuple);
+ /* all done */
+ systable_endscan(pg_class_scan);
heap_close(pg_class_desc, AccessShareLock);
- /* The xxxIndexScan routines will have returned a palloc'd tuple. */
-
- return return_tuple;
+ return pg_class_tuple;
}
/*
* RelationBuildTupleDesc
*
* Form the relation's tuple descriptor from information in
- * the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
+ * the pg_attribute, pg_attrdef & pg_relcheck system catalogs.
*/
static void
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
Relation relation)
-{
- /*
- * If this is bootstrap time (initdb), then we can't use the system
- * catalog indices, because they may not exist yet. Otherwise, we
- * can, and do.
- */
-
- if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
- build_tupdesc_seq(buildinfo, relation);
- else
- build_tupdesc_ind(buildinfo, relation);
-}
-
-static void
-SetConstrOfRelation(Relation relation,
- TupleConstr *constr,
- int ndef,
- AttrDefault *attrdef)
-{
- if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
- {
- relation->rd_att->constr = constr;
-
- if (ndef > 0) /* DEFAULTs */
- {
- if (ndef < relation->rd_rel->relnatts)
- constr->defval = (AttrDefault *)
- repalloc(attrdef, ndef * sizeof(AttrDefault));
- else
- constr->defval = attrdef;
- constr->num_defval = ndef;
- AttrDefaultFetch(relation);
- }
- else
- constr->num_defval = 0;
-
- if (relation->rd_rel->relchecks > 0) /* CHECKs */
- {
- constr->num_check = relation->rd_rel->relchecks;
- constr->check = (ConstrCheck *)
- MemoryContextAlloc(CacheMemoryContext,
- constr->num_check * sizeof(ConstrCheck));
- MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
- RelCheckFetch(relation);
- }
- else
- constr->num_check = 0;
- }
- else
- {
- pfree(constr);
- relation->rd_att->constr = NULL;
- }
-}
-
-static void
-build_tupdesc_seq(RelationBuildDescInfo buildinfo,
- Relation relation)
{
HeapTuple pg_attribute_tuple;
Relation pg_attribute_desc;
- HeapScanDesc pg_attribute_scan;
- Form_pg_attribute attp;
- ScanKeyData key;
+ SysScanDesc pg_attribute_scan;
+ ScanKeyData skey[2];
int need;
TupleConstr *constr;
AttrDefault *attrdef = NULL;
constr->has_not_null = false;
/*
- * form a scan key
+ * Form a scan key that selects only user attributes (attnum > 0).
+ * (Eliminating system attribute rows at the index level is lots
+ * faster than fetching them.)
*/
- ScanKeyEntryInitialize(&key, 0,
+ ScanKeyEntryInitialize(&skey[0], 0,
Anum_pg_attribute_attrelid,
F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation)));
+ ScanKeyEntryInitialize(&skey[1], 0,
+ Anum_pg_attribute_attnum,
+ F_INT2GT,
+ Int16GetDatum(0));
/*
- * open pg_attribute and begin a scan
+ * Open pg_attribute and begin a scan. Force heap scan if we haven't
+ * yet built the critical relcache entries (this includes initdb
+ * and startup without a pg_internal.init file).
*/
pg_attribute_desc = heap_openr(AttributeRelationName, AccessShareLock);
- pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key);
+ pg_attribute_scan = systable_beginscan(pg_attribute_desc,
+ AttributeRelidNumIndex,
+ criticalRelcachesBuilt,
+ SnapshotNow,
+ 2, skey);
/*
* add attribute data to relation->rd_att
*/
need = relation->rd_rel->relnatts;
- pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
- while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
+ while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
{
+ Form_pg_attribute attp;
+
attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
- if (attp->attnum > 0)
- {
- relation->rd_att->attrs[attp->attnum - 1] =
- (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
+ if (attp->attnum <= 0 ||
+ attp->attnum > relation->rd_rel->relnatts)
+ elog(ERROR, "Bogus attribute number %d for %s",
+ attp->attnum, RelationGetRelationName(relation));
+
+ relation->rd_att->attrs[attp->attnum - 1] =
+ (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
ATTRIBUTE_TUPLE_SIZE);
- memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
- (char *) attp,
- ATTRIBUTE_TUPLE_SIZE);
- need--;
+ memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
+ (char *) attp,
+ ATTRIBUTE_TUPLE_SIZE);
- /* Update if this attribute have a constraint */
- if (attp->attnotnull)
- constr->has_not_null = true;
+ /* Update constraint/default info */
+ if (attp->attnotnull)
+ constr->has_not_null = true;
- if (attp->atthasdef)
+ if (attp->atthasdef)
+ {
+ if (attrdef == NULL)
{
- if (attrdef == NULL)
- {
- attrdef = (AttrDefault *)
- MemoryContextAlloc(CacheMemoryContext,
- relation->rd_rel->relnatts *
- sizeof(AttrDefault));
- MemSet(attrdef, 0,
+ attrdef = (AttrDefault *)
+ MemoryContextAlloc(CacheMemoryContext,
+ relation->rd_rel->relnatts *
+ sizeof(AttrDefault));
+ MemSet(attrdef, 0,
relation->rd_rel->relnatts * sizeof(AttrDefault));
- }
- attrdef[ndef].adnum = attp->attnum;
- attrdef[ndef].adbin = NULL;
- ndef++;
}
+ attrdef[ndef].adnum = attp->attnum;
+ attrdef[ndef].adbin = NULL;
+ ndef++;
}
- pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
+ need--;
+ if (need == 0)
+ break;
}
- if (need > 0)
- elog(ERROR, "catalog is missing %d attribute%s for relid %u",
- need, (need == 1 ? "" : "s"), RelationGetRelid(relation));
-
/*
* end the scan and close the attribute relation
*/
- heap_endscan(pg_attribute_scan);
+ systable_endscan(pg_attribute_scan);
heap_close(pg_attribute_desc, AccessShareLock);
+ if (need != 0)
+ elog(ERROR, "catalog is missing %d attribute(s) for relid %u",
+ need, RelationGetRelid(relation));
+
/*
* The attcacheoff values we read from pg_attribute should all be -1
* ("unknown"). Verify this if assert checking is on. They will be
*/
relation->rd_att->attrs[0]->attcacheoff = 0;
- SetConstrOfRelation(relation, constr, ndef, attrdef);
-}
-
-static void
-build_tupdesc_ind(RelationBuildDescInfo buildinfo,
- Relation relation)
-{
- Relation attrel;
- HeapTuple atttup;
- Form_pg_attribute attp;
- TupleConstr *constr;
- AttrDefault *attrdef = NULL;
- int ndef = 0;
- int i;
-
- constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
- sizeof(TupleConstr));
- constr->has_not_null = false;
-
- attrel = heap_openr(AttributeRelationName, AccessShareLock);
-
- for (i = 1; i <= relation->rd_rel->relnatts; i++)
+ /*
+ * Set up constraint/default info
+ */
+ if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
{
-#ifdef _DROP_COLUMN_HACK__
- bool columnDropped = false;
-#endif /* _DROP_COLUMN_HACK__ */
-
- atttup = AttributeRelidNumIndexScan(attrel,
- ObjectIdGetDatum(RelationGetRelid(relation)),
- Int32GetDatum(i));
+ relation->rd_att->constr = constr;
- if (!HeapTupleIsValid(atttup))
+ if (ndef > 0) /* DEFAULTs */
{
-#ifdef _DROP_COLUMN_HACK__
- atttup = AttributeRelidNumIndexScan(attrel,
- ObjectIdGetDatum(RelationGetRelid(relation)),
- Int32GetDatum(DROPPED_COLUMN_INDEX(i)));
- if (!HeapTupleIsValid(atttup))
-#endif /* _DROP_COLUMN_HACK__ */
- elog(ERROR, "cannot find attribute %d of relation %s", i,
- RelationGetRelationName(relation));
-#ifdef _DROP_COLUMN_HACK__
- columnDropped = true;
-#endif /* _DROP_COLUMN_HACK__ */
+ if (ndef < relation->rd_rel->relnatts)
+ constr->defval = (AttrDefault *)
+ repalloc(attrdef, ndef * sizeof(AttrDefault));
+ else
+ constr->defval = attrdef;
+ constr->num_defval = ndef;
+ AttrDefaultFetch(relation);
}
+ else
+ constr->num_defval = 0;
- relation->rd_att->attrs[i - 1] = attp =
- (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
- ATTRIBUTE_TUPLE_SIZE);
-
- memcpy((char *) attp,
- (char *) (Form_pg_attribute) GETSTRUCT(atttup),
- ATTRIBUTE_TUPLE_SIZE);
-
- /* don't forget to free the tuple returned from xxxIndexScan */
- heap_freetuple(atttup);
-
-#ifdef _DROP_COLUMN_HACK__
- if (columnDropped)
- continue;
-#endif /* _DROP_COLUMN_HACK__ */
-
- /* Update if this attribute have a constraint */
- if (attp->attnotnull)
- constr->has_not_null = true;
-
- if (attp->atthasdef)
+ if (relation->rd_rel->relchecks > 0) /* CHECKs */
{
- if (attrdef == NULL)
- {
- attrdef = (AttrDefault *)
- MemoryContextAlloc(CacheMemoryContext,
- relation->rd_rel->relnatts *
- sizeof(AttrDefault));
- MemSet(attrdef, 0,
- relation->rd_rel->relnatts * sizeof(AttrDefault));
- }
- attrdef[ndef].adnum = i;
- attrdef[ndef].adbin = NULL;
- ndef++;
+ constr->num_check = relation->rd_rel->relchecks;
+ constr->check = (ConstrCheck *)
+ MemoryContextAlloc(CacheMemoryContext,
+ constr->num_check * sizeof(ConstrCheck));
+ MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
+ RelCheckFetch(relation);
}
+ else
+ constr->num_check = 0;
+ }
+ else
+ {
+ pfree(constr);
+ relation->rd_att->constr = NULL;
}
-
- heap_close(attrel, AccessShareLock);
-
- /*
- * The attcacheoff values we read from pg_attribute should all be -1
- * ("unknown"). Verify this if assert checking is on. They will be
- * computed when and if needed during tuple access.
- */
-#ifdef USE_ASSERT_CHECKING
- for (i = 0; i < relation->rd_rel->relnatts; i++)
- Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
-#endif
-
- /*
- * However, we can easily set the attcacheoff value for the first
- * attribute: it must be zero. This eliminates the need for special
- * cases for attnum=1 that used to exist in fastgetattr() and
- * index_getattr().
- */
- relation->rd_att->attrs[0]->attcacheoff = 0;
-
- SetConstrOfRelation(relation, constr, ndef, attrdef);
}
/*
HeapTuple pg_rewrite_tuple;
Relation pg_rewrite_desc;
TupleDesc pg_rewrite_tupdesc;
- HeapScanDesc pg_rewrite_scan;
+ SysScanDesc pg_rewrite_scan;
ScanKeyData key;
RuleLock *rulelock;
int numlocks;
/*
* open pg_rewrite and begin a scan
+ *
+ * XXX: there is no suitable index for this scan. FIXME.
*/
pg_rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock);
- pg_rewrite_scan = heap_beginscan(pg_rewrite_desc, 0, SnapshotNow, 1, &key);
pg_rewrite_tupdesc = RelationGetDescr(pg_rewrite_desc);
+ pg_rewrite_scan = systable_beginscan(pg_rewrite_desc, NULL, false,
+ SnapshotNow,
+ 1, &key);
- while (HeapTupleIsValid(pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0)))
+ while (HeapTupleIsValid(pg_rewrite_tuple = systable_getnext(pg_rewrite_scan)))
{
bool isnull;
Datum ruleaction;
/*
* end the scan and close the attribute relation
*/
- heap_endscan(pg_rewrite_scan);
+ systable_endscan(pg_rewrite_scan);
heap_close(pg_rewrite_desc, AccessShareLock);
/*
* recycling the given old relation object. The latter case
* supports rebuilding a relcache entry without invalidating
* pointers to it.
- *
- * To build a relation descriptor, we have to allocate space,
- * open the underlying unix file and initialize the following
- * fields:
- *
- * File rd_fd; open file descriptor
- * BlockNumber rd_nblocks; number of blocks in rel
- * it will be set in ambeginscan()
- * int rd_refcnt; reference count
- * Form_pg_am rd_am; AM tuple
- * Form_pg_class rd_rel; RELATION tuple
- * Oid rd_id; relation's object id
- * LockInfoData rd_lockInfo; lock manager's info
- * TupleDesc rd_att; tuple descriptor
- *
- * Note: rd_ismem (rel is in-memory only) is currently unused
- * by any part of the system. someday this will indicate that
- * the relation lives only in the main-memory buffer pool
- * -cim 2/4/91
* --------------------------------
*/
static Relation
{
Relation relation;
Oid relid;
- Oid relam;
HeapTuple pg_class_tuple;
Form_pg_class relp;
MemoryContext oldcxt;
*/
relation->rd_isnailed = false;
- /*
- * initialize the access method information (relation->rd_am)
- */
- relam = relation->rd_rel->relam;
- if (OidIsValid(relam))
- relation->rd_am = AccessMethodObjectIdGetForm(relam,
- CacheMemoryContext);
-
/*
* initialize the tuple descriptor (relation->rd_att).
*/
relation->trigdesc = NULL;
/*
- * initialize index strategy and support information for this relation
+ * if it's an index, initialize index-related information
*/
- if (OidIsValid(relam))
+ if (OidIsValid(relation->rd_rel->relam))
RelationInitIndexAccessInfo(relation);
/*
relation->rd_node.tblNode = MyDatabaseId;
relation->rd_node.relNode = relation->rd_rel->relfilenode;
- /*
- * Open the relation and assign the file descriptor returned by the
- * storage manager code to rd_fd.
- *
- * We do not raise a hard error if we fail to open the relation at this
- * point. If we did, it would be impossible to drop a relation whose
- * underlying physical file had disappeared.
- */
- if (relation->rd_rel->relkind != RELKIND_VIEW)
- {
- relation->rd_fd = smgropen(DEFAULT_SMGR, relation, true);
- Assert(relation->rd_fd >= -1);
- if (relation->rd_fd == -1)
- elog(NOTICE, "RelationBuildDesc: can't open %s: %m",
- RelationGetRelationName(relation));
- }
- else
- relation->rd_fd = -1;
+ /* make sure relation is marked as having no open file yet */
+ relation->rd_fd = -1;
/*
* insert newly created relation into proper relcaches, restore memory
void
RelationInitIndexAccessInfo(Relation relation)
{
+ HeapTuple tuple;
+ Size iformsize;
+ Form_pg_index iform;
+ Form_pg_am aform;
MemoryContext indexcxt;
IndexStrategy strategy;
+ Oid *operator;
RegProcedure *support;
FmgrInfo *supportinfo;
int natts;
uint16 amstrategies;
uint16 amsupport;
- Size stratSize;
+
+ /*
+ * Make a copy of the pg_index entry for the index. Note that this
+ * is a variable-length tuple.
+ */
+ tuple = SearchSysCache(INDEXRELID,
+ ObjectIdGetDatum(RelationGetRelid(relation)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "RelationInitIndexAccessInfo: no pg_index entry for index %u",
+ RelationGetRelid(relation));
+ iformsize = tuple->t_len - tuple->t_data->t_hoff;
+ iform = (Form_pg_index) MemoryContextAlloc(CacheMemoryContext, iformsize);
+ memcpy(iform, GETSTRUCT(tuple), iformsize);
+ ReleaseSysCache(tuple);
+ relation->rd_index = iform;
+
+ /* this field is now kinda redundant... */
+ relation->rd_uniqueindex = iform->indisunique;
+
+ /*
+ * Make a copy of the pg_am entry for the index's access method
+ */
+ tuple = SearchSysCache(AMOID,
+ ObjectIdGetDatum(relation->rd_rel->relam),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "RelationInitIndexAccessInfo: cache lookup failed for AM %u",
+ relation->rd_rel->relam);
+ aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform);
+ memcpy(aform, GETSTRUCT(tuple), sizeof *aform);
+ ReleaseSysCache(tuple);
+ relation->rd_am = aform;
natts = relation->rd_rel->relnatts;
- amstrategies = relation->rd_am->amstrategies;
- amsupport = relation->rd_am->amsupport;
+ amstrategies = aform->amstrategies;
+ amsupport = aform->amsupport;
/*
* Make the private context to hold index access info. The reason we
/*
* Allocate arrays to hold data
*/
- stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
- strategy = (IndexStrategy) MemoryContextAlloc(indexcxt, stratSize);
+ if (amstrategies > 0)
+ {
+ int noperators = natts * amstrategies;
+ Size stratSize;
+
+ stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
+ strategy = (IndexStrategy) MemoryContextAlloc(indexcxt, stratSize);
+ MemSet(strategy, 0, stratSize);
+ operator = (Oid *)
+ MemoryContextAlloc(indexcxt, noperators * sizeof(Oid));
+ MemSet(operator, 0, noperators * sizeof(Oid));
+ }
+ else
+ {
+ strategy = NULL;
+ operator = NULL;
+ }
if (amsupport > 0)
{
support = (RegProcedure *)
MemoryContextAlloc(indexcxt, nsupport * sizeof(RegProcedure));
+ MemSet(support, 0, nsupport * sizeof(RegProcedure));
supportinfo = (FmgrInfo *)
MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
MemSet(supportinfo, 0, nsupport * sizeof(FmgrInfo));
supportinfo = NULL;
}
+ relation->rd_istrat = strategy;
+ relation->rd_operator = operator;
+ relation->rd_support = support;
+ relation->rd_supportinfo = supportinfo;
+
/*
* Fill the strategy map and the support RegProcedure arrays.
* (supportinfo is left as zeroes, and is filled on-the-fly when used)
*/
- IndexSupportInitialize(strategy, support,
- &relation->rd_uniqueindex,
- RelationGetRelid(relation),
- relation->rd_rel->relam,
+ IndexSupportInitialize(iform,
+ strategy, operator, support,
amstrategies, amsupport, natts);
-
- relation->rd_istrat = strategy;
- relation->rd_support = support;
- relation->rd_supportinfo = supportinfo;
}
/*
- * formrdesc
+ * IndexSupportInitialize
+ * Initializes an index strategy and associated support procedures,
+ * given the index's pg_index tuple.
*
- * This is a special cut-down version of RelationBuildDesc()
- * used by RelationCacheInitialize() in initializing the relcache.
- * The relation descriptor is built just from the supplied parameters,
+ * Data is returned into *indexStrategy, *indexOperator, and *indexSupport,
+ * all of which are objects allocated by the caller.
+ *
+ * The caller also passes maxStrategyNumber, maxSupportNumber, and
+ * maxAttributeNumber, since these indicate the size of the 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.
+ */
+static void
+IndexSupportInitialize(Form_pg_index iform,
+ IndexStrategy indexStrategy,
+ Oid *indexOperator,
+ RegProcedure *indexSupport,
+ StrategyNumber maxStrategyNumber,
+ StrategyNumber maxSupportNumber,
+ AttrNumber maxAttributeNumber)
+{
+ int attIndex;
+
+ maxStrategyNumber = AMStrategies(maxStrategyNumber);
+
+ /*
+ * 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++)
+ {
+ OpClassCacheEnt *opcentry;
+
+ if (iform->indkey[attIndex] == InvalidAttrNumber ||
+ !OidIsValid(iform->indclass[attIndex]))
+ elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
+
+ /* look up the info for this opclass, using a cache */
+ opcentry = LookupOpclassInfo(iform->indclass[attIndex],
+ maxStrategyNumber,
+ maxSupportNumber);
+
+ /* load the strategy information for the index operators */
+ if (maxStrategyNumber > 0)
+ {
+ StrategyMap map;
+ Oid *opers;
+ StrategyNumber strategy;
+
+ map = IndexStrategyGetStrategyMap(indexStrategy,
+ maxStrategyNumber,
+ attIndex + 1);
+ opers = &indexOperator[attIndex * maxStrategyNumber];
+
+ for (strategy = 0; strategy < maxStrategyNumber; strategy++)
+ {
+ ScanKey mapentry;
+
+ mapentry = StrategyMapGetScanKeyEntry(map, strategy + 1);
+ if (RegProcedureIsValid(opcentry->operatorProcs[strategy]))
+ {
+ MemSet(mapentry, 0, sizeof(*mapentry));
+ mapentry->sk_flags = 0;
+ mapentry->sk_procedure = opcentry->operatorProcs[strategy];
+ /*
+ * Mark mapentry->sk_func invalid, until and unless
+ * someone sets it up.
+ */
+ mapentry->sk_func.fn_oid = InvalidOid;
+ }
+ else
+ ScanKeyEntrySetIllegal(mapentry);
+ opers[strategy] = opcentry->operatorOids[strategy];
+ }
+ }
+
+ /* if support routines exist for this access method, load them */
+ if (maxSupportNumber > 0)
+ {
+ RegProcedure *procs;
+ StrategyNumber support;
+
+ procs = &indexSupport[attIndex * maxSupportNumber];
+
+ for (support = 0; support < maxSupportNumber; ++support)
+ procs[support] = opcentry->supportProcs[support];
+ }
+ }
+}
+
+/*
+ * LookupOpclassInfo
+ *
+ * This routine maintains a per-opclass cache of the information needed
+ * by IndexSupportInitialize(). This is more efficient than relying on
+ * the catalog cache, because we can load all the info about a particular
+ * opclass in a single indexscan of pg_amproc or pg_amop.
+ *
+ * The information from pg_am about expected range of strategy and support
+ * numbers is passed in, rather than being looked up, mainly because the
+ * caller will have it already.
+ *
+ * XXX There isn't any provision for flushing the cache. However, there
+ * isn't any provision for flushing relcache entries when opclass info
+ * changes, either :-(
+ */
+static OpClassCacheEnt *
+LookupOpclassInfo(Oid operatorClassOid,
+ StrategyNumber numStrats,
+ StrategyNumber numSupport)
+{
+ OpClassCacheEnt *opcentry;
+ bool found;
+ Relation pg_amop_desc;
+ Relation pg_amproc_desc;
+ SysScanDesc pg_amop_scan;
+ SysScanDesc pg_amproc_scan;
+ ScanKeyData key;
+ HeapTuple htup;
+ bool indexOK;
+
+ if (OpClassCache == NULL)
+ {
+ /* First time through: initialize the opclass cache */
+ HASHCTL ctl;
+
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
+
+ MemSet(&ctl, 0, sizeof(ctl));
+ ctl.keysize = sizeof(Oid);
+ ctl.entrysize = sizeof(OpClassCacheEnt);
+ ctl.hash = tag_hash;
+ OpClassCache = hash_create("Operator class cache", 64,
+ &ctl, HASH_ELEM | HASH_FUNCTION);
+ }
+
+ opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
+ (void *) &operatorClassOid,
+ HASH_ENTER, &found);
+ if (opcentry == NULL)
+ elog(ERROR, "out of memory for operator class cache");
+
+ if (found && opcentry->valid)
+ {
+ /* Already made an entry for it */
+ Assert(numStrats == opcentry->numStrats);
+ Assert(numSupport == opcentry->numSupport);
+ return opcentry;
+ }
+
+ /* Need to fill in new entry */
+ opcentry->valid = false; /* until known OK */
+ opcentry->numStrats = numStrats;
+ opcentry->numSupport = numSupport;
+
+ if (numStrats > 0)
+ {
+ opcentry->operatorOids = (Oid *)
+ MemoryContextAlloc(CacheMemoryContext,
+ numStrats * sizeof(Oid));
+ MemSet(opcentry->operatorOids, 0, numStrats * sizeof(Oid));
+ opcentry->operatorProcs = (RegProcedure *)
+ MemoryContextAlloc(CacheMemoryContext,
+ numStrats * sizeof(RegProcedure));
+ MemSet(opcentry->operatorProcs, 0, numStrats * sizeof(RegProcedure));
+ }
+ else
+ {
+ opcentry->operatorOids = NULL;
+ opcentry->operatorProcs = NULL;
+ }
+
+ if (numSupport > 0)
+ {
+ opcentry->supportProcs = (RegProcedure *)
+ MemoryContextAlloc(CacheMemoryContext,
+ numSupport * sizeof(RegProcedure));
+ MemSet(opcentry->supportProcs, 0, numSupport * sizeof(RegProcedure));
+ }
+ else
+ opcentry->supportProcs = NULL;
+
+ /*
+ * To avoid infinite recursion during startup, force a heap scan if
+ * we're looking up info for the opclasses used by the indexes we
+ * would like to reference here.
+ */
+ indexOK = criticalRelcachesBuilt ||
+ (operatorClassOid != OID_BTREE_OPS_OID &&
+ operatorClassOid != INT2_BTREE_OPS_OID);
+
+ /*
+ * Scan pg_amop to obtain operators for the opclass
+ */
+ if (numStrats > 0)
+ {
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_amop_amopclaid,
+ F_OIDEQ,
+ ObjectIdGetDatum(operatorClassOid));
+ pg_amop_desc = heap_openr(AccessMethodOperatorRelationName,
+ AccessShareLock);
+ pg_amop_scan = systable_beginscan(pg_amop_desc,
+ AccessMethodStrategyIndex,
+ indexOK,
+ SnapshotNow,
+ 1, &key);
+
+ while (HeapTupleIsValid(htup = systable_getnext(pg_amop_scan)))
+ {
+ Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(htup);
+
+ if (amopform->amopstrategy <= 0 ||
+ (StrategyNumber) amopform->amopstrategy > numStrats)
+ elog(ERROR, "Bogus amopstrategy number %d for opclass %u",
+ amopform->amopstrategy, operatorClassOid);
+ opcentry->operatorOids[amopform->amopstrategy - 1] =
+ amopform->amopopr;
+ opcentry->operatorProcs[amopform->amopstrategy - 1] =
+ get_opcode(amopform->amopopr);
+ }
+
+ systable_endscan(pg_amop_scan);
+ heap_close(pg_amop_desc, AccessShareLock);
+ }
+
+ /*
+ * Scan pg_amproc to obtain support procs for the opclass
+ */
+ if (numSupport > 0)
+ {
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_amproc_amopclaid,
+ F_OIDEQ,
+ ObjectIdGetDatum(operatorClassOid));
+ pg_amproc_desc = heap_openr(AccessMethodProcedureRelationName,
+ AccessShareLock);
+ pg_amproc_scan = systable_beginscan(pg_amproc_desc,
+ AccessMethodProcedureIndex,
+ indexOK,
+ SnapshotNow,
+ 1, &key);
+
+ while (HeapTupleIsValid(htup = systable_getnext(pg_amproc_scan)))
+ {
+ Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
+
+ if (amprocform->amprocnum <= 0 ||
+ (StrategyNumber) amprocform->amprocnum > numSupport)
+ elog(ERROR, "Bogus amproc number %d for opclass %u",
+ amprocform->amprocnum, operatorClassOid);
+
+ opcentry->supportProcs[amprocform->amprocnum - 1] =
+ amprocform->amproc;
+ }
+
+ systable_endscan(pg_amproc_scan);
+ heap_close(pg_amproc_desc, AccessShareLock);
+ }
+
+ opcentry->valid = true;
+ return opcentry;
+}
+
+
+/*
+ * formrdesc
+ *
+ * This is a special cut-down version of RelationBuildDesc()
+ * used by RelationCacheInitialize() in initializing the relcache.
+ * The relation descriptor is built just from the supplied parameters,
* without actually looking at any system table entries. We cheat
* quite a lot since we only need to work for a few basic system
* catalogs...
*
+ * Note that these catalogs can't have constraints, default values,
+ * rules, or triggers, since we don't cope with any of that.
+ *
* NOTE: we assume we are already switched into CacheMemoryContext.
*/
static void
/*
* initialize attribute tuple form
+ *
+ * Unlike the case with the relation tuple, this data had better be
+ * right because it will never be replaced. The input values must be
+ * correctly defined by macros in src/include/catalog/ headers.
*/
relation->rd_att = CreateTemplateTupleDesc(natts);
memcpy((char *) relation->rd_att->attrs[i],
(char *) &att[i],
ATTRIBUTE_TUPLE_SIZE);
+ /* make sure attcacheoff is valid */
+ relation->rd_att->attrs[i]->attcacheoff = -1;
}
+ /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
+ relation->rd_att->attrs[0]->attcacheoff = 0;
+
/*
* initialize relation id from info in att array (my, this is ugly)
*/
}
-/*
- * fixrdesc
- *
- * Update the phony data inserted by formrdesc() with real info
- * from pg_class.
- */
-static void
-fixrdesc(char *relationName)
-{
- RelationBuildDescInfo buildinfo;
- HeapTuple pg_class_tuple;
- Form_pg_class relp;
- Relation relation;
-
- /*
- * find the tuple in pg_class corresponding to the given relation name
- */
- buildinfo.infotype = INFO_RELNAME;
- buildinfo.i.info_name = relationName;
-
- pg_class_tuple = ScanPgRelation(buildinfo);
-
- if (!HeapTupleIsValid(pg_class_tuple))
- elog(FATAL, "fixrdesc: no pg_class entry for %s",
- relationName);
- relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
-
- /*
- * find the pre-made relcache entry (better be there!)
- */
- relation = RelationNameCacheGetRelation(relationName);
- if (!RelationIsValid(relation))
- elog(FATAL, "fixrdesc: no existing relcache entry for %s",
- relationName);
-
- /*
- * and copy pg_class_tuple to relation->rd_rel. (See notes in
- * AllocateRelationDesc())
- */
- Assert(relation->rd_rel != NULL);
- memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
-
- heap_freetuple(pg_class_tuple);
-}
-
-
/* ----------------------------------------------------------------
* Relation Descriptor Lookup Interface
* ----------------------------------------------------------------
RelationIdCacheLookup(relationId, rd);
if (RelationIsValid(rd))
- {
- /* re-open files if necessary */
- if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
- rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
-
RelationIncrementReferenceCount(rd);
- }
return rd;
}
RelationNameCacheLookup(NameStr(name), rd);
if (RelationIsValid(rd))
- {
- /* re-open files if necessary */
- if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
- rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
-
RelationIncrementReferenceCount(rd);
- }
return rd;
}
RelationNodeCacheLookup(rnode, rd);
if (RelationIsValid(rd))
- {
- /* re-open files if necessary */
- if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
- rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
-
RelationIncrementReferenceCount(rd);
- }
return rd;
}
* manager might have pointers into the rewrite rules. So to begin
* with, we can only get rid of these fields:
*/
+ if (relation->rd_index)
+ pfree(relation->rd_index);
if (relation->rd_am)
pfree(relation->rd_am);
if (relation->rd_rel)
RelationIdCacheLookup(relationId, relation);
if (PointerIsValid(relation))
- RelationFlushRelation(relation);
-}
-
-#if NOT_USED
-/* only used by RelationIdInvalidateRelationCacheByAccessMethodId,
- * which is dead code.
- */
-static void
-RelationFlushIndexes(Relation *r,
- Oid accessMethodId)
-{
- Relation relation = *r;
-
- if (!RelationIsValid(relation))
{
- elog(NOTICE, "inval call to RFI");
- return;
- }
-
- if (relation->rd_rel->relkind == RELKIND_INDEX && /* XXX style */
- (!OidIsValid(accessMethodId) ||
- relation->rd_rel->relam == accessMethodId))
+ relcacheInvalsReceived++;
RelationFlushRelation(relation);
+ }
}
-#endif
-
/*
* RelationCacheInvalidate
if (relation->rd_myxactonly)
continue;
+ relcacheInvalsReceived++;
+
if (RelationHasReferenceCountZero(relation))
{
/* Delete this entry immediately */
/*
* RelationCacheInitialize
*
- * This initializes the relation descriptor cache.
+ * This initializes the relation descriptor cache. At the time
+ * that this is invoked, we can't do database access yet (mainly
+ * because the transaction subsystem is not up), so we can't get
+ * "real" info. However it's okay to read the pg_internal.init
+ * cache file, if one is available. Otherwise we make phony
+ * entries for the minimum set of nailed-in-cache relations.
*/
#define INITRELCACHESIZE 400
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/*
- * create global caches
+ * create hashtables that index the relcache
*/
MemSet(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(NameData);
&ctl, HASH_ELEM | HASH_FUNCTION);
/*
- * initialize the cache with pre-made relation descriptors for some of
- * the more important system relations. These relations should always
- * be in the cache.
- *
- * NB: see also the list in RelationCacheInitializePhase2().
- */
- formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class);
- formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute);
- formrdesc(ProcedureRelationName, Natts_pg_proc, Desc_pg_proc);
- formrdesc(TypeRelationName, Natts_pg_type, Desc_pg_type);
-
- /*
- * init_irels() used to be called here. It is changed to be called in
- * RelationCacheInitializePhase2() now so that transactional control
- * could guarantee the consistency.
+ * Try to load the relcache cache file. If successful, we're done
+ * for now. Otherwise, initialize the cache with pre-made descriptors
+ * for the critical "nailed-in" system catalogs.
*/
+ if (IsBootstrapProcessingMode() ||
+ ! load_relcache_init_file())
+ {
+ formrdesc(RelationRelationName,
+ Natts_pg_class, Desc_pg_class);
+ formrdesc(AttributeRelationName,
+ Natts_pg_attribute, Desc_pg_attribute);
+ formrdesc(ProcedureRelationName,
+ Natts_pg_proc, Desc_pg_proc);
+ formrdesc(TypeRelationName,
+ Natts_pg_type, Desc_pg_type);
+
+#define NUM_CRITICAL_RELS 4 /* fix if you change list above */
+ }
MemoryContextSwitchTo(oldcxt);
}
/*
* RelationCacheInitializePhase2
*
- * This completes initialization of the relcache after catcache
- * is functional and we are able to actually load data from pg_class.
+ * This is called as soon as the catcache and transaction system
+ * are functional. At this point we can actually read data from
+ * the system catalogs. Update the relcache entries made during
+ * RelationCacheInitialize, and make sure we have entries for the
+ * critical system indexes.
*/
void
RelationCacheInitializePhase2(void)
{
+ HASH_SEQ_STATUS status;
+ RelNameCacheEnt *namehentry;
+
+ if (IsBootstrapProcessingMode())
+ return;
+
/*
- * Get the real pg_class tuple for each nailed-in-cache relcache entry
- * that was made by RelationCacheInitialize(), and replace the phony
- * rd_rel entry made by formrdesc(). This is necessary so that we
- * have, for example, the correct toast-table info for tables that
- * have such.
+ * If we didn't get the critical system indexes loaded into relcache,
+ * do so now. These are critical because the catcache depends on them
+ * for catcache fetches that are done during relcache load. Thus, we
+ * have an infinite-recursion problem. We can break the recursion
+ * by doing heapscans instead of indexscans at certain key spots.
+ * To avoid hobbling performance, we only want to do that until we
+ * have the critical indexes loaded into relcache. Thus, the flag
+ * criticalRelcachesBuilt is used to decide whether to do heapscan
+ * or indexscan at the key spots, and we set it true after we've loaded
+ * the critical indexes.
+ *
+ * The critical indexes are marked as "nailed in cache", partly to make
+ * it easy for load_relcache_init_file to count them, but mainly
+ * because we cannot flush and rebuild them once we've set
+ * criticalRelcachesBuilt to true. (NOTE: perhaps it would be possible
+ * to reload them by temporarily setting criticalRelcachesBuilt to
+ * false again. For now, though, we just nail 'em in.)
+ */
+ if (! criticalRelcachesBuilt)
+ {
+ RelationBuildDescInfo buildinfo;
+ Relation ird;
+
+#define LOAD_CRIT_INDEX(indname) \
+ do { \
+ buildinfo.infotype = INFO_RELNAME; \
+ buildinfo.i.info_name = (indname); \
+ ird = RelationBuildDesc(buildinfo, NULL); \
+ ird->rd_isnailed = true; \
+ RelationSetReferenceCount(ird, 1); \
+ } while (0)
+
+ LOAD_CRIT_INDEX(ClassNameIndex);
+ LOAD_CRIT_INDEX(ClassOidIndex);
+ LOAD_CRIT_INDEX(AttributeRelidNumIndex);
+ LOAD_CRIT_INDEX(IndexRelidIndex);
+ LOAD_CRIT_INDEX(AccessMethodStrategyIndex);
+ LOAD_CRIT_INDEX(AccessMethodProcedureIndex);
+ LOAD_CRIT_INDEX(OperatorOidIndex);
+
+#define NUM_CRITICAL_INDEXES 7 /* fix if you change list above */
+
+ criticalRelcachesBuilt = true;
+ }
+
+ /*
+ * Now, scan all the relcache entries and update anything that might
+ * be wrong in the results from formrdesc or the relcache cache file.
+ * If we faked up relcache entries using formrdesc, then read
+ * the real pg_class rows and replace the fake entries with them.
+ * Also, if any of the relcache entries have rules or triggers,
+ * load that info the hard way since it isn't recorded in the cache file.
*/
- if (!IsBootstrapProcessingMode())
+ hash_seq_init(&status, RelationNameCache);
+
+ while ((namehentry = (RelNameCacheEnt *) hash_seq_search(&status)) != NULL)
{
+ Relation relation = namehentry->reldesc;
+
/*
- * Initialize critical system index relation descriptors, first.
- * They are to make building relation descriptors fast.
- * init_irels() used to be called in RelationCacheInitialize(). It
- * is changed to be called here to be transaction safe.
+ * If it's a faked-up entry, read the real pg_class tuple.
*/
- MemoryContext oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+ if (needNewCacheFile && relation->rd_isnailed)
+ {
+ HeapTuple htup;
+ Form_pg_class relp;
- init_irels();
- MemoryContextSwitchTo(oldcxt);
+ htup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(RelationGetRelid(relation)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htup))
+ elog(FATAL, "RelationCacheInitializePhase2: no pg_class entry for %s",
+ RelationGetRelationName(relation));
+ relp = (Form_pg_class) GETSTRUCT(htup);
+ /*
+ * Copy tuple to relation->rd_rel. (See notes in
+ * AllocateRelationDesc())
+ */
+ Assert(relation->rd_rel != NULL);
+ memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
- /* fix nailed-in-cache relations */
- fixrdesc(RelationRelationName);
- fixrdesc(AttributeRelationName);
- fixrdesc(ProcedureRelationName);
- fixrdesc(TypeRelationName);
+ ReleaseSysCache(htup);
+ }
+
+ /*
+ * Fix data that isn't saved in relcache cache file.
+ */
+ if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
+ RelationBuildRuleLock(relation);
+ if (relation->rd_rel->reltriggers > 0 && relation->trigdesc == NULL)
+ RelationBuildTriggers(relation);
}
}
+/*
+ * RelationCacheInitializePhase3
+ *
+ * Final step of relcache initialization: write out a new relcache
+ * cache file if one is needed.
+ */
+void
+RelationCacheInitializePhase3(void)
+{
+ if (IsBootstrapProcessingMode())
+ return;
+
+ if (needNewCacheFile)
+ {
+ /*
+ * Force all the catcaches to finish initializing and thereby
+ * open the catalogs and indexes they use. This will preload
+ * the relcache with entries for all the most important system
+ * catalogs and indexes, so that the init file will be most
+ * useful for future backends.
+ */
+ InitCatalogCachePhase2();
+
+ /* now write the file */
+ write_relcache_init_file();
+ }
+}
+
+
/* used by XLogInitCache */
void CreateDummyCaches(void);
void DestroyDummyCaches(void);
AttrDefault *attrdef = relation->rd_att->constr->defval;
int ndef = relation->rd_att->constr->num_defval;
Relation adrel;
- Relation irel = (Relation) NULL;
+ SysScanDesc adscan;
ScanKeyData skey;
- HeapTupleData tuple;
HeapTuple htup;
- Form_pg_attrdef adform;
- IndexScanDesc sd = (IndexScanDesc) NULL;
- HeapScanDesc adscan = (HeapScanDesc) NULL;
- RetrieveIndexResult indexRes;
Datum val;
bool isnull;
int found;
int i;
- bool hasindex;
ScanKeyEntryInitialize(&skey,
(bits16) 0x0,
- (AttrNumber) 1,
+ (AttrNumber) Anum_pg_attrdef_adrelid,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation)));
adrel = heap_openr(AttrDefaultRelationName, AccessShareLock);
- hasindex = (adrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
- if (hasindex)
- {
- irel = index_openr(AttrDefaultIndex);
- sd = index_beginscan(irel, false, 1, &skey);
- }
- else
- adscan = heap_beginscan(adrel, false, SnapshotNow, 1, &skey);
- tuple.t_datamcxt = NULL;
- tuple.t_data = NULL;
+ adscan = systable_beginscan(adrel, AttrDefaultIndex, true,
+ SnapshotNow,
+ 1, &skey);
+ found = 0;
- for (found = 0;;)
+ while (HeapTupleIsValid(htup = systable_getnext(adscan)))
{
- Buffer buffer;
+ Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
- if (hasindex)
- {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (!indexRes)
- break;
-
- tuple.t_self = indexRes->heap_iptr;
- heap_fetch(adrel, SnapshotNow, &tuple, &buffer, sd);
- pfree(indexRes);
- if (tuple.t_data == NULL)
- continue;
- htup = &tuple;
- }
- else
- {
- htup = heap_getnext(adscan, 0);
- if (!HeapTupleIsValid(htup))
- break;
- }
found++;
- adform = (Form_pg_attrdef) GETSTRUCT(htup);
for (i = 0; i < ndef; i++)
{
if (adform->adnum != attrdef[i].adnum)
val)));
break;
}
- if (hasindex)
- ReleaseBuffer(buffer);
if (i >= ndef)
elog(NOTICE, "AttrDefaultFetch: unexpected record found for attr %d in rel %s",
RelationGetRelationName(relation));
}
- if (found < ndef)
- elog(NOTICE, "AttrDefaultFetch: %d record not found for rel %s",
- ndef - found, RelationGetRelationName(relation));
-
- if (hasindex)
- {
- index_endscan(sd);
- index_close(irel);
- }
- else
- heap_endscan(adscan);
+ systable_endscan(adscan);
heap_close(adrel, AccessShareLock);
+
+ if (found != ndef)
+ elog(NOTICE, "AttrDefaultFetch: %d record(s) not found for rel %s",
+ ndef - found, RelationGetRelationName(relation));
}
static void
ConstrCheck *check = relation->rd_att->constr->check;
int ncheck = relation->rd_att->constr->num_check;
Relation rcrel;
- Relation irel = (Relation) NULL;
+ SysScanDesc rcscan;
ScanKeyData skey;
- HeapTupleData tuple;
HeapTuple htup;
- IndexScanDesc sd = (IndexScanDesc) NULL;
- HeapScanDesc rcscan = (HeapScanDesc) NULL;
- RetrieveIndexResult indexRes;
Name rcname;
Datum val;
bool isnull;
int found;
- bool hasindex;
ScanKeyEntryInitialize(&skey,
(bits16) 0x0,
- (AttrNumber) 1,
+ (AttrNumber) Anum_pg_relcheck_rcrelid,
(RegProcedure) F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation)));
rcrel = heap_openr(RelCheckRelationName, AccessShareLock);
- hasindex = (rcrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
- if (hasindex)
- {
- irel = index_openr(RelCheckIndex);
- sd = index_beginscan(irel, false, 1, &skey);
- }
- else
- rcscan = heap_beginscan(rcrel, false, SnapshotNow, 1, &skey);
- tuple.t_datamcxt = NULL;
- tuple.t_data = NULL;
+ rcscan = systable_beginscan(rcrel, RelCheckIndex, true,
+ SnapshotNow,
+ 1, &skey);
+ found = 0;
- for (found = 0;;)
+ while (HeapTupleIsValid(htup = systable_getnext(rcscan)))
{
- Buffer buffer;
-
- if (hasindex)
- {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (!indexRes)
- break;
-
- tuple.t_self = indexRes->heap_iptr;
- heap_fetch(rcrel, SnapshotNow, &tuple, &buffer, sd);
- pfree(indexRes);
- if (tuple.t_data == NULL)
- continue;
- htup = &tuple;
- }
- else
- {
- htup = heap_getnext(rcscan, 0);
- if (!HeapTupleIsValid(htup))
- break;
- }
if (found == ncheck)
elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
RelationGetRelationName(relation));
DatumGetCString(DirectFunctionCall1(textout,
val)));
found++;
- if (hasindex)
- ReleaseBuffer(buffer);
}
- if (found < ncheck)
- elog(ERROR, "RelCheckFetch: %d record not found for rel %s",
- ncheck - found, RelationGetRelationName(relation));
-
- if (hasindex)
- {
- index_endscan(sd);
- index_close(irel);
- }
- else
- heap_endscan(rcscan);
+ systable_endscan(rcscan);
heap_close(rcrel, AccessShareLock);
+
+ if (found != ncheck)
+ elog(ERROR, "RelCheckFetch: %d record(s) not found for rel %s",
+ ncheck - found, RelationGetRelationName(relation));
}
/*
RelationGetIndexList(Relation relation)
{
Relation indrel;
- Relation irel = (Relation) NULL;
+ SysScanDesc indscan;
ScanKeyData skey;
- IndexScanDesc sd = (IndexScanDesc) NULL;
- HeapScanDesc hscan = (HeapScanDesc) NULL;
- bool hasindex;
+ HeapTuple htup;
List *result;
MemoryContext oldcxt;
if (relation->rd_indexfound)
return listCopy(relation->rd_indexlist);
- /* Prepare to scan pg_index for entries having indrelid = this rel. */
- indrel = heap_openr(IndexRelationName, AccessShareLock);
- hasindex = (indrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes());
- if (hasindex)
- {
- irel = index_openr(IndexIndrelidIndex);
- ScanKeyEntryInitialize(&skey,
- (bits16) 0x0,
- (AttrNumber) 1,
- (RegProcedure) F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(relation)));
- sd = index_beginscan(irel, false, 1, &skey);
- }
- else
- {
- ScanKeyEntryInitialize(&skey,
- (bits16) 0x0,
- (AttrNumber) Anum_pg_index_indrelid,
- (RegProcedure) F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(relation)));
- hscan = heap_beginscan(indrel, false, SnapshotNow, 1, &skey);
- }
-
/*
* We build the list we intend to return (in the caller's context)
* while doing the scan. After successfully completing the scan, we
*/
result = NIL;
- for (;;)
- {
- HeapTupleData tuple;
- HeapTuple htup;
- Buffer buffer;
- Form_pg_index index;
+ /* Prepare to scan pg_index for entries having indrelid = this rel. */
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) Anum_pg_index_indrelid,
+ (RegProcedure) F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(relation)));
- if (hasindex)
- {
- RetrieveIndexResult indexRes;
-
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (!indexRes)
- break;
- tuple.t_self = indexRes->heap_iptr;
- tuple.t_datamcxt = NULL;
- tuple.t_data = NULL;
- heap_fetch(indrel, SnapshotNow, &tuple, &buffer, sd);
- pfree(indexRes);
- if (tuple.t_data == NULL)
- continue;
- htup = &tuple;
- }
- else
- {
- htup = heap_getnext(hscan, 0);
- if (!HeapTupleIsValid(htup))
- break;
- }
+ indrel = heap_openr(IndexRelationName, AccessShareLock);
+ indscan = systable_beginscan(indrel, IndexIndrelidIndex, true,
+ SnapshotNow,
+ 1, &skey);
- index = (Form_pg_index) GETSTRUCT(htup);
+ while (HeapTupleIsValid(htup = systable_getnext(indscan)))
+ {
+ Form_pg_index index = (Form_pg_index) GETSTRUCT(htup);
result = insert_ordered_oid(result, index->indexrelid);
-
- if (hasindex)
- ReleaseBuffer(buffer);
}
- if (hasindex)
- {
- index_endscan(sd);
- index_close(irel);
- }
- else
- heap_endscan(hscan);
+ systable_endscan(indscan);
heap_close(indrel, AccessShareLock);
/* Now save a copy of the completed list in the relcache entry. */
/*
- * init_irels(), write_irels() -- handle special-case initialization of
- * index relation descriptors.
+ * load_relcache_init_file, write_relcache_init_file
*
* In late 1992, we started regularly having databases with more than
* a thousand classes in them. With this number of classes, it became
* In order to get around the problem, we do the following:
*
* + When the database system is initialized (at initdb time), we
- * don't use indices on pg_attribute. We do sequential scans.
+ * don't use indexes. We do sequential scans.
*
* + When the backend is started up in normal mode, we load an image
* of the appropriate relation descriptors, in internal format,
*
* We could dispense with the initialization file and just build the
* critical reldescs the hard way on every backend startup, but that
- * slows down backend startup noticeably if pg_class is large.
+ * slows down backend startup noticeably.
+ *
+ * We can in fact go further, and save more relcache entries than
+ * just the ones that are absolutely critical; this allows us to speed
+ * up backend startup by not having to build such entries the hard way.
+ * Presently, all the catalog and index entries that are referred to
+ * by catcaches are stored in the initialization file.
*
* As of v6.5, vacuum.c deletes the initialization file at completion
* of a VACUUM, so that it will be rebuilt at the next backend startup.
- * This ensures that vacuum-collected stats for the system indexes
- * will eventually get used by the optimizer --- otherwise the relcache
- * entries for these indexes will show zero sizes forever, since the
- * relcache entries are pinned in memory and will never be reloaded
- * from pg_class.
+ * This ensures that vacuum-collected stats for the system catalogs
+ * and indexes will be seen by backends started later.
*/
-/* pg_attnumind, pg_classnameind, pg_classoidind */
-#define Num_indices_bootstrap 3
-
-static void
-init_irels(void)
+/*
+ * load_relcache_init_file -- attempt to load cache from the init file
+ *
+ * If successful, return TRUE and set criticalRelcachesBuilt to true.
+ * If not successful, return FALSE and set needNewCacheFile to true.
+ *
+ * NOTE: we assume we are already switched into CacheMemoryContext.
+ */
+static bool
+load_relcache_init_file(void)
{
- Size len;
- int nread;
- File fd;
- Relation irel[Num_indices_bootstrap];
- Relation ird;
- Form_pg_am am;
- Form_pg_class relform;
- MemoryContext indexcxt;
- IndexStrategy strat;
- RegProcedure *support;
- int nstrategies,
- nsupport;
+ FILE *fp;
+ char initfilename[MAXPGPATH];
+ Relation *rels;
+ int relno,
+ num_rels,
+ max_rels,
+ nailed_rels,
+ nailed_indexes;
int i;
- int relno;
- if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | PG_BINARY, 0600)) < 0)
+ snprintf(initfilename, sizeof(initfilename), "%s/%s",
+ DatabasePath, RELCACHE_INIT_FILENAME);
+
+ fp = AllocateFile(initfilename, PG_BINARY_R);
+ if (fp == NULL)
{
- write_irels();
- return;
+ needNewCacheFile = true;
+ return false;
}
- for (relno = 0; relno < Num_indices_bootstrap; relno++)
+ /*
+ * Read the index relcache entries from the file. Note we will not
+ * enter any of them into the cache if the read fails partway through;
+ * this helps to guard against broken init files.
+ */
+ max_rels = 100;
+ rels = (Relation *) palloc(max_rels * sizeof(Relation));
+ num_rels = 0;
+ nailed_rels = nailed_indexes = 0;
+ initFileRelationIds = NIL;
+
+ for (relno = 0; ; relno++)
{
+ Size len;
+ size_t nread;
+ Relation rel;
+ Form_pg_class relform;
+
/* first read the relation descriptor length */
- if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ {
+ if (nread == 0)
+ break; /* end of file */
goto read_failed;
+ }
/* safety check for incompatible relcache layout */
if (len != sizeof(RelationData))
goto read_failed;
- ird = irel[relno] = (Relation) palloc(len);
- MemSet(ird, 0, len);
-
- /* then, read the Relation structure */
- if ((nread = FileRead(fd, (char *) ird, len)) != len)
- goto read_failed;
-
- /* reset transient fields */
- ird->rd_targblock = InvalidBlockNumber;
- ird->rd_fd = -1;
- ird->rd_refcnt = 0;
+ /* allocate another relcache header */
+ if (num_rels >= max_rels)
+ {
+ max_rels *= 2;
+ rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
+ }
- ird->rd_node.tblNode = MyDatabaseId;
+ rel = rels[num_rels++] = (Relation) palloc(len);
- /* next, read the access method tuple form */
- if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
- goto read_failed;
-
- am = (Form_pg_am) palloc(len);
- if ((nread = FileRead(fd, (char *) am, len)) != len)
+ /* then, read the Relation structure */
+ if ((nread = fread(rel, 1, len, fp)) != len)
goto read_failed;
- ird->rd_am = am;
-
/* next read the relation tuple form */
- if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
relform = (Form_pg_class) palloc(len);
- if ((nread = FileRead(fd, (char *) relform, len)) != len)
+ if ((nread = fread(relform, 1, len, fp)) != len)
goto read_failed;
- ird->rd_rel = relform;
+ rel->rd_rel = relform;
/* initialize attribute tuple forms */
- ird->rd_att = CreateTemplateTupleDesc(relform->relnatts);
+ rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
/* next read all the attribute tuple form data entries */
- len = ATTRIBUTE_TUPLE_SIZE;
for (i = 0; i < relform->relnatts; i++)
{
- if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
- ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
+ rel->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
- if ((nread = FileRead(fd, (char *) ird->rd_att->attrs[i], len)) != len)
+ if ((nread = fread(rel->rd_att->attrs[i], 1, len, fp)) != len)
goto read_failed;
}
- /*
- * prepare index info context --- parameters should match
- * RelationInitIndexAccessInfo
- */
- indexcxt = AllocSetContextCreate(CacheMemoryContext,
- RelationGetRelationName(ird),
- 0, /* minsize */
- 512, /* initsize */
- 1024); /* maxsize */
- ird->rd_indexcxt = indexcxt;
-
- /* next, read the index strategy map */
- if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
- goto read_failed;
+ /* If it's an index, there's more to do */
+ if (rel->rd_rel->relkind == RELKIND_INDEX)
+ {
+ Form_pg_am am;
+ MemoryContext indexcxt;
+ IndexStrategy strat;
+ Oid *operator;
+ RegProcedure *support;
+ int nstrategies,
+ nsupport;
+
+ /* Count nailed indexes to ensure we have 'em all */
+ if (rel->rd_isnailed)
+ nailed_indexes++;
+
+ /* next, read the pg_index tuple form */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
- strat = (IndexStrategy) MemoryContextAlloc(indexcxt, len);
- if ((nread = FileRead(fd, (char *) strat, len)) != len)
- goto read_failed;
+ rel->rd_index = (Form_pg_index) palloc(len);
+ if ((nread = fread(rel->rd_index, 1, len, fp)) != len)
+ goto read_failed;
- /* have to invalidate any FmgrInfo data in the strategy maps */
- nstrategies = am->amstrategies * relform->relnatts;
- for (i = 0; i < nstrategies; i++)
- strat->strategyMapData[i].entry[0].sk_func.fn_oid = InvalidOid;
+ /* next, read the access method tuple form */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
- ird->rd_istrat = strat;
+ am = (Form_pg_am) palloc(len);
+ if ((nread = fread(am, 1, len, fp)) != len)
+ goto read_failed;
+ rel->rd_am = am;
- /* finally, read the vector of support procedures */
- if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
- goto read_failed;
- support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
- if ((nread = FileRead(fd, (char *) support, len)) != len)
- goto read_failed;
+ /*
+ * prepare index info context --- parameters should match
+ * RelationInitIndexAccessInfo
+ */
+ indexcxt = AllocSetContextCreate(CacheMemoryContext,
+ RelationGetRelationName(rel),
+ 0, /* minsize */
+ 512, /* initsize */
+ 1024); /* maxsize */
+ rel->rd_indexcxt = indexcxt;
+
+ /* next, read the index strategy map */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
- ird->rd_support = support;
+ strat = (IndexStrategy) MemoryContextAlloc(indexcxt, len);
+ if ((nread = fread(strat, 1, len, fp)) != len)
+ goto read_failed;
- nsupport = relform->relnatts * am->amsupport;
- ird->rd_supportinfo = (FmgrInfo *)
- MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
- MemSet(ird->rd_supportinfo, 0, nsupport * sizeof(FmgrInfo));
+ /* have to invalidate any FmgrInfo data in the strategy maps */
+ nstrategies = am->amstrategies * relform->relnatts;
+ for (i = 0; i < nstrategies; i++)
+ strat->strategyMapData[i].entry[0].sk_func.fn_oid = InvalidOid;
+
+ rel->rd_istrat = strat;
+
+ /* next, read the vector of operator OIDs */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
+
+ operator = (Oid *) MemoryContextAlloc(indexcxt, len);
+ if ((nread = fread(operator, 1, len, fp)) != len)
+ goto read_failed;
+
+ rel->rd_operator = operator;
- RelationInitLockInfo(ird);
+ /* finally, read the vector of support procedures */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
+ support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
+ if ((nread = fread(support, 1, len, fp)) != len)
+ goto read_failed;
+
+ rel->rd_support = support;
+
+ /* add a zeroed support-fmgr-info vector */
+ nsupport = relform->relnatts * am->amsupport;
+ rel->rd_supportinfo = (FmgrInfo *)
+ MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
+ MemSet(rel->rd_supportinfo, 0, nsupport * sizeof(FmgrInfo));
+ }
+ else
+ {
+ /* Count nailed rels to ensure we have 'em all */
+ if (rel->rd_isnailed)
+ nailed_rels++;
+
+ Assert(rel->rd_index == NULL);
+ Assert(rel->rd_am == NULL);
+ Assert(rel->rd_indexcxt == NULL);
+ Assert(rel->rd_istrat == NULL);
+ Assert(rel->rd_operator == NULL);
+ Assert(rel->rd_support == NULL);
+ Assert(rel->rd_supportinfo == NULL);
+ }
+
+ /*
+ * Rules and triggers are not saved (mainly because the internal
+ * format is complex and subject to change). They must be rebuilt
+ * if needed by RelationCacheInitializePhase2. This is not expected
+ * to be a big performance hit since few system catalogs have such.
+ */
+ rel->rd_rules = NULL;
+ rel->rd_rulescxt = NULL;
+ rel->trigdesc = NULL;
+
+ /*
+ * Reset transient-state fields in the relcache entry
+ */
+ rel->rd_fd = -1;
+ rel->rd_targblock = InvalidBlockNumber;
+ if (rel->rd_isnailed)
+ RelationSetReferenceCount(rel, 1);
+ else
+ RelationSetReferenceCount(rel, 0);
+ rel->rd_indexfound = false;
+ rel->rd_indexlist = NIL;
+ MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
- RelationCacheInsert(ird);
+ /*
+ * Make sure database ID is correct. This is needed in case the
+ * pg_internal.init file was copied from some other database by
+ * CREATE DATABASE.
+ */
+ if (rel->rd_rel->relisshared)
+ rel->rd_node.tblNode = InvalidOid;
+ else
+ rel->rd_node.tblNode = MyDatabaseId;
+
+ RelationInitLockInfo(rel);
+ }
+
+ /*
+ * We reached the end of the init file without apparent problem.
+ * Did we get the right number of nailed items? (This is a useful
+ * crosscheck in case the set of critical rels or indexes changes.)
+ */
+ if (nailed_rels != NUM_CRITICAL_RELS ||
+ nailed_indexes != NUM_CRITICAL_INDEXES)
+ goto read_failed;
+
+ /*
+ * OK, all appears well.
+ *
+ * Now insert all the new relcache entries into the cache.
+ */
+ for (relno = 0; relno < num_rels; relno++)
+ {
+ RelationCacheInsert(rels[relno]);
+ /* also make a list of their OIDs, for RelationIdIsInInitFile */
+ initFileRelationIds = lconsi((int) RelationGetRelid(rels[relno]),
+ initFileRelationIds);
}
- /* successfully read the init file */
- FileClose(fd);
+ pfree(rels);
+ FreeFile(fp);
+
criticalRelcachesBuilt = true;
- return;
+ return true;
- /* init file is broken, so do it the hard way */
+ /*
+ * init file is broken, so do it the hard way. We don't bother
+ * trying to free the clutter we just allocated; it's not in the
+ * relcache so it won't hurt.
+ */
read_failed:
- FileClose(fd);
- write_irels();
+ pfree(rels);
+ FreeFile(fp);
+
+ needNewCacheFile = true;
+ return false;
}
+/*
+ * Write out a new initialization file with the current contents
+ * of the relcache.
+ */
static void
-write_irels(void)
+write_relcache_init_file(void)
{
- Size len;
- int nwritten;
- File fd;
- Relation irel[Num_indices_bootstrap];
- Relation ird;
- Form_pg_am am;
- Form_pg_class relform;
- IndexStrategy strat;
- RegProcedure *support;
- int i;
- int relno;
- RelationBuildDescInfo bi;
+ FILE *fp;
char tempfilename[MAXPGPATH];
char finalfilename[MAXPGPATH];
+ HASH_SEQ_STATUS status;
+ RelNameCacheEnt *namehentry;
+ MemoryContext oldcxt;
+ int i;
/*
* We must write a temporary file and rename it into place. Otherwise,
snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
DatabasePath, RELCACHE_INIT_FILENAME);
- fd = PathNameOpenFile(tempfilename, O_WRONLY | O_CREAT | O_TRUNC | PG_BINARY, 0600);
- if (fd < 0)
+ unlink(tempfilename); /* in case it exists w/wrong permissions */
+
+ fp = AllocateFile(tempfilename, PG_BINARY_W);
+ if (fp == NULL)
{
/*
* We used to consider this a fatal error, but we might as well
return;
}
- FileSeek(fd, 0L, SEEK_SET);
-
/*
- * Build relation descriptors for the critical system indexes without
- * resort to the descriptor cache. In order to do this, we set
- * ProcessingMode to Bootstrap. The effect of this is to disable
- * indexed relation searches -- a necessary step, since we're trying
- * to instantiate the index relation descriptors here. Once we have
- * the descriptors, nail them into cache so we never lose them.
- */
-
- /*---------
- * Removed the following ProcessingMode change -- inoue
- * At this point
- * 1) Catalog Cache isn't initialized
- * 2) Relation Cache for the following critical indexes aren't built
- * oldmode = GetProcessingMode();
- * SetProcessingMode(BootstrapProcessing);
- *---------
+ * Write all the reldescs (in no particular order).
*/
+ hash_seq_init(&status, RelationNameCache);
- bi.infotype = INFO_RELNAME;
- bi.i.info_name = AttributeRelidNumIndex;
- irel[0] = RelationBuildDesc(bi, NULL);
- irel[0]->rd_isnailed = true;
-
- bi.i.info_name = ClassNameIndex;
- irel[1] = RelationBuildDesc(bi, NULL);
- irel[1]->rd_isnailed = true;
-
- bi.i.info_name = ClassOidIndex;
- irel[2] = RelationBuildDesc(bi, NULL);
- irel[2]->rd_isnailed = true;
-
- criticalRelcachesBuilt = true;
+ initFileRelationIds = NIL;
- /*
- * Removed the following ProcessingMode -- inoue
- * SetProcessingMode(oldmode);
- */
-
- /*
- * Write out the index reldescs to the special cache file.
- */
- for (relno = 0; relno < Num_indices_bootstrap; relno++)
+ while ((namehentry = (RelNameCacheEnt *) hash_seq_search(&status)) != NULL)
{
- ird = irel[relno];
-
- /* save the volatile fields in the relation descriptor */
- am = ird->rd_am;
- ird->rd_am = (Form_pg_am) NULL;
- relform = ird->rd_rel;
- ird->rd_rel = (Form_pg_class) NULL;
- strat = ird->rd_istrat;
- support = ird->rd_support;
+ Relation rel = namehentry->reldesc;
+ Form_pg_class relform = rel->rd_rel;
+ Size len;
/*
- * first write the relation descriptor , excluding strategy and
- * support
+ * first write the relcache entry proper
*/
len = sizeof(RelationData);
/* first, write the relation descriptor length */
- if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
- != sizeof(len))
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
elog(FATAL, "cannot write init file -- descriptor length");
/* next, write out the Relation structure */
- if ((nwritten = FileWrite(fd, (char *) ird, len)) != len)
+ if (fwrite(rel, 1, len, fp) != len)
elog(FATAL, "cannot write init file -- reldesc");
- /* next, write the access method tuple form */
- len = sizeof(FormData_pg_am);
- if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
- != sizeof(len))
- elog(FATAL, "cannot write init file -- am tuple form length");
-
- if ((nwritten = FileWrite(fd, (char *) am, len)) != len)
- elog(FATAL, "cannot write init file -- am tuple form");
-
/* next write the relation tuple form */
len = sizeof(FormData_pg_class);
- if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
- != sizeof(len))
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
elog(FATAL, "cannot write init file -- relation tuple form length");
- if ((nwritten = FileWrite(fd, (char *) relform, len)) != len)
+ if (fwrite(relform, 1, len, fp) != len)
elog(FATAL, "cannot write init file -- relation tuple form");
/* next, do all the attribute tuple form data entries */
- len = ATTRIBUTE_TUPLE_SIZE;
for (i = 0; i < relform->relnatts; i++)
{
- if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
- != sizeof(len))
+ len = ATTRIBUTE_TUPLE_SIZE;
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
elog(FATAL, "cannot write init file -- length of attdesc %d", i);
- if ((nwritten = FileWrite(fd, (char *) ird->rd_att->attrs[i], len))
- != len)
+ if (fwrite(rel->rd_att->attrs[i], 1, len, fp) != len)
elog(FATAL, "cannot write init file -- attdesc %d", i);
}
- /* next, write the index strategy map */
- len = AttributeNumberGetIndexStrategySize(relform->relnatts,
- am->amstrategies);
- if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
- != sizeof(len))
- elog(FATAL, "cannot write init file -- strategy map length");
-
- if ((nwritten = FileWrite(fd, (char *) strat, len)) != len)
- elog(FATAL, "cannot write init file -- strategy map");
-
- /* finally, write the vector of support procedures */
- len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
- if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
- != sizeof(len))
- elog(FATAL, "cannot write init file -- support vector length");
+ /* If it's an index, there's more to do */
+ if (rel->rd_rel->relkind == RELKIND_INDEX)
+ {
+ Form_pg_am am = rel->rd_am;
+ HeapTuple tuple;
- if ((nwritten = FileWrite(fd, (char *) support, len)) != len)
- elog(FATAL, "cannot write init file -- support vector");
+ /*
+ * We need to write the index tuple form, but this is a bit
+ * tricky since it's a variable-length struct. Rather than
+ * hoping to intuit the length, fetch the pg_index tuple
+ * afresh using the syscache, and write that.
+ */
+ tuple = SearchSysCache(INDEXRELID,
+ ObjectIdGetDatum(RelationGetRelid(rel)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "write_relcache_init_file: no pg_index entry for index %u",
+ RelationGetRelid(rel));
+ len = tuple->t_len - tuple->t_data->t_hoff;
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+ elog(FATAL, "cannot write init file -- index tuple form length");
+ if (fwrite(GETSTRUCT(tuple), 1, len, fp) != len)
+ elog(FATAL, "cannot write init file -- index tuple form");
+ ReleaseSysCache(tuple);
+
+ /* next, write the access method tuple form */
+ len = sizeof(FormData_pg_am);
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+ elog(FATAL, "cannot write init file -- am tuple form length");
+
+ if (fwrite(am, 1, len, fp) != len)
+ elog(FATAL, "cannot write init file -- am tuple form");
+
+ /* next, write the index strategy map */
+ len = AttributeNumberGetIndexStrategySize(relform->relnatts,
+ am->amstrategies);
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+ elog(FATAL, "cannot write init file -- strategy map length");
+
+ if (fwrite(rel->rd_istrat, 1, len, fp) != len)
+ elog(FATAL, "cannot write init file -- strategy map");
+
+ /* next, write the vector of operator OIDs */
+ len = relform->relnatts * (am->amstrategies * sizeof(Oid));
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+ elog(FATAL, "cannot write init file -- operator vector length");
+
+ if (fwrite(rel->rd_operator, 1, len, fp) != len)
+ elog(FATAL, "cannot write init file -- operator vector");
+
+ /* finally, write the vector of support procedures */
+ len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
+ if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
+ elog(FATAL, "cannot write init file -- support vector length");
+
+ if (fwrite(rel->rd_support, 1, len, fp) != len)
+ elog(FATAL, "cannot write init file -- support vector");
+ }
- /* restore volatile fields */
- ird->rd_am = am;
- ird->rd_rel = relform;
+ /* also make a list of their OIDs, for RelationIdIsInInitFile */
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+ initFileRelationIds = lconsi((int) RelationGetRelid(rel),
+ initFileRelationIds);
+ MemoryContextSwitchTo(oldcxt);
}
- FileClose(fd);
+ FreeFile(fp);
/*
- * And rename the temp file to its final name, deleting any
- * previously-existing init file.
+ * Now we have to check whether the data we've so painstakingly
+ * accumulated is already obsolete due to someone else's just-committed
+ * catalog changes. If so, we just delete the temp file and leave it
+ * to the next backend to try again. (Our own relcache entries will be
+ * updated by SI message processing, but we can't be sure whether what
+ * we wrote out was up-to-date.)
*
- * Note: a failure here is possible under Cygwin, if some other
- * backend is holding open an unlinked-but-not-yet-gone init file.
- * So treat this as a noncritical failure.
+ * This mustn't run concurrently with RelationCacheInitFileInvalidate,
+ * so grab a serialization lock for the duration.
*/
- if (rename(tempfilename, finalfilename) < 0)
+ LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
+
+ /* Make sure we have seen all incoming SI messages */
+ AcceptInvalidationMessages();
+
+ /*
+ * If we have received any SI relcache invals since backend start,
+ * assume we may have written out-of-date data.
+ */
+ if (relcacheInvalsReceived == 0L)
{
- elog(NOTICE, "Cannot rename init file %s to %s: %m\n\tContinuing anyway, but there's something wrong.", tempfilename, finalfilename);
/*
- * If we fail, try to clean up the useless temp file; don't bother
- * to complain if this fails too.
+ * OK, rename the temp file to its final name, deleting any
+ * previously-existing init file.
+ *
+ * Note: a failure here is possible under Cygwin, if some other
+ * backend is holding open an unlinked-but-not-yet-gone init file.
+ * So treat this as a noncritical failure.
*/
+ if (rename(tempfilename, finalfilename) < 0)
+ {
+ elog(NOTICE, "Cannot rename init file %s to %s: %m\n\tContinuing anyway, but there's something wrong.", tempfilename, finalfilename);
+ /*
+ * If we fail, try to clean up the useless temp file; don't bother
+ * to complain if this fails too.
+ */
+ unlink(tempfilename);
+ }
+ }
+ else
+ {
+ /* Delete the already-obsolete temp file */
unlink(tempfilename);
}
+
+ LWLockRelease(RelCacheInitLock);
+}
+
+/*
+ * Detect whether a given relation (identified by OID) is one of the ones
+ * we store in the init file.
+ *
+ * Note that we effectively assume that all backends running in a database
+ * would choose to store the same set of relations in the init file;
+ * otherwise there are cases where we'd fail to detect the need for an init
+ * file invalidation. This does not seem likely to be a problem in practice.
+ */
+bool
+RelationIdIsInInitFile(Oid relationId)
+{
+ return intMember((int) relationId, initFileRelationIds);
+}
+
+/*
+ * Invalidate (remove) the init file during commit of a transaction that
+ * changed one or more of the relation cache entries that are kept in the
+ * init file.
+ *
+ * We actually need to remove the init file twice: once just before sending
+ * the SI messages that include relcache inval for such relations, and once
+ * just after sending them. The unlink before ensures that a backend that's
+ * currently starting cannot read the now-obsolete init file and then miss
+ * the SI messages that will force it to update its relcache entries. (This
+ * works because the backend startup sequence gets into the PROC array before
+ * trying to load the init file.) The unlink after is to synchronize with a
+ * backend that may currently be trying to write an init file based on data
+ * that we've just rendered invalid. Such a backend will see the SI messages,
+ * but we can't leave the init file sitting around to fool later backends.
+ *
+ * Ignore any failure to unlink the file, since it might not be there if
+ * no backend has been started since the last removal.
+ */
+void
+RelationCacheInitFileInvalidate(bool beforeSend)
+{
+ char initfilename[MAXPGPATH];
+
+ snprintf(initfilename, sizeof(initfilename), "%s/%s",
+ DatabasePath, RELCACHE_INIT_FILENAME);
+
+ if (beforeSend)
+ {
+ /* no interlock needed here */
+ unlink(initfilename);
+ }
+ else
+ {
+ /*
+ * We need to interlock this against write_relcache_init_file,
+ * to guard against possibility that someone renames a new-but-
+ * already-obsolete init file into place just after we unlink.
+ * With the interlock, it's certain that write_relcache_init_file
+ * will notice our SI inval message before renaming into place,
+ * or else that we will execute second and successfully unlink
+ * the file.
+ */
+ LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
+ unlink(initfilename);
+ LWLockRelease(RelCacheInitLock);
+ }
}
*
*
* 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
0,
0
}},
+ {AccessMethodRelationName, /* AMOID */
+ AmOidIndex,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ }},
{AccessMethodOperatorRelationName, /* AMOPOPID */
AccessMethodOperatorIndex,
0,
}}
};
-static CatCache *SysCache[
- lengthof(cacheinfo)];
+static CatCache *SysCache[lengthof(cacheinfo)];
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
*
* 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
}
+/*
+ * 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
*
*
*
* 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 $
*
*
*-------------------------------------------------------------------------
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();
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();
/*
}
}
else
+ {
/* normal multiuser case */
InitializeSessionUserId(username);
+ }
/*
* Unless we are bootstrapping, double-check that InitMyDatabaseInfo()
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
#define IndexStrategyIsValid(s) PointerIsValid(s)
+extern ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
+ StrategyNumber strategyNumber);
extern StrategyMap IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
StrategyNumber maxStrategyNum, AttrNumber attrNum);
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
#define INDEX_H
#include "access/itup.h"
+#include "catalog/pg_index.h"
#include "nodes/execnodes.h"
void *state);
-extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
- MemoryContext resultCxt);
-
extern Oid index_create(char *heapRelationName,
char *indexRelationName,
IndexInfo *indexInfo,
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,
* 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 $
*
*-------------------------------------------------------------------------
*/
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
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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);
* 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 $
*
*-------------------------------------------------------------------------
*/
ControlFileLock,
CheckpointLock,
CLogControlLock,
+ RelCacheInitLock,
NumFixedLWLocks, /* must be last except for
* MaxDynamicLWLock */
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
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,
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
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
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);