On 12/09/2011 12:12, I wrote:
On 2011-09-10 19:50, Marti Raudsepp wrote:
I tried this patch and noticed something weird. This is probably not
intentional:

Indeed, it is not intentional.  Will see how I can fix this.

The attached patch is the best I could come up with. I considered showing "Rows Removed by Foo: (never executed)" and omitting the line altogether, but I didn't particularly like either of those options. The current patch simply displays "Rows Removed by Foo: 0".

I also added a comment the last patch was missing.


--
Marko Tiikkaja                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 6408d16..1f42f46 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -64,9 +64,15 @@ static void show_qual(List *qual, const char *qlabel,
 static void show_scan_qual(List *qual, const char *qlabel,
                           PlanState *planstate, List *ancestors,
                           ExplainState *es);
+static void show_instrumented_scan_qual(List *qual, const char *qlabel,
+                                       PlanState *planstate, double nremoved,
+                                       List *ancestors, ExplainState *es);
 static void show_upper_qual(List *qual, const char *qlabel,
                                PlanState *planstate, List *ancestors,
                                ExplainState *es);
+static void show_instrumented_upper_qual(List *qual, const char *qlabel,
+                               PlanState *planstate, double nremoved,
+                               List *ancestors, ExplainState *es);
 static void show_sort_keys(SortState *sortstate, List *ancestors,
                           ExplainState *es);
 static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors,
@@ -1002,29 +1008,37 @@ ExplainNode(PlanState *planstate, List *ancestors,
                                                   "Index Cond", planstate, 
ancestors, es);
                        show_scan_qual(((IndexScan *) plan)->indexorderbyorig,
                                                   "Order By", planstate, 
ancestors, es);
-                       show_scan_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_scan_qual(plan->qual, "Filter", 
planstate,
+                                                                               
((ScanState *) planstate)->ss_qualnremoved,
+                                                                               
ancestors, es);
                        break;
                case T_BitmapIndexScan:
                        show_scan_qual(((BitmapIndexScan *) 
plan)->indexqualorig,
                                                   "Index Cond", planstate, 
ancestors, es);
                        break;
                case T_BitmapHeapScan:
-                       show_scan_qual(((BitmapHeapScan *) 
plan)->bitmapqualorig,
-                                                  "Recheck Cond", planstate, 
ancestors, es);
+                       show_instrumented_scan_qual(((BitmapHeapScan *) 
plan)->bitmapqualorig,
+                                                                               
"Recheck Cond", planstate,
+                                                                               
((BitmapHeapScanState *) planstate)->bqonremoved,
+                                                                               
ancestors, es);
                        /* FALL THRU */
                case T_SeqScan:
                case T_ValuesScan:
                case T_CteScan:
                case T_WorkTableScan:
                case T_SubqueryScan:
-                       show_scan_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_scan_qual(plan->qual, "Filter", 
planstate,
+                                                                               
((ScanState *) planstate)->ss_qualnremoved,
+                                                                               
ancestors, es);
                        break;
                case T_FunctionScan:
                        if (es->verbose)
                                show_expression(((FunctionScan *) 
plan)->funcexpr,
                                                                "Function 
Call", planstate, ancestors,
                                                                es->verbose, 
es);
-                       show_scan_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_scan_qual(plan->qual, "Filter", 
planstate,
+                                                                               
((ScanState *) planstate)->ss_qualnremoved,
+                                                                               
ancestors, es);
                        break;
                case T_TidScan:
                        {
@@ -1037,35 +1051,47 @@ ExplainNode(PlanState *planstate, List *ancestors,
                                if (list_length(tidquals) > 1)
                                        tidquals = 
list_make1(make_orclause(tidquals));
                                show_scan_qual(tidquals, "TID Cond", planstate, 
ancestors, es);
-                               show_scan_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                               show_instrumented_scan_qual(plan->qual, 
"Filter", planstate,
+                                                                               
        ((ScanState *) planstate)->ss_qualnremoved,
+                                                                               
        ancestors, es);
                        }
                        break;
                case T_ForeignScan:
-                       show_scan_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_scan_qual(plan->qual, "Filter", 
planstate,
+                                                                               
((ScanState *) planstate)->ss_qualnremoved,
+                                                                               
ancestors, es);
                        show_foreignscan_info((ForeignScanState *) planstate, 
es);
                        break;
                case T_NestLoop:
                        show_upper_qual(((NestLoop *) plan)->join.joinqual,
                                                        "Join Filter", 
planstate, ancestors, es);
-                       show_upper_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_upper_qual(plan->qual, "Filter", 
planstate,
+                                                                               
 ((JoinState *) planstate)->js_oqnremoved,
+                                                                               
 ancestors, es);
                        break;
                case T_MergeJoin:
                        show_upper_qual(((MergeJoin *) plan)->mergeclauses,
                                                        "Merge Cond", 
planstate, ancestors, es);
                        show_upper_qual(((MergeJoin *) plan)->join.joinqual,
                                                        "Join Filter", 
planstate, ancestors, es);
-                       show_upper_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_upper_qual(plan->qual, "Filter", 
planstate,
+                                                                               
 ((JoinState *) planstate)->js_oqnremoved,
+                                                                               
 ancestors, es);
                        break;
                case T_HashJoin:
                        show_upper_qual(((HashJoin *) plan)->hashclauses,
                                                        "Hash Cond", planstate, 
ancestors, es);
                        show_upper_qual(((HashJoin *) plan)->join.joinqual,
                                                        "Join Filter", 
planstate, ancestors, es);
-                       show_upper_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_upper_qual(plan->qual, "Filter", 
planstate,
+                                                                               
 ((JoinState *) planstate)->js_oqnremoved,
+                                                                               
 ancestors, es);
                        break;
                case T_Agg:
                case T_Group:
-                       show_upper_qual(plan->qual, "Filter", planstate, 
ancestors, es);
+                       show_instrumented_upper_qual(plan->qual, "Filter", 
planstate,
+                                                                               
 ((ScanState *) planstate)->ss_qualnremoved,
+                                                                               
 ancestors, es);
                        break;
                case T_Sort:
                        show_sort_keys((SortState *) planstate, ancestors, es);
@@ -1356,6 +1382,31 @@ show_scan_qual(List *qual, const char *qlabel,
 }
 
 /*
+ * Show a qualifier expression and instrumentation information (if in EXPLAIN
+ * ANALYZE) for a scan plan node
+ */
+static void
+show_instrumented_scan_qual(List *qual, const char *qlabel,
+                                                       PlanState *planstate, 
double nremoved,
+                                                       List *ancestors, 
ExplainState *es)
+{
+       char buf[256];
+       
+       show_scan_qual(qual, qlabel, planstate, ancestors, es);
+
+       if (!qual || !es->analyze)
+               return;
+
+       snprintf(buf, sizeof(buf), "Rows Removed by %s", qlabel);
+
+       if (planstate->instrument->nloops > 0)
+               ExplainPropertyFloat(buf, nremoved / 
planstate->instrument->nloops, 0, es);
+       else
+               ExplainPropertyFloat(buf, 0.0, 0, es);
+}
+
+
+/*
  * Show a qualifier expression for an upper-level plan node
  */
 static void
@@ -1370,6 +1421,30 @@ show_upper_qual(List *qual, const char *qlabel,
 }
 
 /*
+ * Show a qualifier expression and instrumentation information (if in EXPLAIN
+ * ANALYZE) for an upper-level node
+ */
+static void
+show_instrumented_upper_qual(List *qual, const char *qlabel,
+                                                        PlanState *planstate, 
double nremoved,
+                                                        List *ancestors, 
ExplainState *es)
+{
+       char buf[256];
+
+       show_upper_qual(qual, qlabel, planstate, ancestors, es);
+
+       if (!qual || !es->analyze)
+               return;
+
+       snprintf(buf, sizeof(buf), "Rows Removed by %s", qlabel);
+
+       if (planstate->instrument->nloops > 0)
+               ExplainPropertyFloat(buf, nremoved / 
planstate->instrument->nloops, 0, es);
+       else
+               ExplainPropertyFloat(buf, 0.0, 0, es);
+}
+
+/*
  * Show the sort keys for a Sort node.
  */
 static void
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index e900588..2de6b56 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -223,6 +223,7 @@ ExecScan(ScanState *node,
                /*
                 * Tuple fails qual, so free per-tuple memory and try again.
                 */
+               node->ss_qualnremoved += 1;
                ResetExprContext(econtext);
        }
 }
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 13d7723..0249c63 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1204,6 +1204,8 @@ agg_retrieve_direct(AggState *aggstate)
                                return result;
                        }
                }
