mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Restructure pg_opclass, pg_amop, and pg_amproc per previous discussions in
pgsql-hackers. pg_opclass now has a row for each opclass supported by each index AM, not a row for each opclass name. This allows pg_opclass to show directly whether an AM supports an opclass, and furthermore makes it possible to store additional information about an opclass that might be AM-dependent. pg_opclass and pg_amop now store "lossy" and "haskeytype" information that we previously expected the user to remember to provide in CREATE INDEX commands. Lossiness is no longer an index-level property, but is associated with the use of a particular operator in a particular index opclass. Along the way, IndexSupportInitialize now uses the syscaches to retrieve pg_amop and pg_amproc entries. I find this reduces backend launch time by about ten percent, at the cost of a couple more special cases in catcache.c's IndexScanOK. Initial work by Oleg Bartunov and Teodor Sigaev, further hacking by Tom Lane. initdb forced.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.81 2001/08/10 14:34:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.82 2001/08/21 16:35:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -20,8 +20,10 @@
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/index.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "executor/executor.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "access/xlogutils.h"
|
||||
|
||||
@@ -1377,10 +1379,9 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
|
||||
|
||||
for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
|
||||
sum_grow=0;
|
||||
for (j=0; j<r->rd_att->natts; j++) {
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
|
||||
|
||||
datum = index_getattr(itup, j+1, r->rd_att, &IsNull);
|
||||
gistdentryinit(giststate, j, &entry, datum, r, p, i, ATTSIZE( datum, r, j+1, IsNull ), FALSE, IsNull);
|
||||
gistpenalty( giststate, j, &entry, IsNull, &identry[j], isnull[j], &usize);
|
||||
@@ -1548,20 +1549,32 @@ initGISTstate(GISTSTATE *giststate, Relation index)
|
||||
RegProcedure consistent_proc,
|
||||
union_proc,
|
||||
compress_proc,
|
||||
decompress_proc;
|
||||
RegProcedure penalty_proc,
|
||||
decompress_proc,
|
||||
penalty_proc,
|
||||
picksplit_proc,
|
||||
equal_proc;
|
||||
HeapTuple htup;
|
||||
HeapTuple itup;
|
||||
HeapTuple ctup;
|
||||
Form_pg_index itupform;
|
||||
Oid indexrelid;
|
||||
Form_pg_opclass opclassform;
|
||||
Oid inputtype;
|
||||
Oid keytype;
|
||||
int i;
|
||||
|
||||
if (index->rd_att->natts >= INDEX_MAX_KEYS)
|
||||
elog(ERROR, "initGISTstate: numberOfAttributes %d > %d",
|
||||
index->rd_att->natts, INDEX_MAX_KEYS);
|
||||
if (index->rd_att->natts > INDEX_MAX_KEYS)
|
||||
elog(ERROR, "initGISTstate: numberOfAttributes %d > %d",
|
||||
index->rd_att->natts, INDEX_MAX_KEYS);
|
||||
|
||||
for(i=0; i<index->rd_att->natts; i++) {
|
||||
itup = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(RelationGetRelid(index)),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(itup))
|
||||
elog(ERROR, "initGISTstate: index %u not found",
|
||||
RelationGetRelid(index));
|
||||
itupform = (Form_pg_index) GETSTRUCT(itup);
|
||||
|
||||
for (i = 0; i < index->rd_att->natts; i++)
|
||||
{
|
||||
consistent_proc = index_getprocid(index, i+1, GIST_CONSISTENT_PROC );
|
||||
union_proc = index_getprocid(index, i+1, GIST_UNION_PROC );
|
||||
compress_proc = index_getprocid(index, i+1, GIST_COMPRESS_PROC );
|
||||
@@ -1577,37 +1590,35 @@ initGISTstate(GISTSTATE *giststate, Relation index)
|
||||
fmgr_info(picksplit_proc, &((giststate->picksplitFn)[i]) );
|
||||
fmgr_info(equal_proc, &((giststate->equalFn)[i]) );
|
||||
|
||||
giststate->attbyval[i] =
|
||||
index->rd_att->attrs[i]->attbyval;
|
||||
/* Check opclass entry to see if there is a keytype */
|
||||
ctup = SearchSysCache(CLAOID,
|
||||
ObjectIdGetDatum(itupform->indclass[i]),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(ctup))
|
||||
elog(ERROR, "cache lookup failed for opclass %u",
|
||||
itupform->indclass[i]);
|
||||
opclassform = (Form_pg_opclass) GETSTRUCT(ctup);
|
||||
inputtype = opclassform->opcintype;
|
||||
keytype = opclassform->opckeytype;
|
||||
ReleaseSysCache(ctup);
|
||||
|
||||
if (OidIsValid(keytype))
|
||||
{
|
||||
/* index column type is (possibly) different from input data */
|
||||
giststate->haskeytype[i] = true;
|
||||
giststate->attbyval[i] = get_typbyval(inputtype);
|
||||
giststate->keytypbyval[i] = index->rd_att->attrs[i]->attbyval;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal case where index column type is same as input data */
|
||||
giststate->haskeytype[i] = false;
|
||||
giststate->attbyval[i] = index->rd_att->attrs[i]->attbyval;
|
||||
giststate->keytypbyval[i] = false; /* not actually used */
|
||||
}
|
||||
}
|
||||
|
||||
/* see if key type is different from type of attribute being indexed */
|
||||
htup = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(RelationGetRelid(index)),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(htup))
|
||||
elog(ERROR, "initGISTstate: index %u not found",
|
||||
RelationGetRelid(index));
|
||||
itupform = (Form_pg_index) GETSTRUCT(htup);
|
||||
giststate->haskeytype = itupform->indhaskeytype;
|
||||
indexrelid = itupform->indexrelid;
|
||||
ReleaseSysCache(htup);
|
||||
|
||||
if (giststate->haskeytype)
|
||||
{
|
||||
/* key type is different -- is it byval? */
|
||||
htup = SearchSysCache(ATTNUM,
|
||||
ObjectIdGetDatum(indexrelid),
|
||||
UInt16GetDatum(FirstOffsetNumber),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(htup))
|
||||
elog(ERROR, "initGISTstate: no attribute tuple %u %d",
|
||||
indexrelid, FirstOffsetNumber);
|
||||
giststate->keytypbyval = (((Form_pg_attribute) htup)->attbyval);
|
||||
ReleaseSysCache(htup);
|
||||
}
|
||||
else
|
||||
giststate->keytypbyval = FALSE;
|
||||
ReleaseSysCache(itup);
|
||||
}
|
||||
|
||||
#ifdef GIST_PAGEADDITEM
|
||||
@@ -1670,7 +1681,7 @@ gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
|
||||
GISTENTRY *dep;
|
||||
|
||||
gistentryinit(*e, k, r, pg, o, b, l);
|
||||
if (giststate->haskeytype)
|
||||
if (giststate->haskeytype[nkey])
|
||||
{
|
||||
if ( b && ! isNull ) {
|
||||
dep = (GISTENTRY *)
|
||||
@@ -1698,7 +1709,7 @@ gistcentryinit(GISTSTATE *giststate, int nkey,
|
||||
GISTENTRY *cep;
|
||||
|
||||
gistentryinit(*e, k, r, pg, o, b, l);
|
||||
if (giststate->haskeytype)
|
||||
if (giststate->haskeytype[nkey])
|
||||
{
|
||||
if ( ! isNull ) {
|
||||
cep = (GISTENTRY *)
|
||||
@@ -1792,7 +1803,7 @@ gistpenalty( GISTSTATE *giststate, int attno,
|
||||
FunctionCall3(&giststate->penaltyFn[attno],
|
||||
PointerGetDatum(key1),
|
||||
PointerGetDatum(key2),
|
||||
PointerGetDatum(&penalty));
|
||||
PointerGetDatum(penalty));
|
||||
}
|
||||
|
||||
#ifdef GISTDEBUG
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.51 2001/06/01 02:41:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.52 2001/08/21 16:36:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -457,61 +457,32 @@ RelationInvokeStrategy(Relation relation,
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
* OperatorRelationFillScanKeyEntry
|
||||
* FillScanKeyEntry
|
||||
*
|
||||
* Initialize a ScanKey entry given already-opened pg_operator relation.
|
||||
* Initialize a ScanKey entry for the given operator OID.
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
OperatorRelationFillScanKeyEntry(Relation operatorRelation,
|
||||
Oid operatorObjectId,
|
||||
ScanKey entry)
|
||||
FillScanKeyEntry(Oid operatorObjectId, ScanKey entry)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
HeapScanDesc scan = NULL;
|
||||
bool cachesearch = (!IsBootstrapProcessingMode()) && IsCacheInitialized();
|
||||
|
||||
if (cachesearch)
|
||||
{
|
||||
tuple = SearchSysCache(OPEROID,
|
||||
ObjectIdGetDatum(operatorObjectId),
|
||||
0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScanKeyData scanKeyData;
|
||||
|
||||
ScanKeyEntryInitialize(&scanKeyData, 0,
|
||||
ObjectIdAttributeNumber,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(operatorObjectId));
|
||||
|
||||
scan = heap_beginscan(operatorRelation, false, SnapshotNow,
|
||||
1, &scanKeyData);
|
||||
|
||||
tuple = heap_getnext(scan, 0);
|
||||
}
|
||||
tuple = SearchSysCache(OPEROID,
|
||||
ObjectIdGetDatum(operatorObjectId),
|
||||
0, 0, 0);
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
if (!cachesearch)
|
||||
heap_endscan(scan);
|
||||
elog(ERROR, "OperatorRelationFillScanKeyEntry: unknown operator %u",
|
||||
elog(ERROR, "FillScanKeyEntry: unknown operator %u",
|
||||
operatorObjectId);
|
||||
}
|
||||
|
||||
MemSet(entry, 0, sizeof(*entry));
|
||||
entry->sk_flags = 0;
|
||||
entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
|
||||
|
||||
if (cachesearch)
|
||||
ReleaseSysCache(tuple);
|
||||
else
|
||||
heap_endscan(scan);
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
if (!RegProcedureIsValid(entry->sk_procedure))
|
||||
elog(ERROR,
|
||||
"OperatorRelationFillScanKeyEntry: no procedure for operator %u",
|
||||
elog(ERROR, "FillScanKeyEntry: no procedure for operator %u",
|
||||
operatorObjectId);
|
||||
|
||||
/*
|
||||
@@ -548,160 +519,99 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
|
||||
StrategyNumber maxSupportNumber,
|
||||
AttrNumber maxAttributeNumber)
|
||||
{
|
||||
Relation relation = NULL;
|
||||
HeapScanDesc scan = NULL;
|
||||
ScanKeyData entry[2];
|
||||
Relation operatorRelation;
|
||||
HeapTuple tuple;
|
||||
Form_pg_index iform;
|
||||
StrategyMap map;
|
||||
AttrNumber attNumber;
|
||||
int attIndex;
|
||||
Oid operatorClassObjectId[INDEX_MAX_KEYS];
|
||||
bool cachesearch = (!IsBootstrapProcessingMode()) && IsCacheInitialized();
|
||||
|
||||
if (cachesearch)
|
||||
{
|
||||
tuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(indexObjectId),
|
||||
0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(indexObjectId));
|
||||
|
||||
relation = heap_openr(IndexRelationName, AccessShareLock);
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
|
||||
tuple = heap_getnext(scan, 0);
|
||||
}
|
||||
maxStrategyNumber = AMStrategies(maxStrategyNumber);
|
||||
|
||||
tuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(indexObjectId),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "IndexSupportInitialize: no pg_index entry for index %u",
|
||||
indexObjectId);
|
||||
|
||||
iform = (Form_pg_index) GETSTRUCT(tuple);
|
||||
|
||||
*isUnique = iform->indisunique;
|
||||
|
||||
maxStrategyNumber = AMStrategies(maxStrategyNumber);
|
||||
|
||||
/*
|
||||
* XXX note that the following assumes the INDEX tuple is well formed
|
||||
* and that the *key and *class are 0 terminated.
|
||||
*/
|
||||
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
|
||||
{
|
||||
if (!OidIsValid(iform->indkey[attIndex]))
|
||||
{
|
||||
if (attIndex == InvalidAttrNumber)
|
||||
elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
|
||||
break;
|
||||
}
|
||||
|
||||
if (iform->indkey[attIndex] == InvalidAttrNumber ||
|
||||
!OidIsValid(iform->indclass[attIndex]))
|
||||
elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
|
||||
operatorClassObjectId[attIndex] = iform->indclass[attIndex];
|
||||
}
|
||||
|
||||
if (cachesearch)
|
||||
ReleaseSysCache(tuple);
|
||||
else
|
||||
{
|
||||
heap_endscan(scan);
|
||||
heap_close(relation, AccessShareLock);
|
||||
}
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
/* if support routines exist for this access method, load them */
|
||||
if (maxSupportNumber > 0)
|
||||
{
|
||||
ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_amproc_amid,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(accessMethodObjectId));
|
||||
|
||||
ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
|
||||
F_OIDEQ,
|
||||
InvalidOid); /* will set below */
|
||||
|
||||
relation = heap_openr(AccessMethodProcedureRelationName,
|
||||
AccessShareLock);
|
||||
|
||||
for (attNumber = 1; attNumber <= maxAttributeNumber; attNumber++)
|
||||
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
|
||||
{
|
||||
Oid opclass = operatorClassObjectId[attIndex];
|
||||
RegProcedure *loc;
|
||||
StrategyNumber support;
|
||||
|
||||
loc = &indexSupport[((attNumber - 1) * maxSupportNumber)];
|
||||
loc = &indexSupport[attIndex * maxSupportNumber];
|
||||
|
||||
for (support = 0; support < maxSupportNumber; ++support)
|
||||
loc[support] = InvalidOid;
|
||||
|
||||
entry[1].sk_argument =
|
||||
ObjectIdGetDatum(operatorClassObjectId[attNumber - 1]);
|
||||
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
Form_pg_amproc aform;
|
||||
tuple = SearchSysCache(AMPROCNUM,
|
||||
ObjectIdGetDatum(opclass),
|
||||
Int16GetDatum(support+1),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
Form_pg_amproc amprocform;
|
||||
|
||||
aform = (Form_pg_amproc) GETSTRUCT(tuple);
|
||||
support = aform->amprocnum;
|
||||
Assert(support > 0 && support <= maxSupportNumber);
|
||||
loc[support - 1] = aform->amproc;
|
||||
amprocform = (Form_pg_amproc) GETSTRUCT(tuple);
|
||||
loc[support] = amprocform->amproc;
|
||||
ReleaseSysCache(tuple);
|
||||
}
|
||||
else
|
||||
loc[support] = InvalidOid;
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
}
|
||||
heap_close(relation, AccessShareLock);
|
||||
}
|
||||
|
||||
/* Now load the strategy information for the index operators */
|
||||
ScanKeyEntryInitialize(&entry[0], 0,
|
||||
Anum_pg_amop_amopid,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(accessMethodObjectId));
|
||||
|
||||
ScanKeyEntryInitialize(&entry[1], 0,
|
||||
Anum_pg_amop_amopclaid,
|
||||
F_OIDEQ,
|
||||
0); /* will fill below */
|
||||
|
||||
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
|
||||
operatorRelation = heap_openr(OperatorRelationName, AccessShareLock);
|
||||
|
||||
for (attNumber = maxAttributeNumber; attNumber > 0; attNumber--)
|
||||
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
|
||||
{
|
||||
Oid opclass = operatorClassObjectId[attIndex];
|
||||
StrategyMap map;
|
||||
StrategyNumber strategy;
|
||||
|
||||
entry[1].sk_argument =
|
||||
ObjectIdGetDatum(operatorClassObjectId[attNumber - 1]);
|
||||
|
||||
map = IndexStrategyGetStrategyMap(indexStrategy,
|
||||
maxStrategyNumber,
|
||||
attNumber);
|
||||
attIndex + 1);
|
||||
|
||||
for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
|
||||
ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));
|
||||
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
Form_pg_amop aform;
|
||||
ScanKey mapentry = StrategyMapGetScanKeyEntry(map, strategy);
|
||||
|
||||
aform = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
strategy = aform->amopstrategy;
|
||||
Assert(strategy > 0 && strategy <= maxStrategyNumber);
|
||||
OperatorRelationFillScanKeyEntry(operatorRelation,
|
||||
aform->amopopr,
|
||||
StrategyMapGetScanKeyEntry(map, strategy));
|
||||
tuple = SearchSysCache(AMOPSTRATEGY,
|
||||
ObjectIdGetDatum(opclass),
|
||||
Int16GetDatum(strategy),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
Form_pg_amop amopform;
|
||||
|
||||
amopform = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
FillScanKeyEntry(amopform->amopopr, mapentry);
|
||||
ReleaseSysCache(tuple);
|
||||
}
|
||||
else
|
||||
ScanKeyEntrySetIllegal(mapentry);
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
}
|
||||
|
||||
heap_close(operatorRelation, AccessShareLock);
|
||||
heap_close(relation, AccessShareLock);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
||||
Reference in New Issue
Block a user