@@ -268,8 +268,9 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
268
268
case RTE_CTE :
269
269
270
270
/*
271
- * CTEs don't support parameterized paths, so just go ahead
272
- * and build their paths immediately.
271
+ * CTEs don't support making a choice between parameterized
272
+ * and unparameterized paths, so just go ahead and build their
273
+ * paths immediately.
273
274
*/
274
275
if (rte -> self_reference )
275
276
set_worktable_pathlist (root , rel , rte );
@@ -376,8 +377,18 @@ set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
376
377
static void
377
378
set_plain_rel_pathlist (PlannerInfo * root , RelOptInfo * rel , RangeTblEntry * rte )
378
379
{
380
+ Relids required_outer ;
381
+
382
+ /*
383
+ * We don't support pushing join clauses into the quals of a seqscan, but
384
+ * it could still have required parameterization due to LATERAL refs in
385
+ * its tlist. (That can only happen if the seqscan is on a relation
386
+ * pulled up out of a UNION ALL appendrel.)
387
+ */
388
+ required_outer = rel -> lateral_relids ;
389
+
379
390
/* Consider sequential scan */
380
- add_path (rel , create_seqscan_path (root , rel , NULL ));
391
+ add_path (rel , create_seqscan_path (root , rel , required_outer ));
381
392
382
393
/* Consider index scans */
383
394
create_index_paths (root , rel );
@@ -536,10 +547,10 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
536
547
* CE failed, so finish copying/modifying targetlist and join quals.
537
548
*
538
549
* Note: the resulting childrel->reltargetlist may contain arbitrary
539
- * expressions, which normally would not occur in a reltargetlist.
540
- * That is okay because nothing outside of this routine will look at
541
- * the child rel's reltargetlist . We do have to cope with the case
542
- * while constructing attr_widths estimates below, though .
550
+ * expressions, which otherwise would not occur in a reltargetlist.
551
+ * Code that might be looking at an appendrel child must cope with
552
+ * such . Note in particular that "arbitrary expression" can include
553
+ * "Var belonging to another relation", due to LATERAL references .
543
554
*/
544
555
childrel -> joininfo = (List * )
545
556
adjust_appendrel_attrs (root ,
@@ -610,7 +621,8 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
610
621
int pndx = parentvar -> varattno - rel -> min_attr ;
611
622
int32 child_width = 0 ;
612
623
613
- if (IsA (childvar , Var ))
624
+ if (IsA (childvar , Var ) &&
625
+ ((Var * ) childvar )-> varno == childrel -> relid )
614
626
{
615
627
int cndx = ((Var * ) childvar )-> varattno - childrel -> min_attr ;
616
628
@@ -1054,17 +1066,10 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
1054
1066
1055
1067
/*
1056
1068
* If it's a LATERAL subquery, it might contain some Vars of the current
1057
- * query level, requiring it to be treated as parameterized.
1069
+ * query level, requiring it to be treated as parameterized, even though
1070
+ * we don't support pushing down join quals into subqueries.
1058
1071
*/
1059
- if (rte -> lateral )
1060
- {
1061
- required_outer = pull_varnos_of_level ((Node * ) subquery , 1 );
1062
- /* Enforce convention that empty required_outer is exactly NULL */
1063
- if (bms_is_empty (required_outer ))
1064
- required_outer = NULL ;
1065
- }
1066
- else
1067
- required_outer = NULL ;
1072
+ required_outer = rel -> lateral_relids ;
1068
1073
1069
1074
/* We need a workspace for keeping track of set-op type coercions */
1070
1075
differentTypes = (bool * )
@@ -1175,29 +1180,18 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
1175
1180
/*
1176
1181
* set_function_pathlist
1177
1182
* Build the (single) access path for a function RTE
1178
- *
1179
- * As with subqueries, a function RTE's path might be parameterized due to
1180
- * LATERAL references, but that's inherent in the function expression and
1181
- * not a result of pushing down join quals.
1182
1183
*/
1183
1184
static void
1184
1185
set_function_pathlist (PlannerInfo * root , RelOptInfo * rel , RangeTblEntry * rte )
1185
1186
{
1186
1187
Relids required_outer ;
1187
1188
1188
1189
/*
1189
- * If it's a LATERAL function, it might contain some Vars of the current
1190
- * query level, requiring it to be treated as parameterized.
1190
+ * We don't support pushing join clauses into the quals of a function
1191
+ * scan, but it could still have required parameterization due to LATERAL
1192
+ * refs in the function expression.
1191
1193
*/
1192
- if (rte -> lateral )
1193
- {
1194
- required_outer = pull_varnos_of_level (rte -> funcexpr , 0 );
1195
- /* Enforce convention that empty required_outer is exactly NULL */
1196
- if (bms_is_empty (required_outer ))
1197
- required_outer = NULL ;
1198
- }
1199
- else
1200
- required_outer = NULL ;
1194
+ required_outer = rel -> lateral_relids ;
1201
1195
1202
1196
/* Generate appropriate path */
1203
1197
add_path (rel , create_functionscan_path (root , rel , required_outer ));
@@ -1209,29 +1203,18 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1209
1203
/*
1210
1204
* set_values_pathlist
1211
1205
* Build the (single) access path for a VALUES RTE
1212
- *
1213
- * As with subqueries, a VALUES RTE's path might be parameterized due to
1214
- * LATERAL references, but that's inherent in the values expressions and
1215
- * not a result of pushing down join quals.
1216
1206
*/
1217
1207
static void
1218
1208
set_values_pathlist (PlannerInfo * root , RelOptInfo * rel , RangeTblEntry * rte )
1219
1209
{
1220
1210
Relids required_outer ;
1221
1211
1222
1212
/*
1223
- * If it's a LATERAL RTE, it might contain some Vars of the current query
1224
- * level, requiring it to be treated as parameterized.
1213
+ * We don't support pushing join clauses into the quals of a values scan,
1214
+ * but it could still have required parameterization due to LATERAL refs
1215
+ * in the values expressions.
1225
1216
*/
1226
- if (rte -> lateral )
1227
- {
1228
- required_outer = pull_varnos_of_level ((Node * ) rte -> values_lists , 0 );
1229
- /* Enforce convention that empty required_outer is exactly NULL */
1230
- if (bms_is_empty (required_outer ))
1231
- required_outer = NULL ;
1232
- }
1233
- else
1234
- required_outer = NULL ;
1217
+ required_outer = rel -> lateral_relids ;
1235
1218
1236
1219
/* Generate appropriate path */
1237
1220
add_path (rel , create_valuesscan_path (root , rel , required_outer ));
@@ -1245,7 +1228,7 @@ set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1245
1228
* Build the (single) access path for a non-self-reference CTE RTE
1246
1229
*
1247
1230
* There's no need for a separate set_cte_size phase, since we don't
1248
- * support parameterized paths for CTEs.
1231
+ * support join-qual- parameterized paths for CTEs.
1249
1232
*/
1250
1233
static void
1251
1234
set_cte_pathlist (PlannerInfo * root , RelOptInfo * rel , RangeTblEntry * rte )
@@ -1256,6 +1239,7 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1256
1239
int ndx ;
1257
1240
ListCell * lc ;
1258
1241
int plan_id ;
1242
+ Relids required_outer ;
1259
1243
1260
1244
/*
1261
1245
* Find the referenced CTE, and locate the plan previously made for it.
@@ -1294,8 +1278,16 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1294
1278
/* Mark rel with estimated output rows, width, etc */
1295
1279
set_cte_size_estimates (root , rel , cteplan );
1296
1280
1281
+ /*
1282
+ * We don't support pushing join clauses into the quals of a CTE scan, but
1283
+ * it could still have required parameterization due to LATERAL refs in
1284
+ * its tlist. (That can only happen if the CTE scan is on a relation
1285
+ * pulled up out of a UNION ALL appendrel.)
1286
+ */
1287
+ required_outer = rel -> lateral_relids ;
1288
+
1297
1289
/* Generate appropriate path */
1298
- add_path (rel , create_ctescan_path (root , rel ));
1290
+ add_path (rel , create_ctescan_path (root , rel , required_outer ));
1299
1291
1300
1292
/* Select cheapest path (pretty easy in this case...) */
1301
1293
set_cheapest (rel );
@@ -1306,14 +1298,15 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1306
1298
* Build the (single) access path for a self-reference CTE RTE
1307
1299
*
1308
1300
* There's no need for a separate set_worktable_size phase, since we don't
1309
- * support parameterized paths for CTEs.
1301
+ * support join-qual- parameterized paths for CTEs.
1310
1302
*/
1311
1303
static void
1312
1304
set_worktable_pathlist (PlannerInfo * root , RelOptInfo * rel , RangeTblEntry * rte )
1313
1305
{
1314
1306
Plan * cteplan ;
1315
1307
PlannerInfo * cteroot ;
1316
1308
Index levelsup ;
1309
+ Relids required_outer ;
1317
1310
1318
1311
/*
1319
1312
* We need to find the non-recursive term's plan, which is in the plan
@@ -1338,8 +1331,18 @@ set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1338
1331
/* Mark rel with estimated output rows, width, etc */
1339
1332
set_cte_size_estimates (root , rel , cteplan );
1340
1333
1334
+ /*
1335
+ * We don't support pushing join clauses into the quals of a worktable
1336
+ * scan, but it could still have required parameterization due to LATERAL
1337
+ * refs in its tlist. (That can only happen if the worktable scan is on a
1338
+ * relation pulled up out of a UNION ALL appendrel. I'm not sure this is
1339
+ * actually possible given the restrictions on recursive references, but
1340
+ * it's easy enough to support.)
1341
+ */
1342
+ required_outer = rel -> lateral_relids ;
1343
+
1341
1344
/* Generate appropriate path */
1342
- add_path (rel , create_worktablescan_path (root , rel ));
1345
+ add_path (rel , create_worktablescan_path (root , rel , required_outer ));
1343
1346
1344
1347
/* Select cheapest path (pretty easy in this case...) */
1345
1348
set_cheapest (rel );
0 commit comments