*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.116 2000/06/17 04:56:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.117 2000/06/17 21:48:39 tgl Exp $
*
*
* INTERFACE ROUTINES
void
index_drop(Oid indexId)
{
+ Oid heapId;
Relation userHeapRelation;
Relation userIndexRelation;
Relation indexRelation;
* else other backends will still see this index in pg_index.
* ----------------
*/
- userHeapRelation = heap_open(IndexGetRelation(indexId),
- AccessExclusiveLock);
+ heapId = IndexGetRelation(indexId);
+ userHeapRelation = heap_open(heapId, AccessExclusiveLock);
userIndexRelation = index_open(indexId);
LockRelation(userIndexRelation, AccessExclusiveLock);
*/
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
+ /* Remove the pg_class tuple for the index itself */
tuple = SearchSysCacheTupleCopy(RELOID,
ObjectIdGetDatum(indexId),
0, 0, 0);
heap_delete(relationRelation, &tuple->t_self, NULL);
heap_freetuple(tuple);
+
+ /*
+ * Find the pg_class tuple for the owning relation. We do not attempt
+ * to clear relhasindex, since we are too lazy to test whether any other
+ * indexes remain (the next VACUUM will fix it if necessary). But we
+ * must send out a shared-cache-inval notice on the owning relation
+ * to ensure other backends update their relcache lists of indexes.
+ */
+ tuple = SearchSysCacheTupleCopy(RELOID,
+ ObjectIdGetDatum(heapId),
+ 0, 0, 0);
+
+ Assert(HeapTupleIsValid(tuple));
+
+ ImmediateInvalidateSharedHeapTuple(relationRelation, tuple);
+ heap_freetuple(tuple);
+
heap_close(relationRelation, RowExclusiveLock);
/* ----------------
*/
if (pg_class_scan)
{
-
- if (!IsBootstrapProcessingMode())
- ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
rd_rel->relhasindex = hasindex;
WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
htup.t_self = tuple->t_self;
heap_fetch(pg_class, SnapshotNow, &htup, &buffer);
- ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
rd_rel = (Form_pg_class) GETSTRUCT(&htup);
rd_rel->relhasindex = hasindex;
WriteBuffer(buffer);
}
+ /*
+ * Send out a shared-cache-inval message so other backends notice the
+ * update and fix their syscaches/relcaches.
+ */
+ if (!IsBootstrapProcessingMode())
+ ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
+
if (!pg_class_scan)
heap_freetuple(tuple);
else
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.114 2000/06/15 03:32:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.115 2000/06/17 21:48:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/builtins.h"
+#include "utils/relcache.h"
#include "utils/syscache.h"
#ifdef MULTIBYTE
* Space for the array itself is palloc'ed.
*/
-typedef struct rel_list
-{
- Oid index_rel_oid;
- struct rel_list *next;
-} RelationList;
-
static void
GetIndexRelations(Oid main_relation_oid,
int *n_indices,
Relation **index_rels)
{
- RelationList *head,
- *scan;
- Relation pg_index_rel;
- HeapScanDesc scandesc;
- Oid index_relation_oid;
- HeapTuple tuple;
- TupleDesc tupDesc;
+ Relation relation;
+ List *indexoidlist,
+ *indexoidscan;
int i;
- bool isnull;
- pg_index_rel = heap_openr(IndexRelationName, AccessShareLock);
- scandesc = heap_beginscan(pg_index_rel, 0, SnapshotNow, 0, NULL);
- tupDesc = RelationGetDescr(pg_index_rel);
+ relation = heap_open(main_relation_oid, AccessShareLock);
+ indexoidlist = RelationGetIndexList(relation);
- *n_indices = 0;
+ *n_indices = length(indexoidlist);
- head = (RelationList *) palloc(sizeof(RelationList));
- scan = head;
- head->next = NULL;
+ if (*n_indices > 0)
+ *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
+ else
+ *index_rels = NULL;
- while (HeapTupleIsValid(tuple = heap_getnext(scandesc, 0)))
+ i = 0;
+ foreach(indexoidscan, indexoidlist)
{
+ Oid indexoid = lfirsti(indexoidscan);
+ Relation index = index_open(indexoid);
- index_relation_oid = (Oid) DatumGetInt32(heap_getattr(tuple, 2,
- tupDesc, &isnull));
- if (index_relation_oid == main_relation_oid)
- {
- scan->index_rel_oid = (Oid) DatumGetInt32(heap_getattr(tuple,
- Anum_pg_index_indexrelid,
- tupDesc, &isnull));
- (*n_indices)++;
- scan->next = (RelationList *) palloc(sizeof(RelationList));
- scan = scan->next;
- }
- }
-
- heap_endscan(scandesc);
- heap_close(pg_index_rel, AccessShareLock);
-
- /* We cannot trust to relhasindex of the main_relation now, so... */
- if (*n_indices == 0)
- return;
-
- *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
-
- for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
- {
- (*index_rels)[i] = index_open(scan->index_rel_oid);
/* see comments in ExecOpenIndices() in execUtils.c */
- if ((*index_rels)[i] != NULL &&
- ((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID &&
- ((*index_rels)[i])->rd_rel->relam != HASH_AM_OID)
- LockRelation((*index_rels)[i], AccessExclusiveLock);
+ if (index != NULL &&
+ index->rd_rel->relam != BTREE_AM_OID &&
+ index->rd_rel->relam != HASH_AM_OID)
+ LockRelation(index, AccessExclusiveLock);
+ (*index_rels)[i] = index;
+ i++;
}
- for (i = 0, scan = head; i < *n_indices + 1; i++)
- {
- scan = head->next;
- pfree(head);
- head = scan;
- }
+ freeList(indexoidlist);
+ heap_close(relation, AccessShareLock);
}
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.29 2000/06/15 03:32:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.30 2000/06/17 21:48:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
lossy, unique, primary);
}
+ /*
+ * We update the relation's pg_class tuple even if it already has
+ * relhasindex = true. This is needed to cause a shared-cache-inval
+ * message to be sent for the pg_class tuple, which will cause other
+ * backends to flush their relcache entries and in particular their
+ * cached lists of the indexes for this relation.
+ */
setRelhasindexInplace(relationId, true, false);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.159 2000/05/29 17:40:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
*
*-------------------------------------------------------------------------
static VacPage tid_reaped(ItemPointer itemptr, VacPageList vacpagelist);
static void reap_page(VacPageList vacpagelist, VacPage vacpage);
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
-static void get_indices(Oid relid, int *nindices, Relation **Irel);
+static void get_indices(Relation relation, int *nindices, Relation **Irel);
static void close_indices(int nindices, Relation *Irel);
static void get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
static void *vac_find_eq(void *bot, int nelem, int size, void *elm,
/* Now open indices */
nindices = 0;
Irel = (Relation *) NULL;
- get_indices(vacrelstats->relid, &nindices, &Irel);
+ get_indices(onerel, &nindices, &Irel);
if (!Irel)
reindex = false;
else if (!RelationGetForm(onerel)->relhasindex)
return CommonSpecialPortalInUse;
}
+
static void
-get_indices(Oid relid, int *nindices, Relation **Irel)
+get_indices(Relation relation, int *nindices, Relation **Irel)
{
- Relation pgindex;
- Relation irel;
- TupleDesc tupdesc;
- HeapTuple tuple;
- HeapScanDesc scan;
- Datum d;
- int i,
- k;
- bool n;
- ScanKeyData key;
- Oid *ioid;
-
- *nindices = i = 0;
-
- ioid = (Oid *) palloc(10 * sizeof(Oid));
-
- /* prepare a heap scan on the pg_index relation */
- pgindex = heap_openr(IndexRelationName, AccessShareLock);
- tupdesc = RelationGetDescr(pgindex);
-
- ScanKeyEntryInitialize(&key, 0x0, Anum_pg_index_indrelid,
- F_OIDEQ,
- ObjectIdGetDatum(relid));
-
- scan = heap_beginscan(pgindex, false, SnapshotNow, 1, &key);
-
- while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
- {
- d = heap_getattr(tuple, Anum_pg_index_indexrelid,
- tupdesc, &n);
- i++;
- if (i % 10 == 0)
- ioid = (Oid *) repalloc(ioid, (i + 10) * sizeof(Oid));
- ioid[i - 1] = DatumGetObjectId(d);
- }
+ List *indexoidlist,
+ *indexoidscan;
+ int i;
- heap_endscan(scan);
- heap_close(pgindex, AccessShareLock);
+ indexoidlist = RelationGetIndexList(relation);
- if (i == 0)
- { /* No one index found */
- pfree(ioid);
- return;
- }
+ *nindices = length(indexoidlist);
- if (Irel != (Relation **) NULL)
- *Irel = (Relation *) palloc(i * sizeof(Relation));
+ if (*nindices > 0)
+ *Irel = (Relation *) palloc(*nindices * sizeof(Relation));
+ else
+ *Irel = NULL;
- for (k = 0; i > 0;)
+ i = 0;
+ foreach(indexoidscan, indexoidlist)
{
- irel = index_open(ioid[--i]);
- if (irel != (Relation) NULL)
- {
- if (Irel != (Relation **) NULL)
- (*Irel)[k] = irel;
- else
- index_close(irel);
- k++;
- }
- else
- elog(NOTICE, "CAN'T OPEN INDEX %u - SKIP IT", ioid[i]);
- }
- *nindices = k;
- pfree(ioid);
+ Oid indexoid = lfirsti(indexoidscan);
- if (Irel != (Relation **) NULL && *nindices == 0)
- {
- pfree(*Irel);
- *Irel = (Relation *) NULL;
+ (*Irel)[i] = index_open(indexoid);
+ i++;
}
+ freeList(indexoidlist);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.117 2000/06/15 04:09:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.118 2000/06/17 21:48:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
if (resultRelationDesc->rd_rel->relhasindex &&
operation != CMD_DELETE)
- ExecOpenIndices(resultRelationOid, resultRelationInfo);
+ ExecOpenIndices(resultRelationInfo);
estate->es_result_relation_info = resultRelationInfo;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.59 2000/06/15 04:09:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.60 2000/06/17 21:48:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
+#include "utils/relcache.h"
+#include "utils/syscache.h"
static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP,
AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
* check parameters
* ----------------
*/
- if (numAttsOutP == NULL && attsOutP == NULL)
+ if (numAttsOutP == NULL || attsOutP == NULL)
{
elog(DEBUG, "ExecGetIndexKeyInfo: %s",
"invalid parameters: numAttsOutP and attsOutP must be non-NULL");
/* ----------------------------------------------------------------
* ExecOpenIndices
*
- * Here we scan the pg_index relation to find indices
- * associated with a given heap relation oid. Since we
- * don't know in advance how many indices we have, we
- * form lists containing the information we need from
- * pg_index and then process these lists.
+ * Find the indices associated with a result relation, open them,
+ * and save information about them in the result RelationInfo.
*
- * Note: much of this code duplicates effort done by
- * the IndexCatalogInformation function in plancat.c
- * because IndexCatalogInformation is poorly written.
+ * At entry, caller has already opened and locked
+ * resultRelationInfo->ri_RelationDesc.
*
- * It would be much better if the functionality provided
- * by this function and IndexCatalogInformation was
- * in the form of a small set of orthogonal routines..
- * If you are trying to understand this, I suggest you
- * look at the code to IndexCatalogInformation and
- * FormIndexTuple.. -cim 9/27/89
+ * This used to be horribly ugly code, and slow too because it
+ * did a sequential scan of pg_index. Now we rely on the relcache
+ * to cache a list of the OIDs of the indices associated with any
+ * specific relation, and we use the pg_index syscache to get the
+ * entries we need from pg_index.
* ----------------------------------------------------------------
*/
void
-ExecOpenIndices(Oid resultRelationOid,
- RelationInfo *resultRelationInfo)
+ExecOpenIndices(RelationInfo *resultRelationInfo)
{
- Relation indexRd;
- HeapScanDesc indexSd;
- ScanKeyData key;
- HeapTuple tuple;
- Form_pg_index indexStruct;
- Oid indexOid;
- List *oidList;
- List *nkeyList;
- List *keyList;
- List *fiList;
- char *predString;
- List *predList;
- List *indexoid;
- List *numkeys;
- List *indexkeys;
- List *indexfuncs;
- List *indexpreds;
- int len;
-
+ Relation resultRelation = resultRelationInfo->ri_RelationDesc;
+ List *indexoidlist,
+ *indexoidscan;
+ int len,
+ i;
RelationPtr relationDescs;
IndexInfo **indexInfoArray;
- FuncIndexInfoPtr fInfoP;
- int numKeyAtts;
- AttrNumber *indexKeyAtts;
- PredInfo *predicate;
- int i;
resultRelationInfo->ri_NumIndices = 0;
- if (!RelationGetForm(resultRelationInfo->ri_RelationDesc)->relhasindex)
+
+ /* checks for disabled indexes */
+ if (! RelationGetForm(resultRelation)->relhasindex)
return;
if (IsIgnoringSystemIndexes() &&
- IsSystemRelationName(RelationGetRelationName(resultRelationInfo->ri_RelationDesc)))
+ IsSystemRelationName(RelationGetRelationName(resultRelation)))
return;
+
/* ----------------
- * open pg_index
+ * Get cached list of index OIDs
* ----------------
*/
- indexRd = heap_openr(IndexRelationName, AccessShareLock);
+ indexoidlist = RelationGetIndexList(resultRelation);
+ len = length(indexoidlist);
+ if (len == 0)
+ return;
/* ----------------
- * form a scan key
+ * allocate space for result arrays
* ----------------
*/
- ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
- F_OIDEQ,
- ObjectIdGetDatum(resultRelationOid));
+ relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
+ indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
+
+ resultRelationInfo->ri_NumIndices = len;
+ resultRelationInfo->ri_IndexRelationDescs = relationDescs;
+ resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
/* ----------------
- * scan the index relation, looking for indices for our
- * result relation..
+ * For each index, open the index relation and save pg_index info.
* ----------------
*/
- indexSd = heap_beginscan(indexRd, /* scan desc */
- false, /* scan backward flag */
- SnapshotNow, /* NOW snapshot */
- 1, /* number scan keys */
- &key); /* scan keys */
-
- oidList = NIL;
- nkeyList = NIL;
- keyList = NIL;
- fiList = NIL;
- predList = NIL;
-
- while (HeapTupleIsValid(tuple = heap_getnext(indexSd, 0)))
+ i = 0;
+ foreach(indexoidscan, indexoidlist)
{
+ Oid indexOid = lfirsti(indexoidscan);
+ Relation indexDesc;
+ HeapTuple indexTuple;
+ Form_pg_index indexStruct;
+ int numKeyAtts;
+ AttrNumber *indexKeyAtts;
+ FuncIndexInfoPtr fInfoP;
+ PredInfo *predicate;
+ IndexInfo *ii;
/* ----------------
- * For each index relation we find, extract the information
- * we need and store it in a list..
+ * Open (and lock, if necessary) the index relation
*
- * first get the oid of the index relation from the tuple
+ * Hack for not btree and hash indices: they use relation
+ * level exclusive locking on update (i.e. - they are not
+ * ready for MVCC) and so we have to exclusively lock
+ * indices here to prevent deadlocks if we will scan them
+ * - index_beginscan places AccessShareLock, indices
+ * update methods don't use locks at all. We release this
+ * lock in ExecCloseIndices. Note, that hashes use page
+ * level locking - i.e. are not deadlock-free, - let's
+ * them be on their way -:)) vadim 03-12-1998
* ----------------
*/
- indexStruct = (Form_pg_index) GETSTRUCT(tuple);
- indexOid = indexStruct->indexrelid;
+ indexDesc = index_open(indexOid);
+
+ if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
+ indexDesc->rd_rel->relam != HASH_AM_OID)
+ LockRelation(indexDesc, AccessExclusiveLock);
/* ----------------
- * allocate space for functional index information.
+ * Get the pg_index tuple for the index
* ----------------
*/
- fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
+ indexTuple = SearchSysCacheTupleCopy(INDEXRELID,
+ ObjectIdGetDatum(indexOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indexTuple))
+ elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
+ indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
/* ----------------
- * next get the index key information from the tuple
+ * extract the index key information from the tuple
* ----------------
*/
+ fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
ExecGetIndexKeyInfo(indexStruct,
&numKeyAtts,
&indexKeyAtts,
*/
if (VARSIZE(&indexStruct->indpred) != 0)
{
+ char *predString;
+
predString = textout(&indexStruct->indpred);
predicate = (PredInfo *) stringToNode(predString);
pfree(predString);
else
predicate = NULL;
- /* ----------------
- * save the index information into lists
- * ----------------
- */
- oidList = lconsi(indexOid, oidList);
- nkeyList = lconsi(numKeyAtts, nkeyList);
- keyList = lcons(indexKeyAtts, keyList);
- fiList = lcons(fInfoP, fiList);
- predList = lcons(predicate, predList);
- }
-
- /* ----------------
- * we have the info we need so close the pg_index relation..
- * ----------------
- */
- heap_endscan(indexSd);
- heap_close(indexRd, AccessShareLock);
-
- /* ----------------
- * Now that we've collected the index information into three
- * lists, we open the index relations and store the descriptors
- * and the key information into arrays.
- * ----------------
- */
- len = length(oidList);
- if (len > 0)
- {
- /* ----------------
- * allocate space for relation descs
- * ----------------
- */
- CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
- relationDescs = (RelationPtr)
- palloc(len * sizeof(Relation));
-
- /* ----------------
- * initialize index info array
- * ----------------
- */
- CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
- indexInfoArray = (IndexInfo **)
- palloc(len * sizeof(IndexInfo *));
-
- for (i = 0; i < len; i++)
- {
- IndexInfo *ii = makeNode(IndexInfo);
+ /* Save the index info */
+ ii = makeNode(IndexInfo);
+ ii->ii_NumKeyAttributes = numKeyAtts;
+ ii->ii_KeyAttributeNumbers = indexKeyAtts;
+ ii->ii_FuncIndexInfo = fInfoP;
+ ii->ii_Predicate = (Node *) predicate;
- ii->ii_NumKeyAttributes = 0;
- ii->ii_KeyAttributeNumbers = (AttrNumber *) NULL;
- ii->ii_FuncIndexInfo = (FuncIndexInfoPtr) NULL;
- ii->ii_Predicate = NULL;
- indexInfoArray[i] = ii;
- }
+ heap_freetuple(indexTuple);
- /* ----------------
- * attempt to open each of the indices. If we succeed,
- * then store the index relation descriptor into the
- * relation descriptor array.
- * ----------------
- */
- i = 0;
- foreach(indexoid, oidList)
- {
- Relation indexDesc;
-
- indexOid = lfirsti(indexoid);
- indexDesc = index_open(indexOid);
- if (indexDesc != NULL)
- {
- relationDescs[i++] = indexDesc;
-
- /*
- * Hack for not btree and hash indices: they use relation
- * level exclusive locking on update (i.e. - they are not
- * ready for MVCC) and so we have to exclusively lock
- * indices here to prevent deadlocks if we will scan them
- * - index_beginscan places AccessShareLock, indices
- * update methods don't use locks at all. We release this
- * lock in ExecCloseIndices. Note, that hashes use page
- * level locking - i.e. are not deadlock-free, - let's
- * them be on their way -:)) vadim 03-12-1998
- */
- if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
- indexDesc->rd_rel->relam != HASH_AM_OID)
- LockRelation(indexDesc, AccessExclusiveLock);
- }
- }
-
- /* ----------------
- * store the relation descriptor array and number of
- * descs into the result relation info.
- * ----------------
- */
- resultRelationInfo->ri_NumIndices = i;
- resultRelationInfo->ri_IndexRelationDescs = relationDescs;
-
- /* ----------------
- * store the index key information collected in our
- * lists into the index info array
- * ----------------
- */
- i = 0;
- foreach(numkeys, nkeyList)
- {
- numKeyAtts = lfirsti(numkeys);
- indexInfoArray[i++]->ii_NumKeyAttributes = numKeyAtts;
- }
-
- i = 0;
- foreach(indexkeys, keyList)
- {
- indexKeyAtts = (AttrNumber *) lfirst(indexkeys);
- indexInfoArray[i++]->ii_KeyAttributeNumbers = indexKeyAtts;
- }
-
- i = 0;
- foreach(indexfuncs, fiList)
- {
- FuncIndexInfoPtr fiP = (FuncIndexInfoPtr) lfirst(indexfuncs);
-
- indexInfoArray[i++]->ii_FuncIndexInfo = fiP;
- }
-
- i = 0;
- foreach(indexpreds, predList)
- indexInfoArray[i++]->ii_Predicate = lfirst(indexpreds);
- /* ----------------
- * store the index info array into relation info
- * ----------------
- */
- resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
+ relationDescs[i] = indexDesc;
+ indexInfoArray[i] = ii;
+ i++;
}
- /* ----------------
- * All done, resultRelationInfo now contains complete information
- * on the indices associated with the result relation.
- * ----------------
- */
-
- /* should free oidList, nkeyList and keyList here */
- /* OK - let's do it -jolly */
- freeList(oidList);
- freeList(nkeyList);
- freeList(keyList);
- freeList(fiList);
- freeList(predList);
+ freeList(indexoidlist);
}
/* ----------------------------------------------------------------
*/
}
-/* ----------------------------------------------------------------
- * ExecFormIndexTuple
- *
- * Most of this code is cannabilized from DefaultBuild().
- * As said in the comments for ExecOpenIndices, most of
- * this functionality should be rearranged into a proper
- * set of routines..
- * ----------------------------------------------------------------
- */
-#ifdef NOT_USED
-IndexTuple
-ExecFormIndexTuple(HeapTuple heapTuple,
- Relation heapRelation,
- Relation indexRelation,
- IndexInfo *indexInfo)
-{
- IndexTuple indexTuple;
- TupleDesc heapDescriptor;
- TupleDesc indexDescriptor;
- Datum *datum;
- char *nulls;
-
- int numberOfAttributes;
- AttrNumber *keyAttributeNumbers;
- FuncIndexInfoPtr fInfoP;
-
- /* ----------------
- * get information from index info structure
- * ----------------
- */
- numberOfAttributes = indexInfo->ii_NumKeyAttributes;
- keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
- fInfoP = indexInfo->ii_FuncIndexInfo;
-
- /* ----------------
- * datum and null are arrays in which we collect the index attributes
- * when forming a new index tuple.
- * ----------------
- */
- CXT1_printf("ExecFormIndexTuple: context is %d\n", CurrentMemoryContext);
- datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
- nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
-
- /* ----------------
- * get the tuple descriptors from the relations so we know
- * how to form the index tuples..
- * ----------------
- */
- heapDescriptor = RelationGetDescr(heapRelation);
- indexDescriptor = RelationGetDescr(indexRelation);
-
- /* ----------------
- * FormIndexDatum fills in its datum and null parameters
- * with attribute information taken from the given heap tuple.
- * ----------------
- */
- FormIndexDatum(numberOfAttributes, /* num attributes */
- keyAttributeNumbers, /* array of att nums to extract */
- heapTuple, /* tuple from base relation */
- heapDescriptor, /* heap tuple's descriptor */
- datum, /* return: array of attributes */
- nulls, /* return: array of char's */
- fInfoP); /* functional index information */
-
- indexTuple = index_formtuple(indexDescriptor,
- datum,
- nulls);
-
- /* ----------------
- * free temporary arrays
- *
- * XXX should store these in the IndexInfo instead of allocating
- * and freeing on every insertion, but efficency here is not
- * that important and FormIndexTuple is wasteful anyways..
- * -cim 9/27/89
- * ----------------
- */
- pfree(nulls);
- pfree(datum);
-
- return indexTuple;
-}
-
-#endif
-
/* ----------------------------------------------------------------
* ExecInsertIndexTuples
*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.33 2000/06/15 04:09:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.34 2000/06/17 21:48:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* indices, but how to tell that here?
*/
if (rri->ri_RelationDesc->rd_rel->relhasindex)
- ExecOpenIndices(reloid, rri);
+ ExecOpenIndices(rri);
}
/*
*
*
* IDENTIFICATION
-<<<<<<< plancat.c
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.56 2000/06/15 03:32:16 momjian Exp $
-=======
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.56 2000/06/15 03:32:16 momjian Exp $
->>>>>>> 1.53
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.57 2000/06/17 21:48:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
+#include "utils/relcache.h"
#include "utils/syscache.h"
#include "catalog/catalog.h"
#include "miscadmin.h"
Form_pg_class relation;
relationTuple = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relationObjectId),
+ ObjectIdGetDatum(relationObjectId),
0, 0, 0);
if (!HeapTupleIsValid(relationTuple))
elog(ERROR, "relation_info: Relation %u not found",
List *
find_secondary_indexes(Query *root, Index relid)
{
- List *indexes = NIL;
+ List *indexinfos = NIL;
+ List *indexoidlist,
+ *indexoidscan;
Oid indrelid = getrelid(relid, root->rtable);
Relation relation;
- HeapScanDesc scan;
- ScanKeyData indexKey;
- HeapTuple indexTuple;
-
- /* Scan pg_index for tuples describing indexes of this rel */
- relation = heap_openr(IndexRelationName, AccessShareLock);
- ScanKeyEntryInitialize(&indexKey, 0,
- Anum_pg_index_indrelid,
- F_OIDEQ,
- ObjectIdGetDatum(indrelid));
+ /*
+ * We used to scan pg_index directly, but now the relcache offers
+ * a cached list of OID indexes for each relation. So, get that list
+ * and then use the syscache to obtain pg_index entries.
+ */
+ relation = heap_open(indrelid, AccessShareLock);
+ indexoidlist = RelationGetIndexList(relation);
- scan = heap_beginscan(relation, 0, SnapshotNow,
- 1, &indexKey);
-
- while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
+ foreach(indexoidscan, indexoidlist)
{
- Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
- IndexOptInfo *info = makeNode(IndexOptInfo);
+ Oid indexoid = lfirsti(indexoidscan);
+ HeapTuple indexTuple;
+ Form_pg_index index;
+ IndexOptInfo *info;
int i;
Relation indexRelation;
Oid relam;
uint16 amorderstrategy;
+ indexTuple = SearchSysCacheTupleCopy(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);
+ info = makeNode(IndexOptInfo);
+
/*
* Need to make these arrays large enough to be sure there is a
* terminating 0 at the end of each one.
}
}
- indexes = lcons(info, indexes);
+ heap_freetuple(indexTuple);
+
+ indexinfos = lcons(info, indexinfos);
}
- heap_endscan(scan);
+ freeList(indexoidlist);
+
+ /* XXX keep the lock here? */
heap_close(relation, AccessShareLock);
- return indexes;
+ return indexinfos;
}
/*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: analyze.c,v 1.147 2000/06/12 19:40:40 momjian Exp $
+ * $Id: analyze.c,v 1.148 2000/06/17 21:48:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
+#include "utils/relcache.h"
+#include "utils/syscache.h"
void CheckSelectForUpdate(Query *qry); /* no points for style... */
{
Relation pkrel;
Form_pg_attribute *pkrel_attrs;
- Relation indexRd;
- HeapScanDesc indexSd;
- ScanKeyData key;
- HeapTuple indexTup;
+ List *indexoidlist,
+ *indexoidscan;
Form_pg_index indexStruct = NULL;
- Ident *pkattr;
- int pkattno;
int i;
/* ----------
pkrel_attrs = pkrel->rd_att->attrs;
/* ----------
- * Open pg_index and begin a scan for all indices defined on
- * the referenced table
+ * Get the list of index OIDs for the table from the relcache,
+ * and look up each one in the pg_index syscache until we find one
+ * marked primary key (hopefully there isn't more than one such).
* ----------
*/
- indexRd = heap_openr(IndexRelationName, AccessShareLock);
- ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
- F_OIDEQ,
- ObjectIdGetDatum(pkrel->rd_id));
- indexSd = heap_beginscan(indexRd, /* scan desc */
- false, /* scan backward flag */
- SnapshotNow, /* NOW snapshot */
- 1, /* number scan keys */
- &key); /* scan keys */
+ indexoidlist = RelationGetIndexList(pkrel);
- /* ----------
- * Fetch the index with indisprimary == true
- * ----------
- */
- while (HeapTupleIsValid(indexTup = heap_getnext(indexSd, 0)))
+ foreach(indexoidscan, indexoidlist)
{
- indexStruct = (Form_pg_index) GETSTRUCT(indexTup);
-
+ Oid indexoid = lfirsti(indexoidscan);
+ HeapTuple indexTuple;
+
+ indexTuple = SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(indexoid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indexTuple))
+ elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
+ indexoid);
+ indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
if (indexStruct->indisprimary)
break;
+ indexStruct = NULL;
}
+ freeList(indexoidlist);
+
/* ----------
* Check that we found it
* ----------
*/
- if (!HeapTupleIsValid(indexTup))
+ if (indexStruct == NULL)
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
fkconstraint->pktable_name);
*/
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
{
- pkattno = indexStruct->indkey[i];
- pkattr = (Ident *) makeNode(Ident);
+ int pkattno = indexStruct->indkey[i];
+ Ident *pkattr = makeNode(Ident);
+
pkattr->name = nameout(&(pkrel_attrs[pkattno - 1]->attname));
pkattr->indirection = NIL;
pkattr->isRel = false;
fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
}
- /* ----------
- * End index scan and close relations
- * ----------
- */
- heap_endscan(indexSd);
- heap_close(indexRd, AccessShareLock);
heap_close(pkrel, AccessShareLock);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.100 2000/06/17 04:56:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.101 2000/06/17 21:48:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_attrdef.h"
+#include "catalog/pg_index.h"
#include "catalog/pg_log.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_relcheck.h"
FormData_pg_attribute *att)
{
Relation relation;
- Size len;
u_int i;
/* ----------------
* allocate new relation desc
* ----------------
*/
- len = sizeof(RelationData);
- relation = (Relation) palloc(len);
- MemSet((char *) relation, 0, len);
+ relation = (Relation) palloc(sizeof(RelationData));
+ MemSet((char *) relation, 0, sizeof(RelationData));
/* ----------------
* don't open the unix file yet..
* initialize relation tuple form
* ----------------
*/
- relation->rd_rel = (Form_pg_class)
- palloc((Size) (sizeof(*relation->rd_rel)));
- MemSet(relation->rd_rel, 0, sizeof(FormData_pg_class));
+ relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
+ MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
strcpy(RelationGetPhysicalRelationName(relation), relationName);
/* ----------------
pfree(relation->rd_istrat);
if (relation->rd_support)
pfree(relation->rd_support);
+ freeList(relation->rd_indexlist);
/*
* If we're really done with the relcache entry, blow it away. But if
heap_close(rcrel, AccessShareLock);
}
+/*
+ * RelationGetIndexList -- get a list of OIDs of indexes on this relation
+ *
+ * The index list is created only if someone requests it. We scan pg_index
+ * to find relevant indexes, and add the list to the relcache entry so that
+ * we won't have to compute it again. Note that shared cache inval of a
+ * relcache entry will delete the old list and set rd_indexfound to false,
+ * so that we must recompute the index list on next request. This handles
+ * creation or deletion of an index.
+ *
+ * Since shared cache inval causes the relcache's copy of the list to go away,
+ * we return a copy of the list palloc'd in the caller's context. The caller
+ * may freeList() the returned list after scanning it. This is necessary
+ * since the caller will typically be doing syscache lookups on the relevant
+ * indexes, and syscache lookup could cause SI messages to be processed!
+ */
+List *
+RelationGetIndexList(Relation relation)
+{
+ Relation indrel;
+ Relation irel = (Relation) NULL;
+ ScanKeyData skey;
+ IndexScanDesc sd = (IndexScanDesc) NULL;
+ HeapScanDesc hscan = (HeapScanDesc) NULL;
+ bool hasindex;
+ List *result;
+ MemoryContext oldcxt;
+
+ /* Quick exit if we already computed the list. */
+ 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 copy that
+ * list into the relcache entry. This avoids cache-context memory leakage
+ * if we get some sort of error partway through.
+ */
+ result = NIL;
+
+ for (;;)
+ {
+ HeapTupleData tuple;
+ HeapTuple htup;
+ Buffer buffer;
+ Form_pg_index index;
+
+ 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);
+ pfree(indexRes);
+ if (tuple.t_data == NULL)
+ continue;
+ htup = &tuple;
+ }
+ else
+ {
+ htup = heap_getnext(hscan, 0);
+ if (!HeapTupleIsValid(htup))
+ break;
+ }
+
+ index = (Form_pg_index) GETSTRUCT(htup);
+
+ result = lappendi(result, index->indexrelid);
+
+ if (hasindex)
+ ReleaseBuffer(buffer);
+ }
+
+ if (hasindex)
+ {
+ index_endscan(sd);
+ index_close(irel);
+ }
+ else
+ heap_endscan(hscan);
+ heap_close(indrel, AccessShareLock);
+
+ /* Now we can save the completed list in the relcache entry. */
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ relation->rd_indexlist = listCopy(result);
+ relation->rd_indexfound = true;
+ MemoryContextSwitchTo(oldcxt);
+
+ return result;
+}
+
/*
* init_irels(), write_irels() -- handle special-case initialization of
* index relation descriptors.
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: executor.h,v 1.43 2000/05/29 01:59:11 tgl Exp $
+ * $Id: executor.h,v 1.44 2000/06/17 21:48:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
CommonScanState *csstate);
extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc);
-extern void ExecOpenIndices(Oid resultRelationOid,
- RelationInfo *resultRelationInfo);
+extern void ExecOpenIndices(RelationInfo *resultRelationInfo);
extern void ExecCloseIndices(RelationInfo *resultRelationInfo);
extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate, bool is_update);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: rel.h,v 1.36 2000/04/12 17:16:55 momjian Exp $
+ * $Id: rel.h,v 1.37 2000/06/17 21:49:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool rd_isnailed; /* rel is nailed in cache */
bool rd_isnoname; /* rel has no name */
bool rd_unlinked; /* rel already unlinked or not created yet */
+ bool rd_indexfound; /* true if rd_indexlist is valid */
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 for locking
- * relation */
+ 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 */
- IndexStrategy rd_istrat;
+ IndexStrategy rd_istrat; /* info needed if rel is an index */
RegProcedure *rd_support;
TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */
} RelationData;
* RelationSetReferenceCount
* Sets relation reference count.
*/
-#define RelationSetReferenceCount(relation,count) ((relation)->rd_refcnt = (count))
+#define RelationSetReferenceCount(relation,count) \
+ ((relation)->rd_refcnt = (count))
/*
* RelationIncrementReferenceCount
* Increments relation reference count.
*/
-#define RelationIncrementReferenceCount(relation) ((relation)->rd_refcnt += 1)
+#define RelationIncrementReferenceCount(relation) \
+ ((relation)->rd_refcnt += 1)
/*
* RelationDecrementReferenceCount
*
* Returns a Relation Name
*/
-#define RelationGetPhysicalRelationName(relation) (NameStr((relation)->rd_rel->relname))
+#define RelationGetPhysicalRelationName(relation) \
+ (NameStr((relation)->rd_rel->relname))
/*
* RelationGetNumberOfAttributes
*/
#define RelationGetIndexStrategy(relation) ((relation)->rd_istrat)
-
+/*
+ * Routines in utils/cache/rel.c
+ */
extern void RelationSetIndexSupport(Relation relation,
- IndexStrategy strategy,
- RegProcedure *support);
+ IndexStrategy strategy,
+ RegProcedure *support);
#endif /* REL_H */
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: relcache.h,v 1.19 2000/01/31 04:35:57 tgl Exp $
+ * $Id: relcache.h,v 1.20 2000/06/17 21:49:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* relation lookup routines
*/
-extern Relation RelationIdCacheGetRelation(Oid relationId);
extern Relation RelationIdGetRelation(Oid relationId);
extern Relation RelationNameGetRelation(const char *relationName);
+/* finds an existing cache entry, but won't make a new one */
+extern Relation RelationIdCacheGetRelation(Oid relationId);
+
extern void RelationClose(Relation relation);
extern void RelationForgetRelation(Oid rid);
+/*
+ * Routines to compute/retrieve additional cached information
+ */
+extern List *RelationGetIndexList(Relation relation);
+
/*
* Routines for flushing/rebuilding relcache entries in various scenarios
*/