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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * predmig.c
  4.  *
  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/_deadcode/predmig.c,v 1.4 1999/05/25 22:41:35 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. /*
  15. ** DESCRIPTION
  16. ** Main Routines to handle Predicate Migration (i.e. correct optimization
  17. ** of queries with expensive functions.)
  18. **
  19. **   The reasoning behind some of these algorithms is rather detailed.
  20. ** Have a look at Sequoia Tech Report 92/13 for more info. Also
  21. ** see Monma and Sidney's paper "Sequencing with Series-Parallel
  22. ** Precedence Constraints", in "Mathematics of Operations Research",
  23. ** volume 4 (1979),  pp. 215-224.
  24. **
  25. **   The main thing that this code does that wasn't handled in xfunc.c is
  26. ** it considers the possibility that two joins in a stream may not
  27. ** be ordered by ascending rank -- in such a scenario, it may be optimal
  28. ** to pullup more restrictions than we did via xfunc_try_pullup.
  29. **
  30. **   This code in some sense generalizes xfunc_try_pullup; if you
  31. ** run postgres -x noprune, you'll turn off xfunc_try_pullup, and this
  32. ** code will do everything that xfunc_try_pullup would have, and maybe
  33. ** more.  However, this results in no pruning, which may slow down the
  34. ** optimizer and/or cause the system to run out of memory.
  35. **    -- JMH, 11/13/92
  36. */
  37. #include "nodes/pg_list.h"
  38. #include "nodes/nodes.h"
  39. #include "nodes/primnodes.h"
  40. #include "nodes/relation.h"
  41. #include "utils/palloc.h"
  42. #include "utils/elog.h"
  43. #include "optimizer/xfunc.h"
  44. #include "optimizer/pathnode.h"
  45. #include "optimizer/internal.h"
  46. #include "optimizer/cost.h"
  47. #include "optimizer/keys.h"
  48. #include "optimizer/tlist.h"
  49. #define is_clause(node) (get_cinfo(node)) /* a stream node
  50.  * represents a clause
  51.  * (not a join) iff it has
  52.  * a non-NULL cinfo field */
  53. static void xfunc_predmig(JoinPath pathnode, Stream streamroot,
  54.   Stream laststream, bool *progressp);
  55. static bool xfunc_series_llel(Stream stream);
  56. static bool xfunc_llel_chains(Stream root, Stream bottom);
  57. static Stream xfunc_complete_stream(Stream stream);
  58. static bool xfunc_prdmig_pullup(Stream origstream, Stream pullme,
  59. JoinPath joinpath);
  60. static void xfunc_form_groups(Stream root, Stream bottom);
  61. static void xfunc_free_stream(Stream root);
  62. static Stream xfunc_add_clauses(Stream current);
  63. static void xfunc_setup_group(Stream node, Stream bottom);
  64. static Stream xfunc_streaminsert(RestrictInfo restrictinfo, Stream current,
  65.    int clausetype);
  66. static int xfunc_num_relids(Stream node);
  67. static StreamPtr xfunc_get_downjoin(Stream node);
  68. static StreamPtr xfunc_get_upjoin(Stream node);
  69. static Stream xfunc_stream_qsort(Stream root, Stream bottom);
  70. static int xfunc_stream_compare(void *arg1, void *arg2);
  71. static bool xfunc_check_stream(Stream node);
  72. static bool xfunc_in_stream(Stream node, Stream stream);
  73. /* -----------------   MAIN FUNCTIONS ------------------------ */
  74. /*
  75. ** xfunc_do_predmig
  76. **   wrapper for Predicate Migration. It calls xfunc_predmig until no
  77. ** more progress is made.
  78. **   return value says if any changes were ever made.
  79. */
  80. bool
  81. xfunc_do_predmig(Path root)
  82. {
  83. bool progress,
  84. changed = false;
  85. if (is_join(root))
  86. do
  87. {
  88. progress = false;
  89. Assert(IsA(root, JoinPath));
  90. xfunc_predmig((JoinPath) root, (Stream) NULL, (Stream) NULL,
  91.   &progress);
  92. if (changed && progress)
  93. elog(DEBUG, "Needed to do a second round of predmig!n");
  94. if (progress)
  95. changed = true;
  96. } while (progress);
  97. return changed;
  98. }
  99. /*
  100.  ** xfunc_predmig
  101.  **  The main routine for Predicate Migration. It traverses a join tree,
  102.  ** and for each root-to-leaf path in the plan tree it constructs a
  103.  ** "Stream", which it passes to xfunc_series_llel for optimization.
  104.  ** Destructively modifies the join tree (via predicate pullup).
  105.  */
  106. static void
  107. xfunc_predmig(JoinPath pathnode,/* root of the join tree */
  108.   Stream streamroot,
  109.   Stream laststream,/* for recursive calls -- these are the
  110.  * root of the stream under construction,
  111.  * and the lowest node created so far */
  112.   bool *progressp)
  113. {
  114. Stream newstream;
  115. /*
  116.  * * traverse the join tree dfs-style, constructing a stream as you
  117.  * go. * When you hit a scan node, pass the stream off to
  118.  * xfunc_series_llel.
  119.  */
  120. /* sanity check */
  121. if ((!streamroot && laststream) ||
  122. (streamroot && !laststream))
  123. elog(ERROR, "called xfunc_predmig with bad inputs");
  124. if (streamroot)
  125. Assert(xfunc_check_stream(streamroot));
  126. /* add path node to stream */
  127. newstream = RMakeStream();
  128. if (!streamroot)
  129. streamroot = newstream;
  130. set_upstream(newstream, (StreamPtr) laststream);
  131. if (laststream)
  132. set_downstream(laststream, (StreamPtr) newstream);
  133. set_downstream(newstream, (StreamPtr) NULL);
  134. set_pathptr(newstream, (pathPtr) pathnode);
  135. set_cinfo(newstream, (RestrictInfo) NULL);
  136. set_clausetype(newstream, XFUNC_UNKNOWN);
  137. /* base case: we're at a leaf, call xfunc_series_llel */
  138. if (!is_join(pathnode))
  139. {
  140. /* form a fleshed-out copy of the stream */
  141. Stream fullstream = xfunc_complete_stream(streamroot);
  142. /* sort it via series-llel */
  143. if (xfunc_series_llel(fullstream))
  144. *progressp = true;
  145. /* free up the copy */
  146. xfunc_free_stream(fullstream);
  147. }
  148. else
  149. {
  150. /* visit left child */
  151. xfunc_predmig((JoinPath) get_outerjoinpath(pathnode),
  152.   streamroot, newstream, progressp);
  153. /* visit right child */
  154. xfunc_predmig((JoinPath) get_innerjoinpath(pathnode),
  155.   streamroot, newstream, progressp);
  156. }
  157. /* remove this node */
  158. if (get_upstream(newstream))
  159. set_downstream((Stream) get_upstream(newstream), (StreamPtr) NULL);
  160. pfree(newstream);
  161. }
  162. /*
  163.  ** xfunc_series_llel
  164.  **    A flavor of Monma and Sidney's Series-Parallel algorithm.
  165.  ** Traverse stream downwards. When you find a node with restrictions on it,
  166.  ** call xfunc_llel_chains on the substream from root to that node.
  167.  */
  168. static bool
  169. xfunc_series_llel(Stream stream)
  170. {
  171. Stream temp,
  172. next;
  173. bool progress = false;
  174. for (temp = stream; temp != (Stream) NULL; temp = next)
  175. {
  176. next = (Stream) xfunc_get_downjoin(temp);
  177. /*
  178.  * * if there are restrictions/secondary join clauses above this *
  179.  * node, call xfunc_llel_chains
  180.  */
  181. if (get_upstream(temp) && is_clause((Stream) get_upstream(temp)))
  182. if (xfunc_llel_chains(stream, temp))
  183. progress = true;
  184. }
  185. return progress;
  186. }
  187. /*
  188.  ** xfunc_llel_chains
  189.  **    A flavor of Monma and Sidney's Parallel Chains algorithm.
  190.  ** Given a stream which has been well-ordered except for its lowermost
  191.  ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate.
  192.  ** What that means here is to form groups in the chain above the lowest
  193.  ** join node above bottom inclusive, and then take all the restrictions
  194.  ** following bottom, and try to pull them up as far as possible.
  195.  */
  196. static bool
  197. xfunc_llel_chains(Stream root, Stream bottom)
  198. {
  199. bool progress = false;
  200. Stream origstream;
  201. Stream tmpstream,
  202. pathstream;
  203. Stream rootcopy = root;
  204. Assert(xfunc_check_stream(root));
  205. /* xfunc_prdmig_pullup will need an unmodified copy of the stream */
  206. origstream = (Stream) copyObject((Node) root);
  207. /* form groups among ill-ordered nodes */
  208. xfunc_form_groups(root, bottom);
  209. /* sort chain by rank */
  210. Assert(xfunc_in_stream(bottom, root));
  211. rootcopy = xfunc_stream_qsort(root, bottom);
  212. /*
  213.  * * traverse sorted stream -- if any restriction has moved above a
  214.  * join, * we must pull it up in the plan. That is, make plan tree *
  215.  * reflect order of sorted stream.
  216.  */
  217. for (tmpstream = rootcopy,
  218.  pathstream = (Stream) xfunc_get_downjoin(rootcopy);
  219.  tmpstream != (Stream) NULL && pathstream != (Stream) NULL;
  220.  tmpstream = (Stream) get_downstream(tmpstream))
  221. {
  222. if (is_clause(tmpstream)
  223. && get_pathptr(pathstream) != get_pathptr(tmpstream))
  224. {
  225. /*
  226.  * * If restriction moved above a Join after sort, we pull it *
  227.  * up in the join plan. *  If restriction moved down, we
  228.  * ignore it. * This is because Joey's Sequoia paper proves
  229.  * that * restrictions should never move down. If this * one
  230.  * were moved down, it would violate "semantic correctness", *
  231.  * i.e. it would be lower than the attributes it references.
  232.  */
  233. Assert(xfunc_num_relids(pathstream) > xfunc_num_relids(tmpstream));
  234. progress = xfunc_prdmig_pullup(origstream, tmpstream,
  235.  (JoinPath) get_pathptr(pathstream));
  236. }
  237. if (get_downstream(tmpstream))
  238. pathstream = (Stream) xfunc_get_downjoin((Stream) get_downstream(tmpstream));
  239. }
  240. /* free up origstream */
  241. xfunc_free_stream(origstream);
  242. return progress;
  243. }
  244. /*
  245.  ** xfunc_complete_stream
  246.  **   Given a stream composed of join nodes only, make a copy containing the
  247.  ** join nodes along with the associated restriction nodes.
  248.  */
  249. static Stream
  250. xfunc_complete_stream(Stream stream)
  251. {
  252. Stream tmpstream,
  253. copystream,
  254. curstream = (Stream) NULL;
  255. copystream = (Stream) copyObject((Node) stream);
  256. Assert(xfunc_check_stream(copystream));
  257. curstream = copystream;
  258. Assert(!is_clause(curstream));
  259. /* curstream = (Stream)xfunc_get_downjoin(curstream); */
  260. while (curstream != (Stream) NULL)
  261. {
  262. xfunc_add_clauses(curstream);
  263. curstream = (Stream) xfunc_get_downjoin(curstream);
  264. }
  265. /* find top of stream and return it */
  266. for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr) NULL;
  267.  tmpstream = (Stream) get_upstream(tmpstream))
  268.  /* no body in for loop */ ;
  269. return tmpstream;
  270. }
  271. /*
  272.  ** xfunc_prdmig_pullup
  273.  **    pullup a clause in a path above joinpath.  Since the JoinPath tree
  274.  ** doesn't have upward pointers, it's difficult to deal with. Thus we
  275.  ** require the original stream, which maintains pointers to all the path
  276.  ** nodes. We use the original stream to find out what joins are
  277.  ** above the clause.
  278.  */
  279. static bool
  280. xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath)
  281. {
  282. RestrictInfo restrictinfo = get_cinfo(pullme);
  283. bool progress = false;
  284. Stream upjoin,
  285. orignode,
  286. temp;
  287. int whichchild;
  288. /* find node in origstream that contains clause */
  289. for (orignode = origstream;
  290.  orignode != (Stream) NULL
  291.  && get_cinfo(orignode) != restrictinfo;
  292.  orignode = (Stream) get_downstream(orignode))
  293.  /* empty body in for loop */ ;
  294. if (!orignode)
  295. elog(ERROR, "Didn't find matching node in original stream");
  296. /* pull up this node as far as it should go */
  297. for (upjoin = (Stream) xfunc_get_upjoin(orignode);
  298.  upjoin != (Stream) NULL
  299.  && (JoinPath) get_pathptr((Stream) xfunc_get_downjoin(upjoin))
  300.  != joinpath;
  301.  upjoin = (Stream) xfunc_get_upjoin(upjoin))
  302. {
  303. #ifdef DEBUG
  304. elog(DEBUG, "pulling up in xfunc_predmig_pullup!");
  305. #endif
  306. /* move clause up in path */
  307. if (get_pathptr((Stream) get_downstream(upjoin))
  308.   == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)))
  309. whichchild = OUTER;
  310. else
  311. whichchild = INNER;
  312. restrictinfo = xfunc_pullup((Path) get_pathptr((Stream) get_downstream(upjoin)),
  313. (JoinPath) get_pathptr(upjoin),
  314. restrictinfo,
  315. whichchild,
  316. get_clausetype(orignode));
  317. set_pathptr(pullme, get_pathptr(upjoin));
  318. /* pullme has been moved into locrestrictinfo */
  319. set_clausetype(pullme, XFUNC_LOCPRD);
  320. /*
  321.  * * xfunc_pullup makes new path nodes for children of *
  322.  * get_pathptr(current). We must modify the stream nodes to point *
  323.  * to these path nodes
  324.  */
  325. if (whichchild == OUTER)
  326. {
  327. for (temp = (Stream) get_downstream(upjoin); is_clause(temp);
  328.  temp = (Stream) get_downstream(temp))
  329. set_pathptr
  330. (temp, (pathPtr)
  331.  get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
  332. set_pathptr
  333. (temp,
  334. (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
  335. }
  336. else
  337. {
  338. for (temp = (Stream) get_downstream(upjoin); is_clause(temp);
  339.  temp = (Stream) get_downstream(temp))
  340. set_pathptr
  341. (temp, (pathPtr)
  342.  get_innerjoinpath((JoinPath) get_pathptr(upjoin)));
  343. set_pathptr
  344. (temp, (pathPtr)
  345.  get_innerjoinpath((JoinPath) get_pathptr(upjoin)));
  346. }
  347. progress = true;
  348. }
  349. if (!progress)
  350. elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup");
  351. return progress;
  352. }
  353. /*
  354.  ** xfunc_form_groups
  355.  **    A group is a pair of stream nodes a,b such that a is constrained to
  356.  ** precede b (for instance if a and b are both joins), but rank(a) > rank(b).
  357.  ** In such a situation, Monma and Sidney prove that no clauses should end
  358.  ** up between a and b, and therefore we may treat them as a group, with
  359.  ** selectivity equal to the product of their selectivities, and cost
  360.  ** equal to the cost of the first plus the selectivity of the first times the
  361.  ** cost of the second.  We define each node to be in a group by itself,
  362.  ** and then repeatedly find adjacent groups which are ordered by descending
  363.  ** rank, and make larger groups.  You know that two adjacent nodes are in a
  364.  ** group together if the lower has groupup set to true.  They will both have
  365.  ** the same groupcost and groupsel (since they're in the same group!)
  366.  */
  367. static void
  368. xfunc_form_groups(Query *queryInfo, Stream root, Stream bottom)
  369. {
  370. Stream temp,
  371. parent;
  372. int lowest = xfunc_num_relids((Stream) xfunc_get_upjoin(bottom));
  373. bool progress;
  374. LispValue primjoin;
  375. int whichchild;
  376. if (!lowest)
  377. return; /* no joins in stream, so no groups */
  378. /* initialize groups to be single nodes */
  379. for (temp = root;
  380.  temp != (Stream) NULL && temp != bottom;
  381.  temp = (Stream) get_downstream(temp))
  382. {
  383. /* if a Join node */
  384. if (!is_clause(temp))
  385. {
  386. if (get_pathptr((Stream) get_downstream(temp))
  387. == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(temp)))
  388. whichchild = OUTER;
  389. else
  390. whichchild = INNER;
  391. set_groupcost(temp,
  392.   xfunc_join_expense((JoinPath) get_pathptr(temp),
  393.  whichchild));
  394. if (primjoin = xfunc_primary_join((JoinPath) get_pathptr(temp)))
  395. {
  396. set_groupsel(temp,
  397.  compute_clause_selec(queryInfo,
  398.   primjoin, NIL));
  399. }
  400. else
  401. set_groupsel(temp, 1.0);
  402. }
  403. else
  404. /* a restriction, or 2-ary join pred */
  405. {
  406. set_groupcost(temp,
  407.   xfunc_expense(queryInfo,
  408. get_clause(get_cinfo(temp))));
  409. set_groupsel(temp,
  410.  compute_clause_selec(queryInfo,
  411.   get_clause(get_cinfo(temp)),
  412.   NIL));
  413. }
  414. set_groupup(temp, false);
  415. }
  416. /* make passes upwards, forming groups */
  417. do
  418. {
  419. progress = false;
  420. for (temp = (Stream) get_upstream(bottom);
  421.  temp != (Stream) NULL;
  422.  temp = (Stream) get_upstream(temp))
  423. {
  424. /* check for grouping with node upstream */
  425. if (!get_groupup(temp) && /* not already grouped */
  426. (parent = (Stream) get_upstream(temp)) != (Stream) NULL &&
  427. /* temp is a join or temp is the top of a group */
  428. (is_join((Path) get_pathptr(temp)) ||
  429.  get_downstream(temp) &&
  430.  get_groupup((Stream) get_downstream(temp))) &&
  431. get_grouprank(parent) < get_grouprank(temp))
  432. {
  433. progress = true;/* we formed a new group */
  434. set_groupup(temp, true);
  435. set_groupcost(temp,
  436.   get_groupcost(temp) +
  437.   get_groupsel(temp) * get_groupcost(parent));
  438. set_groupsel(temp, get_groupsel(temp) * get_groupsel(parent));
  439. /* fix costs and sels of all members of group */
  440. xfunc_setup_group(temp, bottom);
  441. }
  442. }
  443. } while (progress);
  444. }
  445. /* -------------------  UTILITY FUNCTIONS    ------------------------- */
  446. /*
  447.  ** xfunc_free_stream
  448.  **   walk down a stream and pfree it
  449.  */
  450. static void
  451. xfunc_free_stream(Stream root)
  452. {
  453. Stream cur,
  454. next;
  455. Assert(xfunc_check_stream(root));
  456. if (root != (Stream) NULL)
  457. for (cur = root; cur != (Stream) NULL; cur = next)
  458. {
  459. next = (Stream) get_downstream(cur);
  460. pfree(cur);
  461. }
  462. }
  463. /*
  464.  ** xfunc_add<_clauses
  465.  **    find any clauses above current, and insert them into stream as
  466.  ** appropriate.  Return uppermost clause inserted, or current if none.
  467.  */
  468. static Stream
  469. xfunc_add_clauses(Stream current)
  470. {
  471. Stream topnode = current;
  472. LispValue temp;
  473. LispValue primjoin;
  474. /* first add in the local clauses */
  475. foreach(temp, get_loc_restrictinfo((Path) get_pathptr(current)))
  476. {
  477. topnode = xfunc_streaminsert((RestrictInfo) lfirst(temp), topnode,
  478.  XFUNC_LOCPRD);
  479. }
  480. /* and add in the join clauses */
  481. if (IsA(get_pathptr(current), JoinPath))
  482. {
  483. primjoin = xfunc_primary_join((JoinPath) get_pathptr(current));
  484. foreach(temp, get_pathrestrictinfo((JoinPath) get_pathptr(current)))
  485. {
  486. if (!equal(get_clause((RestrictInfo) lfirst(temp)), primjoin))
  487. topnode = xfunc_streaminsert((RestrictInfo) lfirst(temp), topnode,
  488.  XFUNC_JOINPRD);
  489. }
  490. }
  491. return topnode;
  492. }
  493. /*
  494.  ** xfunc_setup_group
  495.  **   find all elements of stream that are grouped with node and are above
  496.  ** bottom, and set their groupcost and groupsel to be the same as node's.
  497.  */
  498. static void
  499. xfunc_setup_group(Stream node, Stream bottom)
  500. {
  501. Stream temp;
  502. if (node != bottom)
  503. /* traverse downwards */
  504. for (temp = (Stream) get_downstream(node);
  505.  temp != (Stream) NULL && temp != bottom;
  506.  temp = (Stream) get_downstream(temp))
  507. {
  508. if (!get_groupup(temp))
  509. break;
  510. else
  511. {
  512. set_groupcost(temp, get_groupcost(node));
  513. set_groupsel(temp, get_groupsel(node));
  514. }
  515. }
  516. /* traverse upwards */
  517. for (temp = (Stream) get_upstream(node); temp != (Stream) NULL;
  518.  temp = (Stream) get_upstream(temp))
  519. {
  520. if (!get_groupup((Stream) get_downstream(temp)))
  521. break;
  522. else
  523. {
  524. set_groupcost(temp, get_groupcost(node));
  525. set_groupsel(temp, get_groupsel(node));
  526. }
  527. }
  528. }
  529. /*
  530.  ** xfunc_streaminsert
  531.  **    Make a new Stream node to hold clause, and insert it above current.
  532.  ** Return new node.
  533.  */
  534. static Stream
  535. xfunc_streaminsert(RestrictInfo restrictinfo,
  536.    Stream current,
  537.    int clausetype) /* XFUNC_LOCPRD or XFUNC_JOINPRD */
  538. {
  539. Stream newstream = RMakeStream();
  540. set_upstream(newstream, get_upstream(current));
  541. if (get_upstream(current))
  542. set_downstream((Stream) (get_upstream(current)), (StreamPtr) newstream);
  543. set_upstream(current, (StreamPtr) newstream);
  544. set_downstream(newstream, (StreamPtr) current);
  545. set_pathptr(newstream, get_pathptr(current));
  546. set_cinfo(newstream, restrictinfo);
  547. set_clausetype(newstream, clausetype);
  548. return newstream;
  549. }
  550. /*
  551.  ** Given a Stream node, find the number of relids referenced in the pathnode
  552.  ** associated with the stream node.  The number of relids gives a unique
  553.  ** ordering on the joins in a stream, which we use to compare the height of
  554.  ** join nodes.
  555.  */
  556. static int
  557. xfunc_num_relids(Stream node)
  558. {
  559. if (!node || !IsA(get_pathptr(node), JoinPath))
  560. return 0;
  561. else
  562. return (length
  563. (get_relids(get_parent((JoinPath) get_pathptr(node)))));
  564. }
  565. /*
  566.  ** xfunc_get_downjoin
  567.  **    Given a stream node, find the next lowest node which points to a
  568.  ** join predicate or a scan node.
  569.  */
  570. static StreamPtr
  571. xfunc_get_downjoin(Stream node)
  572. {
  573. Stream temp;
  574. if (!is_clause(node)) /* if this is a join */
  575. node = (Stream) get_downstream(node);
  576. for (temp = node; temp && is_clause(temp);
  577.  temp = (Stream) get_downstream(temp))
  578.  /* empty body in for loop */ ;
  579. return (StreamPtr) temp;
  580. }
  581. /*
  582.  ** xfunc_get_upjoin
  583.  **   same as above, but upwards.
  584.  */
  585. static StreamPtr
  586. xfunc_get_upjoin(Stream node)
  587. {
  588. Stream temp;
  589. if (!is_clause(node)) /* if this is a join */
  590. node = (Stream) get_upstream(node);
  591. for (temp = node; temp && is_clause(temp);
  592.  temp = (Stream) get_upstream(temp))
  593.  /* empty body in for loop */ ;
  594. return (StreamPtr) temp;
  595. }
  596. /*
  597.  ** xfunc_stream_qsort
  598.  **   Given a stream, sort by group rank the elements in the stream from the
  599.  ** node "bottom" up.  DESTRUCTIVELY MODIFIES STREAM!  Returns new root.
  600.  */
  601. static Stream
  602. xfunc_stream_qsort(Stream root, Stream bottom)
  603. {
  604. int i;
  605. size_t num;
  606. Stream    *nodearray,
  607. output;
  608. Stream tmp;
  609. /* find size of list */
  610. for (num = 0, tmp = root; tmp != bottom;
  611.  tmp = (Stream) get_downstream(tmp))
  612. num++;
  613. if (num <= 1)
  614. return root;
  615. /* copy elements of the list into an array */
  616. nodearray = (Stream *) palloc(num * sizeof(Stream));
  617. for (tmp = root, i = 0; tmp != bottom;
  618.  tmp = (Stream) get_downstream(tmp), i++)
  619. nodearray[i] = tmp;
  620. /* sort the array */
  621. qsort(nodearray, num, sizeof(LispValue), xfunc_stream_compare);
  622. /* paste together the array elements */
  623. output = nodearray[num - 1];
  624. set_upstream(output, (StreamPtr) NULL);
  625. for (i = num - 2; i >= 0; i--)
  626. {
  627. set_downstream(nodearray[i + 1], (StreamPtr) nodearray[i]);
  628. set_upstream(nodearray[i], (StreamPtr) nodearray[i + 1]);
  629. }
  630. set_downstream(nodearray[0], (StreamPtr) bottom);
  631. if (bottom)
  632. set_upstream(bottom, (StreamPtr) nodearray[0]);
  633. Assert(xfunc_check_stream(output));
  634. return output;
  635. }
  636. /*
  637.  ** xfunc_stream_compare
  638.  **    comparison function for xfunc_stream_qsort.
  639.  ** Compare nodes by group rank.  If group ranks are equal, ensure that
  640.  ** join nodes appear in same order as in plan tree.
  641.  */
  642. static int
  643. xfunc_stream_compare(void *arg1, void *arg2)
  644. {
  645. Stream stream1 = *(Stream *) arg1;
  646. Stream stream2 = *(Stream *) arg2;
  647. Cost rank1,
  648. rank2;
  649. rank1 = get_grouprank(stream1);
  650. rank2 = get_grouprank(stream2);
  651. if (rank1 > rank2)
  652. return 1;
  653. else if (rank1 < rank2)
  654. return -1;
  655. else
  656. {
  657. if (is_clause(stream1) && is_clause(stream2))
  658. return 0; /* doesn't matter what order if both are
  659.  * restrictions */
  660. else if (!is_clause(stream1) && !is_clause(stream2))
  661. {
  662. if (xfunc_num_relids(stream1) < xfunc_num_relids(stream2))
  663. return -1;
  664. else
  665. return 1;
  666. }
  667. else if (is_clause(stream1) && !is_clause(stream2))
  668. {
  669. if (xfunc_num_relids(stream1) == xfunc_num_relids(stream2))
  670. /* stream1 is a restriction over stream2 */
  671. return 1;
  672. else
  673. return -1;
  674. }
  675. else if (!is_clause(stream1) && is_clause(stream2))
  676. {
  677. /* stream2 is a restriction over stream1: never push down */
  678. return -1;
  679. }
  680. }
  681. }
  682. /* ------------------  DEBUGGING ROUTINES ---------------------------- */
  683. /*
  684.  ** Make sure all pointers in stream make sense.  Make sure no joins are
  685.  ** out of order.
  686.  */
  687. static bool
  688. xfunc_check_stream(Stream node)
  689. {
  690. Stream temp;
  691. int numrelids,
  692. tmp;
  693. /* set numrelids higher than max */
  694. if (!is_clause(node))
  695. numrelids = xfunc_num_relids(node) + 1;
  696. else if (xfunc_get_downjoin(node))
  697. numrelids = xfunc_num_relids((Stream) xfunc_get_downjoin(node)) + 1;
  698. else
  699. numrelids = 1;
  700. for (temp = node; get_downstream(temp); temp = (Stream) get_downstream(temp))
  701. {
  702. if ((Stream) get_upstream((Stream) get_downstream(temp)) != temp)
  703. {
  704. elog(ERROR, "bad pointers in stream");
  705. return false;
  706. }
  707. if (!is_clause(temp))
  708. {
  709. if ((tmp = xfunc_num_relids(temp)) >= numrelids)
  710. {
  711. elog(ERROR, "Joins got reordered!");
  712. return false;
  713. }
  714. numrelids = tmp;
  715. }
  716. }
  717. return true;
  718. }
  719. /*
  720.  ** xfunc_in_stream
  721.  **   check if node is in stream
  722.  */
  723. static bool
  724. xfunc_in_stream(Stream node, Stream stream)
  725. {
  726. Stream temp;
  727. for (temp = stream; temp; temp = (Stream) get_downstream(temp))
  728. if (temp == node)
  729. return 1;
  730. return 0;
  731. }