Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f9094c4

Browse files
committed
Prevent generation of invalid plans for RIGHT or FULL joins with multiple
join clauses. The mergejoin executor wants all the join clauses to appear as merge quals, not as extra joinquals, for these kinds of joins. But the planner would consider plans in which partially-sorted input paths were used, leading to only some of the join clauses becoming merge quals. This is fine for inner/left joins, not fine for right/full joins.
1 parent 15a6cd0 commit f9094c4

File tree

1 file changed

+52
-8
lines changed

1 file changed

+52
-8
lines changed

src/backend/optimizer/path/joinpath.c

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.62 2001/03/22 03:59:35 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.63 2001/04/15 00:48:17 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -290,20 +290,34 @@ match_unsorted_outer(Query *root,
290290
JoinType jointype)
291291
{
292292
bool nestjoinOK;
293+
bool useallclauses;
293294
Path *bestinnerjoin;
294295
List *i;
295296

296297
/*
297-
* Nestloop only supports inner and left joins.
298+
* Nestloop only supports inner and left joins. Also, if we are doing
299+
* a right or full join, we must use *all* the mergeclauses as join
300+
* clauses, else we will not have a valid plan. (Although these two flags
301+
* are currently inverses, keep them separate for clarity and possible
302+
* future changes.)
298303
*/
299304
switch (jointype)
300305
{
301306
case JOIN_INNER:
302307
case JOIN_LEFT:
303308
nestjoinOK = true;
309+
useallclauses = false;
304310
break;
305-
default:
311+
case JOIN_RIGHT:
312+
case JOIN_FULL:
306313
nestjoinOK = false;
314+
useallclauses = true;
315+
break;
316+
default:
317+
elog(ERROR, "match_unsorted_outer: unexpected join type %d",
318+
(int) jointype);
319+
nestjoinOK = false; /* keep compiler quiet */
320+
useallclauses = false;
307321
break;
308322
}
309323

@@ -339,8 +353,8 @@ match_unsorted_outer(Query *root,
339353

340354
/*
341355
* Always consider a nestloop join with this outer and
342-
* cheapest- total-cost inner. Consider nestloops using the
343-
* cheapest- startup-cost inner as well, and the best
356+
* cheapest-total-cost inner. Consider nestloops using the
357+
* cheapest-startup-cost inner as well, and the best
344358
* innerjoin indexpath.
345359
*/
346360
add_path(joinrel, (Path *)
@@ -377,6 +391,8 @@ match_unsorted_outer(Query *root,
377391
/* Done with this outer path if no chance for a mergejoin */
378392
if (mergeclauses == NIL)
379393
continue;
394+
if (useallclauses && length(mergeclauses) != length(mergeclause_list))
395+
continue;
380396

381397
/* Compute the required ordering of the inner path */
382398
innersortkeys = make_pathkeys_for_mergeclauses(root,
@@ -402,13 +418,14 @@ match_unsorted_outer(Query *root,
402418

403419
/*
404420
* Look for presorted inner paths that satisfy the innersortkey
405-
* list or any truncation thereof. Here, we consider both cheap
406-
* startup cost and cheap total cost. Ignore
421+
* list --- or any truncation thereof, if we are allowed to build
422+
* a mergejoin using a subset of the merge clauses. Here, we
423+
* consider both cheap startup cost and cheap total cost. Ignore
407424
* innerrel->cheapest_total_path, since we already made a path
408425
* with it.
409426
*/
410427
num_sortkeys = length(innersortkeys);
411-
if (num_sortkeys > 1)
428+
if (num_sortkeys > 1 && !useallclauses)
412429
trialsortkeys = listCopy(innersortkeys); /* need modifiable copy */
413430
else
414431
trialsortkeys = innersortkeys; /* won't really truncate */
@@ -503,6 +520,11 @@ match_unsorted_outer(Query *root,
503520
}
504521
cheapest_startup_inner = innerpath;
505522
}
523+
/*
524+
* Don't consider truncated sortkeys if we need all clauses.
525+
*/
526+
if (useallclauses)
527+
break;
506528
}
507529
}
508530
}
@@ -532,8 +554,26 @@ match_unsorted_inner(Query *root,
532554
List *mergeclause_list,
533555
JoinType jointype)
534556
{
557+
bool useallclauses;
535558
List *i;
536559

560+
switch (jointype)
561+
{
562+
case JOIN_INNER:
563+
case JOIN_LEFT:
564+
useallclauses = false;
565+
break;
566+
case JOIN_RIGHT:
567+
case JOIN_FULL:
568+
useallclauses = true;
569+
break;
570+
default:
571+
elog(ERROR, "match_unsorted_inner: unexpected join type %d",
572+
(int) jointype);
573+
useallclauses = false; /* keep compiler quiet */
574+
break;
575+
}
576+
537577
foreach(i, innerrel->pathlist)
538578
{
539579
Path *innerpath = (Path *) lfirst(i);
@@ -547,8 +587,12 @@ match_unsorted_inner(Query *root,
547587
mergeclauses = find_mergeclauses_for_pathkeys(root,
548588
innerpath->pathkeys,
549589
mergeclause_list);
590+
591+
/* Done with this inner path if no chance for a mergejoin */
550592
if (mergeclauses == NIL)
551593
continue;
594+
if (useallclauses && length(mergeclauses) != length(mergeclause_list))
595+
continue;
552596

553597
/* Compute the required ordering of the outer path */
554598
outersortkeys = make_pathkeys_for_mergeclauses(root,

0 commit comments

Comments
 (0)