mirror of
https://github.com/postgres/postgres.git
synced 2025-11-01 21:31:19 +03:00
Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
585
src/backend/utils/adt/selfuncs.c
Normal file
585
src/backend/utils/adt/selfuncs.c
Normal file
@@ -0,0 +1,585 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* selfuncs.c--
|
||||
* Selectivity functions for system catalogs and builtin types
|
||||
*
|
||||
* These routines are registered in the operator catalog in the
|
||||
* "oprrest" and "oprjoin" attributes.
|
||||
*
|
||||
* XXX check all the functions--I suspect them to be 1-based.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "utils/tqual.h" /* for NowTimeQual */
|
||||
#include "fmgr.h"
|
||||
#include "utils/builtins.h" /* for textout() prototype
|
||||
and where the declarations go */
|
||||
#include "utils/elog.h"
|
||||
#include "utils/palloc.h"
|
||||
|
||||
#include "catalog/catname.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/lsyscache.h" /* for get_oprrest() */
|
||||
#include "catalog/pg_statistic.h"
|
||||
|
||||
|
||||
/* N is not a valid var/constant or relation id */
|
||||
#define NONVALUE(N) ((N) == -1)
|
||||
|
||||
/*
|
||||
* generalize the test for functional index selectivity request
|
||||
*/
|
||||
#define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttrNumber)
|
||||
|
||||
static int32 getattnvals(Oid relid, AttrNumber attnum);
|
||||
static void gethilokey(Oid relid, AttrNumber attnum, Oid opid,
|
||||
char **high, char **low);
|
||||
|
||||
|
||||
/*
|
||||
* eqsel - Selectivity of "=" for any data type.
|
||||
*/
|
||||
float64
|
||||
eqsel(Oid opid,
|
||||
Oid relid,
|
||||
AttrNumber attno,
|
||||
char *value,
|
||||
int32 flag)
|
||||
{
|
||||
int32 nvals;
|
||||
float64 result;
|
||||
|
||||
result = (float64) palloc(sizeof(float64data));
|
||||
if (NONVALUE(attno) || NONVALUE(relid))
|
||||
*result = 0.1;
|
||||
else {
|
||||
nvals = getattnvals(relid, (int) attno);
|
||||
if (nvals == 0)
|
||||
*result = 0.0;
|
||||
else
|
||||
*result = 1.0 / nvals;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* neqsel - Selectivity of "!=" for any data type.
|
||||
*/
|
||||
float64
|
||||
neqsel(Oid opid,
|
||||
Oid relid,
|
||||
AttrNumber attno,
|
||||
char *value,
|
||||
int32 flag)
|
||||
{
|
||||
float64 result;
|
||||
|
||||
result = eqsel(opid, relid, attno, value, flag);
|
||||
*result = 1.0 - *result;
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* intltsel - Selectivity of "<" for integers.
|
||||
* Should work for both longs and shorts.
|
||||
*/
|
||||
float64
|
||||
intltsel(Oid opid,
|
||||
Oid relid,
|
||||
AttrNumber attno,
|
||||
int32 value,
|
||||
int32 flag)
|
||||
{
|
||||
float64 result;
|
||||
char *highchar, *lowchar;
|
||||
long val, high, low, top, bottom;
|
||||
|
||||
result = (float64) palloc(sizeof(float64data));
|
||||
if (NONVALUE(attno) || NONVALUE(relid))
|
||||
*result = 1.0 / 3;
|
||||
else {
|
||||
/* XXX val = atol(value);*/
|
||||
val = value;
|
||||
gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
|
||||
if (*highchar == 'n' || *lowchar == 'n') {
|
||||
*result = 1.0/3.0;
|
||||
return (result);
|
||||
}
|
||||
high = atol(highchar);
|
||||
low = atol(lowchar);
|
||||
if ((flag & SEL_RIGHT && val < low) ||
|
||||
(!(flag & SEL_RIGHT) && val > high)) {
|
||||
int nvals;
|
||||
nvals = getattnvals(relid, (int) attno);
|
||||
if (nvals == 0)
|
||||
*result = 1.0 / 3.0;
|
||||
else
|
||||
*result = 3.0 / nvals;
|
||||
}else {
|
||||
bottom = high - low;
|
||||
if (bottom == 0)
|
||||
++bottom;
|
||||
if (flag & SEL_RIGHT)
|
||||
top = val - low;
|
||||
else
|
||||
top = high - val;
|
||||
if (top > bottom)
|
||||
*result = 1.0;
|
||||
else {
|
||||
if (top == 0)
|
||||
++top;
|
||||
*result = ((1.0 * top) / bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* intgtsel - Selectivity of ">" for integers.
|
||||
* Should work for both longs and shorts.
|
||||
*/
|
||||
float64
|
||||
intgtsel(Oid opid,
|
||||
Oid relid,
|
||||
AttrNumber attno,
|
||||
int32 value,
|
||||
int32 flag)
|
||||
{
|
||||
float64 result;
|
||||
int notflag;
|
||||
|
||||
if (flag & 0)
|
||||
notflag = flag & ~SEL_RIGHT;
|
||||
else
|
||||
notflag = flag | SEL_RIGHT;
|
||||
result = intltsel(opid, relid, attno, value, (int32) notflag);
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* eqjoinsel - Join selectivity of "="
|
||||
*/
|
||||
float64
|
||||
eqjoinsel(Oid opid,
|
||||
Oid relid1,
|
||||
AttrNumber attno1,
|
||||
Oid relid2,
|
||||
AttrNumber attno2)
|
||||
{
|
||||
float64 result;
|
||||
int32 num1, num2, max;
|
||||
|
||||
result = (float64) palloc(sizeof(float64data));
|
||||
if (NONVALUE(attno1) || NONVALUE(relid1) ||
|
||||
NONVALUE(attno2) || NONVALUE(relid2))
|
||||
*result = 0.1;
|
||||
else {
|
||||
num1 = getattnvals(relid1, (int) attno1);
|
||||
num2 = getattnvals(relid2, (int) attno2);
|
||||
max = (num1 > num2) ? num1 : num2;
|
||||
if (max == 0)
|
||||
*result = 1.0;
|
||||
else
|
||||
*result = 1.0 / max;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* neqjoinsel - Join selectivity of "!="
|
||||
*/
|
||||
float64
|
||||
neqjoinsel(Oid opid,
|
||||
Oid relid1,
|
||||
AttrNumber attno1,
|
||||
Oid relid2,
|
||||
AttrNumber attno2)
|
||||
{
|
||||
float64 result;
|
||||
|
||||
result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
|
||||
*result = 1.0 - *result;
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* intltjoinsel - Join selectivity of "<"
|
||||
*/
|
||||
float64
|
||||
intltjoinsel(Oid opid,
|
||||
Oid relid1,
|
||||
AttrNumber attno1,
|
||||
Oid relid2,
|
||||
AttrNumber attno2)
|
||||
{
|
||||
float64 result;
|
||||
|
||||
result = (float64) palloc(sizeof(float64data));
|
||||
*result = 1.0 / 3.0;
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* intgtjoinsel - Join selectivity of ">"
|
||||
*/
|
||||
float64
|
||||
intgtjoinsel(Oid opid,
|
||||
Oid relid1,
|
||||
AttrNumber attno1,
|
||||
Oid relid2,
|
||||
AttrNumber attno2)
|
||||
{
|
||||
float64 result;
|
||||
|
||||
result = (float64) palloc(sizeof(float64data));
|
||||
*result = 1.0 / 3.0;
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* getattnvals - Retrieves the number of values within an attribute.
|
||||
*
|
||||
* Note:
|
||||
* getattnvals and gethilokey both currently use keyed
|
||||
* relation scans and amgetattr. Alternatively,
|
||||
* the relation scan could be non-keyed and the tuple
|
||||
* returned could be cast (struct X *) tuple + tuple->t_hoff.
|
||||
* The first method is good for testing the implementation,
|
||||
* but the second may ultimately be faster?!? In any case,
|
||||
* using the cast instead of amgetattr would be
|
||||
* more efficient. However, the cast will not work
|
||||
* for gethilokey which accesses stahikey in struct statistic.
|
||||
*/
|
||||
static int32
|
||||
getattnvals(Oid relid, AttrNumber attnum)
|
||||
{
|
||||
HeapTuple atp;
|
||||
int nvals;
|
||||
|
||||
atp = SearchSysCacheTuple(ATTNUM,
|
||||
ObjectIdGetDatum(relid),
|
||||
Int16GetDatum(attnum),
|
||||
0,0);
|
||||
if (!HeapTupleIsValid(atp)) {
|
||||
elog(WARN, "getattnvals: no attribute tuple %d %d",
|
||||
relid, attnum);
|
||||
return(0);
|
||||
}
|
||||
nvals = ((AttributeTupleForm ) GETSTRUCT(atp))->attnvals;
|
||||
if (nvals > 0) return(nvals);
|
||||
|
||||
atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(relid),
|
||||
0,0,0);
|
||||
/* XXX -- use number of tuples as number of distinctive values
|
||||
just for now, in case number of distinctive values is
|
||||
not cached */
|
||||
if (!HeapTupleIsValid(atp)) {
|
||||
elog(WARN, "getattnvals: no relation tuple %d", relid);
|
||||
return(0);
|
||||
}
|
||||
nvals = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
|
||||
return(nvals);
|
||||
}
|
||||
|
||||
/*
|
||||
* gethilokey - Returns a pointer to strings containing
|
||||
* the high and low keys within an attribute.
|
||||
*
|
||||
* Currently returns "0", and "0" in high and low if the statistic
|
||||
* catalog does not contain the proper tuple. Eventually, the
|
||||
* statistic demon should have the tuple maintained, and it should
|
||||
* elog() if the tuple is missing.
|
||||
*
|
||||
* XXX Question: is this worth sticking in the catalog caches,
|
||||
* or will this get invalidated too often?
|
||||
*/
|
||||
static void
|
||||
gethilokey(Oid relid,
|
||||
AttrNumber attnum,
|
||||
Oid opid,
|
||||
char **high,
|
||||
char **low)
|
||||
{
|
||||
register Relation rdesc;
|
||||
register HeapScanDesc sdesc;
|
||||
static ScanKeyData key[3] = {
|
||||
{ 0, Anum_pg_statistic_starelid, F_OIDEQ },
|
||||
{ 0, Anum_pg_statistic_staattnum, F_INT2EQ },
|
||||
{ 0, Anum_pg_statistic_staop, F_OIDEQ }
|
||||
};
|
||||
bool isnull;
|
||||
HeapTuple tuple;
|
||||
|
||||
rdesc = heap_openr(StatisticRelationName);
|
||||
|
||||
key[0].sk_argument = ObjectIdGetDatum(relid);
|
||||
key[1].sk_argument = Int16GetDatum((int16) attnum);
|
||||
key[2].sk_argument = ObjectIdGetDatum(opid);
|
||||
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 3, key);
|
||||
tuple = heap_getnext(sdesc, 0, (Buffer *) NULL);
|
||||
if (!HeapTupleIsValid(tuple)) {
|
||||
*high = "n";
|
||||
*low = "n";
|
||||
/* XXX elog(WARN, "gethilokey: statistic tuple not found");*/
|
||||
return;
|
||||
}
|
||||
*high = textout((struct varlena *)
|
||||
heap_getattr(tuple,
|
||||
InvalidBuffer,
|
||||
Anum_pg_statistic_stahikey,
|
||||
RelationGetTupleDescriptor(rdesc),
|
||||
&isnull));
|
||||
if (isnull)
|
||||
elog(DEBUG, "gethilokey: high key is null");
|
||||
*low = textout((struct varlena *)
|
||||
heap_getattr(tuple,
|
||||
InvalidBuffer,
|
||||
Anum_pg_statistic_stalokey,
|
||||
RelationGetTupleDescriptor(rdesc),
|
||||
&isnull));
|
||||
if (isnull)
|
||||
elog(DEBUG, "gethilokey: low key is null");
|
||||
heap_endscan(sdesc);
|
||||
heap_close(rdesc);
|
||||
}
|
||||
|
||||
float64
|
||||
btreesel(Oid operatorObjectId,
|
||||
Oid indrelid,
|
||||
AttrNumber attributeNumber,
|
||||
char *constValue,
|
||||
int32 constFlag,
|
||||
int32 nIndexKeys,
|
||||
Oid indexrelid)
|
||||
{
|
||||
float64 result;
|
||||
float64data resultData;
|
||||
|
||||
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
|
||||
/*
|
||||
* Need to call the functions selectivity
|
||||
* function here. For now simply assume it's
|
||||
* 1/3 since functions don't currently
|
||||
* have selectivity functions
|
||||
*/
|
||||
resultData = 1.0 / 3.0;
|
||||
result = &resultData;
|
||||
}
|
||||
else {
|
||||
result = (float64)fmgr(get_oprrest (operatorObjectId),
|
||||
(char*)operatorObjectId,
|
||||
(char*)indrelid,
|
||||
(char*)attributeNumber,
|
||||
(char*)constValue,
|
||||
(char*)constFlag,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!PointerIsValid(result))
|
||||
elog(WARN, "Btree Selectivity: bad pointer");
|
||||
if (*result < 0.0 || *result > 1.0)
|
||||
elog(WARN, "Btree Selectivity: bad value %lf", *result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
float64
|
||||
btreenpage(Oid operatorObjectId,
|
||||
Oid indrelid,
|
||||
AttrNumber attributeNumber,
|
||||
char *constValue,
|
||||
int32 constFlag,
|
||||
int32 nIndexKeys,
|
||||
Oid indexrelid)
|
||||
{
|
||||
float64 temp, result;
|
||||
float64data tempData;
|
||||
HeapTuple atp;
|
||||
int npage;
|
||||
|
||||
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
|
||||
/*
|
||||
* Need to call the functions selectivity
|
||||
* function here. For now simply assume it's
|
||||
* 1/3 since functions don't currently
|
||||
* have selectivity functions
|
||||
*/
|
||||
tempData = 1.0 / 3.0;
|
||||
temp = &tempData;
|
||||
}
|
||||
else {
|
||||
temp = (float64)fmgr(get_oprrest (operatorObjectId),
|
||||
(char*)operatorObjectId,
|
||||
(char*)indrelid,
|
||||
(char*)attributeNumber,
|
||||
(char*)constValue,
|
||||
(char*)constFlag,
|
||||
NULL);
|
||||
}
|
||||
atp = SearchSysCacheTuple(RELOID,
|
||||
ObjectIdGetDatum(indexrelid),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(atp)) {
|
||||
elog(WARN, "btreenpage: no index tuple %d", indexrelid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
|
||||
result = (float64)palloc(sizeof(float64data));
|
||||
*result = *temp * npage;
|
||||
return(result);
|
||||
}
|
||||
|
||||
float64
|
||||
hashsel(Oid operatorObjectId,
|
||||
Oid indrelid,
|
||||
AttrNumber attributeNumber,
|
||||
char *constValue,
|
||||
int32 constFlag,
|
||||
int32 nIndexKeys,
|
||||
Oid indexrelid)
|
||||
{
|
||||
|
||||
float64 result;
|
||||
float64data resultData;
|
||||
HeapTuple atp;
|
||||
int ntuples;
|
||||
|
||||
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
|
||||
/*
|
||||
* Need to call the functions selectivity
|
||||
* function here. For now simply use 1/Number of Tuples
|
||||
* since functions don't currently
|
||||
* have selectivity functions
|
||||
*/
|
||||
|
||||
atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(atp)) {
|
||||
elog(WARN, "hashsel: no index tuple %d", indexrelid);
|
||||
return(0);
|
||||
}
|
||||
ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
|
||||
if (ntuples > 0) {
|
||||
resultData = 1.0 / (float64data) ntuples;
|
||||
}
|
||||
else {
|
||||
resultData = (float64data) (1.0 / 100.0);
|
||||
}
|
||||
result = &resultData;
|
||||
|
||||
}
|
||||
else {
|
||||
result = (float64)fmgr(get_oprrest (operatorObjectId),
|
||||
(char*)operatorObjectId,
|
||||
(char*)indrelid,
|
||||
(char*)attributeNumber,
|
||||
(char*)constValue,
|
||||
(char*)constFlag,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!PointerIsValid(result))
|
||||
elog(WARN, "Hash Table Selectivity: bad pointer");
|
||||
if (*result < 0.0 || *result > 1.0)
|
||||
elog(WARN, "Hash Table Selectivity: bad value %lf", *result);
|
||||
|
||||
return(result);
|
||||
|
||||
|
||||
}
|
||||
|
||||
float64
|
||||
hashnpage(Oid operatorObjectId,
|
||||
Oid indrelid,
|
||||
AttrNumber attributeNumber,
|
||||
char *constValue,
|
||||
int32 constFlag,
|
||||
int32 nIndexKeys,
|
||||
Oid indexrelid)
|
||||
{
|
||||
float64 temp, result;
|
||||
float64data tempData;
|
||||
HeapTuple atp;
|
||||
int npage;
|
||||
int ntuples;
|
||||
|
||||
atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(atp)) {
|
||||
elog(WARN, "hashsel: no index tuple %d", indexrelid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
|
||||
/*
|
||||
* Need to call the functions selectivity
|
||||
* function here. For now, use 1/Number of Tuples
|
||||
* since functions don't currently
|
||||
* have selectivity functions
|
||||
*/
|
||||
|
||||
ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
|
||||
if (ntuples > 0) {
|
||||
tempData = 1.0 / (float64data) ntuples;
|
||||
}
|
||||
else {
|
||||
tempData = (float64data) (1.0 / 100.0);
|
||||
}
|
||||
temp = &tempData;
|
||||
|
||||
}
|
||||
else {
|
||||
temp = (float64)fmgr(get_oprrest (operatorObjectId),
|
||||
(char*)operatorObjectId,
|
||||
(char*)indrelid,
|
||||
(char*)attributeNumber,
|
||||
(char*)constValue,
|
||||
(char*)constFlag,
|
||||
NULL);
|
||||
}
|
||||
|
||||
npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
|
||||
result = (float64)palloc(sizeof(float64data));
|
||||
*result = *temp * npage;
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
float64
|
||||
rtsel(Oid operatorObjectId,
|
||||
Oid indrelid,
|
||||
AttrNumber attributeNumber,
|
||||
char *constValue,
|
||||
int32 constFlag,
|
||||
int32 nIndexKeys,
|
||||
Oid indexrelid)
|
||||
{
|
||||
return (btreesel(operatorObjectId, indrelid, attributeNumber,
|
||||
constValue, constFlag, nIndexKeys, indexrelid));
|
||||
}
|
||||
|
||||
float64
|
||||
rtnpage(Oid operatorObjectId,
|
||||
Oid indrelid,
|
||||
AttrNumber attributeNumber,
|
||||
char *constValue,
|
||||
int32 constFlag,
|
||||
int32 nIndexKeys,
|
||||
Oid indexrelid)
|
||||
{
|
||||
return (btreenpage(operatorObjectId, indrelid, attributeNumber,
|
||||
constValue, constFlag, nIndexKeys, indexrelid));
|
||||
}
|
||||
Reference in New Issue
Block a user