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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * createplan.c
  4.  *   Routines to create the desired plan for processing a query
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.57.2.1 1999/07/29 03:34:11 tgl Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <string.h>
  15. #include <sys/types.h>
  16. #include "postgres.h"
  17. #include <utils/syscache.h>
  18. #include <catalog/pg_index.h>
  19. #include "nodes/execnodes.h"
  20. #include "nodes/plannodes.h"
  21. #include "nodes/relation.h"
  22. #include "nodes/primnodes.h"
  23. #include "nodes/nodeFuncs.h"
  24. #include "nodes/makefuncs.h"
  25. #include "utils/lsyscache.h"
  26. #include "utils/palloc.h"
  27. #include "utils/builtins.h"
  28. #include "optimizer/restrictinfo.h"
  29. #include "optimizer/cost.h"
  30. #include "optimizer/clauses.h"
  31. #include "optimizer/planmain.h"
  32. #include "optimizer/tlist.h"
  33. #include "optimizer/planner.h"
  34. #include "optimizer/xfunc.h"
  35. #include "optimizer/internal.h"
  36. #define NONAME_SORT 1
  37. #define NONAME_MATERIAL 2
  38. static List *switch_outer(List *clauses);
  39. static Oid *generate_merge_input_sortorder(List *pathkeys,
  40.    MergeOrder *mergeorder);
  41. static Scan *create_scan_node(Path *best_path, List *tlist);
  42. static Join *create_join_node(JoinPath *best_path, List *tlist);
  43. static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
  44. List *scan_clauses);
  45. static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
  46.   List *scan_clauses);
  47. static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist,
  48.  List *clauses, Plan *outer_node, List *outer_tlist,
  49.  Plan *inner_node, List *inner_tlist);
  50. static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist,
  51.   List *clauses, Plan *outer_node, List *outer_tlist,
  52.   Plan *inner_node, List *inner_tlist);
  53. static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist,
  54.  List *clauses, Plan *outer_node, List *outer_tlist,
  55.  Plan *inner_node, List *inner_tlist);
  56. static Node *fix_indxqual_references(Node *clause, Path *index_path);
  57. static Noname *make_noname(List *tlist, List *pathkeys, Oid *operators,
  58. Plan *plan_node, int nonametype);
  59. static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
  60.    List *indxid, List *indxqual, List *indxqualorig);
  61. static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
  62.   Plan *righttree);
  63. static HashJoin *make_hashjoin(List *tlist, List *qpqual,
  64.   List *hashclauses, Plan *lefttree, Plan *righttree);
  65. static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
  66. static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
  67.    List *mergeclauses, Plan *righttree, Plan *lefttree);
  68. static Material *make_material(List *tlist, Oid nonameid, Plan *lefttree,
  69.   int keycount);
  70. static void copy_costsize(Plan *dest, Plan *src);
  71. /*
  72.  * create_plan
  73.  *   Creates the access plan for a query by tracing backwards through the
  74.  *   desired chain of pathnodes, starting at the node 'best_path'.  For
  75.  *   every pathnode found:
  76.  *   (1) Create a corresponding plan node containing appropriate id,
  77.  *   target list, and qualification information.
  78.  *   (2) Modify ALL clauses so that attributes are referenced using
  79.  *   relative values.
  80.  *   (3) Target lists are not modified, but will be in another routine.
  81.  *
  82.  *   best_path is the best access path
  83.  *
  84.  *   Returns the optimal(?) access plan.
  85.  */
  86. Plan *
  87. create_plan(Path *best_path)
  88. {
  89. List    *tlist;
  90. Plan    *plan_node = (Plan *) NULL;
  91. RelOptInfo *parent_rel;
  92. int size;
  93. int width;
  94. int pages;
  95. int tuples;
  96. parent_rel = best_path->parent;
  97. tlist = get_actual_tlist(parent_rel->targetlist);
  98. size = parent_rel->size;
  99. width = parent_rel->width;
  100. pages = parent_rel->pages;
  101. tuples = parent_rel->tuples;
  102. switch (best_path->pathtype)
  103. {
  104. case T_IndexScan:
  105. case T_SeqScan:
  106. plan_node = (Plan *) create_scan_node(best_path, tlist);
  107. break;
  108. case T_HashJoin:
  109. case T_MergeJoin:
  110. case T_NestLoop:
  111. plan_node = (Plan *) create_join_node((JoinPath *) best_path, tlist);
  112. break;
  113. default:
  114. /* do nothing */
  115. break;
  116. }
  117. plan_node->plan_size = size;
  118. plan_node->plan_width = width;
  119. if (pages == 0)
  120. pages = 1;
  121. plan_node->plan_tupperpage = tuples / pages;
  122. #ifdef NOT_USED /* fix xfunc */
  123. /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
  124. if (XfuncMode != XFUNC_OFF)
  125. {
  126. set_qpqual((Plan) plan_node,
  127.    lisp_qsort(get_qpqual((Plan) plan_node),
  128.   xfunc_clause_compare));
  129. if (XfuncMode != XFUNC_NOR)
  130. /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
  131. xfunc_disjunct_sort(plan_node->qpqual);
  132. }
  133. #endif
  134. return plan_node;
  135. }
  136. /*
  137.  * create_scan_node
  138.  *  Create a scan path for the parent relation of 'best_path'.
  139.  *
  140.  *  tlist is the targetlist for the base relation scanned by 'best_path'
  141.  *
  142.  *  Returns the scan node.
  143.  */
  144. static Scan *
  145. create_scan_node(Path *best_path, List *tlist)
  146. {
  147. Scan    *node = NULL;
  148. List    *scan_clauses;
  149. /*
  150.  * Extract the relevant clauses from the parent relation and replace
  151.  * the operator OIDs with the corresponding regproc ids.
  152.  *
  153.  * now that local predicate clauses are copied into paths in
  154.  * find_rel_paths() and then (possibly) pulled up in
  155.  * xfunc_trypullup(), we get the relevant clauses from the path
  156.  * itself, not its parent relation.   --- JMH, 6/15/92
  157.  */
  158. scan_clauses = fix_opids(get_actual_clauses(best_path->loc_restrictinfo));
  159. switch (best_path->pathtype)
  160. {
  161. case T_SeqScan:
  162. node = (Scan *) create_seqscan_node(best_path, tlist, scan_clauses);
  163. break;
  164. case T_IndexScan:
  165. node = (Scan *) create_indexscan_node((IndexPath *) best_path,
  166.   tlist,
  167.   scan_clauses);
  168. break;
  169. default:
  170. elog(ERROR, "create_scan_node: unknown node type",
  171.  best_path->pathtype);
  172. break;
  173. }
  174. return node;
  175. }
  176. /*
  177.  * create_join_node
  178.  *   Create a join path for 'best_path' and(recursively) paths for its
  179.  *   inner and outer paths.
  180.  *
  181.  *   'tlist' is the targetlist for the join relation corresponding to
  182.  * 'best_path'
  183.  *
  184.  *   Returns the join node.
  185.  */
  186. static Join *
  187. create_join_node(JoinPath *best_path, List *tlist)
  188. {
  189. Plan    *outer_node;
  190. List    *outer_tlist;
  191. Plan    *inner_node;
  192. List    *inner_tlist;
  193. List    *clauses;
  194. Join    *retval = NULL;
  195. outer_node = create_plan((Path *) best_path->outerjoinpath);
  196. outer_tlist = outer_node->targetlist;
  197. inner_node = create_plan((Path *) best_path->innerjoinpath);
  198. inner_tlist = inner_node->targetlist;
  199. clauses = get_actual_clauses(best_path->pathinfo);
  200. switch (best_path->path.pathtype)
  201. {
  202. case T_MergeJoin:
  203. retval = (Join *) create_mergejoin_node((MergePath *) best_path,
  204. tlist,
  205. clauses,
  206. outer_node,
  207. outer_tlist,
  208. inner_node,
  209. inner_tlist);
  210. break;
  211. case T_HashJoin:
  212. retval = (Join *) create_hashjoin_node((HashPath *) best_path,
  213.    tlist,
  214.    clauses,
  215.    outer_node,
  216.    outer_tlist,
  217.    inner_node,
  218.    inner_tlist);
  219. break;
  220. case T_NestLoop:
  221. retval = (Join *) create_nestloop_node((NestPath *) best_path,
  222.    tlist,
  223.    clauses,
  224.    outer_node,
  225.    outer_tlist,
  226.    inner_node,
  227.    inner_tlist);
  228. break;
  229. default:
  230. /* do nothing */
  231. elog(ERROR, "create_join_node: unknown node type",
  232.  best_path->path.pathtype);
  233. }
  234. #if 0
  235. /*
  236.  * * Expensive function pullups may have pulled local predicates *
  237.  * into this path node.  Put them in the qpqual of the plan node. *
  238.  * JMH, 6/15/92
  239.  */
  240. if (get_loc_restrictinfo(best_path) != NIL)
  241. set_qpqual((Plan) retval,
  242.    nconc(get_qpqual((Plan) retval),
  243.  fix_opids(get_actual_clauses
  244.    (get_loc_restrictinfo(best_path)))));
  245. #endif
  246. return retval;
  247. }
  248. /*****************************************************************************
  249.  *
  250.  * BASE-RELATION SCAN METHODS
  251.  *
  252.  *****************************************************************************/
  253. /*
  254.  * create_seqscan_node
  255.  *  Returns a seqscan node for the base relation scanned by 'best_path'
  256.  *  with restriction clauses 'scan_clauses' and targetlist 'tlist'.
  257.  */
  258. static SeqScan *
  259. create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
  260. {
  261. SeqScan    *scan_node = (SeqScan *) NULL;
  262. Index scan_relid = -1;
  263. List    *temp;
  264. temp = best_path->parent->relids;
  265. if (temp == NULL)
  266. elog(ERROR, "scanrelid is empty");
  267. else
  268. scan_relid = (Index) lfirsti(temp); /* ??? who takes care of
  269.  * lnext? - ay */
  270. scan_node = make_seqscan(tlist,
  271.  scan_clauses,
  272.  scan_relid,
  273.  (Plan *) NULL);
  274. scan_node->plan.cost = best_path->path_cost;
  275. return scan_node;
  276. }
  277. /*
  278.  * create_indexscan_node
  279.  *   Returns a indexscan node for the base relation scanned by 'best_path'
  280.  *   with restriction clauses 'scan_clauses' and targetlist 'tlist'.
  281.  */
  282. static IndexScan *
  283. create_indexscan_node(IndexPath *best_path,
  284.   List *tlist,
  285.   List *scan_clauses)
  286. {
  287. /*
  288.  * Extract the(first if conjunct, only if disjunct) clause from the
  289.  * restrictinfo list.
  290.  */
  291. Expr    *index_clause = (Expr *) NULL;
  292. List    *indxqual = NIL;
  293. List    *qpqual = NIL;
  294. List    *fixed_indxqual = NIL;
  295. List    *ixid;
  296. IndexScan  *scan_node = (IndexScan *) NULL;
  297. bool lossy = FALSE;
  298. HeapTuple indexTuple;
  299. Form_pg_index index;
  300. /*
  301.  * If an 'or' clause is to be used with this index, the indxqual field
  302.  * will contain a list of the 'or' clause arguments, e.g., the
  303.  * clause(OR a b c) will generate: ((a) (b) (c)).  Otherwise, the
  304.  * indxqual will simply contain one conjunctive qualification: ((a)).
  305.  */
  306. if (best_path->indexqual != NULL)
  307. /* added call to fix_opids, JMH 6/23/92 */
  308. index_clause = (Expr *)
  309. lfirst(fix_opids(get_actual_clauses(best_path->indexqual)));
  310. if (or_clause((Node *) index_clause))
  311. {
  312. List    *temp = NIL;
  313. foreach(temp, index_clause->args)
  314. indxqual = lappend(indxqual, lcons(lfirst(temp), NIL));
  315. }
  316. else
  317. {
  318. indxqual = lcons(get_actual_clauses(best_path->indexqual),
  319.  NIL);
  320. }
  321. /* check and see if any indices are lossy */
  322. foreach(ixid, best_path->indexid)
  323. {
  324. indexTuple = SearchSysCacheTuple(INDEXRELID,
  325.  ObjectIdGetDatum(lfirsti(ixid)),
  326.  0, 0, 0);
  327. if (!HeapTupleIsValid(indexTuple))
  328. elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
  329. index = (Form_pg_index) GETSTRUCT(indexTuple);
  330. if (index->indislossy)
  331. lossy = TRUE;
  332. }
  333. /*
  334.  * The qpqual field contains all restrictions not automatically
  335.  * handled by the index.  Note that for non-lossy indices, the
  336.  * predicates in the indxqual are handled by the index, while for
  337.  * lossy indices the indxqual predicates need to be double-checked
  338.  * after the index fetches the best-guess tuples.
  339.  */
  340. if (or_clause((Node *) index_clause))
  341. {
  342. qpqual = set_difference(scan_clauses,
  343. lcons(index_clause, NIL));
  344. if (lossy)
  345. qpqual = lappend(qpqual, (List *) copyObject(index_clause));
  346. }
  347. else
  348. {
  349. qpqual = set_difference(scan_clauses, lfirst(indxqual));
  350. if (lossy)
  351. qpqual = nconc(qpqual,
  352.    (List *) copyObject(lfirst(indxqual)));
  353. }
  354. fixed_indxqual = (List *) fix_indxqual_references((Node *) indxqual, (Path *) best_path);
  355. scan_node = make_indexscan(tlist,
  356.    qpqual,
  357.    lfirsti(best_path->path.parent->relids),
  358.    best_path->indexid,
  359.    fixed_indxqual,
  360.    indxqual);
  361. scan_node->scan.plan.cost = best_path->path.path_cost;
  362. return scan_node;
  363. }
  364. /*****************************************************************************
  365.  *
  366.  * JOIN METHODS
  367.  *
  368.  *****************************************************************************/
  369. static NestLoop *
  370. create_nestloop_node(NestPath *best_path,
  371.  List *tlist,
  372.  List *clauses,
  373.  Plan *outer_node,
  374.  List *outer_tlist,
  375.  Plan *inner_node,
  376.  List *inner_tlist)
  377. {
  378. NestLoop   *join_node = (NestLoop *) NULL;
  379. if (IsA(inner_node, IndexScan))
  380. {
  381. /*
  382.  * An index is being used to reduce the number of tuples scanned
  383.  * in the inner relation. There will never be more than one index
  384.  * used in the inner scan path, so we need only consider the first
  385.  * set of qualifications in indxqual.
  386.  *
  387.  * But there may be more than one clause in this "first set" in the
  388.  * case of multi-column indices. - vadim 03/18/97
  389.  */
  390. List    *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual);
  391. List    *inner_qual;
  392. bool found = false;
  393. foreach(inner_qual, inner_indxqual)
  394. {
  395. if (!qual_clause_p((Node *) lfirst(inner_qual)))
  396. {
  397. found = true;
  398. break;
  399. }
  400. }
  401. /*
  402.  * If we have in fact found a join index qualification, remove
  403.  * these index clauses from the nestloop's join clauses and reset
  404.  * the inner(index) scan's qualification so that the var nodes
  405.  * refer to the proper outer join relation attributes.
  406.  *
  407.  * XXX Re-moving index clauses doesn't work properly: 1.
  408.  * fix_indxqual_references may change varattno-s in
  409.  * inner_indxqual; 2. clauses may be commuted I havn't time to fix
  410.  * it at the moment.   - vadim 04/24/97
  411.  */
  412. if (found)
  413. {
  414. List    *new_inner_qual = NIL;
  415. clauses = set_difference(clauses, inner_indxqual); /* XXX */
  416. new_inner_qual = index_outerjoin_references(inner_indxqual,
  417.   outer_node->targetlist,
  418.    ((Scan *) inner_node)->scanrelid);
  419. ((IndexScan *) inner_node)->indxqual = lcons(new_inner_qual, NIL);
  420. }
  421. }
  422. else if (IsA_Join(inner_node))
  423. {
  424. inner_node = (Plan *) make_noname(inner_tlist,
  425.   NIL,
  426.   NULL,
  427.   inner_node,
  428.   NONAME_MATERIAL);
  429. }
  430. join_node = make_nestloop(tlist,
  431.   join_references(clauses,
  432.   outer_tlist,
  433.   inner_tlist),
  434.   outer_node,
  435.   inner_node);
  436. join_node->join.cost = best_path->path.path_cost;
  437. return join_node;
  438. }
  439. static MergeJoin *
  440. create_mergejoin_node(MergePath *best_path,
  441.   List *tlist,
  442.   List *clauses,
  443.   Plan *outer_node,
  444.   List *outer_tlist,
  445.   Plan *inner_node,
  446.   List *inner_tlist)
  447. {
  448. List    *qpqual,
  449.    *mergeclauses;
  450. MergeJoin  *join_node;
  451. /*
  452.  * Separate the mergeclauses from the other join qualification clauses
  453.  * and set those clauses to contain references to lower attributes.
  454.  */
  455. qpqual = join_references(set_difference(clauses,
  456. best_path->path_mergeclauses),
  457.  outer_tlist,
  458.  inner_tlist);
  459. /*
  460.  * Now set the references in the mergeclauses and rearrange them so
  461.  * that the outer variable is always on the left.
  462.  */
  463. mergeclauses = switch_outer(join_references(best_path->path_mergeclauses,
  464. outer_tlist,
  465. inner_tlist));
  466. /*
  467.  * Create explicit sort paths for the outer and inner join paths if
  468.  * necessary.  The sort cost was already accounted for in the path.
  469.  */
  470. if (best_path->outersortkeys)
  471. {
  472. Oid    *outer_order = generate_merge_input_sortorder(
  473. best_path->outersortkeys,
  474.  best_path->jpath.path.pathorder->ord.merge);
  475. outer_node = (Plan *) make_noname(outer_tlist,
  476.   best_path->outersortkeys,
  477.   outer_order,
  478.   outer_node,
  479.   NONAME_SORT);
  480. }
  481. if (best_path->innersortkeys)
  482. {
  483. Oid    *inner_order = generate_merge_input_sortorder(
  484. best_path->innersortkeys,
  485.  best_path->jpath.path.pathorder->ord.merge);
  486. inner_node = (Plan *) make_noname(inner_tlist,
  487.   best_path->innersortkeys,
  488.   inner_order,
  489.   inner_node,
  490.   NONAME_SORT);
  491. }
  492. join_node = make_mergejoin(tlist,
  493.    qpqual,
  494.    mergeclauses,
  495.    inner_node,
  496.    outer_node);
  497. join_node->join.cost = best_path->jpath.path.path_cost;
  498. return join_node;
  499. }
  500. /*
  501.  * create_hashjoin_node-- XXX HASH
  502.  *
  503.  *   Returns a new hashjoin node.
  504.  *
  505.  *   XXX hash join ops are totally bogus -- how the hell do we choose
  506.  * these??  at runtime?  what about a hash index?
  507.  */
  508. static HashJoin *
  509. create_hashjoin_node(HashPath *best_path,
  510.  List *tlist,
  511.  List *clauses,
  512.  Plan *outer_node,
  513.  List *outer_tlist,
  514.  Plan *inner_node,
  515.  List *inner_tlist)
  516. {
  517. List    *qpqual;
  518. List    *hashclauses;
  519. HashJoin   *join_node;
  520. Hash    *hash_node;
  521. Var    *innerhashkey;
  522. /*
  523.  * Separate the hashclauses from the other join qualification clauses
  524.  * and set those clauses to contain references to lower attributes.
  525.  */
  526. qpqual = join_references(set_difference(clauses,
  527. best_path->path_hashclauses),
  528.  outer_tlist,
  529.  inner_tlist);
  530. /*
  531.  * Now set the references in the hashclauses and rearrange them so
  532.  * that the outer variable is always on the left.
  533.  */
  534. hashclauses = switch_outer(join_references(best_path->path_hashclauses,
  535.    outer_tlist,
  536.    inner_tlist));
  537. innerhashkey = get_rightop(lfirst(hashclauses));
  538. hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
  539. join_node = make_hashjoin(tlist,
  540.   qpqual,
  541.   hashclauses,
  542.   outer_node,
  543.   (Plan *) hash_node);
  544. join_node->join.cost = best_path->jpath.path.path_cost;
  545. return join_node;
  546. }
  547. /*****************************************************************************
  548.  *
  549.  * SUPPORTING ROUTINES
  550.  *
  551.  *****************************************************************************/
  552. /*
  553.  * fix_indxqual_references
  554.  * Adjust a qual clause to refer to an index instead of the original relation.
  555.  *
  556.  * Returns a modified copy of the given clause --- the original is not changed.
  557.  */
  558. static Node *
  559. fix_indxqual_references(Node *clause, Path *index_path)
  560. {
  561. if (clause == NULL)
  562. return NULL;
  563. else if (IsA(clause, Var))
  564. {
  565. if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno)
  566. {
  567. Node    *newclause;
  568. int pos = 0;
  569. int varatt = ((Var *) clause)->varattno;
  570. int    *indexkeys = ((IndexPath *) index_path)->indexkeys;
  571. if (indexkeys)
  572. {
  573. while (indexkeys[pos] != 0)
  574. {
  575. if (varatt == indexkeys[pos])
  576. break;
  577. pos++;
  578. }
  579. }
  580. newclause = copyObject(clause);
  581. ((Var *) newclause)->varattno = pos + 1;
  582. return newclause;
  583. }
  584. /* The Var is not part of the indexed relation, leave it alone */
  585. return copyObject(clause);
  586. }
  587. else if (single_node(clause))
  588. return copyObject(clause);
  589. else if (is_opclause(clause) &&
  590.  is_funcclause((Node *) get_leftop((Expr *) clause)) &&
  591. ((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex)
  592. {
  593. /*
  594.  * This looks pretty seriously wrong to me, but I'm not sure what
  595.  * it's supposed to be doing ... tgl 5/99
  596.  */
  597. Var    *newvar = makeVar((Index) lfirsti(index_path->parent->relids),
  598.  1, /* func indices have one key */
  599. ((Func *) ((Expr *) clause)->oper)->functype,
  600.  -1,
  601.  0,
  602.  (Index) lfirsti(index_path->parent->relids),
  603.  0);
  604. return ((Node *) make_opclause((Oper *) ((Expr *) clause)->oper,
  605.    newvar,
  606.    get_rightop((Expr *) clause)));
  607. }
  608. else if (IsA(clause, Expr))
  609. {
  610. Expr    *expr = (Expr *) clause;
  611. List    *new_subclauses = NIL;
  612. List    *i;
  613. foreach(i, expr->args)
  614. {
  615. Node    *subclause = lfirst(i);
  616. new_subclauses = lappend(new_subclauses,
  617.  fix_indxqual_references(subclause,
  618.  index_path));
  619. }
  620. return (Node *) make_clause(expr->opType, expr->oper, new_subclauses);
  621. }
  622. else if (IsA(clause, List))
  623. {
  624. List    *new_subclauses = NIL;
  625. List    *i;
  626. foreach(i, (List *) clause)
  627. {
  628. Node    *subclause = lfirst(i);
  629. new_subclauses = lappend(new_subclauses,
  630.  fix_indxqual_references(subclause,
  631.  index_path));
  632. }
  633. return (Node *) new_subclauses;
  634. }
  635. else if (IsA(clause, ArrayRef))
  636. {
  637. ArrayRef   *oldnode = (ArrayRef *) clause;
  638. ArrayRef   *newnode = makeNode(ArrayRef);
  639. newnode->refattrlength = oldnode->refattrlength;
  640. newnode->refelemlength = oldnode->refelemlength;
  641. newnode->refelemtype = oldnode->refelemtype;
  642. newnode->refelembyval = oldnode->refelembyval;
  643. newnode->refupperindexpr = (List *)
  644. fix_indxqual_references((Node *) oldnode->refupperindexpr,
  645. index_path);
  646. newnode->reflowerindexpr = (List *)
  647. fix_indxqual_references((Node *) oldnode->reflowerindexpr,
  648. index_path);
  649. newnode->refexpr =
  650. fix_indxqual_references(oldnode->refexpr, index_path);
  651. newnode->refassgnexpr =
  652. fix_indxqual_references(oldnode->refassgnexpr, index_path);
  653. return (Node *) newnode;
  654. }
  655. else if (IsA(clause, CaseExpr))
  656. {
  657. CaseExpr   *oldnode = (CaseExpr *) clause;
  658. CaseExpr   *newnode = makeNode(CaseExpr);
  659. newnode->casetype = oldnode->casetype;
  660. newnode->arg = oldnode->arg; /* XXX should always be null
  661.  * anyway ... */
  662. newnode->args = (List *)
  663. fix_indxqual_references((Node *) oldnode->args,
  664. index_path);
  665. newnode->defresult =
  666. fix_indxqual_references(oldnode->defresult,
  667. index_path);
  668. return (Node *) newnode;
  669. }
  670. else if (IsA(clause, CaseWhen))
  671. {
  672. CaseWhen   *oldnode = (CaseWhen *) clause;
  673. CaseWhen   *newnode = makeNode(CaseWhen);
  674. newnode->expr =
  675. fix_indxqual_references(oldnode->expr,
  676. index_path);
  677. newnode->result =
  678. fix_indxqual_references(oldnode->result,
  679. index_path);
  680. return (Node *) newnode;
  681. }
  682. else
  683. {
  684. elog(ERROR, "fix_indxqual_references: Cannot handle node type %d",
  685.  nodeTag(clause));
  686. return NULL;
  687. }
  688. }
  689. /*
  690.  * switch_outer
  691.  *   Given a list of merge clauses, rearranges the elements within the
  692.  *   clauses so the outer join variable is on the left and the inner is on
  693.  *   the right.  The original list is not touched; a modified list
  694.  *   is returned.
  695.  */
  696. static List *
  697. switch_outer(List *clauses)
  698. {
  699. List    *t_list = NIL;
  700. Expr    *temp;
  701. List    *i;
  702. Expr    *clause;
  703. Node    *op;
  704. foreach(i, clauses)
  705. {
  706. clause = lfirst(i);
  707. Assert(is_opclause((Node *) clause));
  708. op = (Node *) get_rightop(clause);
  709. Assert(op != (Node *) NULL);
  710. if (IsA(op, ArrayRef))
  711. op = ((ArrayRef *) op)->refexpr;
  712. Assert(IsA(op, Var));
  713. if (var_is_outer((Var *) op))
  714. {
  715. /*
  716.  * Duplicate just enough of the structure to allow commuting
  717.  * the clause without changing the original list.  Could use
  718.  * copyObject, but a complete deep copy is overkill.
  719.  */
  720. temp = make_clause(clause->opType, clause->oper,
  721.    lcons(get_leftop(clause),
  722.  lcons(get_rightop(clause),
  723.    NIL)));
  724. /* Commute it --- note this modifies the temp node in-place. */
  725. CommuteClause((Node *) temp);
  726. t_list = lappend(t_list, temp);
  727. }
  728. else
  729. t_list = lappend(t_list, clause);
  730. }
  731. return t_list;
  732. }
  733. /*
  734.  * generate_merge_input_sortorder
  735.  *
  736.  * Generate the list of sort ops needed to sort one of the input paths for
  737.  * a merge.  We may have to use either left or right sortop for each item,
  738.  * since the original mergejoin clause may or may not have been commuted
  739.  * (compare switch_outer above).
  740.  *
  741.  * XXX This is largely a crock.  It works only because group_clauses_by_order
  742.  * only groups together mergejoin clauses that have identical MergeOrder info,
  743.  * which means we can safely use a single MergeOrder input to deal with all
  744.  * the data.  There should be a more general data structure that allows coping
  745.  * with groups of mergejoin clauses that have different join operators.
  746.  */
  747. static Oid *
  748. generate_merge_input_sortorder(List *pathkeys, MergeOrder *mergeorder)
  749. {
  750. int listlength = length(pathkeys);
  751. Oid    *result = (Oid *) palloc(sizeof(Oid) * (listlength + 1));
  752. Oid    *nextsortop = result;
  753. List    *p;
  754. foreach(p, pathkeys)
  755. {
  756. Var    *pkey = (Var *) lfirst((List *) lfirst(p));
  757. Assert(IsA(pkey, Var));
  758. if (pkey->vartype == mergeorder->left_type)
  759. *nextsortop++ = mergeorder->left_operator;
  760. else if (pkey->vartype == mergeorder->right_type)
  761. *nextsortop++ = mergeorder->right_operator;
  762. else
  763. elog(ERROR,
  764.  "generate_merge_input_sortorder: can't handle data type %d",
  765.  pkey->vartype);
  766. }
  767. *nextsortop++ = InvalidOid;
  768. return result;
  769. }
  770. /*
  771.  * set_noname_tlist_operators
  772.  *   Sets the key and keyop fields of resdom nodes in a target list.
  773.  *
  774.  *   'tlist' is the target list
  775.  *   'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)),
  776.  * corresponding to vars in the target list that are to
  777.  * be sorted or hashed
  778.  *   'operators' is the corresponding list of N sort or hash operators
  779.  *
  780.  *   Returns the modified-in-place target list.
  781.  */
  782. static List *
  783. set_noname_tlist_operators(List *tlist, List *pathkeys, Oid *operators)
  784. {
  785. int keyno = 1;
  786. Node    *pathkey;
  787. Resdom    *resdom;
  788. List    *i;
  789. foreach(i, pathkeys)
  790. {
  791. pathkey = lfirst((List *) lfirst(i));
  792. resdom = tlist_member((Var *) pathkey, tlist);
  793. if (resdom)
  794. {
  795. /*
  796.  * Order the resdom pathkey and replace the operator OID for
  797.  * each key with the regproc OID.
  798.  */
  799. resdom->reskey = keyno;
  800. resdom->reskeyop = get_opcode(operators[keyno - 1]);
  801. }
  802. keyno += 1;
  803. }
  804. return tlist;
  805. }
  806. /*
  807.  * Copy cost and size info from a lower plan node to an inserted node.
  808.  * This is not critical, since the decisions have already been made,
  809.  * but it helps produce more reasonable-looking EXPLAIN output.
  810.  */
  811. static void
  812. copy_costsize(Plan *dest, Plan *src)
  813. {
  814. if (src)
  815. {
  816. dest->cost = src->cost;
  817. dest->plan_size = src->plan_size;
  818. dest->plan_width = src->plan_width;
  819. }
  820. else
  821. {
  822. dest->cost = 0;
  823. dest->plan_size = 0;
  824. dest->plan_width = 0;
  825. }
  826. }
  827. /*****************************************************************************
  828.  *
  829.  *
  830.  *****************************************************************************/
  831. /*
  832.  * make_noname
  833.  *   Create plan nodes to sort or materialize relations into noname. The
  834.  *   result returned for a sort will look like (SEQSCAN(SORT(plan_node)))
  835.  *   or (SEQSCAN(MATERIAL(plan_node)))
  836.  *
  837.  *   'tlist' is the target list of the scan to be sorted or hashed
  838.  *   'pathkeys' is the list of keys which the sort or hash will be done on
  839.  *   'operators' is the operators with which the sort or hash is to be done
  840.  * (a list of operator OIDs)
  841.  *   'plan_node' is the node which yields tuples for the sort
  842.  *   'nonametype' indicates which operation(sort or hash) to perform
  843.  */
  844. static Noname *
  845. make_noname(List *tlist,
  846. List *pathkeys,
  847. Oid *operators,
  848. Plan *plan_node,
  849. int nonametype)
  850. {
  851. List    *noname_tlist;
  852. Noname    *retval = NULL;
  853. /* Create a new target list for the noname, with keys set. */
  854. noname_tlist = set_noname_tlist_operators(new_unsorted_tlist(tlist),
  855.   pathkeys,
  856.   operators);
  857. switch (nonametype)
  858. {
  859. case NONAME_SORT:
  860. retval = (Noname *) make_seqscan(tlist,
  861.  NIL,
  862.  _NONAME_RELATION_ID_,
  863.  (Plan *) make_sort(noname_tlist,
  864. _NONAME_RELATION_ID_,
  865. plan_node,
  866.   length(pathkeys)));
  867. break;
  868. case NONAME_MATERIAL:
  869. retval = (Noname *) make_seqscan(tlist,
  870.  NIL,
  871.  _NONAME_RELATION_ID_,
  872.  (Plan *) make_material(noname_tlist,
  873. _NONAME_RELATION_ID_,
  874. plan_node,
  875.   length(pathkeys)));
  876. break;
  877. default:
  878. elog(ERROR, "make_noname: unknown noname type %d", nonametype);
  879. }
  880. return retval;
  881. }
  882. SeqScan    *
  883. make_seqscan(List *qptlist,
  884.  List *qpqual,
  885.  Index scanrelid,
  886.  Plan *lefttree)
  887. {
  888. SeqScan    *node = makeNode(SeqScan);
  889. Plan    *plan = &node->plan;
  890. copy_costsize(plan, lefttree);
  891. plan->state = (EState *) NULL;
  892. plan->targetlist = qptlist;
  893. plan->qual = qpqual;
  894. plan->lefttree = lefttree;
  895. plan->righttree = NULL;
  896. node->scanrelid = scanrelid;
  897. node->scanstate = (CommonScanState *) NULL;
  898. return node;
  899. }
  900. static IndexScan *
  901. make_indexscan(List *qptlist,
  902.    List *qpqual,
  903.    Index scanrelid,
  904.    List *indxid,
  905.    List *indxqual,
  906.    List *indxqualorig)
  907. {
  908. IndexScan  *node = makeNode(IndexScan);
  909. Plan    *plan = &node->scan.plan;
  910. copy_costsize(plan, NULL);
  911. plan->state = (EState *) NULL;
  912. plan->targetlist = qptlist;
  913. plan->qual = qpqual;
  914. plan->lefttree = NULL;
  915. plan->righttree = NULL;
  916. node->scan.scanrelid = scanrelid;
  917. node->indxid = indxid;
  918. node->indxqual = indxqual;
  919. node->indxqualorig = indxqualorig;
  920. node->scan.scanstate = (CommonScanState *) NULL;
  921. return node;
  922. }
  923. static NestLoop *
  924. make_nestloop(List *qptlist,
  925.   List *qpqual,
  926.   Plan *lefttree,
  927.   Plan *righttree)
  928. {
  929. NestLoop   *node = makeNode(NestLoop);
  930. Plan    *plan = &node->join;
  931. /*
  932.  * this cost estimate is entirely bogus... hopefully it will be
  933.  * overwritten by caller.
  934.  */
  935. plan->cost = (lefttree ? lefttree->cost : 0) +
  936. (righttree ? righttree->cost : 0);
  937. plan->state = (EState *) NULL;
  938. plan->targetlist = qptlist;
  939. plan->qual = qpqual;
  940. plan->lefttree = lefttree;
  941. plan->righttree = righttree;
  942. node->nlstate = (NestLoopState *) NULL;
  943. return node;
  944. }
  945. static HashJoin *
  946. make_hashjoin(List *tlist,
  947.   List *qpqual,
  948.   List *hashclauses,
  949.   Plan *lefttree,
  950.   Plan *righttree)
  951. {
  952. HashJoin   *node = makeNode(HashJoin);
  953. Plan    *plan = &node->join;
  954. /*
  955.  * this cost estimate is entirely bogus... hopefully it will be
  956.  * overwritten by caller.
  957.  */
  958. plan->cost = (lefttree ? lefttree->cost : 0) +
  959. (righttree ? righttree->cost : 0);
  960. plan->state = (EState *) NULL;
  961. plan->targetlist = tlist;
  962. plan->qual = qpqual;
  963. plan->lefttree = lefttree;
  964. plan->righttree = righttree;
  965. node->hashclauses = hashclauses;
  966. node->hashdone = false;
  967. return node;
  968. }
  969. static Hash *
  970. make_hash(List *tlist, Var *hashkey, Plan *lefttree)
  971. {
  972. Hash    *node = makeNode(Hash);
  973. Plan    *plan = &node->plan;
  974. copy_costsize(plan, lefttree);
  975. plan->state = (EState *) NULL;
  976. plan->targetlist = tlist;
  977. plan->qual = NULL;
  978. plan->lefttree = lefttree;
  979. plan->righttree = NULL;
  980. node->hashkey = hashkey;
  981. return node;
  982. }
  983. static MergeJoin *
  984. make_mergejoin(List *tlist,
  985.    List *qpqual,
  986.    List *mergeclauses,
  987.    Plan *righttree,
  988.    Plan *lefttree)
  989. {
  990. MergeJoin  *node = makeNode(MergeJoin);
  991. Plan    *plan = &node->join;
  992. /*
  993.  * this cost estimate is entirely bogus... hopefully it will be
  994.  * overwritten by caller.
  995.  */
  996. plan->cost = (lefttree ? lefttree->cost : 0) +
  997. (righttree ? righttree->cost : 0);
  998. plan->state = (EState *) NULL;
  999. plan->targetlist = tlist;
  1000. plan->qual = qpqual;
  1001. plan->lefttree = lefttree;
  1002. plan->righttree = righttree;
  1003. node->mergeclauses = mergeclauses;
  1004. return node;
  1005. }
  1006. Sort *
  1007. make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount)
  1008. {
  1009. Sort    *node = makeNode(Sort);
  1010. Plan    *plan = &node->plan;
  1011. copy_costsize(plan, lefttree);
  1012. plan->cost += cost_sort(NULL, plan->plan_size, plan->plan_width);
  1013. plan->state = (EState *) NULL;
  1014. plan->targetlist = tlist;
  1015. plan->qual = NIL;
  1016. plan->lefttree = lefttree;
  1017. plan->righttree = NULL;
  1018. node->nonameid = nonameid;
  1019. node->keycount = keycount;
  1020. return node;
  1021. }
  1022. static Material *
  1023. make_material(List *tlist,
  1024.   Oid nonameid,
  1025.   Plan *lefttree,
  1026.   int keycount)
  1027. {
  1028. Material   *node = makeNode(Material);
  1029. Plan    *plan = &node->plan;
  1030. copy_costsize(plan, lefttree);
  1031. plan->state = (EState *) NULL;
  1032. plan->targetlist = tlist;
  1033. plan->qual = NIL;
  1034. plan->lefttree = lefttree;
  1035. plan->righttree = NULL;
  1036. node->nonameid = nonameid;
  1037. node->keycount = keycount;
  1038. return node;
  1039. }
  1040. Agg *
  1041. make_agg(List *tlist, Plan *lefttree)
  1042. {
  1043. Agg    *node = makeNode(Agg);
  1044. copy_costsize(&node->plan, lefttree);
  1045. node->plan.state = (EState *) NULL;
  1046. node->plan.qual = NULL;
  1047. node->plan.targetlist = tlist;
  1048. node->plan.lefttree = lefttree;
  1049. node->plan.righttree = (Plan *) NULL;
  1050. node->aggs = NIL;
  1051. return node;
  1052. }
  1053. Group *
  1054. make_group(List *tlist,
  1055.    bool tuplePerGroup,
  1056.    int ngrp,
  1057.    AttrNumber *grpColIdx,
  1058.    Sort *lefttree)
  1059. {
  1060. Group    *node = makeNode(Group);
  1061. copy_costsize(&node->plan, (Plan *) lefttree);
  1062. node->plan.state = (EState *) NULL;
  1063. node->plan.qual = NULL;
  1064. node->plan.targetlist = tlist;
  1065. node->plan.lefttree = (Plan *) lefttree;
  1066. node->plan.righttree = (Plan *) NULL;
  1067. node->tuplePerGroup = tuplePerGroup;
  1068. node->numCols = ngrp;
  1069. node->grpColIdx = grpColIdx;
  1070. return node;
  1071. }
  1072. /*
  1073.  * A unique node always has a SORT node in the lefttree.
  1074.  *
  1075.  * the uniqueAttr argument must be a null-terminated string,
  1076.  * either the name of the attribute to select unique on
  1077.  * or "*"
  1078.  */
  1079. Unique *
  1080. make_unique(List *tlist, Plan *lefttree, char *uniqueAttr)
  1081. {
  1082. Unique    *node = makeNode(Unique);
  1083. Plan    *plan = &node->plan;
  1084. copy_costsize(plan, lefttree);
  1085. plan->state = (EState *) NULL;
  1086. plan->targetlist = tlist;
  1087. plan->qual = NIL;
  1088. plan->lefttree = lefttree;
  1089. plan->righttree = NULL;
  1090. node->nonameid = _NONAME_RELATION_ID_;
  1091. node->keycount = 0;
  1092. if (strcmp(uniqueAttr, "*") == 0)
  1093. node->uniqueAttr = NULL;
  1094. else
  1095. node->uniqueAttr = pstrdup(uniqueAttr);
  1096. return node;
  1097. }
  1098. #ifdef NOT_USED
  1099. List *
  1100. generate_fjoin(List *tlist)
  1101. {
  1102. List tlistP;
  1103. List newTlist = NIL;
  1104. List fjoinList = NIL;
  1105. int nIters = 0;
  1106. /*
  1107.  * Break the target list into elements with Iter nodes, and those
  1108.  * without them.
  1109.  */
  1110. foreach(tlistP, tlist)
  1111. {
  1112. List tlistElem;
  1113. tlistElem = lfirst(tlistP);
  1114. if (IsA(lsecond(tlistElem), Iter))
  1115. {
  1116. nIters++;
  1117. fjoinList = lappend(fjoinList, tlistElem);
  1118. }
  1119. else
  1120. newTlist = lappend(newTlist, tlistElem);
  1121. }
  1122. /*
  1123.  * if we have an Iter node then we need to flatten.
  1124.  */
  1125. if (nIters > 0)
  1126. {
  1127. List    *inner;
  1128. List    *tempList;
  1129. Fjoin    *fjoinNode;
  1130. DatumPtr results = (DatumPtr) palloc(nIters * sizeof(Datum));
  1131. BoolPtr alwaysDone = (BoolPtr) palloc(nIters * sizeof(bool));
  1132. inner = lfirst(fjoinList);
  1133. fjoinList = lnext(fjoinList);
  1134. fjoinNode = (Fjoin) MakeFjoin(false,
  1135.   nIters,
  1136.   inner,
  1137.   results,
  1138.   alwaysDone);
  1139. tempList = lcons(fjoinNode, fjoinList);
  1140. newTlist = lappend(newTlist, tempList);
  1141. }
  1142. return newTlist;
  1143. return tlist; /* do nothing for now - ay 10/94 */
  1144. }
  1145. #endif