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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * joinutils.c
  4.  *   Utilities for matching and building join and path keys
  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/pathkeys.c,v 1.10.2.1 1999/08/02 06:26:59 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "optimizer/joininfo.h"
  16. #include "optimizer/keys.h"
  17. #include "optimizer/ordering.h"
  18. #include "optimizer/paths.h"
  19. #include "optimizer/tlist.h"
  20. static int match_pathkey_joinkeys(List *pathkey, List *joinkeys,
  21.    int outer_or_inner);
  22. static List *new_join_pathkey(List *pathkeys, List *join_rel_tlist,
  23.  List *joinclauses);
  24. /*--------------------
  25.  * Explanation of Path.pathkeys
  26.  *
  27.  * Path.pathkeys is a List of List of Var nodes that represent the sort
  28.  * order of the result generated by the Path.
  29.  *
  30.  * In single/base relation RelOptInfo's, the Path's represent various ways
  31.  * of generating the relation and the resulting ordering of the tuples.
  32.  * Sequential scan Paths have NIL pathkeys, indicating no known ordering.
  33.  * Index scans have Path.pathkeys that represent the chosen index.
  34.  * A single-key index pathkeys would be { {tab1_indexkey1} }. For a
  35.  * multi-key index pathkeys would be { {tab1_indexkey1}, {tab1_indexkey2} },
  36.  * indicating major sort by indexkey1 and minor sort by indexkey2.
  37.  *
  38.  * Multi-relation RelOptInfo Path's are more complicated.  Mergejoins are
  39.  * only performed with equijoins ("=").  Because of this, the multi-relation
  40.  * path actually has more than one primary Var key.  For example, a
  41.  * mergejoin Path of "tab1.col1 = tab2.col1" would generate a pathkeys of
  42.  * { {tab1.col1, tab2.col1} }, indicating that the major sort order of the
  43.  * Path can be taken to be *either* tab1.col1 or tab2.col1.
  44.  * They are equal, so they are both primary sort keys.  This allows future
  45.  * joins to use either Var as a pre-sorted key to prevent upper Mergejoins
  46.  * from having to re-sort the Path.  This is why pathkeys is a List of Lists.
  47.  *
  48.  * Note that while the order of the top list is meaningful (primary vs.
  49.  * secondary sort key), the order of each sublist is arbitrary.
  50.  *
  51.  * For multi-key sorts, if the outer is sorted by a multi-key index, the
  52.  * multi-key index remains after the join.  If the inner has a multi-key
  53.  * sort, only the primary key of the inner is added to the result.
  54.  * Mergejoins only join on the primary key.  Currently, non-primary keys
  55.  * in the pathkeys List are of limited value.
  56.  *
  57.  * Although Hashjoins also work only with equijoin operators, it is *not*
  58.  * safe to consider the output of a Hashjoin to be sorted in any particular
  59.  * order --- not even the outer path's order.  This is true because the
  60.  * executor might have to split the join into multiple batches.
  61.  *
  62.  * NestJoin does not perform sorting, and allows non-equijoins, so it does
  63.  * not allow useful pathkeys. (But couldn't we use the outer path's order?)
  64.  *
  65.  * -- bjm
  66.  *--------------------
  67.  */
  68. /****************************************************************************
  69.  * KEY COMPARISONS
  70.  ****************************************************************************/
  71. /*
  72.  * order_joinkeys_by_pathkeys
  73.  *   Attempts to match the keys of a path against the keys of join clauses.
  74.  *   This is done by looking for a matching join key in 'joinkeys' for
  75.  *   every path key in the list 'path.keys'. If there is a matching join key
  76.  *   (not necessarily unique) for every path key, then the list of
  77.  *   corresponding join keys and join clauses are returned in the order in
  78.  *   which the keys matched the path keys.
  79.  *
  80.  * 'pathkeys' is a list of path keys:
  81.  * ( ( (var) (var) ... ) ( (var) ... ) )
  82.  * 'joinkeys' is a list of join keys:
  83.  * ( (outer inner) (outer inner) ... )
  84.  * 'joinclauses' is a list of clauses corresponding to the join keys in
  85.  * 'joinkeys'
  86.  * 'outer_or_inner' is a flag that selects the desired pathkey of a join key
  87.  * in 'joinkeys'
  88.  *
  89.  * Returns the join keys and corresponding join clauses in a list if all
  90.  * of the path keys were matched:
  91.  * (
  92.  *  ( (outerkey0 innerkey0) ... (outerkeyN or innerkeyN) )
  93.  *  ( clause0 ... clauseN )
  94.  * )
  95.  * and nil otherwise.
  96.  *
  97.  * Returns a list of matched join keys and a list of matched join clauses
  98.  * in pointers if valid order can be found.
  99.  */
  100. bool
  101. order_joinkeys_by_pathkeys(List *pathkeys,
  102.    List *joinkeys,
  103.    List *joinclauses,
  104.    int outer_or_inner,
  105.    List **matchedJoinKeysPtr,
  106.    List **matchedJoinClausesPtr)
  107. {
  108. List    *matched_joinkeys = NIL;
  109. List    *matched_joinclauses = NIL;
  110. List    *pathkey = NIL;
  111. List    *i = NIL;
  112. int matched_joinkey_index = -1;
  113. int matched_keys = 0;
  114. /*
  115.  * Reorder the joinkeys by picking out one that matches each pathkey,
  116.  * and create a new joinkey/joinclause list in pathkey order
  117.  */
  118. foreach(i, pathkeys)
  119. {
  120. pathkey = lfirst(i);
  121. matched_joinkey_index = match_pathkey_joinkeys(pathkey, joinkeys,
  122.    outer_or_inner);
  123. if (matched_joinkey_index != -1)
  124. {
  125. matched_keys++;
  126. if (matchedJoinKeysPtr)
  127. {
  128. JoinKey    *joinkey = nth(matched_joinkey_index, joinkeys);
  129. matched_joinkeys = lappend(matched_joinkeys, joinkey);
  130. }
  131. if (matchedJoinClausesPtr)
  132. {
  133. Expr    *joinclause = nth(matched_joinkey_index,
  134.  joinclauses);
  135. Assert(joinclauses);
  136. matched_joinclauses = lappend(matched_joinclauses, joinclause);
  137. }
  138. }
  139. else
  140. /* A pathkey could not be matched. */
  141. break;
  142. }
  143. /*
  144.  * Did we fail to match all the joinkeys? Extra pathkeys are no
  145.  * problem.
  146.  */
  147. if (matched_keys != length(joinkeys))
  148. {
  149. if (matchedJoinKeysPtr)
  150. *matchedJoinKeysPtr = NIL;
  151. if (matchedJoinClausesPtr)
  152. *matchedJoinClausesPtr = NIL;
  153. return false;
  154. }
  155. if (matchedJoinKeysPtr)
  156. *matchedJoinKeysPtr = matched_joinkeys;
  157. if (matchedJoinClausesPtr)
  158. *matchedJoinClausesPtr = matched_joinclauses;
  159. return true;
  160. }
  161. /*
  162.  * match_pathkey_joinkeys
  163.  *   Returns the 0-based index into 'joinkeys' of the first joinkey whose
  164.  *   outer or inner pathkey matches any subkey of 'pathkey'.
  165.  *
  166.  * All these keys are equivalent, so any of them can match.  See above.
  167.  */
  168. static int
  169. match_pathkey_joinkeys(List *pathkey,
  170.    List *joinkeys,
  171.    int outer_or_inner)
  172. {
  173. Var    *key;
  174. int pos;
  175. List    *i,
  176.    *x;
  177. JoinKey    *jk;
  178. foreach(i, pathkey)
  179. {
  180. key = (Var *) lfirst(i);
  181. pos = 0;
  182. foreach(x, joinkeys)
  183. {
  184. jk = (JoinKey *) lfirst(x);
  185. if (equal(key, extract_join_key(jk, outer_or_inner)))
  186. return pos;
  187. pos++;
  188. }
  189. }
  190. return -1; /* no index found */
  191. }
  192. /*
  193.  * get_cheapest_path_for_joinkeys
  194.  *   Attempts to find a path in 'paths' whose keys match a set of join
  195.  *   keys 'joinkeys'. To match,
  196.  *   1. the path node ordering must equal 'ordering'.
  197.  *   2. each pathkey of a given path must match(i.e., be(equal) to) the
  198.  *  appropriate pathkey of the corresponding join key in 'joinkeys',
  199.  *  i.e., the Nth path key must match its pathkeys against the pathkey of
  200.  *  the Nth join key in 'joinkeys'.
  201.  *
  202.  * 'joinkeys' is the list of key pairs to which the path keys must be
  203.  * matched
  204.  * 'ordering' is the ordering of the(outer) path to which 'joinkeys'
  205.  * must correspond
  206.  * 'paths' is a list of(inner) paths which are to be matched against
  207.  * each join key in 'joinkeys'
  208.  * 'outer_or_inner' is a flag that selects the desired pathkey of a join key
  209.  * in 'joinkeys'
  210.  *
  211.  * Find the cheapest path that matches the join keys
  212.  */
  213. Path *
  214. get_cheapest_path_for_joinkeys(List *joinkeys,
  215.    PathOrder *ordering,
  216.    List *paths,
  217.    int outer_or_inner)
  218. {
  219. Path    *matched_path = NULL;
  220. List    *i;
  221. foreach(i, paths)
  222. {
  223. Path    *path = (Path *) lfirst(i);
  224. int better_sort;
  225. if (order_joinkeys_by_pathkeys(path->pathkeys, joinkeys, NIL,
  226.    outer_or_inner, NULL, NULL) &&
  227. pathorder_match(ordering, path->pathorder, &better_sort) &&
  228. better_sort == 0)
  229. {
  230. if (matched_path == NULL ||
  231. path->path_cost < matched_path->path_cost)
  232. matched_path = path;
  233. }
  234. }
  235. return matched_path;
  236. }
  237. /*
  238.  * make_pathkeys_from_joinkeys
  239.  *   Builds a pathkey list for a path by pulling one of the pathkeys from
  240.  *   a list of join keys 'joinkeys' and then finding the var node in the
  241.  *   target list 'tlist' that corresponds to that pathkey.
  242.  *
  243.  * 'joinkeys' is a list of join key pairs
  244.  * 'tlist' is a relation target list
  245.  * 'outer_or_inner' is a flag that selects the desired pathkey of a join key
  246.  * in 'joinkeys'
  247.  *
  248.  * Returns a list of pathkeys: ((tlvar1)(tlvar2)...(tlvarN)).
  249.  * It is a list of lists because of multi-key indexes.
  250.  */
  251. List *
  252. make_pathkeys_from_joinkeys(List *joinkeys,
  253. List *tlist,
  254. int outer_or_inner)
  255. {
  256. List    *pathkeys = NIL;
  257. List    *jk;
  258. foreach(jk, joinkeys)
  259. {
  260. JoinKey    *jkey = (JoinKey *) lfirst(jk);
  261. Var    *key;
  262. List    *p,
  263.    *p2;
  264. bool found = false;
  265. key = (Var *) extract_join_key(jkey, outer_or_inner);
  266. /* check to see if it is in the target list */
  267. if (matching_tlist_var(key, tlist))
  268. {
  269. /*
  270.  * Include it in the pathkeys list if we haven't already done
  271.  * so
  272.  */
  273. foreach(p, pathkeys)
  274. {
  275. List    *pathkey = lfirst(p);
  276. foreach(p2, pathkey)
  277. {
  278. Var    *pkey = lfirst(p2);
  279. if (equal(key, pkey))
  280. {
  281. found = true;
  282. break;
  283. }
  284. }
  285. if (found)
  286. break;
  287. }
  288. if (!found)
  289. pathkeys = lappend(pathkeys, lcons(key, NIL));
  290. }
  291. }
  292. return pathkeys;
  293. }
  294. /****************************************************************************
  295.  * NEW PATHKEY FORMATION
  296.  ****************************************************************************/
  297. /*
  298.  * new_join_pathkeys
  299.  *   Find the path keys for a join relation by finding all vars in the list
  300.  *   of join clauses 'joinclauses' such that:
  301.  * (1) the var corresponding to the outer join relation is a
  302.  * key on the outer path
  303.  * (2) the var appears in the target list of the join relation
  304.  *   In other words, add to each outer path key the inner path keys that
  305.  *   are required for qualification.
  306.  *
  307.  * 'outer_pathkeys' is the list of the outer path's path keys
  308.  * 'join_rel_tlist' is the target list of the join relation
  309.  * 'joinclauses' is the list of restricting join clauses
  310.  *
  311.  * Returns the list of new path keys.
  312.  *
  313.  */
  314. List *
  315. new_join_pathkeys(List *outer_pathkeys,
  316.   List *join_rel_tlist,
  317.   List *joinclauses)
  318. {
  319. List    *final_pathkeys = NIL;
  320. List    *i;
  321. foreach(i, outer_pathkeys)
  322. {
  323. List    *outer_pathkey = lfirst(i);
  324. List    *new_pathkey;
  325. new_pathkey = new_join_pathkey(outer_pathkey, join_rel_tlist,
  326.    joinclauses);
  327. if (new_pathkey != NIL)
  328. final_pathkeys = lappend(final_pathkeys, new_pathkey);
  329. }
  330. return final_pathkeys;
  331. }
  332. /*
  333.  * new_join_pathkey
  334.  *   Generate an individual pathkey sublist, consisting of the outer vars
  335.  *   already mentioned in 'pathkey' plus any inner vars that are joined to
  336.  *   them (and thus can now also be considered path keys, per discussion
  337.  *   at the top of this file).
  338.  *
  339.  *   Note that each returned pathkey is the var node found in
  340.  *   'join_rel_tlist' rather than the joinclause var node.
  341.  *   (Is this important?) Also, we return a fully copied list
  342.  *   that does not share any subnodes with existing data structures.
  343.  *   (Is that important, either?)
  344.  *
  345.  * Returns a new pathkey (list of pathkey variables).
  346.  *
  347.  */
  348. static List *
  349. new_join_pathkey(List *pathkey,
  350.  List *join_rel_tlist,
  351.  List *joinclauses)
  352. {
  353. List    *new_pathkey = NIL;
  354. List    *i,
  355.    *j;
  356. foreach(i, pathkey)
  357. {
  358. Var    *key = (Var *) lfirst(i);
  359. Expr    *tlist_key;
  360. Assert(key);
  361. tlist_key = matching_tlist_var(key, join_rel_tlist);
  362. if (tlist_key && !member(tlist_key, new_pathkey))
  363. new_pathkey = lcons(copyObject(tlist_key), new_pathkey);
  364. foreach(j, joinclauses)
  365. {
  366. Expr    *joinclause = lfirst(j);
  367. Expr    *tlist_other_var;
  368. tlist_other_var = matching_tlist_var(
  369.   other_join_clause_var(key, joinclause),
  370.  join_rel_tlist);
  371. if (tlist_other_var && !member(tlist_other_var, new_pathkey))
  372. new_pathkey = lcons(copyObject(tlist_other_var), new_pathkey);
  373. }
  374. }
  375. return new_pathkey;
  376. }