Amit Langote wrote:

> That's neat!  Definitely agree that we should call ExecInitExpr just once
> here.  The patch looks good too, except the long line.

How about this as a small tweak?  Determine the array index using a
macro, which serves as documentation.

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>From 135740cd17e8c05f36a3b91b3af29515df6a2d3b Mon Sep 17 00:00:00 2001
From: "dgrow...@gmail.com" <dgrow...@gmail.com>
Date: Thu, 19 Apr 2018 11:51:16 +1200
Subject: [PATCH v3] Initialize ExprStates once in run-time partition pruning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Instead of doing ExecInitExpr every time a Param needs to be evaluated
in run-time partition pruning, do it once during run-time pruning
set-up and cache the exprstate in PartitionPruneContext, saving a lot of
work.

Author: David Rowley
Reviewed-by: Amit Langote, Álvaro Herrera
Discussion: 
https://postgr.es/m/CAKJS1f8-x+q-90QAPDu_okhQBV4DPEtPz8CJ=m0940gyt4d...@mail.gmail.com
---
 src/backend/executor/execPartition.c | 35 +++++++++++++++++++++++++++++++++++
 src/backend/partitioning/partprune.c | 27 +++++++++++++++++----------
 src/include/partitioning/partprune.h |  9 +++++++++
 3 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index f7bbb804aa..f7418f64b1 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -1442,7 +1442,9 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                PartitionDesc partdesc;
                Relation        rel;
                PartitionKey partkey;
+               ListCell   *lc2;
                int                     partnatts;
+               int                     n_steps;
 
                pprune->present_parts = bms_copy(pinfo->present_parts);
                pprune->subnode_map = palloc(sizeof(int) * pinfo->nparts);
@@ -1465,6 +1467,7 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
 
                partkey = RelationGetPartitionKey(rel);
                partdesc = RelationGetPartitionDesc(rel);
+               n_steps = list_length(pinfo->pruning_steps);
 
                context->strategy = partkey->strategy;
                context->partnatts = partnatts = partkey->partnatts;
@@ -1476,6 +1479,38 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                context->boundinfo = partition_bounds_copy(partdesc->boundinfo, 
partkey);
                context->planstate = planstate;
                context->safeparams = NULL; /* empty for now */
+               context->exprstates = palloc0(sizeof(ExprState *) * n_steps * 
partnatts);
+
+               /* Initialize expression states for each expression */
+               foreach(lc2, pinfo->pruning_steps)
+               {
+                       PartitionPruneStepOp *step = (PartitionPruneStepOp *) 
lfirst(lc2);
+                       ListCell   *lc3;
+                       int                     keyno;
+
+                       /* not needed for other step kinds */
+                       if (!IsA(step, PartitionPruneStepOp))
+                               continue;
+
+                       Assert(list_length(step->exprs) <= partnatts);
+
+                       keyno = 0;
+                       foreach(lc3, step->exprs)
+                       {
+                               Expr       *expr = (Expr *) lfirst(lc3);
+                               int                     stateidx;
+
+                               /* not needed for Consts */
+                               if (!IsA(expr, Const))
+                               {
+                                       stateidx = PruneCxtStateIdx(partnatts,
+                                                                               
                step->step.step_id, keyno);
+                                       context->exprstates[stateidx] =
+                                               ExecInitExpr(expr, 
context->planstate);
+                               }
+                               keyno++;
+                       }
+               }
 
                pprune->pruning_steps = pinfo->pruning_steps;
                pprune->extparams = bms_copy(pinfo->extparams);
