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.cindex 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.cindex 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"
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