postgres.git / summary / log / commit / refs

commit    2759924f33a6b7021f68dda05bb34b10bb4579e2
Author:   David Rowley <drowley@postgresql.org>
Date:     Thu Oct 12 12:15:12 2023 +0000
First released in: 17.0, 11.22, 12.17, 13.13, 14.10, 15.5, 16.1

    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.


src/backend/executor/execPartition.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index b667d03c7ff..d4c6833650d 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1673,7 +1673,7 @@ ExecInitPruningContext(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 */ @@ -1682,22 +1682,27 @@ ExecInitPruningContext(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); + + /* not needed for Consts */ + if (!IsA(expr, Const)) + { + int stateidx = PruneCxtStateIdx(partnatts, + step->step.step_id, + keyno); - context->exprstates[stateidx] = - ExecInitExpr(expr, context->planstate); + context->exprstates[stateidx] = + ExecInitExpr(expr, context->planstate); + } + lc2 = lnext(lc2); } - keyno++; } } } [parent: 8f1d44b64890]