aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/relcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r--src/backend/utils/cache/relcache.c138
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