Skip to content

Commit b73f1b5

Browse files
committed
Make simpler-simple-expressions code cope with a Gather plan.
Commit 00418c6 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/[email protected]
1 parent 70b573b commit b73f1b5

File tree

1 file changed

+46
-15
lines changed

1 file changed

+46
-15
lines changed

src/pl/plpgsql/src/pl_exec.c

+46-15
Original file line numberDiff line numberDiff line change
@@ -6553,7 +6553,7 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
65536553
{
65546554
PlannedStmt *stmt;
65556555
Plan *plan;
6556-
TargetEntry *tle;
6556+
Expr *tle_expr;
65576557

65586558
/*
65596559
* 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)
65636563
/* Extract the single PlannedStmt */
65646564
Assert(list_length(cplan->stmt_list) == 1);
65656565
stmt = linitial_node(PlannedStmt, cplan->stmt_list);
6566-
6567-
/* Should be a trivial Result plan */
65686566
Assert(stmt->commandType == CMD_SELECT);
6567+
6568+
/*
6569+
* Ordinarily, the plan node should be a simple Result. However, if
6570+
* force_parallel_mode is on, the planner might've stuck a Gather node
6571+
* atop that. The simplest way to deal with this is to look through the
6572+
* Gather node. The Gather node's tlist would normally contain a Var
6573+
* referencing the child node's output ... but setrefs.c might also have
6574+
* copied a Const as-is.
6575+
*/
65696576
plan = stmt->planTree;
6570-
Assert(IsA(plan, Result));
6571-
Assert(plan->lefttree == NULL &&
6572-
plan->righttree == NULL &&
6573-
plan->initPlan == NULL &&
6574-
plan->qual == NULL &&
6575-
((Result *) plan)->resconstantqual == NULL);
6577+
for (;;)
6578+
{
6579+
/* Extract the single tlist expression */
6580+
Assert(list_length(plan->targetlist) == 1);
6581+
tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
65766582

6577-
/* Extract the single tlist expression */
6578-
Assert(list_length(plan->targetlist) == 1);
6579-
tle = (TargetEntry *) linitial(plan->targetlist);
6583+
if (IsA(plan, Result))
6584+
{
6585+
Assert(plan->lefttree == NULL &&
6586+
plan->righttree == NULL &&
6587+
plan->initPlan == NULL &&
6588+
plan->qual == NULL &&
6589+
((Result *) plan)->resconstantqual == NULL);
6590+
break;
6591+
}
6592+
else if (IsA(plan, Gather))
6593+
{
6594+
Assert(plan->lefttree != NULL &&
6595+
plan->righttree == NULL &&
6596+
plan->initPlan == NULL &&
6597+
plan->qual == NULL);
6598+
/* If setrefs.c copied up a Const, no need to look further */
6599+
if (IsA(tle_expr, Const))
6600+
break;
6601+
/* Otherwise, it better be an outer Var */
6602+
Assert(IsA(tle_expr, Var));
6603+
Assert(((Var *) tle_expr)->varno == OUTER_VAR);
6604+
/* Descend to the child node */
6605+
plan = plan->lefttree;
6606+
}
6607+
else
6608+
elog(ERROR, "unexpected plan node type: %d",
6609+
(int) nodeTag(plan));
6610+
}
65806611

65816612
/*
65826613
* Save the simple expression, and initialize state to "not valid in
65836614
* current transaction".
65846615
*/
6585-
expr->expr_simple_expr = tle->expr;
6616+
expr->expr_simple_expr = tle_expr;
65866617
expr->expr_simple_generation = cplan->generation;
65876618
expr->expr_simple_state = NULL;
65886619
expr->expr_simple_in_use = false;
65896620
expr->expr_simple_lxid = InvalidLocalTransactionId;
65906621
/* Also stash away the expression result type */
6591-
expr->expr_simple_type = exprType((Node *) tle->expr);
6592-
expr->expr_simple_typmod = exprTypmod((Node *) tle->expr);
6622+
expr->expr_simple_type = exprType((Node *) tle_expr);
6623+
expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
65936624
}
65946625

65956626
/*

0 commit comments

Comments
 (0)