selfuncs.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:16k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * selfuncs.c
  4.  *   Selectivity functions for system catalogs and builtin types
  5.  *
  6.  *   These routines are registered in the operator catalog in the
  7.  *   "oprrest" and "oprjoin" attributes.
  8.  *
  9.  *   XXX check all the functions--I suspect them to be 1-based.
  10.  *
  11.  * Copyright (c) 1994, Regents of the University of California
  12.  *
  13.  *
  14.  * IDENTIFICATION
  15.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.30.2.1 1999/08/02 05:24:57 scrappy Exp $
  16.  *
  17.  *-------------------------------------------------------------------------
  18.  */
  19. #include "postgres.h"
  20. #include "access/heapam.h"
  21. #include "catalog/catname.h"
  22. #include "catalog/pg_statistic.h"
  23. #include "utils/builtins.h"
  24. #include "utils/lsyscache.h"
  25. #include "utils/syscache.h"
  26. /* N is not a valid var/constant or relation id */
  27. #define NONVALUE(N) ((N) == -1)
  28. /*
  29.  * generalize the test for functional index selectivity request
  30.  */
  31. #define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttrNumber)
  32. static float32data getattdisbursion(Oid relid, AttrNumber attnum);
  33. static void gethilokey(Oid relid, AttrNumber attnum, Oid opid,
  34.    char **high, char **low);
  35. /*
  36.  * eqsel - Selectivity of "=" for any data type.
  37.  */
  38. float64
  39. eqsel(Oid opid,
  40.   Oid relid,
  41.   AttrNumber attno,
  42.   char *value,
  43.   int32 flag)
  44. {
  45. float64 result;
  46. result = (float64) palloc(sizeof(float64data));
  47. if (NONVALUE(attno) || NONVALUE(relid))
  48. *result = 0.1;
  49. else
  50. *result = (float64data) getattdisbursion(relid, (int) attno);
  51. return result;
  52. }
  53. /*
  54.  * neqsel - Selectivity of "!=" for any data type.
  55.  */
  56. float64
  57. neqsel(Oid opid,
  58.    Oid relid,
  59.    AttrNumber attno,
  60.    char *value,
  61.    int32 flag)
  62. {
  63. float64 result;
  64. result = eqsel(opid, relid, attno, value, flag);
  65. *result = 1.0 - *result;
  66. return result;
  67. }
  68. /*
  69.  * intltsel - Selectivity of "<" for integers.
  70.  *   Should work for both longs and shorts.
  71.  */
  72. float64
  73. intltsel(Oid opid,
  74.  Oid relid,
  75.  AttrNumber attno,
  76.  int32 value,
  77.  int32 flag)
  78. {
  79. float64 result;
  80. char    *highchar,
  81.    *lowchar;
  82. long val,
  83. high,
  84. low,
  85. top,
  86. bottom;
  87. result = (float64) palloc(sizeof(float64data));
  88. if (NONVALUE(attno) || NONVALUE(relid))
  89. *result = 1.0 / 3;
  90. else
  91. {
  92. /* XXX val = atol(value); */
  93. val = value;
  94. gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
  95. if (*highchar == 'n' || *lowchar == 'n')
  96. {
  97. *result = 1.0 / 3.0;
  98. return result;
  99. }
  100. high = atol(highchar);
  101. low = atol(lowchar);
  102. if ((flag & SEL_RIGHT && val < low) ||
  103. (!(flag & SEL_RIGHT) && val > high))
  104. {
  105. float32data nvals;
  106. nvals = getattdisbursion(relid, (int) attno);
  107. if (nvals == 0)
  108. *result = 1.0 / 3.0;
  109. else
  110. {
  111. *result = 3.0 * (float64data) nvals;
  112. if (*result > 1.0)
  113. *result = 1;
  114. }
  115. }
  116. else
  117. {
  118. bottom = high - low;
  119. if (bottom == 0)
  120. ++bottom;
  121. if (flag & SEL_RIGHT)
  122. top = val - low;
  123. else
  124. top = high - val;
  125. if (top > bottom)
  126. *result = 1.0;
  127. else
  128. {
  129. if (top == 0)
  130. ++top;
  131. *result = ((1.0 * top) / bottom);
  132. }
  133. }
  134. }
  135. return result;
  136. }
  137. /*
  138.  * intgtsel - Selectivity of ">" for integers.
  139.  *   Should work for both longs and shorts.
  140.  */
  141. float64
  142. intgtsel(Oid opid,
  143.  Oid relid,
  144.  AttrNumber attno,
  145.  int32 value,
  146.  int32 flag)
  147. {
  148. float64 result;
  149. int notflag;
  150. if (flag & 0)
  151. notflag = flag & ~SEL_RIGHT;
  152. else
  153. notflag = flag | SEL_RIGHT;
  154. result = intltsel(opid, relid, attno, value, (int32) notflag);
  155. return result;
  156. }
  157. /*
  158.  * eqjoinsel - Join selectivity of "="
  159.  */
  160. float64
  161. eqjoinsel(Oid opid,
  162.   Oid relid1,
  163.   AttrNumber attno1,
  164.   Oid relid2,
  165.   AttrNumber attno2)
  166. {
  167. float64 result;
  168. float32data num1,
  169. num2,
  170. max;
  171. result = (float64) palloc(sizeof(float64data));
  172. if (NONVALUE(attno1) || NONVALUE(relid1) ||
  173. NONVALUE(attno2) || NONVALUE(relid2))
  174. *result = 0.1;
  175. else
  176. {
  177. num1 = getattdisbursion(relid1, (int) attno1);
  178. num2 = getattdisbursion(relid2, (int) attno2);
  179. max = (num1 > num2) ? num1 : num2;
  180. if (max == 0)
  181. *result = 1.0;
  182. else
  183. *result = (float64data) max;
  184. }
  185. return result;
  186. }
  187. /*
  188.  * neqjoinsel - Join selectivity of "!="
  189.  */
  190. float64
  191. neqjoinsel(Oid opid,
  192.    Oid relid1,
  193.    AttrNumber attno1,
  194.    Oid relid2,
  195.    AttrNumber attno2)
  196. {
  197. float64 result;
  198. result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
  199. *result = 1.0 - *result;
  200. return result;
  201. }
  202. /*
  203.  * intltjoinsel - Join selectivity of "<"
  204.  */
  205. float64
  206. intltjoinsel(Oid opid,
  207.  Oid relid1,
  208.  AttrNumber attno1,
  209.  Oid relid2,
  210.  AttrNumber attno2)
  211. {
  212. float64 result;
  213. result = (float64) palloc(sizeof(float64data));
  214. *result = 1.0 / 3.0;
  215. return result;
  216. }
  217. /*
  218.  * intgtjoinsel - Join selectivity of ">"
  219.  */
  220. float64
  221. intgtjoinsel(Oid opid,
  222.  Oid relid1,
  223.  AttrNumber attno1,
  224.  Oid relid2,
  225.  AttrNumber attno2)
  226. {
  227. float64 result;
  228. result = (float64) palloc(sizeof(float64data));
  229. *result = 1.0 / 3.0;
  230. return result;
  231. }
  232. /*
  233.  * getattdisbursion - Retrieves the number of values within an attribute.
  234.  *
  235.  * Note:
  236.  * getattdisbursion and gethilokey both currently use keyed
  237.  * relation scans and amgetattr.  Alternatively,
  238.  * the relation scan could be non-keyed and the tuple
  239.  * returned could be cast (struct X *) tuple + tuple->t_hoff.
  240.  * The first method is good for testing the implementation,
  241.  * but the second may ultimately be faster?!? In any case,
  242.  * using the cast instead of amgetattr would be
  243.  * more efficient.  However, the cast will not work
  244.  * for gethilokey which accesses stahikey in struct statistic.
  245.  */
  246. static float32data
  247. getattdisbursion(Oid relid, AttrNumber attnum)
  248. {
  249. HeapTuple atp;
  250. float32data nvals;
  251. int32 ntuples;
  252. atp = SearchSysCacheTuple(ATTNUM,
  253.   ObjectIdGetDatum(relid),
  254.   Int16GetDatum(attnum),
  255.   0, 0);
  256. if (!HeapTupleIsValid(atp))
  257. {
  258. elog(ERROR, "getattdisbursion: no attribute tuple %u %d",
  259.  relid, attnum);
  260. return 0;
  261. }
  262. nvals = ((Form_pg_attribute) GETSTRUCT(atp))->attdisbursion;
  263. if (nvals > 0)
  264. return nvals;
  265. atp = SearchSysCacheTuple(RELOID,
  266.   ObjectIdGetDatum(relid),
  267.   0, 0, 0);
  268. /*
  269.  * XXX -- use number of tuples as number of distinctive values just
  270.  * for now, in case number of distinctive values is not cached
  271.  */
  272. if (!HeapTupleIsValid(atp))
  273. {
  274. elog(ERROR, "getattdisbursion: no relation tuple %u", relid);
  275. return 0;
  276. }
  277. ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
  278. /* Look above how nvals is used. - vadim 04/09/97 */
  279. if (ntuples > 0)
  280. nvals = 1.0 / ntuples;
  281. return nvals;
  282. }
  283. /*
  284.  * gethilokey - Returns a pointer to strings containing
  285.  *   the high and low keys within an attribute.
  286.  *
  287.  * Currently returns "0", and "0" in high and low if the statistic
  288.  * catalog does not contain the proper tuple. Eventually, the
  289.  * statistic demon should have the tuple maintained, and it should
  290.  * elog() if the tuple is missing.
  291.  *
  292.  * XXX Question: is this worth sticking in the catalog caches,
  293.  * or will this get invalidated too often?
  294.  */
  295. static void
  296. gethilokey(Oid relid,
  297.    AttrNumber attnum,
  298.    Oid opid,
  299.    char **high,
  300.    char **low)
  301. {
  302. Relation rel;
  303. HeapScanDesc scan;
  304. static ScanKeyData key[3] = {
  305. {0, Anum_pg_statistic_starelid, F_OIDEQ, {0, 0, F_OIDEQ}},
  306. {0, Anum_pg_statistic_staattnum, F_INT2EQ, {0, 0, F_INT2EQ}},
  307. {0, Anum_pg_statistic_staop, F_OIDEQ, {0, 0, F_OIDEQ}}
  308. };
  309. bool isnull;
  310. HeapTuple tuple;
  311. rel = heap_openr(StatisticRelationName);
  312. key[0].sk_argument = ObjectIdGetDatum(relid);
  313. key[1].sk_argument = Int16GetDatum((int16) attnum);
  314. key[2].sk_argument = ObjectIdGetDatum(opid);
  315. scan = heap_beginscan(rel, 0, SnapshotNow, 3, key);
  316. tuple = heap_getnext(scan, 0);
  317. if (!HeapTupleIsValid(tuple))
  318. {
  319. *high = "n";
  320. *low = "n";
  321. /*
  322.  * XXX elog(ERROR, "gethilokey: statistic tuple not
  323.  * found");
  324.  */
  325. return;
  326. }
  327. *high = textout((struct varlena *)
  328. heap_getattr(tuple,
  329.  Anum_pg_statistic_stahikey,
  330.  RelationGetDescr(rel),
  331.  &isnull));
  332. if (isnull)
  333. elog(DEBUG, "gethilokey: high key is null");
  334. *low = textout((struct varlena *)
  335.    heap_getattr(tuple,
  336. Anum_pg_statistic_stalokey,
  337. RelationGetDescr(rel),
  338. &isnull));
  339. if (isnull)
  340. elog(DEBUG, "gethilokey: low key is null");
  341. heap_endscan(scan);
  342. heap_close(rel);
  343. }
  344. float64
  345. btreesel(Oid operatorObjectId,
  346.  Oid indrelid,
  347.  AttrNumber attributeNumber,
  348.  char *constValue,
  349.  int32 constFlag,
  350.  int32 nIndexKeys,
  351.  Oid indexrelid)
  352. {
  353. float64 result;
  354. if (FunctionalSelectivity(nIndexKeys, attributeNumber))
  355. {
  356. /*
  357.  * Need to call the functions selectivity function here.  For now
  358.  * simply assume it's 1/3 since functions don't currently have
  359.  * selectivity functions
  360.  */
  361. result = (float64) palloc(sizeof(float64data));
  362. *result = 1.0 / 3.0;
  363. }
  364. else
  365. {
  366. RegProcedure oprrest = get_oprrest(operatorObjectId);
  367. /*
  368.  * Operators used for indexes should have selectivity estimators.
  369.  * (An alternative is to default to 0.5, as the optimizer does in
  370.  * dealing with operators occurring in WHERE clauses, but if you
  371.  * are going to the trouble of making index support you probably
  372.  * don't want to miss the benefits of a good selectivity estimate.)
  373.  */
  374. if (!oprrest)
  375. {
  376. #if 1
  377. /*
  378.  * XXX temporary fix for 6.5: rtree operators are missing their
  379.  * selectivity estimators, so return a default estimate instead.
  380.  * Ugh.
  381.  */
  382. result = (float64) palloc(sizeof(float64data));
  383. *result = 0.5;
  384. #else
  385. elog(ERROR,
  386.  "Operator %u must have a restriction selectivity estimator to be used in an index",
  387.  operatorObjectId);
  388. #endif
  389. }
  390. else
  391. result = (float64) fmgr(oprrest,
  392. (char *) operatorObjectId,
  393. (char *) indrelid,
  394. (char *) (int) attributeNumber,
  395. (char *) constValue,
  396. (char *) constFlag,
  397. NULL);
  398. }
  399. if (!PointerIsValid(result))
  400. elog(ERROR, "Btree Selectivity: bad pointer");
  401. if (*result < 0.0 || *result > 1.0)
  402. elog(ERROR, "Btree Selectivity: bad value %lf", *result);
  403. return result;
  404. }
  405. float64
  406. btreenpage(Oid operatorObjectId,
  407.    Oid indrelid,
  408.    AttrNumber attributeNumber,
  409.    char *constValue,
  410.    int32 constFlag,
  411.    int32 nIndexKeys,
  412.    Oid indexrelid)
  413. {
  414. float64 temp,
  415. result;
  416. float64data tempData;
  417. HeapTuple atp;
  418. int npage;
  419. if (FunctionalSelectivity(nIndexKeys, attributeNumber))
  420. {
  421. /*
  422.  * Need to call the functions selectivity function here.  For now
  423.  * simply assume it's 1/3 since functions don't currently have
  424.  * selectivity functions
  425.  */
  426. tempData = 1.0 / 3.0;
  427. temp = &tempData;
  428. }
  429. else
  430. {
  431. RegProcedure oprrest = get_oprrest(operatorObjectId);
  432. /*
  433.  * Operators used for indexes should have selectivity estimators.
  434.  * (An alternative is to default to 0.5, as the optimizer does in
  435.  * dealing with operators occurring in WHERE clauses, but if you
  436.  * are going to the trouble of making index support you probably
  437.  * don't want to miss the benefits of a good selectivity estimate.)
  438.  */
  439. if (!oprrest)
  440. {
  441. #if 1
  442. /*
  443.  * XXX temporary fix for 6.5: rtree operators are missing their
  444.  * selectivity estimators, so return a default estimate instead.
  445.  * Ugh.
  446.  */
  447. tempData = 0.5;
  448. temp = &tempData;
  449. #else
  450. elog(ERROR,
  451.  "Operator %u must have a restriction selectivity estimator to be used in an index",
  452.  operatorObjectId);
  453. #endif
  454. }
  455. else
  456. temp = (float64) fmgr(oprrest,
  457.   (char *) operatorObjectId,
  458.   (char *) indrelid,
  459.   (char *) (int) attributeNumber,
  460.   (char *) constValue,
  461.   (char *) constFlag,
  462.   NULL);
  463. }
  464. atp = SearchSysCacheTuple(RELOID,
  465.   ObjectIdGetDatum(indexrelid),
  466.   0, 0, 0);
  467. if (!HeapTupleIsValid(atp))
  468. {
  469. elog(ERROR, "btreenpage: no index tuple %u", indexrelid);
  470. return 0;
  471. }
  472. npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
  473. result = (float64) palloc(sizeof(float64data));
  474. *result = *temp * npage;
  475. return result;
  476. }
  477. float64
  478. hashsel(Oid operatorObjectId,
  479. Oid indrelid,
  480. AttrNumber attributeNumber,
  481. char *constValue,
  482. int32 constFlag,
  483. int32 nIndexKeys,
  484. Oid indexrelid)
  485. {
  486. float64 result;
  487. float64data resultData;
  488. HeapTuple atp;
  489. int ntuples;
  490. if (FunctionalSelectivity(nIndexKeys, attributeNumber))
  491. {
  492. /*
  493.  * Need to call the functions selectivity function here.  For now
  494.  * simply use 1/Number of Tuples since functions don't currently
  495.  * have selectivity functions
  496.  */
  497. atp = SearchSysCacheTuple(RELOID,
  498.   ObjectIdGetDatum(indexrelid),
  499.   0, 0, 0);
  500. if (!HeapTupleIsValid(atp))
  501. {
  502. elog(ERROR, "hashsel: no index tuple %u", indexrelid);
  503. return 0;
  504. }
  505. ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
  506. if (ntuples > 0)
  507. resultData = 1.0 / (float64data) ntuples;
  508. else
  509. resultData = (float64data) (1.0 / 100.0);
  510. result = &resultData;
  511. }
  512. else
  513. {
  514. RegProcedure oprrest = get_oprrest(operatorObjectId);
  515. /*
  516.  * Operators used for indexes should have selectivity estimators.
  517.  * (An alternative is to default to 0.5, as the optimizer does in
  518.  * dealing with operators occurring in WHERE clauses, but if you
  519.  * are going to the trouble of making index support you probably
  520.  * don't want to miss the benefits of a good selectivity estimate.)
  521.  */
  522. if (!oprrest)
  523. elog(ERROR,
  524.  "Operator %u must have a restriction selectivity estimator to be used in a hash index",
  525.  operatorObjectId);
  526. result = (float64) fmgr(oprrest,
  527. (char *) operatorObjectId,
  528. (char *) indrelid,
  529. (char *) (int) attributeNumber,
  530. (char *) constValue,
  531. (char *) constFlag,
  532. NULL);
  533. }
  534. if (!PointerIsValid(result))
  535. elog(ERROR, "Hash Table Selectivity: bad pointer");
  536. if (*result < 0.0 || *result > 1.0)
  537. elog(ERROR, "Hash Table Selectivity: bad value %lf", *result);
  538. return result;
  539. }
  540. float64
  541. hashnpage(Oid operatorObjectId,
  542.   Oid indrelid,
  543.   AttrNumber attributeNumber,
  544.   char *constValue,
  545.   int32 constFlag,
  546.   int32 nIndexKeys,
  547.   Oid indexrelid)
  548. {
  549. float64 temp,
  550. result;
  551. float64data tempData;
  552. HeapTuple atp;
  553. int npage;
  554. int ntuples;
  555. atp = SearchSysCacheTuple(RELOID,
  556.   ObjectIdGetDatum(indexrelid),
  557.   0, 0, 0);
  558. if (!HeapTupleIsValid(atp))
  559. {
  560. elog(ERROR, "hashsel: no index tuple %u", indexrelid);
  561. return 0;
  562. }
  563. if (FunctionalSelectivity(nIndexKeys, attributeNumber))
  564. {
  565. /*
  566.  * Need to call the functions selectivity function here.  For now,
  567.  * use 1/Number of Tuples since functions don't currently have
  568.  * selectivity functions
  569.  */
  570. ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
  571. if (ntuples > 0)
  572. tempData = 1.0 / (float64data) ntuples;
  573. else
  574. tempData = (float64data) (1.0 / 100.0);
  575. temp = &tempData;
  576. }
  577. else
  578. {
  579. RegProcedure oprrest = get_oprrest(operatorObjectId);
  580. /*
  581.  * Operators used for indexes should have selectivity estimators.
  582.  * (An alternative is to default to 0.5, as the optimizer does in
  583.  * dealing with operators occurring in WHERE clauses, but if you
  584.  * are going to the trouble of making index support you probably
  585.  * don't want to miss the benefits of a good selectivity estimate.)
  586.  */
  587. if (!oprrest)
  588. elog(ERROR,
  589.  "Operator %u must have a restriction selectivity estimator to be used in a hash index",
  590.  operatorObjectId);
  591. temp = (float64) fmgr(oprrest,
  592.   (char *) operatorObjectId,
  593.   (char *) indrelid,
  594.   (char *) (int) attributeNumber,
  595.   (char *) constValue,
  596.   (char *) constFlag,
  597.   NULL);
  598. }
  599. npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
  600. result = (float64) palloc(sizeof(float64data));
  601. *result = *temp * npage;
  602. return result;
  603. }
  604. float64
  605. rtsel(Oid operatorObjectId,
  606.   Oid indrelid,
  607.   AttrNumber attributeNumber,
  608.   char *constValue,
  609.   int32 constFlag,
  610.   int32 nIndexKeys,
  611.   Oid indexrelid)
  612. {
  613. return (btreesel(operatorObjectId, indrelid, attributeNumber,
  614.  constValue, constFlag, nIndexKeys, indexrelid));
  615. }
  616. float64
  617. rtnpage(Oid operatorObjectId,
  618. Oid indrelid,
  619. AttrNumber attributeNumber,
  620. char *constValue,
  621. int32 constFlag,
  622. int32 nIndexKeys,
  623. Oid indexrelid)
  624. {
  625. return (btreenpage(operatorObjectId, indrelid, attributeNumber,
  626.    constValue, constFlag, nIndexKeys, indexrelid));
  627. }
  628. float64
  629. gistsel(Oid operatorObjectId,
  630. Oid indrelid,
  631. AttrNumber attributeNumber,
  632. char *constValue,
  633. int32 constFlag,
  634. int32 nIndexKeys,
  635. Oid indexrelid)
  636. {
  637. return (btreesel(operatorObjectId, indrelid, attributeNumber,
  638.  constValue, constFlag, nIndexKeys, indexrelid));
  639. }
  640. float64
  641. gistnpage(Oid operatorObjectId,
  642.   Oid indrelid,
  643.   AttrNumber attributeNumber,
  644.   char *constValue,
  645.   int32 constFlag,
  646.   int32 nIndexKeys,
  647.   Oid indexrelid)
  648. {
  649. return (btreenpage(operatorObjectId, indrelid, attributeNumber,
  650.    constValue, constFlag, nIndexKeys, indexrelid));
  651. }