postgresql/src/backend/catalog/indexing.c

303 lines
8.2 KiB
C

/*-------------------------------------------------------------------------
*
* indexing.c
* This file contains routines to support indices defined on system
* catalogs.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.76 2001/01/24 19:42:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_index.h"
#include "miscadmin.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
/*
* Names of indices - they match all system caches
*/
char *Name_pg_aggregate_indices[Num_pg_aggregate_indices] =
{AggregateNameTypeIndex};
char *Name_pg_am_indices[Num_pg_am_indices] =
{AmNameIndex};
char *Name_pg_amop_indices[Num_pg_amop_indices] =
{AccessMethodOpidIndex, AccessMethodStrategyIndex};
char *Name_pg_attr_indices[Num_pg_attr_indices] =
{AttributeRelidNameIndex, AttributeRelidNumIndex};
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] =
{AttrDefaultIndex};
char *Name_pg_class_indices[Num_pg_class_indices] =
{ClassNameIndex, ClassOidIndex};
char *Name_pg_group_indices[Num_pg_group_indices] =
{GroupNameIndex, GroupSysidIndex};
char *Name_pg_index_indices[Num_pg_index_indices] =
{IndexRelidIndex, IndexIndrelidIndex};
char *Name_pg_inherits_indices[Num_pg_inherits_indices] =
{InheritsRelidSeqnoIndex};
char *Name_pg_language_indices[Num_pg_language_indices] =
{LanguageOidIndex, LanguageNameIndex};
char *Name_pg_largeobject_indices[Num_pg_largeobject_indices] =
{LargeObjectLOidPNIndex};
char *Name_pg_listener_indices[Num_pg_listener_indices] =
{ListenerPidRelnameIndex};
char *Name_pg_opclass_indices[Num_pg_opclass_indices] =
{OpclassNameIndex, OpclassDeftypeIndex};
char *Name_pg_operator_indices[Num_pg_operator_indices] =
{OperatorOidIndex, OperatorNameIndex};
char *Name_pg_proc_indices[Num_pg_proc_indices] =
{ProcedureOidIndex, ProcedureNameIndex};
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] =
{RelCheckIndex};
char *Name_pg_rewrite_indices[Num_pg_rewrite_indices] =
{RewriteOidIndex, RewriteRulenameIndex};
char *Name_pg_shadow_indices[Num_pg_shadow_indices] =
{ShadowNameIndex, ShadowSysidIndex};
char *Name_pg_statistic_indices[Num_pg_statistic_indices] =
{StatisticRelidAttnumIndex};
char *Name_pg_trigger_indices[Num_pg_trigger_indices] =
{TriggerRelidIndex, TriggerConstrNameIndex, TriggerConstrRelidIndex};
char *Name_pg_type_indices[Num_pg_type_indices] =
{TypeNameIndex, TypeOidIndex};
char *Name_pg_description_indices[Num_pg_description_indices] =
{DescriptionObjIndex};
static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
Relation idesc,
ScanKey skey,
int16 num_keys);
/*
* Changes (appends) to catalogs can and do happen at various places
* throughout the code. We need a generic routine that will open all of
* the indices defined on a given catalog and return the relation descriptors
* associated with them.
*/
void
CatalogOpenIndices(int nIndices, char **names, Relation *idescs)
{
int i;
if (IsIgnoringSystemIndexes())
return;
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;
if (IsIgnoringSystemIndexes())
return;
for (i = 0; i < nIndices; i++)
index_close(idescs[i]);
}
/*
* For the same reasons outlined above for CatalogOpenIndices(), we need a
* routine that takes a new catalog tuple and inserts an associated index
* tuple into each catalog index.
*
* NOTE: since this routine looks up all the pg_index data on each call,
* it's relatively inefficient for inserting a large number of tuples into
* the same catalog. We use it only for inserting one or a few tuples
* in a given command. See ExecOpenIndices() and related routines if you
* are inserting tuples in bulk.
*
* NOTE: we do not bother to handle partial indices. Nor do we try to
* be efficient for functional indices (the code should work for them,
* but may leak memory intraquery). This should be OK for system catalogs,
* but don't use this routine for user tables!
*/
void
CatalogIndexInsert(Relation *idescs,
int nIndices,
Relation heapRelation,
HeapTuple heapTuple)
{
TupleDesc heapDescriptor;
Datum datum[INDEX_MAX_KEYS];
char nullv[INDEX_MAX_KEYS];
int i;
if (IsIgnoringSystemIndexes() || (!heapRelation->rd_rel->relhasindex))
return;
heapDescriptor = RelationGetDescr(heapRelation);
for (i = 0; i < nIndices; i++)
{
HeapTuple index_tup;
IndexInfo *indexInfo;
InsertIndexResult indexRes;
index_tup = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(idescs[i]->rd_id),
0, 0, 0);
if (!HeapTupleIsValid(index_tup))
elog(ERROR, "CatalogIndexInsert: index %u not found",
idescs[i]->rd_id);
indexInfo = BuildIndexInfo(index_tup);
ReleaseSysCache(index_tup);
FormIndexDatum(indexInfo,
heapTuple,
heapDescriptor,
CurrentMemoryContext,
datum,
nullv);
indexRes = index_insert(idescs[i], datum, nullv,
&heapTuple->t_self, heapRelation);
if (indexRes)
pfree(indexRes);
pfree(indexInfo);
}
}
/*
* CatalogIndexFetchTuple() -- Get a tuple that satisfies a scan key
* from a catalog relation.
*
* Since the index may contain pointers to dead tuples, we need to
* iterate until we find a tuple that's valid and satisfies the scan
* key.
*/
static HeapTuple
CatalogIndexFetchTuple(Relation heapRelation,
Relation idesc,
ScanKey skey,
int16 num_keys)
{
IndexScanDesc sd;
RetrieveIndexResult indexRes;
HeapTupleData tuple;
HeapTuple result = NULL;
Buffer buffer;
sd = index_beginscan(idesc, false, num_keys, skey);
tuple.t_datamcxt = CurrentMemoryContext;
tuple.t_data = NULL;
while ((indexRes = index_getnext(sd, ForwardScanDirection)))
{
tuple.t_self = indexRes->heap_iptr;
heap_fetch(heapRelation, SnapshotNow, &tuple, &buffer);
pfree(indexRes);
if (tuple.t_data != NULL)
break;
}
if (tuple.t_data != NULL)
{
result = heap_copytuple(&tuple);
ReleaseBuffer(buffer);
}
index_endscan(sd);
return result;
}
/*---------------------------------------------------------------------
* Class-specific index lookups
*---------------------------------------------------------------------
*/
/*
* The remainder of the file is for individual index scan routines.
* These routines provide canned scanning code for certain widely-used
* indexes. Most indexes don't need one of these.
*/
HeapTuple
AttributeRelidNumIndexScan(Relation heapRelation,
Datum relid,
Datum attnum)
{
Relation idesc;
ScanKeyData skey[2];
HeapTuple tuple;
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_OIDEQ,
relid);
ScanKeyEntryInitialize(&skey[1],
(bits16) 0x0,
(AttrNumber) 2,
(RegProcedure) F_INT2EQ,
attnum);
idesc = index_openr(AttributeRelidNumIndex);
tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 2);
index_close(idesc);
return tuple;
}
HeapTuple
ClassNameIndexScan(Relation heapRelation, Datum relName)
{
Relation idesc;
ScanKeyData skey[1];
HeapTuple tuple;
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_NAMEEQ,
relName);
idesc = index_openr(ClassNameIndex);
tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 1);
index_close(idesc);
return tuple;
}
HeapTuple
ClassOidIndexScan(Relation heapRelation, Datum relId)
{
Relation idesc;
ScanKeyData skey[1];
HeapTuple tuple;
ScanKeyEntryInitialize(&skey[0],
(bits16) 0x0,
(AttrNumber) 1,
(RegProcedure) F_OIDEQ,
relId);
idesc = index_openr(ClassOidIndex);
tuple = CatalogIndexFetchTuple(heapRelation, idesc, skey, 1);
index_close(idesc);
return tuple;
}