diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2015-12-11 14:22:20 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2015-12-11 14:22:20 -0500 |
commit | acfcd45cacb6df23edba4cb3753a2be594238a99 (patch) | |
tree | 0f7988231aca0d7bc43632a857dfc8868fc5c3f3 /src/include | |
parent | 69e7235c93e2965cc0e17186bd044e4c54997c19 (diff) |
Still more fixes for planner's handling of LATERAL references.
More fuzz testing by Andreas Seltenreich exposed that the planner did not
cope well with chains of lateral references. If relation X references Y
laterally, and Y references Z laterally, then we will have to scan X on the
inside of a nestloop with Z, so for all intents and purposes X is laterally
dependent on Z too. The planner did not understand this and would generate
intermediate joins that could not be used. While that was usually harmless
except for wasting some planning cycles, under the right circumstances it
would lead to "failed to build any N-way joins" or "could not devise a
query plan" planner failures.
To fix that, convert the existing per-relation lateral_relids and
lateral_referencers relid sets into their transitive closures; that is,
they now show all relations on which a rel is directly or indirectly
laterally dependent. This not only fixes the chained-reference problem
but allows some of the relevant tests to be made substantially simpler
and faster, since they can be reduced to simple bitmap manipulations
instead of searches of the LateralJoinInfo list.
Also, when a PlaceHolderVar that is due to be evaluated at a join contains
lateral references, we should treat those references as indirect lateral
dependencies of each of the join's base relations. This prevents us from
trying to join any individual base relations to the lateral reference
source before the join is formed, which again cannot work.
Andreas' testing also exposed another oversight in the "dangerous
PlaceHolderVar" test added in commit 85e5e222b1dd02f1. Simply rejecting
unsafe join paths in joinpath.c is insufficient, because in some cases
we will end up rejecting *all* possible paths for a particular join, again
leading to "could not devise a query plan" failures. The restriction has
to be known also to join_is_legal and its cohort functions, so that they
will not select a join for which that will happen. I chose to move the
supporting logic into joinrels.c where the latter functions are.
Back-patch to 9.3 where LATERAL support was introduced.
Diffstat (limited to 'src/include')
-rw-r--r-- | src/include/nodes/relation.h | 2 | ||||
-rw-r--r-- | src/include/optimizer/pathnode.h | 5 | ||||
-rw-r--r-- | src/include/optimizer/paths.h | 2 |
3 files changed, 8 insertions, 1 deletions
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 32321238ae4..f7796f8efbe 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -358,6 +358,7 @@ typedef struct PlannerInfo * cheapest_parameterized_paths - best paths for their parameterizations; * always includes cheapest_total_path, even if that's unparameterized * lateral_relids - required outer rels for LATERAL, as a Relids set + * (includes both direct and indirect lateral references) * * If the relation is a base relation it will have these fields set: * @@ -373,6 +374,7 @@ typedef struct PlannerInfo * lateral_vars - lateral cross-references of rel, if any (list of * Vars and PlaceHolderVars) * lateral_referencers - relids of rels that reference this one laterally + * (includes both direct and indirect lateral references) * indexlist - list of IndexOptInfo nodes for relation's indexes * (always NIL if it's not a table) * pages - number of disk pages in relation (zero if not a table) diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index f41847f4093..8fb9eda01b6 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -148,7 +148,10 @@ extern RelOptInfo *build_join_rel(PlannerInfo *root, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List **restrictlist_ptr); -extern Relids min_join_parameterization(PlannerInfo *root, Relids joinrelids); +extern Relids min_join_parameterization(PlannerInfo *root, + Relids joinrelids, + RelOptInfo *outer_rel, + RelOptInfo *inner_rel); extern RelOptInfo *build_empty_join_rel(PlannerInfo *root); extern AppendRelInfo *find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel); diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 87123a57295..7757741c104 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -98,6 +98,8 @@ extern RelOptInfo *make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2); extern bool have_join_order_restriction(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2); +extern bool have_dangerous_phv(PlannerInfo *root, + Relids outer_relids, Relids inner_params); /* * equivclass.c |