+               else
+                       aggstate->ss.ss_qualnremoved += 1;
        }
 
        /* No more groups */
@@ -1354,6 +1356,8 @@ agg_retrieve_hash_table(AggState *aggstate)
                                return result;
                        }
                }
+               else
+                       aggstate->ss.ss_qualnremoved += 1;
        }
 
        /* No more groups */
@@ -1387,6 +1391,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
        aggstate = makeNode(AggState);
        aggstate->ss.ps.plan = (Plan *) node;
        aggstate->ss.ps.state = estate;
+       aggstate->ss.ss_qualnremoved = 0;
 
        aggstate->aggs = NIL;
        aggstate->numaggs = 0;
diff --git a/src/backend/executor/nodeBitmapHeapscan.c 
b/src/backend/executor/nodeBitmapHeapscan.c
index 8e50fb1..abb9ff4 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -278,6 +278,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
                        if (!ExecQual(node->bitmapqualorig, econtext, false))
                        {
                                /* Fails recheck, so drop it and loop back for 
another */
+                               node->bqonremoved += 1;
                                ExecClearTuple(slot);
                                continue;
                        }
@@ -542,7 +543,10 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState 
*estate, int eflags)
        scanstate = makeNode(BitmapHeapScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ss_qualnremoved = 0;
 
+
+       scanstate->bqonremoved = 0;
        scanstate->tbm = NULL;
        scanstate->tbmiterator = NULL;
        scanstate->tbmres = NULL;
diff --git a/src/backend/executor/nodeBitmapIndexscan.c 
b/src/backend/executor/nodeBitmapIndexscan.c
index 9a56fd4..4dd1367 100644
--- a/src/backend/executor/nodeBitmapIndexscan.c
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -207,6 +207,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState 
*estate, int eflags)
        indexstate = makeNode(BitmapIndexScanState);
        indexstate->ss.ps.plan = (Plan *) node;
        indexstate->ss.ps.state = estate;
