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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * prepunion.c
  4.  *   Routines to plan inheritance, union, and version queries
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.33.2.1 1999/08/02 06:27:05 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <sys/types.h>
  15. #include "postgres.h"
  16. #include "optimizer/plancat.h"
  17. #include "optimizer/planmain.h"
  18. #include "optimizer/planner.h"
  19. #include "optimizer/prep.h"
  20. #include "parser/parse_clause.h"
  21. #include "parser/parsetree.h"
  22. #include "utils/lsyscache.h"
  23. static List *plan_inherit_query(Relids relids, Index rt_index,
  24.    RangeTblEntry *rt_entry, Query *parse, List *tlist,
  25.    List **union_rtentriesPtr);
  26. static RangeTblEntry *new_rangetable_entry(Oid new_relid,
  27.  RangeTblEntry *old_entry);
  28. static Query *subst_rangetable(Query *root, Index index,
  29.  RangeTblEntry *new_entry);
  30. static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
  31.   Oid new_relid, Query *parsetree);
  32. static Append *make_append(List *appendplans, List *unionrtables, Index rt_index,
  33. List *inheritrtable, List *tlist);
  34. /*
  35.  * plan_union_queries
  36.  *
  37.  *   Plans the queries for a given UNION.
  38.  *
  39.  * Returns a list containing a list of plans and a list of rangetables
  40.  */
  41. Append *
  42. plan_union_queries(Query *parse)
  43. {
  44. List    *union_plans = NIL,
  45.    *ulist,
  46.    *union_all_queries,
  47.    *union_rts,
  48.    *last_union = NIL,
  49.    *hold_sortClause = parse->sortClause;
  50. bool union_all_found = false,
  51. union_found = false,
  52. last_union_all_flag = false;
  53. /*------------------------------------------------------------------
  54.  *
  55.  * Do we need to split up our unions because we have UNION and UNION
  56.  * ALL?
  57.  *
  58.  * We are checking for the case of: SELECT 1 UNION SELECT 2 UNION SELECT
  59.  * 3 UNION ALL SELECT 4 UNION ALL SELECT 5
  60.  *
  61.  * where we have to do a DISTINCT on the output of the first three
  62.  * queries, then add the rest. If they have used UNION and UNION ALL,
  63.  * we grab all queries up to the last UNION query, make them their own
  64.  * UNION with the owner as the first query in the list.  Then, we take
  65.  * the remaining queries, which is UNION ALL, and add them to the list
  66.  * of union queries.
  67.  *
  68.  * So the above query becomes:
  69.  *
  70.  * Append Node
  71.  * {
  72.  * Sort and Unique
  73.  * {
  74.  * Append Node
  75.  * {
  76.  * SELECT 1 This is really a sub-UNION.
  77.  * unionClause We run a DISTINCT on these.
  78.  * {
  79.  * SELECT 2
  80.  * SELECT 3
  81.  * }
  82.  * }
  83.  * }
  84.  * SELECT 4
  85.  * SELECT 5
  86.  * }
  87.  *
  88.  *---------------------------------------------------------------------
  89.  */
  90. foreach(ulist, parse->unionClause)
  91. {
  92. Query    *union_query = lfirst(ulist);
  93. if (union_query->unionall)
  94. union_all_found = true;
  95. else
  96. {
  97. union_found = true;
  98. last_union = ulist;
  99. }
  100. last_union_all_flag = union_query->unionall;
  101. }
  102. /* Is this a simple one */
  103. if (!union_all_found ||
  104. !union_found ||
  105. /* A trailing UNION negates the affect of earlier UNION ALLs */
  106. !last_union_all_flag)
  107. {
  108. List    *hold_unionClause = parse->unionClause;
  109. /* we will do this later, so don't do it now */
  110. if (!union_all_found ||
  111. !last_union_all_flag)
  112. {
  113. parse->sortClause = NIL;
  114. parse->uniqueFlag = NULL;
  115. }
  116. parse->unionClause = NIL; /* prevent recursion */
  117. union_plans = lcons(union_planner(parse), NIL);
  118. union_rts = lcons(parse->rtable, NIL);
  119. foreach(ulist, hold_unionClause)
  120. {
  121. Query    *union_query = lfirst(ulist);
  122. union_plans = lappend(union_plans, union_planner(union_query));
  123. union_rts = lappend(union_rts, union_query->rtable);
  124. }
  125. }
  126. else
  127. {
  128. /*
  129.  * We have mixed unions and non-unions
  130.  *
  131.  * We need to restructure this to put the UNIONs on their own so we
  132.  * can do a DISTINCT.
  133.  */
  134. /* save off everthing past the last UNION */
  135. union_all_queries = lnext(last_union);
  136. /* clip off the list to remove the trailing UNION ALLs */
  137. lnext(last_union) = NIL;
  138. /*
  139.  * Recursion, but UNION only. The last one is a UNION, so it will
  140.  * not come here in recursion,
  141.  */
  142. union_plans = lcons(union_planner(parse), NIL);
  143. union_rts = lcons(parse->rtable, NIL);
  144. /* Append the remainging UNION ALLs */
  145. foreach(ulist, union_all_queries)
  146. {
  147. Query    *union_all_query = lfirst(ulist);
  148. union_plans = lappend(union_plans, union_planner(union_all_query));
  149. union_rts = lappend(union_rts, union_all_query->rtable);
  150. }
  151. }
  152. /* We have already split UNION and UNION ALL and we made it consistent */
  153. if (!last_union_all_flag)
  154. {
  155. parse->uniqueFlag = "*";
  156. parse->sortClause = transformSortClause(NULL, NIL,
  157. hold_sortClause,
  158. parse->targetList, "*");
  159. }
  160. else
  161. /* needed so we don't take the flag from the first query */
  162. parse->uniqueFlag = NULL;
  163. /* Make sure we don't try to apply the first query's grouping stuff
  164.  * to the Append node, either.  Basically we don't want union_planner
  165.  * to do anything when we return control, except add the top sort/unique
  166.  * nodes for DISTINCT processing if this wasn't UNION ALL, or the top
  167.  * sort node if it was UNION ALL with a user-provided sort clause.
  168.  */
  169. parse->groupClause = NULL;
  170. parse->havingQual = NULL;
  171. parse->hasAggs = false;
  172. return (make_append(union_plans,
  173. union_rts,
  174. 0,
  175. NULL,
  176. parse->targetList));
  177. }
  178. /*
  179.  * plan_inherit_queries
  180.  *
  181.  *   Plans the queries for a given parent relation.
  182.  *
  183.  * Inputs:
  184.  * parse = parent parse tree
  185.  * tlist = target list for inheritance subqueries (not same as parent's!)
  186.  * rt_index = rangetable index for current inheritance item
  187.  *
  188.  * Returns an APPEND node that forms the result of performing the given
  189.  * query for each member relation of the inheritance group.
  190.  *
  191.  * If grouping, aggregation, or sorting is specified in the parent plan,
  192.  * the subplans should not do any of those steps --- we must do those
  193.  * operations just once above the APPEND node.  The given tlist has been
  194.  * modified appropriately to remove group/aggregate expressions, but the
  195.  * Query node still has the relevant fields set.  We remove them in the
  196.  * copies used for subplans (see plan_inherit_query).
  197.  *
  198.  * NOTE: this can be invoked recursively if more than one inheritance wildcard
  199.  * is present.  At each level of recursion, the first wildcard remaining in
  200.  * the rangetable is expanded.
  201.  */
  202. Append *
  203. plan_inherit_queries(Query *parse, List *tlist, Index rt_index)
  204. {
  205. List    *rangetable = parse->rtable;
  206. RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
  207. List    *inheritrtable = NIL;
  208. List    *union_relids;
  209. List    *union_plans;
  210. union_relids = find_all_inheritors(lconsi(rt_entry->relid,
  211.   NIL),
  212.    NIL);
  213. /*
  214.  * Remove the flag for this relation, since we're about to handle it
  215.  * (do it before recursing!). XXX destructive change to parent parse tree
  216.  */
  217. rt_entry->inh = false;
  218. union_plans = plan_inherit_query(union_relids, rt_index, rt_entry,
  219.  parse, tlist, &inheritrtable);
  220. return (make_append(union_plans,
  221. NULL,
  222. rt_index,
  223. inheritrtable,
  224. ((Plan *) lfirst(union_plans))->targetlist));
  225. }
  226. /*
  227.  * plan_inherit_query
  228.  *   Returns a list of plans for 'relids' and a list of range table entries
  229.  *   in union_rtentries.
  230.  */
  231. static List *
  232. plan_inherit_query(Relids relids,
  233.    Index rt_index,
  234.    RangeTblEntry *rt_entry,
  235.    Query *root,
  236.    List *tlist,
  237.    List **union_rtentriesPtr)
  238. {
  239. List    *union_plans = NIL;
  240. List    *union_rtentries = NIL;
  241. List    *i;
  242. foreach(i, relids)
  243. {
  244. int relid = lfirsti(i);
  245. RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
  246.    rt_entry);
  247. Query    *new_root = subst_rangetable(root,
  248. rt_index,
  249. new_rt_entry);
  250. /*
  251.  * Insert the desired simplified tlist into the subquery
  252.  */
  253. new_root->targetList = copyObject(tlist);
  254. /*
  255.  * Clear the sorting and grouping qualifications in the subquery,
  256.  * so that sorting will only be done once after append
  257.  */
  258. new_root->uniqueFlag = NULL;
  259. new_root->sortClause = NULL;
  260. new_root->groupClause = NULL;
  261. new_root->havingQual = NULL;
  262. new_root->hasAggs = false; /* shouldn't be any left ... */
  263. /* Fix attribute numbers as necessary */
  264. fix_parsetree_attnums(rt_index,
  265.   rt_entry->relid,
  266.   relid,
  267.   new_root);
  268. union_plans = lappend(union_plans, union_planner(new_root));
  269. union_rtentries = lappend(union_rtentries, new_rt_entry);
  270. }
  271. *union_rtentriesPtr = union_rtentries;
  272. return union_plans;
  273. }
  274. /*
  275.  * find_all_inheritors -
  276.  * Returns a list of relids corresponding to relations that inherit
  277.  * attributes from any relations listed in either of the argument relid
  278.  * lists.
  279.  */
  280. List *
  281. find_all_inheritors(Relids unexamined_relids,
  282. Relids examined_relids)
  283. {
  284. List    *new_inheritors = NIL;
  285. List    *new_examined_relids = NIL;
  286. List    *new_unexamined_relids = NIL;
  287. /*
  288.  * Find all relations which inherit from members of
  289.  * 'unexamined_relids' and store them in 'new_inheritors'.
  290.  */
  291. List    *rels = NIL;
  292. List    *newrels = NIL;
  293. foreach(rels, unexamined_relids)
  294. {
  295. newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)),
  296.   newrels);
  297. }
  298. new_inheritors = newrels;
  299. new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids);
  300. new_unexamined_relids = set_differencei(new_inheritors,
  301. new_examined_relids);
  302. if (new_unexamined_relids == NULL)
  303. return new_examined_relids;
  304. else
  305. {
  306. return (find_all_inheritors(new_unexamined_relids,
  307. new_examined_relids));
  308. }
  309. }
  310. /*
  311.  * first_inherit_rt_entry -
  312.  * Given a rangetable, find the first rangetable entry that represents
  313.  * the appropriate special case.
  314.  *
  315.  * Returns a rangetable index.,  Returns -1 if no matches
  316.  */
  317. int
  318. first_inherit_rt_entry(List *rangetable)
  319. {
  320. int count = 0;
  321. List    *temp;
  322. foreach(temp, rangetable)
  323. {
  324. RangeTblEntry *rt_entry = lfirst(temp);
  325. if (rt_entry->inh)
  326. return count + 1;
  327. count++;
  328. }
  329. return -1;
  330. }
  331. /*
  332.  * new_rangetable_entry -
  333.  * Replaces the name and relid of 'old_entry' with the values for
  334.  * 'new_relid'.
  335.  *
  336.  * Returns a copy of 'old_entry' with the parameters substituted.
  337.  */
  338. static RangeTblEntry *
  339. new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
  340. {
  341. RangeTblEntry *new_entry = copyObject(old_entry);
  342. /* ??? someone tell me what the following is doing! - ay 11/94 */
  343. if (!strcmp(new_entry->refname, "*CURRENT*") ||
  344. !strcmp(new_entry->refname, "*NEW*"))
  345. new_entry->refname = get_rel_name(new_relid);
  346. else
  347. new_entry->relname = get_rel_name(new_relid);
  348. new_entry->relid = new_relid;
  349. return new_entry;
  350. }
  351. /*
  352.  * subst_rangetable
  353.  *   Replaces the 'index'th rangetable entry in 'root' with 'new_entry'.
  354.  *
  355.  * Returns a new copy of 'root'.
  356.  */
  357. static Query *
  358. subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry)
  359. {
  360. Query    *new_root = copyObject(root);
  361. List    *temp;
  362. int i;
  363. for (temp = new_root->rtable, i = 1; i < index; temp = lnext(temp), i++)
  364. ;
  365. lfirst(temp) = new_entry;
  366. return new_root;
  367. }
  368. /*
  369.  * Adjust varnos for child tables.  This routine makes it possible for
  370.  * child tables to have different column positions for the "same" attribute
  371.  * as a parent, which helps ALTER TABLE ADD COLUMN.  Unfortunately this isn't
  372.  * nearly enough to make it work transparently; there are other places where
  373.  * things fall down if children and parents don't have the same column numbers
  374.  * for inherited attributes.  It'd be better to rip this code out and fix
  375.  * ALTER TABLE...
  376.  */
  377. static void
  378. fix_parsetree_attnums_nodes(Index rt_index,
  379. Oid old_relid,
  380. Oid new_relid,
  381. Node *node)
  382. {
  383. if (node == NULL)
  384. return;
  385. switch (nodeTag(node))
  386. {
  387. case T_TargetEntry:
  388. {
  389. TargetEntry *tle = (TargetEntry *) node;
  390. fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
  391. tle->expr);
  392. }
  393. break;
  394. case T_Expr:
  395. {
  396. Expr    *expr = (Expr *) node;
  397. fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
  398. (Node *) expr->args);
  399. }
  400. break;
  401. case T_Var:
  402. {
  403. Var    *var = (Var *) node;
  404. if (var->varno == rt_index && var->varattno != 0)
  405. {
  406. var->varattno = get_attnum(new_relid,
  407.  get_attname(old_relid, var->varattno));
  408. }
  409. }
  410. break;
  411. case T_List:
  412. {
  413. List    *l;
  414. foreach(l, (List *) node)
  415. {
  416. fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
  417. (Node *) lfirst(l));
  418. }
  419. }
  420. break;
  421. default:
  422. break;
  423. }
  424. }
  425. /*
  426.  * fix_parsetree_attnums
  427.  *   Replaces attribute numbers from the relation represented by
  428.  *   'old_relid' in 'parsetree' with the attribute numbers from
  429.  *   'new_relid'.
  430.  *
  431.  * Returns the destructively_modified parsetree.
  432.  *
  433.  */
  434. static void
  435. fix_parsetree_attnums(Index rt_index,
  436.   Oid old_relid,
  437.   Oid new_relid,
  438.   Query *parsetree)
  439. {
  440. if (old_relid == new_relid)
  441. return;
  442. fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
  443. (Node *) parsetree->targetList);
  444. fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
  445. parsetree->qual);
  446. }
  447. static Append *
  448. make_append(List *appendplans,
  449. List *unionrtables,
  450. Index rt_index,
  451. List *inheritrtable,
  452. List *tlist)
  453. {
  454. Append    *node = makeNode(Append);
  455. List    *subnode;
  456. node->appendplans = appendplans;
  457. node->unionrtables = unionrtables;
  458. node->inheritrelid = rt_index;
  459. node->inheritrtable = inheritrtable;
  460. node->plan.cost = 0.0;
  461. foreach(subnode, appendplans)
  462. node->plan.cost += ((Plan *) lfirst(subnode))->cost;
  463. node->plan.state = (EState *) NULL;
  464. node->plan.targetlist = tlist;
  465. node->plan.qual = NIL;
  466. node->plan.lefttree = (Plan *) NULL;
  467. node->plan.righttree = (Plan *) NULL;
  468. return node;
  469. }