Reduce lock level for ALTER DOMAIN ... VALIDATE CONSTRAINT

Reduce from ShareLock to ShareUpdateExclusivelock.  Validation during
ALTER DOMAIN ... ADD CONSTRAINT keeps using ShareLock.

Example:

    create domain d1 as int;
    create table t (a d1);
    alter domain d1 add constraint cc10 check (value > 10) not valid;

    begin;
    alter domain d1 validate constraint cc10;

    -- another session
    insert into t values (8);

Now we should still be able to perform DML operations on table t while
the domain constraint is being validated.  The equivalent works
already on table constraints.

Author: jian he <jian.universality@gmail.com>
Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
Reviewed-by: wenhui qiu <qiuwenhuifx@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CACJufxHz92A88NLRTA2msgE2dpXpE-EoZ2QO61od76-6bfqurA%40mail.gmail.com
master
Peter Eisentraut 3 weeks ago
parent 123e65fdb7
commit 16a0039dc0
  1. 24
      src/backend/commands/typecmds.c

@ -126,7 +126,7 @@ static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid);
static Oid findRangeSubOpclass(List *opcname, Oid subtype);
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin);
static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode);
static void validateDomainNotNullConstraint(Oid domainoid);
static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
static void checkEnumOwner(HeapTuple tup);
@ -2986,7 +2986,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint,
* to.
*/
if (!constr->skip_validation)
validateDomainCheckConstraint(domainoid, ccbin);
validateDomainCheckConstraint(domainoid, ccbin, ShareLock);
/*
* We must send out an sinval message for the domain, to ensure that
@ -3098,7 +3098,12 @@ AlterDomainValidateConstraint(List *names, const char *constrName)
val = SysCacheGetAttrNotNull(CONSTROID, tuple, Anum_pg_constraint_conbin);
conbin = TextDatumGetCString(val);
validateDomainCheckConstraint(domainoid, conbin);
/*
* Locking related relations with ShareUpdateExclusiveLock is ok because
* not-yet-valid constraints are still enforced against concurrent inserts
* or updates.
*/
validateDomainCheckConstraint(domainoid, conbin, ShareUpdateExclusiveLock);
/*
* Now update the catalog, while we have the door open.
@ -3191,9 +3196,16 @@ validateDomainNotNullConstraint(Oid domainoid)
/*
* Verify that all columns currently using the domain satisfy the given check
* constraint expression.
*
* It is used to validate existing constraints and to add newly created check
* constraints to a domain.
*
* The lockmode is used for relations using the domain. It should be
* ShareLock when adding a new constraint to domain. It can be
* ShareUpdateExclusiveLock when validating an existing constraint.
*/
static void
validateDomainCheckConstraint(Oid domainoid, const char *ccbin)
validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode)
{
Expr *expr = (Expr *) stringToNode(ccbin);
List *rels;
@ -3210,9 +3222,7 @@ validateDomainCheckConstraint(Oid domainoid, const char *ccbin)
exprstate = ExecPrepareExpr(expr, estate);
/* Fetch relation list with attributes based on this domain */
/* ShareLock is sufficient to prevent concurrent data changes */
rels = get_rels_with_domain(domainoid, ShareLock);
rels = get_rels_with_domain(domainoid, lockmode);
foreach(rt, rels)
{

Loading…
Cancel
Save