@@ -145,6 +145,65 @@ replace_outer_var(PlannerInfo *root, Var *var)
145
145
return retval ;
146
146
}
147
147
148
+ /*
149
+ * Generate a Param node to replace the given PlaceHolderVar,
150
+ * which is expected to have phlevelsup > 0 (ie, it is not local).
151
+ *
152
+ * This is just like replace_outer_var, except for PlaceHolderVars.
153
+ */
154
+ static Param *
155
+ replace_outer_placeholdervar (PlannerInfo * root , PlaceHolderVar * phv )
156
+ {
157
+ Param * retval ;
158
+ ListCell * ppl ;
159
+ PlannerParamItem * pitem ;
160
+ Index abslevel ;
161
+ int i ;
162
+
163
+ Assert (phv -> phlevelsup > 0 && phv -> phlevelsup < root -> query_level );
164
+ abslevel = root -> query_level - phv -> phlevelsup ;
165
+
166
+ /* If there's already a paramlist entry for this same PHV, just use it */
167
+ i = 0 ;
168
+ foreach (ppl , root -> glob -> paramlist )
169
+ {
170
+ pitem = (PlannerParamItem * ) lfirst (ppl );
171
+ if (pitem -> abslevel == abslevel && IsA (pitem -> item , PlaceHolderVar ))
172
+ {
173
+ PlaceHolderVar * pphv = (PlaceHolderVar * ) pitem -> item ;
174
+
175
+ /* We assume comparing the PHIDs is sufficient */
176
+ if (pphv -> phid == phv -> phid )
177
+ break ;
178
+ }
179
+ i ++ ;
180
+ }
181
+
182
+ if (!ppl )
183
+ {
184
+ /* Nope, so make a new one */
185
+ phv = (PlaceHolderVar * ) copyObject (phv );
186
+ IncrementVarSublevelsUp ((Node * ) phv , - ((int ) phv -> phlevelsup ), 0 );
187
+ Assert (phv -> phlevelsup == 0 );
188
+
189
+ pitem = makeNode (PlannerParamItem );
190
+ pitem -> item = (Node * ) phv ;
191
+ pitem -> abslevel = abslevel ;
192
+
193
+ root -> glob -> paramlist = lappend (root -> glob -> paramlist , pitem );
194
+ /* i is already the correct index for the new item */
195
+ }
196
+
197
+ retval = makeNode (Param );
198
+ retval -> paramkind = PARAM_EXEC ;
199
+ retval -> paramid = i ;
200
+ retval -> paramtype = exprType ((Node * ) phv -> phexpr );
201
+ retval -> paramtypmod = exprTypmod ((Node * ) phv -> phexpr );
202
+ retval -> location = -1 ;
203
+
204
+ return retval ;
205
+ }
206
+
148
207
/*
149
208
* Generate a Param node to replace the given Aggref
150
209
* which is expected to have agglevelsup > 0 (ie, it is not local).
@@ -440,17 +499,19 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable,
440
499
Node * arg ;
441
500
442
501
/*
443
- * The Var or Aggref has already been adjusted to have the correct
444
- * varlevelsup or agglevelsup. We probably don't even need to
445
- * copy it again, but be safe.
502
+ * The Var, PlaceHolderVar, or Aggref has already been adjusted to
503
+ * have the correct varlevelsup, phlevelsup, or agglevelsup. We
504
+ * probably don't even need to copy it again, but be safe.
446
505
*/
447
506
arg = copyObject (pitem -> item );
448
507
449
508
/*
450
- * If it's an Aggref, its arguments might contain SubLinks, which
451
- * have not yet been processed. Do that now.
509
+ * If it's a PlaceHolderVar or Aggref, its arguments might contain
510
+ * SubLinks, which have not yet been processed (see the comments
511
+ * for SS_replace_correlation_vars). Do that now.
452
512
*/
453
- if (IsA (arg , Aggref ))
513
+ if (IsA (arg , PlaceHolderVar ) ||
514
+ IsA (arg , Aggref ))
454
515
arg = SS_process_sublinks (root , arg , false);
455
516
456
517
splan -> parParam = lappend_int (splan -> parParam , paramid );
@@ -1544,24 +1605,25 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
1544
1605
/*
1545
1606
* Replace correlation vars (uplevel vars) with Params.
1546
1607
*
1547
- * Uplevel aggregates are replaced, too.
1608
+ * Uplevel PlaceHolderVars and aggregates are replaced, too.
1548
1609
*
1549
1610
* Note: it is critical that this runs immediately after SS_process_sublinks.
1550
- * Since we do not recurse into the arguments of uplevel aggregates, they will
1551
- * get copied to the appropriate subplan args list in the parent query with
1552
- * uplevel vars not replaced by Params, but only adjusted in level (see
1553
- * replace_outer_agg). That's exactly what we want for the vars of the parent
1554
- * level --- but if an aggregate's argument contains any further-up variables,
1555
- * they have to be replaced with Params in their turn. That will happen when
1556
- * the parent level runs SS_replace_correlation_vars. Therefore it must do
1557
- * so after expanding its sublinks to subplans. And we don't want any steps
1558
- * in between, else those steps would never get applied to the aggregate
1559
- * argument expressions, either in the parent or the child level.
1611
+ * Since we do not recurse into the arguments of uplevel PHVs and aggregates,
1612
+ * they will get copied to the appropriate subplan args list in the parent
1613
+ * query with uplevel vars not replaced by Params, but only adjusted in level
1614
+ * (see replace_outer_placeholdervar and replace_outer_agg). That's exactly
1615
+ * what we want for the vars of the parent level --- but if a PHV's or
1616
+ * aggregate's argument contains any further-up variables, they have to be
1617
+ * replaced with Params in their turn. That will happen when the parent level
1618
+ * runs SS_replace_correlation_vars. Therefore it must do so after expanding
1619
+ * its sublinks to subplans. And we don't want any steps in between, else
1620
+ * those steps would never get applied to the argument expressions, either in
1621
+ * the parent or the child level.
1560
1622
*
1561
1623
* Another fairly tricky thing going on here is the handling of SubLinks in
1562
- * the arguments of uplevel aggregates. Those are not touched inside the
1563
- * intermediate query level, either. Instead, SS_process_sublinks recurses
1564
- * on them after copying the Aggref expression into the parent plan level
1624
+ * the arguments of uplevel PHVs/ aggregates. Those are not touched inside the
1625
+ * intermediate query level, either. Instead, SS_process_sublinks recurses on
1626
+ * them after copying the PHV or Aggref expression into the parent plan level
1565
1627
* (this is actually taken care of in build_subplan).
1566
1628
*/
1567
1629
Node *
@@ -1581,6 +1643,12 @@ replace_correlation_vars_mutator(Node *node, PlannerInfo *root)
1581
1643
if (((Var * ) node )-> varlevelsup > 0 )
1582
1644
return (Node * ) replace_outer_var (root , (Var * ) node );
1583
1645
}
1646
+ if (IsA (node , PlaceHolderVar ))
1647
+ {
1648
+ if (((PlaceHolderVar * ) node )-> phlevelsup > 0 )
1649
+ return (Node * ) replace_outer_placeholdervar (root ,
1650
+ (PlaceHolderVar * ) node );
1651
+ }
1584
1652
if (IsA (node , Aggref ))
1585
1653
{
1586
1654
if (((Aggref * ) node )-> agglevelsup > 0 )
@@ -1640,12 +1708,17 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
1640
1708
}
1641
1709
1642
1710
/*
1643
- * Don't recurse into the arguments of an outer aggregate here. Any
1644
- * SubLinks in the arguments have to be dealt with at the outer query
1645
- * level; they'll be handled when build_subplan collects the Aggref into
1646
- * the arguments to be passed down to the current subplan.
1711
+ * Don't recurse into the arguments of an outer PHV or aggregate here.
1712
+ * Any SubLinks in the arguments have to be dealt with at the outer query
1713
+ * level; they'll be handled when build_subplan collects the PHV or Aggref
1714
+ * into the arguments to be passed down to the current subplan.
1647
1715
*/
1648
- if (IsA (node , Aggref ))
1716
+ if (IsA (node , PlaceHolderVar ))
1717
+ {
1718
+ if (((PlaceHolderVar * ) node )-> phlevelsup > 0 )
1719
+ return node ;
1720
+ }
1721
+ else if (IsA (node , Aggref ))
1649
1722
{
1650
1723
if (((Aggref * ) node )-> agglevelsup > 0 )
1651
1724
return node ;
0 commit comments