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
This commit is contained in:
parent
00418c6124
commit
e139f1953f
@ -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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
* 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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
* 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,
|
|||||||
* 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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
*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 *
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
4
src/backend/utils/cache/relcache.c
vendored
4
src/backend/utils/cache/relcache.c
vendored
@ -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
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user