diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 17 | ||||
-rw-r--r-- | src/backend/utils/cache/typcache.c | 59 |
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 */ |