diff --git a/src/backend/partitioning/partprune.c 
b/src/backend/partitioning/partprune.c
index f8844ef2eb..62159477c1 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -169,7 +169,7 @@ static PruneStepResult 
*perform_pruning_combine_step(PartitionPruneContext *cont
 static bool match_boolean_partition_clause(Oid partopfamily, Expr *clause,
                                                           Expr *partkey, Expr 
**outconst);
 static bool partkey_datum_from_expr(PartitionPruneContext *context,
-                                               Expr *expr, Datum *value);
+                                               Expr *expr, int stateidx, Datum 
*value);
 
 /*
  * make_partition_pruneinfo
@@ -444,6 +444,7 @@ prune_append_rel_partitions(RelOptInfo *rel)
        /* Not valid when being called from the planner */
        context.planstate = NULL;
        context.safeparams = NULL;
+       context.exprstates = NULL;
 
        /* Actual pruning happens here. */
        partindexes = get_matching_partitions(&context, pruning_steps);
@@ -2788,10 +2789,13 @@ perform_pruning_base_step(PartitionPruneContext 
*context,
                if (lc1 != NULL)
                {
                        Expr       *expr;
+                       int                     stateidx;
                        Datum           datum;
 
                        expr = lfirst(lc1);
-                       if (partkey_datum_from_expr(context, expr, &datum))
+                       stateidx = PruneCxtStateIdx(context->partnatts,
+                                                                               
opstep->step.step_id, keyno);
+                       if (partkey_datum_from_expr(context, expr, stateidx, 
&datum))
                        {
                                Oid                     cmpfn;
 
@@ -3025,12 +3029,15 @@ match_boolean_partition_clause(Oid partopfamily, Expr 
*clause, Expr *partkey,
 
 /*
  * partkey_datum_from_expr
- *             Evaluate 'expr', set *value to the resulting Datum. Return true 
if
- *             evaluation was possible, otherwise false.
+ *             Evaluate expression for potential partition pruning
+ *
+ * Evaluate 'expr', whose ExprState is stateidx of the context exprstate
+ * array; set *value to the resulting Datum.  Return true if evaluation was
+ * possible, otherwise false.
  */
 static bool
 partkey_datum_from_expr(PartitionPruneContext *context,
-                                               Expr *expr, Datum *value)
+                                               Expr *expr, int stateidx, Datum 
*value)
 {
        switch (nodeTag(expr))
        {
@@ -3048,18 +3055,18 @@ partkey_datum_from_expr(PartitionPruneContext *context,
                                bms_is_member(((Param *) expr)->paramid, 
context->safeparams))
                        {
                                ExprState  *exprstate;
+                               ExprContext *ectx;
                                bool            isNull;
 
-                               exprstate = ExecInitExpr(expr, 
context->planstate);
-
-                               *value = ExecEvalExprSwitchContext(exprstate,
-                                                                               
                   context->planstate->ps_ExprContext,
-                                                                               
                   &isNull);
+                               exprstate = context->exprstates[stateidx];
+                               ectx = context->planstate->ps_ExprContext;
+                               *value = ExecEvalExprSwitchContext(exprstate, 
ectx, &isNull);
                                if (isNull)
                                        return false;
 
                                return true;
                        }
+                       break;
 
                default:
                        break;
diff --git a/src/include/partitioning/partprune.h 
b/src/include/partitioning/partprune.h
index a5568abce6..c9fe95dc30 100644
--- a/src/include/partitioning/partprune.h
+++ b/src/include/partitioning/partprune.h
@@ -50,8 +50,17 @@ typedef struct PartitionPruneContext
         * are not safe to use until the executor is running.
         */
        Bitmapset  *safeparams;
+
+       /*
+        * Array of ExprStates, indexed as per PruneCtxStateIdx; one for each
+        * partkey in each pruning step.  Allocated if planstate is non-NULL,
+        * otherwise NULL.
+        */
+       ExprState **exprstates;
 } PartitionPruneContext;
 
+#define PruneCxtStateIdx(partnatts, step_id, keyno) \
+       ((partnatts) * (step_id) + (keyno))
 
 extern List *make_partition_pruneinfo(PlannerInfo *root, List *partition_rels,
                                                 List *subpaths, List 
*prunequal);
-- 
2.11.0

Reply via email to