pg.ddx.io  pgsql-bugs@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Subject: [PATCH 1/2] Fix detach bug
Date: Mon, 20 May 2024 17:11:23 +0200

---
 src/backend/executor/execPartition.c | 56 ++++++++++++++++++++++++----
 src/backend/partitioning/partdesc.c  | 18 +++++++++
 2 files changed, 67 insertions(+), 7 deletions(-)

inline patch 1: src/backend/executor/execPartition.c, src/backend/partitioning/partdesc.c (+67/-7 lines) download inline-1.patchdiff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index bb14dcbe6f..637e5bac5d 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1942,13 +1942,10 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo) /* * Initialize the subplan_map and subpart_map. * - * Because we request detached partitions to be included, and - * detaching waits for old transactions, it is safe to assume that - * no partitions have disappeared since this query was planned. - * - * However, new partitions may have been added. + * The set of partitions that exist now might not be the same that + * existed when the plan was made, so we have to cope. */ - Assert(partdesc->nparts >= pinfo->nparts); + pprune->nparts = partdesc->nparts; pprune->subplan_map = palloc(sizeof(int) * partdesc->nparts); if (partdesc->nparts == pinfo->nparts) @@ -1974,7 +1971,7 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo) } #endif } - else + else if (partdesc->nparts > pinfo->nparts) { int pd_idx = 0; int pp_idx; @@ -2031,6 +2028,51 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo) if (pd_idx != pinfo->nparts) elog(ERROR, "could not match partition child tables to plan elements"); } + else if (partdesc->nparts == pinfo->nparts - 1) + { + int pd_idx = 0; + int pp_idx; + + /* + * In this case we know that the plan-time descriptor had more + * partitions than the current descriptor, which means that + * one partition was detached in concurrent mode. (It's not + * possible for multiple partitions to be detached in this + * way). Cope with this by setting them as pruned, because + * the query cannot possibly care about results coming from + * them anyway. + */ + + pprune->subpart_map = palloc(sizeof(int) * pinfo->nparts); + for (pp_idx = 0; pp_idx < partdesc->nparts; pp_idx++) + { + if (pinfo->relid_map[pd_idx] != partdesc->oids[pp_idx]) + { + pprune->subplan_map[pp_idx] = -1; + pprune->subpart_map[pp_idx] = -1; + pd_idx++; + } + + if (pd_idx < pinfo->nparts && + pinfo->relid_map[pd_idx] == partdesc->oids[pp_idx]) + { + pprune->subplan_map[pp_idx] = + pinfo->subplan_map[pd_idx]; + pprune->subpart_map[pp_idx] = + pinfo->subpart_map[pd_idx]; + pd_idx++; + } + else + { + pprune->subplan_map[pp_idx] = -1; + pprune->subpart_map[pp_idx] = -1; + } + } + } + else + ereport(ERROR, + errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("too many detached partitions")); /* present_parts is also subject to later modification */ pprune->present_parts = bms_copy(pinfo->present_parts); diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c index 47c97566e6..16ce956d03 100644 --- a/src/backend/partitioning/partdesc.c +++ b/src/backend/partitioning/partdesc.c @@ -24,6 +24,7 @@ #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/hsearch.h" +#include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/partcache.h" @@ -149,6 +150,8 @@ RelationBuildPartitionDesc(Relation rel, bool omit_detached) MemoryContext oldcxt; int *mapping; +retry: + /* * Get partition oids from pg_inherits. This uses a single snapshot to * fetch the list of children, so while more children may be getting added @@ -179,6 +182,7 @@ RelationBuildPartitionDesc(Relation rel, bool omit_detached) Oid inhrelid = lfirst_oid(cell); HeapTuple tuple; PartitionBoundSpec *boundspec = NULL; + bool retried = false; /* Try fetching the tuple from the catcache, for speed. */ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(inhrelid)); @@ -233,6 +237,20 @@ RelationBuildPartitionDesc(Relation rel, bool omit_detached) table_close(pg_class, AccessShareLock); } + /* + * If any of our partitions is still seen with a NULL relpartbound + * after rereading pg_class directly, it might be that it's no longer + * in the set of partitions anymore because of DETACH CONCURRENTLY. + * We can dodge this by reading invalidation messages and fetching a + * fresh list of partitions. We only do this once, because ... XXX + * ??? + */ + if (!boundspec && !retried) + { + AcceptInvalidationMessages(); + retried = true; + goto retry; + } /* Sanity checks. */ if (!boundspec) elog(ERROR, "missing relpartbound for relation %u", inhrelid); -- 2.39.2
--2d3ceazxqldvimr4 Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="0002-Fix-typo.patch"

Message-ID: <no-message-id-25541@localhost>
Permalink:  ../no-message-id-25541@localhost/
Also on:    postgresql.org/message-id/no-message-id-25541@localhost

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-bugs@postgresql.org
  Cc: alvherre@alvh.no-ip.org
  Subject: Re: [PATCH 1/2] Fix detach bug
  In-Reply-To: <no-message-id-25541@localhost>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox