1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-09 06:21:09 +03:00

Major planner/optimizer revision: get rid of PathOrder node type,

store all ordering information in pathkeys lists (which are now lists of
lists of PathKeyItem nodes, not just lists of lists of vars).  This was
a big win --- the code is smaller and IMHO more understandable than it
was, even though it handles more cases.  I believe the node changes will
not force an initdb for anyone; planner nodes don't show up in stored
rules.
This commit is contained in:
Tom Lane
1999-08-16 02:17:58 +00:00
parent 08320bfb22
commit e6381966c1
43 changed files with 1937 additions and 3270 deletions

View File

@@ -4,7 +4,7 @@
# Makefile for optimizer/util
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.8 1999/02/05 19:59:28 momjian Exp $
# $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.9 1999/08/16 02:17:56 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -14,7 +14,7 @@ include ../../../Makefile.global
CFLAGS += -I../..
OBJS = restrictinfo.o clauses.o indexnode.o plancat.o \
joininfo.o keys.o ordering.o pathnode.o relnode.o tlist.o var.o
joininfo.o pathnode.o relnode.o tlist.o var.o
# not ready yet: predmig.o xfunc.o

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.46 1999/08/12 04:32:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.47 1999/08/16 02:17:56 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -164,7 +164,7 @@ make_funcclause(Func *func, List *funcargs)
{
Expr *expr = makeNode(Expr);
expr->typeOid = InvalidOid; /* assume type checking done */
expr->typeOid = func->functype;
expr->opType = FUNC_EXPR;
expr->oper = (Node *) func;
expr->args = funcargs;
@@ -416,43 +416,6 @@ NumRelids(Node *clause)
return result;
}
/*
* is_joinable
*
* Returns t iff 'clause' is a valid join clause.
*
*/
bool
is_joinable(Node *clause)
{
Node *leftop,
*rightop;
if (!is_opclause(clause))
return false;
leftop = (Node *) get_leftop((Expr *) clause);
rightop = (Node *) get_rightop((Expr *) clause);
if (!rightop)
return false; /* unary opclauses need not apply */
/*
* One side of the clause (i.e. left or right operands) must either be
* a var node ...
*/
if (IsA(leftop, Var) || IsA(rightop, Var))
return true;
/*
* ... or a func node.
*/
if (is_funcclause(leftop) || is_funcclause(rightop))
return true;
return false;
}
/*
* fix_opids
* Calculate opid field from opno for each Oper node in given tree.

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.19 1999/07/16 04:59:24 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.20 1999/08/16 02:17:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -39,21 +39,20 @@ find_relation_indices(Query *root, RelOptInfo *rel)
/*
* find_secondary_index
* Creates a list of index path nodes containing information for each
* Creates a list of RelOptInfo nodes containing information for each
* secondary index defined on a relation by searching through the index
* catalog.
*
* 'relid' is the OID of the relation for which indices are being located
*
* Returns a list of new index nodes.
*
* Returns a list of new index RelOptInfo nodes.
*/
static List *
find_secondary_index(Query *root, Oid relid)
{
IdxInfoRetval indexinfo;
List *indexes = NIL;
bool first = TRUE;
bool first = true;
while (index_info(root, first, relid, &indexinfo))
{
@@ -63,9 +62,9 @@ find_secondary_index(Query *root, Oid relid)
indexnode->relam = indexinfo.relam;
indexnode->pages = indexinfo.pages;
indexnode->tuples = indexinfo.tuples;
indexnode->classlist = indexinfo.classlist;
indexnode->indexkeys = indexinfo.indexkeys;
indexnode->ordering = indexinfo.orderOprs;
indexnode->classlist = indexinfo.classlist;
indexnode->indproc = indexinfo.indproc;
indexnode->indpred = (List *) indexinfo.indpred;
@@ -81,7 +80,7 @@ find_secondary_index(Query *root, Oid relid)
indexnode->innerjoin = NIL;
indexes = lcons(indexnode, indexes);
first = FALSE;
first = false;
}
return indexes;

View File

@@ -7,14 +7,13 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.23 1999/07/16 04:59:25 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.24 1999/08/16 02:17:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/clauses.h"
#include "optimizer/joininfo.h"
@@ -51,8 +50,8 @@ joininfo_member(List *join_relids, List *joininfo_list)
/*
* find_joininfo_node
* Find the joininfo node within a relation entry corresponding
* to a join between 'this_rel' and the relations in 'join_relids'. A
* new node is created and added to the relation entry's joininfo
* to a join between 'this_rel' and the relations in 'join_relids'.
* A new node is created and added to the relation entry's joininfo
* field if the desired one can't be found.
*
* Returns a joininfo node.
@@ -69,40 +68,7 @@ find_joininfo_node(RelOptInfo *this_rel, Relids join_relids)
joininfo = makeNode(JoinInfo);
joininfo->unjoined_relids = join_relids;
joininfo->jinfo_restrictinfo = NIL;
joininfo->mergejoinable = false;
joininfo->hashjoinable = false;
this_rel->joininfo = lcons(joininfo, this_rel->joininfo);
}
return joininfo;
}
/*
* other_join_clause_var
* Determines whether a var node is contained within a joinclause
* of the form(op var var).
*
* Returns the other var node in the joinclause if it is, nil if not.
*
*/
Var *
other_join_clause_var(Var *var, Expr *clause)
{
Var *retval;
Var *l,
*r;
retval = (Var *) NULL;
if (var != NULL && is_joinable((Node *) clause))
{
l = (Var *) get_leftop(clause);
r = (Var *) get_rightop(clause);
if (equal(var, l))
retval = r;
else if (equal(var, r))
retval = l;
}
return retval;
}

View File

@@ -1,237 +0,0 @@
/*-------------------------------------------------------------------------
*
* keys.c
* Key manipulation routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.23 1999/07/15 22:39:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/keys.h"
static Expr *matching2_tlvar(int var, List *tlist, bool (*test) ());
static bool equal_indexkey_var(int index_key, Var *var);
/*
* 1. index key
* one of:
* attnum
* (attnum arrayindex)
* 2. path key
* (subkey1 ... subkeyN)
* where subkeyI is a var node
* note that the 'Keys field is a list of these
* 3. join key
* (outer_subkey inner_subkey)
* where each subkey is a var node
* 4. sort key
* one of:
* SortKey node
* number
* nil
* (may also refer to the 'SortKey field of a SortKey node,
* which looks exactly like an index key)
*
*/
/*
* match_indexkey_operand
* Returns t iff an index key 'index_key' matches the given clause
* operand.
*
*/
bool
match_indexkey_operand(int indexkey, Var *operand, RelOptInfo *rel)
{
if (IsA(operand, Var) &&
(lfirsti(rel->relids) == operand->varno) &&
equal_indexkey_var(indexkey, operand))
return true;
else
return false;
}
/*
* equal_indexkey_var
* Returns t iff an index key 'index_key' matches the corresponding
* fields of var node 'var'.
*
*/
static bool
equal_indexkey_var(int index_key, Var *var)
{
if (index_key == var->varattno)
return true;
else
return false;
}
/*
* extract_join_key
* Returns the subkey in a join key corresponding to the outer or inner
* relation.
*
*/
Var *
extract_join_key(JoinKey *jk, int outer_or_inner)
{
Var *retval;
switch (outer_or_inner)
{
case OUTER:
retval = jk->outer;
break;
case INNER:
retval = jk->inner;
break;
default: /* do nothing */
elog(DEBUG, "extract_join_key with neither INNER or OUTER");
retval = NULL;
}
return retval;
}
/*
* pathkeys_match
* Returns t iff two sets of path keys are equivalent. They are
* equivalent if the first Var nodes match the second Var nodes.
*
* See the top of optimizer/path/pathkeys.c for a description of pathkeys.
* Each pathkey is ordered by its join order, so they not pre-ordered to
* match. We must search them ourselves.
*
* This gets called a lot, so it is optimized.
*/
bool
pathkeys_match(List *keys1, List *keys2, int *better_key)
{
List *key1,
*key2;
bool key1_subsetof_key2 = true,
key2_subsetof_key1 = true;
for (key1 = keys1, key2 = keys2;
key1 != NIL && key2 != NIL;
key1 = lnext(key1), key2 = lnext(key2))
{
List *i;
if (key1_subsetof_key2)
foreach(i, lfirst(key1))
{
Var *subkey = lfirst(i);
if (!member(subkey, lfirst(key2)))
{
key1_subsetof_key2 = false;
break;
}
}
if (key2_subsetof_key1)
foreach(i, lfirst(key2))
{
Var *subkey = lfirst(i);
if (!member(subkey, lfirst(key1)))
{
key2_subsetof_key1 = false;
break;
}
}
if (!key1_subsetof_key2 && !key2_subsetof_key1)
break; /* no need to continue comparisons. */
}
if (!key1_subsetof_key2 && !key2_subsetof_key1)
{
*better_key = 0;
return false;
}
if (key1_subsetof_key2 && !key2_subsetof_key1)
{
*better_key = 2;
return true;
}
if (!key1_subsetof_key2 && key2_subsetof_key1)
{
*better_key = 1;
return true;
}
*better_key = 0;
return true;
}
/*
* collect_index_pathkeys
* Creates a list of subkeys by retrieving var nodes corresponding to
* each index key in 'index_keys' from the relation's target list
* 'tlist'. If the key is not in the target list, the key is irrelevant
* and is thrown away. The returned subkey list is of the form:
* ((var1) (var2) ... (varn))
*
* 'index_keys' is a list of index keys
* 'tlist' is a relation target list
*
* Returns the list of cons'd subkeys.
*
*/
/* This function is identical to matching_tlvar and tlistentry_member.
* They should be merged.
*/
static Expr *
matching2_tlvar(int var, List *tlist, bool (*test) ())
{
TargetEntry *tlentry = NULL;
if (var)
{
List *temp;
foreach(temp, tlist)
{
if ((*test) (var, get_expr(lfirst(temp))))
{
tlentry = lfirst(temp);
break;
}
}
}
if (tlentry)
return (Expr *) get_expr(tlentry);
else
return (Expr *) NULL;
}
List *
collect_index_pathkeys(int *index_keys, List *tlist)
{
List *retval = NIL;
Assert(index_keys != NULL);
while (index_keys[0] != 0)
{
Expr *mvar;
mvar = matching2_tlvar(index_keys[0],
tlist,
equal_indexkey_var);
if (mvar)
retval = lappend(retval, lcons(mvar, NIL));
index_keys++;
}
return retval;
}

View File

@@ -1,169 +0,0 @@
/*-------------------------------------------------------------------------
*
* ordering.c
* Routines to manipulate and compare merge and path orderings
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/ordering.c,v 1.17 1999/07/15 22:39:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/types.h>
#include "postgres.h"
#include "optimizer/ordering.h"
static bool sortops_order_match(Oid *ordering1, Oid *ordering2,
int *better_sort);
/*
* equal_path_ordering
* Returns t iff two path orderings are equal.
*
*/
bool
pathorder_match(PathOrder *path_ordering1,
PathOrder *path_ordering2,
int *better_sort)
{
*better_sort = 0;
if (path_ordering1 == path_ordering2)
return true;
if (!path_ordering2)
{
*better_sort = 1;
return true;
}
if (!path_ordering1)
{
*better_sort = 2;
return true;
}
if (path_ordering1->ordtype == MERGE_ORDER &&
path_ordering2->ordtype == MERGE_ORDER)
return equal(path_ordering1->ord.merge, path_ordering2->ord.merge);
else if (path_ordering1->ordtype == SORTOP_ORDER &&
path_ordering2->ordtype == SORTOP_ORDER)
{
return sortops_order_match(path_ordering1->ord.sortop,
path_ordering2->ord.sortop,
better_sort);
}
else if (path_ordering1->ordtype == MERGE_ORDER &&
path_ordering2->ordtype == SORTOP_ORDER)
{
if (!path_ordering2->ord.sortop)
{
*better_sort = 1;
return true;
}
return path_ordering1->ord.merge->left_operator == path_ordering2->ord.sortop[0];
}
else
{
if (!path_ordering1->ord.sortop)
{
*better_sort = 2;
return true;
}
return path_ordering1->ord.sortop[0] == path_ordering2->ord.merge->left_operator;
}
}
/*
* equal_path_merge_ordering
* Returns t iff a path ordering is usable for ordering a merge join.
*
* XXX Presently, this means that the first sortop of the path matches
* either of the merge sortops. Is there a "right" and "wrong"
* sortop to match?
*
*/
bool
equal_path_merge_ordering(Oid *path_ordering,
MergeOrder *merge_ordering)
{
if (path_ordering == NULL || merge_ordering == NULL)
return false;
if (path_ordering[0] == merge_ordering->left_operator ||
path_ordering[0] == merge_ordering->right_operator)
return true;
else
return false;
}
/*
* equal_merge_ordering
* Returns t iff two merge orderings are equal.
*
*/
bool
equal_merge_ordering(MergeOrder *merge_ordering1,
MergeOrder *merge_ordering2)
{
return equal(merge_ordering1, merge_ordering2);
}
/*
* sortops
*
*/
/*
* equal_sort_ops_order -
* Returns true iff the sort operators are in the same order.
*/
static bool
sortops_order_match(Oid *ordering1, Oid *ordering2, int *better_sort)
{
int i = 0;
*better_sort = 0;
if (ordering1 == ordering2)
return true;
if (!ordering2)
{
*better_sort = 1;
return true;
}
if (!ordering1)
{
*better_sort = 2;
return true;
}
while (ordering1[i] != 0 && ordering2[i] != 0)
{
if (ordering1[i] != ordering2[i])
break;
i++;
}
if (ordering1[i] != 0 && ordering2[i] == 0)
{
*better_sort = 1;
return true;
}
if (ordering1[i] == 0 && ordering2[i] != 0)
{
*better_sort = 2;
return true;
}
return ordering1[i] == 0 && ordering2[i] == 0;
}

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.53 1999/08/06 04:00:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.54 1999/08/16 02:17:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,16 +18,12 @@
#include "optimizer/cost.h"
#include "optimizer/keys.h"
#include "optimizer/ordering.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/plancat.h"
#include "optimizer/restrictinfo.h"
#include "parser/parsetree.h"
static Path *better_path(Path *new_path, List *unique_paths, bool *is_new);
/*****************************************************************************
* MISC. PATH UTILITIES
@@ -84,186 +80,104 @@ set_cheapest(RelOptInfo *parent_rel, List *pathlist)
/*
* add_pathlist
* For each path in the list 'new_paths', add to the list 'unique_paths'
* only those paths that are unique (i.e., unique ordering and ordering
* keys). Should a conflict arise, the more expensive path is thrown out,
* thereby pruning the plan space. But we don't prune if xfunc
* told us not to.
* Construct an output path list by adding to old_paths each path in
* new_paths that is worth considering --- that is, it has either a
* better sort order (better pathkeys) or cheaper cost than any of the
* existing old paths.
*
* Unless parent_rel->pruneable is false, we also remove from the output
* pathlist any old paths that are dominated by added path(s) --- that is,
* some new path is both cheaper and at least as well ordered.
*
* Note: the list old_paths is destructively modified, and in fact is
* turned into the output list.
*
* 'parent_rel' is the relation entry to which these paths correspond.
* 'old_paths' is the list of previously accepted paths for parent_rel.
* 'new_paths' is a list of potential new paths.
*
* Returns the list of unique pathnodes.
*
* Returns the updated list of interesting pathnodes.
*/
List *
add_pathlist(RelOptInfo *parent_rel, List *unique_paths, List *new_paths)
add_pathlist(RelOptInfo *parent_rel, List *old_paths, List *new_paths)
{
List *p1;
foreach(p1, new_paths)
{
Path *new_path = (Path *) lfirst(p1);
Path *old_path;
bool is_new;
bool accept_new = true; /* unless we find a superior old path */
List *p2_prev = NIL;
List *p2;
/* Is this new path already in unique_paths? */
if (member(new_path, unique_paths))
continue;
/* Find best matching path */
old_path = better_path(new_path, unique_paths, &is_new);
if (is_new)
/*
* Loop to check proposed new path against old paths. Note it is
* possible for more than one old path to be tossed out because
* new_path dominates it.
*/
foreach(p2, old_paths)
{
/* This is a brand new path. */
new_path->parent = parent_rel;
unique_paths = lcons(new_path, unique_paths);
}
else if (old_path == NULL)
{
; /* do nothing if path is not cheaper */
}
else if (old_path != NULL)
{ /* (IsA(old_path,Path)) { */
new_path->parent = parent_rel;
if (!parent_rel->pruneable)
unique_paths = lcons(new_path, unique_paths);
else
unique_paths = lcons(new_path,
LispRemove(old_path, unique_paths));
}
}
return unique_paths;
}
Path *old_path = (Path *) lfirst(p2);
bool remove_old = false; /* unless new proves superior */
/*
* better_path
* Determines whether 'new_path' has the same ordering and keys as some
* path in the list 'unique_paths'. If there is a redundant path,
* eliminate the more expensive path.
*
* Returns:
* The old path - if 'new_path' matches some path in 'unique_paths' and is
* cheaper
* nil - if 'new_path' matches but isn't cheaper
* t - if there is no path in the list with the same ordering and keys
*
*/
static Path *
better_path(Path *new_path, List *unique_paths, bool *is_new)
{
Path *path = (Path *) NULL;
List *temp = NIL;
int better_key;
int better_sort;
#ifdef OPTDUP_DEBUG
printf("better_path entry\n");
printf("new\n");
pprint(new_path);
printf("unique_paths\n");
pprint(unique_paths);
#endif
foreach(temp, unique_paths)
{
path = (Path *) lfirst(temp);
#ifdef OPTDUP_DEBUG
if (!pathkeys_match(new_path->pathkeys, path->pathkeys, &better_key) ||
better_key != 0)
{
printf("betterkey = %d\n", better_key);
printf("newpath\n");
pprint(new_path->pathkeys);
printf("oldpath\n");
pprint(path->pathkeys);
if (path->pathkeys && new_path->pathkeys &&
length(lfirst(path->pathkeys)) >= 2 /* &&
* length(lfirst(path->pa
* thkeys)) <
* length(lfirst(new_path
->pathkeys)) */ )
sleep(0); /* set breakpoint here */
}
if (!pathorder_match(new_path->pathorder, path->pathorder,
&better_sort) ||
better_sort != 0)
{
printf("neword\n");
pprint(new_path->pathorder);
printf("oldord\n");
pprint(path->pathorder);
}
#endif
if (pathkeys_match(new_path->pathkeys, path->pathkeys,
&better_key) &&
pathorder_match(new_path->pathorder, path->pathorder,
&better_sort))
{
switch (compare_pathkeys(new_path->pathkeys, old_path->pathkeys))
{
case PATHKEYS_EQUAL:
if (new_path->path_cost < old_path->path_cost)
remove_old = true; /* new dominates old */
else
accept_new = false; /* old equals or dominates new */
break;
case PATHKEYS_BETTER1:
if (new_path->path_cost <= old_path->path_cost)
remove_old = true; /* new dominates old */
break;
case PATHKEYS_BETTER2:
if (new_path->path_cost >= old_path->path_cost)
accept_new = false; /* old dominates new */
break;
case PATHKEYS_DIFFERENT:
/* keep both paths, since they have different ordering */
break;
}
/*
* Replace pathkeys that match exactly, {{1,2}}, {{1,2}}
* Replace pathkeys {{1,2}} with {{1,2,3}}} if the latter is
* not more expensive and replace unordered path with ordered
* path if it is not more expensive. Favor sorted keys over
* unsorted keys in the same way.
* Remove current element from old_list if dominated by new,
* unless xfunc told us not to remove any paths.
*/
/* same keys, and new is cheaper, use it */
if ((better_key == 0 && better_sort == 0 &&
new_path->path_cost < path->path_cost) ||
/* new is better, and cheaper, use it */
(((better_key == 1 && better_sort != 2) ||
(better_key != 2 && better_sort == 1)) &&
new_path->path_cost <= path->path_cost))
if (remove_old && parent_rel->pruneable)
{
#ifdef OPTDUP_DEBUG
printf("replace with new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort);
printf("new\n");
pprint(new_path);
printf("old\n");
pprint(path);
#endif
*is_new = false;
return path;
if (p2_prev)
lnext(p2_prev) = lnext(p2);
else
old_paths = lnext(p2);
}
else
p2_prev = p2;
/* same keys, new is more expensive, stop */
if ((better_key == 0 && better_sort == 0 &&
new_path->path_cost >= path->path_cost) ||
/*
* If we found an old path that dominates new_path, we can quit
* scanning old_paths; we will not add new_path, and we assume
* new_path cannot dominate any other elements of old_paths.
*/
if (! accept_new)
break;
}
/* old is better, and less expensive, stop */
(((better_key == 2 && better_sort != 1) ||
(better_key != 1 && better_sort == 2)) &&
new_path->path_cost >= path->path_cost))
{
#ifdef OPTDUP_DEBUG
printf("skip new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort);
printf("new\n");
pprint(new_path);
printf("old\n");
pprint(path);
#endif
*is_new = false;
return NULL;
}
if (accept_new)
{
/* Accept the path. Note that it will now be eligible to be
* compared against the additional elements of new_paths...
*/
new_path->parent = parent_rel; /* not redundant, see prune.c */
old_paths = lcons(new_path, old_paths);
}
}
#ifdef OPTDUP_DEBUG
printf("add new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort);
printf("new\n");
pprint(new_path);
#endif
*is_new = true;
return NULL;
return old_paths;
}
/*****************************************************************************
* PATH NODE CREATION ROUTINES
*****************************************************************************/
@@ -277,19 +191,15 @@ better_path(Path *new_path, List *unique_paths, bool *is_new)
Path *
create_seqscan_path(RelOptInfo *rel)
{
int relid = 0;
Path *pathnode = makeNode(Path);
int relid = 0;
pathnode->pathtype = T_SeqScan;
pathnode->parent = rel;
pathnode->path_cost = 0.0;
pathnode->pathorder = makeNode(PathOrder);
pathnode->pathorder->ordtype = SORTOP_ORDER;
pathnode->pathorder->ord.sortop = NULL;
pathnode->pathkeys = NIL;
pathnode->pathkeys = NIL; /* seqscan has unordered result */
if (rel->relids != NULL)
if (rel->relids != NIL) /* can this happen? */
relid = lfirsti(rel->relids);
pathnode->path_cost = cost_seqscan(relid,
@@ -319,12 +229,10 @@ create_index_path(Query *root,
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
pathnode->path.pathorder = makeNode(PathOrder);
pathnode->path.pathorder->ordtype = SORTOP_ORDER;
pathnode->path.pathorder->ord.sortop = index->ordering;
pathnode->path.pathkeys = NIL;
pathnode->path.pathkeys = build_index_pathkeys(root, rel, index);
/* Note that we are making a pathnode for a single-scan indexscan;
/*
* Note that we are making a pathnode for a single-scan indexscan;
* therefore, both indexid and indexqual should be single-element
* lists. We initialize indexqual to contain one empty sublist,
* representing a single index traversal with no index restriction
@@ -334,29 +242,7 @@ create_index_path(Query *root,
Assert(length(index->relids) == 1);
pathnode->indexid = index->relids;
pathnode->indexqual = lcons(NIL, NIL);
pathnode->indexkeys = index->indexkeys;
/*
* The index must have an ordering for the path to have (ordering)
* keys, and vice versa.
*/
if (pathnode->path.pathorder->ord.sortop)
{
pathnode->path.pathkeys = collect_index_pathkeys(index->indexkeys,
rel->targetlist);
/*
* Check that the keys haven't 'disappeared', since they may no
* longer be in the target list (i.e., index keys that are not
* relevant to the scan are not applied to the scan path node, so
* if no index keys were found, we can't order the path).
*/
if (pathnode->path.pathkeys == NULL)
pathnode->path.pathorder->ord.sortop = NULL;
}
else
pathnode->path.pathkeys = NULL;
pathnode->joinrelids = NIL; /* no join clauses here */
if (restriction_clauses == NIL)
{
@@ -377,7 +263,7 @@ create_index_path(Query *root,
{
/*
* Compute scan cost for the case when 'index' is used with
* restriction clause(s).
* restriction clause(s). Also, place indexqual in path node.
*/
List *indexquals;
float npages;
@@ -439,9 +325,9 @@ create_index_path(Query *root,
*
* 'joinrel' is the join relation.
* 'outer_rel' is the outer join relation
* 'outer_path' is the outer join path.
* 'inner_path' is the inner join path.
* 'pathkeys' are the keys of the path
* 'outer_path' is the outer path
* 'inner_path' is the inner path
* 'pathkeys' are the path keys of the new join path
*
* Returns the resulting path node.
*
@@ -461,23 +347,6 @@ create_nestloop_path(RelOptInfo *joinrel,
pathnode->innerjoinpath = inner_path;
pathnode->pathinfo = joinrel->restrictinfo;
pathnode->path.pathkeys = pathkeys;
pathnode->path.joinid = NIL;
pathnode->path.outerjoincost = (Cost) 0.0;
pathnode->path.pathorder = makeNode(PathOrder);
if (pathkeys)
{
pathnode->path.pathorder->ordtype = outer_path->pathorder->ordtype;
if (outer_path->pathorder->ordtype == SORTOP_ORDER)
pathnode->path.pathorder->ord.sortop = outer_path->pathorder->ord.sortop;
else
pathnode->path.pathorder->ord.merge = outer_path->pathorder->ord.merge;
}
else
{
pathnode->path.pathorder->ordtype = SORTOP_ORDER;
pathnode->path.pathorder->ord.sortop = NULL;
}
pathnode->path.path_cost = cost_nestloop(outer_path->path_cost,
inner_path->path_cost,
@@ -502,8 +371,7 @@ create_nestloop_path(RelOptInfo *joinrel,
* 'innerwidth' is the number of bytes per tuple in the inner relation
* 'outer_path' is the outer path
* 'inner_path' is the inner path
* 'pathkeys' are the new keys of the join relation
* 'order' is the sort order required for the merge
* 'pathkeys' are the path keys of the new join path
* 'mergeclauses' are the applicable join/restriction clauses
* 'outersortkeys' are the sort varkeys for the outer relation
* 'innersortkeys' are the sort varkeys for the inner relation
@@ -518,22 +386,29 @@ create_mergejoin_path(RelOptInfo *joinrel,
Path *outer_path,
Path *inner_path,
List *pathkeys,
MergeOrder *order,
List *mergeclauses,
List *outersortkeys,
List *innersortkeys)
{
MergePath *pathnode = makeNode(MergePath);
/*
* If the given paths are already well enough ordered, we can skip
* doing an explicit sort.
*/
if (outersortkeys &&
pathkeys_contained_in(outersortkeys, outer_path->pathkeys))
outersortkeys = NIL;
if (innersortkeys &&
pathkeys_contained_in(innersortkeys, inner_path->pathkeys))
innersortkeys = NIL;
pathnode->jpath.path.pathtype = T_MergeJoin;
pathnode->jpath.path.parent = joinrel;
pathnode->jpath.outerjoinpath = outer_path;
pathnode->jpath.innerjoinpath = inner_path;
pathnode->jpath.pathinfo = joinrel->restrictinfo;
pathnode->jpath.path.pathkeys = pathkeys;
pathnode->jpath.path.pathorder = makeNode(PathOrder);
pathnode->jpath.path.pathorder->ordtype = MERGE_ORDER;
pathnode->jpath.path.pathorder->ord.merge = order;
pathnode->path_mergeclauses = mergeclauses;
pathnode->outersortkeys = outersortkeys;
pathnode->innersortkeys = innersortkeys;
@@ -560,15 +435,11 @@ create_mergejoin_path(RelOptInfo *joinrel,
* 'innerwidth' is the number of bytes per tuple in the inner relation
* 'outer_path' is the cheapest outer path
* 'inner_path' is the cheapest inner path
* 'pathkeys' are the path keys of the new join path
* 'operator' is the hashjoin operator
* 'hashclauses' is a list of the hash join clause (always a 1-element list)
* 'outerkeys' are the sort varkeys for the outer relation
* 'innerkeys' are the sort varkeys for the inner relation
* 'innerdisbursion' is an estimate of the disbursion of the inner hash key
*
*/
HashPath *
HashPath *
create_hashjoin_path(RelOptInfo *joinrel,
int outersize,
int innersize,
@@ -576,11 +447,7 @@ create_hashjoin_path(RelOptInfo *joinrel,
int innerwidth,
Path *outer_path,
Path *inner_path,
List *pathkeys,
Oid operator,
List *hashclauses,
List *outerkeys,
List *innerkeys,
Cost innerdisbursion)
{
HashPath *pathnode = makeNode(HashPath);
@@ -590,16 +457,9 @@ create_hashjoin_path(RelOptInfo *joinrel,
pathnode->jpath.outerjoinpath = outer_path;
pathnode->jpath.innerjoinpath = inner_path;
pathnode->jpath.pathinfo = joinrel->restrictinfo;
pathnode->jpath.path.pathkeys = pathkeys;
pathnode->jpath.path.pathorder = makeNode(PathOrder);
pathnode->jpath.path.pathorder->ordtype = SORTOP_ORDER;
pathnode->jpath.path.pathorder->ord.sortop = NULL;
pathnode->jpath.path.outerjoincost = (Cost) 0.0;
pathnode->jpath.path.joinid = (Relids) NULL;
/* pathnode->hashjoinoperator = operator; */
/* A hashjoin never has pathkeys, since its ordering is unpredictable */
pathnode->jpath.path.pathkeys = NIL;
pathnode->path_hashclauses = hashclauses;
pathnode->outerhashkeys = outerkeys;
pathnode->innerhashkeys = innerkeys;
pathnode->jpath.path.path_cost = cost_hashjoin(outer_path->path_cost,
inner_path->path_cost,
outersize, innersize,

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.18 1999/07/16 03:13:05 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.19 1999/08/16 02:17:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,10 +29,9 @@
RelOptInfo *
get_base_rel(Query *root, int relid)
{
Relids relids;
Relids relids = lconsi(relid, NIL);
RelOptInfo *rel;
relids = lconsi(relid, NIL);
rel = rel_member(relids, root->base_rel_list);
if (rel == NULL)
{
@@ -41,28 +40,26 @@ get_base_rel(Query *root, int relid)
rel->indexed = false;
rel->pages = 0;
rel->tuples = 0;
rel->size = 0;
rel->width = 0;
rel->targetlist = NIL;
rel->pathlist = NIL;
rel->cheapestpath = (Path *) NULL;
rel->pruneable = true;
rel->classlist = NULL;
rel->indexkeys = NULL;
rel->ordering = NULL;
rel->relam = InvalidOid;
rel->indproc = InvalidOid;
rel->indpred = NIL;
rel->restrictinfo = NIL;
rel->joininfo = NIL;
rel->innerjoin = NIL;
root->base_rel_list = lcons(rel, root->base_rel_list);
/*
* ??? the old lispy C code (get_rel) do a listp(relid) here but
* that can never happen since we already established relid is not
* a list. -ay 10/94
*/
if (relid < 0)
{
/*
* If the relation is a materialized relation, assume
* constants for sizes.
@@ -72,18 +69,12 @@ get_base_rel(Query *root, int relid)
}
else
{
bool hasindex;
int pages,
tuples;
/*
* Otherwise, retrieve relation characteristics from the
* Otherwise, retrieve relation statistics from the
* system catalogs.
*/
relation_info(root, relid, &hasindex, &pages, &tuples);
rel->indexed = hasindex;
rel->pages = pages;
rel->tuples = tuples;
relation_info(root, relid,
&rel->indexed, &rel->pages, &rel->tuples);
}
}
return rel;
@@ -111,16 +102,16 @@ get_join_rel(Query *root, Relids relid)
RelOptInfo *
rel_member(Relids relids, List *rels)
{
List *temp = NIL;
List *temprelid = NIL;
if (relids != NIL && rels != NIL)
{
List *temp;
foreach(temp, rels)
{
temprelid = ((RelOptInfo *) lfirst(temp))->relids;
if (same(temprelid, relids))
return (RelOptInfo *) (lfirst(temp));
RelOptInfo *rel = (RelOptInfo *) lfirst(temp);
if (same(rel->relids, relids))
return rel;
}
}
return NULL;