8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.108 2005/07/02 23:00:41 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.109 2005/09/28 21:17:02 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -38,7 +38,8 @@ static void mark_baserels_for_outer_join(PlannerInfo *root, Relids rels,
38
38
Relids outerrels );
39
39
static void distribute_qual_to_rels (PlannerInfo * root , Node * clause ,
40
40
bool is_pushed_down ,
41
- bool isdeduced ,
41
+ bool is_deduced ,
42
+ bool below_outer_join ,
42
43
Relids outerjoin_nonnullable ,
43
44
Relids qualscope );
44
45
static void add_vars_to_targetlist (PlannerInfo * root , List * vars ,
@@ -174,6 +175,10 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
174
175
* with outerjoinset information, to aid in proper positioning of qual
175
176
* clauses that appear above outer joins.
176
177
*
178
+ * jtnode is the jointree node currently being examined. below_outer_join
179
+ * is TRUE if this node is within the nullable side of a higher-level outer
180
+ * join.
181
+ *
177
182
* NOTE: when dealing with inner joins, it is appropriate to let a qual clause
178
183
* be evaluated at the lowest level where all the variables it mentions are
179
184
* available. However, we cannot push a qual down into the nullable side(s)
@@ -189,7 +194,8 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
189
194
* internal convenience; no outside callers pay attention to the result.
190
195
*/
191
196
Relids
192
- distribute_quals_to_rels (PlannerInfo * root , Node * jtnode )
197
+ distribute_quals_to_rels (PlannerInfo * root , Node * jtnode ,
198
+ bool below_outer_join )
193
199
{
194
200
Relids result = NULL ;
195
201
@@ -214,7 +220,8 @@ distribute_quals_to_rels(PlannerInfo *root, Node *jtnode)
214
220
{
215
221
result = bms_add_members (result ,
216
222
distribute_quals_to_rels (root ,
217
- lfirst (l )));
223
+ lfirst (l ),
224
+ below_outer_join ));
218
225
}
219
226
220
227
/*
@@ -223,7 +230,8 @@ distribute_quals_to_rels(PlannerInfo *root, Node *jtnode)
223
230
*/
224
231
foreach (l , (List * ) f -> quals )
225
232
distribute_qual_to_rels (root , (Node * ) lfirst (l ),
226
- true, false, NULL , result );
233
+ true, false, below_outer_join ,
234
+ NULL , result );
227
235
}
228
236
else if (IsA (jtnode , JoinExpr ))
229
237
{
@@ -247,27 +255,47 @@ distribute_quals_to_rels(PlannerInfo *root, Node *jtnode)
247
255
* rels from being pushed down below this level. (It's okay for
248
256
* upper quals to be pushed down to the outer side, however.)
249
257
*/
250
- leftids = distribute_quals_to_rels (root , j -> larg );
251
- rightids = distribute_quals_to_rels (root , j -> rarg );
252
-
253
- result = bms_union (leftids , rightids );
254
-
255
- nonnullable_rels = nullable_rels = NULL ;
256
258
switch (j -> jointype )
257
259
{
258
260
case JOIN_INNER :
261
+ leftids = distribute_quals_to_rels (root , j -> larg ,
262
+ below_outer_join );
263
+ rightids = distribute_quals_to_rels (root , j -> rarg ,
264
+ below_outer_join );
265
+
266
+ result = bms_union (leftids , rightids );
259
267
/* Inner join adds no restrictions for quals */
268
+ nonnullable_rels = NULL ;
269
+ nullable_rels = NULL ;
260
270
break ;
261
271
case JOIN_LEFT :
272
+ leftids = distribute_quals_to_rels (root , j -> larg ,
273
+ below_outer_join );
274
+ rightids = distribute_quals_to_rels (root , j -> rarg ,
275
+ true);
276
+
277
+ result = bms_union (leftids , rightids );
262
278
nonnullable_rels = leftids ;
263
279
nullable_rels = rightids ;
264
280
break ;
265
281
case JOIN_FULL :
282
+ leftids = distribute_quals_to_rels (root , j -> larg ,
283
+ true);
284
+ rightids = distribute_quals_to_rels (root , j -> rarg ,
285
+ true);
286
+
287
+ result = bms_union (leftids , rightids );
266
288
/* each side is both outer and inner */
267
289
nonnullable_rels = result ;
268
290
nullable_rels = result ;
269
291
break ;
270
292
case JOIN_RIGHT :
293
+ leftids = distribute_quals_to_rels (root , j -> larg ,
294
+ true);
295
+ rightids = distribute_quals_to_rels (root , j -> rarg ,
296
+ below_outer_join );
297
+
298
+ result = bms_union (leftids , rightids );
271
299
nonnullable_rels = rightids ;
272
300
nullable_rels = leftids ;
273
301
break ;
@@ -280,16 +308,20 @@ distribute_quals_to_rels(PlannerInfo *root, Node *jtnode)
280
308
ereport (ERROR ,
281
309
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
282
310
errmsg ("UNION JOIN is not implemented" )));
311
+ nonnullable_rels = NULL ; /* keep compiler quiet */
312
+ nullable_rels = NULL ;
283
313
break ;
284
314
default :
285
315
elog (ERROR , "unrecognized join type: %d" ,
286
316
(int ) j -> jointype );
317
+ nonnullable_rels = NULL ; /* keep compiler quiet */
318
+ nullable_rels = NULL ;
287
319
break ;
288
320
}
289
321
290
322
foreach (qual , (List * ) j -> quals )
291
323
distribute_qual_to_rels (root , (Node * ) lfirst (qual ),
292
- false, false,
324
+ false, false, below_outer_join ,
293
325
nonnullable_rels , result );
294
326
295
327
if (nullable_rels != NULL )
@@ -357,7 +389,9 @@ mark_baserels_for_outer_join(PlannerInfo *root, Relids rels, Relids outerrels)
357
389
* 'clause': the qual clause to be distributed
358
390
* 'is_pushed_down': if TRUE, force the clause to be marked 'is_pushed_down'
359
391
* (this indicates the clause came from a FromExpr, not a JoinExpr)
360
- * 'isdeduced': TRUE if the qual came from implied-equality deduction
392
+ * 'is_deduced': TRUE if the qual came from implied-equality deduction
393
+ * 'below_outer_join': TRUE if the qual is from a JOIN/ON that is below the
394
+ * nullable side of a higher-level outer join.
361
395
* 'outerjoin_nonnullable': NULL if not an outer-join qual, else the set of
362
396
* baserels appearing on the outer (nonnullable) side of the join
363
397
* 'qualscope': set of baserels the qual's syntactic scope covers
@@ -369,7 +403,8 @@ mark_baserels_for_outer_join(PlannerInfo *root, Relids rels, Relids outerrels)
369
403
static void
370
404
distribute_qual_to_rels (PlannerInfo * root , Node * clause ,
371
405
bool is_pushed_down ,
372
- bool isdeduced ,
406
+ bool is_deduced ,
407
+ bool below_outer_join ,
373
408
Relids outerjoin_nonnullable ,
374
409
Relids qualscope )
375
410
{
@@ -406,7 +441,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
406
441
* Check to see if clause application must be delayed by outer-join
407
442
* considerations.
408
443
*/
409
- if (isdeduced )
444
+ if (is_deduced )
410
445
{
411
446
/*
412
447
* If the qual came from implied-equality deduction, we always
@@ -432,14 +467,18 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
432
467
*
433
468
* Note: an outer-join qual that mentions only nullable-side rels can
434
469
* be pushed down into the nullable side without changing the join
435
- * result, so we treat it the same as an ordinary inner-join qual.
470
+ * result, so we treat it the same as an ordinary inner-join qual,
471
+ * except for not setting maybe_equijoin (see below).
436
472
*/
437
473
relids = qualscope ;
438
474
/*
439
475
* We can't use such a clause to deduce equijoin (the left and
440
476
* right sides might be unequal above the join because one of
441
477
* them has gone to NULL) ... but we might be able to use it
442
- * for more limited purposes.
478
+ * for more limited purposes. Note: for the current uses of
479
+ * deductions from an outer-join clause, it seems safe to make
480
+ * the deductions even when the clause is below a higher-level
481
+ * outer join; so we do not check below_outer_join here.
443
482
*/
444
483
maybe_equijoin = false;
445
484
maybe_outer_join = true;
@@ -473,8 +512,19 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
473
512
474
513
if (bms_is_subset (addrelids , relids ))
475
514
{
476
- /* Qual is not affected by any outer-join restriction */
477
- maybe_equijoin = true;
515
+ /*
516
+ * Qual is not delayed by any lower outer-join restriction.
517
+ * If it is not itself below or within an outer join, we
518
+ * can consider it "valid everywhere", so consider feeding
519
+ * it to the equijoin machinery. (If it is within an outer
520
+ * join, we can't consider it "valid everywhere": once the
521
+ * contained variables have gone to NULL, we'd be asserting
522
+ * things like NULL = NULL, which is not true.)
523
+ */
524
+ if (!below_outer_join && outerjoin_nonnullable == NULL )
525
+ maybe_equijoin = true;
526
+ else
527
+ maybe_equijoin = false;
478
528
}
479
529
else
480
530
{
@@ -543,7 +593,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
543
593
* redundancy will be detected when the join clause is moved
544
594
* into a join rel's restriction list.)
545
595
*/
546
- if (!isdeduced ||
596
+ if (!is_deduced ||
547
597
!qual_is_redundant (root , restrictinfo ,
548
598
rel -> baserestrictinfo ))
549
599
{
@@ -810,7 +860,7 @@ process_implied_equality(PlannerInfo *root,
810
860
* taken for an original JOIN/ON clause.
811
861
*/
812
862
distribute_qual_to_rels (root , (Node * ) clause ,
813
- true, true, NULL , relids );
863
+ true, true, false, NULL , relids );
814
864
}
815
865
816
866
/*
0 commit comments