Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit719012e

Browse files
committed
Add some defenses against constant-FALSE outer join conditions. Since
eval_const_expressions will generally throw away anything that's ANDed withconstant FALSE, what we're left with given an example likeselect * from tenk1 a where (unique1,0) in (select unique2,1 from tenk1 b);is a cartesian product computation, which is really not acceptable.This is a regression in CVS HEAD compared to previous releases, which wereable to notice the impossible join condition in this case --- though not insome related cases that are also improved by this patch, such asselect * from tenk1 a left join tenk1 b on (a.unique1=b.unique2 and 0=1);Fix by skipping evaluation of the appropriate side of the outer join incases where it's demonstrably unnecessary.
1 parentf2689e4 commit719012e

File tree

1 file changed

+64
-15
lines changed

1 file changed

+64
-15
lines changed

‎src/backend/optimizer/path/joinrels.c

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.93 2008/08/14 18:47:59 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.94 2008/08/17 19:40:11 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -28,7 +28,8 @@ static List *make_rels_by_clauseless_joins(PlannerInfo *root,
2828
staticboolhas_join_restriction(PlannerInfo*root,RelOptInfo*rel);
2929
staticboolhas_legal_joinclause(PlannerInfo*root,RelOptInfo*rel);
3030
staticboolis_dummy_rel(RelOptInfo*rel);
31-
staticvoidmark_dummy_join(RelOptInfo*rel);
31+
staticvoidmark_dummy_rel(RelOptInfo*rel);
32+
staticboolrestriction_is_constant_false(List*restrictlist);
3233

3334

3435
/*
@@ -558,15 +559,20 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
558559
* this way since it's conceivable that dummy-ness of a multi-element
559560
* join might only be noticeable for certain construction paths.)
560561
*
562+
* Also, a provably constant-false join restriction typically means that
563+
* we can skip evaluating one or both sides of the join. We do this
564+
* by marking the appropriate rel as dummy.
565+
*
561566
* We need only consider the jointypes that appear in join_info_list,
562567
* plus JOIN_INNER.
563568
*/
564569
switch (sjinfo->jointype)
565570
{
566571
caseJOIN_INNER:
567-
if (is_dummy_rel(rel1)||is_dummy_rel(rel2))
572+
if (is_dummy_rel(rel1)||is_dummy_rel(rel2)||
573+
restriction_is_constant_false(restrictlist))
568574
{
569-
mark_dummy_join(joinrel);
575+
mark_dummy_rel(joinrel);
570576
break;
571577
}
572578
add_paths_to_joinrel(root,joinrel,rel1,rel2,
@@ -579,9 +585,12 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
579585
caseJOIN_LEFT:
580586
if (is_dummy_rel(rel1))
581587
{
582-
mark_dummy_join(joinrel);
588+
mark_dummy_rel(joinrel);
583589
break;
584590
}
591+
if (restriction_is_constant_false(restrictlist)&&
592+
bms_is_subset(rel2->relids,sjinfo->syn_righthand))
593+
mark_dummy_rel(rel2);
585594
add_paths_to_joinrel(root,joinrel,rel1,rel2,
586595
JOIN_LEFT,sjinfo,
587596
restrictlist);
@@ -592,7 +601,7 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
592601
caseJOIN_FULL:
593602
if (is_dummy_rel(rel1)&&is_dummy_rel(rel2))
594603
{
595-
mark_dummy_join(joinrel);
604+
mark_dummy_rel(joinrel);
596605
break;
597606
}
598607
add_paths_to_joinrel(root,joinrel,rel1,rel2,
@@ -603,9 +612,10 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
603612
restrictlist);
604613
break;
605614
caseJOIN_SEMI:
606-
if (is_dummy_rel(rel1)||is_dummy_rel(rel2))
615+
if (is_dummy_rel(rel1)||is_dummy_rel(rel2)||
616+
restriction_is_constant_false(restrictlist))
607617
{
608-
mark_dummy_join(joinrel);
618+
mark_dummy_rel(joinrel);
609619
break;
610620
}
611621
add_paths_to_joinrel(root,joinrel,rel1,rel2,
@@ -632,9 +642,12 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
632642
caseJOIN_ANTI:
633643
if (is_dummy_rel(rel1))
634644
{
635-
mark_dummy_join(joinrel);
645+
mark_dummy_rel(joinrel);
636646
break;
637647
}
648+
if (restriction_is_constant_false(restrictlist)&&
649+
bms_is_subset(rel2->relids,sjinfo->syn_righthand))
650+
mark_dummy_rel(rel2);
638651
add_paths_to_joinrel(root,joinrel,rel1,rel2,
639652
JOIN_ANTI,sjinfo,
640653
restrictlist);
@@ -851,10 +864,10 @@ is_dummy_rel(RelOptInfo *rel)
851864
}
852865

853866
/*
854-
* Mark ajoinrel as proven empty.
867+
* Mark arel as proven empty.
855868
*/
856869
staticvoid
857-
mark_dummy_join(RelOptInfo*rel)
870+
mark_dummy_rel(RelOptInfo*rel)
858871
{
859872
/* Set dummy size estimate */
860873
rel->rows=0;
@@ -865,10 +878,46 @@ mark_dummy_join(RelOptInfo *rel)
865878
/* Set up the dummy path */
866879
add_path(rel, (Path*)create_append_path(rel,NIL));
867880

881+
/* Set or update cheapest_total_path */
882+
set_cheapest(rel);
883+
}
884+
885+
886+
/*
887+
* restriction_is_constant_false --- is a restrictlist just FALSE?
888+
*
889+
* In cases where a qual is provably constant FALSE, eval_const_expressions
890+
* will generally have thrown away anything that's ANDed with it. In outer
891+
* join situations this will leave us computing cartesian products only to
892+
* decide there's no match for an outer row, which is pretty stupid. So,
893+
* we need to detect the case.
894+
*/
895+
staticbool
896+
restriction_is_constant_false(List*restrictlist)
897+
{
898+
ListCell*lc;
899+
868900
/*
869-
* Although set_cheapest will be done again later, we do it immediately
870-
* in order to keep is_dummy_rel as cheap as possible (ie, not have
871-
* to examine the pathlist).
901+
* Despite the above comment, the restriction list we see here might
902+
* possibly have other members besides the FALSE constant, since other
903+
* quals could get "pushed down" to the outer join level. So we check
904+
* each member of the list.
872905
*/
873-
set_cheapest(rel);
906+
foreach(lc,restrictlist)
907+
{
908+
RestrictInfo*rinfo= (RestrictInfo*)lfirst(lc);
909+
910+
Assert(IsA(rinfo,RestrictInfo));
911+
if (rinfo->clause&&IsA(rinfo->clause,Const))
912+
{
913+
Const*con= (Const*)rinfo->clause;
914+
915+
/* constant NULL is as good as constant FALSE for our purposes */
916+
if (con->constisnull)
917+
return true;
918+
if (!DatumGetBool(con->constvalue))
919+
return true;
920+
}
921+
}
922+
return false;
874923
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp