Commit e2fa76d8 authored by Tom Lane's avatar Tom Lane

Use parameterized paths to generate inner indexscans more flexibly.

This patch fixes the planner so that it can generate nestloop-with-
inner-indexscan plans even with one or more levels of joining between
the indexscan and the nestloop join that is supplying the parameter.
The executor was fixed to handle such cases some time ago, but the
planner was not ready.  This should improve our plans in many situations
where join ordering restrictions formerly forced complete table scans.

There is probably a fair amount of tuning work yet to be done, because
of various heuristics that have been added to limit the number of
parameterized paths considered.  However, we are not going to find out
what needs to be adjusted until the code gets some real-world use, so
it's time to get it in there where it can be tested easily.

Note API change for index AM amcostestimate functions.  I'm not aware of
any non-core index AMs, but if there are any, they will need minor
adjustments.
parent b376ec6f
...@@ -289,7 +289,7 @@ amcanreturn (Relation indexRelation); ...@@ -289,7 +289,7 @@ amcanreturn (Relation indexRelation);
void void
amcostestimate (PlannerInfo *root, amcostestimate (PlannerInfo *root,
IndexPath *path, IndexPath *path,
RelOptInfo *outer_rel, double loop_count,
Cost *indexStartupCost, Cost *indexStartupCost,
Cost *indexTotalCost, Cost *indexTotalCost,
Selectivity *indexSelectivity, Selectivity *indexSelectivity,
...@@ -928,7 +928,7 @@ amrestrpos (IndexScanDesc scan); ...@@ -928,7 +928,7 @@ amrestrpos (IndexScanDesc scan);
void void
amcostestimate (PlannerInfo *root, amcostestimate (PlannerInfo *root,
IndexPath *path, IndexPath *path,
RelOptInfo *outer_rel, double loop_count,
Cost *indexStartupCost, Cost *indexStartupCost,
Cost *indexTotalCost, Cost *indexTotalCost,
Selectivity *indexSelectivity, Selectivity *indexSelectivity,
...@@ -958,16 +958,15 @@ amcostestimate (PlannerInfo *root, ...@@ -958,16 +958,15 @@ amcostestimate (PlannerInfo *root,
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><parameter>outer_rel</></term> <term><parameter>loop_count</></term>
<listitem> <listitem>
<para> <para>
If the index is being considered for use in a join inner indexscan, The number of repetitions of the index scan that should be factored
the planner's information about the outer side of the join. Otherwise into the cost estimates. This will typically be greater than one when
<symbol>NULL</>. When non-<symbol>NULL</>, some of the qual clauses considering a parameterized scan for use in the inside of a nestloop
will be join clauses for joins join. Note that the cost estimates should still be for just one scan;
with this rel rather than being simple restriction clauses. Also, a larger <parameter>loop_count</> means that it may be appropriate
the cost estimator should expect that the index scan will be repeated to allow for some caching effects across multiple scans.
for each row of the outer rel.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1062,8 +1061,8 @@ amcostestimate (PlannerInfo *root, ...@@ -1062,8 +1061,8 @@ amcostestimate (PlannerInfo *root,
</para> </para>
<para> <para>
In the join case, the returned numbers should be averages expected for When <parameter>loop_count</> is greater than one, the returned numbers
any one scan of the index. should be averages expected for any one scan of the index.
</para> </para>
<procedure> <procedure>
...@@ -1121,7 +1120,7 @@ cost_qual_eval(&amp;index_qual_cost, path-&gt;indexquals, root); ...@@ -1121,7 +1120,7 @@ cost_qual_eval(&amp;index_qual_cost, path-&gt;indexquals, root);
</programlisting> </programlisting>
However, the above does not account for amortization of index reads However, the above does not account for amortization of index reads
across repeated index scans in the join case. across repeated index scans.
</para> </para>
</step> </step>
......
...@@ -335,6 +335,83 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b) ...@@ -335,6 +335,83 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b)
return true; return true;
} }
/*
* bms_subset_compare - compare A and B for equality/subset relationships
*
* This is more efficient than testing bms_is_subset in both directions.
*/
BMS_Comparison
bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
{
BMS_Comparison result;
int shortlen;
int longlen;
int i;
/* Handle cases where either input is NULL */
if (a == NULL)
{
if (b == NULL)
return BMS_EQUAL;
return bms_is_empty(b) ? BMS_EQUAL : BMS_SUBSET1;
}
if (b == NULL)
return bms_is_empty(a) ? BMS_EQUAL : BMS_SUBSET2;
/* Check common words */
result = BMS_EQUAL; /* status so far */
shortlen = Min(a->nwords, b->nwords);
for (i = 0; i < shortlen; i++)
{
bitmapword aword = a->words[i];
bitmapword bword = b->words[i];
if ((aword & ~bword) != 0)
{
/* a is not a subset of b */
if (result == BMS_SUBSET1)
return BMS_DIFFERENT;
result = BMS_SUBSET2;
}
if ((bword & ~aword) != 0)
{
/* b is not a subset of a */
if (result == BMS_SUBSET2)
return BMS_DIFFERENT;
result = BMS_SUBSET1;
}
}
/* Check extra words */
if (a->nwords > b->nwords)
{
longlen = a->nwords;
for (; i < longlen; i++)
{
if (a->words[i] != 0)
{
/* a is not a subset of b */
if (result == BMS_SUBSET1)
return BMS_DIFFERENT;
result = BMS_SUBSET2;
}
}
}
else if (a->nwords < b->nwords)
{
longlen = b->nwords;
for (; i < longlen; i++)
{
if (b->words[i] != 0)
{
/* b is not a subset of a */
if (result == BMS_SUBSET2)
return BMS_DIFFERENT;
result = BMS_SUBSET1;
}
}
}
return result;
}
/* /*
* bms_is_member - is X a member of A? * bms_is_member - is X a member of A?
*/ */
......
...@@ -1475,9 +1475,12 @@ _outPathInfo(StringInfo str, const Path *node) ...@@ -1475,9 +1475,12 @@ _outPathInfo(StringInfo str, const Path *node)
WRITE_ENUM_FIELD(pathtype, NodeTag); WRITE_ENUM_FIELD(pathtype, NodeTag);
appendStringInfo(str, " :parent_relids "); appendStringInfo(str, " :parent_relids ");
_outBitmapset(str, node->parent->relids); _outBitmapset(str, node->parent->relids);
WRITE_FLOAT_FIELD(rows, "%.0f");
WRITE_FLOAT_FIELD(startup_cost, "%.2f"); WRITE_FLOAT_FIELD(startup_cost, "%.2f");
WRITE_FLOAT_FIELD(total_cost, "%.2f"); WRITE_FLOAT_FIELD(total_cost, "%.2f");
WRITE_NODE_FIELD(pathkeys); WRITE_NODE_FIELD(pathkeys);
WRITE_BITMAPSET_FIELD(required_outer);
WRITE_NODE_FIELD(param_clauses);
} }
/* /*
...@@ -1515,11 +1518,9 @@ _outIndexPath(StringInfo str, const IndexPath *node) ...@@ -1515,11 +1518,9 @@ _outIndexPath(StringInfo str, const IndexPath *node)
WRITE_NODE_FIELD(indexqualcols); WRITE_NODE_FIELD(indexqualcols);
WRITE_NODE_FIELD(indexorderbys); WRITE_NODE_FIELD(indexorderbys);
WRITE_NODE_FIELD(indexorderbycols); WRITE_NODE_FIELD(indexorderbycols);
WRITE_BOOL_FIELD(isjoininner);
WRITE_ENUM_FIELD(indexscandir, ScanDirection); WRITE_ENUM_FIELD(indexscandir, ScanDirection);
WRITE_FLOAT_FIELD(indextotalcost, "%.2f"); WRITE_FLOAT_FIELD(indextotalcost, "%.2f");
WRITE_FLOAT_FIELD(indexselectivity, "%.4f"); WRITE_FLOAT_FIELD(indexselectivity, "%.4f");
WRITE_FLOAT_FIELD(rows, "%.0f");
} }
static void static void
...@@ -1530,8 +1531,6 @@ _outBitmapHeapPath(StringInfo str, const BitmapHeapPath *node) ...@@ -1530,8 +1531,6 @@ _outBitmapHeapPath(StringInfo str, const BitmapHeapPath *node)
_outPathInfo(str, (const Path *) node); _outPathInfo(str, (const Path *) node);
WRITE_NODE_FIELD(bitmapqual); WRITE_NODE_FIELD(bitmapqual);
WRITE_BOOL_FIELD(isjoininner);
WRITE_FLOAT_FIELD(rows, "%.0f");
} }
static void static void
...@@ -1628,7 +1627,6 @@ _outUniquePath(StringInfo str, const UniquePath *node) ...@@ -1628,7 +1627,6 @@ _outUniquePath(StringInfo str, const UniquePath *node)
WRITE_ENUM_FIELD(umethod, UniquePathMethod); WRITE_ENUM_FIELD(umethod, UniquePathMethod);
WRITE_NODE_FIELD(in_operators); WRITE_NODE_FIELD(in_operators);
WRITE_NODE_FIELD(uniq_exprs); WRITE_NODE_FIELD(uniq_exprs);
WRITE_FLOAT_FIELD(rows, "%.0f");
} }
static void static void
...@@ -1691,6 +1689,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node) ...@@ -1691,6 +1689,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
WRITE_NODE_FIELD(parse); WRITE_NODE_FIELD(parse);
WRITE_NODE_FIELD(glob); WRITE_NODE_FIELD(glob);
WRITE_UINT_FIELD(query_level); WRITE_UINT_FIELD(query_level);
WRITE_BITMAPSET_FIELD(all_baserels);
WRITE_NODE_FIELD(join_rel_list); WRITE_NODE_FIELD(join_rel_list);
WRITE_INT_FIELD(join_cur_level); WRITE_INT_FIELD(join_cur_level);
WRITE_NODE_FIELD(init_plans); WRITE_NODE_FIELD(init_plans);
...@@ -1738,6 +1737,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) ...@@ -1738,6 +1737,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
WRITE_NODE_FIELD(cheapest_startup_path); WRITE_NODE_FIELD(cheapest_startup_path);
WRITE_NODE_FIELD(cheapest_total_path); WRITE_NODE_FIELD(cheapest_total_path);
WRITE_NODE_FIELD(cheapest_unique_path); WRITE_NODE_FIELD(cheapest_unique_path);
WRITE_NODE_FIELD(cheapest_parameterized_paths);
WRITE_UINT_FIELD(relid); WRITE_UINT_FIELD(relid);
WRITE_UINT_FIELD(reltablespace); WRITE_UINT_FIELD(reltablespace);
WRITE_ENUM_FIELD(rtekind, RTEKind); WRITE_ENUM_FIELD(rtekind, RTEKind);
...@@ -1752,8 +1752,6 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) ...@@ -1752,8 +1752,6 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
WRITE_NODE_FIELD(baserestrictinfo); WRITE_NODE_FIELD(baserestrictinfo);
WRITE_NODE_FIELD(joininfo); WRITE_NODE_FIELD(joininfo);
WRITE_BOOL_FIELD(has_eclass_joins); WRITE_BOOL_FIELD(has_eclass_joins);
WRITE_BITMAPSET_FIELD(index_outer_relids);
WRITE_NODE_FIELD(index_inner_paths);
} }
static void static void
...@@ -1854,16 +1852,6 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node) ...@@ -1854,16 +1852,6 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node)
WRITE_OID_FIELD(hashjoinoperator); WRITE_OID_FIELD(hashjoinoperator);
} }
static void
_outInnerIndexscanInfo(StringInfo str, const InnerIndexscanInfo *node)
{
WRITE_NODE_TYPE("INNERINDEXSCANINFO");
WRITE_BITMAPSET_FIELD(other_relids);
WRITE_BOOL_FIELD(isouterjoin);
WRITE_NODE_FIELD(cheapest_startup_innerpath);
WRITE_NODE_FIELD(cheapest_total_innerpath);
}
static void static void
_outPlaceHolderVar(StringInfo str, const PlaceHolderVar *node) _outPlaceHolderVar(StringInfo str, const PlaceHolderVar *node)
{ {
...@@ -3015,9 +3003,6 @@ _outNode(StringInfo str, const void *obj) ...@@ -3015,9 +3003,6 @@ _outNode(StringInfo str, const void *obj)
case T_RestrictInfo: case T_RestrictInfo:
_outRestrictInfo(str, obj); _outRestrictInfo(str, obj);
break; break;
case T_InnerIndexscanInfo:
_outInnerIndexscanInfo(str, obj);
break;
case T_PlaceHolderVar: case T_PlaceHolderVar:
_outPlaceHolderVar(str, obj); _outPlaceHolderVar(str, obj);
break; break;
......
...@@ -78,10 +78,10 @@ ways. All the Paths made for a given relation are placed in its ...@@ -78,10 +78,10 @@ ways. All the Paths made for a given relation are placed in its
RelOptInfo.pathlist. (Actually, we discard Paths that are obviously RelOptInfo.pathlist. (Actually, we discard Paths that are obviously
inferior alternatives before they ever get into the pathlist --- what inferior alternatives before they ever get into the pathlist --- what
ends up in the pathlist is the cheapest way of generating each potentially ends up in the pathlist is the cheapest way of generating each potentially
useful sort ordering of the relation.) Also create a RelOptInfo.joininfo useful sort ordering and parameterization of the relation.) Also create a
list including all the join clauses that involve this relation. For RelOptInfo.joininfo list including all the join clauses that involve this
example, the WHERE clause "tab1.col1 = tab2.col1" generates entries in relation. For example, the WHERE clause "tab1.col1 = tab2.col1" generates
both tab1 and tab2's joininfo lists. entries in both tab1 and tab2's joininfo lists.
If we have only a single base relation in the query, we are done. If we have only a single base relation in the query, we are done.
Otherwise we have to figure out how to join the base relations into a Otherwise we have to figure out how to join the base relations into a
...@@ -173,12 +173,12 @@ for it or the cheapest path with the desired ordering (if that's cheaper ...@@ -173,12 +173,12 @@ for it or the cheapest path with the desired ordering (if that's cheaper
than applying a sort to the cheapest other path). than applying a sort to the cheapest other path).
If the query contains one-sided outer joins (LEFT or RIGHT joins), or If the query contains one-sided outer joins (LEFT or RIGHT joins), or
IN or EXISTS WHERE clauses that were converted to joins, then some of IN or EXISTS WHERE clauses that were converted to semijoins or antijoins,
the possible join orders may be illegal. These are excluded by having then some of the possible join orders may be illegal. These are excluded
join_is_legal consult a side list of such "special" joins to see by having join_is_legal consult a side list of such "special" joins to see
whether a proposed join is illegal. (The same consultation allows it whether a proposed join is illegal. (The same consultation allows it to
to see which join style should be applied for a valid join, ie, see which join style should be applied for a valid join, ie, JOIN_INNER,
JOIN_INNER, JOIN_LEFT, etc.) JOIN_LEFT, etc.)
Valid OUTER JOIN Optimizations Valid OUTER JOIN Optimizations
...@@ -526,12 +526,11 @@ multi-column index generates a list with one element per index column. ...@@ -526,12 +526,11 @@ multi-column index generates a list with one element per index column.
are two possible sort orders and two possible PathKey lists it can are two possible sort orders and two possible PathKey lists it can
generate.) generate.)
Note that a bitmap scan or multi-pass indexscan (OR clause scan) has NIL Note that a bitmap scan has NIL pathkeys since we can say nothing about
pathkeys since we can say nothing about the overall order of its result. the overall order of its result. Also, an indexscan on an unordered type
Also, an indexscan on an unordered type of index generates NIL pathkeys. of index generates NIL pathkeys. However, we can always create a pathkey
However, we can always create a pathkey by doing an explicit sort. The by doing an explicit sort. The pathkeys for a Sort plan's output just
pathkeys for a Sort plan's output just represent the sort key fields and represent the sort key fields and the ordering operators used.
the ordering operators used.
Things get more interesting when we consider joins. Suppose we do a Things get more interesting when we consider joins. Suppose we do a
mergejoin between A and B using the mergeclause A.X = B.Y. The output mergejoin between A and B using the mergeclause A.X = B.Y. The output
...@@ -668,4 +667,102 @@ Currently this happens only for queries involving multiple window functions ...@@ -668,4 +667,102 @@ Currently this happens only for queries involving multiple window functions
with different orderings, for which extra sorts are needed anyway. with different orderings, for which extra sorts are needed anyway.
Parameterized Paths
-------------------
The naive way to join two relations using a clause like WHERE A.X = B.Y
is to generate a nestloop plan like this:
NestLoop
Filter: A.X = B.Y
-> Seq Scan on A
-> Seq Scan on B
We can make this better by using a merge or hash join, but it still
requires scanning all of both input relations. If A is very small and B is
very large, but there is an index on B.Y, it can be enormously better to do
something like this:
NestLoop
-> Seq Scan on A
-> Index Scan using B_Y_IDX on B
Index Condition: B.Y = A.X
Here, we are expecting that for each row scanned from A, the nestloop
plan node will pass down the current value of A.X into the scan of B.
That allows the indexscan to treat A.X as a constant for any one
invocation, and thereby use it as an index key. This is the only plan type
that can avoid fetching all of B, and for small numbers of rows coming from
A, that will dominate every other consideration. (As A gets larger, this
gets less attractive, and eventually a merge or hash join will win instead.
So we have to cost out all the alternatives to decide what to do.)
It can be useful for the parameter value to be passed down through
intermediate layers of joins, for example:
NestLoop
-> Seq Scan on A
Hash Join
Join Condition: B.Y = C.W
-> Seq Scan on B
-> Index Scan using C_Z_IDX on C
Index Condition: C.Z = A.X
If all joins are plain inner joins then this is unnecessary, because
it's always possible to reorder the joins so that a parameter is used
immediately below the nestloop node that provides it. But in the
presence of outer joins, join reordering may not be possible, and then
this option can be critical. Before version 9.2, Postgres used ad-hoc
methods for planning and executing such queries, and those methods could
not handle passing parameters down through multiple join levels.
To plan such queries, we now use a notion of a "parameterized path",
which is a path that makes use of a join clause to a relation that's not
scanned by the path. In the example just above, we would construct a
path representing the possibility of doing this:
-> Index Scan using C_Z_IDX on C
Index Condition: C.Z = A.X
This path will be marked as being parameterized by relation A. (Note that
this is only one of the possible access paths for C; we'd still have a
plain unparameterized seqscan, and perhaps other possibilities.) The
parameterization marker does not prevent joining the path to B, so one of
the paths generated for the joinrel {B C} will represent
Hash Join
Join Condition: B.Y = C.W
-> Seq Scan on B
-> Index Scan using C_Z_IDX on C
Index Condition: C.Z = A.X
This path is still marked as being parameterized by A. When we attempt to
join {B C} to A to form the complete join tree, such a path can only be
used as the inner side of a nestloop join: it will be ignored for other
possible join types. So we will form a join path representing the query
plan shown above, and it will compete in the usual way with paths built
from non-parameterized scans.
To limit planning time, we have to avoid generating an unreasonably large
number of parameterized paths. We do this by only generating parameterized
relation scan paths for index scans, and then only for indexes for which
suitable join clauses are available. There are also heuristics in join
planning that try to limit the number of parameterized paths considered.
In particular, there's been a deliberate policy decision to favor hash
joins over merge joins for parameterized join steps (those occurring below
a nestloop that provides parameters to the lower join's inputs). While we
do not ignore merge joins entirely, joinpath.c does not fully explore the
space of potential merge joins with parameterized inputs. Also, add_path
treats parameterized paths as having no pathkeys, so that they compete
only on cost and don't get preference for producing a special sort order.
This creates additional bias against merge joins, since we might discard
a path that could have been useful for performing a merge without an
explicit sort step. Since a parameterized path must ultimately be used
on the inside of a nestloop, where its sort order is uninteresting, these
choices do not affect any requirement for the final output order of a
query --- they only make it harder to use a merge join at a lower level.
The savings in planning work justifies that.
-- bjm & tgl -- bjm & tgl
This diff is collapsed.
This diff is collapsed.
...@@ -59,6 +59,7 @@ static bool reconsider_outer_join_clause(PlannerInfo *root, ...@@ -59,6 +59,7 @@ static bool reconsider_outer_join_clause(PlannerInfo *root,
bool outer_on_left); bool outer_on_left);
static bool reconsider_full_join_clause(PlannerInfo *root, static bool reconsider_full_join_clause(PlannerInfo *root,
RestrictInfo *rinfo); RestrictInfo *rinfo);
static Index get_parent_relid(PlannerInfo *root, RelOptInfo *rel);
/* /*
...@@ -892,7 +893,7 @@ generate_base_implied_equalities_broken(PlannerInfo *root, ...@@ -892,7 +893,7 @@ generate_base_implied_equalities_broken(PlannerInfo *root,
* *
* The results are sufficient for use in merge, hash, and plain nestloop join * The results are sufficient for use in merge, hash, and plain nestloop join
* methods. We do not worry here about selecting clauses that are optimal * methods. We do not worry here about selecting clauses that are optimal
* for use in a nestloop-with-inner-indexscan join, however. indxpath.c makes * for use in a nestloop-with-parameterized-inner-scan. indxpath.c makes
* its own selections of clauses to use, and if the ones we pick here are * its own selections of clauses to use, and if the ones we pick here are
* redundant with those, the extras will be eliminated in createplan.c. * redundant with those, the extras will be eliminated in createplan.c.
* *
...@@ -1858,21 +1859,40 @@ mutate_eclass_expressions(PlannerInfo *root, ...@@ -1858,21 +1859,40 @@ mutate_eclass_expressions(PlannerInfo *root,
/* /*
* find_eclass_clauses_for_index_join * generate_implied_equalities_for_indexcol
* Create joinclauses usable for a nestloop-with-inner-indexscan * Create EC-derived joinclauses usable with a specific index column.
* scanning the given inner rel with the specified set of outer rels. *
* We assume that any given index column could appear in only one EC.
* (This should be true in all but the most pathological cases, and if it
* isn't, we stop on the first match anyway.) Therefore, what we return
* is a redundant list of clauses equating the index column to each of
* the other-relation values it is known to be equal to. Any one of
* these clauses can be used to create a parameterized indexscan, and there
* is no value in using more than one. (But it *is* worthwhile to create
* a separate parameterized path for each one, since that leads to different
* join orders.)
*/ */
List * List *
find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel, generate_implied_equalities_for_indexcol(PlannerInfo *root,
Relids outer_relids) IndexOptInfo *index,
int indexcol)
{ {
List *result = NIL; List *result = NIL;
RelOptInfo *rel = index->rel;
bool is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL); bool is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
Index parent_relid;
ListCell *lc1; ListCell *lc1;
/* If it's a child rel, we'll need to know what its parent is */
if (is_child_rel)
parent_relid = get_parent_relid(root, rel);
else
parent_relid = 0; /* not used, but keep compiler quiet */
foreach(lc1, root->eq_classes) foreach(lc1, root->eq_classes)
{ {
EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1); EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
EquivalenceMember *cur_em;
ListCell *lc2; ListCell *lc2;
/* /*
...@@ -1889,71 +1909,94 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel, ...@@ -1889,71 +1909,94 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel,
if (!is_child_rel && if (!is_child_rel &&
!bms_is_subset(rel->relids, cur_ec->ec_relids)) !bms_is_subset(rel->relids, cur_ec->ec_relids))
continue; continue;
/* ... nor if no overlap with outer_relids */
if (!bms_overlap(outer_relids, cur_ec->ec_relids))
continue;
/* Scan members, looking for indexable columns */ /* Scan members, looking for a match to the indexable column */
cur_em = NULL;
foreach(lc2, cur_ec->ec_members) foreach(lc2, cur_ec->ec_members)
{ {
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2); cur_em = (EquivalenceMember *) lfirst(lc2);
EquivalenceMember *best_outer_em = NULL; if (bms_equal(cur_em->em_relids, rel->relids) &&
Oid best_eq_op = InvalidOid; eclass_member_matches_indexcol(cur_ec, cur_em,
ListCell *lc3; index, indexcol))
break;
cur_em = NULL;
}
if (!bms_equal(cur_em->em_relids, rel->relids) || if (!cur_em)
!eclass_matches_any_index(cur_ec, cur_em, rel))
continue; continue;
/* /*
* Found one, so try to generate a join clause. This is like * Found our match. Scan the other EC members and attempt to generate
* generate_join_implied_equalities_normal, except simpler since * joinclauses.
* our only preference item is to pick a Var on the outer side. We
* only need one join clause per index col.
*/ */
foreach(lc3, cur_ec->ec_members) foreach(lc2, cur_ec->ec_members)
{ {
EquivalenceMember *outer_em = (EquivalenceMember *) lfirst(lc3); EquivalenceMember *other_em = (EquivalenceMember *) lfirst(lc2);
Oid eq_op; Oid eq_op;
RestrictInfo *rinfo;
/* Make sure it'll be a join to a different rel */
if (other_em == cur_em ||
bms_overlap(other_em->em_relids, rel->relids))
continue;
if (!bms_is_subset(outer_em->em_relids, outer_relids)) /*
* Also, if this is a child rel, avoid generating a useless join
* to its parent rel.
*/
if (is_child_rel &&
bms_is_member(parent_relid, other_em->em_relids))
continue; continue;
eq_op = select_equality_operator(cur_ec, eq_op = select_equality_operator(cur_ec,
cur_em->em_datatype, cur_em->em_datatype,
outer_em->em_datatype); other_em->em_datatype);
if (!OidIsValid(eq_op)) if (!OidIsValid(eq_op))
continue; continue;
best_outer_em = outer_em;
best_eq_op = eq_op;
if (IsA(outer_em->em_expr, Var) ||
(IsA(outer_em->em_expr, RelabelType) &&
IsA(((RelabelType *) outer_em->em_expr)->arg, Var)))
break; /* no need to look further */
}
if (best_outer_em)
{
/* Found a suitable joinclause */
RestrictInfo *rinfo;
/* set parent_ec to mark as redundant with other joinclauses */ /* set parent_ec to mark as redundant with other joinclauses */
rinfo = create_join_clause(root, cur_ec, best_eq_op, rinfo = create_join_clause(root, cur_ec, eq_op,
cur_em, best_outer_em, cur_em, other_em,
cur_ec); cur_ec);
result = lappend(result, rinfo); result = lappend(result, rinfo);
}
/* /*
* Note: we keep scanning here because we want to provide a * If somehow we failed to create any join clauses, we might as well
* clause for every possible indexcol. * keep scanning the ECs for another match. But if we did make any,
* we're done, because we don't want to return non-redundant clauses.
*/ */
} if (result)
} break;
} }
return result; return result;
} }
/*
* get_parent_relid
* Get the relid of a child rel's parent appendrel
*
* Possibly this should be somewhere else, but right now the logic is only
* needed here.
*/
static Index
get_parent_relid(PlannerInfo *root, RelOptInfo *rel)
{
ListCell *lc;
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
if (appinfo->child_relid == rel->relid)
return appinfo->parent_relid;
}
/* should have found the entry ... */
elog(ERROR, "child rel not found in append_rel_list");
return 0;
}
/* /*
* have_relevant_eclass_joinclause * have_relevant_eclass_joinclause
......
This diff is collapsed.
This diff is collapsed.
...@@ -935,14 +935,11 @@ has_legal_joinclause(PlannerInfo *root, RelOptInfo *rel) ...@@ -935,14 +935,11 @@ has_legal_joinclause(PlannerInfo *root, RelOptInfo *rel)
/* /*
* is_dummy_rel --- has relation been proven empty? * is_dummy_rel --- has relation been proven empty?
*
* If so, it will have a single path that is dummy.
*/ */
static bool static bool
is_dummy_rel(RelOptInfo *rel) is_dummy_rel(RelOptInfo *rel)
{ {
return (rel->cheapest_total_path != NULL && return IS_DUMMY_REL(rel);
IS_DUMMY_PATH(rel->cheapest_total_path));
} }
/* /*
...@@ -981,7 +978,7 @@ mark_dummy_rel(RelOptInfo *rel) ...@@ -981,7 +978,7 @@ mark_dummy_rel(RelOptInfo *rel)
/* Set up the dummy path */ /* Set up the dummy path */
add_path(rel, (Path *) create_append_path(rel, NIL)); add_path(rel, (Path *) create_append_path(rel, NIL));
/* Set or update cheapest_total_path */ /* Set or update cheapest_total_path and related fields */
set_cheapest(rel); set_cheapest(rel);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
......
...@@ -88,6 +88,10 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) ...@@ -88,6 +88,10 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
orig_selec; orig_selec;
ListCell *i; ListCell *i;
/* Skip the whole mess if no indexes */
if (rel->indexlist == NIL)
return false;
/* /*
* Find potentially interesting OR joinclauses. * Find potentially interesting OR joinclauses.
* *
...@@ -114,8 +118,8 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) ...@@ -114,8 +118,8 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
* Use the generate_bitmap_or_paths() machinery to estimate the * Use the generate_bitmap_or_paths() machinery to estimate the
* value of each OR clause. We can use regular restriction * value of each OR clause. We can use regular restriction
* clauses along with the OR clause contents to generate * clauses along with the OR clause contents to generate
* indexquals. We pass outer_rel = NULL so that sub-clauses that * indexquals. We pass restriction_only = true so that any
* are actually joins will be ignored. * sub-clauses that are actually joins will be ignored.
*/ */
List *orpaths; List *orpaths;
ListCell *k; ListCell *k;
...@@ -123,7 +127,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) ...@@ -123,7 +127,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
orpaths = generate_bitmap_or_paths(root, rel, orpaths = generate_bitmap_or_paths(root, rel,
list_make1(rinfo), list_make1(rinfo),
rel->baserestrictinfo, rel->baserestrictinfo,
NULL); true);
/* Locate the cheapest OR path */ /* Locate the cheapest OR path */
foreach(k, orpaths) foreach(k, orpaths)
......
...@@ -403,14 +403,17 @@ pathkeys_contained_in(List *keys1, List *keys2) ...@@ -403,14 +403,17 @@ pathkeys_contained_in(List *keys1, List *keys2)
/* /*
* get_cheapest_path_for_pathkeys * get_cheapest_path_for_pathkeys
* Find the cheapest path (according to the specified criterion) that * Find the cheapest path (according to the specified criterion) that
* satisfies the given pathkeys. Return NULL if no such path. * satisfies the given pathkeys and parameterization.
* Return NULL if no such path.
* *
* 'paths' is a list of possible paths that all generate the same relation * 'paths' is a list of possible paths that all generate the same relation
* 'pathkeys' represents a required ordering (already canonicalized!) * 'pathkeys' represents a required ordering (already canonicalized!)
* 'required_outer' denotes allowable outer relations for parameterized paths
* 'cost_criterion' is STARTUP_COST or TOTAL_COST * 'cost_criterion' is STARTUP_COST or TOTAL_COST
*/ */
Path * Path *
get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
Relids required_outer,
CostSelector cost_criterion) CostSelector cost_criterion)
{ {
Path *matched_path = NULL; Path *matched_path = NULL;
...@@ -428,7 +431,8 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, ...@@ -428,7 +431,8 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
compare_path_costs(matched_path, path, cost_criterion) <= 0) compare_path_costs(matched_path, path, cost_criterion) <= 0)
continue; continue;
if (pathkeys_contained_in(pathkeys, path->pathkeys)) if (pathkeys_contained_in(pathkeys, path->pathkeys) &&
bms_is_subset(path->required_outer, required_outer))
matched_path = path; matched_path = path;
} }
return matched_path; return matched_path;
...@@ -437,7 +441,7 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, ...@@ -437,7 +441,7 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
/* /*
* get_cheapest_fractional_path_for_pathkeys * get_cheapest_fractional_path_for_pathkeys
* Find the cheapest path (for retrieving a specified fraction of all * Find the cheapest path (for retrieving a specified fraction of all
* the tuples) that satisfies the given pathkeys. * the tuples) that satisfies the given pathkeys and parameterization.
* Return NULL if no such path. * Return NULL if no such path.
* *
* See compare_fractional_path_costs() for the interpretation of the fraction * See compare_fractional_path_costs() for the interpretation of the fraction
...@@ -445,11 +449,13 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, ...@@ -445,11 +449,13 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
* *
* 'paths' is a list of possible paths that all generate the same relation * 'paths' is a list of possible paths that all generate the same relation
* 'pathkeys' represents a required ordering (already canonicalized!) * 'pathkeys' represents a required ordering (already canonicalized!)
* 'required_outer' denotes allowable outer relations for parameterized paths
* 'fraction' is the fraction of the total tuples expected to be retrieved * 'fraction' is the fraction of the total tuples expected to be retrieved
*/ */
Path * Path *
get_cheapest_fractional_path_for_pathkeys(List *paths, get_cheapest_fractional_path_for_pathkeys(List *paths,
List *pathkeys, List *pathkeys,
Relids required_outer,
double fraction) double fraction)
{ {
Path *matched_path = NULL; Path *matched_path = NULL;
...@@ -461,13 +467,14 @@ get_cheapest_fractional_path_for_pathkeys(List *paths, ...@@ -461,13 +467,14 @@ get_cheapest_fractional_path_for_pathkeys(List *paths,
/* /*
* Since cost comparison is a lot cheaper than pathkey comparison, do * Since cost comparison is a lot cheaper than pathkey comparison, do
* that first. * that first. (XXX is that still true?)
*/ */
if (matched_path != NULL && if (matched_path != NULL &&
compare_fractional_path_costs(matched_path, path, fraction) <= 0) compare_fractional_path_costs(matched_path, path, fraction) <= 0)
continue; continue;
if (pathkeys_contained_in(pathkeys, path->pathkeys)) if (pathkeys_contained_in(pathkeys, path->pathkeys) &&
bms_is_subset(path->required_outer, required_outer))
matched_path = path; matched_path = path;
} }
return matched_path; return matched_path;
......
...@@ -932,7 +932,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path) ...@@ -932,7 +932,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
long numGroups; long numGroups;
Oid *groupOperators; Oid *groupOperators;
numGroups = (long) Min(best_path->rows, (double) LONG_MAX); numGroups = (long) Min(best_path->path.rows, (double) LONG_MAX);
/* /*
* Get the hashable equality operators for the Agg node to use. * Get the hashable equality operators for the Agg node to use.
...@@ -1018,7 +1018,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path) ...@@ -1018,7 +1018,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
} }
/* Adjust output size estimate (other fields should be OK already) */ /* Adjust output size estimate (other fields should be OK already) */
plan->plan_rows = best_path->rows; plan->plan_rows = best_path->path.rows;
return plan; return plan;
} }
...@@ -1112,7 +1112,7 @@ create_indexscan_plan(PlannerInfo *root, ...@@ -1112,7 +1112,7 @@ create_indexscan_plan(PlannerInfo *root,
fixed_indexorderbys = fix_indexorderby_references(root, best_path); fixed_indexorderbys = fix_indexorderby_references(root, best_path);
/* /*
* If this is an innerjoin scan, the indexclauses will contain join * If this is a parameterized scan, the indexclauses will contain join
* clauses that are not present in scan_clauses (since the passed-in value * clauses that are not present in scan_clauses (since the passed-in value
* is just the rel's baserestrictinfo list). We must add these clauses to * is just the rel's baserestrictinfo list). We must add these clauses to
* scan_clauses to ensure they get checked. In most cases we will remove * scan_clauses to ensure they get checked. In most cases we will remove
...@@ -1122,7 +1122,7 @@ create_indexscan_plan(PlannerInfo *root, ...@@ -1122,7 +1122,7 @@ create_indexscan_plan(PlannerInfo *root,
* Note: pointer comparison should be enough to determine RestrictInfo * Note: pointer comparison should be enough to determine RestrictInfo
* matches. * matches.
*/ */
if (best_path->isjoininner) if (best_path->path.required_outer)
scan_clauses = list_union_ptr(scan_clauses, best_path->indexclauses); scan_clauses = list_union_ptr(scan_clauses, best_path->indexclauses);
/* /*
...@@ -1189,7 +1189,7 @@ create_indexscan_plan(PlannerInfo *root, ...@@ -1189,7 +1189,7 @@ create_indexscan_plan(PlannerInfo *root,
* it'd break the comparisons to predicates above ... (or would it? Those * it'd break the comparisons to predicates above ... (or would it? Those
* wouldn't have outer refs) * wouldn't have outer refs)
*/ */
if (best_path->isjoininner) if (best_path->path.required_outer)
{ {
stripped_indexquals = (List *) stripped_indexquals = (List *)
replace_nestloop_params(root, (Node *) stripped_indexquals); replace_nestloop_params(root, (Node *) stripped_indexquals);
...@@ -1221,8 +1221,6 @@ create_indexscan_plan(PlannerInfo *root, ...@@ -1221,8 +1221,6 @@ create_indexscan_plan(PlannerInfo *root,
best_path->indexscandir); best_path->indexscandir);
copy_path_costsize(&scan_plan->plan, &best_path->path); copy_path_costsize(&scan_plan->plan, &best_path->path);
/* use the indexscan-specific rows estimate, not the parent rel's */
scan_plan->plan.plan_rows = best_path->rows;
return scan_plan; return scan_plan;
} }
...@@ -1258,14 +1256,14 @@ create_bitmap_scan_plan(PlannerInfo *root, ...@@ -1258,14 +1256,14 @@ create_bitmap_scan_plan(PlannerInfo *root,
scan_clauses = extract_actual_clauses(scan_clauses, false); scan_clauses = extract_actual_clauses(scan_clauses, false);
/* /*
* If this is a innerjoin scan, the indexclauses will contain join clauses * If this is a parameterized scan, the indexclauses will contain join clauses
* that are not present in scan_clauses (since the passed-in value is just * that are not present in scan_clauses (since the passed-in value is just
* the rel's baserestrictinfo list). We must add these clauses to * the rel's baserestrictinfo list). We must add these clauses to
* scan_clauses to ensure they get checked. In most cases we will remove * scan_clauses to ensure they get checked. In most cases we will remove
* the join clauses again below, but if a join clause contains a special * the join clauses again below, but if a join clause contains a special
* operator, we need to make sure it gets into the scan_clauses. * operator, we need to make sure it gets into the scan_clauses.
*/ */
if (best_path->isjoininner) if (best_path->path.required_outer)
{ {
scan_clauses = list_concat_unique(scan_clauses, bitmapqualorig); scan_clauses = list_concat_unique(scan_clauses, bitmapqualorig);
} }
...@@ -1328,8 +1326,6 @@ create_bitmap_scan_plan(PlannerInfo *root, ...@@ -1328,8 +1326,6 @@ create_bitmap_scan_plan(PlannerInfo *root,
baserelid); baserelid);
copy_path_costsize(&scan_plan->scan.plan, &best_path->path); copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
/* use the indexscan-specific rows estimate, not the parent rel's */
scan_plan->scan.plan.plan_rows = best_path->rows;
return scan_plan; return scan_plan;
} }
...@@ -1510,7 +1506,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, ...@@ -1510,7 +1506,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
* Replace outer-relation variables with nestloop params, but only * Replace outer-relation variables with nestloop params, but only
* after doing the above comparisons to index predicates. * after doing the above comparisons to index predicates.
*/ */
if (ipath->isjoininner) if (ipath->path.required_outer)
{ {
*qual = (List *) *qual = (List *)
replace_nestloop_params(root, (Node *) *qual); replace_nestloop_params(root, (Node *) *qual);
...@@ -1883,14 +1879,13 @@ create_nestloop_plan(PlannerInfo *root, ...@@ -1883,14 +1879,13 @@ create_nestloop_plan(PlannerInfo *root,
ListCell *next; ListCell *next;
/* /*
* If the inner path is a nestloop inner indexscan, it might be using some * If the inner path is parameterized, it might have already used some of
* of the join quals as index quals, in which case we don't have to check * the join quals, in which case we don't have to check them again at the
* them again at the join node. Remove any join quals that are redundant. * join node. Remove any join quals that are redundant.
*/ */
joinrestrictclauses = joinrestrictclauses =
select_nonredundant_join_clauses(root, select_nonredundant_join_clauses(joinrestrictclauses,
joinrestrictclauses, best_path->innerjoinpath->param_clauses);
best_path->innerjoinpath);
/* Sort join qual clauses into best execution order */ /* Sort join qual clauses into best execution order */
joinrestrictclauses = order_qual_clauses(root, joinrestrictclauses); joinrestrictclauses = order_qual_clauses(root, joinrestrictclauses);
...@@ -2054,7 +2049,7 @@ create_mergejoin_plan(PlannerInfo *root, ...@@ -2054,7 +2049,7 @@ create_mergejoin_plan(PlannerInfo *root,
/* /*
* We assume the materialize will not spill to disk, and therefore * We assume the materialize will not spill to disk, and therefore
* charge just cpu_operator_cost per tuple. (Keep this estimate in * charge just cpu_operator_cost per tuple. (Keep this estimate in
* sync with cost_mergejoin.) * sync with final_cost_mergejoin.)
*/ */
copy_plan_costsize(matplan, inner_plan); copy_plan_costsize(matplan, inner_plan);
matplan->total_cost += cpu_operator_cost * matplan->plan_rows; matplan->total_cost += cpu_operator_cost * matplan->plan_rows;
...@@ -2885,7 +2880,7 @@ copy_path_costsize(Plan *dest, Path *src) ...@@ -2885,7 +2880,7 @@ copy_path_costsize(Plan *dest, Path *src)
{ {
dest->startup_cost = src->startup_cost; dest->startup_cost = src->startup_cost;
dest->total_cost = src->total_cost; dest->total_cost = src->total_cost;
dest->plan_rows = src->parent->rows; dest->plan_rows = src->rows;
dest->plan_width = src->parent->width; dest->plan_width = src->parent->width;
} }
else else
......
...@@ -375,6 +375,7 @@ query_planner(PlannerInfo *root, List *tlist, ...@@ -375,6 +375,7 @@ query_planner(PlannerInfo *root, List *tlist,
sortedpath = sortedpath =
get_cheapest_fractional_path_for_pathkeys(final_rel->pathlist, get_cheapest_fractional_path_for_pathkeys(final_rel->pathlist,
root->query_pathkeys, root->query_pathkeys,
NULL,
tuple_fraction); tuple_fraction);
/* Don't return same path in both guises; just wastes effort */ /* Don't return same path in both guises; just wastes effort */
......
...@@ -3297,7 +3297,8 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) ...@@ -3297,7 +3297,8 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
/* Estimate the cost of index scan */ /* Estimate the cost of index scan */
indexScanPath = create_index_path(root, indexInfo, indexScanPath = create_index_path(root, indexInfo,
NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
ForwardScanDirection, false, NULL); ForwardScanDirection, false,
NULL, 1.0);
return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost); return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
} }
This diff is collapsed.
...@@ -103,6 +103,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) ...@@ -103,6 +103,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->cheapest_startup_path = NULL; rel->cheapest_startup_path = NULL;
rel->cheapest_total_path = NULL; rel->cheapest_total_path = NULL;
rel->cheapest_unique_path = NULL; rel->cheapest_unique_path = NULL;
rel->cheapest_parameterized_paths = NIL;
rel->relid = relid; rel->relid = relid;
rel->rtekind = rte->rtekind; rel->rtekind = rte->rtekind;
/* min_attr, max_attr, attr_needed, attr_widths are set below */ /* min_attr, max_attr, attr_needed, attr_widths are set below */
...@@ -117,8 +118,6 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) ...@@ -117,8 +118,6 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rel->baserestrictcost.per_tuple = 0; rel->baserestrictcost.per_tuple = 0;
rel->joininfo = NIL; rel->joininfo = NIL;
rel->has_eclass_joins = false; rel->has_eclass_joins = false;
rel->index_outer_relids = NULL;
rel->index_inner_paths = NIL;
/* Check type of rtable entry */ /* Check type of rtable entry */
switch (rte->rtekind) switch (rte->rtekind)
...@@ -354,6 +353,7 @@ build_join_rel(PlannerInfo *root, ...@@ -354,6 +353,7 @@ build_join_rel(PlannerInfo *root,
joinrel->cheapest_startup_path = NULL; joinrel->cheapest_startup_path = NULL;
joinrel->cheapest_total_path = NULL; joinrel->cheapest_total_path = NULL;
joinrel->cheapest_unique_path = NULL; joinrel->cheapest_unique_path = NULL;
joinrel->cheapest_parameterized_paths = NIL;
joinrel->relid = 0; /* indicates not a baserel */ joinrel->relid = 0; /* indicates not a baserel */
joinrel->rtekind = RTE_JOIN; joinrel->rtekind = RTE_JOIN;
joinrel->min_attr = 0; joinrel->min_attr = 0;
...@@ -371,8 +371,6 @@ build_join_rel(PlannerInfo *root, ...@@ -371,8 +371,6 @@ build_join_rel(PlannerInfo *root,
joinrel->baserestrictcost.per_tuple = 0; joinrel->baserestrictcost.per_tuple = 0;
joinrel->joininfo = NIL; joinrel->joininfo = NIL;
joinrel->has_eclass_joins = false; joinrel->has_eclass_joins = false;
joinrel->index_outer_relids = NULL;
joinrel->index_inner_paths = NIL;
/* /*
* Create a new tlist containing just the vars that need to be output from * Create a new tlist containing just the vars that need to be output from
......
...@@ -33,8 +33,6 @@ static Expr *make_sub_restrictinfos(Expr *clause, ...@@ -33,8 +33,6 @@ static Expr *make_sub_restrictinfos(Expr *clause,
bool pseudoconstant, bool pseudoconstant,
Relids required_relids, Relids required_relids,
Relids nullable_relids); Relids nullable_relids);
static List *select_nonredundant_join_list(List *restrictinfo_list,
List *reference_list);
static bool join_clause_is_redundant(RestrictInfo *rinfo, static bool join_clause_is_redundant(RestrictInfo *rinfo,
List *reference_list); List *reference_list);
...@@ -623,11 +621,14 @@ extract_actual_join_clauses(List *restrictinfo_list, ...@@ -623,11 +621,14 @@ extract_actual_join_clauses(List *restrictinfo_list,
/* /*
* select_nonredundant_join_clauses * select_nonredundant_join_clauses
* Select the members of restrictinfo_list that are not redundant with
* any member of reference_list.
* *
* Given a list of RestrictInfo clauses that are to be applied in a join, * Given a list of RestrictInfo clauses that are to be applied in a join,
* select the ones that are not redundant with any clause that's enforced * select the ones that are not redundant with any clause that's listed in
* by the inner_path. This is used for nestloop joins, wherein any clause * reference_list. This is used, for example, to avoid checking joinclauses
* being used in an inner indexscan need not be checked again at the join. * again at a nestloop join when they've already been enforced by a
* parameterized inner path.
* *
* "Redundant" means either equal() or derived from the same EquivalenceClass. * "Redundant" means either equal() or derived from the same EquivalenceClass.
* We have to check the latter because indxpath.c may select different derived * We have to check the latter because indxpath.c may select different derived
...@@ -637,78 +638,16 @@ extract_actual_join_clauses(List *restrictinfo_list, ...@@ -637,78 +638,16 @@ extract_actual_join_clauses(List *restrictinfo_list,
* restrictinfo_list; that should have been handled elsewhere. * restrictinfo_list; that should have been handled elsewhere.
*/ */
List * List *
select_nonredundant_join_clauses(PlannerInfo *root, select_nonredundant_join_clauses(List *restrictinfo_list,
List *restrictinfo_list,
Path *inner_path)
{
if (IsA(inner_path, IndexPath))
{
/*
* Check the index quals to see if any of them are join clauses.
*
* We can skip this if the index path is an ordinary indexpath and not
* a special innerjoin path, since it then wouldn't be using any join
* clauses.
*/
IndexPath *innerpath = (IndexPath *) inner_path;
if (innerpath->isjoininner)
restrictinfo_list =
select_nonredundant_join_list(restrictinfo_list,
innerpath->indexclauses);
}
else if (IsA(inner_path, BitmapHeapPath))
{
/*
* Same deal for bitmapped index scans.
*
* Note: both here and above, we ignore any implicit index
* restrictions associated with the use of partial indexes. This is
* OK because we're only trying to prove we can dispense with some
* join quals; failing to prove that doesn't result in an incorrect
* plan. It's quite unlikely that a join qual could be proven
* redundant by an index predicate anyway. (Also, if we did manage to
* prove it, we'd have to have a special case for update targets; see
* notes about EvalPlanQual testing in create_indexscan_plan().)
*/
BitmapHeapPath *innerpath = (BitmapHeapPath *) inner_path;
if (innerpath->isjoininner)
{
List *bitmapclauses;
bitmapclauses =
make_restrictinfo_from_bitmapqual(innerpath->bitmapqual,
true,
false);
restrictinfo_list =
select_nonredundant_join_list(restrictinfo_list,
bitmapclauses);
}
}
/*
* XXX the inner path of a nestloop could also be an append relation whose
* elements use join quals. However, they might each use different quals;
* we could only remove join quals that are enforced by all the appendrel
* members. For the moment we don't bother to try.
*/
return restrictinfo_list;
}
/*
* select_nonredundant_join_list
* Select the members of restrictinfo_list that are not redundant with
* any member of reference_list. See above for more info.
*/
static List *
select_nonredundant_join_list(List *restrictinfo_list,
List *reference_list) List *reference_list)
{ {
List *result = NIL; List *result = NIL;
ListCell *item; ListCell *item;
/* Quick out if nothing could be removed */
if (reference_list == NIL)
return restrictinfo_list;
foreach(item, restrictinfo_list) foreach(item, restrictinfo_list)
{ {
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item); RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
......
...@@ -5971,7 +5971,7 @@ string_to_bytea_const(const char *str, size_t str_len) ...@@ -5971,7 +5971,7 @@ string_to_bytea_const(const char *str, size_t str_len)
static void static void
genericcostestimate(PlannerInfo *root, genericcostestimate(PlannerInfo *root,
IndexPath *path, IndexPath *path,
RelOptInfo *outer_rel, double loop_count,
double numIndexTuples, double numIndexTuples,
Cost *indexStartupCost, Cost *indexStartupCost,
Cost *indexTotalCost, Cost *indexTotalCost,
...@@ -6119,16 +6119,8 @@ genericcostestimate(PlannerInfo *root, ...@@ -6119,16 +6119,8 @@ genericcostestimate(PlannerInfo *root,
* Note that we are counting pages not tuples anymore, so we take N = T = * Note that we are counting pages not tuples anymore, so we take N = T =
* index size, as if there were one "tuple" per page. * index size, as if there were one "tuple" per page.
*/ */
if (outer_rel != NULL && outer_rel->rows > 1) num_outer_scans = loop_count;
{
num_outer_scans = outer_rel->rows;
num_scans = num_sa_scans * num_outer_scans; num_scans = num_sa_scans * num_outer_scans;
}
else
{
num_outer_scans = 1;
num_scans = num_sa_scans;
}
if (num_scans > 1) if (num_scans > 1)
{ {
...@@ -6234,7 +6226,7 @@ btcostestimate(PG_FUNCTION_ARGS) ...@@ -6234,7 +6226,7 @@ btcostestimate(PG_FUNCTION_ARGS)
{ {
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2); double loop_count = PG_GETARG_FLOAT8(2);
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
...@@ -6410,7 +6402,7 @@ btcostestimate(PG_FUNCTION_ARGS) ...@@ -6410,7 +6402,7 @@ btcostestimate(PG_FUNCTION_ARGS)
numIndexTuples = rint(numIndexTuples / num_sa_scans); numIndexTuples = rint(numIndexTuples / num_sa_scans);
} }
genericcostestimate(root, path, outer_rel, genericcostestimate(root, path, loop_count,
numIndexTuples, numIndexTuples,
indexStartupCost, indexTotalCost, indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation); indexSelectivity, indexCorrelation);
...@@ -6527,13 +6519,13 @@ hashcostestimate(PG_FUNCTION_ARGS) ...@@ -6527,13 +6519,13 @@ hashcostestimate(PG_FUNCTION_ARGS)
{ {
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2); double loop_count = PG_GETARG_FLOAT8(2);
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
double *indexCorrelation = (double *) PG_GETARG_POINTER(6); double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
genericcostestimate(root, path, outer_rel, 0.0, genericcostestimate(root, path, loop_count, 0.0,
indexStartupCost, indexTotalCost, indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation); indexSelectivity, indexCorrelation);
...@@ -6545,13 +6537,13 @@ gistcostestimate(PG_FUNCTION_ARGS) ...@@ -6545,13 +6537,13 @@ gistcostestimate(PG_FUNCTION_ARGS)
{ {
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2); double loop_count = PG_GETARG_FLOAT8(2);
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
double *indexCorrelation = (double *) PG_GETARG_POINTER(6); double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
genericcostestimate(root, path, outer_rel, 0.0, genericcostestimate(root, path, loop_count, 0.0,
indexStartupCost, indexTotalCost, indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation); indexSelectivity, indexCorrelation);
...@@ -6563,13 +6555,13 @@ spgcostestimate(PG_FUNCTION_ARGS) ...@@ -6563,13 +6555,13 @@ spgcostestimate(PG_FUNCTION_ARGS)
{ {
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2); double loop_count = PG_GETARG_FLOAT8(2);
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
double *indexCorrelation = (double *) PG_GETARG_POINTER(6); double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
genericcostestimate(root, path, outer_rel, 0.0, genericcostestimate(root, path, loop_count, 0.0,
indexStartupCost, indexTotalCost, indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation); indexSelectivity, indexCorrelation);
...@@ -6884,7 +6876,7 @@ gincostestimate(PG_FUNCTION_ARGS) ...@@ -6884,7 +6876,7 @@ gincostestimate(PG_FUNCTION_ARGS)
{ {
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1); IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2); double loop_count = PG_GETARG_FLOAT8(2);
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3); Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4); Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5); Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
...@@ -7051,10 +7043,7 @@ gincostestimate(PG_FUNCTION_ARGS) ...@@ -7051,10 +7043,7 @@ gincostestimate(PG_FUNCTION_ARGS)
} }
/* Will we have more than one iteration of a nestloop scan? */ /* Will we have more than one iteration of a nestloop scan? */
if (outer_rel != NULL && outer_rel->rows > 1) outer_scans = loop_count;
outer_scans = outer_rel->rows;
else
outer_scans = 1;
/* /*
* Compute cost to begin scan, first of all, pay attention to pending list. * Compute cost to begin scan, first of all, pay attention to pending list.
......
...@@ -36,6 +36,15 @@ typedef struct Bitmapset ...@@ -36,6 +36,15 @@ typedef struct Bitmapset
} Bitmapset; /* VARIABLE LENGTH STRUCT */ } Bitmapset; /* VARIABLE LENGTH STRUCT */
/* result of bms_subset_compare */
typedef enum
{
BMS_EQUAL, /* sets are equal */
BMS_SUBSET1, /* first set is a subset of the second */
BMS_SUBSET2, /* second set is a subset of the first */
BMS_DIFFERENT /* neither set is a subset of the other */
} BMS_Comparison;
/* result of bms_membership */ /* result of bms_membership */
typedef enum typedef enum
{ {
...@@ -58,6 +67,7 @@ extern Bitmapset *bms_union(const Bitmapset *a, const Bitmapset *b); ...@@ -58,6 +67,7 @@ extern Bitmapset *bms_union(const Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_intersect(const Bitmapset *a, const Bitmapset *b); extern Bitmapset *bms_intersect(const Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_difference(const Bitmapset *a, const Bitmapset *b); extern Bitmapset *bms_difference(const Bitmapset *a, const Bitmapset *b);
extern bool bms_is_subset(const Bitmapset *a, const Bitmapset *b); extern bool bms_is_subset(const Bitmapset *a, const Bitmapset *b);
extern BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b);
extern bool bms_is_member(int x, const Bitmapset *a); extern bool bms_is_member(int x, const Bitmapset *a);
extern bool bms_overlap(const Bitmapset *a, const Bitmapset *b); extern bool bms_overlap(const Bitmapset *a, const Bitmapset *b);
extern bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b); extern bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b);
......
...@@ -232,7 +232,6 @@ typedef enum NodeTag ...@@ -232,7 +232,6 @@ typedef enum NodeTag
T_EquivalenceMember, T_EquivalenceMember,
T_PathKey, T_PathKey,
T_RestrictInfo, T_RestrictInfo,
T_InnerIndexscanInfo,
T_PlaceHolderVar, T_PlaceHolderVar,
T_SpecialJoinInfo, T_SpecialJoinInfo,
T_AppendRelInfo, T_AppendRelInfo,
......
This diff is collapsed.
...@@ -68,9 +68,9 @@ extern double index_pages_fetched(double tuples_fetched, BlockNumber pages, ...@@ -68,9 +68,9 @@ extern double index_pages_fetched(double tuples_fetched, BlockNumber pages,
double index_pages, PlannerInfo *root); double index_pages, PlannerInfo *root);
extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel); extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel);
extern void cost_index(IndexPath *path, PlannerInfo *root, extern void cost_index(IndexPath *path, PlannerInfo *root,
RelOptInfo *outer_rel); double loop_count);
extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
Path *bitmapqual, RelOptInfo *outer_rel); Path *bitmapqual, double loop_count);
extern void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root); extern void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root);
extern void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root); extern void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root);
extern void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec); extern void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
...@@ -107,15 +107,47 @@ extern void cost_group(Path *path, PlannerInfo *root, ...@@ -107,15 +107,47 @@ extern void cost_group(Path *path, PlannerInfo *root,
int numGroupCols, double numGroups, int numGroupCols, double numGroups,
Cost input_startup_cost, Cost input_total_cost, Cost input_startup_cost, Cost input_total_cost,
double input_tuples); double input_tuples);
extern void cost_nestloop(NestPath *path, PlannerInfo *root, extern void initial_cost_nestloop(PlannerInfo *root,
SpecialJoinInfo *sjinfo); JoinCostWorkspace *workspace,
extern void cost_mergejoin(MergePath *path, PlannerInfo *root, JoinType jointype,
Path *outer_path, Path *inner_path,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors);
extern void final_cost_nestloop(PlannerInfo *root, NestPath *path,
JoinCostWorkspace *workspace,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors);
extern void initial_cost_mergejoin(PlannerInfo *root,
JoinCostWorkspace *workspace,
JoinType jointype,
List *mergeclauses,
Path *outer_path, Path *inner_path,
List *outersortkeys, List *innersortkeys,
SpecialJoinInfo *sjinfo); SpecialJoinInfo *sjinfo);
extern void cost_hashjoin(HashPath *path, PlannerInfo *root, extern void final_cost_mergejoin(PlannerInfo *root, MergePath *path,
JoinCostWorkspace *workspace,
SpecialJoinInfo *sjinfo); SpecialJoinInfo *sjinfo);
extern void initial_cost_hashjoin(PlannerInfo *root,
JoinCostWorkspace *workspace,
JoinType jointype,
List *hashclauses,
Path *outer_path, Path *inner_path,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors);
extern void final_cost_hashjoin(PlannerInfo *root, HashPath *path,
JoinCostWorkspace *workspace,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors);
extern void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan); extern void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan);
extern void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root); extern void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root);
extern void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root); extern void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root);
extern void compute_semi_anti_join_factors(PlannerInfo *root,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
JoinType jointype,
SpecialJoinInfo *sjinfo,
List *restrictlist,
SemiAntiJoinFactors *semifactors);
extern void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel); extern void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel);
extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *outer_rel, RelOptInfo *outer_rel,
......
...@@ -26,6 +26,9 @@ extern int compare_fractional_path_costs(Path *path1, Path *path2, ...@@ -26,6 +26,9 @@ extern int compare_fractional_path_costs(Path *path1, Path *path2,
double fraction); double fraction);
extern void set_cheapest(RelOptInfo *parent_rel); extern void set_cheapest(RelOptInfo *parent_rel);
extern void add_path(RelOptInfo *parent_rel, Path *new_path); extern void add_path(RelOptInfo *parent_rel, Path *new_path);
extern bool add_path_precheck(RelOptInfo *parent_rel,
Cost startup_cost, Cost total_cost,
List *pathkeys, Relids required_outer);
extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel); extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel);
extern IndexPath *create_index_path(PlannerInfo *root, extern IndexPath *create_index_path(PlannerInfo *root,
...@@ -37,11 +40,12 @@ extern IndexPath *create_index_path(PlannerInfo *root, ...@@ -37,11 +40,12 @@ extern IndexPath *create_index_path(PlannerInfo *root,
List *pathkeys, List *pathkeys,
ScanDirection indexscandir, ScanDirection indexscandir,
bool indexonly, bool indexonly,
RelOptInfo *outer_rel); Relids required_outer,
double loop_count);
extern BitmapHeapPath *create_bitmap_heap_path(PlannerInfo *root, extern BitmapHeapPath *create_bitmap_heap_path(PlannerInfo *root,
RelOptInfo *rel, RelOptInfo *rel,
Path *bitmapqual, Path *bitmapqual,
RelOptInfo *outer_rel); double loop_count);
extern BitmapAndPath *create_bitmap_and_path(PlannerInfo *root, extern BitmapAndPath *create_bitmap_and_path(PlannerInfo *root,
RelOptInfo *rel, RelOptInfo *rel,
List *bitmapquals); List *bitmapquals);
...@@ -66,23 +70,31 @@ extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel); ...@@ -66,23 +70,31 @@ extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel);
extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel); extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel);
extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel); extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel);
extern Relids calc_nestloop_required_outer(Path *outer_path, Path *inner_path);
extern Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path);
extern NestPath *create_nestloop_path(PlannerInfo *root, extern NestPath *create_nestloop_path(PlannerInfo *root,
RelOptInfo *joinrel, RelOptInfo *joinrel,
JoinType jointype, JoinType jointype,
JoinCostWorkspace *workspace,
SpecialJoinInfo *sjinfo, SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Path *outer_path, Path *outer_path,
Path *inner_path, Path *inner_path,
List *restrict_clauses, List *restrict_clauses,
List *pathkeys); List *pathkeys,
Relids required_outer);
extern MergePath *create_mergejoin_path(PlannerInfo *root, extern MergePath *create_mergejoin_path(PlannerInfo *root,
RelOptInfo *joinrel, RelOptInfo *joinrel,
JoinType jointype, JoinType jointype,
JoinCostWorkspace *workspace,
SpecialJoinInfo *sjinfo, SpecialJoinInfo *sjinfo,
Path *outer_path, Path *outer_path,
Path *inner_path, Path *inner_path,
List *restrict_clauses, List *restrict_clauses,
List *pathkeys, List *pathkeys,
Relids required_outer,
List *mergeclauses, List *mergeclauses,
List *outersortkeys, List *outersortkeys,
List *innersortkeys); List *innersortkeys);
...@@ -90,10 +102,13 @@ extern MergePath *create_mergejoin_path(PlannerInfo *root, ...@@ -90,10 +102,13 @@ extern MergePath *create_mergejoin_path(PlannerInfo *root,
extern HashPath *create_hashjoin_path(PlannerInfo *root, extern HashPath *create_hashjoin_path(PlannerInfo *root,
RelOptInfo *joinrel, RelOptInfo *joinrel,
JoinType jointype, JoinType jointype,
JoinCostWorkspace *workspace,
SpecialJoinInfo *sjinfo, SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Path *outer_path, Path *outer_path,
Path *inner_path, Path *inner_path,
List *restrict_clauses, List *restrict_clauses,
Relids required_outer,
List *hashclauses); List *hashclauses);
/* /*
......
...@@ -44,17 +44,14 @@ extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel); ...@@ -44,17 +44,14 @@ extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
*/ */
extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel); extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel);
extern List *generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel, extern List *generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
List *clauses, List *outer_clauses, List *clauses, List *other_clauses,
RelOptInfo *outer_rel); bool restriction_only);
extern void best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *outer_rel, JoinType jointype,
Path **cheapest_startup, Path **cheapest_total);
extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
List *restrictlist, List *restrictlist,
List *exprlist, List *oprlist); List *exprlist, List *oprlist);
extern bool eclass_matches_any_index(EquivalenceClass *ec, extern bool eclass_member_matches_indexcol(EquivalenceClass *ec,
EquivalenceMember *em, EquivalenceMember *em,
RelOptInfo *rel); IndexOptInfo *index, int indexcol);
extern bool match_index_to_operand(Node *operand, int indexcol, extern bool match_index_to_operand(Node *operand, int indexcol,
IndexOptInfo *index); IndexOptInfo *index);
extern void expand_indexqual_conditions(IndexOptInfo *index, extern void expand_indexqual_conditions(IndexOptInfo *index,
...@@ -127,9 +124,9 @@ extern void add_child_rel_equivalences(PlannerInfo *root, ...@@ -127,9 +124,9 @@ extern void add_child_rel_equivalences(PlannerInfo *root,
extern void mutate_eclass_expressions(PlannerInfo *root, extern void mutate_eclass_expressions(PlannerInfo *root,
Node *(*mutator) (), Node *(*mutator) (),
void *context); void *context);
extern List *find_eclass_clauses_for_index_join(PlannerInfo *root, extern List *generate_implied_equalities_for_indexcol(PlannerInfo *root,
RelOptInfo *rel, IndexOptInfo *index,
Relids outer_relids); int indexcol);
extern bool have_relevant_eclass_joinclause(PlannerInfo *root, extern bool have_relevant_eclass_joinclause(PlannerInfo *root,
RelOptInfo *rel1, RelOptInfo *rel2); RelOptInfo *rel1, RelOptInfo *rel2);
extern bool has_relevant_eclass_joinclause(PlannerInfo *root, extern bool has_relevant_eclass_joinclause(PlannerInfo *root,
...@@ -153,9 +150,11 @@ extern List *canonicalize_pathkeys(PlannerInfo *root, List *pathkeys); ...@@ -153,9 +150,11 @@ extern List *canonicalize_pathkeys(PlannerInfo *root, List *pathkeys);
extern PathKeysComparison compare_pathkeys(List *keys1, List *keys2); extern PathKeysComparison compare_pathkeys(List *keys1, List *keys2);
extern bool pathkeys_contained_in(List *keys1, List *keys2); extern bool pathkeys_contained_in(List *keys1, List *keys2);
extern Path *get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, extern Path *get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
Relids required_outer,
CostSelector cost_criterion); CostSelector cost_criterion);
extern Path *get_cheapest_fractional_path_for_pathkeys(List *paths, extern Path *get_cheapest_fractional_path_for_pathkeys(List *paths,
List *pathkeys, List *pathkeys,
Relids required_outer,
double fraction); double fraction);
extern List *build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index, extern List *build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index,
ScanDirection scandir); ScanDirection scandir);
......
...@@ -40,8 +40,7 @@ extern List *extract_actual_clauses(List *restrictinfo_list, ...@@ -40,8 +40,7 @@ extern List *extract_actual_clauses(List *restrictinfo_list,
extern void extract_actual_join_clauses(List *restrictinfo_list, extern void extract_actual_join_clauses(List *restrictinfo_list,
List **joinquals, List **joinquals,
List **otherquals); List **otherquals);
extern List *select_nonredundant_join_clauses(PlannerInfo *root, extern List *select_nonredundant_join_clauses(List *restrictinfo_list,
List *restrictinfo_list, List *reference_list);
Path *inner_path);
#endif /* RESTRICTINFO_H */ #endif /* RESTRICTINFO_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment