*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
BooleanEqualOperator,
relid,
((Var *) clause)->varoattno,
- "t",
- _SELEC_CONSTANT_RIGHT_);
+ Int8GetDatum(true),
+ SEL_CONSTANT | SEL_RIGHT);
}
else if (IsA(clause, Param))
{
*/
Oid opno = ((Oper *) ((Expr *) clause)->oper)->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 (!oprrest)
s1 = (Cost) 0.5;
- else if (attno == InvalidAttrNumber)
+ else
{
- /*
- * attno can be Invalid if the clause had a function in it,
- * i.e. WHERE myFunc(f) = 10
- */
- /* this should be FIXED somehow to use function selectivity */
- s1 = (Cost) (0.5);
+ int relidx;
+ AttrNumber attno;
+ Datum constval;
+ int flag;
+
+ 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
{
*/
Oid opno = ((Oper *) ((Expr *) clause)->oper)->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 (!oprjoin)
s1 = (Cost) (0.5);
else
- s1 = (Cost) join_selectivity(oprjoin,
- opno,
- relid1,
- attno1,
- relid2,
- attno2);
+ {
+ int relid1,
+ relid2;
+ AttrNumber attno1,
+ 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);
+ }
}
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
List *clausegroup = lfirst(i);
IndexPath *pathnode = makeNode(IndexPath);
- Cost temp_selec;
- float temp_pages;
- List *attnos,
- *values,
- *flags;
-
- get_joinvars(lfirsti(rel->relids), clausegroup,
- &attnos, &values, &flags);
- index_selectivity(lfirsti(index->relids),
- index->classlist,
- get_opnos(clausegroup),
- getrelid(lfirsti(rel->relids),
- root->rtable),
- attnos,
- values,
- flags,
- length(clausegroup),
- &temp_pages,
- &temp_selec);
+ List *indexquals;
+ float npages;
+ float selec;
+
+ indexquals = get_actual_clauses(clausegroup);
+
+ index_selectivity(root,
+ lfirsti(rel->relids),
+ lfirsti(index->relids),
+ indexquals,
+ &npages,
+ &selec);
+
+ /* XXX this code ought to be merged with create_index_path */
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
*/
pathnode->indexid = index->relids;
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 */
pathnode->path.joinid = lfirst(outerrelids_list);
pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
- (int) temp_pages,
- temp_selec,
+ (int) npages,
+ selec,
rel->pages,
rel->tuples,
index->pages,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
pathnode->indexqual = NIL;
foreach(orclause, clausenode->clause->args)
{
- List *sublist;
- if (and_clause(lfirst(orclause)))
- sublist = ((Expr *) lfirst(orclause))->args;
+ Expr *subclause = (Expr *) lfirst(orclause);
+ List *sublist;
+
+ if (and_clause((Node *) subclause))
+ sublist = subclause->args;
else
- sublist = lcons(lfirst(orclause), NIL);
+ sublist = lcons(subclause, NIL);
+ /* expansion call... */
pathnode->indexqual = lappend(pathnode->indexqual,
sublist);
}
Cost *retCost, /* 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;
+ List *indexquals;
List *ilist;
/* if we don't match anything, return zeros */
*retCost = (Cost) 0.0;
*retSelec = (Cost) 0.0;
- if (constant_on_right) /* XXX looks pretty bogus ... tgl */
- value = ((Const *) get_rightop(subclause))->constvalue;
- else
- value = NameGetDatum("");
- if (constant_on_right)
- flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
+ /* convert 'or' subclause to an indexqual list */
+ if (and_clause((Node *) subclause))
+ indexquals = subclause->args;
else
- flag = _SELEC_CONSTANT_RIGHT_;
-
- /* 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);
+ indexquals = lcons(subclause, NIL);
+ /* expansion call... */
foreach(ilist, indices)
{
RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
Oid indexid = (Oid) lfirsti(index->relids);
Cost subcost;
- float npages,
- selec;
-
- index_selectivity(indexid,
- index->classlist,
- opnos,
- relid,
- attnos,
- values,
- flags,
- 1,
+ float npages;
+ float selec;
+
+ index_selectivity(root,
+ lfirsti(rel->relids),
+ indexid,
+ indexquals,
&npages,
&selec);
*
*
* 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
* AUTHOR DATE MAJOR EVENT
static bool fix_opid_walker(Node *node, void *context);
+static int is_single_func(Node *node);
Expr *
/*
* get_relattval
- * For a non-join clause, returns a list consisting of the
- * relid,
- * attno,
- * value of the CONST node (if any), and a
- * flag indicating whether the value appears on the left or right
- * of the operator and whether the value varied.
- *
- * OLD OBSOLETE COMMENT FOLLOWS:
- * If 'clause' is not of the format (op var node) or (op node var),
- * or if the var refers to a nested attribute, then -1's are returned for
- * everything but the value a blank string "" (pointer to \0) is
- * returned for the value if it is unknown or null.
- * END OF OLD OBSOLETE COMMENT.
- * NEW COMMENT:
- * when defining rules one of the attributes of the operator can
- * be a Param node (which is supposed to be treated as a constant).
- * However as there is no value specified for a parameter until run time
- * 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)".
+ * Extract information from a restriction or join clause for
+ * selectivity estimation. The inputs are an expression
+ * and a relation number (which can be 0 if we don't care which
+ * relation is used; that'd normally be the case for restriction
+ * clauses, where the caller already knows that only one relation
+ * is referenced in the clause). The routine checks that the
+ * expression is of the form (var op something) or (something op var)
+ * where the var is an attribute of the specified relation, or
+ * a function of a var of the specified relation. If so, it
+ * returns the following info:
+ * the found relation number (same as targetrelid unless that is 0)
+ * the found var number (or InvalidAttrNumber if a function)
+ * if the "something" is a constant, the value of the constant
+ * flags indicating whether a constant was found, and on which side.
+ * Default values are returned if the expression is too complicated,
+ * specifically -1 for the relid and attno, 0 for the constant value.
+ * Note that InvalidAttrNumber is *not* -1, but 0.
*/
void
get_relattval(Node *clause,
+ int targetrelid,
int *relid,
AttrNumber *attno,
Datum *constval,
int *flag)
{
Var *left,
- *right;
+ *right,
+ *other;
+ int funcvarno;
/* Careful; the passed clause might not be a binary operator at all */
if (!right)
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;
*attno = left->varattno;
- *constval = ((Const *) right)->constvalue;
- *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
+ *flag = SEL_RIGHT;
}
- else if (IsA(left, Var) &&IsA(right, Param))
+ else if (IsA(right, Var) &&
+ (targetrelid == 0 || targetrelid == right->varno))
{
- *relid = left->varno;
- *attno = left->varattno;
- *constval = 0;
- *flag = (_SELEC_NOT_CONSTANT_);
+ *relid = right->varno;
+ *attno = right->varattno;
+ *flag = 0;
}
- 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 = ((Var *) lfirst(vars))->varno;
+ *relid = funcvarno;
*attno = InvalidAttrNumber;
- *constval = ((Const *) right)->constvalue;
- *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
+ *flag = SEL_RIGHT;
}
- else if (IsA(right, Var) &&IsA(left, Const))
+ else if ((funcvarno = is_single_func((Node *) right)) != 0 &&
+ (targetrelid == 0 || targetrelid == funcvarno))
{
- *relid = right->varno;
- *attno = right->varattno;
- *constval = ((Const *) left)->constvalue;
- *flag = (_SELEC_IS_CONSTANT_);
+ *relid = funcvarno;
+ *attno = InvalidAttrNumber;
+ *flag = 0;
}
- else if (IsA(right, Var) &&IsA(left, Param))
+ else
{
- *relid = right->varno;
- *attno = right->varattno;
+ /* Duh, it's too complicated for me... */
+default_results:
+ *relid = -1;
+ *attno = -1;
*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;
- *attno = InvalidAttrNumber;
- *constval = ((Const *) left)->constvalue;
- *flag = (_SELEC_IS_CONSTANT_);
+ /* OK, we identified the var or func; now look at the other side */
+
+ other = (*flag == 0) ? left : right;
+
+ if (IsA(other, Const))
+ {
+ *constval = ((Const *) other)->constvalue;
+ *flag |= SEL_CONSTANT;
}
else
{
- /* Duh, it's too complicated for me... */
-default_results:
- *relid = _SELEC_VALUE_UNKNOWN_;
- *attno = _SELEC_VALUE_UNKNOWN_;
*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 )
* 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.
*
*/
int *relid2,
AttrNumber *attno2)
{
+ /* set default values */
+ *relid1 = -1;
+ *attno1 = -1;
+ *relid2 = -1;
+ *attno2 = -1;
+
if (is_opclause(clause))
{
Var *left = get_leftop((Expr *) clause);
if (left && right)
{
- bool var_left = IsA(left, Var);
- 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)
- {
+ int funcvarno;
- *relid1 = left->varno;
- *attno1 = left->varoattno;
- *relid2 = right->varno;
- *attno2 = right->varoattno;
- return;
- }
- if (var_left && varexpr_right)
+ if (IsA(left, Var))
{
-
*relid1 = left->varno;
- *attno1 = left->varoattno;
- *relid2 = _SELEC_VALUE_UNKNOWN_;
- *attno2 = _SELEC_VALUE_UNKNOWN_;
- return;
+ *attno1 = left->varattno;
}
- if (varexpr_left && var_right)
+ else if ((funcvarno = is_single_func((Node *) left)) != 0)
{
+ *relid1 = funcvarno;
+ *attno1 = InvalidAttrNumber;
+ }
- *relid1 = _SELEC_VALUE_UNKNOWN_;
- *attno1 = _SELEC_VALUE_UNKNOWN_;
+ if (IsA(right, Var))
+ {
*relid2 = right->varno;
- *attno2 = right->varoattno;
- return;
+ *attno2 = right->varattno;
+ }
+ 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_;
}
/*--------------------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
pathnode->path.pathorder = makeNode(PathOrder);
pathnode->path.pathorder->ordtype = SORTOP_ORDER;
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->indexkeys = index->indexkeys;
pathnode->indexqual = NIL;
* JMH, 7/7/92
*/
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)
index->pages,
index->tuples,
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
{
-
/*
* Compute scan cost for the case when 'index' is used with a
* restriction clause.
*/
- List *attnos;
- List *values;
- List *flags;
+ List *indexquals;
float npages;
float selec;
Cost clausesel;
- get_relattvals(restriction_clauses,
- &attnos,
- &values,
- &flags);
- index_selectivity(lfirsti(index->relids),
- index->classlist,
- get_opnos(restriction_clauses),
- getrelid(lfirsti(rel->relids),
- root->rtable),
- attnos,
- values,
- flags,
- length(restriction_clauses),
+ indexquals = get_actual_clauses(restriction_clauses);
+
+ index_selectivity(root,
+ lfirsti(rel->relids),
+ lfirsti(index->relids),
+ indexquals,
&npages,
&selec);
- /* each clause gets an equal selectivity */
- clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
- pathnode->indexqual = lcons(get_actual_clauses(restriction_clauses),
- NIL);
+ pathnode->indexqual = lcons(indexquals, NIL);
pathnode->path.path_cost = cost_index(lfirsti(index->relids),
(int) npages,
selec,
index->tuples,
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
* of this index, subdividing the selectivity equally over each of
* 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.
*/
-
- /* XXX Can this divide the selectivities in a better way? */
+ clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_inherits.h"
+#include "optimizer/clauses.h"
#include "optimizer/internal.h"
#include "optimizer/plancat.h"
#include "parser/parsetree.h"
#include "utils/syscache.h"
-static void IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys,
- Oid *AccessMethodOperatorClasses, Oid *operatorObjectIds,
- int32 *varAttributeNumbers, char **constValues, int32 *constFlags,
- float *idxPages, float *idxSelec);
+static void IndexSelectivity(Oid indexrelid, Oid baserelid, int nIndexKeys,
+ Oid *operatorObjectIds,
+ AttrNumber *varAttributeNumbers,
+ Datum *constValues,
+ int *constFlags,
+ float *idxPages,
+ float *idxSelec);
/*
/*
* index_selectivity
+ * Estimate the selectivity of an index scan with the given index quals.
*
- * Call util/plancat.c:IndexSelectivity with the indicated arguments.
- *
- * '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'.
+ * NOTE: an indexscan plan node can actually represent several passes,
+ * but here we consider the cost of just one pass.
*
+ * '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
-index_selectivity(Oid indid,
- Oid *classes,
- List *opnos,
- Oid relid,
- List *attnos,
- List *values,
- List *flags,
- int32 nkeys,
+index_selectivity(Query *root,
+ int relid,
+ Oid indexid,
+ List *indexquals,
float *idxPages,
float *idxSelec)
{
+ int nclauses = length(indexquals);
Oid *opno_array;
- int *attno_array,
- *flag_array;
- char **value_array;
- int i = 0;
- List *xopno,
- *xattno,
- *value,
- *flag;
-
- if (length(opnos) != nkeys || length(attnos) != nkeys ||
- length(values) != nkeys || length(flags) != nkeys)
- {
+ AttrNumber *attno_array;
+ Datum *value_array;
+ int *flag_array;
+ List *q;
+ int i;
+ if (nclauses <= 0)
+ {
*idxPages = 0.0;
*idxSelec = 1.0;
return;
}
-
- opno_array = (Oid *) palloc(nkeys * sizeof(Oid));
- attno_array = (int *) palloc(nkeys * sizeof(int32));
- value_array = (char **) palloc(nkeys * sizeof(char *));
- flag_array = (int *) palloc(nkeys * sizeof(int32));
+ opno_array = (Oid *) palloc(nclauses * sizeof(Oid));
+ attno_array = (AttrNumber *) palloc(nclauses * sizeof(AttrNumber));
+ value_array = (Datum *) palloc(nclauses * sizeof(Datum));
+ flag_array = (int *) palloc(nclauses * sizeof(int));
i = 0;
- foreach(xopno, opnos)
- opno_array[i++] = lfirsti(xopno);
-
- i = 0;
- foreach(xattno, attnos)
- attno_array[i++] = lfirsti(xattno);
+ foreach(q, indexquals)
+ {
+ Node *expr = (Node *) lfirst(q);
+ int dummyrelid;
- i = 0;
- foreach(value, values)
- value_array[i++] = (char *) lfirst(value);
+ if (is_opclause(expr))
+ opno_array[i] = ((Oper *) ((Expr *) expr)->oper)->opno;
+ else
+ opno_array[i] = InvalidOid;
- i = 0;
- foreach(flag, flags)
- flag_array[i++] = lfirsti(flag);
+ get_relattval(expr, relid, &dummyrelid, &attno_array[i],
+ &value_array[i], &flag_array[i]);
+ i++;
+ }
- IndexSelectivity(indid,
- relid,
- nkeys,
- classes, /* not used */
+ IndexSelectivity(indexid,
+ getrelid(relid, root->rtable),
+ nclauses,
opno_array,
attno_array,
value_array,
flag_array,
idxPages,
idxSelec);
- return;
+
+ pfree(opno_array);
+ pfree(attno_array);
+ pfree(value_array);
+ pfree(flag_array);
}
/*
Oid operatorObjectId,
Oid relationObjectId,
AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag)
+ Datum constValue,
+ int constFlag)
{
float64 result;
*****************************************************************************/
/*
- * 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.
- * These two parameters are returned by copying them to into an array of
- * floats.
+ * The total number of pages and product of the selectivities are returned.
*
* Assumption: the attribute numbers and operator ObjectIds are in order
* WRT to each other (otherwise, you have no way of knowing which
* 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
* 'constValues' contains the constant values
* '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
IndexSelectivity(Oid indexrelid,
- Oid indrelid,
- int32 nIndexKeys,
- Oid *AccessMethodOperatorClasses, /* XXX not used? */
+ Oid baserelid,
+ int nIndexKeys,
Oid *operatorObjectIds,
- int32 *varAttributeNumbers,
- char **constValues,
- int32 *constFlags,
+ AttrNumber *varAttributeNumbers,
+ Datum *constValues,
+ int *constFlags,
float *idxPages,
float *idxSelec)
{
HeapTuple indexTuple,
amopTuple,
indRel;
+ Form_pg_class indexrelation;
Form_pg_index index;
Form_pg_amop amop;
Oid indclass;
if (!HeapTupleIsValid(indRel))
elog(ERROR, "IndexSelectivity: index %u not found",
indexrelid);
- relam = ((Form_pg_class) GETSTRUCT(indRel))->relam;
+ indexrelation = (Form_pg_class) GETSTRUCT(indRel);
+ relam = indexrelation->relam;
indexTuple = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(indexrelid),
npages = 0.0;
select = 1.0;
- for (n = 0; n < nIndexKeys; ++n)
+ for (n = 0; n < nIndexKeys; n++)
{
-
/*
* Find the AM class for this key.
*
amopTuple = SearchSysCacheTuple(AMOPOPID,
ObjectIdGetDatum(indclass),
- ObjectIdGetDatum(operatorObjectIds[n]),
+ ObjectIdGetDatum(operatorObjectIds[n]),
ObjectIdGetDatum(relam),
0);
if (!HeapTupleIsValid(amopTuple))
- elog(ERROR, "IndexSelectivity: no amop %u %u",
- indclass, operatorObjectIds[n]);
+ elog(ERROR, "IndexSelectivity: no amop %u %u %u",
+ indclass, operatorObjectIds[n], relam);
amop = (Form_pg_amop) GETSTRUCT(amopTuple);
if (!nphack)
{
amopnpages = (float64) fmgr(amop->amopnpages,
(char *) operatorObjectIds[n],
- (char *) indrelid,
- (char *) varAttributeNumbers[n],
+ (char *) baserelid,
+ (char *) (int) varAttributeNumbers[n],
(char *) constValues[n],
(char *) constFlags[n],
(char *) nIndexKeys,
(char *) indexrelid);
-#ifdef NOT_USED
-/*
- * 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;
+ if (PointerIsValid(amopnpages))
+ npages += *amopnpages;
}
amopselect = (float64) fmgr(amop->amopselect,
(char *) operatorObjectIds[n],
- (char *) indrelid,
- (char *) varAttributeNumbers[n],
+ (char *) baserelid,
+ (char *) (int) varAttributeNumbers[n],
(char *) constValues[n],
(char *) constFlags[n],
(char *) nIndexKeys,
(char *) indexrelid);
- if (nphack && varAttributeNumbers[n] == index->indkey[0])
- fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
-
- select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
+ if (PointerIsValid(amopselect))
+ {
+ select *= *amopselect;
+ if (nphack && varAttributeNumbers[n] == index->indkey[0])
+ fattr_select *= *amopselect;
+ }
}
/*
*/
if (nphack)
{
- npages = fattr_select * ((Form_pg_class) GETSTRUCT(indRel))->relpages;
+ npages = fattr_select * indexrelation->relpages;
*idxPages = ceil((double) npages);
}
else
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
List *
get_actual_clauses(List *restrictinfo_list)
{
- List *temp = 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;
foreach(temp, restrictinfo_list)
{
- RestrictInfo *restrictinfo = lfirst(temp);
- Expr *clause = restrictinfo->clause;
+ RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
- if (IsA(get_leftop(clause), Var) &&
- (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));
+ result = lappend(result, clause->clause);
}
return result;
}
*
* 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 $
*
*-------------------------------------------------------------------------
*/
extern bool qual_clause_p(Node *clause);
extern void fix_opid(Node *clause);
extern List *fix_opids(List *clauses);
-extern void get_relattval(Node *clause, int *relid,
- AttrNumber *attno, Datum *constval, int *flag);
+extern void get_relattval(Node *clause, int targetrelid,
+ int *relid, AttrNumber *attno,
+ Datum *constval, int *flag);
extern void get_rels_atts(Node *clause, int *relid1,
AttrNumber *attno1, int *relid2, AttrNumber *attno2);
extern void CommuteClause(Node *clause);
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* used to be -1 */
#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 joininfo_inactive(joininfo) joininfo->inactive */
*
* 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 $
*
*-------------------------------------------------------------------------
*/
Oid operatorObjectId,
Oid relationObjectId,
AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag);
+ Datum constValue,
+ int constFlag);
-extern void index_selectivity(Oid indid, Oid *classes, List *opnos,
- Oid relid, List *attnos, List *values, List *flags,
- int32 nkeys, float *idxPages, float *idxSelec);
+extern void index_selectivity(Query *root, int relid, Oid indexid,
+ List *indexquals,
+ float *idxPages, float *idxSelec);
extern Cost join_selectivity(Oid functionObjectId, Oid operatorObjectId,
Oid relationObjectId1, AttrNumber attributeNumber1,
*
* 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 $
*
*-------------------------------------------------------------------------
*/
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
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 */