@@ -274,6 +274,8 @@ build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
274
274
* have a single owning relation; we keep their attr_needed info in
275
275
* root->placeholder_list instead. Find or create the associated
276
276
* PlaceHolderInfo entry, and update its ph_needed.
277
+ *
278
+ * See also add_vars_to_attr_needed.
277
279
*/
278
280
void
279
281
add_vars_to_targetlist (PlannerInfo * root , List * vars ,
@@ -327,6 +329,63 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars,
327
329
}
328
330
}
329
331
332
+ /*
333
+ * add_vars_to_attr_needed
334
+ * This does a subset of what add_vars_to_targetlist does: it just
335
+ * updates attr_needed for Vars and ph_needed for PlaceHolderVars.
336
+ * We assume the Vars are already in their relations' targetlists.
337
+ *
338
+ * This is used to rebuild attr_needed/ph_needed sets after removal
339
+ * of a useless outer join. The removed join clause might have been
340
+ * the only upper-level use of some other relation's Var, in which
341
+ * case we can reduce that Var's attr_needed and thereby possibly
342
+ * open the door to further join removals. But we can't tell that
343
+ * without tedious reconstruction of the attr_needed data.
344
+ *
345
+ * Note that if a Var's attr_needed is successfully reduced to empty,
346
+ * it will still be in the relation's targetlist even though we do
347
+ * not really need the scan plan node to emit it. The extra plan
348
+ * inefficiency seems tiny enough to not be worth spending planner
349
+ * cycles to get rid of it.
350
+ */
351
+ void
352
+ add_vars_to_attr_needed (PlannerInfo * root , List * vars ,
353
+ Relids where_needed )
354
+ {
355
+ ListCell * temp ;
356
+
357
+ Assert (!bms_is_empty (where_needed ));
358
+
359
+ foreach (temp , vars )
360
+ {
361
+ Node * node = (Node * ) lfirst (temp );
362
+
363
+ if (IsA (node , Var ))
364
+ {
365
+ Var * var = (Var * ) node ;
366
+ RelOptInfo * rel = find_base_rel (root , var -> varno );
367
+ int attno = var -> varattno ;
368
+
369
+ if (bms_is_subset (where_needed , rel -> relids ))
370
+ continue ;
371
+ Assert (attno >= rel -> min_attr && attno <= rel -> max_attr );
372
+ attno -= rel -> min_attr ;
373
+ rel -> attr_needed [attno ] = bms_add_members (rel -> attr_needed [attno ],
374
+ where_needed );
375
+ }
376
+ else if (IsA (node , PlaceHolderVar ))
377
+ {
378
+ PlaceHolderVar * phv = (PlaceHolderVar * ) node ;
379
+ PlaceHolderInfo * phinfo = find_placeholder_info (root , phv );
380
+
381
+ phinfo -> ph_needed = bms_add_members (phinfo -> ph_needed ,
382
+ where_needed );
383
+ }
384
+ else
385
+ elog (ERROR , "unrecognized node type: %d" , (int ) nodeTag (node ));
386
+ }
387
+ }
388
+
330
389
331
390
/*****************************************************************************
332
391
*
@@ -488,10 +547,54 @@ extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
488
547
*/
489
548
add_vars_to_targetlist (root , newvars , where_needed );
490
549
491
- /* Remember the lateral references for create_lateral_join_info */
550
+ /*
551
+ * Remember the lateral references for rebuild_lateral_attr_needed and
552
+ * create_lateral_join_info.
553
+ */
492
554
brel -> lateral_vars = newvars ;
493
555
}
494
556
557
+ /*
558
+ * rebuild_lateral_attr_needed
559
+ * Put back attr_needed bits for Vars/PHVs needed for lateral references.
560
+ *
561
+ * This is used to rebuild attr_needed/ph_needed sets after removal of a
562
+ * useless outer join. It should match what find_lateral_references did,
563
+ * except that we call add_vars_to_attr_needed not add_vars_to_targetlist.
564
+ */
565
+ void
566
+ rebuild_lateral_attr_needed (PlannerInfo * root )
567
+ {
568
+ Index rti ;
569
+
570
+ /* We need do nothing if the query contains no LATERAL RTEs */
571
+ if (!root -> hasLateralRTEs )
572
+ return ;
573
+
574
+ /* Examine the same baserels that find_lateral_references did */
575
+ for (rti = 1 ; rti < root -> simple_rel_array_size ; rti ++ )
576
+ {
577
+ RelOptInfo * brel = root -> simple_rel_array [rti ];
578
+ Relids where_needed ;
579
+
580
+ if (brel == NULL )
581
+ continue ;
582
+ if (brel -> reloptkind != RELOPT_BASEREL )
583
+ continue ;
584
+
585
+ /*
586
+ * We don't need to repeat all of extract_lateral_references, since it
587
+ * kindly saved the extracted Vars/PHVs in lateral_vars.
588
+ */
589
+ if (brel -> lateral_vars == NIL )
590
+ continue ;
591
+
592
+ where_needed = bms_make_singleton (rti );
593
+
594
+ add_vars_to_attr_needed (root , brel -> lateral_vars , where_needed );
595
+ }
596
+ }
597
+
495
598
/*
496
599
* create_lateral_join_info
497
600
* Fill in the per-base-relation direct_lateral_relids, lateral_relids
@@ -2445,6 +2548,9 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
2445
2548
* var propagation is ensured by making ojscope include input rels from
2446
2549
* both sides of the join.
2447
2550
*
2551
+ * See also rebuild_joinclause_attr_needed, which has to partially repeat
2552
+ * this work after removal of an outer join.
2553
+ *
2448
2554
* Note: if the clause gets absorbed into an EquivalenceClass then this
2449
2555
* may be unnecessary, but for now we have to do it to cover the case
2450
2556
* where the EC becomes ec_broken and we end up reinserting the original
@@ -3014,6 +3120,11 @@ process_implied_equality(PlannerInfo *root,
3014
3120
* some of the Vars could have missed having that done because they only
3015
3121
* appeared in single-relation clauses originally. So do it here for
3016
3122
* safety.
3123
+ *
3124
+ * See also rebuild_joinclause_attr_needed, which has to partially repeat
3125
+ * this work after removal of an outer join. (Since we will put this
3126
+ * clause into the joininfo lists, that function needn't do any extra work
3127
+ * to find it.)
3017
3128
*/
3018
3129
if (bms_membership (relids ) == BMS_MULTIPLE )
3019
3130
{
@@ -3155,6 +3266,72 @@ get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids)
3155
3266
}
3156
3267
3157
3268
3269
+ /*
3270
+ * rebuild_joinclause_attr_needed
3271
+ * Put back attr_needed bits for Vars/PHVs needed for join clauses.
3272
+ *
3273
+ * This is used to rebuild attr_needed/ph_needed sets after removal of a
3274
+ * useless outer join. It should match what distribute_qual_to_rels did,
3275
+ * except that we call add_vars_to_attr_needed not add_vars_to_targetlist.
3276
+ */
3277
+ void
3278
+ rebuild_joinclause_attr_needed (PlannerInfo * root )
3279
+ {
3280
+ /*
3281
+ * We must examine all join clauses, but there's no value in processing
3282
+ * any join clause more than once. So it's slightly annoying that we have
3283
+ * to find them via the per-base-relation joininfo lists. Avoid duplicate
3284
+ * processing by tracking the rinfo_serial numbers of join clauses we've
3285
+ * already seen. (This doesn't work for is_clone clauses, so we must
3286
+ * waste effort on them.)
3287
+ */
3288
+ Bitmapset * seen_serials = NULL ;
3289
+ Index rti ;
3290
+
3291
+ /* Scan all baserels for join clauses */
3292
+ for (rti = 1 ; rti < root -> simple_rel_array_size ; rti ++ )
3293
+ {
3294
+ RelOptInfo * brel = root -> simple_rel_array [rti ];
3295
+ ListCell * lc ;
3296
+
3297
+ if (brel == NULL )
3298
+ continue ;
3299
+ if (brel -> reloptkind != RELOPT_BASEREL )
3300
+ continue ;
3301
+
3302
+ foreach (lc , brel -> joininfo )
3303
+ {
3304
+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
3305
+ Relids relids = rinfo -> required_relids ;
3306
+
3307
+ if (!rinfo -> is_clone ) /* else serial number is not unique */
3308
+ {
3309
+ if (bms_is_member (rinfo -> rinfo_serial , seen_serials ))
3310
+ continue ; /* saw it already */
3311
+ seen_serials = bms_add_member (seen_serials ,
3312
+ rinfo -> rinfo_serial );
3313
+ }
3314
+
3315
+ if (bms_membership (relids ) == BMS_MULTIPLE )
3316
+ {
3317
+ List * vars = pull_var_clause ((Node * ) rinfo -> clause ,
3318
+ PVC_RECURSE_AGGREGATES |
3319
+ PVC_RECURSE_WINDOWFUNCS |
3320
+ PVC_INCLUDE_PLACEHOLDERS );
3321
+ Relids where_needed ;
3322
+
3323
+ if (rinfo -> is_clone )
3324
+ where_needed = bms_intersect (relids , root -> all_baserels );
3325
+ else
3326
+ where_needed = relids ;
3327
+ add_vars_to_attr_needed (root , vars , where_needed );
3328
+ list_free (vars );
3329
+ }
3330
+ }
3331
+ }
3332
+ }
3333
+
3334
+
3158
3335
/*
3159
3336
* match_foreign_keys_to_quals
3160
3337
* Match foreign-key constraints to equivalence classes and join quals
0 commit comments