mirror of
https://github.com/postgres/postgres.git
synced 2026-01-27 21:43:08 +03:00
Commit cbc127917e introduced tracking of unpruned relids to avoid
processing pruned relations, and changed ExecInitModifyTable() to
initialize only unpruned result relations. As a result, MERGE
statements that prune all target partitions can now lead to crashes
or incorrect behavior during execution.
The crash occurs because some executor code paths rely on
ModifyTableState.resultRelInfo[0] being present and initialized,
even when no result relations remain after pruning. For example,
ExecMerge() and ExecMergeNotMatched() use the first resultRelInfo
to determine the appropriate action. Similarly,
ExecInitPartitionInfo() assumes that at least one result relation
exists.
To preserve these assumptions, ExecInitModifyTable() now includes the
first result relation in the initialized result relation list if all
result relations for that ModifyTable were pruned. To enable that,
ExecDoInitialPruning() ensures the first relation is locked if it was
pruned and locking is necessary.
To support this exception to the pruning logic, PlannedStmt now
includes a list of RT indexes identifying the first result relation
of each ModifyTable node in the plan. This allows
ExecDoInitialPruning() to check whether each such relation was
pruned and, if so, lock it if necessary.
Bug: #18830
Reported-by: Robins Tharakan <tharakan@gmail.com>
Diagnozed-by: Tender Wang <tndrwang@gmail.com>
Diagnozed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Co-authored-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Discussion: https://postgr.es/m/18830-1f31ea1dc930d444%40postgresql.org
144 lines
5.7 KiB
C
144 lines
5.7 KiB
C
/*--------------------------------------------------------------------
|
|
* execPartition.h
|
|
* POSTGRES partitioning executor interface
|
|
*
|
|
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* src/include/executor/execPartition.h
|
|
*--------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef EXECPARTITION_H
|
|
#define EXECPARTITION_H
|
|
|
|
#include "nodes/execnodes.h"
|
|
#include "nodes/parsenodes.h"
|
|
#include "nodes/plannodes.h"
|
|
#include "partitioning/partprune.h"
|
|
|
|
/* See execPartition.c for the definitions. */
|
|
typedef struct PartitionDispatchData *PartitionDispatch;
|
|
typedef struct PartitionTupleRouting PartitionTupleRouting;
|
|
|
|
extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(EState *estate,
|
|
Relation rel);
|
|
extern ResultRelInfo *ExecFindPartition(ModifyTableState *mtstate,
|
|
ResultRelInfo *rootResultRelInfo,
|
|
PartitionTupleRouting *proute,
|
|
TupleTableSlot *slot,
|
|
EState *estate);
|
|
extern void ExecCleanupTupleRouting(ModifyTableState *mtstate,
|
|
PartitionTupleRouting *proute);
|
|
|
|
|
|
/*
|
|
* PartitionedRelPruningData - Per-partitioned-table data for run-time pruning
|
|
* of partitions. For a multilevel partitioned table, we have one of these
|
|
* for the topmost partition plus one for each non-leaf child partition.
|
|
*
|
|
* subplan_map[] and subpart_map[] have the same definitions as in
|
|
* PartitionedRelPruneInfo (see plannodes.h); though note that here,
|
|
* subpart_map contains indexes into PartitionPruningData.partrelprunedata[].
|
|
*
|
|
* partrel Partitioned table Relation; obtained by
|
|
* ExecGetRangeTableRelation(estate, rti, false),
|
|
* where rti is PartitionedRelPruneInfo.rtindex.
|
|
* nparts Length of subplan_map[] and subpart_map[].
|
|
* subplan_map Subplan index by partition index, or -1.
|
|
* subpart_map Subpart index by partition index, or -1.
|
|
* leafpart_rti_map RT index by partition index, or 0.
|
|
* present_parts A Bitmapset of the partition indexes that we
|
|
* have subplans or subparts for.
|
|
* initial_pruning_steps List of PartitionPruneSteps used to
|
|
* perform executor startup pruning.
|
|
* exec_pruning_steps List of PartitionPruneSteps used to
|
|
* perform per-scan pruning.
|
|
* initial_context If initial_pruning_steps isn't NIL, contains
|
|
* the details needed to execute those steps.
|
|
* exec_context If exec_pruning_steps isn't NIL, contains
|
|
* the details needed to execute those steps.
|
|
*/
|
|
typedef struct PartitionedRelPruningData
|
|
{
|
|
Relation partrel;
|
|
int nparts;
|
|
int *subplan_map;
|
|
int *subpart_map;
|
|
int *leafpart_rti_map;
|
|
Bitmapset *present_parts;
|
|
List *initial_pruning_steps;
|
|
List *exec_pruning_steps;
|
|
PartitionPruneContext initial_context;
|
|
PartitionPruneContext exec_context;
|
|
} PartitionedRelPruningData;
|
|
|
|
/*
|
|
* PartitionPruningData - Holds all the run-time pruning information for
|
|
* a single partitioning hierarchy containing one or more partitions.
|
|
* partrelprunedata[] is an array ordered such that parents appear before
|
|
* their children; in particular, the first entry is the topmost partition,
|
|
* which was actually named in the SQL query.
|
|
*/
|
|
typedef struct PartitionPruningData
|
|
{
|
|
int num_partrelprunedata; /* number of array entries */
|
|
PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER];
|
|
} PartitionPruningData;
|
|
|
|
/*
|
|
* PartitionPruneState - State object required for plan nodes to perform
|
|
* run-time partition pruning.
|
|
*
|
|
* This struct can be attached to plan types which support arbitrary Lists of
|
|
* subplans containing partitions, to allow subplans to be eliminated due to
|
|
* the clauses being unable to match to any tuple that the subplan could
|
|
* possibly produce.
|
|
*
|
|
* econtext Standalone ExprContext to evaluate expressions in
|
|
* the pruning steps
|
|
* execparamids Contains paramids of PARAM_EXEC Params found within
|
|
* any of the partprunedata structs. Pruning must be
|
|
* done again each time the value of one of these
|
|
* parameters changes.
|
|
* other_subplans Contains indexes of subplans that don't belong to any
|
|
* "partprunedata", e.g UNION ALL children that are not
|
|
* partitioned tables, or a partitioned table that the
|
|
* planner deemed run-time pruning to be useless for.
|
|
* These must not be pruned.
|
|
* prune_context A short-lived memory context in which to execute the
|
|
* partition pruning functions.
|
|
* do_initial_prune true if pruning should be performed during executor
|
|
* startup (at any hierarchy level).
|
|
* do_exec_prune true if pruning should be performed during
|
|
* executor run (at any hierarchy level).
|
|
* num_partprunedata Number of items in "partprunedata" array.
|
|
* partprunedata Array of PartitionPruningData pointers for the plan's
|
|
* partitioned relation(s), one for each partitioning
|
|
* hierarchy that requires run-time pruning.
|
|
*/
|
|
typedef struct PartitionPruneState
|
|
{
|
|
ExprContext *econtext;
|
|
Bitmapset *execparamids;
|
|
Bitmapset *other_subplans;
|
|
MemoryContext prune_context;
|
|
bool do_initial_prune;
|
|
bool do_exec_prune;
|
|
int num_partprunedata;
|
|
PartitionPruningData *partprunedata[FLEXIBLE_ARRAY_MEMBER];
|
|
} PartitionPruneState;
|
|
|
|
extern void ExecDoInitialPruning(EState *estate);
|
|
extern PartitionPruneState *ExecInitPartitionExecPruning(PlanState *planstate,
|
|
int n_total_subplans,
|
|
int part_prune_index,
|
|
Bitmapset *relids,
|
|
Bitmapset **initially_valid_subplans);
|
|
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate,
|
|
bool initial_prune,
|
|
Bitmapset **validsubplan_rtis);
|
|
|
|
#endif /* EXECPARTITION_H */
|