+       indexstate->ss.ss_qualnremoved = 0;
 
        /* normally we don't make the result bitmap till runtime */
        indexstate->biss_result = NULL;
diff --git a/src/backend/executor/nodeCtescan.c 
b/src/backend/executor/nodeCtescan.c
index ec39f29..fdef1e8 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -191,6 +191,7 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
        scanstate = makeNode(CteScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ss_qualnremoved = 0;
        scanstate->eflags = eflags;
        scanstate->cte_table = NULL;
        scanstate->eof_cte = false;
diff --git a/src/backend/executor/nodeForeignscan.c 
b/src/backend/executor/nodeForeignscan.c
index 841ae69..6a25fd7 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -114,6 +114,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int 
eflags)
        scanstate = makeNode(ForeignScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ss_qualnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeFunctionscan.c 
b/src/backend/executor/nodeFunctionscan.c
index 5d5727e..894208c 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -133,6 +133,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, 
int eflags)
        scanstate = makeNode(FunctionScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ss_qualnremoved = 0;
        scanstate->eflags = eflags;
 
        /*
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index fa403e5..f167a39 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -118,6 +118,8 @@ ExecGroup(GroupState *node)
                                return result;
                        }
                }
+               else
+                       node->ss.ss_qualnremoved += 1;
        }
 
        /*
@@ -179,6 +181,8 @@ ExecGroup(GroupState *node)
                                return result;
                        }
                }
+               else
+                       node->ss.ss_qualnremoved += 1;
        }
 
        /* NOTREACHED */
@@ -206,6 +210,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
        grpstate = makeNode(GroupState);
        grpstate->ss.ps.plan = (Plan *) node;
        grpstate->ss.ps.state = estate;
+       grpstate->ss.ss_qualnremoved = 0;
        grpstate->grp_done = FALSE;
 
        /*
diff --git a/src/backend/executor/nodeHashjoin.c 
b/src/backend/executor/nodeHashjoin.c
index 3a66981..11aa4a6 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -325,6 +325,8 @@ ExecHashJoin(HashJoinState *node)
                                                        return result;
                                                }
                                        }
+                                       else
+                                               node->js.js_oqnremoved += 1;
                                }
                                break;
 
@@ -360,6 +362,8 @@ ExecHashJoin(HashJoinState *node)
                                                        return result;
                                                }
                                        }
+                                       else
+                                               node->js.js_oqnremoved += 1;
                                }
                                break;
 
@@ -397,6 +401,8 @@ ExecHashJoin(HashJoinState *node)
                                                return result;
                                        }
                                }
+                               else
+                                       node->js.js_oqnremoved += 1;
                                break;
 
                        case HJ_NEED_NEW_BATCH:
@@ -442,6 +448,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
        hjstate = makeNode(HashJoinState);
        hjstate->js.ps.plan = (Plan *) node;
        hjstate->js.ps.state = estate;
+       hjstate->js.js_oqnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeIndexscan.c 
b/src/backend/executor/nodeIndexscan.c
index 955008e..cb705f4 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -468,6 +468,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int 
eflags)
        indexstate = makeNode(IndexScanState);
        indexstate->ss.ps.plan = (Plan *) node;
        indexstate->ss.ps.state = estate;
+       indexstate->ss.ss_qualnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeMergejoin.c 
b/src/backend/executor/nodeMergejoin.c
index e23dd6c..b3a1b10 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -893,6 +893,8 @@ ExecMergeJoin(MergeJoinState *node)
                                                        return result;
                                                }
                                        }
+                                       else
+                                               node->js.js_oqnremoved += 1;
                                }
                                break;
 
@@ -1503,6 +1505,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int 
eflags)
        mergestate = makeNode(MergeJoinState);
        mergestate->js.ps.plan = (Plan *) node;
        mergestate->js.ps.state = estate;
+       mergestate->js.js_oqnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeNestloop.c 
b/src/backend/executor/nodeNestloop.c
index e98bc0f..a4b9c92 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -214,6 +214,8 @@ ExecNestLoop(NestLoopState *node)
                                                return result;
                                        }
                                }
+                               else
+                                       node->js.js_oqnremoved += 1;
                        }
 
                        /*
@@ -270,6 +272,8 @@ ExecNestLoop(NestLoopState *node)
                                        return result;
                                }
                        }
+                       else
+                               node->js.js_oqnremoved += 1;
                }
 
                /*
@@ -302,6 +306,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
        nlstate = makeNode(NestLoopState);
        nlstate->js.ps.plan = (Plan *) node;
        nlstate->js.ps.state = estate;
+       nlstate->js.js_oqnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeSeqscan.c 
b/src/backend/executor/nodeSeqscan.c
index 5b652c9..7a115c9 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -169,6 +169,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
        scanstate = makeNode(SeqScanState);
        scanstate->ps.plan = (Plan *) node;
        scanstate->ps.state = estate;
+       scanstate->ss_qualnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeSubqueryscan.c 
b/src/backend/executor/nodeSubqueryscan.c
index 7e4d5de..26e0e70 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -109,6 +109,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, 
int eflags)
        subquerystate = makeNode(SubqueryScanState);
        subquerystate->ss.ps.plan = (Plan *) node;
        subquerystate->ss.ps.state = estate;
+       subquerystate->ss.ss_qualnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeTidscan.c 
b/src/backend/executor/nodeTidscan.c
index 69f47ff..68d61b9 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -491,6 +491,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
        tidstate = makeNode(TidScanState);
        tidstate->ss.ps.plan = (Plan *) node;
        tidstate->ss.ps.state = estate;
+       tidstate->ss.ss_qualnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeValuesscan.c 
b/src/backend/executor/nodeValuesscan.c
index d5260e4..5d474f6 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -205,6 +205,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int 
eflags)
        scanstate = makeNode(ValuesScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ss_qualnremoved = 0;
 
        /*
         * Miscellaneous initialization
diff --git a/src/backend/executor/nodeWorktablescan.c 
b/src/backend/executor/nodeWorktablescan.c
index bdebb6d..762605f 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -146,6 +146,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, 
int eflags)
        scanstate = makeNode(WorkTableScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ss_qualnremoved = 0;
        scanstate->rustate = NULL;      /* we'll set this later */
 
        /*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index b3eed7d..7139e8c 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1170,6 +1170,7 @@ typedef struct ScanState
        Relation        ss_currentRelation;
        HeapScanDesc ss_currentScanDesc;
        TupleTableSlot *ss_ScanTupleSlot;
+       double          ss_qualnremoved; /* number of rows removed by ps.qual */
 } ScanState;
 
 /*
@@ -1280,6 +1281,7 @@ typedef struct BitmapHeapScanState
 {
        ScanState       ss;                             /* its first field is 
NodeTag */
        List       *bitmapqualorig;
+       double          bqonremoved; /* number of rows removed by 
bitmapqualorig */
        TIDBitmap  *tbm;
        TBMIterator *tbmiterator;
        TBMIterateResult *tbmres;
@@ -1438,6 +1440,7 @@ typedef struct JoinState
        PlanState       ps;
        JoinType        jointype;
        List       *joinqual;           /* JOIN quals (in addition to ps.qual) 
*/
+       double          js_oqnremoved; /* number of rows removed by otherqual 
(ps.qual) */
 } JoinState;
 
 /* ----------------
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to