diff --git a/src/backend/executor/nodeTidrangescan.c b/src/backend/executor/nodeTidrangescan.c index 1bce8d6cbfe6..39239c6692b1 100644 --- a/src/backend/executor/nodeTidrangescan.c +++ b/src/backend/executor/nodeTidrangescan.c @@ -128,14 +128,17 @@ TidExprListCreate(TidRangeScanState *tidrangestate) * TidRangeEval * * Compute and set node's block and offset range to scan by evaluating - * node->trss_tidexprs. Returns false if we detect the range cannot - * contain any tuples. Returns true if it's possible for the range to - * contain tuples. We don't bother validating that trss_mintid is less - * than or equal to trss_maxtid, as the scan_set_tidrange() table AM - * function will handle that. + * node->trss_tidexprs. Sets node's trss_rangeIsEmpty to true if the + * calculated range must be empty of any tuples, otherwise sets + * trss_rangeIsEmpty to false and sets trss_mintid and trss_maxtid to the + * calculated range. + * + * We don't bother validating that trss_mintid is less than or equal to + * trss_maxtid, as the scan_set_tidrange() table AM function will handle + * that. * ---------------------------------------------------------------- */ -static bool +static void TidRangeEval(TidRangeScanState *node) { ExprContext *econtext = node->ss.ps.ps_ExprContext; @@ -165,7 +168,10 @@ TidRangeEval(TidRangeScanState *node) /* If the bound is NULL, *nothing* matches the qual. */ if (isNull) - return false; + { + node->trss_rangeIsEmpty = true; + return; + } if (tidopexpr->exprtype == TIDEXPR_LOWER_BOUND) { @@ -207,7 +213,7 @@ TidRangeEval(TidRangeScanState *node) ItemPointerCopy(&lowerBound, &node->trss_mintid); ItemPointerCopy(&upperBound, &node->trss_maxtid); - return true; + node->trss_rangeIsEmpty = false; } /* ---------------------------------------------------------------- @@ -234,12 +240,19 @@ TidRangeNext(TidRangeScanState *node) slot = node->ss.ss_ScanTupleSlot; direction = estate->es_direction; - if (!node->trss_inScan) + /* First time through, compute TID range to scan */ + if (!node->trss_rangeCalcDone) { - /* First time through, compute TID range to scan */ - if (!TidRangeEval(node)) - return NULL; + TidRangeEval(node); + node->trss_rangeCalcDone = true; + } + + /* Check if the range was detected not to contain any tuples */ + if (node->trss_rangeIsEmpty) + return NULL; + if (!node->trss_inScan) + { if (scandesc == NULL) { scandesc = table_beginscan_tidrange(node->ss.ss_currentRelation, @@ -274,13 +287,18 @@ TidRangeNext(TidRangeScanState *node) static bool TidRangeRecheck(TidRangeScanState *node, TupleTableSlot *slot) { - if (!TidRangeEval(node)) - return false; + /* First call? Compute the TID Range */ + if (!node->trss_rangeCalcDone) + { + TidRangeEval(node); + node->trss_rangeCalcDone = true; + } Assert(ItemPointerIsValid(&slot->tts_tid)); /* Recheck the ctid is still within range */ - if (ItemPointerCompare(&slot->tts_tid, &node->trss_mintid) < 0 || + if (node->trss_rangeIsEmpty || + ItemPointerCompare(&slot->tts_tid, &node->trss_mintid) < 0 || ItemPointerCompare(&slot->tts_tid, &node->trss_maxtid) > 0) return false; @@ -322,6 +340,13 @@ ExecReScanTidRangeScan(TidRangeScanState *node) /* mark scan as not in progress, and tid range list as not computed yet */ node->trss_inScan = false; + /* + * Set the Tid Range to be recalculated when any parameters that might + * effect the calculated range have changed. + */ + if (bms_overlap(node->ss.ps.chgParam, ((TidRangeScan *) node->ss.ps.plan)->tidparamids)) + node->trss_rangeCalcDone = false; + /* * We must wait until TidRangeNext before calling table_rescan_tidrange. */ @@ -380,6 +405,10 @@ ExecInitTidRangeScan(TidRangeScan *node, EState *estate, int eflags) * mark scan as not in progress, and TID range as not computed yet */ tidrangestate->trss_inScan = false; + tidrangestate->trss_rangeCalcDone = false; + + /* This will be calculated correctly in TidRangeEval() */ + tidrangestate->trss_rangeIsEmpty = true; /* * open the scan relation diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index d50c6600358c..b40a31e0d2fa 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -457,10 +457,19 @@ ExecTidScan(PlanState *pstate) void ExecReScanTidScan(TidScanState *node) { - if (node->tss_TidList) - pfree(node->tss_TidList); - node->tss_TidList = NULL; - node->tss_NumTids = 0; + /* + * Set the TidList to be recalculated when any parameters that might + * effect the computed list has changed. + */ + if (bms_overlap(node->ss.ps.chgParam, + ((TidScan *) node->ss.ps.plan)->tidparamids)) + { + if (node->tss_TidList) + pfree(node->tss_TidList); + node->tss_TidList = NULL; + node->tss_NumTids = 0; + } + node->tss_TidPtr = -1; /* not really necessary, but seems good form */ diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 6791cbeb416e..87e2597ee8c4 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -201,9 +201,10 @@ static BitmapHeapScan *make_bitmap_heapscan(List *qptlist, List *bitmapqualorig, Index scanrelid); static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, - List *tidquals); + List *tidquals, Bitmapset *paramids); static TidRangeScan *make_tidrangescan(List *qptlist, List *qpqual, - Index scanrelid, List *tidrangequals); + Index scanrelid, List *tidrangequals, + Bitmapset *paramids); static SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual, Index scanrelid, @@ -3384,6 +3385,7 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path, TidScan *scan_plan; Index scan_relid = best_path->path.parent->relid; List *tidquals = best_path->tidquals; + Bitmapset *paramids; /* it should be a base rel... */ Assert(scan_relid > 0); @@ -3459,10 +3461,13 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path, replace_nestloop_params(root, (Node *) scan_clauses); } + paramids = pull_paramids((Expr *) tidquals); + scan_plan = make_tidscan(tlist, scan_clauses, scan_relid, - tidquals); + tidquals, + paramids); copy_generic_path_info(&scan_plan->scan.plan, &best_path->path); @@ -3481,6 +3486,7 @@ create_tidrangescan_plan(PlannerInfo *root, TidRangePath *best_path, TidRangeScan *scan_plan; Index scan_relid = best_path->path.parent->relid; List *tidrangequals = best_path->tidrangequals; + Bitmapset *paramids; /* it should be a base rel... */ Assert(scan_relid > 0); @@ -3524,10 +3530,13 @@ create_tidrangescan_plan(PlannerInfo *root, TidRangePath *best_path, replace_nestloop_params(root, (Node *) scan_clauses); } + paramids = pull_paramids((Expr *) tidrangequals); + scan_plan = make_tidrangescan(tlist, scan_clauses, scan_relid, - tidrangequals); + tidrangequals, + paramids); copy_generic_path_info(&scan_plan->scan.plan, &best_path->path); @@ -5622,7 +5631,8 @@ static TidScan * make_tidscan(List *qptlist, List *qpqual, Index scanrelid, - List *tidquals) + List *tidquals, + Bitmapset *paramids) { TidScan *node = makeNode(TidScan); Plan *plan = &node->scan.plan; @@ -5633,6 +5643,7 @@ make_tidscan(List *qptlist, plan->righttree = NULL; node->scan.scanrelid = scanrelid; node->tidquals = tidquals; + node->tidparamids = paramids; return node; } @@ -5641,7 +5652,8 @@ static TidRangeScan * make_tidrangescan(List *qptlist, List *qpqual, Index scanrelid, - List *tidrangequals) + List *tidrangequals, + Bitmapset *paramids) { TidRangeScan *node = makeNode(TidRangeScan); Plan *plan = &node->scan.plan; @@ -5652,6 +5664,7 @@ make_tidrangescan(List *qptlist, plan->righttree = NULL; node->scan.scanrelid = scanrelid; node->tidrangequals = tidrangequals; + node->tidparamids = paramids; return node; } diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 3a920cc7d17a..a5abe176aeff 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1924,6 +1924,8 @@ typedef struct TidScanState * trss_mintid the lowest TID in the scan range * trss_maxtid the highest TID in the scan range * trss_inScan is a scan currently in progress? + * trss_rangeCalcDone has the TID range been calculated yet? + * trss_rangeIsEmpty true if the TID range is certainly empty * ---------------- */ typedef struct TidRangeScanState @@ -1933,6 +1935,8 @@ typedef struct TidRangeScanState ItemPointerData trss_mintid; ItemPointerData trss_maxtid; bool trss_inScan; + bool trss_rangeCalcDone; + bool trss_rangeIsEmpty; } TidRangeScanState; /* ---------------- diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 29d7732d6a03..a3d220e9d5e6 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -677,6 +677,8 @@ typedef struct TidScan Scan scan; /* qual(s) involving CTID = something */ List *tidquals; + /* Set of ParamIds mentioned in tidquals */ + Bitmapset *tidparamids; } TidScan; /* ---------------- @@ -691,6 +693,8 @@ typedef struct TidRangeScan Scan scan; /* qual(s) involving CTID op something */ List *tidrangequals; + /* Set of ParamIds mentioned in tidrangequals */ + Bitmapset *tidparamids; } TidRangeScan; /* ----------------