303 lines
8.2 KiB
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;
|
|
}
|