mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-09 08:10:09 +08:00
Make simpler-simple-expressions code cope with a Gather plan.
Commit 00418c612
expected that the plan generated for a simple-expression
query would always be a plain Result node. However, if force_parallel_mode
is on, the planner might stick a Gather atop that. Cope by looking through
the Gather. For safety, assert that the Gather's tlist is trivial.
Per buildfarm.
Discussion: https://postgr.es/m/23425.1502822098@sss.pgh.pa.us
This commit is contained in:
parent
70b573b267
commit
b73f1b5c29
@ -6553,7 +6553,7 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
|
||||
{
|
||||
PlannedStmt *stmt;
|
||||
Plan *plan;
|
||||
TargetEntry *tle;
|
||||
Expr *tle_expr;
|
||||
|
||||
/*
|
||||
* Given the checks that exec_simple_check_plan did, none of the Asserts
|
||||
@ -6563,33 +6563,64 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
|
||||
/* Extract the single PlannedStmt */
|
||||
Assert(list_length(cplan->stmt_list) == 1);
|
||||
stmt = linitial_node(PlannedStmt, cplan->stmt_list);
|
||||
|
||||
/* Should be a trivial Result plan */
|
||||
Assert(stmt->commandType == CMD_SELECT);
|
||||
plan = stmt->planTree;
|
||||
Assert(IsA(plan, Result));
|
||||
Assert(plan->lefttree == NULL &&
|
||||
plan->righttree == NULL &&
|
||||
plan->initPlan == NULL &&
|
||||
plan->qual == NULL &&
|
||||
((Result *) plan)->resconstantqual == NULL);
|
||||
|
||||
/* Extract the single tlist expression */
|
||||
Assert(list_length(plan->targetlist) == 1);
|
||||
tle = (TargetEntry *) linitial(plan->targetlist);
|
||||
/*
|
||||
* Ordinarily, the plan node should be a simple Result. However, if
|
||||
* force_parallel_mode is on, the planner might've stuck a Gather node
|
||||
* atop that. The simplest way to deal with this is to look through the
|
||||
* Gather node. The Gather node's tlist would normally contain a Var
|
||||
* referencing the child node's output ... but setrefs.c might also have
|
||||
* copied a Const as-is.
|
||||
*/
|
||||
plan = stmt->planTree;
|
||||
for (;;)
|
||||
{
|
||||
/* Extract the single tlist expression */
|
||||
Assert(list_length(plan->targetlist) == 1);
|
||||
tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
|
||||
|
||||
if (IsA(plan, Result))
|
||||
{
|
||||
Assert(plan->lefttree == NULL &&
|
||||
plan->righttree == NULL &&
|
||||
plan->initPlan == NULL &&
|
||||
plan->qual == NULL &&
|
||||
((Result *) plan)->resconstantqual == NULL);
|
||||
break;
|
||||
}
|
||||
else if (IsA(plan, Gather))
|
||||
{
|
||||
Assert(plan->lefttree != NULL &&
|
||||
plan->righttree == NULL &&
|
||||
plan->initPlan == NULL &&
|
||||
plan->qual == NULL);
|
||||
/* If setrefs.c copied up a Const, no need to look further */
|
||||
if (IsA(tle_expr, Const))
|
||||
break;
|
||||
/* Otherwise, it better be an outer Var */
|
||||
Assert(IsA(tle_expr, Var));
|
||||
Assert(((Var *) tle_expr)->varno == OUTER_VAR);
|
||||
/* Descend to the child node */
|
||||
plan = plan->lefttree;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "unexpected plan node type: %d",
|
||||
(int) nodeTag(plan));
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the simple expression, and initialize state to "not valid in
|
||||
* current transaction".
|
||||
*/
|
||||
expr->expr_simple_expr = tle->expr;
|
||||
expr->expr_simple_expr = tle_expr;
|
||||
expr->expr_simple_generation = cplan->generation;
|
||||
expr->expr_simple_state = NULL;
|
||||
expr->expr_simple_in_use = false;
|
||||
expr->expr_simple_lxid = InvalidLocalTransactionId;
|
||||
/* Also stash away the expression result type */
|
||||
expr->expr_simple_type = exprType((Node *) tle->expr);
|
||||
expr->expr_simple_typmod = exprTypmod((Node *) tle->expr);
|
||||
expr->expr_simple_type = exprType((Node *) tle_expr);
|
||||
expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user