aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/utils/cache/relcache.c17
-rw-r--r--src/backend/utils/cache/typcache.c59
2 files changed, 70 insertions, 6 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 1db4ba84100..4ea01d1ad63 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -271,6 +271,7 @@ static TupleDesc GetPgClassDescriptor(void);
static TupleDesc GetPgIndexDescriptor(void);
static void AttrDefaultFetch(Relation relation);
static void CheckConstraintFetch(Relation relation);
+static int CheckConstraintCmp(const void *a, const void *b);
static List *insert_ordered_oid(List *list, Oid datum);
static void IndexSupportInitialize(oidvector *indclass,
RegProcedure *indexSupport,
@@ -3734,6 +3735,22 @@ CheckConstraintFetch(Relation relation)
if (found != ncheck)
elog(ERROR, "%d constraint record(s) missing for rel %s",
ncheck - found, RelationGetRelationName(relation));
+
+ /* Sort the records so that CHECKs are applied in a deterministic order */
+ if (ncheck > 1)
+ qsort(check, ncheck, sizeof(ConstrCheck), CheckConstraintCmp);
+}
+
+/*
+ * qsort comparator to sort ConstrCheck entries by name
+ */
+static int
+CheckConstraintCmp(const void *a, const void *b)
+{
+ const ConstrCheck *ca = (const ConstrCheck *) a;
+ const ConstrCheck *cb = (const ConstrCheck *) b;
+
+ return strcmp(ca->ccname, cb->ccname);
}
/*
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index 44b5937415f..57257d281d4 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -149,6 +149,7 @@ static int32 NextRecordTypmod = 0; /* number of entries used */
static void load_typcache_tupdesc(TypeCacheEntry *typentry);
static void load_rangetype_info(TypeCacheEntry *typentry);
static void load_domaintype_info(TypeCacheEntry *typentry);
+static int dcs_cmp(const void *a, const void *b);
static void decr_dcc_refcount(DomainConstraintCache *dcc);
static void dccref_deletion_callback(void *arg);
static bool array_element_has_equality(TypeCacheEntry *typentry);
@@ -650,6 +651,8 @@ load_domaintype_info(TypeCacheEntry *typentry)
Oid typeOid = typentry->type_id;
DomainConstraintCache *dcc;
bool notNull = false;
+ DomainConstraintState **ccons;
+ int cconslen;
Relation conRel;
MemoryContext oldcxt;
@@ -666,9 +669,12 @@ load_domaintype_info(TypeCacheEntry *typentry)
/*
* We try to optimize the common case of no domain constraints, so don't
- * create the dcc object and context until we find a constraint.
+ * create the dcc object and context until we find a constraint. Likewise
+ * for the temp sorting array.
*/
dcc = NULL;
+ ccons = NULL;
+ cconslen = 0;
/*
* Scan pg_constraint for relevant constraints. We want to find
@@ -682,6 +688,7 @@ load_domaintype_info(TypeCacheEntry *typentry)
HeapTuple tup;
HeapTuple conTup;
Form_pg_type typTup;
+ int nccons = 0;
ScanKeyData key[1];
SysScanDesc scan;
@@ -763,17 +770,45 @@ load_domaintype_info(TypeCacheEntry *typentry)
r->name = pstrdup(NameStr(c->conname));
r->check_expr = ExecInitExpr(check_expr, NULL);
+ MemoryContextSwitchTo(oldcxt);
+
+ /* Accumulate constraints in an array, for sorting below */
+ if (ccons == NULL)
+ {
+ cconslen = 8;
+ ccons = (DomainConstraintState **)
+ palloc(cconslen * sizeof(DomainConstraintState *));
+ }
+ else if (nccons >= cconslen)
+ {
+ cconslen *= 2;
+ ccons = (DomainConstraintState **)
+ repalloc(ccons, cconslen * sizeof(DomainConstraintState *));
+ }
+ ccons[nccons++] = r;
+ }
+
+ systable_endscan(scan);
+
+ if (nccons > 0)
+ {
/*
- * Use lcons() here because constraints of parent domains should
- * be applied earlier.
+ * Sort the items for this domain, so that CHECKs are applied in a
+ * deterministic order.
*/
- dcc->constraints = lcons(r, dcc->constraints);
+ if (nccons > 1)
+ qsort(ccons, nccons, sizeof(DomainConstraintState *), dcs_cmp);
+ /*
+ * Now attach them to the overall list. Use lcons() here because
+ * constraints of parent domains should be applied earlier.
+ */
+ oldcxt = MemoryContextSwitchTo(dcc->dccContext);
+ while (nccons > 0)
+ dcc->constraints = lcons(ccons[--nccons], dcc->constraints);
MemoryContextSwitchTo(oldcxt);
}
- systable_endscan(scan);
-
/* loop to next domain in stack */
typeOid = typTup->typbasetype;
ReleaseSysCache(tup);
@@ -837,6 +872,18 @@ load_domaintype_info(TypeCacheEntry *typentry)
}
/*
+ * qsort comparator to sort DomainConstraintState pointers by name
+ */
+static int
+dcs_cmp(const void *a, const void *b)
+{
+ const DomainConstraintState *const * ca = (const DomainConstraintState *const *) a;
+ const DomainConstraintState *const * cb = (const DomainConstraintState *const *) b;
+
+ return strcmp((*ca)->name, (*cb)->name);
+}
+
+/*
* decr_dcc_refcount --- decrement a DomainConstraintCache's refcount,
* and free it if no references remain
*/