提交 0dbffa70 编写于 作者: T Tom Lane

First cut at making useful selectivity estimates for range queries

(ie, WHERE x > lowbound AND x < highbound).  It's not very bright yet
but it does something useful.  Also, rename intltsel/intgtsel to
scalarltsel/scalargtsel to reflect usage better.  Extend convert_to_scalar
to do something a little bit useful with string data types.  Still need
to make it do something with date/time datatypes, but I'll wait for
Thomas's datetime unification dust to settle first.  Eventually the
routine ought not have any type-specific knowledge at all; it ought to
be calling a type-dependent routine found via a pg_type column; but
that's a task for another day.
上级 8bcac560
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.6 2000/01/22 23:50:08 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.7 2000/01/24 07:16:49 tgl Exp $
Postgres documentation
-->
......@@ -542,25 +542,25 @@ CREATE OPERATOR = (
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');
UPDATE pg_operator
SET oprrest = 'intltsel'::regproc, oprjoin = 'intltjoinsel'
SET oprrest = 'scalarltsel'::regproc, oprjoin = 'scalarltjoinsel'
WHERE oprname = '<' AND
oprleft = oprright AND
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');
UPDATE pg_operator
SET oprrest = 'intltsel'::regproc, oprjoin = 'intltjoinsel'
SET oprrest = 'scalarltsel'::regproc, oprjoin = 'scalarltjoinsel'
WHERE oprname = '<=' AND
oprleft = oprright AND
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');
UPDATE pg_operator
SET oprrest = 'intgtsel'::regproc, oprjoin = 'intgtjoinsel'
SET oprrest = 'scalargtsel'::regproc, oprjoin = 'scalargtjoinsel'
WHERE oprname = '>' AND
oprleft = oprright AND
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');
UPDATE pg_operator
SET oprrest = 'intgtsel'::regproc, oprjoin = 'intgtjoinsel'
SET oprrest = 'scalargtsel'::regproc, oprjoin = 'scalargtjoinsel'
WHERE oprname = '>=' AND
oprleft = oprright AND
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');</filename></filename>
......
......@@ -231,8 +231,8 @@ SELECT (a + b) AS c FROM test_complex;
<ProgramListing>
eqsel for =
neqsel for &lt;&gt;
intltsel for &lt; or &lt;=
intgtsel for &gt; or &gt;=
scalarltsel for &lt; or &lt;=
scalargtsel for &gt; or &gt;=
</ProgramListing>
It might seem a little odd that these are the categories, but they
make sense if you think about it. '=' will typically accept only
......@@ -254,6 +254,17 @@ SELECT (a + b) AS c FROM test_complex;
matching operators (~, ~*, etc) use eqsel on the assumption that they'll
usually only match a small fraction of the entries in a table.
</para>
<para>
You can use scalarltsel and scalargtsel for comparisons on datatypes that
have some sensible means of being converted into numeric scalars for
range comparisons. If possible, add the datatype to those understood
by the routine convert_to_scalar() in src/backend/utils/adt/selfuncs.c.
(Eventually, this routine should be replaced by per-datatype functions
identified through a column of the pg_type table; but that hasn't happened
yet.) If you do not do this, things will still work, but the optimizer's
estimates won't be as good as they could be.
</para>
</sect2>
<sect2>
......@@ -281,8 +292,8 @@ SELECT (a + b) AS c FROM test_complex;
<ProgramListing>
eqjoinsel for =
neqjoinsel for &lt;&gt;
intltjoinsel for &lt; or &lt;=
intgtjoinsel for &gt; or &gt;=
scalarltjoinsel for &lt; or &lt;=
scalargtjoinsel for &gt; or &gt;=
</ProgramListing>
</para>
</sect2>
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.28 2000/01/23 02:06:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.29 2000/01/24 07:16:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -23,6 +23,23 @@
#include "utils/lsyscache.h"
/*
* Data structure for accumulating info about possible range-query
* clause pairs in clauselist_selectivity.
*/
typedef struct RangeQueryClause {
struct RangeQueryClause *next; /* next in linked list */
Node *var; /* The common variable of the clauses */
bool have_lobound; /* found a low-bound clause yet? */
bool have_hibound; /* found a high-bound clause yet? */
Selectivity lobound; /* Selectivity of a var > something clause */
Selectivity hibound; /* Selectivity of a var < something clause */
} RangeQueryClause;
static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
int flag, bool isLTsel, Selectivity s2);
/****************************************************************************
* ROUTINES TO COMPUTE SELECTIVITIES
****************************************************************************/
......@@ -55,29 +72,237 @@ restrictlist_selectivity(Query *root,
* must be returned.
*
* See clause_selectivity() for the meaning of the varRelid parameter.
*
* Our basic approach is to take the product of the selectivities of the
* subclauses. However, that's only right if the subclauses have independent
* probabilities, and in reality they are often NOT independent. So,
* we want to be smarter where we can.
* Currently, the only extra smarts we have is to recognize "range queries",
* such as "x > 34 AND x < 42". Clauses are recognized as possible range
* query components if they are restriction opclauses whose operators have
* scalarltsel() or scalargtsel() as their restriction selectivity estimator.
* We pair up clauses of this form that refer to the same variable. An
* unpairable clause of this kind is simply multiplied into the selectivity
* product in the normal way. But when we find a pair, we know that the
* selectivities represent the relative positions of the low and high bounds
* within the column's range, so instead of figuring the selectivity as
* hisel * losel, we can figure it as hisel + losel - 1. (To visualize this,
* see that hisel is the fraction of the range below the high bound, while
* losel is the fraction above the low bound; so hisel can be interpreted
* directly as a 0..1 value but we need to convert losel to 1-losel before
* interpreting it as a value. Then the available range is 1-losel to hisel.)
* If the calculation yields zero or negative, however, we chicken out and
* use the default interpretation; that probably means that one or both
* selectivities is a default estimate rather than an actual range value.
* Of course this is all very dependent on the behavior of
* scalarltsel/scalargtsel; perhaps some day we can generalize the approach.
*/
Selectivity
clauselist_selectivity(Query *root,
List *clauses,
int varRelid)
{
Selectivity s1 = 1.0;
List *clause;
Selectivity s1 = 1.0;
RangeQueryClause *rqlist = NULL;
List *clist;
/* Use the product of the selectivities of the subclauses.
* XXX this is too optimistic, since the subclauses
* are very likely not independent...
/*
* Initial scan over clauses. Anything that doesn't look like a
* potential rangequery clause gets multiplied into s1 and forgotten.
* Anything that does gets inserted into an rqlist entry.
*/
foreach(clause, clauses)
foreach(clist, clauses)
{
Selectivity s2 = clause_selectivity(root,
(Node *) lfirst(clause),
varRelid);
Node *clause = (Node *) lfirst(clist);
Selectivity s2;
/*
* See if it looks like a restriction clause with a constant.
* (If it's not a constant we can't really trust the selectivity!)
* NB: for consistency of results, this fragment of code had
* better match what clause_selectivity() would do.
*/
if (varRelid != 0 || NumRelids(clause) == 1)
{
int relidx;
AttrNumber attno;
Datum constval;
int flag;
get_relattval(clause, varRelid,
&relidx, &attno, &constval, &flag);
if (relidx != 0 && (flag & SEL_CONSTANT))
{
/* if get_relattval succeeded, it must be an opclause */
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
RegProcedure oprrest = get_oprrest(opno);
if (!oprrest)
s2 = (Selectivity) 0.5;
else
s2 = restriction_selectivity(oprrest, opno,
getrelid(relidx,
root->rtable),
attno,
constval, flag);
/*
* If we reach here, we have computed the same result
* that clause_selectivity would, so we can just use s2
* if it's the wrong oprrest. But if it's the right
* oprrest, add the clause to rqlist for later processing.
*/
switch (oprrest)
{
case F_SCALARLTSEL:
addRangeClause(&rqlist, clause, flag, true, s2);
break;
case F_SCALARGTSEL:
addRangeClause(&rqlist, clause, flag, false, s2);
break;
default:
/* Just merge the selectivity in generically */
s1 = s1 * s2;
break;
}
continue; /* drop to loop bottom */
}
}
/* Not the right form, so treat it generically. */
s2 = clause_selectivity(root, clause, varRelid);
s1 = s1 * s2;
}
/*
* Now scan the rangequery pair list.
*/
while (rqlist != NULL)
{
RangeQueryClause *rqnext;
if (rqlist->have_lobound && rqlist->have_hibound)
{
/* Successfully matched a pair of range clauses */
Selectivity s2 = rqlist->hibound + rqlist->lobound - 1.0;
if (s2 > 0.0)
{
/* All our hard work has paid off! */
s1 *= s2;
}
else
{
/* One or both is probably a default estimate,
* so punt and just merge them in generically.
*/
s1 *= rqlist->hibound * rqlist->lobound;
}
}
else
{
/* Only found one of a pair, merge it in generically */
if (rqlist->have_lobound)
s1 *= rqlist->lobound;
else
s1 *= rqlist->hibound;
}
/* release storage and advance */
rqnext = rqlist->next;
pfree(rqlist);
rqlist = rqnext;
}
return s1;
}
/*
* addRangeClause --- add a new range clause for clauselist_selectivity
*
* Here is where we try to match up pairs of range-query clauses
*/
static void
addRangeClause(RangeQueryClause **rqlist, Node *clause,
int flag, bool isLTsel, Selectivity s2)
{
RangeQueryClause *rqelem;
Node *var;
bool is_lobound;
/* get_relattval sets flag&SEL_RIGHT if the var is on the LEFT. */
if (flag & SEL_RIGHT)
{
var = (Node *) get_leftop((Expr *) clause);
is_lobound = ! isLTsel; /* x < something is high bound */
}
else
{
var = (Node *) get_rightop((Expr *) clause);
is_lobound = isLTsel; /* something < x is low bound */
}
for (rqelem = *rqlist; rqelem; rqelem = rqelem->next)
{
/* We use full equal() here because the "var" might be a function
* of one or more attributes of the same relation...
*/
if (! equal(var, rqelem->var))
continue;
/* Found the right group to put this clause in */
if (is_lobound)
{
if (! rqelem->have_lobound)
{
rqelem->have_lobound = true;
rqelem->lobound = s2;
}
else
{
/* We have found two similar clauses, such as
* x < y AND x < z. Keep only the more restrictive one.
*/
if (rqelem->lobound > s2)
rqelem->lobound = s2;
}
}
else
{
if (! rqelem->have_hibound)
{
rqelem->have_hibound = true;
rqelem->hibound = s2;
}
else
{
/* We have found two similar clauses, such as
* x > y AND x > z. Keep only the more restrictive one.
*/
if (rqelem->hibound > s2)
rqelem->hibound = s2;
}
}
return;
}
/* No matching var found, so make a new clause-pair data structure */
rqelem = (RangeQueryClause *) palloc(sizeof(RangeQueryClause));
rqelem->var = var;
if (is_lobound)
{
rqelem->have_lobound = true;
rqelem->have_hibound = false;
rqelem->lobound = s2;
}
else
{
rqelem->have_lobound = false;
rqelem->have_hibound = true;
rqelem->hibound = s2;
}
rqelem->next = *rqlist;
*rqlist = rqelem;
}
/*
* clause_selectivity -
* Compute the selectivity of a general boolean expression clause.
......
......@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.52 2000/01/24 02:12:55 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.53 2000/01/24 07:16:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -47,15 +47,13 @@
/* default selectivity estimate for inequalities such as "A < b" */
#define DEFAULT_INEQ_SEL (1.0 / 3.0)
static bool convert_to_scale(Datum value, Oid typid,
double *scaleval);
static void getattproperties(Oid relid, AttrNumber attnum,
Oid *typid,
int *typlen,
bool *typbyval,
int32 *typmod);
static bool getattstatistics(Oid relid, AttrNumber attnum,
Oid opid, Oid typid, int32 typmod,
Oid typid, int32 typmod,
double *nullfrac,
double *commonfrac,
Datum *commonval,
......@@ -100,7 +98,7 @@ eqsel(Oid opid,
&typid, &typlen, &typbyval, &typmod);
/* get stats for the attribute, if available */
if (getattstatistics(relid, attno, opid, typid, typmod,
if (getattstatistics(relid, attno, typid, typmod,
&nullfrac, &commonfrac, &commonval,
NULL, NULL))
{
......@@ -212,19 +210,18 @@ neqsel(Oid opid,
}
/*
* intltsel - Selectivity of "<" (also "<=") for integers.
* scalarltsel - Selectivity of "<" (also "<=") for scalars.
*
* Actually, this works and is used for all numeric types, so it should
* be renamed. In fact, it is also currently called for all manner of
* non-numeric types, for which it is NOT very helpful. That needs
* to be fixed.
* This routine works for any datatype (or pair of datatypes) known to
* convert_to_scalar(). If it is applied to some other datatype,
* it will return a default estimate.
*/
float64
intltsel(Oid opid,
Oid relid,
AttrNumber attno,
Datum value,
int32 flag)
scalarltsel(Oid opid,
Oid relid,
AttrNumber attno,
Datum value,
int32 flag)
{
float64 result;
......@@ -253,19 +250,19 @@ intltsel(Oid opid,
*/
oprtuple = get_operator_tuple(opid);
if (! HeapTupleIsValid(oprtuple))
elog(ERROR, "intltsel: no tuple for operator %u", opid);
elog(ERROR, "scalarltsel: no tuple for operator %u", opid);
ltype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprleft;
rtype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprright;
/* Convert the constant to a uniform comparison scale. */
if (! convert_to_scale(value,
((flag & SEL_RIGHT) ? rtype : ltype),
&val))
if (! convert_to_scalar(value,
((flag & SEL_RIGHT) ? rtype : ltype),
&val))
{
/* Ideally we'd produce an error here, on the grounds that
* the given operator shouldn't have intltsel registered as its
/* Ideally we'd produce an error here, on the grounds that the
* given operator shouldn't have scalarltsel registered as its
* selectivity func unless we can deal with its operand types.
* But currently, all manner of stuff is invoking intltsel,
* But currently, all manner of stuff is invoking scalarltsel,
* so give a default estimate until that can be fixed.
*/
*result = DEFAULT_INEQ_SEL;
......@@ -276,7 +273,7 @@ intltsel(Oid opid,
getattproperties(relid, attno,
&typid, &typlen, &typbyval, &typmod);
if (! getattstatistics(relid, attno, opid, typid, typmod,
if (! getattstatistics(relid, attno, typid, typmod,
NULL, NULL, NULL,
&loval, &hival))
{
......@@ -286,8 +283,8 @@ intltsel(Oid opid,
}
/* Convert the attribute's loval/hival to common scale. */
if (! convert_to_scale(loval, typid, &low) ||
! convert_to_scale(hival, typid, &high))
if (! convert_to_scalar(loval, typid, &low) ||
! convert_to_scalar(hival, typid, &high))
{
/* See above comments... */
if (! typbyval)
......@@ -341,23 +338,23 @@ intltsel(Oid opid,
}
/*
* intgtsel - Selectivity of ">" (also ">=") for integers.
* scalargtsel - Selectivity of ">" (also ">=") for integers.
*
* See above comments for intltsel.
* See above comments for scalarltsel.
*/
float64
intgtsel(Oid opid,
Oid relid,
AttrNumber attno,
Datum value,
int32 flag)
scalargtsel(Oid opid,
Oid relid,
AttrNumber attno,
Datum value,
int32 flag)
{
float64 result;
/* Compute selectivity of "<", then invert --- but only if we
* were able to produce a non-default estimate.
*/
result = intltsel(opid, relid, attno, value, flag);
result = scalarltsel(opid, relid, attno, value, flag);
if (*result != DEFAULT_INEQ_SEL)
*result = 1.0 - *result;
return result;
......@@ -429,14 +426,14 @@ neqjoinsel(Oid opid,
}
/*
* intltjoinsel - Join selectivity of "<" and "<="
* scalarltjoinsel - Join selectivity of "<" and "<=" for scalars
*/
float64
intltjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
scalarltjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
{
float64 result;
......@@ -446,14 +443,14 @@ intltjoinsel(Oid opid,
}
/*
* intgtjoinsel - Join selectivity of ">" and ">="
* scalargtjoinsel - Join selectivity of ">" and ">=" for scalars
*/
float64
intgtjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
scalargtjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
{
float64 result;
......@@ -463,21 +460,25 @@ intgtjoinsel(Oid opid,
}
/*
* convert_to_scale
* Convert a given value of the indicated type to the comparison
* scale needed by intltsel(). Returns "true" if successful.
* convert_to_scalar
* Convert a non-NULL value of the indicated type to the comparison
* scale needed by scalarltsel()/scalargtsel().
* Returns "true" if successful.
*
* All numeric datatypes are simply converted to their equivalent
* "double" values.
* Future extension: convert string-like types to some suitable scale.
* "double" values. String datatypes are converted to a crude scale
* using their first character (only if it is in the ASCII range,
* to try to avoid problems with non-ASCII collating sequences).
*/
static bool
convert_to_scale(Datum value, Oid typid,
double *scaleval)
bool
convert_to_scalar(Datum value, Oid typid,
double *scaleval)
{
/* Fast-path conversions for some built-in types */
switch (typid)
{
/*
* Built-in numeric types
*/
case BOOLOID:
*scaleval = (double) DatumGetUInt8(value);
return true;
......@@ -504,18 +505,54 @@ convert_to_scale(Datum value, Oid typid,
/* we can treat OIDs as integers... */
*scaleval = (double) DatumGetObjectId(value);
return true;
/*
* Built-in string types
*/
case CHAROID:
{
char ch = DatumGetChar(value);
if (ch >= 0 && ch < 127)
{
*scaleval = (double) ch;
return true;
}
break;
}
case BPCHAROID:
case VARCHAROID:
case TEXTOID:
/*
* Eventually this should get handled by somehow scaling as a
* string value. For now, we need to call it out to avoid
* falling into the default case, because there is a float8(text)
* function declared in pg_proc that will do the wrong thing :-(
*/
if (VARSIZE(DatumGetPointer(value)) > VARHDRSZ)
{
char ch = * (char *) VARDATA(DatumGetPointer(value));
if (ch >= 0 && ch < 127)
{
*scaleval = (double) ch;
return true;
}
}
break;
case NAMEOID:
{
NameData *nm = (NameData *) DatumGetPointer(value);
char ch = NameStr(*nm)[0];
if (ch >= 0 && ch < 127)
{
*scaleval = (double) ch;
return true;
}
break;
}
default:
{
/* See whether there is a registered type-conversion function,
/*
* See whether there is a registered type-conversion function,
* namely a procedure named "float8" with the right signature.
* If so, assume we can convert the value to the numeric scale.
*/
Oid oid_array[FUNC_MAX_ARGS];
HeapTuple ftup;
......@@ -589,7 +626,9 @@ getattproperties(Oid relid, AttrNumber attnum,
* after use if the data type is not by-value.)
*/
static bool
getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid,
getattstatistics(Oid relid,
AttrNumber attnum,
Oid typid,
int32 typmod,
double *nullfrac,
double *commonfrac,
......@@ -603,8 +642,15 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid,
Oid typelem;
bool isnull;
/* We assume that there will only be one entry in pg_statistic
* for the given rel/att. Someday, VACUUM might store more than one...
/*
* We assume that there will only be one entry in pg_statistic for
* the given rel/att, so we search WITHOUT considering the staop
* column. Someday, VACUUM might store more than one entry per rel/att,
* corresponding to more than one possible sort ordering defined for
* the column type. However, to make that work we will need to figure
* out which staop to search for --- it's not necessarily the one we
* have at hand! (For example, we might have a '>' operator rather than
* the '<' operator that will appear in staop.)
*/
tuple = SearchSysCacheTuple(STATRELID,
ObjectIdGetDatum(relid),
......
......@@ -36,7 +36,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.10 2000/01/24 02:12:57 momjian Exp $
* $Id: catversion.h,v 1.11 2000/01/24 07:16:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -52,6 +52,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200001251
#define CATALOG_VERSION_NO 200001241
#endif
此差异已折叠。
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_proc.h,v 1.115 2000/01/22 23:50:23 tgl Exp $
* $Id: pg_proc.h,v 1.116 2000/01/24 07:16:52 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
......@@ -219,21 +219,21 @@ DESCR("btree cost estimator");
/* OIDS 100 - 199 */
DATA(insert OID = 1272 ( eqsel PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100 eqsel - ));
DESCR("general selectivity");
DESCR("restriction selectivity of = and related operators");
DATA(insert OID = 102 ( neqsel PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100 neqsel - ));
DESCR("not-equal selectivity");
DATA(insert OID = 103 ( intltsel PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100 intltsel - ));
DESCR("selectivity");
DATA(insert OID = 104 ( intgtsel PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100 intgtsel - ));
DESCR("selectivity");
DESCR("restriction selectivity of <> and related operators");
DATA(insert OID = 103 ( scalarltsel PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100 scalarltsel - ));
DESCR("restriction selectivity of < and related operators on scalar datatypes");
DATA(insert OID = 104 ( scalargtsel PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100 scalargtsel - ));
DESCR("restriction selectivity of > and related operators on scalar datatypes");
DATA(insert OID = 105 ( eqjoinsel PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100 eqjoinsel - ));
DESCR("selectivity");
DESCR("join selectivity of = and related operators");
DATA(insert OID = 106 ( neqjoinsel PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100 neqjoinsel - ));
DESCR("selectivity");
DATA(insert OID = 107 ( intltjoinsel PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100 intltjoinsel - ));
DESCR("selectivity");
DATA(insert OID = 108 ( intgtjoinsel PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100 intgtjoinsel - ));
DESCR("selectivity");
DESCR("join selectivity of <> and related operators");
DATA(insert OID = 107 ( scalarltjoinsel PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100 scalarltjoinsel - ));
DESCR("join selectivity of < and related operators on scalar datatypes");
DATA(insert OID = 108 ( scalargtjoinsel PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100 scalargtjoinsel - ));
DESCR("join selectivity of > and related operators on scalar datatypes");
DATA(insert OID = 112 ( int4_text PGUID 11 f t t 1 f 25 "23" 100 0 0 100 int4_text - ));
DESCR("convert int4 to text");
......@@ -292,9 +292,9 @@ DESCR("contained in");
DATA(insert OID = 138 ( box_center PGUID 11 f t t 1 f 600 "603" 100 1 0 100 box_center - ));
DESCR("center of");
DATA(insert OID = 139 ( areasel PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100 areasel - ));
DESCR("selectivity");
DESCR("restriction selectivity for operators on areas");
DATA(insert OID = 140 ( areajoinsel PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100 areajoinsel - ));
DESCR("selectivity");
DESCR("join selectivity for operators on areas");
DATA(insert OID = 141 ( int4mul PGUID 11 f t t 2 f 23 "23 23" 100 0 0 100 int4mul - ));
DESCR("multiply");
DATA(insert OID = 142 ( int4fac PGUID 11 f t t 1 f 23 "23" 100 0 0 100 int4fac - ));
......
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: builtins.h,v 1.97 2000/01/22 23:50:27 tgl Exp $
* $Id: builtins.h,v 1.98 2000/01/24 07:16:47 tgl Exp $
*
* NOTES
* This should normally only be included by fmgr.h.
......@@ -389,12 +389,13 @@ extern char *deparse_expression(Node *expr, List *rangetables,
/* selfuncs.c */
extern float64 eqsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
extern float64 neqsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
extern float64 intltsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
extern float64 intgtsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
extern float64 scalarltsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
extern float64 scalargtsel(Oid opid, Oid relid, AttrNumber attno, Datum value, int32 flag);
extern float64 eqjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2);
extern float64 neqjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2);
extern float64 intltjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2);
extern float64 intgtjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2);
extern float64 scalarltjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2);
extern float64 scalargtjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2);
extern bool convert_to_scalar(Datum value, Oid typid, double *scaleval);
extern void btcostestimate(Query *root, RelOptInfo *rel,
IndexOptInfo *index, List *indexQuals,
......
......@@ -7,7 +7,7 @@
--
-- Copyright (c) 1994, Regents of the University of California
--
-- $Id: complex.source,v 1.5 2000/01/22 23:50:30 tgl Exp $
-- $Id: complex.source,v 1.6 2000/01/24 07:16:48 tgl Exp $
--
---------------------------------------------------------------------------
......@@ -148,15 +148,13 @@ CREATE FUNCTION complex_abs_ge(complex, complex) RETURNS bool
CREATE FUNCTION complex_abs_gt(complex, complex) RETURNS bool
AS '_OBJWD_/complex.so' LANGUAGE 'c';
-- the restrict and join selectivity functions are bogus (notice we only
-- have intltsel, eqsel and intgtsel)
CREATE OPERATOR < (
leftarg = complex, rightarg = complex, procedure = complex_abs_lt,
restrict = intltsel, join = intltjoinsel
restrict = scalarltsel, join = scalarltjoinsel
);
CREATE OPERATOR <= (
leftarg = complex, rightarg = complex, procedure = complex_abs_le,
restrict = intltsel, join = intltjoinsel
restrict = scalarltsel, join = scalarltjoinsel
);
CREATE OPERATOR = (
leftarg = complex, rightarg = complex, procedure = complex_abs_eq,
......@@ -164,11 +162,11 @@ CREATE OPERATOR = (
);
CREATE OPERATOR >= (
leftarg = complex, rightarg = complex, procedure = complex_abs_ge,
restrict = intgtsel, join = intgtjoinsel
restrict = scalargtsel, join = scalargtjoinsel
);
CREATE OPERATOR > (
leftarg = complex, rightarg = complex, procedure = complex_abs_gt,
restrict = intgtsel, join = intgtjoinsel
restrict = scalargtsel, join = scalargtjoinsel
);
INSERT INTO pg_opclass VALUES ('complex_abs_ops');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册