Commit 835bb975 authored by Tom Lane's avatar Tom Lane

Restructure building of join relation targetlists so that a join plan

node emits only those vars that are actually needed above it in the
plan tree.  (There were comments in the code suggesting that this was
done at some point in the dim past, but for a long time we have just
made join nodes emit everything that either input emitted.)  Aside from
being marginally more efficient, this fixes the problem noted by Peter
Eisentraut where a join above an IN-implemented-as-join might fail,
because the subplan targetlist constructed in the latter case didn't
meet the expectation of including everything.
Along the way, fix some places that were O(N^2) in the targetlist
length.  This is not all the trouble spots for wide queries by any
means, but it's a step forward.
parent cf883ea9
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group * Copyright (c) 2003, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/bitmapset.c,v 1.1 2003/02/08 20:20:53 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/bitmapset.c,v 1.2 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -388,6 +388,36 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b) ...@@ -388,6 +388,36 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b)
return false; return false;
} }
/*
* bms_nonempty_difference - do sets have a nonempty difference?
*/
bool
bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
{
int shortlen;
int i;
/* Handle cases where either input is NULL */
if (a == NULL)
return false;
if (b == NULL)
return !bms_is_empty(a);
/* Check words in common */
shortlen = Min(a->nwords, b->nwords);
for (i = 0; i < shortlen; i++)
{
if ((a->words[i] & ~ b->words[i]) != 0)
return true;
}
/* Check extra words in a */
for (; i < a->nwords; i++)
{
if (a->words[i] != 0)
return true;
}
return false;
}
/* /*
* bms_singleton_member - return the sole integer member of set * bms_singleton_member - return the sole integer member of set
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.102 2003/04/24 23:43:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.103 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -235,6 +235,9 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, ...@@ -235,6 +235,9 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
RangeTblEntry *childrte; RangeTblEntry *childrte;
Oid childOID; Oid childOID;
RelOptInfo *childrel; RelOptInfo *childrel;
List *reltlist;
List *parentvars;
List *childvars;
childrte = rt_fetch(childRTindex, root->rtable); childrte = rt_fetch(childRTindex, root->rtable);
childOID = childrte->relid; childOID = childrte->relid;
...@@ -251,21 +254,24 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, ...@@ -251,21 +254,24 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
* Copy the parent's targetlist and restriction quals to the * Copy the parent's targetlist and restriction quals to the
* child, with attribute-number adjustment as needed. We don't * child, with attribute-number adjustment as needed. We don't
* bother to copy the join quals, since we can't do any joining of * bother to copy the join quals, since we can't do any joining of
* the individual tables. * the individual tables. Also, we just zap attr_needed rather
* than trying to adjust it; it won't be looked at in the child.
*/ */
childrel->targetlist = (List *) reltlist = FastListValue(&rel->reltargetlist);
adjust_inherited_attrs((Node *) rel->targetlist, reltlist = (List *)
adjust_inherited_attrs((Node *) reltlist,
parentRTindex, parentRTindex,
parentOID, parentOID,
childRTindex, childRTindex,
childOID); childOID);
FastListFromList(&childrel->reltargetlist, reltlist);
childrel->attr_needed = NULL;
childrel->baserestrictinfo = (List *) childrel->baserestrictinfo = (List *)
adjust_inherited_attrs((Node *) rel->baserestrictinfo, adjust_inherited_attrs((Node *) rel->baserestrictinfo,
parentRTindex, parentRTindex,
parentOID, parentOID,
childRTindex, childRTindex,
childOID); childOID);
childrel->baserestrictcost = rel->baserestrictcost;
/* /*
* Now compute child access paths, and save the cheapest. * Now compute child access paths, and save the cheapest.
...@@ -274,10 +280,27 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, ...@@ -274,10 +280,27 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
subpaths = lappend(subpaths, childrel->cheapest_total_path); subpaths = lappend(subpaths, childrel->cheapest_total_path);
/* Also update total size estimates */ /*
* Propagate size information from the child back to the parent.
* For simplicity, we use the largest widths from any child as the
* parent estimates.
*/
rel->rows += childrel->rows; rel->rows += childrel->rows;
if (childrel->width > rel->width) if (childrel->width > rel->width)
rel->width = childrel->width; rel->width = childrel->width;
childvars = FastListValue(&childrel->reltargetlist);
foreach(parentvars, FastListValue(&rel->reltargetlist))
{
Var *parentvar = (Var *) lfirst(parentvars);
Var *childvar = (Var *) lfirst(childvars);
int parentndx = parentvar->varattno - rel->min_attr;
int childndx = childvar->varattno - childrel->min_attr;
if (childrel->attr_widths[childndx] > rel->attr_widths[parentndx])
rel->attr_widths[parentndx] = childrel->attr_widths[childndx];
childvars = lnext(childvars);
}
} }
/* /*
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.108 2003/06/29 00:33:43 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.109 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1792,13 +1792,9 @@ set_joinrel_size_estimates(Query *root, RelOptInfo *rel, ...@@ -1792,13 +1792,9 @@ set_joinrel_size_estimates(Query *root, RelOptInfo *rel,
rel->rows = temp; rel->rows = temp;
/* /*
* We could apply set_rel_width() to compute the output tuple width * We need not compute the output width here, because build_joinrel_tlist
* from scratch, but at present it's always just the sum of the input * already did.
* widths, so why work harder than necessary? If relnode.c is ever
* taught to remove unneeded columns from join targetlists, go back to
* using set_rel_width here.
*/ */
rel->width = outer_rel->width + inner_rel->width;
} }
/* /*
...@@ -1858,13 +1854,16 @@ set_function_size_estimates(Query *root, RelOptInfo *rel) ...@@ -1858,13 +1854,16 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
/* /*
* set_rel_width * set_rel_width
* Set the estimated output width of the relation. * Set the estimated output width of a base relation.
* *
* NB: this works best on base relations because it prefers to look at * NB: this works best on plain relations because it prefers to look at
* real Vars. It will fail to make use of pg_statistic info when applied * real Vars. It will fail to make use of pg_statistic info when applied
* to a subquery relation, even if the subquery outputs are simple vars * to a subquery relation, even if the subquery outputs are simple vars
* that we could have gotten info for. Is it worth trying to be smarter * that we could have gotten info for. Is it worth trying to be smarter
* about subqueries? * about subqueries?
*
* The per-attribute width estimates are cached for possible re-use while
* building join relations.
*/ */
static void static void
set_rel_width(Query *root, RelOptInfo *rel) set_rel_width(Query *root, RelOptInfo *rel)
...@@ -1872,38 +1871,41 @@ set_rel_width(Query *root, RelOptInfo *rel) ...@@ -1872,38 +1871,41 @@ set_rel_width(Query *root, RelOptInfo *rel)
int32 tuple_width = 0; int32 tuple_width = 0;
List *tllist; List *tllist;
foreach(tllist, rel->targetlist) foreach(tllist, FastListValue(&rel->reltargetlist))
{ {
TargetEntry *tle = (TargetEntry *) lfirst(tllist); Var *var = (Var *) lfirst(tllist);
int ndx = var->varattno - rel->min_attr;
Oid relid;
int32 item_width; int32 item_width;
/* Assert(IsA(var, Var));
* If it's a Var, try to get statistical info from pg_statistic.
*/ /* The width probably hasn't been cached yet, but may as well check */
if (tle->expr && IsA(tle->expr, Var)) if (rel->attr_widths[ndx] > 0)
{ {
Var *var = (Var *) tle->expr; tuple_width += rel->attr_widths[ndx];
Oid relid; continue;
}
relid = getrelid(var->varno, root->rtable); relid = getrelid(var->varno, root->rtable);
if (relid != InvalidOid) if (relid != InvalidOid)
{
item_width = get_attavgwidth(relid, var->varattno);
if (item_width > 0)
{ {
item_width = get_attavgwidth(relid, var->varattno); rel->attr_widths[ndx] = item_width;
if (item_width > 0) tuple_width += item_width;
{ continue;
tuple_width += item_width;
continue;
}
} }
} }
/* /*
* Not a Var, or can't find statistics for it. Estimate using * Not a plain relation, or can't find statistics for it.
* just the type info. * Estimate using just the type info.
*/ */
item_width = get_typavgwidth(tle->resdom->restype, item_width = get_typavgwidth(var->vartype, var->vartypmod);
tle->resdom->restypmod);
Assert(item_width > 0); Assert(item_width > 0);
rel->attr_widths[ndx] = item_width;
tuple_width += item_width; tuple_width += item_width;
} }
Assert(tuple_width >= 0); Assert(tuple_width >= 0);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.49 2003/05/28 16:03:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.50 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -703,20 +703,18 @@ find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno) ...@@ -703,20 +703,18 @@ find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno)
vartypeid; vartypeid;
int32 type_mod; int32 type_mod;
foreach(temp, rel->targetlist) foreach(temp, FastListValue(&rel->reltargetlist))
{ {
Var *tle_var = (Var *) ((TargetEntry *) lfirst(temp))->expr; Var *var = (Var *) lfirst(temp);
if (IsA(tle_var, Var) && if (IsA(var, Var) &&
tle_var->varattno == varattno) var->varattno == varattno)
return tle_var; return var;
} }
relid = rel->relid; relid = rel->relid;
Assert(relid > 0);
reloid = getrelid(relid, root->rtable); reloid = getrelid(relid, root->rtable);
vartypeid = get_atttype(reloid, varattno); get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod);
type_mod = get_atttypmod(reloid, varattno);
return makeVar(relid, varattno, vartypeid, type_mod, 0); return makeVar(relid, varattno, vartypeid, type_mod, 0);
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.146 2003/06/16 02:03:37 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.147 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
#include "optimizer/plancat.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h" #include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h" #include "optimizer/tlist.h"
...@@ -34,6 +35,7 @@ ...@@ -34,6 +35,7 @@
static Scan *create_scan_plan(Query *root, Path *best_path); static Scan *create_scan_plan(Query *root, Path *best_path);
static List *build_relation_tlist(RelOptInfo *rel);
static bool use_physical_tlist(RelOptInfo *rel); static bool use_physical_tlist(RelOptInfo *rel);
static void disuse_physical_tlist(Plan *plan, Path *path); static void disuse_physical_tlist(Plan *plan, Path *path);
static Join *create_join_plan(Query *root, JoinPath *best_path); static Join *create_join_plan(Query *root, JoinPath *best_path);
...@@ -199,20 +201,13 @@ create_scan_plan(Query *root, Path *best_path) ...@@ -199,20 +201,13 @@ create_scan_plan(Query *root, Path *best_path)
*/ */
if (use_physical_tlist(rel)) if (use_physical_tlist(rel))
{ {
int resdomno = 1; tlist = build_physical_tlist(root, rel);
List *v; /* if fail because of dropped cols, use regular method */
if (tlist == NIL)
tlist = NIL; tlist = build_relation_tlist(rel);
foreach(v, rel->varlist)
{
Var *var = (Var *) lfirst(v);
tlist = lappend(tlist, create_tl_element(var, resdomno));
resdomno++;
}
} }
else else
tlist = rel->targetlist; tlist = build_relation_tlist(rel);
/* /*
* Extract the relevant restriction clauses from the parent relation; * Extract the relevant restriction clauses from the parent relation;
...@@ -266,6 +261,28 @@ create_scan_plan(Query *root, Path *best_path) ...@@ -266,6 +261,28 @@ create_scan_plan(Query *root, Path *best_path)
return plan; return plan;
} }
/*
* Build a target list (ie, a list of TargetEntry) for a relation.
*/
static List *
build_relation_tlist(RelOptInfo *rel)
{
FastList tlist;
int resdomno = 1;
List *v;
FastListInit(&tlist);
foreach(v, FastListValue(&rel->reltargetlist))
{
/* Do we really need to copy here? Not sure */
Var *var = (Var *) copyObject(lfirst(v));
FastAppend(&tlist, create_tl_element(var, resdomno));
resdomno++;
}
return FastListValue(&tlist);
}
/* /*
* use_physical_tlist * use_physical_tlist
* Decide whether to use a tlist matching relation structure, * Decide whether to use a tlist matching relation structure,
...@@ -274,12 +291,12 @@ create_scan_plan(Query *root, Path *best_path) ...@@ -274,12 +291,12 @@ create_scan_plan(Query *root, Path *best_path)
static bool static bool
use_physical_tlist(RelOptInfo *rel) use_physical_tlist(RelOptInfo *rel)
{ {
List *t; int i;
/* /*
* Currently, can't do this for subquery or function scans. (This * Currently, can't do this for subquery or function scans. (This
* is mainly because we don't set up the necessary info when creating * is mainly because we don't have an equivalent of build_physical_tlist
* their RelOptInfo nodes.) * for them; worth adding?)
*/ */
if (rel->rtekind != RTE_RELATION) if (rel->rtekind != RTE_RELATION)
return false; return false;
...@@ -289,26 +306,15 @@ use_physical_tlist(RelOptInfo *rel) ...@@ -289,26 +306,15 @@ use_physical_tlist(RelOptInfo *rel)
*/ */
if (rel->reloptkind != RELOPT_BASEREL) if (rel->reloptkind != RELOPT_BASEREL)
return false; return false;
/*
* Can't do it if relation contains dropped columns. This is detected
* in plancat.c, see notes there.
*/
if (rel->varlist == NIL)
return false;
/* /*
* Can't do it if any system columns are requested, either. (This could * Can't do it if any system columns are requested, either. (This could
* possibly be fixed but would take some fragile assumptions in setrefs.c, * possibly be fixed but would take some fragile assumptions in setrefs.c,
* I think.) * I think.)
*/ */
foreach(t, rel->targetlist) for (i = rel->min_attr; i <= 0; i++)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(t); if (!bms_is_empty(rel->attr_needed[i - rel->min_attr]))
Var *var = (Var *) tle->expr; return false;
if (!var || !IsA(var, Var))
return false; /* probably can't happen */
if (var->varattno <= 0)
return false; /* system column! */
} }
return true; return true;
} }
...@@ -333,7 +339,7 @@ disuse_physical_tlist(Plan *plan, Path *path) ...@@ -333,7 +339,7 @@ disuse_physical_tlist(Plan *plan, Path *path)
case T_TidScan: case T_TidScan:
case T_SubqueryScan: case T_SubqueryScan:
case T_FunctionScan: case T_FunctionScan:
plan->targetlist = path->parent->targetlist; plan->targetlist = build_relation_tlist(path->parent);
break; break;
default: default:
break; break;
...@@ -411,7 +417,7 @@ static Append * ...@@ -411,7 +417,7 @@ static Append *
create_append_plan(Query *root, AppendPath *best_path) create_append_plan(Query *root, AppendPath *best_path)
{ {
Append *plan; Append *plan;
List *tlist = best_path->path.parent->targetlist; List *tlist = build_relation_tlist(best_path->path.parent);
List *subplans = NIL; List *subplans = NIL;
List *subpaths; List *subpaths;
...@@ -443,7 +449,7 @@ create_result_plan(Query *root, ResultPath *best_path) ...@@ -443,7 +449,7 @@ create_result_plan(Query *root, ResultPath *best_path)
Plan *subplan; Plan *subplan;
if (best_path->path.parent) if (best_path->path.parent)
tlist = best_path->path.parent->targetlist; tlist = build_relation_tlist(best_path->path.parent);
else else
tlist = NIL; /* will be filled in later */ tlist = NIL; /* will be filled in later */
...@@ -842,7 +848,7 @@ create_nestloop_plan(Query *root, ...@@ -842,7 +848,7 @@ create_nestloop_plan(Query *root,
Plan *outer_plan, Plan *outer_plan,
Plan *inner_plan) Plan *inner_plan)
{ {
List *tlist = best_path->path.parent->targetlist; List *tlist = build_relation_tlist(best_path->path.parent);
List *joinrestrictclauses = best_path->joinrestrictinfo; List *joinrestrictclauses = best_path->joinrestrictinfo;
List *joinclauses; List *joinclauses;
List *otherclauses; List *otherclauses;
...@@ -912,7 +918,7 @@ create_mergejoin_plan(Query *root, ...@@ -912,7 +918,7 @@ create_mergejoin_plan(Query *root,
Plan *outer_plan, Plan *outer_plan,
Plan *inner_plan) Plan *inner_plan)
{ {
List *tlist = best_path->jpath.path.parent->targetlist; List *tlist = build_relation_tlist(best_path->jpath.path.parent);
List *joinclauses; List *joinclauses;
List *otherclauses; List *otherclauses;
List *mergeclauses; List *mergeclauses;
...@@ -992,7 +998,7 @@ create_hashjoin_plan(Query *root, ...@@ -992,7 +998,7 @@ create_hashjoin_plan(Query *root,
Plan *outer_plan, Plan *outer_plan,
Plan *inner_plan) Plan *inner_plan)
{ {
List *tlist = best_path->jpath.path.parent->targetlist; List *tlist = build_relation_tlist(best_path->jpath.path.parent);
List *joinclauses; List *joinclauses;
List *otherclauses; List *otherclauses;
List *hashclauses; List *hashclauses;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.85 2003/03/02 23:46:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.86 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,7 +40,8 @@ static void distribute_qual_to_rels(Query *root, Node *clause, ...@@ -40,7 +40,8 @@ static void distribute_qual_to_rels(Query *root, Node *clause,
bool isdeduced, bool isdeduced,
Relids outerjoin_nonnullable, Relids outerjoin_nonnullable,
Relids qualscope); Relids qualscope);
static void add_vars_to_targetlist(Query *root, List *vars); static void add_vars_to_targetlist(Query *root, List *vars,
Relids where_needed);
static bool qual_is_redundant(Query *root, RestrictInfo *restrictinfo, static bool qual_is_redundant(Query *root, RestrictInfo *restrictinfo,
List *restrictlist); List *restrictlist);
static void check_mergejoinable(RestrictInfo *restrictinfo); static void check_mergejoinable(RestrictInfo *restrictinfo);
...@@ -112,34 +113,54 @@ add_base_rels_to_query(Query *root, Node *jtnode) ...@@ -112,34 +113,54 @@ add_base_rels_to_query(Query *root, Node *jtnode)
/* /*
* build_base_rel_tlists * build_base_rel_tlists
* Creates targetlist entries for each var seen in 'tlist' and adds * Add targetlist entries for each var needed in the query's final tlist
* them to the tlist of the appropriate rel node. * to the appropriate base relations.
*
* We mark such vars as needed by "relation 0" to ensure that they will
* propagate up through all join plan steps.
*/ */
void void
build_base_rel_tlists(Query *root, List *tlist) build_base_rel_tlists(Query *root, List *final_tlist)
{ {
List *tlist_vars = pull_var_clause((Node *) tlist, false); List *tlist_vars = pull_var_clause((Node *) final_tlist, false);
add_vars_to_targetlist(root, tlist_vars); if (tlist_vars != NIL)
freeList(tlist_vars); {
add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0));
freeList(tlist_vars);
}
} }
/* /*
* add_vars_to_targetlist * add_vars_to_targetlist
* For each variable appearing in the list, add it to the owning * For each variable appearing in the list, add it to the owning
* relation's targetlist if not already present. * relation's targetlist if not already present, and mark the variable
* as being needed for the indicated join (or for final output if
* where_needed includes "relation 0").
*/ */
static void static void
add_vars_to_targetlist(Query *root, List *vars) add_vars_to_targetlist(Query *root, List *vars, Relids where_needed)
{ {
List *temp; List *temp;
Assert(!bms_is_empty(where_needed));
foreach(temp, vars) foreach(temp, vars)
{ {
Var *var = (Var *) lfirst(temp); Var *var = (Var *) lfirst(temp);
RelOptInfo *rel = find_base_rel(root, var->varno); RelOptInfo *rel = find_base_rel(root, var->varno);
int attrno = var->varattno;
add_var_to_tlist(rel, var); Assert(attrno >= rel->min_attr && attrno <= rel->max_attr);
attrno -= rel->min_attr;
if (bms_is_empty(rel->attr_needed[attrno]))
{
/* Variable not yet requested, so add to reltargetlist */
/* XXX is copyObject necessary here? */
FastAppend(&rel->reltargetlist, copyObject(var));
}
rel->attr_needed[attrno] = bms_add_members(rel->attr_needed[attrno],
where_needed);
} }
} }
...@@ -575,7 +596,7 @@ distribute_qual_to_rels(Query *root, Node *clause, ...@@ -575,7 +596,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
* scan those relations (else they won't be available at the join * scan those relations (else they won't be available at the join
* node!). * node!).
*/ */
add_vars_to_targetlist(root, vars); add_vars_to_targetlist(root, vars, relids);
break; break;
default: default:
/* /*
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.96 2003/06/16 02:03:37 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.97 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -800,6 +800,7 @@ adjust_inherited_attrs_mutator(Node *node, ...@@ -800,6 +800,7 @@ adjust_inherited_attrs_mutator(Node *node,
var->varno == context->old_rt_index) var->varno == context->old_rt_index)
{ {
var->varno = context->new_rt_index; var->varno = context->new_rt_index;
var->varnoold = context->new_rt_index;
if (var->varattno > 0) if (var->varattno > 0)
{ {
char *attname = get_attname(context->old_relid, char *attname = get_attname(context->old_relid,
...@@ -809,6 +810,7 @@ adjust_inherited_attrs_mutator(Node *node, ...@@ -809,6 +810,7 @@ adjust_inherited_attrs_mutator(Node *node,
if (var->varattno == InvalidAttrNumber) if (var->varattno == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"", elog(ERROR, "Relation \"%s\" has no column \"%s\"",
get_rel_name(context->new_relid), attname); get_rel_name(context->new_relid), attname);
var->varoattno = var->varattno;
pfree(attname); pfree(attname);
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.90 2003/06/15 22:51:45 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.91 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -581,7 +581,7 @@ create_unique_path(Query *root, RelOptInfo *rel, Path *subpath) ...@@ -581,7 +581,7 @@ create_unique_path(Query *root, RelOptInfo *rel, Path *subpath)
else else
{ {
pathnode->rows = rel->rows; pathnode->rows = rel->rows;
numCols = length(rel->targetlist); /* second-best estimate */ numCols = length(FastListValue(&rel->reltargetlist));
} }
/* /*
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.83 2003/05/28 16:03:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.84 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "rewrite/rewriteManip.h" #include "rewrite/rewriteManip.h"
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -44,7 +45,8 @@ ...@@ -44,7 +45,8 @@
* Given the Oid of the relation, return the following info into fields * Given the Oid of the relation, return the following info into fields
* of the RelOptInfo struct: * of the RelOptInfo struct:
* *
* varlist list of physical columns (expressed as Vars) * min_attr lowest valid AttrNumber
* max_attr highest valid AttrNumber
* indexlist list of IndexOptInfos for relation's indexes * indexlist list of IndexOptInfos for relation's indexes
* pages number of pages * pages number of pages
* tuples number of tuples * tuples number of tuples
...@@ -52,49 +54,15 @@ ...@@ -52,49 +54,15 @@
void void
get_relation_info(Oid relationObjectId, RelOptInfo *rel) get_relation_info(Oid relationObjectId, RelOptInfo *rel)
{ {
Relation relation;
Index varno = rel->relid; Index varno = rel->relid;
Relation relation;
bool hasindex; bool hasindex;
List *varlist = NIL;
List *indexinfos = NIL; List *indexinfos = NIL;
int attrno,
numattrs;
relation = heap_open(relationObjectId, AccessShareLock); relation = heap_open(relationObjectId, AccessShareLock);
/* rel->min_attr = FirstLowInvalidHeapAttributeNumber + 1;
* Make list of physical Vars. But if there are any dropped columns, rel->max_attr = RelationGetNumberOfAttributes(relation);
* punt and set varlist to NIL. (XXX Ideally we would like to include
* dropped columns so that the varlist models the physical tuples
* of the relation. However this creates problems for ExecTypeFromTL,
* which may be asked to build a tupdesc for a tlist that includes vars
* of no-longer-existent types. In theory we could dig out the required
* info from the pg_attribute entries of the relation, but that data is
* not readily available to ExecTypeFromTL. For now, punt and don't
* apply the physical-tlist optimization when there are dropped cols.)
*/
numattrs = RelationGetNumberOfAttributes(relation);
for (attrno = 1; attrno <= numattrs; attrno++)
{
Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1];
if (att_tup->attisdropped)
{
/* found a dropped col, so punt */
varlist = NIL;
break;
}
varlist = lappend(varlist,
makeVar(varno,
attrno,
att_tup->atttypid,
att_tup->atttypmod,
0));
}
rel->varlist = varlist;
/* /*
* Make list of indexes. Ignore indexes on system catalogs if told to. * Make list of indexes. Ignore indexes on system catalogs if told to.
...@@ -199,6 +167,65 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel) ...@@ -199,6 +167,65 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
heap_close(relation, AccessShareLock); heap_close(relation, AccessShareLock);
} }
/*
* build_physical_tlist
*
* Build a targetlist consisting of exactly the relation's user attributes,
* in order. The executor can special-case such tlists to avoid a projection
* step at runtime, so we use such tlists preferentially for scan nodes.
*
* Exception: if there are any dropped columns, we punt and return NIL.
* Ideally we would like to handle the dropped-column case too. However this
* creates problems for ExecTypeFromTL, which may be asked to build a tupdesc
* for a tlist that includes vars of no-longer-existent types. In theory we
* could dig out the required info from the pg_attribute entries of the
* relation, but that data is not readily available to ExecTypeFromTL.
* For now, we don't apply the physical-tlist optimization when there are
* dropped cols.
*/
List *
build_physical_tlist(Query *root, RelOptInfo *rel)
{
Index varno = rel->relid;
RangeTblEntry *rte = rt_fetch(varno, root->rtable);
Relation relation;
FastList tlist;
int attrno,
numattrs;
FastListInit(&tlist);
Assert(rte->rtekind == RTE_RELATION);
relation = heap_open(rte->relid, AccessShareLock);
numattrs = RelationGetNumberOfAttributes(relation);
for (attrno = 1; attrno <= numattrs; attrno++)
{
Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1];
if (att_tup->attisdropped)
{
/* found a dropped col, so punt */
FastListInit(&tlist);
break;
}
FastAppend(&tlist,
create_tl_element(makeVar(varno,
attrno,
att_tup->atttypid,
att_tup->atttypmod,
0),
attrno));
}
heap_close(relation, AccessShareLock);
return FastListValue(&tlist);
}
/* /*
* restriction_selectivity * restriction_selectivity
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.48 2003/02/15 20:12:40 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.49 2003/06/29 23:05:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
static RelOptInfo *make_base_rel(Query *root, int relid); static RelOptInfo *make_base_rel(Query *root, int relid);
static List *new_join_tlist(List *tlist, int first_resdomno); static void build_joinrel_tlist(Query *root, RelOptInfo *joinrel);
static List *build_joinrel_restrictlist(Query *root, static List *build_joinrel_restrictlist(Query *root,
RelOptInfo *joinrel, RelOptInfo *joinrel,
RelOptInfo *outer_rel, RelOptInfo *outer_rel,
...@@ -130,7 +130,7 @@ make_base_rel(Query *root, int relid) ...@@ -130,7 +130,7 @@ make_base_rel(Query *root, int relid)
rel->relids = bms_make_singleton(relid); rel->relids = bms_make_singleton(relid);
rel->rows = 0; rel->rows = 0;
rel->width = 0; rel->width = 0;
rel->targetlist = NIL; FastListInit(&rel->reltargetlist);
rel->pathlist = NIL; rel->pathlist = NIL;
rel->cheapest_startup_path = NULL; rel->cheapest_startup_path = NULL;
rel->cheapest_total_path = NULL; rel->cheapest_total_path = NULL;
...@@ -138,7 +138,7 @@ make_base_rel(Query *root, int relid) ...@@ -138,7 +138,7 @@ make_base_rel(Query *root, int relid)
rel->pruneable = true; rel->pruneable = true;
rel->relid = relid; rel->relid = relid;
rel->rtekind = rte->rtekind; rel->rtekind = rte->rtekind;
rel->varlist = NIL; /* min_attr, max_attr, attr_needed, attr_widths are set below */
rel->indexlist = NIL; rel->indexlist = NIL;
rel->pages = 0; rel->pages = 0;
rel->tuples = 0; rel->tuples = 0;
...@@ -160,7 +160,9 @@ make_base_rel(Query *root, int relid) ...@@ -160,7 +160,9 @@ make_base_rel(Query *root, int relid)
break; break;
case RTE_SUBQUERY: case RTE_SUBQUERY:
case RTE_FUNCTION: case RTE_FUNCTION:
/* Subquery or function --- nothing to do here */ /* Subquery or function --- need only set up attr range */
rel->min_attr = 1;
rel->max_attr = length(rte->eref->colnames);
break; break;
default: default:
elog(ERROR, "make_base_rel: unsupported RTE kind %d", elog(ERROR, "make_base_rel: unsupported RTE kind %d",
...@@ -168,6 +170,19 @@ make_base_rel(Query *root, int relid) ...@@ -168,6 +170,19 @@ make_base_rel(Query *root, int relid)
break; break;
} }
if (rel->max_attr >= rel->min_attr)
{
rel->attr_needed = (Relids *)
palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
rel->attr_widths = (int32 *)
palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
}
else
{
rel->attr_needed = NULL;
rel->attr_widths = NULL;
}
return rel; return rel;
} }
...@@ -252,8 +267,6 @@ build_join_rel(Query *root, ...@@ -252,8 +267,6 @@ build_join_rel(Query *root,
{ {
RelOptInfo *joinrel; RelOptInfo *joinrel;
List *restrictlist; List *restrictlist;
List *new_outer_tlist;
List *new_inner_tlist;
/* /*
* See if we already have a joinrel for this set of base rels. * See if we already have a joinrel for this set of base rels.
...@@ -283,7 +296,7 @@ build_join_rel(Query *root, ...@@ -283,7 +296,7 @@ build_join_rel(Query *root,
joinrel->relids = bms_copy(joinrelids); joinrel->relids = bms_copy(joinrelids);
joinrel->rows = 0; joinrel->rows = 0;
joinrel->width = 0; joinrel->width = 0;
joinrel->targetlist = NIL; FastListInit(&joinrel->reltargetlist);
joinrel->pathlist = NIL; joinrel->pathlist = NIL;
joinrel->cheapest_startup_path = NULL; joinrel->cheapest_startup_path = NULL;
joinrel->cheapest_total_path = NULL; joinrel->cheapest_total_path = NULL;
...@@ -291,7 +304,10 @@ build_join_rel(Query *root, ...@@ -291,7 +304,10 @@ build_join_rel(Query *root,
joinrel->pruneable = true; joinrel->pruneable = true;
joinrel->relid = 0; /* indicates not a baserel */ joinrel->relid = 0; /* indicates not a baserel */
joinrel->rtekind = RTE_JOIN; joinrel->rtekind = RTE_JOIN;
joinrel->varlist = NIL; joinrel->min_attr = 0;
joinrel->max_attr = 0;
joinrel->attr_needed = NULL;
joinrel->attr_widths = NULL;
joinrel->indexlist = NIL; joinrel->indexlist = NIL;
joinrel->pages = 0; joinrel->pages = 0;
joinrel->tuples = 0; joinrel->tuples = 0;
...@@ -305,24 +321,10 @@ build_join_rel(Query *root, ...@@ -305,24 +321,10 @@ build_join_rel(Query *root,
joinrel->index_inner_paths = NIL; joinrel->index_inner_paths = NIL;
/* /*
* Create a new tlist by removing irrelevant elements from both tlists * Create a new tlist containing just the vars that need to be output
* of the outer and inner join relations and then merging the results * from this join (ie, are needed for higher joinclauses or final output).
* together.
*
* XXX right now we don't remove any irrelevant elements, we just append
* the two tlists together. Someday consider pruning vars from the
* join's targetlist if they are needed only to evaluate restriction
* clauses of this join, and will never be accessed at higher levels
* of the plantree.
*
* NOTE: the tlist order for a join rel will depend on which pair of
* outer and inner rels we first try to build it from. But the
* contents should be the same regardless.
*/ */
new_outer_tlist = new_join_tlist(outer_rel->targetlist, 1); build_joinrel_tlist(root, joinrel);
new_inner_tlist = new_join_tlist(inner_rel->targetlist,
length(new_outer_tlist) + 1);
joinrel->targetlist = nconc(new_outer_tlist, new_inner_tlist);
/* /*
* Construct restrict and join clause lists for the new joinrel. (The * Construct restrict and join clause lists for the new joinrel. (The
...@@ -353,42 +355,51 @@ build_join_rel(Query *root, ...@@ -353,42 +355,51 @@ build_join_rel(Query *root,
} }
/* /*
* new_join_tlist * build_joinrel_tlist
* Builds a join relation's target list by keeping those elements that * Builds a join relation's target list.
* will be in the final target list and any other elements that are still
* needed for future joins. For a target list entry to still be needed
* for future joins, its 'joinlist' field must not be empty after removal
* of all relids in 'other_relids'.
* *
* XXX the above comment refers to code that is long dead and gone; * The join's targetlist includes all Vars of its member relations that
* we don't keep track of joinlists for individual targetlist entries * will still be needed above the join.
* anymore. For now, all vars present in either input tlist will be
* emitted in the join's tlist.
* *
* 'tlist' is the target list of one of the join relations * In a former lifetime, this just merged the tlists of the two member
* 'first_resdomno' is the resdom number to use for the first created * relations first presented. While we could still do that, working from
* target list entry * lists of Vars would mean doing a find_base_rel lookup for each Var.
* It seems more efficient to scan the list of base rels and collect the
* needed vars directly from there.
* *
* Returns the new target list. * We also compute the expected width of the join's output, making use
* of data that was cached at the baserel level by set_rel_width().
*/ */
static List * static void
new_join_tlist(List *tlist, build_joinrel_tlist(Query *root, RelOptInfo *joinrel)
int first_resdomno)
{ {
int resdomno = first_resdomno - 1; Relids relids = joinrel->relids;
List *t_list = NIL; List *rels;
List *i; List *vars;
FastListInit(&joinrel->reltargetlist);
joinrel->width = 0;
foreach(i, tlist) foreach(rels, root->base_rel_list)
{ {
TargetEntry *tle = lfirst(i); RelOptInfo *baserel = (RelOptInfo *) lfirst(rels);
resdomno += 1; if (!bms_is_member(baserel->relid, relids))
t_list = lappend(t_list, continue;
create_tl_element((Var *) tle->expr, resdomno));
}
return t_list; foreach(vars, FastListValue(&baserel->reltargetlist))
{
Var *var = (Var *) lfirst(vars);
int ndx = var->varattno - baserel->min_attr;
if (bms_nonempty_difference(baserel->attr_needed[ndx], relids))
{
FastAppend(&joinrel->reltargetlist, var);
Assert(baserel->attr_widths[ndx] > 0);
joinrel->width += baserel->attr_widths[ndx];
}
}
}
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.56 2003/05/06 00:20:32 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.57 2003/06/29 23:05:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
/***************************************************************************** /*****************************************************************************
* ---------- RELATION node target list routines ---------- * Target list creation and searching utilities
*****************************************************************************/ *****************************************************************************/
/* /*
...@@ -79,24 +79,6 @@ tlist_member(Node *node, List *targetlist) ...@@ -79,24 +79,6 @@ tlist_member(Node *node, List *targetlist)
return (Resdom *) NULL; return (Resdom *) NULL;
} }
/*
* add_var_to_tlist
* Creates a targetlist entry corresponding to the supplied var node
* 'var' and adds the new targetlist entry to the targetlist field of
* 'rel'. No entry is created if 'var' is already in the tlist.
*/
void
add_var_to_tlist(RelOptInfo *rel, Var *var)
{
if (!tlistentry_member((Node *) var, rel->targetlist))
{
/* XXX is copyObject necessary here? */
rel->targetlist = lappend(rel->targetlist,
create_tl_element((Var *) copyObject(var),
length(rel->targetlist) + 1));
}
}
/* /*
* create_tl_element * create_tl_element
* Creates a target list entry node and its associated (resdom var) pair * Creates a target list entry node and its associated (resdom var) pair
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* Copyright (c) 2003, PostgreSQL Global Development Group * Copyright (c) 2003, PostgreSQL Global Development Group
* *
* $Id: bitmapset.h,v 1.1 2003/02/08 20:20:55 tgl Exp $ * $Id: bitmapset.h,v 1.2 2003/06/29 23:05:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -59,6 +59,7 @@ extern Bitmapset *bms_difference(const Bitmapset *a, const Bitmapset *b); ...@@ -59,6 +59,7 @@ 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 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 int bms_singleton_member(const Bitmapset *a); extern int bms_singleton_member(const Bitmapset *a);
extern int bms_num_members(const Bitmapset *a); extern int bms_num_members(const Bitmapset *a);
/* optimized tests when we don't need to know exact membership count: */ /* optimized tests when we don't need to know exact membership count: */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: relation.h,v 1.81 2003/06/15 22:51:45 tgl Exp $ * $Id: relation.h,v 1.82 2003/06/29 23:05:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -89,8 +89,8 @@ typedef struct QualCost ...@@ -89,8 +89,8 @@ typedef struct QualCost
* clauses have been applied (ie, output rows of a plan for it) * clauses have been applied (ie, output rows of a plan for it)
* width - avg. number of bytes per tuple in the relation after the * width - avg. number of bytes per tuple in the relation after the
* appropriate projections have been done (ie, output width) * appropriate projections have been done (ie, output width)
* targetlist - List of TargetEntry nodes for the attributes we need * reltargetlist - List of Var nodes for the attributes we need to
* to output from this relation * output from this relation (in no particular order)
* pathlist - List of Path nodes, one for each potentially useful * pathlist - List of Path nodes, one for each potentially useful
* method of generating the relation * method of generating the relation
* cheapest_startup_path - the pathlist member with lowest startup cost * cheapest_startup_path - the pathlist member with lowest startup cost
...@@ -107,7 +107,12 @@ typedef struct QualCost ...@@ -107,7 +107,12 @@ typedef struct QualCost
* relid - RTE index (this is redundant with the relids field, but * relid - RTE index (this is redundant with the relids field, but
* is provided for convenience of access) * is provided for convenience of access)
* rtekind - distinguishes plain relation, subquery, or function RTE * rtekind - distinguishes plain relation, subquery, or function RTE
* varlist - list of Vars for physical columns (only if table) * min_attr, max_attr - range of valid AttrNumbers for rel
* attr_needed - array of bitmapsets indicating the highest joinrel
* in which each attribute is needed; if bit 0 is set then
* the attribute is needed as part of final targetlist
* attr_widths - cache space for per-attribute width estimates;
* zero means not computed yet
* indexlist - list of IndexOptInfo nodes for relation's indexes * indexlist - list of IndexOptInfo nodes for relation's indexes
* (always NIL if it's not a table) * (always NIL if it's not a table)
* pages - number of disk pages in relation (zero if not a table) * pages - number of disk pages in relation (zero if not a table)
...@@ -183,7 +188,7 @@ typedef struct RelOptInfo ...@@ -183,7 +188,7 @@ typedef struct RelOptInfo
int width; /* estimated avg width of result tuples */ int width; /* estimated avg width of result tuples */
/* materialization information */ /* materialization information */
List *targetlist; FastList reltargetlist;
List *pathlist; /* Path structures */ List *pathlist; /* Path structures */
struct Path *cheapest_startup_path; struct Path *cheapest_startup_path;
struct Path *cheapest_total_path; struct Path *cheapest_total_path;
...@@ -193,7 +198,10 @@ typedef struct RelOptInfo ...@@ -193,7 +198,10 @@ typedef struct RelOptInfo
/* information about a base rel (not set for join rels!) */ /* information about a base rel (not set for join rels!) */
Index relid; Index relid;
RTEKind rtekind; /* RELATION, SUBQUERY, or FUNCTION */ RTEKind rtekind; /* RELATION, SUBQUERY, or FUNCTION */
List *varlist; AttrNumber min_attr; /* smallest attrno of rel (often <0) */
AttrNumber max_attr; /* largest attrno of rel */
Relids *attr_needed; /* array indexed [min_attr .. max_attr] */
int32 *attr_widths; /* array indexed [min_attr .. max_attr] */
List *indexlist; List *indexlist;
long pages; long pages;
double tuples; double tuples;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: plancat.h,v 1.29 2003/02/03 15:07:08 tgl Exp $ * $Id: plancat.h,v 1.30 2003/06/29 23:05:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
extern void get_relation_info(Oid relationObjectId, RelOptInfo *rel); extern void get_relation_info(Oid relationObjectId, RelOptInfo *rel);
extern List *build_physical_tlist(Query *root, RelOptInfo *rel);
extern List *find_inheritance_children(Oid inhparent); extern List *find_inheritance_children(Oid inhparent);
extern bool has_subclass(Oid relationId); extern bool has_subclass(Oid relationId);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: planmain.h,v 1.71 2003/06/29 00:33:44 tgl Exp $ * $Id: planmain.h,v 1.72 2003/06/29 23:05:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,7 +56,7 @@ extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); ...@@ -56,7 +56,7 @@ extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
* prototypes for plan/initsplan.c * prototypes for plan/initsplan.c
*/ */
extern void add_base_rels_to_query(Query *root, Node *jtnode); extern void add_base_rels_to_query(Query *root, Node *jtnode);
extern void build_base_rel_tlists(Query *root, List *tlist); extern void build_base_rel_tlists(Query *root, List *final_tlist);
extern Relids distribute_quals_to_rels(Query *root, Node *jtnode); extern Relids distribute_quals_to_rels(Query *root, Node *jtnode);
extern void process_implied_equality(Query *root, extern void process_implied_equality(Query *root,
Node *item1, Node *item2, Node *item1, Node *item2,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: tlist.h,v 1.35 2003/05/06 00:20:33 tgl Exp $ * $Id: tlist.h,v 1.36 2003/06/29 23:05:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
#include "nodes/relation.h" #include "nodes/relation.h"
extern TargetEntry *tlistentry_member(Node *node, List *targetlist); extern TargetEntry *tlistentry_member(Node *node, List *targetlist);
extern Resdom *tlist_member(Node *node, List *targetlist); extern Resdom *tlist_member(Node *node, List *targetlist);
extern void add_var_to_tlist(RelOptInfo *rel, Var *var);
extern TargetEntry *create_tl_element(Var *var, int resdomno); extern TargetEntry *create_tl_element(Var *var, int resdomno);
extern List *flatten_tlist(List *tlist); extern List *flatten_tlist(List *tlist);
......
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