Commit e139f195 authored by Robert Haas's avatar Robert Haas

Assorted preparatory refactoring for partition-wise join.

Instead of duplicating the logic to search for a matching
ParamPathInfo in multiple places, factor it out into a separate
function.

Pass only the relevant bits of the PartitionKey to
partition_bounds_equal instead of the whole thing, because
partition-wise join will want to call this without having a
PartitionKey available.

Adjust allow_star_schema_join and calc_nestloop_required_outer
to take relevant Relids rather than the entire Path, because
partition-wise join will want to call it with the top-parent
relids to determine whether a child join is allowable.

Ashutosh Bapat.  Review and testing of the larger patch set of which
this is a part by Amit Langote, Rajkumar Raghuwanshi, Rafia Sabih,
Thomas Munro, Dilip Kumar, and me.

Discussion: http://postgr.es/m/CA+TgmobQK80vtXjAsPZWWXd7c8u13G86gmuLupN+uUJjA+i4nA@mail.gmail.com
parent 00418c61
...@@ -583,7 +583,7 @@ RelationBuildPartitionDesc(Relation rel) ...@@ -583,7 +583,7 @@ RelationBuildPartitionDesc(Relation rel)
* representation of partition bounds. * representation of partition bounds.
*/ */
bool bool
partition_bounds_equal(PartitionKey key, partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
PartitionBoundInfo b1, PartitionBoundInfo b2) PartitionBoundInfo b1, PartitionBoundInfo b2)
{ {
int i; int i;
...@@ -601,7 +601,7 @@ partition_bounds_equal(PartitionKey key, ...@@ -601,7 +601,7 @@ partition_bounds_equal(PartitionKey key,
{ {
int j; int j;
for (j = 0; j < key->partnatts; j++) for (j = 0; j < partnatts; j++)
{ {
/* For range partitions, the bounds might not be finite. */ /* For range partitions, the bounds might not be finite. */
if (b1->kind != NULL) if (b1->kind != NULL)
...@@ -627,8 +627,7 @@ partition_bounds_equal(PartitionKey key, ...@@ -627,8 +627,7 @@ partition_bounds_equal(PartitionKey key,
* context. datumIsEqual() should be simple enough to be safe. * context. datumIsEqual() should be simple enough to be safe.
*/ */
if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j], if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
key->parttypbyval[j], parttypbyval[j], parttyplen[j]))
key->parttyplen[j]))
return false; return false;
} }
...@@ -637,7 +636,7 @@ partition_bounds_equal(PartitionKey key, ...@@ -637,7 +636,7 @@ partition_bounds_equal(PartitionKey key,
} }
/* There are ndatums+1 indexes in case of range partitions */ /* There are ndatums+1 indexes in case of range partitions */
if (key->strategy == PARTITION_STRATEGY_RANGE && if (b1->strategy == PARTITION_STRATEGY_RANGE &&
b1->indexes[i] != b2->indexes[i]) b1->indexes[i] != b2->indexes[i])
return false; return false;
......
...@@ -318,18 +318,15 @@ add_paths_to_joinrel(PlannerInfo *root, ...@@ -318,18 +318,15 @@ add_paths_to_joinrel(PlannerInfo *root,
*/ */
static inline bool static inline bool
allow_star_schema_join(PlannerInfo *root, allow_star_schema_join(PlannerInfo *root,
Path *outer_path, Relids outerrelids,
Path *inner_path) Relids inner_paramrels)
{ {
Relids innerparams = PATH_REQ_OUTER(inner_path);
Relids outerrelids = outer_path->parent->relids;
/* /*
* It's a star-schema case if the outer rel provides some but not all of * It's a star-schema case if the outer rel provides some but not all of
* the inner rel's parameterization. * the inner rel's parameterization.
*/ */
return (bms_overlap(innerparams, outerrelids) && return (bms_overlap(inner_paramrels, outerrelids) &&
bms_nonempty_difference(innerparams, outerrelids)); bms_nonempty_difference(inner_paramrels, outerrelids));
} }
/* /*
...@@ -348,6 +345,12 @@ try_nestloop_path(PlannerInfo *root, ...@@ -348,6 +345,12 @@ try_nestloop_path(PlannerInfo *root,
{ {
Relids required_outer; Relids required_outer;
JoinCostWorkspace workspace; JoinCostWorkspace workspace;
RelOptInfo *innerrel = inner_path->parent;
RelOptInfo *outerrel = outer_path->parent;
Relids innerrelids = innerrel->relids;
Relids outerrelids = outerrel->relids;
Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
/* /*
* Check to see if proposed path is still parameterized, and reject if the * Check to see if proposed path is still parameterized, and reject if the
...@@ -356,14 +359,12 @@ try_nestloop_path(PlannerInfo *root, ...@@ -356,14 +359,12 @@ try_nestloop_path(PlannerInfo *root,
* doesn't like the look of it, which could only happen if the nestloop is * doesn't like the look of it, which could only happen if the nestloop is
* still parameterized. * still parameterized.
*/ */
required_outer = calc_nestloop_required_outer(outer_path, required_outer = calc_nestloop_required_outer(outerrelids, outer_paramrels,
inner_path); innerrelids, inner_paramrels);
if (required_outer && if (required_outer &&
((!bms_overlap(required_outer, extra->param_source_rels) && ((!bms_overlap(required_outer, extra->param_source_rels) &&
!allow_star_schema_join(root, outer_path, inner_path)) || !allow_star_schema_join(root, outerrelids, inner_paramrels)) ||
have_dangerous_phv(root, have_dangerous_phv(root, outerrelids, inner_paramrels)))
outer_path->parent->relids,
PATH_REQ_OUTER(inner_path))))
{ {
/* Waste no memory when we reject a path here */ /* Waste no memory when we reject a path here */
bms_free(required_outer); bms_free(required_outer);
......
...@@ -1993,14 +1993,15 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, ...@@ -1993,14 +1993,15 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
* Note: result must not share storage with either input * Note: result must not share storage with either input
*/ */
Relids Relids
calc_nestloop_required_outer(Path *outer_path, Path *inner_path) calc_nestloop_required_outer(Relids outerrelids,
Relids outer_paramrels,
Relids innerrelids,
Relids inner_paramrels)
{ {
Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
Relids required_outer; Relids required_outer;
/* inner_path can require rels from outer path, but not vice versa */ /* inner_path can require rels from outer path, but not vice versa */
Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids)); Assert(!bms_overlap(outer_paramrels, innerrelids));
/* easy case if inner path is not parameterized */ /* easy case if inner path is not parameterized */
if (!inner_paramrels) if (!inner_paramrels)
return bms_copy(outer_paramrels); return bms_copy(outer_paramrels);
...@@ -2008,7 +2009,7 @@ calc_nestloop_required_outer(Path *outer_path, Path *inner_path) ...@@ -2008,7 +2009,7 @@ calc_nestloop_required_outer(Path *outer_path, Path *inner_path)
required_outer = bms_union(outer_paramrels, inner_paramrels); required_outer = bms_union(outer_paramrels, inner_paramrels);
/* ... and remove any mention of now-satisfied outer rels */ /* ... and remove any mention of now-satisfied outer rels */
required_outer = bms_del_members(required_outer, required_outer = bms_del_members(required_outer,
outer_path->parent->relids); outerrelids);
/* maintain invariant that required_outer is exactly NULL if empty */ /* maintain invariant that required_outer is exactly NULL if empty */
if (bms_is_empty(required_outer)) if (bms_is_empty(required_outer))
{ {
......
...@@ -1048,12 +1048,8 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, ...@@ -1048,12 +1048,8 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
Assert(!bms_overlap(baserel->relids, required_outer)); Assert(!bms_overlap(baserel->relids, required_outer));
/* If we already have a PPI for this parameterization, just return it */ /* If we already have a PPI for this parameterization, just return it */
foreach(lc, baserel->ppilist) if ((ppi = find_param_path_info(baserel, required_outer)))
{ return ppi;
ppi = (ParamPathInfo *) lfirst(lc);
if (bms_equal(ppi->ppi_req_outer, required_outer))
return ppi;
}
/* /*
* Identify all joinclauses that are movable to this base rel given this * Identify all joinclauses that are movable to this base rel given this
...@@ -1290,12 +1286,8 @@ get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel, ...@@ -1290,12 +1286,8 @@ get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel,
*restrict_clauses = list_concat(pclauses, *restrict_clauses); *restrict_clauses = list_concat(pclauses, *restrict_clauses);
/* If we already have a PPI for this parameterization, just return it */ /* If we already have a PPI for this parameterization, just return it */
foreach(lc, joinrel->ppilist) if ((ppi = find_param_path_info(joinrel, required_outer)))
{ return ppi;
ppi = (ParamPathInfo *) lfirst(lc);
if (bms_equal(ppi->ppi_req_outer, required_outer))
return ppi;
}
/* Estimate the number of rows returned by the parameterized join */ /* Estimate the number of rows returned by the parameterized join */
rows = get_parameterized_joinrel_size(root, joinrel, rows = get_parameterized_joinrel_size(root, joinrel,
...@@ -1334,7 +1326,6 @@ ParamPathInfo * ...@@ -1334,7 +1326,6 @@ ParamPathInfo *
get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer) get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
{ {
ParamPathInfo *ppi; ParamPathInfo *ppi;
ListCell *lc;
/* Unparameterized paths have no ParamPathInfo */ /* Unparameterized paths have no ParamPathInfo */
if (bms_is_empty(required_outer)) if (bms_is_empty(required_outer))
...@@ -1343,12 +1334,8 @@ get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer) ...@@ -1343,12 +1334,8 @@ get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
Assert(!bms_overlap(appendrel->relids, required_outer)); Assert(!bms_overlap(appendrel->relids, required_outer));
/* If we already have a PPI for this parameterization, just return it */ /* If we already have a PPI for this parameterization, just return it */
foreach(lc, appendrel->ppilist) if ((ppi = find_param_path_info(appendrel, required_outer)))
{ return ppi;
ppi = (ParamPathInfo *) lfirst(lc);
if (bms_equal(ppi->ppi_req_outer, required_outer))
return ppi;
}
/* Else build the ParamPathInfo */ /* Else build the ParamPathInfo */
ppi = makeNode(ParamPathInfo); ppi = makeNode(ParamPathInfo);
...@@ -1359,3 +1346,23 @@ get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer) ...@@ -1359,3 +1346,23 @@ get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
return ppi; return ppi;
} }
/*
* Returns a ParamPathInfo for the parameterization given by required_outer, if
* already available in the given rel. Returns NULL otherwise.
*/
ParamPathInfo *
find_param_path_info(RelOptInfo *rel, Relids required_outer)
{
ListCell *lc;
foreach(lc, rel->ppilist)
{
ParamPathInfo *ppi = (ParamPathInfo *) lfirst(lc);
if (bms_equal(ppi->ppi_req_outer, required_outer))
return ppi;
}
return NULL;
}
...@@ -1208,7 +1208,9 @@ equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1, ...@@ -1208,7 +1208,9 @@ equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1,
if (partdesc2->boundinfo == NULL) if (partdesc2->boundinfo == NULL)
return false; return false;
if (!partition_bounds_equal(key, partdesc1->boundinfo, if (!partition_bounds_equal(key->partnatts, key->parttyplen,
key->parttypbyval,
partdesc1->boundinfo,
partdesc2->boundinfo)) partdesc2->boundinfo))
return false; return false;
} }
......
...@@ -71,8 +71,9 @@ typedef struct PartitionDispatchData ...@@ -71,8 +71,9 @@ typedef struct PartitionDispatchData
typedef struct PartitionDispatchData *PartitionDispatch; typedef struct PartitionDispatchData *PartitionDispatch;
extern void RelationBuildPartitionDesc(Relation relation); extern void RelationBuildPartitionDesc(Relation relation);
extern bool partition_bounds_equal(PartitionKey key, extern bool partition_bounds_equal(int partnatts, int16 *parttyplen,
PartitionBoundInfo p1, PartitionBoundInfo p2); bool *parttypbyval, PartitionBoundInfo b1,
PartitionBoundInfo b2);
extern void check_new_partition_bound(char *relname, Relation parent, extern void check_new_partition_bound(char *relname, Relation parent,
PartitionBoundSpec *spec); PartitionBoundSpec *spec);
......
...@@ -112,7 +112,10 @@ extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, ...@@ -112,7 +112,10 @@ extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
Path *fdw_outerpath, Path *fdw_outerpath,
List *fdw_private); List *fdw_private);
extern Relids calc_nestloop_required_outer(Path *outer_path, Path *inner_path); extern Relids calc_nestloop_required_outer(Relids outerrelids,
Relids outer_paramrels,
Relids innerrelids,
Relids inner_paramrels);
extern Relids calc_non_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,
...@@ -285,5 +288,7 @@ extern ParamPathInfo *get_joinrel_parampathinfo(PlannerInfo *root, ...@@ -285,5 +288,7 @@ extern ParamPathInfo *get_joinrel_parampathinfo(PlannerInfo *root,
List **restrict_clauses); List **restrict_clauses);
extern ParamPathInfo *get_appendrel_parampathinfo(RelOptInfo *appendrel, extern ParamPathInfo *get_appendrel_parampathinfo(RelOptInfo *appendrel,
Relids required_outer); Relids required_outer);
extern ParamPathInfo *find_param_path_info(RelOptInfo *rel,
Relids required_outer);
#endif /* PATHNODE_H */ #endif /* PATHNODE_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