diff options
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 138 |
1 files changed, 135 insertions, 3 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 3a66e2aa8e7..82c4bbc01a9 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.292 2009/09/26 23:08:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.293 2009/12/07 05:22:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -60,9 +60,11 @@ #include "storage/fd.h" #include "storage/lmgr.h" #include "storage/smgr.h" +#include "utils/array.h" #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/inval.h" +#include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/relcache.h" #include "utils/resowner.h" @@ -1079,10 +1081,13 @@ RelationInitIndexAccessInfo(Relation relation) memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16)); /* - * expressions and predicate cache will be filled later + * expressions, predicate, exclusion caches will be filled later */ relation->rd_indexprs = NIL; relation->rd_indpred = NIL; + relation->rd_exclops = NULL; + relation->rd_exclprocs = NULL; + relation->rd_exclstrats = NULL; relation->rd_amcache = NULL; } @@ -3453,6 +3458,130 @@ RelationGetIndexAttrBitmap(Relation relation) return indexattrs; } +/* + * RelationGetExclusionInfo -- get info about index's exclusion constraint + * + * This should be called only for an index that is known to have an + * associated exclusion constraint. It returns arrays (palloc'd in caller's + * context) of the exclusion operator OIDs, their underlying functions' + * OIDs, and their strategy numbers in the index's opclasses. We cache + * all this information since it requires a fair amount of work to get. + */ +void +RelationGetExclusionInfo(Relation indexRelation, + Oid **operators, + Oid **procs, + uint16 **strategies) +{ + int ncols = indexRelation->rd_rel->relnatts; + Oid *ops; + Oid *funcs; + uint16 *strats; + Relation conrel; + SysScanDesc conscan; + ScanKeyData skey[1]; + HeapTuple htup; + bool found; + MemoryContext oldcxt; + int i; + + /* Allocate result space in caller context */ + *operators = ops = (Oid *) palloc(sizeof(Oid) * ncols); + *procs = funcs = (Oid *) palloc(sizeof(Oid) * ncols); + *strategies = strats = (uint16 *) palloc(sizeof(uint16) * ncols); + + /* Quick exit if we have the data cached already */ + if (indexRelation->rd_exclstrats != NULL) + { + memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * ncols); + memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * ncols); + memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * ncols); + return; + } + + /* + * Search pg_constraint for the constraint associated with the index. + * To make this not too painfully slow, we use the index on conrelid; + * that will hold the parent relation's OID not the index's own OID. + */ + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(indexRelation->rd_index->indrelid)); + + conrel = heap_open(ConstraintRelationId, AccessShareLock); + conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true, + SnapshotNow, 1, skey); + found = false; + + while (HeapTupleIsValid(htup = systable_getnext(conscan))) + { + Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup); + Datum val; + bool isnull; + ArrayType *arr; + int nelem; + + /* We want the exclusion constraint owning the index */ + if (conform->contype != CONSTRAINT_EXCLUSION || + conform->conindid != RelationGetRelid(indexRelation)) + continue; + + /* There should be only one */ + if (found) + elog(ERROR, "unexpected exclusion constraint record found for rel %s", + RelationGetRelationName(indexRelation)); + found = true; + + /* Extract the operator OIDS from conexclop */ + val = fastgetattr(htup, + Anum_pg_constraint_conexclop, + conrel->rd_att, &isnull); + if (isnull) + elog(ERROR, "null conexclop for rel %s", + RelationGetRelationName(indexRelation)); + + arr = DatumGetArrayTypeP(val); /* ensure not toasted */ + nelem = ARR_DIMS(arr)[0]; + if (ARR_NDIM(arr) != 1 || + nelem != ncols || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "conexclop is not a 1-D Oid array"); + + memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * ncols); + } + + systable_endscan(conscan); + heap_close(conrel, AccessShareLock); + + if (!found) + elog(ERROR, "exclusion constraint record missing for rel %s", + RelationGetRelationName(indexRelation)); + + /* We need the func OIDs and strategy numbers too */ + for (i = 0; i < ncols; i++) + { + funcs[i] = get_opcode(ops[i]); + strats[i] = get_op_opfamily_strategy(ops[i], + indexRelation->rd_opfamily[i]); + /* shouldn't fail, since it was checked at index creation */ + if (strats[i] == InvalidStrategy) + elog(ERROR, "could not find strategy for operator %u in family %u", + ops[i], indexRelation->rd_opfamily[i]); + } + + /* Save a copy of the results in the relcache entry. */ + oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt); + indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * ncols); + indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * ncols); + indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * ncols); + memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * ncols); + memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * ncols); + memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * ncols); + MemoryContextSwitchTo(oldcxt); +} + /* * load_relcache_init_file, write_relcache_init_file @@ -3768,13 +3897,16 @@ load_relcache_init_file(bool shared) * format is complex and subject to change). They must be rebuilt if * needed by RelationCacheInitializePhase3. This is not expected to * be a big performance hit since few system catalogs have such. Ditto - * for index expressions and predicates. + * for index expressions, predicates, and exclusion info. */ rel->rd_rules = NULL; rel->rd_rulescxt = NULL; rel->trigdesc = NULL; rel->rd_indexprs = NIL; rel->rd_indpred = NIL; + rel->rd_exclops = NULL; + rel->rd_exclprocs = NULL; + rel->rd_exclstrats = NULL; /* * Reset transient-state fields in the relcache entry |