summaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorDavid Rowley <drowley@postgresql.org>2023-10-13 01:13:36 +1300
committerDavid Rowley <drowley@postgresql.org>2023-10-13 01:13:36 +1300
commit1e81d3e6e0a0e35e52e109742c5ce3738c3e87c6 (patch)
treeb57fa306cb90e294dabf921abda32626e53d47bd /src/backend/executor
parent245e0f4e8de565ec87c1ec64bfd89d846f3d496e (diff)
Fix runtime partition pruning for HASH partitioned tables
This could only affect HASH partitioned tables with at least 2 partition key columns. If partition pruning was delayed until execution and the query contained an IS NULL qual on one of the partitioned keys, and some subsequent partitioned key was being compared to a non-Const, then this could result in a crash due to the incorrect keyno being used to calculate the stateidx for the expression evaluation code. Here we fix this by properly skipping partitioned keys which have a nullkey set. Effectively, this must be the same as what's going on inside perform_pruning_base_step(). Sergei Glukhov also provided a patch, but that's not what's being used here. Reported-by: Sergei Glukhov Reviewed-by: tender wang, Sergei Glukhov Discussion: https://postgr.es/m/d05b26fa-af54-27e1-f693-6c31590802fa@postgrespro.ru Backpatch-through: 11, where runtime partition pruning was added.
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execPartition.c53
1 files changed, 29 insertions, 24 deletions
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 73bc5bb9585..ba5a58d027c 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1956,7 +1956,7 @@ InitPartitionPruneContext(PartitionPruneContext *context,
foreach(lc, pruning_steps)
{
PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc);
- ListCell *lc2;
+ ListCell *lc2 = list_head(step->exprs);
int keyno;
/* not needed for other step kinds */
@@ -1965,34 +1965,39 @@ InitPartitionPruneContext(PartitionPruneContext *context,
Assert(list_length(step->exprs) <= partnatts);
- keyno = 0;
- foreach(lc2, step->exprs)
+ for (keyno = 0; keyno < partnatts; keyno++)
{
- Expr *expr = (Expr *) lfirst(lc2);
+ if (bms_is_member(keyno, step->nullkeys))
+ continue;
- /* not needed for Consts */
- if (!IsA(expr, Const))
+ if (lc2 != NULL)
{
- int stateidx = PruneCxtStateIdx(partnatts,
- step->step.step_id,
- keyno);
+ Expr *expr = lfirst(lc2);
- /*
- * When planstate is NULL, pruning_steps is known not to
- * contain any expressions that depend on the parent plan.
- * Information of any available EXTERN parameters must be
- * passed explicitly in that case, which the caller must have
- * made available via econtext.
- */
- if (planstate == NULL)
- context->exprstates[stateidx] =
- ExecInitExprWithParams(expr,
- econtext->ecxt_param_list_info);
- else
- context->exprstates[stateidx] =
- ExecInitExpr(expr, context->planstate);
+ /* not needed for Consts */
+ if (!IsA(expr, Const))
+ {
+ int stateidx = PruneCxtStateIdx(partnatts,
+ step->step.step_id,
+ keyno);
+
+ /*
+ * When planstate is NULL, pruning_steps is known not to
+ * contain any expressions that depend on the parent plan.
+ * Information of any available EXTERN parameters must be
+ * passed explicitly in that case, which the caller must
+ * have made available via econtext.
+ */
+ if (planstate == NULL)
+ context->exprstates[stateidx] =
+ ExecInitExprWithParams(expr,
+ econtext->ecxt_param_list_info);
+ else
+ context->exprstates[stateidx] =
+ ExecInitExpr(expr, context->planstate);
+ }
+ lc2 = lnext(step->exprs, lc2);
}
- keyno++;
}
}
}