aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeModifyTable.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-10-24 14:48:28 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-10-24 14:48:33 -0400
commit387f9ed0a0832760a709d27abd630002903e3459 (patch)
treeec319e9518cb7a8e1bf234207452b3fb14ad3b7c /src/backend/executor/nodeModifyTable.c
parent74e5ea1e002f861d499ded6562cab9e769f44781 (diff)
downloadpostgresql-387f9ed0a0832760a709d27abd630002903e3459.tar.gz
postgresql-387f9ed0a0832760a709d27abd630002903e3459.zip
Fix problems when a plain-inheritance parent table is excluded.
When an UPDATE/DELETE/MERGE's target table is an old-style inheritance tree, it's possible for the parent to get excluded from the plan while some children are not. (I believe this is only possible if we can prove that a CHECK ... NO INHERIT constraint on the parent contradicts the query WHERE clause, so it's a very unusual case.) In such a case, ExecInitModifyTable mistakenly concluded that the first surviving child is the target table, leading to at least two bugs: 1. The wrong table's statement-level triggers would get fired. 2. In v16 and up, it was possible to fail with "invalid perminfoindex 0 in RTE with relid nnnn" due to the child RTE not having permissions data included in the query plan. This was hard to reproduce reliably because it did not occur unless the update triggered some non-HOT index updates. In v14 and up, this is easy to fix by defining ModifyTable.rootRelation to be the parent RTE in plain inheritance as well as partitioned cases. While the wrong-triggers bug also appears in older branches, the relevant code in both the planner and executor is quite a bit different, so it would take a good deal of effort to develop and test a suitable patch. Given the lack of field complaints about the trigger issue, I'll desist for now. (Patching v11 for this seems unwise anyway, given that it will have no more releases after next month.) Per bug #18147 from Hans Buschmann. Amit Langote and Tom Lane Discussion: https://postgr.es/m/18147-6fc796538913ee88@postgresql.org
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r--src/backend/executor/nodeModifyTable.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index f62d28ac608..299c2c75be8 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -3966,10 +3966,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
* must be converted, and
* - the root partitioned table used for tuple routing.
*
- * If it's a partitioned table, the root partition doesn't appear
- * elsewhere in the plan and its RT index is given explicitly in
- * node->rootRelation. Otherwise (i.e. table inheritance) the target
- * relation is the first relation in the node->resultRelations list.
+ * If it's a partitioned or inherited table, the root partition or
+ * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
+ * given explicitly in node->rootRelation. Otherwise, the target relation
+ * is the sole relation in the node->resultRelations list.
*----------
*/
if (node->rootRelation > 0)
@@ -3980,6 +3980,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
}
else
{
+ Assert(list_length(node->resultRelations) == 1);
mtstate->rootResultRelInfo = mtstate->resultRelInfo;
ExecInitResultRelation(estate, mtstate->resultRelInfo,
linitial_int(node->resultRelations));