mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
Restructure planner's handling of inheritance. Rather than processing
inheritance trees on-the-fly, which pretty well constrained us to considering only one way of planning inheritance, expand inheritance sets during the planner prep phase, and build a side data structure that can be consulted later to find which RTEs are members of which inheritance sets. As proof of concept, use the data structure to plan joins against inheritance sets more efficiently: we can now use indexes on the set members in inner-indexscan joins. (The generated plans could be improved further, but it'll take some executor changes.) This data structure will also support handling UNION ALL subqueries in the same way as inheritance sets, but that aspect of it isn't finished yet.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.74 2005/12/20 02:30:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.75 2006/01/31 21:39:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -30,8 +30,6 @@ typedef struct JoinHashEntry
|
||||
RelOptInfo *join_rel;
|
||||
} JoinHashEntry;
|
||||
|
||||
static RelOptInfo *make_reloptinfo(PlannerInfo *root, int relid,
|
||||
RelOptKind reloptkind);
|
||||
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
|
||||
RelOptInfo *input_rel);
|
||||
static List *build_joinrel_restrictlist(PlannerInfo *root,
|
||||
@ -49,71 +47,25 @@ static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
|
||||
|
||||
|
||||
/*
|
||||
* build_base_rel
|
||||
* Construct a new base relation RelOptInfo, and put it in the query's
|
||||
* base_rel_array.
|
||||
*/
|
||||
void
|
||||
build_base_rel(PlannerInfo *root, int relid)
|
||||
{
|
||||
Assert(relid > 0);
|
||||
|
||||
/* Rel should not exist already */
|
||||
if (relid < root->base_rel_array_size &&
|
||||
root->base_rel_array[relid] != NULL)
|
||||
elog(ERROR, "rel already exists");
|
||||
|
||||
/* No existing RelOptInfo for this base rel, so make a new one */
|
||||
(void) make_reloptinfo(root, relid, RELOPT_BASEREL);
|
||||
}
|
||||
|
||||
/*
|
||||
* build_other_rel
|
||||
* Returns relation entry corresponding to 'relid', creating a new one
|
||||
* if necessary. This is for 'other' relations, which are much like
|
||||
* base relations except that they have a different RelOptKind.
|
||||
* build_simple_rel
|
||||
* Construct a new RelOptInfo for a base relation or 'other' relation.
|
||||
*/
|
||||
RelOptInfo *
|
||||
build_other_rel(PlannerInfo *root, int relid)
|
||||
build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
|
||||
{
|
||||
RelOptInfo *rel;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
Assert(relid > 0);
|
||||
/* Fetch RTE for relation */
|
||||
Assert(relid > 0 && relid <= list_length(root->parse->rtable));
|
||||
rte = rt_fetch(relid, root->parse->rtable);
|
||||
|
||||
/* Already made? */
|
||||
if (relid < root->base_rel_array_size)
|
||||
{
|
||||
rel = root->base_rel_array[relid];
|
||||
if (rel)
|
||||
{
|
||||
/* it should not exist as a base rel */
|
||||
if (rel->reloptkind == RELOPT_BASEREL)
|
||||
elog(ERROR, "rel already exists as base rel");
|
||||
/* otherwise, A-OK */
|
||||
return rel;
|
||||
}
|
||||
}
|
||||
|
||||
/* No existing RelOptInfo for this other rel, so make a new one */
|
||||
/* presently, must be an inheritance child rel */
|
||||
rel = make_reloptinfo(root, relid, RELOPT_OTHER_CHILD_REL);
|
||||
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
* make_reloptinfo
|
||||
* Construct a RelOptInfo for the specified rangetable index,
|
||||
* and enter it into base_rel_array.
|
||||
*
|
||||
* Common code for build_base_rel and build_other_rel.
|
||||
*/
|
||||
static RelOptInfo *
|
||||
make_reloptinfo(PlannerInfo *root, int relid, RelOptKind reloptkind)
|
||||
{
|
||||
RelOptInfo *rel = makeNode(RelOptInfo);
|
||||
RangeTblEntry *rte = rt_fetch(relid, root->parse->rtable);
|
||||
/* Rel should not exist already */
|
||||
Assert(relid < root->simple_rel_array_size);
|
||||
if (root->simple_rel_array[relid] != NULL)
|
||||
elog(ERROR, "rel %d already exists", relid);
|
||||
|
||||
rel = makeNode(RelOptInfo);
|
||||
rel->reloptkind = reloptkind;
|
||||
rel->relids = bms_make_singleton(relid);
|
||||
rel->rows = 0;
|
||||
@ -161,21 +113,8 @@ make_reloptinfo(PlannerInfo *root, int relid, RelOptKind reloptkind)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add the finished struct to the base_rel_array */
|
||||
if (relid >= root->base_rel_array_size)
|
||||
{
|
||||
int oldsize = root->base_rel_array_size;
|
||||
int newsize;
|
||||
|
||||
newsize = Max(oldsize * 2, relid + 1);
|
||||
root->base_rel_array = (RelOptInfo **)
|
||||
repalloc(root->base_rel_array, newsize * sizeof(RelOptInfo *));
|
||||
MemSet(root->base_rel_array + oldsize, 0,
|
||||
(newsize - oldsize) * sizeof(RelOptInfo *));
|
||||
root->base_rel_array_size = newsize;
|
||||
}
|
||||
|
||||
root->base_rel_array[relid] = rel;
|
||||
/* Save the finished struct in the query's simple_rel_array */
|
||||
root->simple_rel_array[relid] = rel;
|
||||
|
||||
return rel;
|
||||
}
|
||||
@ -191,9 +130,9 @@ find_base_rel(PlannerInfo *root, int relid)
|
||||
|
||||
Assert(relid > 0);
|
||||
|
||||
if (relid < root->base_rel_array_size)
|
||||
if (relid < root->simple_rel_array_size)
|
||||
{
|
||||
rel = root->base_rel_array[relid];
|
||||
rel = root->simple_rel_array[relid];
|
||||
if (rel)
|
||||
return rel;
|
||||
}
|
||||
@ -446,12 +385,24 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
|
||||
|
||||
foreach(vars, input_rel->reltargetlist)
|
||||
{
|
||||
Var *var = (Var *) lfirst(vars);
|
||||
Var *origvar = (Var *) lfirst(vars);
|
||||
Var *var;
|
||||
RelOptInfo *baserel;
|
||||
int ndx;
|
||||
|
||||
/* We can't run into any child RowExprs here */
|
||||
Assert(IsA(var, Var));
|
||||
/*
|
||||
* We can't run into any child RowExprs here, but we could find
|
||||
* a whole-row Var with a ConvertRowtypeExpr atop it.
|
||||
*/
|
||||
var = origvar;
|
||||
while (!IsA(var, Var))
|
||||
{
|
||||
if (IsA(var, ConvertRowtypeExpr))
|
||||
var = (Var *) ((ConvertRowtypeExpr *) var)->arg;
|
||||
else
|
||||
elog(ERROR, "unexpected node type in reltargetlist: %d",
|
||||
(int) nodeTag(var));
|
||||
}
|
||||
|
||||
/* Get the Var's original base rel */
|
||||
baserel = find_base_rel(root, var->varno);
|
||||
@ -461,8 +412,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
|
||||
if (bms_nonempty_difference(baserel->attr_needed[ndx], relids))
|
||||
{
|
||||
/* Yup, add it to the output */
|
||||
joinrel->reltargetlist = lappend(joinrel->reltargetlist, var);
|
||||
Assert(baserel->attr_widths[ndx] > 0);
|
||||
joinrel->reltargetlist = lappend(joinrel->reltargetlist, origvar);
|
||||
joinrel->width += baserel->attr_widths[ndx];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user