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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * orindxpath.c
  4.  *   Routines to find index paths that match a set of 'or' clauses
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.25.2.1 1999/08/02 06:26:58 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "nodes/nodeFuncs.h"
  16. #include "optimizer/clauses.h"
  17. #include "optimizer/cost.h"
  18. #include "optimizer/internal.h"
  19. #include "optimizer/paths.h"
  20. #include "optimizer/plancat.h"
  21. #include "optimizer/restrictinfo.h"
  22. #include "parser/parsetree.h" 
  23. static void best_or_subclause_indices(Query *root, RelOptInfo *rel, List *subclauses,
  24. List *indices, List **indexids, Cost *cost, Cost *selec);
  25. static void best_or_subclause_index(Query *root, RelOptInfo *rel, Expr *subclause,
  26.    List *indices, int *indexid, Cost *cost, Cost *selec);
  27. /*
  28.  * create_or_index_paths
  29.  *   Creates index paths for indices that match 'or' clauses.
  30.  *
  31.  * 'rel' is the relation entry for which the paths are to be defined on
  32.  * 'clauses' is the list of available restriction clause nodes
  33.  *
  34.  * Returns a list of these index path nodes.
  35.  *
  36.  */
  37. List *
  38. create_or_index_paths(Query *root,
  39.   RelOptInfo *rel, List *clauses)
  40. {
  41. List    *t_list = NIL;
  42. List    *clist;
  43. foreach(clist, clauses)
  44. {
  45. RestrictInfo *clausenode = (RestrictInfo *) (lfirst(clist));
  46. /*
  47.  * Check to see if this clause is an 'or' clause, and, if so,
  48.  * whether or not each of the subclauses within the 'or' clause
  49.  * has been matched by an index (the 'Index field was set in
  50.  * (match_or)  if no index matches a given subclause, one of the
  51.  * lists of index nodes returned by (get_index) will be 'nil').
  52.  */
  53. if (valid_or_clause(clausenode) &&
  54. clausenode->indexids)
  55. {
  56. List    *temp = NIL;
  57. List    *index_list = NIL;
  58. bool index_flag = true;
  59. index_list = clausenode->indexids;
  60. foreach(temp, index_list)
  61. {
  62. if (!lfirst(temp))
  63. {
  64. index_flag = false;
  65. break;
  66. }
  67. }
  68. /* do they all have indexes? */
  69. if (index_flag)
  70. { /* used to be a lisp every function */
  71. IndexPath  *pathnode = makeNode(IndexPath);
  72. List    *indexids = NIL;
  73. Cost cost;
  74. Cost selec;
  75. best_or_subclause_indices(root,
  76.   rel,
  77.   clausenode->clause->args,
  78.   clausenode->indexids,
  79.   &indexids,
  80.   &cost,
  81.   &selec);
  82. pathnode->path.pathtype = T_IndexScan;
  83. pathnode->path.parent = rel;
  84. pathnode->path.pathorder = makeNode(PathOrder);
  85. pathnode->path.pathorder->ordtype = SORTOP_ORDER;
  86. /*
  87.  * This is an IndexScan, but it does index lookups based
  88.  * on the order of the fields specified in the WHERE
  89.  * clause, not in any order, so the sortop is NULL.
  90.  */
  91. pathnode->path.pathorder->ord.sortop = NULL;
  92. pathnode->path.pathkeys = NIL;
  93. pathnode->indexqual = lcons(clausenode, NIL);
  94. pathnode->indexid = indexids;
  95. pathnode->path.path_cost = cost;
  96. /*
  97.  * copy restrictinfo list into path for expensive function
  98.  * processing  -- JMH, 7/7/92
  99.  */
  100. pathnode->path.loc_restrictinfo = set_difference(copyObject((Node *) rel->restrictinfo),
  101.  lcons(clausenode, NIL));
  102. #ifdef NOT_USED /* fix xfunc */
  103. /* add in cost for expensive functions!  -- JMH, 7/7/92 */
  104. if (XfuncMode != XFUNC_OFF)
  105. ((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path) pathnode);
  106. #endif
  107. clausenode->selectivity = (Cost) selec;
  108. t_list = lappend(t_list, pathnode);
  109. }
  110. }
  111. }
  112. return t_list;
  113. }
  114. /*
  115.  * best_or_subclause_indices
  116.  *   Determines the best index to be used in conjunction with each subclause
  117.  *   of an 'or' clause and the cost of scanning a relation using these
  118.  *   indices. The cost is the sum of the individual index costs.
  119.  *
  120.  * 'rel' is the node of the relation on which the index is defined
  121.  * 'subclauses' are the subclauses of the 'or' clause
  122.  * 'indices' are those index nodes that matched subclauses of the 'or'
  123.  * clause
  124.  * 'examined_indexids' is a list of those index ids to be used with
  125.  * subclauses that have already been examined
  126.  * 'subcost' is the cost of using the indices in 'examined_indexids'
  127.  * 'selec' is a list of all subclauses that have already been examined
  128.  *
  129.  * Returns a list of the indexids, cost, and selectivities of each
  130.  * subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID,
  131.  * 'cost' is a flonum, and 's' is a flonum.
  132.  */
  133. static void
  134. best_or_subclause_indices(Query *root,
  135.   RelOptInfo *rel,
  136.   List *subclauses,
  137.   List *indices,
  138.   List **indexids, /* return value */
  139.   Cost *cost, /* return value */
  140.   Cost *selec) /* return value */
  141. {
  142. List    *slist;
  143. *selec = (Cost) 0.0;
  144. *cost = (Cost) 0.0;
  145. foreach(slist, subclauses)
  146. {
  147. int best_indexid;
  148. Cost best_cost;
  149. Cost best_selec;
  150. best_or_subclause_index(root, rel, lfirst(slist), lfirst(indices),
  151. &best_indexid, &best_cost, &best_selec);
  152. *indexids = lappendi(*indexids, best_indexid);
  153. *cost += best_cost;
  154. *selec += best_selec;
  155. if (*selec > (Cost) 1.0)
  156. *selec = (Cost) 1.0;
  157. indices = lnext(indices);
  158. }
  159. return;
  160. }
  161. /*
  162.  * best_or_subclause_index
  163.  *   Determines which is the best index to be used with a subclause of
  164.  *   an 'or' clause by estimating the cost of using each index and selecting
  165.  *   the least expensive.
  166.  *
  167.  * 'rel' is the node of the relation on which the index is defined
  168.  * 'subclause' is the subclause
  169.  * 'indices' is a list of index nodes that match the subclause
  170.  *
  171.  * Returns a list (index_id index_subcost index_selectivity)
  172.  * (a fixnum, a fixnum, and a flonum respectively).
  173.  *
  174.  */
  175. static void
  176. best_or_subclause_index(Query *root,
  177. RelOptInfo *rel,
  178. Expr *subclause,
  179. List *indices,
  180. int *retIndexid, /* return value */
  181. Cost *retCost, /* return value */
  182. Cost *retSelec) /* return value */
  183. {
  184. List    *ilist;
  185. bool first_run = true;
  186. /* if we don't match anything, return zeros */
  187. *retIndexid = 0;
  188. *retCost = 0.0;
  189. *retSelec = 0.0;
  190. foreach(ilist, indices)
  191. {
  192. RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
  193. Datum value;
  194. int flag = 0;
  195. Cost subcost;
  196. AttrNumber attno = (get_leftop(subclause))->varattno;
  197. Oid opno = ((Oper *) subclause->oper)->opno;
  198. bool constant_on_right = non_null((Expr *) get_rightop(subclause));
  199. float npages,
  200. selec;
  201. if (constant_on_right)
  202. value = ((Const *) get_rightop(subclause))->constvalue;
  203. else
  204. value = NameGetDatum("");
  205. if (constant_on_right)
  206. flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
  207. else
  208. flag = _SELEC_CONSTANT_RIGHT_;
  209. index_selectivity(lfirsti(index->relids),
  210.   index->classlist,
  211.   lconsi(opno, NIL),
  212.   getrelid(lfirsti(rel->relids),
  213.    root->rtable),
  214.   lconsi(attno, NIL),
  215.   lconsi(value, NIL),
  216.   lconsi(flag, NIL),
  217.   1,
  218.   &npages,
  219.   &selec);
  220. subcost = cost_index((Oid) lfirsti(index->relids),
  221.  (int) npages,
  222.  (Cost) selec,
  223.  rel->pages,
  224.  rel->tuples,
  225.  index->pages,
  226.  index->tuples,
  227.  false);
  228. if (first_run || subcost < *retCost)
  229. {
  230. *retIndexid = lfirsti(index->relids);
  231. *retCost = subcost;
  232. *retSelec = selec;
  233. first_run = false;
  234. }
  235. }
  236. return;
  237. }