@@ -6553,7 +6553,7 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
6553
6553
{
6554
6554
PlannedStmt * stmt ;
6555
6555
Plan * plan ;
6556
- TargetEntry * tle ;
6556
+ Expr * tle_expr ;
6557
6557
6558
6558
/*
6559
6559
* 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)
6563
6563
/* Extract the single PlannedStmt */
6564
6564
Assert (list_length (cplan -> stmt_list ) == 1 );
6565
6565
stmt = linitial_node (PlannedStmt , cplan -> stmt_list );
6566
-
6567
- /* Should be a trivial Result plan */
6568
6566
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
+ */
6569
6576
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 ;
6576
6582
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
+ }
6580
6611
6581
6612
/*
6582
6613
* Save the simple expression, and initialize state to "not valid in
6583
6614
* current transaction".
6584
6615
*/
6585
- expr -> expr_simple_expr = tle -> expr ;
6616
+ expr -> expr_simple_expr = tle_expr ;
6586
6617
expr -> expr_simple_generation = cplan -> generation ;
6587
6618
expr -> expr_simple_state = NULL ;
6588
6619
expr -> expr_simple_in_use = false;
6589
6620
expr -> expr_simple_lxid = InvalidLocalTransactionId ;
6590
6621
/* 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 );
6593
6624
}
6594
6625
6595
6626
/*
0 commit comments