Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lVIZ2-0004Sl-Iy for pgsql-hackers@arkaria.postgresql.org; Sat, 10 Apr 2021 18:42:36 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1lVIYz-0008CD-IN for pgsql-hackers@arkaria.postgresql.org; Sat, 10 Apr 2021 18:42:33 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lVIYz-0008C6-5j for pgsql-hackers@lists.postgresql.org; Sat, 10 Apr 2021 18:42:33 +0000 Received: from mail-il1-x12b.google.com ([2607:f8b0:4864:20::12b]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1lVIYw-0006OG-HL for pgsql-hackers@lists.postgresql.org; Sat, 10 Apr 2021 18:42:32 +0000 Received: by mail-il1-x12b.google.com with SMTP id w2so7471042ilj.12 for ; Sat, 10 Apr 2021 11:42:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telsasoft-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=r+3ohxRAZ11f+5QV6EZtPTIb1NI5a6iQ0u1TQBmfrdA=; b=tTjUd0Uhz1Glb5SKYQVAHch+BYA49vmind2kTzWXiZ9YzC+agw+JN4SflUDpjDP5BJ 1H3AdcdjLPr282sc8NlR1rwZcm2atEfLsAqYGPEzkIlAPzZZ6JOg5cEGhJpppnsLgEwH lFnCt1AC1AVqqwuELDoYIo8k83ni/D6SthMR25sfjuSHPwdMnWfKSlx/7JCdQ9fJOpYO eNJI72Ya2OFlbgASGW0oPhINSlMi9KfijIdTAGYK+n5BXEYrfXbpQ+GJRKW/CyNeUFfM s2YONDIQLvn1/U2+gPlAi3oFAT/HI8AzjwfjzCbaHOIPn0V9di1eVG7P0T9QMyBSa7YD Gv/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=r+3ohxRAZ11f+5QV6EZtPTIb1NI5a6iQ0u1TQBmfrdA=; b=WCdzxI3rXU4Q8fYOAcRMsCoTv3brn+C0arYLL/tGyyZjtFUiKCyaTDM+VZRW9LEdBb vfJW3jjLgRGvD9ohAnuLOWaURc35IaVFz4K4JIE8CpAJCMWApCWo8IdgmgyWuKQ5eTJP /bO+Vyf89RqZwfIxG9ix4wKayS9HyGo0cFtL/owxq8msQY2ZkKAr4vJBDGnRpGq3Dxax IC2n+8p5TKDmD+YtNT+wa6dQ3o2vphhCA7bvsbPJZoNxqXiLn03v8I6YOEDJwHOpLoKb Gt9vwnDPZe9GH63FKaw1wOyZKRBeTtyXBQ9it9lAsX5gaXR2dlnYRMOQpznkOyQ9d5Gu VWqw== X-Gm-Message-State: AOAM5304uPjjLJYnQAjY+5E4qOxk4sKZ6D4XoTf44bjBY3Pxt5fLR17f CJEC8wMikd/Meyc4mPrENYyd3A== X-Google-Smtp-Source: ABdhPJzngtOtM3PytcEf9nQ/WeSz2WMXGX/lvWt14myaf5rByyVdZZ1HXLcOXGSJWY6MjbGYrYLP9Q== X-Received: by 2002:a05:6e02:1a0f:: with SMTP id s15mr2581847ild.59.1618080148990; Sat, 10 Apr 2021 11:42:28 -0700 (PDT) Received: from pryzbyj.telsasoft (charmander.telsasoft.com. [50.244.222.1]) by smtp.gmail.com with ESMTPSA id s5sm2885009ilu.78.2021.04.10.11.42.27 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 10 Apr 2021 11:42:28 -0700 (PDT) Received: by pryzbyj.telsasoft (Postfix, from userid 1000) id D96CB802183; Sat, 10 Apr 2021 13:42:26 -0500 (CDT) Date: Sat, 10 Apr 2021 13:42:26 -0500 From: Justin Pryzby To: Alvaro Herrera Cc: Amit Langote , pgsql-hackers@lists.postgresql.org Subject: Re: ALTER TABLE .. DETACH PARTITION CONCURRENTLY Message-ID: <20210410184226.GY6592@telsasoft.com> References: <20210321175453.GB11765@telsasoft.com> <20210321180115.GA2101@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="KSyhVCl2eeZHT0Rn" Content-Disposition: inline In-Reply-To: <20210321180115.GA2101@alvherre.pgsql> User-Agent: Mutt/1.9.4 (2018-02-28) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --KSyhVCl2eeZHT0Rn Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sun, Mar 21, 2021 at 03:01:15PM -0300, Alvaro Herrera wrote: > > But note that it doesn't check if an existing constraint "implies" the new > > constraint - maybe it should. > > Hm, I'm not sure I want to do that, because that means that if I later > have to attach the partition again with the same partition bounds, then > I might have to incur a scan to recheck the constraint. I think we want > to make the new constraint be as tight as possible ... If it *implies* the partition constraint, then it's at least as tight (and maybe tighter), yes ? I think you're concerned with the case that someone has a partition with "tight" bounds like (a>=200 and a<300) and a check constraint that's "less tight" like (a>=100 AND a<400). In that case, the loose check constraint doesn't imply the tighter partition constraint, so your patch would add a non-redundant constraint. I'm interested in the case that someone has a check constraint that almost but not exactly matches the partition constraint, like (a<300 AND a>=200). In that case, your patch adds a redundant constraint. I wrote a patch which seems to effect my preferred behavior - please check. -- Justin --KSyhVCl2eeZHT0Rn Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0001-DETACH-CONCURRENTLY-avoid-creation-of-redundant-cons.patch" From 1ecc8cb17192d13f7432fe582a43ab8597b15c00 Mon Sep 17 00:00:00 2001 From: Justin Pryzby Date: Thu, 25 Mar 2021 21:24:10 -0500 Subject: [PATCH] DETACH CONCURRENTLY: avoid creation of redundant constraint --- src/backend/commands/tablecmds.c | 29 ++++++++++------------- src/test/regress/expected/alter_table.out | 20 ++++++++++++++++ src/test/regress/sql/alter_table.sql | 6 +++++ 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 7d0bdc9ac4..62398b6882 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -17873,31 +17873,28 @@ ATExecDetachPartitionFinalize(Relation rel, RangeVar *name) * DetachAddConstraintIfNeeded * Subroutine for ATExecDetachPartition. Create a constraint that * takes the place of the partition constraint, but avoid creating - * a dupe if an equivalent constraint already exists. + * a dupe if an constraint already exists which implies the needed + * constraint. */ static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel) { AlteredTableInfo *tab; - Expr *constraintExpr; - TupleDesc td = RelationGetDescr(partRel); + List *constraintExpr; Constraint *n; - constraintExpr = make_ands_explicit(RelationGetPartitionQual(partRel)); + constraintExpr = (List *) eval_const_expressions(NULL, + (Node *) RelationGetPartitionQual(partRel)); - /* If an identical constraint exists, we don't need to create one */ - if (td->constr && td->constr->num_check > 0) - { - for (int i = 0; i < td->constr->num_check; i++) - { - Node *thisconstr; + constraintExpr = (List *) make_ands_explicit(constraintExpr); - thisconstr = stringToNode(td->constr->check[i].ccbin); - - if (equal(constraintExpr, thisconstr)) - return; - } - } + /* + * Avoid adding a new constraint if the needed constraint is implied by an + * existing constraint + */ + if (PartConstraintImpliedByRelConstraint(partRel, + list_make1(constraintExpr))) + return; tab = ATGetQueueEntry(wqueue, partRel); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index ec14b060a6..f81bdf513b 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -4191,6 +4191,26 @@ ALTER TABLE range_parted2 DETACH PARTITION part_rp CONCURRENTLY; Partition key: RANGE (a) Number of partitions: 0 +-- constraint should be created +\d part_rp + Table "public.part_rp" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | +Check constraints: + "part_rp_a_check" CHECK (a IS NOT NULL AND a >= 0 AND a < 100) + +CREATE TABLE part_rp100 PARTITION OF range_parted2 (CHECK (a>=123 AND a<133 AND a IS NOT NULL)) FOR VALUES FROM (100) to (200); +ALTER TABLE range_parted2 DETACH PARTITION part_rp100 CONCURRENTLY; +-- redundant constraint should not be created +\d part_rp100 + Table "public.part_rp100" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | +Check constraints: + "part_rp100_a_check" CHECK (a >= 123 AND a < 133 AND a IS NOT NULL) + DROP TABLE range_parted2; -- Check ALTER TABLE commands for partitioned tables and partitions -- cannot add/drop column to/from *only* the parent diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 7a9c9252dc..dc0200adcb 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2696,6 +2696,12 @@ DROP TABLE part_rpd; -- works fine ALTER TABLE range_parted2 DETACH PARTITION part_rp CONCURRENTLY; \d+ range_parted2 +-- constraint should be created +\d part_rp +CREATE TABLE part_rp100 PARTITION OF range_parted2 (CHECK (a>=123 AND a<133 AND a IS NOT NULL)) FOR VALUES FROM (100) to (200); +ALTER TABLE range_parted2 DETACH PARTITION part_rp100 CONCURRENTLY; +-- redundant constraint should not be created +\d part_rp100 DROP TABLE range_parted2; -- Check ALTER TABLE commands for partitioned tables and partitions -- 2.17.0 --KSyhVCl2eeZHT0Rn--