Commit 49ed4dd7 authored by Tom Lane's avatar Tom Lane

Further work on planning of indexscans. Cleaned up interfaces

to index_selectivity so that it can be handed an indexqual clause list
rather than a bunch of assorted derivative data.
parent 8ae29a1d
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.24 1999/07/24 23:21:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.25 1999/07/25 23:07:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -142,8 +142,8 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -142,8 +142,8 @@ compute_clause_selec(Query *root, Node *clause)
BooleanEqualOperator, BooleanEqualOperator,
relid, relid,
((Var *) clause)->varoattno, ((Var *) clause)->varoattno,
"t", Int8GetDatum(true),
_SELEC_CONSTANT_RIGHT_); SEL_CONSTANT | SEL_RIGHT);
} }
else if (IsA(clause, Param)) else if (IsA(clause, Param))
{ {
...@@ -215,14 +215,6 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -215,14 +215,6 @@ compute_clause_selec(Query *root, Node *clause)
*/ */
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
RegProcedure oprrest = get_oprrest(opno); RegProcedure oprrest = get_oprrest(opno);
Oid relid;
int relidx;
AttrNumber attno;
Datum constval;
int flag;
get_relattval(clause, &relidx, &attno, &constval, &flag);
relid = getrelid(relidx, root->rtable);
/* /*
* if the oprrest procedure is missing for whatever reason, use a * if the oprrest procedure is missing for whatever reason, use a
...@@ -230,22 +222,33 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -230,22 +222,33 @@ compute_clause_selec(Query *root, Node *clause)
*/ */
if (!oprrest) if (!oprrest)
s1 = (Cost) 0.5; s1 = (Cost) 0.5;
else if (attno == InvalidAttrNumber) else
{ {
/* int relidx;
* attno can be Invalid if the clause had a function in it, AttrNumber attno;
* i.e. WHERE myFunc(f) = 10 Datum constval;
*/ int flag;
/* this should be FIXED somehow to use function selectivity */
s1 = (Cost) (0.5); get_relattval(clause, 0, &relidx, &attno, &constval, &flag);
if (relidx <= 0 || attno <= 0)
{
/*
* attno can be Invalid if the clause had a function in it,
* i.e. WHERE myFunc(f) = 10
*
* XXX should be FIXED to use function selectivity
*/
s1 = (Cost) (0.5);
}
else
s1 = (Cost) restriction_selectivity(oprrest,
opno,
getrelid(relidx,
root->rtable),
attno,
constval,
flag);
} }
else
s1 = (Cost) restriction_selectivity(oprrest,
opno,
relid,
attno,
(char *) constval,
flag);
} }
else else
{ {
...@@ -256,14 +259,6 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -256,14 +259,6 @@ compute_clause_selec(Query *root, Node *clause)
*/ */
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
RegProcedure oprjoin = get_oprjoin(opno); RegProcedure oprjoin = get_oprjoin(opno);
int relid1,
relid2;
AttrNumber attno1,
attno2;
get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
relid1 = getrelid(relid1, root->rtable);
relid2 = getrelid(relid2, root->rtable);
/* /*
* if the oprjoin procedure is missing for whatever reason, use a * if the oprjoin procedure is missing for whatever reason, use a
...@@ -272,12 +267,25 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -272,12 +267,25 @@ compute_clause_selec(Query *root, Node *clause)
if (!oprjoin) if (!oprjoin)
s1 = (Cost) (0.5); s1 = (Cost) (0.5);
else else
s1 = (Cost) join_selectivity(oprjoin, {
opno, int relid1,
relid1, relid2;
attno1, AttrNumber attno1,
relid2, attno2;
attno2);
get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
if (relid1 > 0 && relid2 > 0 && attno1 > 0 && attno2 > 0)
s1 = (Cost) join_selectivity(oprjoin,
opno,
getrelid(relid1,
root->rtable),
attno1,
getrelid(relid2,
root->rtable),
attno2);
else /* XXX more code for function selectivity? */
s1 = (Cost) (0.5);
}
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.64 1999/07/25 17:53:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.65 1999/07/25 23:07:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1216,25 +1216,20 @@ index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index, ...@@ -1216,25 +1216,20 @@ index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
{ {
List *clausegroup = lfirst(i); List *clausegroup = lfirst(i);
IndexPath *pathnode = makeNode(IndexPath); IndexPath *pathnode = makeNode(IndexPath);
Cost temp_selec; List *indexquals;
float temp_pages; float npages;
List *attnos, float selec;
*values,
*flags; indexquals = get_actual_clauses(clausegroup);
get_joinvars(lfirsti(rel->relids), clausegroup, index_selectivity(root,
&attnos, &values, &flags); lfirsti(rel->relids),
index_selectivity(lfirsti(index->relids), lfirsti(index->relids),
index->classlist, indexquals,
get_opnos(clausegroup), &npages,
getrelid(lfirsti(rel->relids), &selec);
root->rtable),
attnos, /* XXX this code ought to be merged with create_index_path */
values,
flags,
length(clausegroup),
&temp_pages,
&temp_selec);
pathnode->path.pathtype = T_IndexScan; pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel; pathnode->path.parent = rel;
...@@ -1249,14 +1244,14 @@ index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index, ...@@ -1249,14 +1244,14 @@ index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
*/ */
pathnode->indexid = index->relids; pathnode->indexid = index->relids;
pathnode->indexkeys = index->indexkeys; pathnode->indexkeys = index->indexkeys;
pathnode->indexqual = lcons(get_actual_clauses(clausegroup), NIL); pathnode->indexqual = lcons(indexquals, NIL);
/* joinid saves the rels needed on the outer side of the join */ /* joinid saves the rels needed on the outer side of the join */
pathnode->path.joinid = lfirst(outerrelids_list); pathnode->path.joinid = lfirst(outerrelids_list);
pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids), pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
(int) temp_pages, (int) npages,
temp_selec, selec,
rel->pages, rel->pages,
rel->tuples, rel->tuples,
index->pages, index->pages,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.29 1999/07/24 23:21:10 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.30 1999/07/25 23:07:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -121,11 +121,14 @@ create_or_index_paths(Query *root, ...@@ -121,11 +121,14 @@ create_or_index_paths(Query *root,
pathnode->indexqual = NIL; pathnode->indexqual = NIL;
foreach(orclause, clausenode->clause->args) foreach(orclause, clausenode->clause->args)
{ {
List *sublist; Expr *subclause = (Expr *) lfirst(orclause);
if (and_clause(lfirst(orclause))) List *sublist;
sublist = ((Expr *) lfirst(orclause))->args;
if (and_clause((Node *) subclause))
sublist = subclause->args;
else else
sublist = lcons(lfirst(orclause), NIL); sublist = lcons(subclause, NIL);
/* expansion call... */
pathnode->indexqual = lappend(pathnode->indexqual, pathnode->indexqual = lappend(pathnode->indexqual,
sublist); sublist);
} }
...@@ -224,18 +227,8 @@ best_or_subclause_index(Query *root, ...@@ -224,18 +227,8 @@ best_or_subclause_index(Query *root,
Cost *retCost, /* return value */ Cost *retCost, /* return value */
Cost *retSelec) /* return value */ Cost *retSelec) /* return value */
{ {
Oid relid = getrelid(lfirsti(rel->relids),
root->rtable);
Oid opno = ((Oper *) subclause->oper)->opno;
AttrNumber attno = (get_leftop(subclause))->varattno;
bool constant_on_right = non_null((Expr *) get_rightop(subclause));
Datum value;
int flag;
List *opnos,
*attnos,
*values,
*flags;
bool first_run = true; bool first_run = true;
List *indexquals;
List *ilist; List *ilist;
/* if we don't match anything, return zeros */ /* if we don't match anything, return zeros */
...@@ -243,37 +236,25 @@ best_or_subclause_index(Query *root, ...@@ -243,37 +236,25 @@ best_or_subclause_index(Query *root,
*retCost = (Cost) 0.0; *retCost = (Cost) 0.0;
*retSelec = (Cost) 0.0; *retSelec = (Cost) 0.0;
if (constant_on_right) /* XXX looks pretty bogus ... tgl */ /* convert 'or' subclause to an indexqual list */
value = ((Const *) get_rightop(subclause))->constvalue; if (and_clause((Node *) subclause))
else indexquals = subclause->args;
value = NameGetDatum("");
if (constant_on_right)
flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
else else
flag = _SELEC_CONSTANT_RIGHT_; indexquals = lcons(subclause, NIL);
/* expansion call... */
/* prebuild lists since we will pass same list to each index */
opnos = lconsi(opno, NIL);
attnos = lconsi(attno, NIL);
values = lconsi(value, NIL);
flags = lconsi(flag, NIL);
foreach(ilist, indices) foreach(ilist, indices)
{ {
RelOptInfo *index = (RelOptInfo *) lfirst(ilist); RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
Oid indexid = (Oid) lfirsti(index->relids); Oid indexid = (Oid) lfirsti(index->relids);
Cost subcost; Cost subcost;
float npages, float npages;
selec; float selec;
index_selectivity(indexid, index_selectivity(root,
index->classlist, lfirsti(rel->relids),
opnos, indexid,
relid, indexquals,
attnos,
values,
flags,
1,
&npages, &npages,
&selec); &selec);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.41 1999/07/24 23:21:13 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.42 1999/07/25 23:07:25 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
static bool fix_opid_walker(Node *node, void *context); static bool fix_opid_walker(Node *node, void *context);
static int is_single_func(Node *node);
Expr * Expr *
...@@ -533,36 +534,36 @@ fix_opids(List *clauses) ...@@ -533,36 +534,36 @@ fix_opids(List *clauses)
/* /*
* get_relattval * get_relattval
* For a non-join clause, returns a list consisting of the * Extract information from a restriction or join clause for
* relid, * selectivity estimation. The inputs are an expression
* attno, * and a relation number (which can be 0 if we don't care which
* value of the CONST node (if any), and a * relation is used; that'd normally be the case for restriction
* flag indicating whether the value appears on the left or right * clauses, where the caller already knows that only one relation
* of the operator and whether the value varied. * is referenced in the clause). The routine checks that the
* * expression is of the form (var op something) or (something op var)
* OLD OBSOLETE COMMENT FOLLOWS: * where the var is an attribute of the specified relation, or
* If 'clause' is not of the format (op var node) or (op node var), * a function of a var of the specified relation. If so, it
* or if the var refers to a nested attribute, then -1's are returned for * returns the following info:
* everything but the value a blank string "" (pointer to \0) is * the found relation number (same as targetrelid unless that is 0)
* returned for the value if it is unknown or null. * the found var number (or InvalidAttrNumber if a function)
* END OF OLD OBSOLETE COMMENT. * if the "something" is a constant, the value of the constant
* NEW COMMENT: * flags indicating whether a constant was found, and on which side.
* when defining rules one of the attributes of the operator can * Default values are returned if the expression is too complicated,
* be a Param node (which is supposed to be treated as a constant). * specifically -1 for the relid and attno, 0 for the constant value.
* However as there is no value specified for a parameter until run time * Note that InvalidAttrNumber is *not* -1, but 0.
* this routine used to return "" as value, which caused 'compute_selec'
* to bomb (because it was expecting a lisp integer and got back a lisp
* string). Now the code returns a plain old good "lispInteger(0)".
*/ */
void void
get_relattval(Node *clause, get_relattval(Node *clause,
int targetrelid,
int *relid, int *relid,
AttrNumber *attno, AttrNumber *attno,
Datum *constval, Datum *constval,
int *flag) int *flag)
{ {
Var *left, Var *left,
*right; *right,
*other;
int funcvarno;
/* Careful; the passed clause might not be a binary operator at all */ /* Careful; the passed clause might not be a binary operator at all */
...@@ -575,71 +576,96 @@ get_relattval(Node *clause, ...@@ -575,71 +576,96 @@ get_relattval(Node *clause,
if (!right) if (!right)
goto default_results; goto default_results;
if (IsA(left, Var) &&IsA(right, Const)) /* First look for the var or func */
if (IsA(left, Var) &&
(targetrelid == 0 || targetrelid == left->varno))
{ {
*relid = left->varno; *relid = left->varno;
*attno = left->varattno; *attno = left->varattno;
*constval = ((Const *) right)->constvalue; *flag = SEL_RIGHT;
*flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
} }
else if (IsA(left, Var) &&IsA(right, Param)) else if (IsA(right, Var) &&
(targetrelid == 0 || targetrelid == right->varno))
{ {
*relid = left->varno; *relid = right->varno;
*attno = left->varattno; *attno = right->varattno;
*constval = 0; *flag = 0;
*flag = (_SELEC_NOT_CONSTANT_);
} }
else if (is_funcclause((Node *) left) && IsA(right, Const)) else if ((funcvarno = is_single_func((Node *) left)) != 0 &&
(targetrelid == 0 || targetrelid == funcvarno))
{ {
List *vars = pull_var_clause((Node *) left); *relid = funcvarno;
*relid = ((Var *) lfirst(vars))->varno;
*attno = InvalidAttrNumber; *attno = InvalidAttrNumber;
*constval = ((Const *) right)->constvalue; *flag = SEL_RIGHT;
*flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
} }
else if (IsA(right, Var) &&IsA(left, Const)) else if ((funcvarno = is_single_func((Node *) right)) != 0 &&
(targetrelid == 0 || targetrelid == funcvarno))
{ {
*relid = right->varno; *relid = funcvarno;
*attno = right->varattno; *attno = InvalidAttrNumber;
*constval = ((Const *) left)->constvalue; *flag = 0;
*flag = (_SELEC_IS_CONSTANT_);
} }
else if (IsA(right, Var) &&IsA(left, Param)) else
{ {
*relid = right->varno; /* Duh, it's too complicated for me... */
*attno = right->varattno; default_results:
*relid = -1;
*attno = -1;
*constval = 0; *constval = 0;
*flag = (_SELEC_NOT_CONSTANT_); *flag = 0;
return;
} }
else if (is_funcclause((Node *) right) && IsA(left, Const))
{
List *vars = pull_var_clause((Node *) right);
*relid = ((Var *) lfirst(vars))->varno; /* OK, we identified the var or func; now look at the other side */
*attno = InvalidAttrNumber;
*constval = ((Const *) left)->constvalue; other = (*flag == 0) ? left : right;
*flag = (_SELEC_IS_CONSTANT_);
if (IsA(other, Const))
{
*constval = ((Const *) other)->constvalue;
*flag |= SEL_CONSTANT;
} }
else else
{ {
/* Duh, it's too complicated for me... */
default_results:
*relid = _SELEC_VALUE_UNKNOWN_;
*attno = _SELEC_VALUE_UNKNOWN_;
*constval = 0; *constval = 0;
*flag = (_SELEC_NOT_CONSTANT_);
} }
} }
/* /*
* get_relsatts * is_single_func
* If the given expression is a function of a single relation,
* return the relation number; else return 0
*/
static int is_single_func(Node *node)
{
if (is_funcclause(node))
{
List *vars = pull_var_clause(node);
if (vars != NIL)
{
int funcvarno = ((Var *) lfirst(vars))->varno;
/* need to check that all args of func are same relation */
while ((vars = lnext(vars)) != NIL)
{
if (((Var *) lfirst(vars))->varno != funcvarno)
return 0;
}
return funcvarno;
}
}
return 0;
}
/*
* get_rels_atts
* *
* Returns a list * Returns the info
* ( relid1 attno1 relid2 attno2 ) * ( relid1 attno1 relid2 attno2 )
* for a joinclause. * for a joinclause.
* *
* If the clause is not of the form (op var var) or if any of the vars * If the clause is not of the form (var op var) or if any of the vars
* refer to nested attributes, then -1's are returned. * refer to nested attributes, then -1's are returned.
* *
*/ */
...@@ -650,6 +676,12 @@ get_rels_atts(Node *clause, ...@@ -650,6 +676,12 @@ get_rels_atts(Node *clause,
int *relid2, int *relid2,
AttrNumber *attno2) AttrNumber *attno2)
{ {
/* set default values */
*relid1 = -1;
*attno1 = -1;
*relid2 = -1;
*attno2 = -1;
if (is_opclause(clause)) if (is_opclause(clause))
{ {
Var *left = get_leftop((Expr *) clause); Var *left = get_leftop((Expr *) clause);
...@@ -657,47 +689,31 @@ get_rels_atts(Node *clause, ...@@ -657,47 +689,31 @@ get_rels_atts(Node *clause,
if (left && right) if (left && right)
{ {
bool var_left = IsA(left, Var); int funcvarno;
bool var_right = IsA(right, Var);
bool varexpr_left = (bool) ((IsA(left, Func) ||IsA(left, Oper)) &&
contain_var_clause((Node *) left));
bool varexpr_right = (bool) ((IsA(right, Func) ||IsA(right, Oper)) &&
contain_var_clause((Node *) right));
if (var_left && var_right)
{
*relid1 = left->varno; if (IsA(left, Var))
*attno1 = left->varoattno;
*relid2 = right->varno;
*attno2 = right->varoattno;
return;
}
if (var_left && varexpr_right)
{ {
*relid1 = left->varno; *relid1 = left->varno;
*attno1 = left->varoattno; *attno1 = left->varattno;
*relid2 = _SELEC_VALUE_UNKNOWN_;
*attno2 = _SELEC_VALUE_UNKNOWN_;
return;
} }
if (varexpr_left && var_right) else if ((funcvarno = is_single_func((Node *) left)) != 0)
{ {
*relid1 = funcvarno;
*attno1 = InvalidAttrNumber;
}
*relid1 = _SELEC_VALUE_UNKNOWN_; if (IsA(right, Var))
*attno1 = _SELEC_VALUE_UNKNOWN_; {
*relid2 = right->varno; *relid2 = right->varno;
*attno2 = right->varoattno; *attno2 = right->varattno;
return; }
else if ((funcvarno = is_single_func((Node *) right)) != 0)
{
*relid2 = funcvarno;
*attno2 = InvalidAttrNumber;
} }
} }
} }
*relid1 = _SELEC_VALUE_UNKNOWN_;
*attno1 = _SELEC_VALUE_UNKNOWN_;
*relid2 = _SELEC_VALUE_UNKNOWN_;
*attno2 = _SELEC_VALUE_UNKNOWN_;
} }
/*-------------------- /*--------------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.47 1999/07/24 23:21:14 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.48 1999/07/25 23:07:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -334,7 +334,12 @@ create_index_path(Query *root, ...@@ -334,7 +334,12 @@ create_index_path(Query *root,
pathnode->path.pathorder = makeNode(PathOrder); pathnode->path.pathorder = makeNode(PathOrder);
pathnode->path.pathorder->ordtype = SORTOP_ORDER; pathnode->path.pathorder->ordtype = SORTOP_ORDER;
pathnode->path.pathorder->ord.sortop = index->ordering; pathnode->path.pathorder->ord.sortop = index->ordering;
pathnode->path.pathkeys = NIL;
/* Note that we are making a pathnode for a single-scan indexscan;
* therefore, both indexid and indexqual should be single-element
* lists (unless indexqual is empty).
*/
pathnode->indexid = index->relids; pathnode->indexid = index->relids;
pathnode->indexkeys = index->indexkeys; pathnode->indexkeys = index->indexkeys;
pathnode->indexqual = NIL; pathnode->indexqual = NIL;
...@@ -344,7 +349,7 @@ create_index_path(Query *root, ...@@ -344,7 +349,7 @@ create_index_path(Query *root,
* JMH, 7/7/92 * JMH, 7/7/92
*/ */
pathnode->path.loc_restrictinfo = set_difference((List *) copyObject((Node *) rel->restrictinfo), pathnode->path.loc_restrictinfo = set_difference((List *) copyObject((Node *) rel->restrictinfo),
(List *) restriction_clauses); restriction_clauses);
/* /*
* The index must have an ordering for the path to have (ordering) * The index must have an ordering for the path to have (ordering)
...@@ -385,49 +390,28 @@ create_index_path(Query *root, ...@@ -385,49 +390,28 @@ create_index_path(Query *root,
index->pages, index->pages,
index->tuples, index->tuples,
false); false);
#ifdef NOT_USED
/* add in expensive functions cost! -- JMH, 7/7/92 */
if (XfuncMode != XFUNC_OFF)
{
pathnode->path_cost = (pathnode->path_cost +
xfunc_get_path_cost((Path *) pathnode));
}
#endif
} }
else else
{ {
/* /*
* Compute scan cost for the case when 'index' is used with a * Compute scan cost for the case when 'index' is used with a
* restriction clause. * restriction clause.
*/ */
List *attnos; List *indexquals;
List *values;
List *flags;
float npages; float npages;
float selec; float selec;
Cost clausesel; Cost clausesel;
get_relattvals(restriction_clauses, indexquals = get_actual_clauses(restriction_clauses);
&attnos,
&values, index_selectivity(root,
&flags); lfirsti(rel->relids),
index_selectivity(lfirsti(index->relids), lfirsti(index->relids),
index->classlist, indexquals,
get_opnos(restriction_clauses),
getrelid(lfirsti(rel->relids),
root->rtable),
attnos,
values,
flags,
length(restriction_clauses),
&npages, &npages,
&selec); &selec);
/* each clause gets an equal selectivity */
clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
pathnode->indexqual = lcons(get_actual_clauses(restriction_clauses), pathnode->indexqual = lcons(indexquals, NIL);
NIL);
pathnode->path.path_cost = cost_index(lfirsti(index->relids), pathnode->path.path_cost = cost_index(lfirsti(index->relids),
(int) npages, (int) npages,
selec, selec,
...@@ -437,21 +421,24 @@ create_index_path(Query *root, ...@@ -437,21 +421,24 @@ create_index_path(Query *root,
index->tuples, index->tuples,
false); false);
#ifdef NOT_USED
/* add in expensive functions cost! -- JMH, 7/7/92 */
if (XfuncMode != XFUNC_OFF)
pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
#endif
/* /*
* Set selectivities of clauses used with index to the selectivity * Set selectivities of clauses used with index to the selectivity
* of this index, subdividing the selectivity equally over each of * of this index, subdividing the selectivity equally over each of
* the clauses. * the clauses.
* XXX Can this divide the selectivities in a better way?
* XXX In fact, why the heck are we doing this at all? We already
* set the cost for the indexpath.
*/ */
clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
/* XXX Can this divide the selectivities in a better way? */
set_clause_selectivities(restriction_clauses, clausesel); set_clause_selectivities(restriction_clauses, clausesel);
} }
#ifdef NOT_USED
/* add in expensive functions cost! -- JMH, 7/7/92 */
if (XfuncMode != XFUNC_OFF)
pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
#endif
return pathnode; return pathnode;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.35 1999/07/17 20:17:18 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.36 1999/07/25 23:07:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,16 +20,20 @@ ...@@ -20,16 +20,20 @@
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_inherits.h" #include "catalog/pg_inherits.h"
#include "optimizer/clauses.h"
#include "optimizer/internal.h" #include "optimizer/internal.h"
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static void IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys, static void IndexSelectivity(Oid indexrelid, Oid baserelid, int nIndexKeys,
Oid *AccessMethodOperatorClasses, Oid *operatorObjectIds, Oid *operatorObjectIds,
int32 *varAttributeNumbers, char **constValues, int32 *constFlags, AttrNumber *varAttributeNumbers,
float *idxPages, float *idxSelec); Datum *constValues,
int *constFlags,
float *idxPages,
float *idxSelec);
/* /*
...@@ -212,85 +216,75 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info) ...@@ -212,85 +216,75 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
/* /*
* index_selectivity * index_selectivity
* Estimate the selectivity of an index scan with the given index quals.
* *
* Call util/plancat.c:IndexSelectivity with the indicated arguments. * NOTE: an indexscan plan node can actually represent several passes,
* * but here we consider the cost of just one pass.
* 'indid' is the index OID
* 'classes' is a list of index key classes
* 'opnos' is a list of index key operator OIDs
* 'relid' is the OID of the relation indexed
* 'attnos' is a list of the relation attnos which the index keys over
* 'values' is a list of the values of the clause's constants
* 'flags' is a list of fixnums which describe the constants
* 'nkeys' is the number of index keys
*
* Returns two floats: index pages and index selectivity in 'idxPages' and
* 'idxSelec'.
* *
* 'root' is the query root
* 'relid' is the RT index of the relation being scanned
* 'indexid' is the OID of the index to be used
* 'indexquals' is the list of qual condition exprs (implicit AND semantics)
* '*idxPages' receives an estimate of the number of index pages touched
* '*idxSelec' receives an estimate of selectivity of the scan
*/ */
void void
index_selectivity(Oid indid, index_selectivity(Query *root,
Oid *classes, int relid,
List *opnos, Oid indexid,
Oid relid, List *indexquals,
List *attnos,
List *values,
List *flags,
int32 nkeys,
float *idxPages, float *idxPages,
float *idxSelec) float *idxSelec)
{ {
int nclauses = length(indexquals);
Oid *opno_array; Oid *opno_array;
int *attno_array, AttrNumber *attno_array;
*flag_array; Datum *value_array;
char **value_array; int *flag_array;
int i = 0; List *q;
List *xopno, int i;
*xattno,
*value,
*flag;
if (length(opnos) != nkeys || length(attnos) != nkeys ||
length(values) != nkeys || length(flags) != nkeys)
{
if (nclauses <= 0)
{
*idxPages = 0.0; *idxPages = 0.0;
*idxSelec = 1.0; *idxSelec = 1.0;
return; return;
} }
opno_array = (Oid *) palloc(nclauses * sizeof(Oid));
opno_array = (Oid *) palloc(nkeys * sizeof(Oid)); attno_array = (AttrNumber *) palloc(nclauses * sizeof(AttrNumber));
attno_array = (int *) palloc(nkeys * sizeof(int32)); value_array = (Datum *) palloc(nclauses * sizeof(Datum));
value_array = (char **) palloc(nkeys * sizeof(char *)); flag_array = (int *) palloc(nclauses * sizeof(int));
flag_array = (int *) palloc(nkeys * sizeof(int32));
i = 0; i = 0;
foreach(xopno, opnos) foreach(q, indexquals)
opno_array[i++] = lfirsti(xopno); {
Node *expr = (Node *) lfirst(q);
i = 0; int dummyrelid;
foreach(xattno, attnos)
attno_array[i++] = lfirsti(xattno);
i = 0; if (is_opclause(expr))
foreach(value, values) opno_array[i] = ((Oper *) ((Expr *) expr)->oper)->opno;
value_array[i++] = (char *) lfirst(value); else
opno_array[i] = InvalidOid;
i = 0; get_relattval(expr, relid, &dummyrelid, &attno_array[i],
foreach(flag, flags) &value_array[i], &flag_array[i]);
flag_array[i++] = lfirsti(flag); i++;
}
IndexSelectivity(indid, IndexSelectivity(indexid,
relid, getrelid(relid, root->rtable),
nkeys, nclauses,
classes, /* not used */
opno_array, opno_array,
attno_array, attno_array,
value_array, value_array,
flag_array, flag_array,
idxPages, idxPages,
idxSelec); idxSelec);
return;
pfree(opno_array);
pfree(attno_array);
pfree(value_array);
pfree(flag_array);
} }
/* /*
...@@ -312,8 +306,8 @@ restriction_selectivity(Oid functionObjectId, ...@@ -312,8 +306,8 @@ restriction_selectivity(Oid functionObjectId,
Oid operatorObjectId, Oid operatorObjectId,
Oid relationObjectId, Oid relationObjectId,
AttrNumber attributeNumber, AttrNumber attributeNumber,
char *constValue, Datum constValue,
int32 constFlag) int constFlag)
{ {
float64 result; float64 result;
...@@ -456,35 +450,29 @@ VersionGetParents(Oid verrelid) ...@@ -456,35 +450,29 @@ VersionGetParents(Oid verrelid)
*****************************************************************************/ *****************************************************************************/
/* /*
* IdexSelectivity * IndexSelectivity
* *
* Retrieves the 'amopnpages' and 'amopselect' parameters for each * Calls the 'amopnpages' and 'amopselect' functions for each
* AM operator when a given index (specified by 'indexrelid') is used. * AM operator when a given index (specified by 'indexrelid') is used.
* These two parameters are returned by copying them to into an array of * The total number of pages and product of the selectivities are returned.
* floats.
* *
* Assumption: the attribute numbers and operator ObjectIds are in order * Assumption: the attribute numbers and operator ObjectIds are in order
* WRT to each other (otherwise, you have no way of knowing which * WRT to each other (otherwise, you have no way of knowing which
* AM operator class or attribute number corresponds to which operator. * AM operator class or attribute number corresponds to which operator.
* *
* 'nIndexKeys' is the number of qual clauses in use
* 'varAttributeNumbers' contains attribute numbers for variables * 'varAttributeNumbers' contains attribute numbers for variables
* 'constValues' contains the constant values * 'constValues' contains the constant values
* 'constFlags' describes how to treat the constants in each clause * 'constFlags' describes how to treat the constants in each clause
* 'nIndexKeys' describes how many keys the index actually has
*
* Returns 'selectivityInfo' filled with the sum of all pages touched
* and the product of each clause's selectivity.
*
*/ */
static void static void
IndexSelectivity(Oid indexrelid, IndexSelectivity(Oid indexrelid,
Oid indrelid, Oid baserelid,
int32 nIndexKeys, int nIndexKeys,
Oid *AccessMethodOperatorClasses, /* XXX not used? */
Oid *operatorObjectIds, Oid *operatorObjectIds,
int32 *varAttributeNumbers, AttrNumber *varAttributeNumbers,
char **constValues, Datum *constValues,
int32 *constFlags, int *constFlags,
float *idxPages, float *idxPages,
float *idxSelec) float *idxSelec)
{ {
...@@ -493,6 +481,7 @@ IndexSelectivity(Oid indexrelid, ...@@ -493,6 +481,7 @@ IndexSelectivity(Oid indexrelid,
HeapTuple indexTuple, HeapTuple indexTuple,
amopTuple, amopTuple,
indRel; indRel;
Form_pg_class indexrelation;
Form_pg_index index; Form_pg_index index;
Form_pg_amop amop; Form_pg_amop amop;
Oid indclass; Oid indclass;
...@@ -510,7 +499,8 @@ IndexSelectivity(Oid indexrelid, ...@@ -510,7 +499,8 @@ IndexSelectivity(Oid indexrelid,
if (!HeapTupleIsValid(indRel)) if (!HeapTupleIsValid(indRel))
elog(ERROR, "IndexSelectivity: index %u not found", elog(ERROR, "IndexSelectivity: index %u not found",
indexrelid); indexrelid);
relam = ((Form_pg_class) GETSTRUCT(indRel))->relam; indexrelation = (Form_pg_class) GETSTRUCT(indRel);
relam = indexrelation->relam;
indexTuple = SearchSysCacheTuple(INDEXRELID, indexTuple = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(indexrelid), ObjectIdGetDatum(indexrelid),
...@@ -530,9 +520,8 @@ IndexSelectivity(Oid indexrelid, ...@@ -530,9 +520,8 @@ IndexSelectivity(Oid indexrelid,
npages = 0.0; npages = 0.0;
select = 1.0; select = 1.0;
for (n = 0; n < nIndexKeys; ++n) for (n = 0; n < nIndexKeys; n++)
{ {
/* /*
* Find the AM class for this key. * Find the AM class for this key.
* *
...@@ -567,49 +556,43 @@ IndexSelectivity(Oid indexrelid, ...@@ -567,49 +556,43 @@ IndexSelectivity(Oid indexrelid,
amopTuple = SearchSysCacheTuple(AMOPOPID, amopTuple = SearchSysCacheTuple(AMOPOPID,
ObjectIdGetDatum(indclass), ObjectIdGetDatum(indclass),
ObjectIdGetDatum(operatorObjectIds[n]), ObjectIdGetDatum(operatorObjectIds[n]),
ObjectIdGetDatum(relam), ObjectIdGetDatum(relam),
0); 0);
if (!HeapTupleIsValid(amopTuple)) if (!HeapTupleIsValid(amopTuple))
elog(ERROR, "IndexSelectivity: no amop %u %u", elog(ERROR, "IndexSelectivity: no amop %u %u %u",
indclass, operatorObjectIds[n]); indclass, operatorObjectIds[n], relam);
amop = (Form_pg_amop) GETSTRUCT(amopTuple); amop = (Form_pg_amop) GETSTRUCT(amopTuple);
if (!nphack) if (!nphack)
{ {
amopnpages = (float64) fmgr(amop->amopnpages, amopnpages = (float64) fmgr(amop->amopnpages,
(char *) operatorObjectIds[n], (char *) operatorObjectIds[n],
(char *) indrelid, (char *) baserelid,
(char *) varAttributeNumbers[n], (char *) (int) varAttributeNumbers[n],
(char *) constValues[n], (char *) constValues[n],
(char *) constFlags[n], (char *) constFlags[n],
(char *) nIndexKeys, (char *) nIndexKeys,
(char *) indexrelid); (char *) indexrelid);
#ifdef NOT_USED if (PointerIsValid(amopnpages))
/* npages += *amopnpages;
* So cool guys! Npages for x > 10 and x < 20 is twice as
* npages for x > 10! - vadim 04/09/97
*/
npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
if ((i = npages) < npages) /* ceil(npages)? */
npages += 1.0;
#endif
npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
} }
amopselect = (float64) fmgr(amop->amopselect, amopselect = (float64) fmgr(amop->amopselect,
(char *) operatorObjectIds[n], (char *) operatorObjectIds[n],
(char *) indrelid, (char *) baserelid,
(char *) varAttributeNumbers[n], (char *) (int) varAttributeNumbers[n],
(char *) constValues[n], (char *) constValues[n],
(char *) constFlags[n], (char *) constFlags[n],
(char *) nIndexKeys, (char *) nIndexKeys,
(char *) indexrelid); (char *) indexrelid);
if (nphack && varAttributeNumbers[n] == index->indkey[0]) if (PointerIsValid(amopselect))
fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0; {
select *= *amopselect;
select *= PointerIsValid(amopselect) ? *amopselect : 1.0; if (nphack && varAttributeNumbers[n] == index->indkey[0])
fattr_select *= *amopselect;
}
} }
/* /*
...@@ -618,7 +601,7 @@ IndexSelectivity(Oid indexrelid, ...@@ -618,7 +601,7 @@ IndexSelectivity(Oid indexrelid,
*/ */
if (nphack) if (nphack)
{ {
npages = fattr_select * ((Form_pg_class) GETSTRUCT(indRel))->relpages; npages = fattr_select * indexrelation->relpages;
*idxPages = ceil((double) npages); *idxPages = ceil((double) npages);
} }
else else
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.7 1999/07/24 23:21:14 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.8 1999/07/25 23:07:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -44,144 +44,14 @@ restriction_is_or_clause(RestrictInfo *restrictinfo) ...@@ -44,144 +44,14 @@ restriction_is_or_clause(RestrictInfo *restrictinfo)
List * List *
get_actual_clauses(List *restrictinfo_list) get_actual_clauses(List *restrictinfo_list)
{ {
List *temp = NIL;
List *result = NIL; List *result = NIL;
RestrictInfo *clause = (RestrictInfo *) NULL;
foreach(temp, restrictinfo_list)
{
clause = (RestrictInfo *) lfirst(temp);
result = lappend(result, clause->clause);
}
return result;
}
/*
* XXX NOTE:
* The following routines must return their contents in the same order
* (e.g., the first clause's info should be first, and so on) or else
* get_index_sel() won't work.
*
*/
/*
* get_relattvals
* For each member of a list of restrictinfo nodes to be used with an
* index, create a vectori-long specifying:
* the attnos,
* the values of the clause constants, and
* flags indicating the type and location of the constant within
* each clause.
* Each clause is of the form (op var some_type_of_constant), thus the
* flag indicating whether the constant is on the left or right should
* always be *SELEC-CONSTANT-RIGHT*.
*
* 'restrictinfo_list' is a list of restrictinfo nodes
*
* Returns a list of vectori-longs.
*
*/
void
get_relattvals(List *restrictinfo_list,
List **attnos,
List **values,
List **flags)
{
List *result1 = NIL;
List *result2 = NIL;
List *result3 = NIL;
RestrictInfo *temp = (RestrictInfo *) NULL;
List *i = NIL;
foreach(i, restrictinfo_list)
{
int dummy;
AttrNumber attno;
Datum constval;
int flag;
temp = (RestrictInfo *) lfirst(i);
get_relattval((Node *) temp->clause, &dummy, &attno, &constval, &flag);
result1 = lappendi(result1, (int) attno);
result2 = lappendi(result2, constval);
result3 = lappendi(result3, flag);
}
*attnos = result1;
*values = result2;
*flags = result3;
return;
}
/*
* get_joinvars
* Given a list of join restrictinfo nodes to be used with the index
* of an inner join relation, return three lists consisting of:
* the attributes corresponding to the inner join relation
* the value of the inner var clause (always "")
* whether the attribute appears on the left or right side of
* the operator.
*
* 'relid' is the inner join relation
* 'restrictinfo_list' is a list of qualification clauses to be used with
* 'rel'
*
*/
void
get_joinvars(Oid relid,
List *restrictinfo_list,
List **attnos,
List **values,
List **flags)
{
List *result1 = NIL;
List *result2 = NIL;
List *result3 = NIL;
List *temp; List *temp;
foreach(temp, restrictinfo_list) foreach(temp, restrictinfo_list)
{ {
RestrictInfo *restrictinfo = lfirst(temp); RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
Expr *clause = restrictinfo->clause;
if (IsA(get_leftop(clause), Var) && result = lappend(result, clause->clause);
(relid == (get_leftop(clause))->varno))
{
result1 = lappendi(result1, (int4) (get_leftop(clause))->varattno);
result2 = lappend(result2, "");
result3 = lappendi(result3, _SELEC_CONSTANT_RIGHT_);
}
else
{
result1 = lappendi(result1, (int4) (get_rightop(clause))->varattno);
result2 = lappend(result2, "");
result3 = lappendi(result3, _SELEC_CONSTANT_LEFT_);
}
}
*attnos = result1;
*values = result2;
*flags = result3;
return;
}
/*
* get_opnos
* Create and return a list containing the clause operators of each member
* of a list of restrictinfo nodes to be used with an index.
*
*/
List *
get_opnos(List *restrictinfo_list)
{
RestrictInfo *temp = (RestrictInfo *) NULL;
List *result = NIL;
List *i = NIL;
foreach(i, restrictinfo_list)
{
temp = (RestrictInfo *) lfirst(i);
result = lappendi(result,
(((Oper *) temp->clause->oper)->opno));
} }
return result; return result;
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: clauses.h,v 1.22 1999/07/24 23:21:05 tgl Exp $ * $Id: clauses.h,v 1.23 1999/07/25 23:07:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -45,8 +45,9 @@ extern bool is_joinable(Node *clause); ...@@ -45,8 +45,9 @@ extern bool is_joinable(Node *clause);
extern bool qual_clause_p(Node *clause); extern bool qual_clause_p(Node *clause);
extern void fix_opid(Node *clause); extern void fix_opid(Node *clause);
extern List *fix_opids(List *clauses); extern List *fix_opids(List *clauses);
extern void get_relattval(Node *clause, int *relid, extern void get_relattval(Node *clause, int targetrelid,
AttrNumber *attno, Datum *constval, int *flag); int *relid, AttrNumber *attno,
Datum *constval, int *flag);
extern void get_rels_atts(Node *clause, int *relid1, extern void get_rels_atts(Node *clause, int *relid1,
AttrNumber *attno1, int *relid2, AttrNumber *attno2); AttrNumber *attno1, int *relid2, AttrNumber *attno2);
extern void CommuteClause(Node *clause); extern void CommuteClause(Node *clause);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: internal.h,v 1.22 1999/07/15 15:21:21 momjian Exp $ * $Id: internal.h,v 1.23 1999/07/25 23:07:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -63,20 +63,6 @@ ...@@ -63,20 +63,6 @@
/* used to be -1 */ /* used to be -1 */
#define _NONAME_RELATION_ID_ InvalidOid #define _NONAME_RELATION_ID_ InvalidOid
/* Identifier for invalid relation OIDs and attribute numbers for use by
* selectivity functions
*/
#define _SELEC_VALUE_UNKNOWN_ (-1)
/* Flag indicating that a clause constant is really a parameter (or other
* non-constant?), a non-parameter, or a constant on the right side
* of the clause.
*/
#define _SELEC_NOT_CONSTANT_ 0
#define _SELEC_IS_CONSTANT_ 1
#define _SELEC_CONSTANT_LEFT_ 0
#define _SELEC_CONSTANT_RIGHT_ 2
/* #define deactivate_joininfo(joininfo) joininfo->inactive=true*/ /* #define deactivate_joininfo(joininfo) joininfo->inactive=true*/
/*#define joininfo_inactive(joininfo) joininfo->inactive */ /*#define joininfo_inactive(joininfo) joininfo->inactive */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: plancat.h,v 1.12 1999/07/15 23:03:58 momjian Exp $ * $Id: plancat.h,v 1.13 1999/07/25 23:07:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,12 +46,12 @@ extern Cost restriction_selectivity(Oid functionObjectId, ...@@ -46,12 +46,12 @@ extern Cost restriction_selectivity(Oid functionObjectId,
Oid operatorObjectId, Oid operatorObjectId,
Oid relationObjectId, Oid relationObjectId,
AttrNumber attributeNumber, AttrNumber attributeNumber,
char *constValue, Datum constValue,
int32 constFlag); int constFlag);
extern void index_selectivity(Oid indid, Oid *classes, List *opnos, extern void index_selectivity(Query *root, int relid, Oid indexid,
Oid relid, List *attnos, List *values, List *flags, List *indexquals,
int32 nkeys, float *idxPages, float *idxSelec); float *idxPages, float *idxSelec);
extern Cost join_selectivity(Oid functionObjectId, Oid operatorObjectId, extern Cost join_selectivity(Oid functionObjectId, Oid operatorObjectId,
Oid relationObjectId1, AttrNumber attributeNumber1, Oid relationObjectId1, AttrNumber attributeNumber1,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: restrictinfo.h,v 1.6 1999/07/24 23:21:05 tgl Exp $ * $Id: restrictinfo.h,v 1.7 1999/07/25 23:07:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,10 +17,5 @@ ...@@ -17,10 +17,5 @@
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo); extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
extern List *get_actual_clauses(List *restrictinfo_list); extern List *get_actual_clauses(List *restrictinfo_list);
extern void get_relattvals(List *restrictinfo_list, List **attnos,
List **values, List **flags);
extern void get_joinvars(Oid relid, List *restrictinfo_list,
List **attnos, List **values, List **flags);
extern List *get_opnos(List *restrictinfo_list);
#endif /* RESTRICTINFO_H */ #endif /* RESTRICTINFO_H */
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