Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1sc6iD-003y1N-LQ for pgsql-hackers@arkaria.postgresql.org; Thu, 08 Aug 2024 17:14:05 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1sc6iC-00FWLt-63 for pgsql-hackers@arkaria.postgresql.org; Thu, 08 Aug 2024 17:14:04 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1sc6iB-00FWLk-R7 for pgsql-hackers@lists.postgresql.org; Thu, 08 Aug 2024 17:14:03 +0000 Received: from mail-oa1-x36.google.com ([2001:4860:4864:20::36]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1sc6i9-003pWw-Jz for pgsql-hackers@lists.postgresql.org; Thu, 08 Aug 2024 17:14:03 +0000 Received: by mail-oa1-x36.google.com with SMTP id 586e51a60fabf-264a12e05b9so789432fac.1 for ; Thu, 08 Aug 2024 10:14:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=leadboat.com; s=google; t=1723137239; x=1723742039; darn=lists.postgresql.org; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:from:to:cc:subject:date :message-id:reply-to; bh=N6/bi9B9Pva+PFimiQx+PoKTeH/OFke+oWVvU5+lfmA=; b=Mq0aP+lAn9NOM9tuoP1ZHuPMV+wqEVPN6xXWip88X/LB6iA6H42dDjAAd6tsATpaEi vZ3Dlt4J/yw2f+AV3TgDBclWpdxn1/cFzIiNku/spswmFBYEFsZ6w1LFEPh9vmJrcM0m c0XH3rzqcbiHGwUERVpuB/nBLUYJ0JJSIBboY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723137239; x=1723742039; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=N6/bi9B9Pva+PFimiQx+PoKTeH/OFke+oWVvU5+lfmA=; b=dZ50e1IdQE4z+xxeJSVs8eBnxrdX1t0c4sJtr6q/3vRRXD5i5BO64vi0WdwXxsu9ZH 890geFHX+X7LepONcEiHL65RwL8Kb4dDoaLC8iN7UtnXEydPFWKxGcs5wzDblTrUyoJq T55LzFCdedpRjNg+VzYSPjY8WeN3U/gTf7msjrfE2jMOXpZBNiADwoz3Q0oxVYdAvaVC rKOz3THLHfrB/3o61NiEOZ0ccLgegWUHbE4Rc+RPS7Xfgowj8OphiBIvN/mKp6MiWwCf 7qALjiJwEojTQqpyVCmL6LeiaA8ErIySm9PxGWu1zE5FzH4eCBJ8RLYK6F8zIM7qHxuO BavA== X-Forwarded-Encrypted: i=1; AJvYcCWmAW+2xlCXe/fEmmrUvgBMhQmeHDw74qXZ1RyKp7PLXvFb0I97h42YUVO2EP9bWx7b8iIhf8DBJuV4kSQgcOcOz1KUbYRmI7PXt2KHCS3vv8cX X-Gm-Message-State: AOJu0YxqvZ2vmPY9/wss8c0A2ZvmY48XIkQbb7Q9ZISuSqkycNziLle/ Qkxj55B3IUJ5wJQcRh5imaEVRSA4SUcuBnhorUxenZJ1r/UCff8Kc8tceeESLgPNVsH7TB7KqXE = X-Google-Smtp-Source: AGHT+IEf0l+gOykEC3lTin1LkxD0O0u6isRrQV1frvUbAgXATDjdo7YzARLxjNGkTSfBqbtYvab4KA== X-Received: by 2002:a05:6870:d8d2:b0:260:f9ee:9700 with SMTP id 586e51a60fabf-2692b6aa205mr3203128fac.30.1723137239134; Thu, 08 Aug 2024 10:13:59 -0700 (PDT) Received: from google.com ([2600:1702:a20:5750::48]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-2689a629415sm4670016fac.41.2024.08.08.10.13.57 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 08 Aug 2024 10:13:58 -0700 (PDT) Date: Thu, 8 Aug 2024 10:13:51 -0700 From: Noah Misch To: Alexander Korotkov Cc: Dmitry Koval , pgsql-hackers@lists.postgresql.org Subject: Re: Add SPLIT PARTITION/MERGE PARTITIONS commands Message-ID: <20240808171351.a9.nmisch@google.com> References: <171085360143.2046436.7217841141682511557.pgcf@coridan.postgresql.org> <171085858750.2046434.12246066729700037354.pgcf@coridan.postgresql.org> <909e16b4-9eda-435c-b033-8294ae4adc05@postgrespro.ru> <3a4b9c1c-3edf-4e29-9629-b4113aefb0f3@postgrespro.ru> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="NQwcF9XvrtwJ+baa" Content-Disposition: inline In-Reply-To: User-Agent: Mutt/2.2.12 (2023-09-09) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --NQwcF9XvrtwJ+baa Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sun, Apr 07, 2024 at 01:22:51AM +0300, Alexander Korotkov wrote: > I've pushed 0001 and 0002 The partition MERGE (1adf16b8f) and SPLIT (87c21bb94) v17 patches introduced createPartitionTable() with this code: createStmt->relation = newPartName; ... wrapper->utilityStmt = (Node *) createStmt; ... ProcessUtility(wrapper, ... newRel = table_openrv(newPartName, NoLock); This breaks from the CVE-2014-0062 (commit 5f17304) principle of not repeating name lookups. The attached demo uses this defect to make one partition have two parents. --NQwcF9XvrtwJ+baa Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="repro-merge-partition-race-v0.patch" diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index ae2efdc..654b502 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -3495,7 +3495,11 @@ StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound) elog(ERROR, "cache lookup failed for relation %u", RelationGetRelid(rel)); -#ifdef USE_ASSERT_CHECKING + /* + * Assertion fails during partition getting multiple parents. Disable the + * assertion, to see what non-assert builds experience. + */ +#if 0 { Form_pg_class classForm; bool isnull; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 8fcb188..48207f9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -95,6 +95,7 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/injection_point.h" #include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/memutils.h" @@ -15825,7 +15826,11 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispart */ if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { - Assert(child_att->attinhcount == 1); + /* + * Assertion fails during partition getting multiple parents. + * Disable, to see what non-assert builds experience. + */ + /* Assert(child_att->attinhcount == 1); */ child_att->attislocal = false; } @@ -20388,7 +20393,14 @@ createPartitionTable(RangeVar *newPartName, Relation modelRel, * Open the new partition with no lock, because we already have * AccessExclusiveLock placed there after creation. */ - newRel = table_openrv(newPartName, NoLock); + INJECTION_POINT("merge-after-create"); + /* + * For testing, switch to taking a lock. This solves two problems. + * First, it gets an AcceptInvalidationMessages(), so we actually + * invalidate the search path. Second, it avoids an assertion failure + * from our lack of lock, so we see what non-assert builds experience. + */ + newRel = table_openrv(newPartName, AccessExclusiveLock); /* * We intended to create the partition with the same persistence as the diff --git a/src/test/modules/injection_points/Makefile b/src/test/modules/injection_points/Makefile index 2ffd2f7..9af45bf 100644 --- a/src/test/modules/injection_points/Makefile +++ b/src/test/modules/injection_points/Makefile @@ -9,7 +9,7 @@ PGFILEDESC = "injection_points - facility for injection points" REGRESS = injection_points REGRESS_OPTS = --dlpath=$(top_builddir)/src/test/regress -ISOLATION = inplace +ISOLATION = inplace merge # The injection points are cluster-wide, so disable installcheck NO_INSTALLCHECK = 1 diff --git a/src/test/modules/injection_points/expected/merge.out b/src/test/modules/injection_points/expected/merge.out new file mode 100644 index 0000000..04920e7 --- /dev/null +++ b/src/test/modules/injection_points/expected/merge.out @@ -0,0 +1,60 @@ +Parsed test spec with 3 sessions + +starting permutation: merge1 ct2 detach3 +injection_points_attach +----------------------- + +(1 row) + +step merge1: + SET search_path = target; + ALTER TABLE parted MERGE PARTITIONS (part1, part3) INTO part_all; + -- only one of *parted should have rows, but both do + SELECT a AS new_target_parted FROM target.parted ORDER BY 1; + SELECT a AS old_target_parted FROM old_target.parted ORDER BY 1; + SELECT a AS new_target_part_all FROM target.part_all ORDER BY 1; + SELECT a AS old_target_part_all FROM old_target.part_all ORDER BY 1; + +step ct2: + ALTER SCHEMA target RENAME TO old_target; + CREATE SCHEMA target + CREATE TABLE parted (a int) partition by list (a) + CREATE TABLE part_all PARTITION OF parted FOR VALUES IN (1, 2, 3, 4) + +step detach3: + SELECT injection_points_detach('merge-after-create'); + SELECT injection_points_wakeup('merge-after-create'); + +injection_points_detach +----------------------- + +(1 row) + +injection_points_wakeup +----------------------- + +(1 row) + +step merge1: <... completed> +new_target_parted +----------------- + 1 + 3 +(2 rows) + +old_target_parted +----------------- + 1 + 3 +(2 rows) + +new_target_part_all +------------------- + 1 + 3 +(2 rows) + +old_target_part_all +------------------- +(0 rows) + diff --git a/src/test/modules/injection_points/specs/merge.spec b/src/test/modules/injection_points/specs/merge.spec new file mode 100644 index 0000000..63bcd2b --- /dev/null +++ b/src/test/modules/injection_points/specs/merge.spec @@ -0,0 +1,51 @@ +setup +{ + CREATE EXTENSION injection_points; + CREATE SCHEMA target + CREATE TABLE parted (a int) partition by list (a) + CREATE TABLE part1 PARTITION OF parted FOR VALUES IN (1, 2) + CREATE TABLE part3 PARTITION OF parted FOR VALUES IN (3, 4); + INSERT INTO target.parted VALUES (1),(3); +} +teardown +{ + DROP SCHEMA target, old_target CASCADE; + DROP EXTENSION injection_points; +} + +# MERGE PARTITIONS +session s1 +setup { + SELECT injection_points_set_local(); + SELECT injection_points_attach('merge-after-create', 'wait'); +} +step merge1 { + SET search_path = target; + ALTER TABLE parted MERGE PARTITIONS (part1, part3) INTO part_all; + -- only one of *parted should have rows, but both do + SELECT a AS new_target_parted FROM target.parted ORDER BY 1; + SELECT a AS old_target_parted FROM old_target.parted ORDER BY 1; + SELECT a AS new_target_part_all FROM target.part_all ORDER BY 1; + SELECT a AS old_target_part_all FROM old_target.part_all ORDER BY 1; +} + + +# inject another table via ALTER SCHEMA RENAME +session s2 +step ct2 { + ALTER SCHEMA target RENAME TO old_target; + CREATE SCHEMA target + CREATE TABLE parted (a int) partition by list (a) + CREATE TABLE part_all PARTITION OF parted FOR VALUES IN (1, 2, 3, 4) +} + + +# injection release +session s3 +step detach3 { + SELECT injection_points_detach('merge-after-create'); + SELECT injection_points_wakeup('merge-after-create'); +} + + +permutation merge1(detach3) ct2 detach3 --NQwcF9XvrtwJ+baa--