📄 selfuncs.c
字号:
/*------------------------------------------------------------------------- * * 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: /usr/local/cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.30.2.1 1999/08/02 05:24:57 scrappy Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catname.h"#include "catalog/pg_statistic.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.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 float32data getattdisbursion(Oid relid, AttrNumber attnum);static void gethilokey(Oid relid, AttrNumber attnum, Oid opid, char **high, char **low);/* * eqsel - Selectivity of "=" for any data type. */float64eqsel(Oid opid, Oid relid, AttrNumber attno, char *value, int32 flag){ float64 result; result = (float64) palloc(sizeof(float64data)); if (NONVALUE(attno) || NONVALUE(relid)) *result = 0.1; else *result = (float64data) getattdisbursion(relid, (int) attno); return result;}/* * neqsel - Selectivity of "!=" for any data type. */float64neqsel(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. */float64intltsel(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)) { float32data nvals; nvals = getattdisbursion(relid, (int) attno); if (nvals == 0) *result = 1.0 / 3.0; else { *result = 3.0 * (float64data) nvals; if (*result > 1.0) *result = 1; } } 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. */float64intgtsel(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 "=" */float64eqjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2){ float64 result; float32data num1, num2, max; result = (float64) palloc(sizeof(float64data)); if (NONVALUE(attno1) || NONVALUE(relid1) || NONVALUE(attno2) || NONVALUE(relid2)) *result = 0.1; else { num1 = getattdisbursion(relid1, (int) attno1); num2 = getattdisbursion(relid2, (int) attno2); max = (num1 > num2) ? num1 : num2; if (max == 0) *result = 1.0; else *result = (float64data) max; } return result;}/* * neqjoinsel - Join selectivity of "!=" */float64neqjoinsel(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 "<" */float64intltjoinsel(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 ">" */float64intgtjoinsel(Oid opid, Oid relid1, AttrNumber attno1, Oid relid2, AttrNumber attno2){ float64 result; result = (float64) palloc(sizeof(float64data)); *result = 1.0 / 3.0; return result;}/* * getattdisbursion - Retrieves the number of values within an attribute. * * Note: * getattdisbursion 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 float32datagetattdisbursion(Oid relid, AttrNumber attnum){ HeapTuple atp; float32data nvals; int32 ntuples; atp = SearchSysCacheTuple(ATTNUM, ObjectIdGetDatum(relid), Int16GetDatum(attnum), 0, 0); if (!HeapTupleIsValid(atp)) { elog(ERROR, "getattdisbursion: no attribute tuple %u %d", relid, attnum); return 0; } nvals = ((Form_pg_attribute) GETSTRUCT(atp))->attdisbursion; 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(ERROR, "getattdisbursion: no relation tuple %u", relid); return 0; } ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples; /* Look above how nvals is used. - vadim 04/09/97 */ if (ntuples > 0) nvals = 1.0 / ntuples; 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 voidgethilokey(Oid relid, AttrNumber attnum, Oid opid, char **high, char **low){ Relation rel; HeapScanDesc scan; static ScanKeyData key[3] = { {0, Anum_pg_statistic_starelid, F_OIDEQ, {0, 0, F_OIDEQ}}, {0, Anum_pg_statistic_staattnum, F_INT2EQ, {0, 0, F_INT2EQ}}, {0, Anum_pg_statistic_staop, F_OIDEQ, {0, 0, F_OIDEQ}} }; bool isnull; HeapTuple tuple; rel = heap_openr(StatisticRelationName); key[0].sk_argument = ObjectIdGetDatum(relid); key[1].sk_argument = Int16GetDatum((int16) attnum); key[2].sk_argument = ObjectIdGetDatum(opid); scan = heap_beginscan(rel, 0, SnapshotNow, 3, key); tuple = heap_getnext(scan, 0); if (!HeapTupleIsValid(tuple)) { *high = "n"; *low = "n"; /* * XXX elog(ERROR, "gethilokey: statistic tuple not * found"); */ return; } *high = textout((struct varlena *) heap_getattr(tuple, Anum_pg_statistic_stahikey, RelationGetDescr(rel),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -