1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* indexing.c--
|
|
|
|
* This file contains routines to support indices defined on system
|
|
|
|
* catalogs.
|
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1997-08-21 03:32:19 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.10 1997/08/21 01:32:06 vadim Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1997-01-10 21:19:49 +01:00
|
|
|
#include <string.h>
|
|
|
|
|
1996-11-06 08:31:26 +01:00
|
|
|
#include <postgres.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1996-11-06 08:31:26 +01:00
|
|
|
#include <utils/builtins.h>
|
|
|
|
#include <utils/oidcompos.h>
|
|
|
|
#include <access/heapam.h>
|
|
|
|
#include <access/genam.h>
|
|
|
|
#include <storage/bufmgr.h>
|
|
|
|
#include <nodes/execnodes.h>
|
|
|
|
#include <catalog/catalog.h>
|
|
|
|
#include <catalog/catname.h>
|
|
|
|
#include <catalog/pg_index.h>
|
|
|
|
#include <catalog/pg_proc.h>
|
|
|
|
#include <utils/syscache.h>
|
|
|
|
#include <catalog/indexing.h>
|
|
|
|
#include <catalog/index.h>
|
|
|
|
#include <miscadmin.h>
|
1996-11-04 00:27:08 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* Names of indices on the following system catalogs:
|
|
|
|
*
|
|
|
|
* pg_attribute
|
|
|
|
* pg_proc
|
|
|
|
* pg_type
|
|
|
|
* pg_naming
|
|
|
|
* pg_class
|
1997-08-21 03:32:19 +02:00
|
|
|
* pg_attrdef
|
|
|
|
* pg_relcheck
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
char *Name_pg_attr_indices[Num_pg_attr_indices] = {AttributeNameIndex,
|
|
|
|
AttributeNumIndex,
|
|
|
|
AttributeRelidIndex};
|
|
|
|
char *Name_pg_proc_indices[Num_pg_proc_indices] = { ProcedureNameIndex,
|
|
|
|
ProcedureOidIndex,
|
|
|
|
ProcedureSrcIndex};
|
|
|
|
char *Name_pg_type_indices[Num_pg_type_indices] = { TypeNameIndex,
|
|
|
|
TypeOidIndex};
|
|
|
|
char *Name_pg_class_indices[Num_pg_class_indices]= { ClassNameIndex,
|
|
|
|
ClassOidIndex};
|
1997-08-21 03:32:19 +02:00
|
|
|
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices]= { AttrDefaultIndex };
|
|
|
|
|
|
|
|
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices]= { RelCheckIndex };
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
|
|
|
|
Relation idesc,
|
|
|
|
ScanKey skey);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Changes (appends) to catalogs can (and does) happen at various places
|
|
|
|
* throughout the code. We need a generic routine that will open all of
|
|
|
|
* the indices defined on a given catalog a return the relation descriptors
|
|
|
|
* associated with them.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CatalogOpenIndices(int nIndices, char *names[], Relation idescs[])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<nIndices; i++)
|
|
|
|
{
|
|
|
|
idescs[i] = index_openr(names[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the inverse routine to CatalogOpenIndices()
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CatalogCloseIndices(int nIndices, Relation *idescs)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<nIndices; i++)
|
|
|
|
index_close(idescs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For the same reasons outlined above CatalogOpenIndices() we need a routine
|
|
|
|
* that takes a new catalog tuple and inserts an associated index tuple into
|
|
|
|
* each catalog index.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CatalogIndexInsert(Relation *idescs,
|
|
|
|
int nIndices,
|
|
|
|
Relation heapRelation,
|
|
|
|
HeapTuple heapTuple)
|
|
|
|
{
|
|
|
|
HeapTuple pgIndexTup;
|
|
|
|
TupleDesc heapDescriptor;
|
|
|
|
IndexTupleForm pgIndexP;
|
|
|
|
Datum datum;
|
|
|
|
int natts;
|
|
|
|
AttrNumber *attnumP;
|
|
|
|
FuncIndexInfo finfo, *finfoP;
|
|
|
|
char nulls[INDEX_MAX_KEYS];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
heapDescriptor = RelationGetTupleDescriptor(heapRelation);
|
|
|
|
|
|
|
|
for (i=0; i<nIndices; i++)
|
|
|
|
{
|
|
|
|
TupleDesc indexDescriptor;
|
|
|
|
InsertIndexResult indexRes;
|
|
|
|
|
|
|
|
indexDescriptor = RelationGetTupleDescriptor(idescs[i]);
|
|
|
|
pgIndexTup = SearchSysCacheTuple(INDEXRELID,
|
|
|
|
Int32GetDatum(idescs[i]->rd_id),
|
|
|
|
0,0,0);
|
|
|
|
Assert(pgIndexTup);
|
|
|
|
pgIndexP = (IndexTupleForm)GETSTRUCT(pgIndexTup);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute the number of attributes we are indexing upon.
|
|
|
|
* very important - can't assume one if this is a functional
|
|
|
|
* index.
|
|
|
|
*/
|
|
|
|
for (attnumP=(&pgIndexP->indkey[0]), natts=0;
|
|
|
|
*attnumP != InvalidAttrNumber;
|
|
|
|
attnumP++, natts++)
|
|
|
|
;
|
|
|
|
|
|
|
|
if (pgIndexP->indproc != InvalidOid)
|
|
|
|
{
|
|
|
|
FIgetnArgs(&finfo) = natts;
|
|
|
|
natts = 1;
|
|
|
|
FIgetProcOid(&finfo) = pgIndexP->indproc;
|
|
|
|
*(FIgetname(&finfo)) = '\0';
|
|
|
|
finfoP = &finfo;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
finfoP = (FuncIndexInfo *)NULL;
|
|
|
|
|
|
|
|
FormIndexDatum(natts,
|
|
|
|
(AttrNumber *)&pgIndexP->indkey[0],
|
|
|
|
heapTuple,
|
|
|
|
heapDescriptor,
|
|
|
|
InvalidBuffer,
|
|
|
|
&datum,
|
|
|
|
nulls,
|
|
|
|
finfoP);
|
|
|
|
|
1996-08-26 08:32:06 +02:00
|
|
|
indexRes = index_insert(idescs[i], &datum, nulls,
|
1997-01-10 10:51:40 +01:00
|
|
|
&(heapTuple->t_ctid), heapRelation);
|
1996-07-09 08:22:35 +02:00
|
|
|
if (indexRes) pfree(indexRes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is needed at initialization when reldescs for some of the crucial
|
|
|
|
* system catalogs are created and nailed into the cache.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
CatalogHasIndex(char *catName, Oid catId)
|
|
|
|
{
|
|
|
|
Relation pg_class;
|
|
|
|
HeapTuple htup;
|
|
|
|
Form_pg_class pgRelP;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
Assert(IsSystemRelationName(catName));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're bootstraping we don't have pg_class (or any indices).
|
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (IsInitProcessingMode()) {
|
|
|
|
for (i = 0; IndexedCatalogNames[i] != NULL; i++) {
|
|
|
|
if ( strcmp(IndexedCatalogNames[i], catName) == 0)
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
pg_class = heap_openr(RelationRelationName);
|
|
|
|
htup = ClassOidIndexScan(pg_class, catId);
|
|
|
|
heap_close(pg_class);
|
|
|
|
|
|
|
|
if (! HeapTupleIsValid(htup)) {
|
|
|
|
elog(NOTICE, "CatalogHasIndex: no relation with oid %d", catId);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pgRelP = (Form_pg_class)GETSTRUCT(htup);
|
|
|
|
return (pgRelP->relhasindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
IndexScanDesc sd;
|
|
|
|
RetrieveIndexResult indexRes;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Buffer buffer;
|
|
|
|
|
|
|
|
sd = index_beginscan(idesc, false, 1, skey);
|
|
|
|
tuple = (HeapTuple)NULL;
|
|
|
|
|
|
|
|
do {
|
|
|
|
indexRes = index_getnext(sd, ForwardScanDirection);
|
|
|
|
if (indexRes) {
|
|
|
|
ItemPointer iptr;
|
|
|
|
|
|
|
|
iptr = &indexRes->heap_iptr;
|
|
|
|
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
|
|
|
pfree(indexRes);
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
} while (!HeapTupleIsValid(tuple));
|
|
|
|
|
|
|
|
if (HeapTupleIsValid(tuple)) {
|
|
|
|
tuple = heap_copytuple(tuple);
|
|
|
|
ReleaseBuffer(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
index_endscan(sd);
|
|
|
|
pfree(sd);
|
|
|
|
return (tuple);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The remainder of the file is for individual index scan routines. Each
|
|
|
|
* index should be scanned according to how it was defined during bootstrap
|
|
|
|
* (that is, functional or normal) and what arguments the cache lookup
|
|
|
|
* requires. Each routine returns the heap tuple that qualifies.
|
|
|
|
*/
|
|
|
|
HeapTuple
|
|
|
|
AttributeNameIndexScan(Relation heapRelation,
|
|
|
|
Oid relid,
|
|
|
|
char *attname)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
|
|
|
OidName keyarg;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
keyarg = mkoidname(relid, attname);
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)OidNameEqRegProcedure,
|
|
|
|
(Datum)keyarg);
|
|
|
|
|
|
|
|
idesc = index_openr(AttributeNameIndex);
|
|
|
|
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
|
|
|
|
|
|
|
index_close(idesc);
|
|
|
|
pfree(keyarg);
|
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
HeapTuple
|
|
|
|
AttributeNumIndexScan(Relation heapRelation,
|
|
|
|
Oid relid,
|
|
|
|
AttrNumber attnum)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
|
|
|
OidInt2 keyarg;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
keyarg = mkoidint2(relid, (uint16)attnum);
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)OidInt2EqRegProcedure,
|
|
|
|
(Datum)keyarg);
|
|
|
|
|
|
|
|
idesc = index_openr(AttributeNumIndex);
|
|
|
|
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
|
|
|
|
|
|
|
index_close(idesc);
|
|
|
|
pfree(keyarg);
|
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
HeapTuple
|
|
|
|
ProcedureOidIndexScan(Relation heapRelation, Oid procId)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)ObjectIdEqualRegProcedure,
|
|
|
|
(Datum)procId);
|
|
|
|
|
|
|
|
idesc = index_openr(ProcedureOidIndex);
|
|
|
|
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
|
|
|
|
|
|
|
index_close(idesc);
|
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|
|
|
|
|
1996-11-26 03:45:05 +01:00
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
HeapTuple
|
|
|
|
ProcedureNameIndexScan(Relation heapRelation,
|
1996-11-26 03:45:05 +01:00
|
|
|
char *procName,
|
|
|
|
int nargs,
|
|
|
|
Oid *argTypes)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
1996-11-26 03:45:05 +01:00
|
|
|
HeapTuple tuple; /* tuple being tested */
|
|
|
|
HeapTuple return_tuple; /* The tuple pointer we eventually return */
|
1996-07-09 08:22:35 +02:00
|
|
|
IndexScanDesc sd;
|
|
|
|
RetrieveIndexResult indexRes;
|
|
|
|
Buffer buffer;
|
|
|
|
Form_pg_proc pgProcP;
|
1996-11-26 03:45:05 +01:00
|
|
|
bool ScanComplete;
|
|
|
|
/* The index scan is complete, i.e. we've scanned everything there
|
|
|
|
is to scan.
|
|
|
|
*/
|
|
|
|
bool FoundMatch;
|
|
|
|
/* In scanning pg_proc, we have found a row that meets our search
|
|
|
|
criteria.
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
1996-11-26 03:45:05 +01:00
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)NameEqualRegProcedure,
|
|
|
|
(Datum)procName);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
idesc = index_openr(ProcedureNameIndex);
|
|
|
|
|
|
|
|
sd = index_beginscan(idesc, false, 1, &skey);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* for now, we do the work usually done by CatalogIndexFetchTuple
|
|
|
|
* by hand, so that we can check that the other keys match. when
|
|
|
|
* multi-key indices are added, they will be used here.
|
|
|
|
*/
|
1996-11-26 03:45:05 +01:00
|
|
|
tuple = (HeapTuple) NULL; /* initial value */
|
|
|
|
ScanComplete = false; /* Scan hasn't begun yet */
|
|
|
|
FoundMatch = false; /* No match yet; haven't even looked. */
|
|
|
|
while (!FoundMatch && !ScanComplete) {
|
|
|
|
indexRes = index_getnext(sd, ForwardScanDirection);
|
|
|
|
if (indexRes) {
|
|
|
|
ItemPointer iptr;
|
|
|
|
|
|
|
|
iptr = &indexRes->heap_iptr;
|
|
|
|
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
|
|
|
pfree(indexRes);
|
|
|
|
if (HeapTupleIsValid(tuple)) {
|
|
|
|
/* Here's a row for a procedure that has the sought procedure
|
|
|
|
name. To be a match, though, we need it to have the
|
|
|
|
right number and type of arguments too, so we check that
|
|
|
|
now.
|
|
|
|
*/
|
|
|
|
pgProcP = (Form_pg_proc)GETSTRUCT(tuple);
|
|
|
|
if (pgProcP->pronargs == nargs &&
|
|
|
|
oid8eq(&(pgProcP->proargtypes[0]), argTypes))
|
|
|
|
FoundMatch = true;
|
|
|
|
else ReleaseBuffer(buffer);
|
|
|
|
}
|
|
|
|
} else ScanComplete = true;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1996-11-26 03:45:05 +01:00
|
|
|
|
|
|
|
if (FoundMatch) {
|
|
|
|
Assert(HeapTupleIsValid(tuple));
|
|
|
|
return_tuple = heap_copytuple(tuple);
|
|
|
|
ReleaseBuffer(buffer);
|
|
|
|
} else return_tuple = (HeapTuple)NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
index_endscan(sd);
|
|
|
|
index_close(idesc);
|
|
|
|
|
1996-11-26 03:45:05 +01:00
|
|
|
return return_tuple;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1996-11-26 03:45:05 +01:00
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
HeapTuple
|
|
|
|
ProcedureSrcIndexScan(Relation heapRelation, text *procSrc)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
IndexScanDesc sd;
|
|
|
|
ScanKeyData skey;
|
|
|
|
RetrieveIndexResult indexRes;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Buffer buffer;
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)Anum_pg_proc_prosrc,
|
|
|
|
(RegProcedure)TextEqualRegProcedure,
|
|
|
|
(Datum)procSrc);
|
|
|
|
|
|
|
|
idesc = index_openr(ProcedureSrcIndex);
|
|
|
|
sd = index_beginscan(idesc, false, 1, &skey);
|
|
|
|
|
|
|
|
indexRes = index_getnext(sd, ForwardScanDirection);
|
|
|
|
if (indexRes) {
|
|
|
|
ItemPointer iptr;
|
|
|
|
|
|
|
|
iptr = &indexRes->heap_iptr;
|
|
|
|
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
|
|
|
pfree(indexRes);
|
|
|
|
} else
|
|
|
|
tuple = (HeapTuple)NULL;
|
|
|
|
|
|
|
|
if (HeapTupleIsValid(tuple)) {
|
|
|
|
tuple = heap_copytuple(tuple);
|
|
|
|
ReleaseBuffer(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
index_endscan(sd);
|
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
HeapTuple
|
|
|
|
TypeOidIndexScan(Relation heapRelation, Oid typeId)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)ObjectIdEqualRegProcedure,
|
|
|
|
(Datum)typeId);
|
|
|
|
|
|
|
|
idesc = index_openr(TypeOidIndex);
|
|
|
|
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
|
|
|
|
|
|
|
index_close(idesc);
|
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
HeapTuple
|
|
|
|
TypeNameIndexScan(Relation heapRelation, char *typeName)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)NameEqualRegProcedure,
|
|
|
|
(Datum)typeName);
|
|
|
|
|
|
|
|
idesc = index_openr(TypeNameIndex);
|
|
|
|
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
|
|
|
|
|
|
|
index_close(idesc);
|
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
HeapTuple
|
|
|
|
ClassNameIndexScan(Relation heapRelation, char *relName)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)NameEqualRegProcedure,
|
|
|
|
(Datum)relName);
|
|
|
|
|
|
|
|
idesc = index_openr(ClassNameIndex);
|
|
|
|
|
|
|
|
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
|
|
|
|
|
|
|
index_close(idesc);
|
|
|
|
return tuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
HeapTuple
|
|
|
|
ClassOidIndexScan(Relation heapRelation, Oid relId)
|
|
|
|
{
|
|
|
|
Relation idesc;
|
|
|
|
ScanKeyData skey;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey,
|
|
|
|
(bits16)0x0,
|
|
|
|
(AttrNumber)1,
|
|
|
|
(RegProcedure)ObjectIdEqualRegProcedure,
|
|
|
|
(Datum)relId);
|
|
|
|
|
|
|
|
idesc = index_openr(ClassOidIndex);
|
|
|
|
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
|
|
|
|
|
|
|
index_close(idesc);
|
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|