aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execCurrent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execCurrent.c')
-rw-r--r--src/backend/executor/execCurrent.c62
1 files changed, 46 insertions, 16 deletions
diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c
index f70e54fe2af..7480cf50ad0 100644
--- a/src/backend/executor/execCurrent.c
+++ b/src/backend/executor/execCurrent.c
@@ -23,7 +23,8 @@
static char *fetch_cursor_param_value(ExprContext *econtext, int paramId);
-static ScanState *search_plan_tree(PlanState *node, Oid table_oid);
+static ScanState *search_plan_tree(PlanState *node, Oid table_oid,
+ bool *pending_rescan);
/*
@@ -156,8 +157,10 @@ execCurrentOf(CurrentOfExpr *cexpr,
* aggregation.
*/
ScanState *scanstate;
+ bool pending_rescan = false;
- scanstate = search_plan_tree(queryDesc->planstate, table_oid);
+ scanstate = search_plan_tree(queryDesc->planstate, table_oid,
+ &pending_rescan);
if (!scanstate)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
@@ -177,8 +180,12 @@ execCurrentOf(CurrentOfExpr *cexpr,
errmsg("cursor \"%s\" is not positioned on a row",
cursor_name)));
- /* Now OK to return false if we found an inactive scan */
- if (TupIsNull(scanstate->ss_ScanTupleSlot))
+ /*
+ * Now OK to return false if we found an inactive scan. It is
+ * inactive either if it's not positioned on a row, or there's a
+ * rescan pending for it.
+ */
+ if (TupIsNull(scanstate->ss_ScanTupleSlot) || pending_rescan)
return false;
/*
@@ -291,10 +298,20 @@ fetch_cursor_param_value(ExprContext *econtext, int paramId)
*
* Search through a PlanState tree for a scan node on the specified table.
* Return NULL if not found or multiple candidates.
+ *
+ * If a candidate is found, set *pending_rescan to true if that candidate
+ * or any node above it has a pending rescan action, i.e. chgParam != NULL.
+ * That indicates that we shouldn't consider the node to be positioned on a
+ * valid tuple, even if its own state would indicate that it is. (Caller
+ * must initialize *pending_rescan to false, and should not trust its state
+ * if multiple candidates are found.)
*/
static ScanState *
-search_plan_tree(PlanState *node, Oid table_oid)
+search_plan_tree(PlanState *node, Oid table_oid,
+ bool *pending_rescan)
{
+ ScanState *result = NULL;
+
if (node == NULL)
return NULL;
switch (nodeTag(node))
@@ -314,7 +331,7 @@ search_plan_tree(PlanState *node, Oid table_oid)
ScanState *sstate = (ScanState *) node;
if (RelationGetRelid(sstate->ss_currentRelation) == table_oid)
- return sstate;
+ result = sstate;
break;
}
@@ -325,13 +342,13 @@ search_plan_tree(PlanState *node, Oid table_oid)
case T_AppendState:
{
AppendState *astate = (AppendState *) node;
- ScanState *result = NULL;
int i;
for (i = 0; i < astate->as_nplans; i++)
{
ScanState *elem = search_plan_tree(astate->appendplans[i],
- table_oid);
+ table_oid,
+ pending_rescan);
if (!elem)
continue;
@@ -339,7 +356,7 @@ search_plan_tree(PlanState *node, Oid table_oid)
return NULL; /* multiple matches */
result = elem;
}
- return result;
+ break;
}
/*
@@ -348,13 +365,13 @@ search_plan_tree(PlanState *node, Oid table_oid)
case T_MergeAppendState:
{
MergeAppendState *mstate = (MergeAppendState *) node;
- ScanState *result = NULL;
int i;
for (i = 0; i < mstate->ms_nplans; i++)
{
ScanState *elem = search_plan_tree(mstate->mergeplans[i],
- table_oid);
+ table_oid,
+ pending_rescan);
if (!elem)
continue;
@@ -362,7 +379,7 @@ search_plan_tree(PlanState *node, Oid table_oid)
return NULL; /* multiple matches */
result = elem;
}
- return result;
+ break;
}
/*
@@ -371,18 +388,31 @@ search_plan_tree(PlanState *node, Oid table_oid)
*/
case T_ResultState:
case T_LimitState:
- return search_plan_tree(node->lefttree, table_oid);
+ result = search_plan_tree(node->lefttree,
+ table_oid,
+ pending_rescan);
+ break;
/*
* SubqueryScan too, but it keeps the child in a different place
*/
case T_SubqueryScanState:
- return search_plan_tree(((SubqueryScanState *) node)->subplan,
- table_oid);
+ result = search_plan_tree(((SubqueryScanState *) node)->subplan,
+ table_oid,
+ pending_rescan);
+ break;
default:
/* Otherwise, assume we can't descend through it */
break;
}
- return NULL;
+
+ /*
+ * If we found a candidate at or below this node, then this node's
+ * chgParam indicates a pending rescan that will affect the candidate.
+ */
+ if (result && node->chgParam != NULL)
+ *pending_rescan = true;
+
+ return result;
}