Commit d03a933e authored by Tom Lane's avatar Tom Lane

Fix performance problems with pg_index lookups (see, for example,

discussion of 5/19/00).  pg_index is now searched for indexes of a
relation using an indexscan.  Moreover, this is done once and cached
in the relcache entry for the relation, in the form of a list of OIDs
for the indexes.  This list is used by the parser and executor to drive
lookups in the pg_index syscache when they want to know the properties
of the indexes.  Net result: index information will be fully cached
for repetitive operations such as inserts.
parent 9cf80f2f
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -1105,6 +1105,7 @@ index_create(char *heapRelationName, ...@@ -1105,6 +1105,7 @@ index_create(char *heapRelationName,
void void
index_drop(Oid indexId) index_drop(Oid indexId)
{ {
Oid heapId;
Relation userHeapRelation; Relation userHeapRelation;
Relation userIndexRelation; Relation userIndexRelation;
Relation indexRelation; Relation indexRelation;
...@@ -1125,8 +1126,8 @@ index_drop(Oid indexId) ...@@ -1125,8 +1126,8 @@ index_drop(Oid indexId)
* else other backends will still see this index in pg_index. * else other backends will still see this index in pg_index.
* ---------------- * ----------------
*/ */
userHeapRelation = heap_open(IndexGetRelation(indexId), heapId = IndexGetRelation(indexId);
AccessExclusiveLock); userHeapRelation = heap_open(heapId, AccessExclusiveLock);
userIndexRelation = index_open(indexId); userIndexRelation = index_open(indexId);
LockRelation(userIndexRelation, AccessExclusiveLock); LockRelation(userIndexRelation, AccessExclusiveLock);
...@@ -1158,6 +1159,7 @@ index_drop(Oid indexId) ...@@ -1158,6 +1159,7 @@ index_drop(Oid indexId)
*/ */
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock); relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
/* Remove the pg_class tuple for the index itself */
tuple = SearchSysCacheTupleCopy(RELOID, tuple = SearchSysCacheTupleCopy(RELOID,
ObjectIdGetDatum(indexId), ObjectIdGetDatum(indexId),
0, 0, 0); 0, 0, 0);
...@@ -1166,6 +1168,23 @@ index_drop(Oid indexId) ...@@ -1166,6 +1168,23 @@ index_drop(Oid indexId)
heap_delete(relationRelation, &tuple->t_self, NULL); heap_delete(relationRelation, &tuple->t_self, NULL);
heap_freetuple(tuple); 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); heap_close(relationRelation, RowExclusiveLock);
/* ---------------- /* ----------------
...@@ -1447,9 +1466,6 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate) ...@@ -1447,9 +1466,6 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
*/ */
if (pg_class_scan) if (pg_class_scan)
{ {
if (!IsBootstrapProcessingMode())
ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
rd_rel = (Form_pg_class) GETSTRUCT(tuple); rd_rel = (Form_pg_class) GETSTRUCT(tuple);
rd_rel->relhasindex = hasindex; rd_rel->relhasindex = hasindex;
WriteNoReleaseBuffer(pg_class_scan->rs_cbuf); WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
...@@ -1461,12 +1477,18 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate) ...@@ -1461,12 +1477,18 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
htup.t_self = tuple->t_self; htup.t_self = tuple->t_self;
heap_fetch(pg_class, SnapshotNow, &htup, &buffer); heap_fetch(pg_class, SnapshotNow, &htup, &buffer);
ImmediateInvalidateSharedHeapTuple(pg_class, tuple);
rd_rel = (Form_pg_class) GETSTRUCT(&htup); rd_rel = (Form_pg_class) GETSTRUCT(&htup);
rd_rel->relhasindex = hasindex; rd_rel->relhasindex = hasindex;
WriteBuffer(buffer); 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) if (!pg_class_scan)
heap_freetuple(tuple); heap_freetuple(tuple);
else else
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#ifdef MULTIBYTE #ifdef MULTIBYTE
...@@ -1081,78 +1082,43 @@ IsTypeByVal(Oid type) ...@@ -1081,78 +1082,43 @@ IsTypeByVal(Oid type)
* Space for the array itself is palloc'ed. * Space for the array itself is palloc'ed.
*/ */
typedef struct rel_list
{
Oid index_rel_oid;
struct rel_list *next;
} RelationList;
static void static void
GetIndexRelations(Oid main_relation_oid, GetIndexRelations(Oid main_relation_oid,
int *n_indices, int *n_indices,
Relation **index_rels) Relation **index_rels)
{ {
RelationList *head, Relation relation;
*scan; List *indexoidlist,
Relation pg_index_rel; *indexoidscan;
HeapScanDesc scandesc;
Oid index_relation_oid;
HeapTuple tuple;
TupleDesc tupDesc;
int i; int i;
bool isnull;
pg_index_rel = heap_openr(IndexRelationName, AccessShareLock); relation = heap_open(main_relation_oid, AccessShareLock);
scandesc = heap_beginscan(pg_index_rel, 0, SnapshotNow, 0, NULL); indexoidlist = RelationGetIndexList(relation);
tupDesc = RelationGetDescr(pg_index_rel);
*n_indices = 0; *n_indices = length(indexoidlist);
head = (RelationList *) palloc(sizeof(RelationList)); if (*n_indices > 0)
scan = head; *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
head->next = NULL; 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 */ /* see comments in ExecOpenIndices() in execUtils.c */
if ((*index_rels)[i] != NULL && if (index != NULL &&
((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID && index->rd_rel->relam != BTREE_AM_OID &&
((*index_rels)[i])->rd_rel->relam != HASH_AM_OID) index->rd_rel->relam != HASH_AM_OID)
LockRelation((*index_rels)[i], AccessExclusiveLock); LockRelation(index, AccessExclusiveLock);
(*index_rels)[i] = index;
i++;
} }
for (i = 0, scan = head; i < *n_indices + 1; i++) freeList(indexoidlist);
{ heap_close(relation, AccessShareLock);
scan = head->next;
pfree(head);
head = scan;
}
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -221,6 +221,13 @@ DefineIndex(char *heapRelationName, ...@@ -221,6 +221,13 @@ DefineIndex(char *heapRelationName,
lossy, unique, primary); 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); setRelhasindexInplace(relationId, true, false);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -72,7 +72,7 @@ static void update_relstats(Oid relid, int num_pages, int num_tuples, bool hasin ...@@ -72,7 +72,7 @@ static void update_relstats(Oid relid, int num_pages, int num_tuples, bool hasin
static VacPage tid_reaped(ItemPointer itemptr, VacPageList vacpagelist); static VacPage tid_reaped(ItemPointer itemptr, VacPageList vacpagelist);
static void reap_page(VacPageList vacpagelist, VacPage vacpage); static void reap_page(VacPageList vacpagelist, VacPage vacpage);
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew); 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 close_indices(int nindices, Relation *Irel);
static void get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc); 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, static void *vac_find_eq(void *bot, int nelem, int size, void *elm,
...@@ -416,7 +416,7 @@ vacuum_rel(Oid relid, bool analyze) ...@@ -416,7 +416,7 @@ vacuum_rel(Oid relid, bool analyze)
/* Now open indices */ /* Now open indices */
nindices = 0; nindices = 0;
Irel = (Relation *) NULL; Irel = (Relation *) NULL;
get_indices(vacrelstats->relid, &nindices, &Irel); get_indices(onerel, &nindices, &Irel);
if (!Irel) if (!Irel)
reindex = false; reindex = false;
else if (!RelationGetForm(onerel)->relhasindex) else if (!RelationGetForm(onerel)->relhasindex)
...@@ -2331,80 +2331,33 @@ CommonSpecialPortalIsOpen(void) ...@@ -2331,80 +2331,33 @@ CommonSpecialPortalIsOpen(void)
return CommonSpecialPortalInUse; return CommonSpecialPortalInUse;
} }
static void static void
get_indices(Oid relid, int *nindices, Relation **Irel) get_indices(Relation relation, int *nindices, Relation **Irel)
{ {
Relation pgindex; List *indexoidlist,
Relation irel; *indexoidscan;
TupleDesc tupdesc; int i;
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);
}
heap_endscan(scan); indexoidlist = RelationGetIndexList(relation);
heap_close(pgindex, AccessShareLock);
if (i == 0) *nindices = length(indexoidlist);
{ /* No one index found */
pfree(ioid);
return;
}
if (Irel != (Relation **) NULL) if (*nindices > 0)
*Irel = (Relation *) palloc(i * sizeof(Relation)); *Irel = (Relation *) palloc(*nindices * sizeof(Relation));
else
*Irel = NULL;
for (k = 0; i > 0;) i = 0;
foreach(indexoidscan, indexoidlist)
{ {
irel = index_open(ioid[--i]); Oid indexoid = lfirsti(indexoidscan);
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);
if (Irel != (Relation **) NULL && *nindices == 0) (*Irel)[i] = index_open(indexoid);
{ i++;
pfree(*Irel);
*Irel = (Relation *) NULL;
} }
freeList(indexoidlist);
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -735,7 +735,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) ...@@ -735,7 +735,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
*/ */
if (resultRelationDesc->rd_rel->relhasindex && if (resultRelationDesc->rd_rel->relhasindex &&
operation != CMD_DELETE) operation != CMD_DELETE)
ExecOpenIndices(resultRelationOid, resultRelationInfo); ExecOpenIndices(resultRelationInfo);
estate->es_result_relation_info = resultRelationInfo; estate->es_result_relation_info = resultRelationInfo;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,8 @@ ...@@ -53,6 +53,8 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP, static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP,
AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP); AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
...@@ -657,7 +659,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple, ...@@ -657,7 +659,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
* check parameters * check parameters
* ---------------- * ----------------
*/ */
if (numAttsOutP == NULL && attsOutP == NULL) if (numAttsOutP == NULL || attsOutP == NULL)
{ {
elog(DEBUG, "ExecGetIndexKeyInfo: %s", elog(DEBUG, "ExecGetIndexKeyInfo: %s",
"invalid parameters: numAttsOutP and attsOutP must be non-NULL"); "invalid parameters: numAttsOutP and attsOutP must be non-NULL");
...@@ -724,115 +726,112 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple, ...@@ -724,115 +726,112 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecOpenIndices * ExecOpenIndices
* *
* Here we scan the pg_index relation to find indices * Find the indices associated with a result relation, open them,
* associated with a given heap relation oid. Since we * and save information about them in the result RelationInfo.
* 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.
* *
* Note: much of this code duplicates effort done by * At entry, caller has already opened and locked
* the IndexCatalogInformation function in plancat.c * resultRelationInfo->ri_RelationDesc.
* because IndexCatalogInformation is poorly written.
* *
* It would be much better if the functionality provided * This used to be horribly ugly code, and slow too because it
* by this function and IndexCatalogInformation was * did a sequential scan of pg_index. Now we rely on the relcache
* in the form of a small set of orthogonal routines.. * to cache a list of the OIDs of the indices associated with any
* If you are trying to understand this, I suggest you * specific relation, and we use the pg_index syscache to get the
* look at the code to IndexCatalogInformation and * entries we need from pg_index.
* FormIndexTuple.. -cim 9/27/89
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
ExecOpenIndices(Oid resultRelationOid, ExecOpenIndices(RelationInfo *resultRelationInfo)
RelationInfo *resultRelationInfo)
{ {
Relation indexRd; Relation resultRelation = resultRelationInfo->ri_RelationDesc;
HeapScanDesc indexSd; List *indexoidlist,
ScanKeyData key; *indexoidscan;
HeapTuple tuple; int len,
Form_pg_index indexStruct; i;
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;
RelationPtr relationDescs; RelationPtr relationDescs;
IndexInfo **indexInfoArray; IndexInfo **indexInfoArray;
FuncIndexInfoPtr fInfoP;
int numKeyAtts;
AttrNumber *indexKeyAtts;
PredInfo *predicate;
int i;
resultRelationInfo->ri_NumIndices = 0; resultRelationInfo->ri_NumIndices = 0;
if (!RelationGetForm(resultRelationInfo->ri_RelationDesc)->relhasindex)
/* checks for disabled indexes */
if (! RelationGetForm(resultRelation)->relhasindex)
return; return;
if (IsIgnoringSystemIndexes() && if (IsIgnoringSystemIndexes() &&
IsSystemRelationName(RelationGetRelationName(resultRelationInfo->ri_RelationDesc))) IsSystemRelationName(RelationGetRelationName(resultRelation)))
return; 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, relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
F_OIDEQ, indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
ObjectIdGetDatum(resultRelationOid));
resultRelationInfo->ri_NumIndices = len;
resultRelationInfo->ri_IndexRelationDescs = relationDescs;
resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
/* ---------------- /* ----------------
* scan the index relation, looking for indices for our * For each index, open the index relation and save pg_index info.
* result relation..
* ---------------- * ----------------
*/ */
indexSd = heap_beginscan(indexRd, /* scan desc */ i = 0;
false, /* scan backward flag */ foreach(indexoidscan, indexoidlist)
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)))
{ {
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 * Open (and lock, if necessary) the index relation
* we need and store it in a list..
* *
* 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); indexDesc = index_open(indexOid);
indexOid = indexStruct->indexrelid;
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, ExecGetIndexKeyInfo(indexStruct,
&numKeyAtts, &numKeyAtts,
&indexKeyAtts, &indexKeyAtts,
...@@ -844,6 +843,8 @@ ExecOpenIndices(Oid resultRelationOid, ...@@ -844,6 +843,8 @@ ExecOpenIndices(Oid resultRelationOid,
*/ */
if (VARSIZE(&indexStruct->indpred) != 0) if (VARSIZE(&indexStruct->indpred) != 0)
{ {
char *predString;
predString = textout(&indexStruct->indpred); predString = textout(&indexStruct->indpred);
predicate = (PredInfo *) stringToNode(predString); predicate = (PredInfo *) stringToNode(predString);
pfree(predString); pfree(predString);
...@@ -851,152 +852,21 @@ ExecOpenIndices(Oid resultRelationOid, ...@@ -851,152 +852,21 @@ ExecOpenIndices(Oid resultRelationOid,
else else
predicate = NULL; predicate = NULL;
/* ---------------- /* Save the index info */
* save the index information into lists ii = makeNode(IndexInfo);
* ---------------- ii->ii_NumKeyAttributes = numKeyAtts;
*/ ii->ii_KeyAttributeNumbers = indexKeyAtts;
oidList = lconsi(indexOid, oidList); ii->ii_FuncIndexInfo = fInfoP;
nkeyList = lconsi(numKeyAtts, nkeyList); ii->ii_Predicate = (Node *) predicate;
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);
ii->ii_NumKeyAttributes = 0; heap_freetuple(indexTuple);
ii->ii_KeyAttributeNumbers = (AttrNumber *) NULL;
ii->ii_FuncIndexInfo = (FuncIndexInfoPtr) NULL;
ii->ii_Predicate = NULL;
indexInfoArray[i] = ii;
}
/* ---------------- relationDescs[i] = indexDesc;
* attempt to open each of the indices. If we succeed, indexInfoArray[i] = ii;
* then store the index relation descriptor into the i++;
* 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;
} }
/* ---------------- freeList(indexoidlist);
* 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);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -1035,91 +905,6 @@ ExecCloseIndices(RelationInfo *resultRelationInfo) ...@@ -1035,91 +905,6 @@ ExecCloseIndices(RelationInfo *resultRelationInfo)
*/ */
} }
/* ----------------------------------------------------------------
* 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 * ExecInsertIndexTuples
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -285,7 +285,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent) ...@@ -285,7 +285,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
* indices, but how to tell that here? * indices, but how to tell that here?
*/ */
if (rri->ri_RelationDesc->rd_rel->relhasindex) if (rri->ri_RelationDesc->rd_rel->relhasindex)
ExecOpenIndices(reloid, rri); ExecOpenIndices(rri);
} }
/* /*
......
...@@ -9,11 +9,7 @@ ...@@ -9,11 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
<<<<<<< plancat.c * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.57 2000/06/17 21:48:51 tgl Exp $
* $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
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,6 +28,7 @@ ...@@ -32,6 +28,7 @@
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "miscadmin.h" #include "miscadmin.h"
...@@ -54,7 +51,7 @@ relation_info(Query *root, Index relid, ...@@ -54,7 +51,7 @@ relation_info(Query *root, Index relid,
Form_pg_class relation; Form_pg_class relation;
relationTuple = SearchSysCacheTuple(RELOID, relationTuple = SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(relationObjectId), ObjectIdGetDatum(relationObjectId),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(relationTuple)) if (!HeapTupleIsValid(relationTuple))
elog(ERROR, "relation_info: Relation %u not found", elog(ERROR, "relation_info: Relation %u not found",
...@@ -81,33 +78,40 @@ relation_info(Query *root, Index relid, ...@@ -81,33 +78,40 @@ relation_info(Query *root, Index relid,
List * List *
find_secondary_indexes(Query *root, Index relid) find_secondary_indexes(Query *root, Index relid)
{ {
List *indexes = NIL; List *indexinfos = NIL;
List *indexoidlist,
*indexoidscan;
Oid indrelid = getrelid(relid, root->rtable); Oid indrelid = getrelid(relid, root->rtable);
Relation relation; 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, * We used to scan pg_index directly, but now the relcache offers
F_OIDEQ, * a cached list of OID indexes for each relation. So, get that list
ObjectIdGetDatum(indrelid)); * and then use the syscache to obtain pg_index entries.
*/
relation = heap_open(indrelid, AccessShareLock);
indexoidlist = RelationGetIndexList(relation);
scan = heap_beginscan(relation, 0, SnapshotNow, foreach(indexoidscan, indexoidlist)
1, &indexKey);
while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
{ {
Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple); Oid indexoid = lfirsti(indexoidscan);
IndexOptInfo *info = makeNode(IndexOptInfo); HeapTuple indexTuple;
Form_pg_index index;
IndexOptInfo *info;
int i; int i;
Relation indexRelation; Relation indexRelation;
Oid relam; Oid relam;
uint16 amorderstrategy; 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 * Need to make these arrays large enough to be sure there is a
* terminating 0 at the end of each one. * terminating 0 at the end of each one.
...@@ -172,13 +176,17 @@ find_secondary_indexes(Query *root, Index relid) ...@@ -172,13 +176,17 @@ find_secondary_indexes(Query *root, Index relid)
} }
} }
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); heap_close(relation, AccessShareLock);
return indexes; return indexinfos;
} }
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
void CheckSelectForUpdate(Query *qry); /* no points for style... */ void CheckSelectForUpdate(Query *qry); /* no points for style... */
...@@ -2003,13 +2005,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint) ...@@ -2003,13 +2005,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
{ {
Relation pkrel; Relation pkrel;
Form_pg_attribute *pkrel_attrs; Form_pg_attribute *pkrel_attrs;
Relation indexRd; List *indexoidlist,
HeapScanDesc indexSd; *indexoidscan;
ScanKeyData key;
HeapTuple indexTup;
Form_pg_index indexStruct = NULL; Form_pg_index indexStruct = NULL;
Ident *pkattr;
int pkattno;
int i; int i;
/* ---------- /* ----------
...@@ -2023,37 +2021,37 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint) ...@@ -2023,37 +2021,37 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
pkrel_attrs = pkrel->rd_att->attrs; pkrel_attrs = pkrel->rd_att->attrs;
/* ---------- /* ----------
* Open pg_index and begin a scan for all indices defined on * Get the list of index OIDs for the table from the relcache,
* the referenced table * 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); indexoidlist = RelationGetIndexList(pkrel);
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 */
/* ---------- foreach(indexoidscan, indexoidlist)
* Fetch the index with indisprimary == true
* ----------
*/
while (HeapTupleIsValid(indexTup = heap_getnext(indexSd, 0)))
{ {
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) if (indexStruct->indisprimary)
break; break;
indexStruct = NULL;
} }
freeList(indexoidlist);
/* ---------- /* ----------
* Check that we found it * Check that we found it
* ---------- * ----------
*/ */
if (!HeapTupleIsValid(indexTup)) if (indexStruct == NULL)
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found", elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
fkconstraint->pktable_name); fkconstraint->pktable_name);
...@@ -2064,8 +2062,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint) ...@@ -2064,8 +2062,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
*/ */
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
{ {
pkattno = indexStruct->indkey[i]; int pkattno = indexStruct->indkey[i];
pkattr = (Ident *) makeNode(Ident); Ident *pkattr = makeNode(Ident);
pkattr->name = nameout(&(pkrel_attrs[pkattno - 1]->attname)); pkattr->name = nameout(&(pkrel_attrs[pkattno - 1]->attname));
pkattr->indirection = NIL; pkattr->indirection = NIL;
pkattr->isRel = false; pkattr->isRel = false;
...@@ -2073,12 +2072,6 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint) ...@@ -2073,12 +2072,6 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr); 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); heap_close(pkrel, AccessShareLock);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "catalog/index.h" #include "catalog/index.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/pg_attrdef.h" #include "catalog/pg_attrdef.h"
#include "catalog/pg_index.h"
#include "catalog/pg_log.h" #include "catalog/pg_log.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_relcheck.h" #include "catalog/pg_relcheck.h"
...@@ -1063,16 +1064,14 @@ formrdesc(char *relationName, ...@@ -1063,16 +1064,14 @@ formrdesc(char *relationName,
FormData_pg_attribute *att) FormData_pg_attribute *att)
{ {
Relation relation; Relation relation;
Size len;
u_int i; u_int i;
/* ---------------- /* ----------------
* allocate new relation desc * allocate new relation desc
* ---------------- * ----------------
*/ */
len = sizeof(RelationData); relation = (Relation) palloc(sizeof(RelationData));
relation = (Relation) palloc(len); MemSet((char *) relation, 0, sizeof(RelationData));
MemSet((char *) relation, 0, len);
/* ---------------- /* ----------------
* don't open the unix file yet.. * don't open the unix file yet..
...@@ -1090,9 +1089,8 @@ formrdesc(char *relationName, ...@@ -1090,9 +1089,8 @@ formrdesc(char *relationName,
* initialize relation tuple form * initialize relation tuple form
* ---------------- * ----------------
*/ */
relation->rd_rel = (Form_pg_class) relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
palloc((Size) (sizeof(*relation->rd_rel))); MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
MemSet(relation->rd_rel, 0, sizeof(FormData_pg_class));
strcpy(RelationGetPhysicalRelationName(relation), relationName); strcpy(RelationGetPhysicalRelationName(relation), relationName);
/* ---------------- /* ----------------
...@@ -1414,6 +1412,7 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1414,6 +1412,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
pfree(relation->rd_istrat); pfree(relation->rd_istrat);
if (relation->rd_support) if (relation->rd_support)
pfree(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 * If we're really done with the relcache entry, blow it away. But if
...@@ -2075,6 +2074,125 @@ RelCheckFetch(Relation relation) ...@@ -2075,6 +2074,125 @@ RelCheckFetch(Relation relation)
heap_close(rcrel, AccessShareLock); 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 * init_irels(), write_irels() -- handle special-case initialization of
* index relation descriptors. * index relation descriptors.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -142,8 +142,7 @@ extern void ExecAssignScanTypeFromOuterPlan(Plan *node, ...@@ -142,8 +142,7 @@ extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
CommonScanState *csstate); CommonScanState *csstate);
extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc); extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc);
extern void ExecOpenIndices(Oid resultRelationOid, extern void ExecOpenIndices(RelationInfo *resultRelationInfo);
RelationInfo *resultRelationInfo);
extern void ExecCloseIndices(RelationInfo *resultRelationInfo); extern void ExecCloseIndices(RelationInfo *resultRelationInfo);
extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate, bool is_update); EState *estate, bool is_update);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -92,14 +92,15 @@ typedef struct RelationData ...@@ -92,14 +92,15 @@ typedef struct RelationData
bool rd_isnailed; /* rel is nailed in cache */ bool rd_isnailed; /* rel is nailed in cache */
bool rd_isnoname; /* rel has no name */ bool rd_isnoname; /* rel has no name */
bool rd_unlinked; /* rel already unlinked or not created yet */ 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_am rd_am; /* AM tuple */
Form_pg_class rd_rel; /* RELATION tuple */ Form_pg_class rd_rel; /* RELATION tuple */
Oid rd_id; /* relation's object id */ Oid rd_id; /* relation's object id */
LockInfoData rd_lockInfo; /* lock manager's info for locking List *rd_indexlist; /* list of OIDs of indexes on relation */
* relation */ LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */
TupleDesc rd_att; /* tuple descriptor */ TupleDesc rd_att; /* tuple descriptor */
RuleLock *rd_rules; /* rewrite rules */ RuleLock *rd_rules; /* rewrite rules */
IndexStrategy rd_istrat; IndexStrategy rd_istrat; /* info needed if rel is an index */
RegProcedure *rd_support; RegProcedure *rd_support;
TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */
} RelationData; } RelationData;
...@@ -138,13 +139,15 @@ typedef Relation *RelationPtr; ...@@ -138,13 +139,15 @@ typedef Relation *RelationPtr;
* RelationSetReferenceCount * RelationSetReferenceCount
* Sets relation reference count. * Sets relation reference count.
*/ */
#define RelationSetReferenceCount(relation,count) ((relation)->rd_refcnt = (count)) #define RelationSetReferenceCount(relation,count) \
((relation)->rd_refcnt = (count))
/* /*
* RelationIncrementReferenceCount * RelationIncrementReferenceCount
* Increments relation reference count. * Increments relation reference count.
*/ */
#define RelationIncrementReferenceCount(relation) ((relation)->rd_refcnt += 1) #define RelationIncrementReferenceCount(relation) \
((relation)->rd_refcnt += 1)
/* /*
* RelationDecrementReferenceCount * RelationDecrementReferenceCount
...@@ -199,7 +202,8 @@ typedef Relation *RelationPtr; ...@@ -199,7 +202,8 @@ typedef Relation *RelationPtr;
* *
* Returns a Relation Name * Returns a Relation Name
*/ */
#define RelationGetPhysicalRelationName(relation) (NameStr((relation)->rd_rel->relname)) #define RelationGetPhysicalRelationName(relation) \
(NameStr((relation)->rd_rel->relname))
/* /*
* RelationGetNumberOfAttributes * RelationGetNumberOfAttributes
...@@ -224,9 +228,11 @@ typedef Relation *RelationPtr; ...@@ -224,9 +228,11 @@ typedef Relation *RelationPtr;
*/ */
#define RelationGetIndexStrategy(relation) ((relation)->rd_istrat) #define RelationGetIndexStrategy(relation) ((relation)->rd_istrat)
/*
* Routines in utils/cache/rel.c
*/
extern void RelationSetIndexSupport(Relation relation, extern void RelationSetIndexSupport(Relation relation,
IndexStrategy strategy, IndexStrategy strategy,
RegProcedure *support); RegProcedure *support);
#endif /* REL_H */ #endif /* REL_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,13 +19,20 @@ ...@@ -19,13 +19,20 @@
/* /*
* relation lookup routines * relation lookup routines
*/ */
extern Relation RelationIdCacheGetRelation(Oid relationId);
extern Relation RelationIdGetRelation(Oid relationId); extern Relation RelationIdGetRelation(Oid relationId);
extern Relation RelationNameGetRelation(const char *relationName); 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 RelationClose(Relation relation);
extern void RelationForgetRelation(Oid rid); 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 * Routines for flushing/rebuilding relcache entries in various scenarios
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment