aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/bitmapset.c32
-rw-r--r--src/backend/optimizer/path/allpaths.c35
-rw-r--r--src/backend/optimizer/path/costsize.c60
-rw-r--r--src/backend/optimizer/path/pathkeys.c16
-rw-r--r--src/backend/optimizer/plan/createplan.c78
-rw-r--r--src/backend/optimizer/plan/initsplan.c45
-rw-r--r--src/backend/optimizer/prep/prepunion.c4
-rw-r--r--src/backend/optimizer/util/pathnode.c4
-rw-r--r--src/backend/optimizer/util/plancat.c105
-rw-r--r--src/backend/optimizer/util/relnode.c117
-rw-r--r--src/backend/optimizer/util/tlist.c22
-rw-r--r--src/include/nodes/bitmapset.h3
-rw-r--r--src/include/nodes/relation.h20
-rw-r--r--src/include/optimizer/plancat.h4
-rw-r--r--src/include/optimizer/planmain.h4
-rw-r--r--src/include/optimizer/tlist.h4
16 files changed, 333 insertions, 220 deletions
diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index 5798b726497..45c6ead0fc0 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -14,7 +14,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -389,6 +389,36 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b)
}
/*
+ * 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
*
* Raises error if |a| is not 1.
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index e6791dddd69..cd04af9f821 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* 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,
RangeTblEntry *childrte;
Oid childOID;
RelOptInfo *childrel;
+ List *reltlist;
+ List *parentvars;
+ List *childvars;
childrte = rt_fetch(childRTindex, root->rtable);
childOID = childrte->relid;
@@ -251,21 +254,24 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
* Copy the parent's targetlist and restriction quals to the
* child, with attribute-number adjustment as needed. We don't
* 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 *)
- adjust_inherited_attrs((Node *) rel->targetlist,
+ reltlist = FastListValue(&rel->reltargetlist);
+ reltlist = (List *)
+ adjust_inherited_attrs((Node *) reltlist,
parentRTindex,
parentOID,
childRTindex,
childOID);
+ FastListFromList(&childrel->reltargetlist, reltlist);
+ childrel->attr_needed = NULL;
childrel->baserestrictinfo = (List *)
adjust_inherited_attrs((Node *) rel->baserestrictinfo,
parentRTindex,
parentOID,
childRTindex,
childOID);
- childrel->baserestrictcost = rel->baserestrictcost;
/*
* Now compute child access paths, and save the cheapest.
@@ -274,10 +280,27 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
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;
if (childrel->width > rel->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);
+ }
}
/*
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 283987b63d5..34a3aaf1c94 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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,
rel->rows = temp;
/*
- * We could apply set_rel_width() to compute the output tuple width
- * from scratch, but at present it's always just the sum of the input
- * 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.
+ * We need not compute the output width here, because build_joinrel_tlist
+ * already did.
*/
- rel->width = outer_rel->width + inner_rel->width;
}
/*
@@ -1858,13 +1854,16 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
/*
* 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
* 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
* about subqueries?
+ *
+ * The per-attribute width estimates are cached for possible re-use while
+ * building join relations.
*/
static void
set_rel_width(Query *root, RelOptInfo *rel)
@@ -1872,38 +1871,41 @@ set_rel_width(Query *root, RelOptInfo *rel)
int32 tuple_width = 0;
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;
- /*
- * If it's a Var, try to get statistical info from pg_statistic.
- */
- if (tle->expr && IsA(tle->expr, Var))
+ Assert(IsA(var, Var));
+
+ /* The width probably hasn't been cached yet, but may as well check */
+ if (rel->attr_widths[ndx] > 0)
{
- Var *var = (Var *) tle->expr;
- Oid relid;
+ tuple_width += rel->attr_widths[ndx];
+ continue;
+ }
- relid = getrelid(var->varno, root->rtable);
- if (relid != InvalidOid)
+ relid = getrelid(var->varno, root->rtable);
+ if (relid != InvalidOid)
+ {
+ item_width = get_attavgwidth(relid, var->varattno);
+ if (item_width > 0)
{
- item_width = get_attavgwidth(relid, var->varattno);
- if (item_width > 0)
- {
- tuple_width += item_width;
- continue;
- }
+ rel->attr_widths[ndx] = item_width;
+ tuple_width += item_width;
+ continue;
}
}
/*
- * Not a Var, or can't find statistics for it. Estimate using
- * just the type info.
+ * Not a plain relation, or can't find statistics for it.
+ * Estimate using just the type info.
*/
- item_width = get_typavgwidth(tle->resdom->restype,
- tle->resdom->restypmod);
+ item_width = get_typavgwidth(var->vartype, var->vartypmod);
Assert(item_width > 0);
+ rel->attr_widths[ndx] = item_width;
tuple_width += item_width;
}
Assert(tuple_width >= 0);
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index f8e4906c13b..d4d1179d545 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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)
vartypeid;
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) &&
- tle_var->varattno == varattno)
- return tle_var;
+ if (IsA(var, Var) &&
+ var->varattno == varattno)
+ return var;
}
relid = rel->relid;
- Assert(relid > 0);
reloid = getrelid(relid, root->rtable);
- vartypeid = get_atttype(reloid, varattno);
- type_mod = get_atttypmod(reloid, varattno);
+ get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod);
return makeVar(relid, varattno, vartypeid, type_mod, 0);
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 81ee7962df9..1cdc3628b20 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* 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 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
+#include "optimizer/plancat.h"
#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
@@ -34,6 +35,7 @@
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 void disuse_physical_tlist(Plan *plan, Path *path);
static Join *create_join_plan(Query *root, JoinPath *best_path);
@@ -199,20 +201,13 @@ create_scan_plan(Query *root, Path *best_path)
*/
if (use_physical_tlist(rel))
{
- int resdomno = 1;
- List *v;
-
- tlist = NIL;
- foreach(v, rel->varlist)
- {
- Var *var = (Var *) lfirst(v);
-
- tlist = lappend(tlist, create_tl_element(var, resdomno));
- resdomno++;
- }
+ tlist = build_physical_tlist(root, rel);
+ /* if fail because of dropped cols, use regular method */
+ if (tlist == NIL)
+ tlist = build_relation_tlist(rel);
}
else
- tlist = rel->targetlist;
+ tlist = build_relation_tlist(rel);
/*
* Extract the relevant restriction clauses from the parent relation;
@@ -267,6 +262,28 @@ create_scan_plan(Query *root, Path *best_path)
}
/*
+ * 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
* Decide whether to use a tlist matching relation structure,
* rather than only those Vars actually referenced.
@@ -274,12 +291,12 @@ create_scan_plan(Query *root, Path *best_path)
static bool
use_physical_tlist(RelOptInfo *rel)
{
- List *t;
+ int i;
/*
* Currently, can't do this for subquery or function scans. (This
- * is mainly because we don't set up the necessary info when creating
- * their RelOptInfo nodes.)
+ * is mainly because we don't have an equivalent of build_physical_tlist
+ * for them; worth adding?)
*/
if (rel->rtekind != RTE_RELATION)
return false;
@@ -290,25 +307,14 @@ use_physical_tlist(RelOptInfo *rel)
if (rel->reloptkind != RELOPT_BASEREL)
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
* possibly be fixed but would take some fragile assumptions in setrefs.c,
* I think.)
*/
- foreach(t, rel->targetlist)
+ for (i = rel->min_attr; i <= 0; i++)
{
- TargetEntry *tle = (TargetEntry *) lfirst(t);
- Var *var = (Var *) tle->expr;
-
- if (!var || !IsA(var, Var))
- return false; /* probably can't happen */
- if (var->varattno <= 0)
- return false; /* system column! */
+ if (!bms_is_empty(rel->attr_needed[i - rel->min_attr]))
+ return false;
}
return true;
}
@@ -333,7 +339,7 @@ disuse_physical_tlist(Plan *plan, Path *path)
case T_TidScan:
case T_SubqueryScan:
case T_FunctionScan:
- plan->targetlist = path->parent->targetlist;
+ plan->targetlist = build_relation_tlist(path->parent);
break;
default:
break;
@@ -411,7 +417,7 @@ static Append *
create_append_plan(Query *root, AppendPath *best_path)
{
Append *plan;
- List *tlist = best_path->path.parent->targetlist;
+ List *tlist = build_relation_tlist(best_path->path.parent);
List *subplans = NIL;
List *subpaths;
@@ -443,7 +449,7 @@ create_result_plan(Query *root, ResultPath *best_path)
Plan *subplan;
if (best_path->path.parent)
- tlist = best_path->path.parent->targetlist;
+ tlist = build_relation_tlist(best_path->path.parent);
else
tlist = NIL; /* will be filled in later */
@@ -842,7 +848,7 @@ create_nestloop_plan(Query *root,
Plan *outer_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 *joinclauses;
List *otherclauses;
@@ -912,7 +918,7 @@ create_mergejoin_plan(Query *root,
Plan *outer_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 *otherclauses;
List *mergeclauses;
@@ -992,7 +998,7 @@ create_hashjoin_plan(Query *root,
Plan *outer_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 *otherclauses;
List *hashclauses;
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 05d963d94c1..cbc1ff365a3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
*
*
* 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,
bool isdeduced,
Relids outerjoin_nonnullable,
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,
List *restrictlist);
static void check_mergejoinable(RestrictInfo *restrictinfo);
@@ -112,34 +113,54 @@ add_base_rels_to_query(Query *root, Node *jtnode)
/*
* build_base_rel_tlists
- * Creates targetlist entries for each var seen in 'tlist' and adds
- * them to the tlist of the appropriate rel node.
+ * Add targetlist entries for each var needed in the query's final tlist
+ * 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
-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);
- freeList(tlist_vars);
+ if (tlist_vars != NIL)
+ {
+ add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0));
+ freeList(tlist_vars);
+ }
}
/*
* add_vars_to_targetlist
* 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
-add_vars_to_targetlist(Query *root, List *vars)
+add_vars_to_targetlist(Query *root, List *vars, Relids where_needed)
{
List *temp;
+ Assert(!bms_is_empty(where_needed));
+
foreach(temp, vars)
{
Var *var = (Var *) lfirst(temp);
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,
* scan those relations (else they won't be available at the join
* node!).
*/
- add_vars_to_targetlist(root, vars);
+ add_vars_to_targetlist(root, vars, relids);
break;
default:
/*
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index ac6e0f0f352..03674e8990f 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -14,7 +14,7 @@
*
*
* 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,
var->varno == context->old_rt_index)
{
var->varno = context->new_rt_index;
+ var->varnoold = context->new_rt_index;
if (var->varattno > 0)
{
char *attname = get_attname(context->old_relid,
@@ -809,6 +810,7 @@ adjust_inherited_attrs_mutator(Node *node,
if (var->varattno == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
get_rel_name(context->new_relid), attname);
+ var->varoattno = var->varattno;
pfree(attname);
}
}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index da9497d58a4..9e919079ccf 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -8,7 +8,7 @@
*
*
* 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)
else
{
pathnode->rows = rel->rows;
- numCols = length(rel->targetlist); /* second-best estimate */
+ numCols = length(FastListValue(&rel->reltargetlist));
}
/*
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 36223be93fd..3f4fe661717 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* 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 @@
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/plancat.h"
+#include "optimizer/tlist.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
@@ -44,7 +45,8 @@
* Given the Oid of the relation, return the following info into fields
* 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
* pages number of pages
* tuples number of tuples
@@ -52,49 +54,15 @@
void
get_relation_info(Oid relationObjectId, RelOptInfo *rel)
{
- Relation relation;
Index varno = rel->relid;
+ Relation relation;
bool hasindex;
- List *varlist = NIL;
List *indexinfos = NIL;
- int attrno,
- numattrs;
relation = heap_open(relationObjectId, AccessShareLock);
- /*
- * Make list of physical Vars. But if there are any dropped columns,
- * 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;
+ rel->min_attr = FirstLowInvalidHeapAttributeNumber + 1;
+ rel->max_attr = RelationGetNumberOfAttributes(relation);
/*
* Make list of indexes. Ignore indexes on system catalogs if told to.
@@ -200,6 +168,65 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
}
/*
+ * 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
*
* Returns the selectivity of a specified restriction operator clause.
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index af44cb7f206..0b82569ba37 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* 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 @@
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,
RelOptInfo *joinrel,
RelOptInfo *outer_rel,
@@ -130,7 +130,7 @@ make_base_rel(Query *root, int relid)
rel->relids = bms_make_singleton(relid);
rel->rows = 0;
rel->width = 0;
- rel->targetlist = NIL;
+ FastListInit(&rel->reltargetlist);
rel->pathlist = NIL;
rel->cheapest_startup_path = NULL;
rel->cheapest_total_path = NULL;
@@ -138,7 +138,7 @@ make_base_rel(Query *root, int relid)
rel->pruneable = true;
rel->relid = relid;
rel->rtekind = rte->rtekind;
- rel->varlist = NIL;
+ /* min_attr, max_attr, attr_needed, attr_widths are set below */
rel->indexlist = NIL;
rel->pages = 0;
rel->tuples = 0;
@@ -160,7 +160,9 @@ make_base_rel(Query *root, int relid)
break;
case RTE_SUBQUERY:
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;
default:
elog(ERROR, "make_base_rel: unsupported RTE kind %d",
@@ -168,6 +170,19 @@ make_base_rel(Query *root, int relid)
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;
}
@@ -252,8 +267,6 @@ build_join_rel(Query *root,
{
RelOptInfo *joinrel;
List *restrictlist;
- List *new_outer_tlist;
- List *new_inner_tlist;
/*
* See if we already have a joinrel for this set of base rels.
@@ -283,7 +296,7 @@ build_join_rel(Query *root,
joinrel->relids = bms_copy(joinrelids);
joinrel->rows = 0;
joinrel->width = 0;
- joinrel->targetlist = NIL;
+ FastListInit(&joinrel->reltargetlist);
joinrel->pathlist = NIL;
joinrel->cheapest_startup_path = NULL;
joinrel->cheapest_total_path = NULL;
@@ -291,7 +304,10 @@ build_join_rel(Query *root,
joinrel->pruneable = true;
joinrel->relid = 0; /* indicates not a baserel */
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->pages = 0;
joinrel->tuples = 0;
@@ -305,24 +321,10 @@ build_join_rel(Query *root,
joinrel->index_inner_paths = NIL;
/*
- * Create a new tlist by removing irrelevant elements from both tlists
- * of the outer and inner join relations and then merging the results
- * 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.
+ * Create a new tlist containing just the vars that need to be output
+ * from this join (ie, are needed for higher joinclauses or final output).
*/
- new_outer_tlist = new_join_tlist(outer_rel->targetlist, 1);
- new_inner_tlist = new_join_tlist(inner_rel->targetlist,
- length(new_outer_tlist) + 1);
- joinrel->targetlist = nconc(new_outer_tlist, new_inner_tlist);
+ build_joinrel_tlist(root, joinrel);
/*
* Construct restrict and join clause lists for the new joinrel. (The
@@ -353,42 +355,51 @@ build_join_rel(Query *root,
}
/*
- * new_join_tlist
- * Builds a join relation's target list by keeping those elements that
- * 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'.
+ * build_joinrel_tlist
+ * Builds a join relation's target list.
*
- * XXX the above comment refers to code that is long dead and gone;
- * we don't keep track of joinlists for individual targetlist entries
- * anymore. For now, all vars present in either input tlist will be
- * emitted in the join's tlist.
+ * The join's targetlist includes all Vars of its member relations that
+ * will still be needed above the join.
*
- * 'tlist' is the target list of one of the join relations
- * 'first_resdomno' is the resdom number to use for the first created
- * target list entry
+ * In a former lifetime, this just merged the tlists of the two member
+ * relations first presented. While we could still do that, working from
+ * 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 *
-new_join_tlist(List *tlist,
- int first_resdomno)
+static void
+build_joinrel_tlist(Query *root, RelOptInfo *joinrel)
{
- int resdomno = first_resdomno - 1;
- List *t_list = NIL;
- List *i;
+ Relids relids = joinrel->relids;
+ List *rels;
+ 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;
- t_list = lappend(t_list,
- create_tl_element((Var *) tle->expr, resdomno));
- }
+ if (!bms_is_member(baserel->relid, relids))
+ continue;
- 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];
+ }
+ }
+ }
}
/*
diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index 9b10e8e97be..7a4422a3594 100644
--- a/src/backend/optimizer/util/tlist.c
+++ b/src/backend/optimizer/util/tlist.c
@@ -8,7 +8,7 @@
*
*
* 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 @@
/*****************************************************************************
- * ---------- RELATION node target list routines ----------
+ * Target list creation and searching utilities
*****************************************************************************/
/*
@@ -80,24 +80,6 @@ tlist_member(Node *node, List *targetlist)
}
/*
- * 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
* Creates a target list entry node and its associated (resdom var) pair
* with its resdom number equal to 'resdomno'.
diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h
index 4e06d7a284a..7974c44aae7 100644
--- a/src/include/nodes/bitmapset.h
+++ b/src/include/nodes/bitmapset.h
@@ -13,7 +13,7 @@
*
* 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);
extern bool bms_is_subset(const Bitmapset *a, const Bitmapset *b);
extern bool bms_is_member(int x, const Bitmapset *a);
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_num_members(const Bitmapset *a);
/* optimized tests when we don't need to know exact membership count: */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 8392ab505bd..2ab9e0f6e7f 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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
* clauses have been applied (ie, output rows of a plan for it)
* width - avg. number of bytes per tuple in the relation after the
* appropriate projections have been done (ie, output width)
- * targetlist - List of TargetEntry nodes for the attributes we need
- * to output from this relation
+ * reltargetlist - List of Var nodes for the attributes we need to
+ * output from this relation (in no particular order)
* pathlist - List of Path nodes, one for each potentially useful
* method of generating the relation
* cheapest_startup_path - the pathlist member with lowest startup cost
@@ -107,7 +107,12 @@ typedef struct QualCost
* relid - RTE index (this is redundant with the relids field, but
* is provided for convenience of access)
* 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
* (always NIL if it's not a table)
* pages - number of disk pages in relation (zero if not a table)
@@ -183,7 +188,7 @@ typedef struct RelOptInfo
int width; /* estimated avg width of result tuples */
/* materialization information */
- List *targetlist;
+ FastList reltargetlist;
List *pathlist; /* Path structures */
struct Path *cheapest_startup_path;
struct Path *cheapest_total_path;
@@ -193,7 +198,10 @@ typedef struct RelOptInfo
/* information about a base rel (not set for join rels!) */
Index relid;
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;
long pages;
double tuples;
diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h
index c6b18ab0da9..8f7cfbe6ceb 100644
--- a/src/include/optimizer/plancat.h
+++ b/src/include/optimizer/plancat.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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 @@
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 bool has_subclass(Oid relationId);
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 106e9d1ce4b..99c9470493d 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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);
* prototypes for plan/initsplan.c
*/
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 void process_implied_equality(Query *root,
Node *item1, Node *item2,
diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h
index e2afc3ac821..d22c78f8d8e 100644
--- a/src/include/optimizer/tlist.h
+++ b/src/include/optimizer/tlist.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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 @@
#include "nodes/relation.h"
+
extern TargetEntry *tlistentry_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 List *flatten_tlist(List *tlist);