arch-dev.sgml
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:148k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. for attributes that are not contained in the {it targetlist} of the {tt
  2. AGG} node yet and add them to the previously made copy.
  3. %
  4. <step> The extended {it targetlist} is used to create the subplan attached to
  5. the {tt lefttree} field of the {tt AGG} node. That means that the
  6. {it targetlists} of the {tt GRP} node, of the {tt SORT} node and of the
  7. {tt SeqScan} node will now contain an entry for the attribute {tt
  8. pno}. The {it targetlist} of the {tt AGG} node itself will not be changed
  9. because we do not want to include the attribute {tt pno} into the
  10. result returned by the whole query.
  11. %
  12. end{itemize}
  13. Care has to be taken that the {tt varattno} fields of the {tt VAR}
  14. nodes used in the {it targetlists} contain the position of the
  15. corresponding attribute in the  {it targetlist} of the subplan (i.e the
  16. subplan delivering the tuples for further processing by the actual
  17. node). \
  18. \
  19. The following part deals with the source code of the new and
  20. changed functions involved in the planner/optimizer stage. The files
  21. affected are: \
  22. \
  23. indent {tt $ldots$/src/backend/optimizer/plan/setrefs.c} \
  24. indent {tt $ldots$/src/backend/optimizer/plan/planner.c} \
  25. \
  26. Since all of the functions presented here are very long and would need
  27. very much space if presented as a whole, we just list the most
  28. important parts. \
  29. \
  30. The following two functions are new and have been
  31. introduced for the {it having logic}. They are contained in the file
  32. {tt $ldots$/src/backend/optimizer/plan/setrefs.c}:
  33. %
  34. begin{itemize}
  35. %
  36. <step> {tt check_having_qual_for_aggs()} \
  37. This function takes the representation of a {it having clause} given
  38. by the parameter {tt clause}, a {it targetlist} given by the
  39. parameter {tt subplanTargetList} and a {it group clause} given by
  40. the parameter {tt groupClause} as arguments and scans the
  41. representation of the {it having clause} recursively for {it
  42. aggregate functions}. If an {it aggregate function} is found it is
  43. attached to a list (internally called {tt agg_list}) and finally
  44. returned by the function. 
  45. Additionally the {tt varno} field of every {tt VAR} node found is
  46. set to the position of the corresponding attribute in the {it
  47. targetlist} given by {tt subplanTargetList}.
  48. If the {it having clause} contains a subquery the function also makes
  49. sure, that every attribute from the {it main query} that is used
  50. within the subquery also appears in the {it group clause} given by
  51. {tt groupClause}. If the attribute cannot be found in the {it group
  52. clause} an error message is printed to the screen and the query
  53. processing is aborted.
  54. %
  55. begin{verbatim}
  56.   List *
  57.   check_having_qual_for_aggs(Node *clause, 
  58.                              List *subplanTargetList, 
  59.                              List *groupClause)
  60.   {
  61.     List *t, *l1;
  62.     List *agg_list = NIL;  
  63.     int  contained_in_group_clause = 0;
  64.   
  65.     if (IsA(clause, Var))
  66.     {
  67.       TargetEntry *subplanVar;      
  68.       subplanVar = match_varid((Var *) clause, 
  69.                                subplanTargetList);      
  70.       /* Change the varattno fields of the 
  71.        * var node to point to the resdom->resnofields 
  72.        * of the subplan (lefttree) 
  73.        */         
  74.       ((Var *) clause)->varattno = 
  75.         subplanVar->resdom->resno;      
  76.       return NIL;      
  77.     }
  78.     else 
  79.       if (is_funcclause(clause) || not_clause(clause)  
  80.           || or_clause(clause) || and_clause(clause))
  81.       {
  82.         int new_length=0, old_length=0;        
  83.         /* This is a function. Recursively call this 
  84.          * routine for its arguments... (i.e. for AND, 
  85.          * OR, ... clauses!)
  86.          */
  87.         foreach(t, ((Expr *) clause)->args)
  88.         {
  89.           old_length=length((List *)agg_list);          
  90.           agg_list = nconc(agg_list,
  91.               check_having_qual_for_aggs(lfirst(t), 
  92.                                  subplanTargetList,
  93.                                  groupClause));          
  94.           if(((new_length=length((List *)agg_list)) == 
  95.               old_length) || (new_length == 0))
  96.           {
  97.             elog(ERROR,"This could have been done 
  98.                                  in a where clause!!");
  99.             return NIL;
  100.           } 
  101.         }
  102.         return agg_list;
  103.       }
  104.       else 
  105.         if (IsA(clause, Aggreg))
  106.         {
  107.           return lcons(clause,
  108.                         check_having_qual_for_aggs(
  109.                             ((Aggreg *)clause)->target, 
  110.                             subplanTargetList,
  111.                             groupClause));                
  112.         }
  113.         else 
  114.                             .
  115.                             .
  116.                             .
  117.   }
  118. end{verbatim}
  119. %
  120. <step> {tt check_having_qual_for_vars()} \
  121. This function takes the representation of a {it having clause} given
  122. by the parameter {tt clause} and the actual {it targetlist}
  123. given by the parameter {tt targetlist_so_far} as arguments and
  124. recursively scans the representation of the {it having clause} for
  125. attributes that are not included in the actual {it targetlist}
  126. yet. Whenever such an attribute is found it is added to the actual
  127. {it targetlist} which is finally returned by the function.
  128. Attributes contained in the {it having clause} but not in the {it
  129. targetlist} show up with queries like:
  130. %
  131. begin{verbatim}
  132.   select sid 
  133.   from  part 
  134.   group by sid 
  135.   having min(pid) > 1;
  136. end{verbatim}
  137. %
  138. In the above query the attribute {tt pid} is used in the {it having
  139. clause} but it does not appear in the {it targetlist} (i.e. the list
  140. of attributes after the keyword {tt select}). Unfortunately only
  141. those attributes are delivered by the subplan and can therefore be
  142. used within the {it having clause}. To become able to handle queries
  143. like that correctly, we have to extend the actual {it targetlist} by
  144. those attributes used in the {tt having clause} but not already
  145. appearing in the {it targetlist}.
  146. %
  147. begin{verbatim}
  148.   List *
  149.   check_having_qual_for_vars(Node *clause, 
  150.                              List *targetlist_so_far)
  151.   {
  152.     List     *t;
  153.     if (IsA(clause, Var))
  154.     {
  155.       Rel         tmp_rel;
  156.       
  157.       tmp_rel.targetlist = targetlist_so_far;
  158.       /* Check if the VAR is already contained in the 
  159.        * targetlist 
  160.        */
  161.       if (tlist_member((Var *)clause, 
  162.                   (List *)targetlist_so_far) == NULL)
  163.       {
  164.         add_tl_element(&tmp_rel, (Var *)clause); 
  165.       }             
  166.       return tmp_rel.targetlist;
  167.     }
  168.     else 
  169.       if (is_funcclause(clause) || not_clause(clause)
  170.           || or_clause(clause) || and_clause(clause))
  171.       {
  172.         /* This is a function. Recursively call this 
  173.          * routine for its arguments...
  174.          */
  175.         foreach(t, ((Expr *) clause)->args)
  176.         {
  177.           targetlist_so_far = 
  178.             check_having_qual_for_vars(lfirst(t), 
  179.                             targetlist_so_far);
  180.         }
  181.         return targetlist_so_far;
  182.       }
  183.       else 
  184.         if (IsA(clause, Aggreg))
  185.         {
  186.           targetlist_so_far = 
  187.             check_having_qual_for_vars(
  188.                             ((Aggreg *)clause)->target, 
  189.                             targetlist_so_far);
  190.           return targetlist_so_far;
  191.         }
  192.                             .
  193.                             .
  194.                             .
  195.   }
  196. end{verbatim}
  197. %
  198. end{itemize}
  199. %
  200. The next function is found in {tt
  201. $ldots$/src/backend/optimizer/plan/planner.c}:
  202. %
  203. begin{itemize}
  204. %
  205. <step> {tt union_planner()} \
  206. This function creates a {it plan} from the {it parsetree} given to
  207. it by the parameter {tt parse} that can be executed by the {it
  208. executor}. 
  209. If {it aggregate functions} are present (indicated by {tt
  210. parse->hasAggs} set to true) the first step is to extend the {it
  211. targetlist} by those attributes that are used within the {it having
  212. clause} (if any is present) but do not appear in the {it select list}
  213. (Refer to the description of {tt check_having_qual_for_vars()}
  214. above).
  215. The next step is to call the function {tt query_planner()} creating
  216. a {it plan} without taking the {it group clause}, the {it aggregate
  217. functions} and the {it having clause} into account for the moment.
  218. Next insert a {tt GRP} node at the top of the {it plan} according
  219. to the {it group clause} of the {it parsetree} if any is present.  
  220. Add an {tt AGG} node to the top of the current {it plan} if {it
  221. aggregate functions} are present and if a {it having clause} is
  222. present additionally perform the following steps:
  223. %
  224. begin{itemize}
  225. <step> Perform various transformations to the representation of the
  226. {it having clause} (e.g. transform it to CNF, $ldots$).
  227. <step> Attach the transformed representation of the {it having clause} to the
  228. field {tt plan.qual} of the just created {tt AGG} node.
  229. <step> Examine the whole {it having clause} and search for {it
  230. aggregate functions}. This is done using the function {tt
  231. check_having_qual_for_aggs()} which appends every {it aggregate
  232. function} found to a list that is finally returned.
  233. <step> Append the list just created to the list already attached to the
  234. field {tt aggs} of the {tt AGG} node (this list contains the {it
  235. aggregate functions} found in the {it targetlist}).
  236. <step> Make sure that  {it aggregate functions} do appear in the 
  237. {it having clause}. This is done by comparing the length of the list
  238. attached to {tt aggs} before and after the call to {tt
  239. check_having_qual_for_aggs()}.  If the length has not changed, we
  240. know that no {it aggregate function} has been detected and that this
  241. query could have been formulated using only a {it where clause}. In
  242. this case an error message is printed to the screen and the processing
  243. is aborted.
  244. end{itemize}
  245. %
  246. pagebreak
  247. %
  248. begin{verbatim}
  249.   Plan *
  250.   union_planner(Query *parse)
  251.   {
  252.      List       *tlist = parse->targetList;
  253. +    /* copy the original tlist, we will need the 
  254. +     * original one for the AGG node later on */
  255. +     List *new_tlist = new_unsorted_tlist(tlist); 
  256.                             .
  257.                             .
  258.                             .
  259. +         if (parse->hasAggs)
  260. +         {
  261. +           /* extend targetlist by variables not
  262. +            * contained already but used in the 
  263. +            * havingQual.
  264. +            */
  265. +           if (parse->havingQual != NULL)
  266. +             {
  267. +               new_tlist = 
  268. +                 check_having_qual_for_vars(
  269. +                              parse->havingQual,
  270. +                              new_tlist);
  271. +             }
  272. +         }          
  273.                             .
  274.                             .
  275.                             .
  276.           /* Call the planner for everything
  277.            * but groupclauses and aggregate funcs. 
  278.            */
  279.           result_plan = query_planner(parse,
  280.                                   parse->commandType,
  281.                                   new_tlist,
  282.                                   (List *) parse->qual);
  283.                             .
  284.                             .
  285.                             .
  286.         /* If aggregate is present, insert the AGG node
  287.          */
  288.         if (parse->hasAggs)
  289.         {
  290.           int old_length=0, new_length=0;                
  291.           /* Create the AGG node but use 'tlist' not 
  292.            * 'new_tlist' as target list because we
  293.            * don't want the additional attributes 
  294.            * (only used for the havingQual, see 
  295.            * above) to show up in the result. 
  296.            */
  297.           result_plan = (Plan *) make_agg(tlist, 
  298.                                        result_plan);
  299.                             .
  300.                             .
  301.                             .
  302. +         /* Check every clause of the havingQual for 
  303. +          * aggregates used and append them to 
  304. +          * the list in result_plan->aggs 
  305. +          */
  306. +         foreach(clause, 
  307. +                 ((Agg *) result_plan)->plan.qual)
  308. +         {
  309. +           /* Make sure there are aggregates in the 
  310. +            * havingQual if so, the list must be 
  311. +            * longer after check_having_qual_for_aggs 
  312. +            */
  313. +           old_length = 
  314. +             length(((Agg *) result_plan)->aggs);                 
  315. +                       
  316. +           ((Agg *) result_plan)->aggs = 
  317. +              nconc(((Agg *) result_plan)->aggs,
  318. +                    check_having_qual_for_aggs(
  319. +                      (Node *) lfirst(clause),
  320. +                      ((Agg *)result_plan)->
  321. +                          plan.lefttree->targetlist,
  322. +                      ((List *) parse->groupClause)));
  323. +           /* Have a look at the length of the returned 
  324. +            * list. If there is no difference, no 
  325. +            * aggregates have been found and that means 
  326. +            * that the Qual belongs to the where clause 
  327. +            */
  328. +           if (((new_length = 
  329. +                 length(((Agg *) result_plan)->aggs))== 
  330. +                 old_length) || (new_length == 0))
  331. +           {
  332. +             elog(ERROR,"This could have been done in a 
  333. +                                      where clause!!");
  334. +             return (Plan *)NIL;
  335. +           }
  336. +         }
  337.                             .
  338.                             .
  339.                             .
  340.   }
  341. end{verbatim}
  342. %
  343. end{itemize}
  344. subsubsection{Executor}
  345. The {it executor} takes the {it queryplan} produced by the {it
  346. planner/optimizer} in the way just described and processes all {it
  347. aggregate functions} in the way described in section ref{aggregates}
  348. {it The Implementation of Aggregate Functions} but before the tuple
  349. derived is handed back the {it operator tree} attached to the field
  350. {tt qpqual} is evaluated by calling the function {tt
  351. ExecQual()}. This function recursively steps through the {it operator
  352. tree} (i.e. the {it having clause}) and evaluates the predicates
  353. appearing there. Thanks to our changes that have been made to the {it
  354. planner} the values of all operands needed to evaluate the predicates
  355. (e.g. the values of all {it aggregate functions}) are already present
  356. and can be accessed throughout the evaluation without any problems.
  357. If the evaluation of the {it having qualification} returns {tt true}
  358. the tuple is returned by the function {tt execAgg()} otherwise it is
  359. ignored and the next group is processed. \
  360. \
  361. The necessary changes and enhancements have been applied to the
  362. following function in the file {tt
  363. $ldots$/src/backend/executor/nodeAgg.c}:
  364. %
  365. begin{itemize}
  366. %
  367. <step> {tt execAgg()}
  368. Whenever the {it executor} gets to an {tt AGG} node this function is
  369. called. Before the {it having logic} had been implemented, all the
  370. {it tuples} of the current group were fetched from the {it
  371. subplan} and all {it aggregate functions} were applied to these
  372. tuples. After that, the results were handed back to the calling
  373. function.
  374. Since the {it having logic} has been implemented there is one
  375. additional step executed. Before the results of applying the {it
  376. aggregate functions} are handed back, the function {tt ExecQual()} is
  377. called with the representation of the {it having clause} as an
  378. argument. If {tt true} is returned, the results are handed back,
  379. otherwise they are ignored and we start from the beginning for the
  380. next group until a group meeting the restrictions given in the {it
  381. having clause} is found.
  382. %
  383. begin{verbatim}
  384.   TupleTableSlot *
  385.   ExecAgg(Agg *node)
  386.   {
  387.                             .
  388.                             .
  389.                             .
  390.         /* We loop retrieving groups until we find one 
  391.          * matching node->plan.qual 
  392.          */
  393. +       do 
  394. +       { 
  395.                             .
  396.                             .
  397.                             .
  398.           /* Apply *all* aggregate function to the 
  399.            * tuples of the *current* group 
  400.            */
  401.                             .
  402.                             .
  403.                             .
  404.           econtext->ecxt_scantuple = 
  405.                    aggstate->csstate.css_ScanTupleSlot;
  406.           resultSlot = ExecProject(projInfo, &isDone);
  407. +         /* As long as the retrieved group does not 
  408. +          * match the qualifications it is ignored and
  409. +          * the next group is fetched 
  410. +          */   
  411. +         if(node->plan.qual != NULL)
  412. +         {
  413. +           qual_result =
  414. +               ExecQual(fix_opids(node->plan.qual),
  415. +                        econtext);
  416. +         }     
  417. +         if (oneTuple) pfree(oneTuple);
  418. +       } 
  419. +       while((node->plan.qual!=NULL) && 
  420. +                               (qual_result!=true));   
  421.         return resultSlot;
  422.   }
  423. end{verbatim}
  424. %
  425. end{itemize}
  426. section{The Realization of Union, Intersect and Except}
  427. label{union_impl}
  428. SQL92 supports the well known set theoretic operations {it union},
  429. {it intersect} and {it set difference} (the {it set difference} is
  430. called {it except} in SQL92). The operators are used to connect two
  431. or more {tt select} statements. Every {tt select} statement returns
  432. a set of tuples and the operators between the {tt select} statements
  433. tell how to merge the returned sets of tuples into one result
  434. relation.
  435. %
  436. begin{example}
  437. label{simple_set_ops}
  438. Let the following tables be given:
  439. %
  440. begin{verbatim}
  441. XXX All these table examples have combinations of "-" and "+" which
  442. causes problems inside an SGML comment. Mess them up to keep this
  443. from happening for now. - thomas 1999-02-10
  444.               A  C1|C2|C3         B  C1|C2|C3
  445.                  MMPMMPMM            MMPMMPMM
  446.                   1| a| b             1| a| b
  447.                   2| a| b             5| a| b
  448.                   3| c| d             3| c| d
  449.                   4| e| f             8| e| f
  450.                          C  C1|C2|C3
  451.                             MMPMMPMM
  452.                              4| e| f
  453.                              8| e| f
  454. end{verbatim}
  455. Now let's have a look at the results of the following queries:
  456. begin{verbatim}
  457.   select * from A
  458.   union
  459.   select * from B;
  460. end{verbatim}
  461. derives the set theoretic {it union} of the two tables:
  462. %
  463. begin{verbatim}
  464.                             C1|C2|C3        
  465.                             MMPMMPMM        
  466.                              1| a| b        
  467.                              2| a| b        
  468.                              3| c| d        
  469.                              4| e| f        
  470.                              5| a| b
  471.                              8| e| f
  472. end{verbatim}
  473. %
  474. The {tt select} statements used may be more complex:
  475. %
  476. begin{verbatim}
  477.   select C1, C3 from A
  478.     where C2 = 'a'
  479.   union
  480.   select C1, C2 from B
  481.     where C3 = 'b';
  482. end{verbatim}
  483. %
  484. noindent will return the following table:
  485. %
  486. begin{verbatim}
  487.                              C1|C3        
  488.                              MMPMM        
  489.                               1| b        
  490.                               2| b        
  491.                               1| a        
  492.                               5| a        
  493. end{verbatim}
  494. %
  495. Note that the selected columns do not need to have identical names,
  496. they only have to be of the same type. In the previous example we
  497. selected for {tt C1} and {tt C3} in the first {tt select} statement
  498. and for {tt C1} and {tt C2} in the second one. The names of the
  499. resulting columns are taken from the first {tt select} statement. \
  500. \
  501. Let's have a look at a query using {tt intersect}:
  502. %
  503. begin{verbatim}
  504.   select * from A
  505.   intersect
  506.   select * from B;
  507. end{verbatim}
  508. %
  509. will return:
  510. begin{verbatim}
  511.                             C1|C2|C3        
  512.                             MMPMMPMM        
  513.                              1| a| b        
  514.                              3| c| d        
  515. end{verbatim}
  516. %
  517. Here is an example using {tt except}:
  518. begin{verbatim}
  519.   select * from A
  520.   except
  521.   select * from B;
  522. end{verbatim}
  523. %
  524. will return:
  525. begin{verbatim}
  526.                             C1|C2|C3        
  527.                             MMPMMPMM        
  528.                              2| a| b
  529.                              4| e| f        
  530. end{verbatim}
  531. %
  532. The last examples were rather simple because they only used one set
  533. operator at a time with only two operands. Now we look at some more
  534. complex queries involving more {it operators}:
  535. %
  536. begin{verbatim}
  537.   select * from A
  538.   union 
  539.   select * from B
  540.   intersect 
  541.   select * from C;
  542. end{verbatim}
  543. %
  544. will return:
  545. %
  546. begin{verbatim}
  547.                             C1|C2|C3        
  548.                             MMPMMPMM        
  549.                              4| e| f
  550.                              8| e| f
  551. end{verbatim}
  552. %
  553. The above query performs the set theoretic computation $(A cup B)
  554. cap C$. When no parentheses are used, the operations are considered to
  555. be left associative, i.e. $A cup B cup C cup D$ will be treated as
  556. $((A cup B) cup C) cup D$. \
  557. \
  558. The same query using parenthesis can lead to a completely different
  559. result:
  560. %
  561. begin{verbatim}
  562.   select * from A
  563.   union 
  564.   (select * from B
  565.    intersect 
  566.    select * from C);
  567. end{verbatim}
  568. %
  569. performs  $A cup (B cap C)$ and will return:
  570. %
  571. begin{verbatim}
  572.                             C1|C2|C3        
  573.                             MMPMMPMM        
  574.                              1| a| b        
  575.                              2| a| b        
  576.                              3| c| d        
  577.                              4| e| f        
  578.                              8| e| f
  579. end{verbatim}
  580. %
  581. end{example}
  582. %
  583. subsection{How Unions have been Realized Until Version 6.3.2}
  584. First we give a description of the implementation of {it union} and
  585. {it union all} until version 6.3.2 because we need it to understand
  586. the implementation of {it intersect} and {it except} described later. \
  587. \
  588. A {it union} query is passed through the usual stages:
  589. %
  590. begin{itemize}
  591. <step> parser
  592. <step> rewrite system
  593. <step> planner/optimizer
  594. <step> executor
  595. end{itemize}
  596. %
  597. and we will now describe what every single stage does to the query.
  598. For our explanation we assume to process a simple query (i.e. a query
  599. without {it subselects}, {it aggregates} and without involving {it views})
  600. subsubsection{The Parser Stage}
  601. As described earlier the {it parser stage} can be divided into two parts:
  602. %
  603. begin{itemize}
  604. <step> the {it parser} built up by the grammar rules given in {tt gram.y}
  605. and
  606. <step> the {it transformation routines} performing a lot of 
  607. changes and analysis to the tree built up by the parser. Most of these
  608. routines reside in {tt analyze.c}.
  609. end{itemize}
  610. %
  611. %pagebreak 
  612. %
  613. A {it union} statement consists of two or more {it select}
  614. statements connected by the keyword {tt union} as the following
  615. example shows:
  616. %
  617. begin{verbatim}
  618.   select * from A 
  619.     where C1=1
  620.   union
  621.   select * from B
  622.     where C2 = 'a'
  623.   union
  624.   select * from C
  625.     where C3 = 'f'
  626. end{verbatim}
  627. %
  628. The above {it union} statement consists of three {it select}
  629. statements connected by the keyword {tt union}. We will refer to the
  630. first {it select} statement by A, to the second one by B and to the
  631.  third one by C for our further explanation (in the new notation our
  632. query looks like this: mbox{{tt A union B union C}}).\
  633. \
  634. The {it parser} (given by {tt gram.y}) processes all three {tt select}
  635. statements, creates a {tt SelectStmt} node for every {tt select} and
  636. attaches the {tt where} qualifications, {it targetlists} etc.  to the
  637. corresponding nodes. Then it creates a list of the second and the
  638. third {tt SelectStmt} node (of B and C) and attaches it to the field
  639. {tt unionClause} of the first node (of A). Finally it hands back the
  640. first node (node A) with the list of the remaining nodes attached as
  641. shown in figure ref{parser_union_back}.
  642. %
  643. begin{figure}
  644. begin{center}
  645. epsfig{figure=figures/parser_union_back.ps}
  646. caption{Data structure handed back by the {it parser}}
  647. label{parser_union_back}
  648. end{center}
  649. end{figure}
  650. \
  651. \
  652. The following {it transformation routines} process the data structure
  653. handed back by the {it parser}. First the top node (node A) is transformed
  654. from a {tt SelectStmt} node to a {tt Query} node.  The {it
  655. targetlist}, the {tt where} qualification etc. attached to it are
  656. transformed as well. Next the list of the remaining nodes (attached to
  657. {tt unionClause} of node A) is transformed and in this step also a
  658. check is made if the types and lengths of the {it targetlists} of
  659. the involved nodes are equal. The new {tt Query} nodes are now handed
  660. back in the same way as the {tt SelectStmt} nodes were before
  661. (i.e. the {tt Query} nodes B and C are collected in a list which is
  662. attached to {tt unionClause} of {tt Query} node A).
  663. subsubsection{The Rewrite System}
  664. If any {it rewrite rules} are present for the {tt Query} nodes
  665. (i.e. one of the {it select} statements uses a {it view}) the
  666. necessary changes to the {tt Query} nodes are performed (see section
  667. ref{view_impl} {it Techniques To Implement Views}). Otherwise no
  668. changes are made to the nodes in this stage.
  669. subsubsection{Planner/Optimizer}
  670. This stage has to create a {it plan} out of the {it querytree}
  671. produced by the {it parser stage} that can be executed by the {it
  672. executor}. In most cases there are several ways (paths) with different
  673. cost to get to the same result. It's the {it planner/optimizer's}
  674. task to find out which path is the cheapest and to create a {it plan}
  675. using this path.  The implementation of {it unions} in <productname>Postgres</productname> is
  676. based on the following idea: \
  677. \
  678. The set derived by evaluating $A cup B$ must contain every member of
  679. $A$ {bf and} every member of $B$. So if we append the members of $B$
  680. to the members of $A$ we are almost done. If there exist members 
  681. common to $A$ and $B$ these members are now contained twice in our new
  682. set, so the only thing left to do is to remove these duplicates. 
  683. pagebreak
  684. noindent In the case of our example the {it planner} would build up the {it
  685. tree} shown in figure ref{union_plan}. Every {tt Query} node is
  686. planned separately and results in a {tt SeqScan} node in our
  687. example. The three {tt SeqScan} nodes are put together into a list
  688. which is attached to {tt unionplans} of an {tt Append} node.
  689. %
  690. begin{figure}[ht]
  691. begin{center}
  692. epsfig{figure=figures/union_plan.ps}
  693. caption{{it Plan} for a union query}
  694. label{union_plan}
  695. end{center}
  696. end{figure}
  697. subsubsection{Executor}
  698. The {it executor} will process all the {tt SeqScan} nodes and append all
  699. the delivered tuples to a single {it result relation}. Now it is
  700. possible that duplicate tuples are contained in the {it result relation}
  701. which have to be removed. The removal is done by the {tt Unique} node
  702. and the sort is just performed to make its work easier.
  703. subsection{How Intersect, Except and Union Work Together}  
  704. The last section showed that every stage ({it parser stage}, {it
  705. planner/optimizer}, {it executor}) of <productname>Postgres</productname> has to provide
  706. features in order to support {it union} statements. For the
  707. implementation of {it intersect} and {it except} statements (and
  708. statements involving all {it set operators}) we choose a different approach
  709. based on {it query rewriting}. \
  710. \
  711. The idea is based on the fact that {it intersect} and {it except}
  712. statements are redundant in SQL, i.e. for every {it intersect} or
  713. {it except} statement it is possible to formulate a semantically
  714. equivalent statement without using {it intersect} or {it except}.
  715. %
  716. begin{example}
  717. label{transform_intersect}
  718. This example shows how a query using {it intersect} can be
  719. transformed to a semantically equivalent query without an {it
  720. intersect}:
  721. %
  722. pagebreak
  723. %
  724. begin{verbatim}
  725.   select C1, C3 from A
  726.   where C1 = 1
  727.   intersect
  728.   select C1, C2 from B
  729.   where C2 = 'c';
  730. end{verbatim}
  731. %
  732. is equivalent to:
  733. %
  734. begin{verbatim}
  735.   select C1, C3
  736.   from A
  737.   where C1 = 1 and
  738.         (C1, C3) in (select C1, C2
  739.                      from B
  740.                      where C2 = 'c');
  741. end{verbatim}
  742. %
  743. This example shows how an {it except} query can be transformed to an
  744. {it except}-less form:
  745. %
  746. begin{verbatim}
  747.   select C1, C2 from A
  748.   where C2 = 'c'
  749.   except
  750.   select C1, C3 from B
  751.   where C3 = 'f';
  752. end{verbatim}
  753. %
  754. is equivalent to:
  755. %
  756. begin{verbatim}
  757.   select C1, C2
  758.   from A
  759.   where C2 = 'c' and
  760.         (C1, C2) not in (select C1, C3
  761.                          from B
  762.                          where C3 = 'f');
  763. end{verbatim}
  764. %
  765. end{example}
  766. %
  767. The transformations used in example ref{transform_intersect} are
  768. always valid because they just implement the set theoretic definition
  769. of {it intersect} and {it except}:
  770. %
  771. begin{definition} 
  772. label{def_intersect}
  773. ~ \
  774. The {it intersection} of two sets $A$ and $B$ is
  775. defined as:
  776. begin{displaymath}
  777. (A cap B) := {x mid x in A wedge x in B }
  778. end{displaymath}
  779. %
  780. The {it intersection} of $n$ sets $A_{1}, ldots, A_{n}$ is defined as:
  781. %
  782. begin{displaymath}
  783. bigcap_{i=1}^{n} A_{i} := {x mid bigwedge_{i=1}^{n} x in A_{i} } 
  784. end{displaymath}
  785. %
  786. end{definition}
  787. %
  788. begin{definition} 
  789. label{def_except}
  790. ~ \
  791. The {it difference} of two sets $A$ and $B$ is
  792. defined as:
  793. begin{displaymath}
  794. (A backslash B) := {x mid x in A wedge x notin B }
  795. end{displaymath}
  796. %
  797. end{definition}
  798. %
  799. begin{definition} 
  800. label{def_union}
  801. ~\
  802. The {it union} of two sets $A$ and $B$ is
  803. defined as:
  804. begin{displaymath}
  805. (A cup B) := {x mid x in A vee x in B }
  806. end{displaymath}
  807. %
  808. The {it union} of $n$ sets $A_{1}, ldots, A_{n}$ is defined as:
  809. %
  810. begin{displaymath}
  811. bigcup_{i=1}^{n} A_{i} := {x mid bigvee_{i=1}^{n} x in A_{i} } 
  812. end{displaymath}
  813. %
  814. end{definition}
  815. begin{definition} Disjunctive Normal Form (DNF) \
  816. Let $F = C_{1} vee ldots vee C_{n}$ be given where every $C_{i}$ is
  817. of the form $(L_{i}^{1} wedge ldots wedge L_{i}^{k_{i}})$ and
  818. $L_{i}^{j}$ is a propositional variable or the negation of a
  819. propositional variable. Now we say $F$ is in DNF.
  820. end{definition}
  821. %
  822. begin{example} In the following example the $L_{i}^{j}$ are of the form
  823. $x in X$ or $neg (x in X)$: \
  824. indent $((x in A wedge neg (x in B) wedge x in C) vee (x in D
  825. wedge x in E))$ is a formula in DNF \
  826. indent $((x in A vee x in B) wedge (x in C vee neg (x in D)))$
  827. is not in DNF.
  828. end{example}
  829. %
  830. The transformation of any formula in propositional logic into DNF is done by
  831. successively applying the following rules: \
  832. \
  833. indent $(R1)~~neg (F_{1} vee F_{2}) Rightarrow (neg F_{1} wedge neg
  834. F_{2})$ \
  835. indent $(R2)~~neg (F_{1} wedge F_{2}) Rightarrow (neg F_{1} vee neg
  836. F_{2})$ \
  837. indent $(R3)~~F_{1} wedge (F_{2} vee F_{3}) Rightarrow (F_{1} wedge
  838. F_{2}) vee (F_{1} wedge F_{3})$ \
  839. indent $(R4)~~(F_{1} vee F_{2}) wedge F_{3} Rightarrow (F_{1} wedge
  840. F_{3}) vee (F_{2} wedge F_{3})$ \
  841. \
  842. It can be shown that the transformation using the rules (R1) to
  843. (R4) always terminates after a finite number of steps.
  844. subsubsection{Set Operations as Propositional Logic Formulas}
  845. Using the definitions from above we can treat formulas
  846. involving set theoretic operations as formulas of {it propositional
  847. logic}. As we will see later these formulas can easily be used in the
  848. {tt where-} and {tt having} qualifications of the {tt select}
  849. statements involved in the query.
  850. %
  851. begin{example}
  852. Here are some examples: \ \
  853. %
  854. indent $((A cup B) cap C) := {x mid (x in A vee x in B) wedge x in C
  855. }$ \
  856. indent $((A cup B) cap (C cup D)) := {x mid (x in A vee x in B)
  857. wedge (x in C vee x in D) }$ \
  858. indent $((A cap B) backslash C) := {x mid (x in A wedge x in
  859. B) wedge x notin C }$ \
  860. indent $(A backslash (B cup C)) := {x mid x in A wedge neg (x
  861. in B vee x in C) }$ \
  862. indent $(((A cap B) cup (C backslash D)) cap E) := {((x in A
  863. wedge x in B) vee (x in C wedge x notin D)) wedge x in E }$
  864. %
  865. end{example}
  866. %
  867. subsection{Implementing Intersect and Except Using the
  868. Union Capabilities}
  869. %
  870. We want to be able to use queries involving more than just one type of
  871. set operation (e.g. only {it union} or only {it intersect}) at a
  872. time, so we have to look for a solution that supports correct handling
  873. of queries like that. As described above there is a solution for pure
  874. {it union} statements implemented already, so we have to develop an
  875. approach that makes use of these {it union} capabilities. \
  876. \
  877. As figure ref{parser_union_back} illustrates, the operands of a {it
  878. union} operation are just {tt Query} nodes (the first operand is the
  879. top node and all further operands form a list which is attached to the
  880. field {tt unionClause} of the top node). So our goal will be to
  881. transform every query involving set operations into this form. (Note
  882. that the operands to the {it union} operation may be complex,
  883. i.e. {it subselects}, {it grouping}, {it aggregates} etc. are allowed.)
  884. The transformation of a query involving set operations in any order
  885. into a query that can be accepted by the {it union} logic is
  886. equivalent to transforming the {it membership formula} (see
  887. definitions ref{def_intersect}, ref{def_except} and ref{def_union})
  888. in propositional logic into {it disjunctive normal form} (DNF). The
  889. transformation of any formula in propositional logic into DNF is
  890. always possible in a finite number of steps.
  891. noindent The advantage of this {it transformation technique} is the little
  892. impact on the whole system and the implicit invocation of the {it
  893. planner/optimizer}. The only changes necessary are made to the {it
  894. parser stage} and the {it rewrite system}. \
  895. \
  896. Here are some changes that had to be applied to the source code before
  897. the {it parser stage} and the {it rewrite system} could be adapted:
  898. %
  899. begin{itemize}
  900. <step> Add the additional field {tt intersectClause} to the data
  901. structures {tt Query} and {tt InsertStmt} defined in the file {tt
  902. $ldots$/src/include/nodes/parsenodes.h}:
  903. %
  904. begin{verbatim}
  905.   typedef struct Query
  906.   {
  907.     NodeTag    type;
  908.     CmdType    commandType;   
  909.             .
  910.             .
  911.             .
  912.     Node       *havingQual;
  913. +   List       *intersectClause;    
  914.     List       *unionClause;       
  915.     List       *base_relation_list_;
  916.     List       *join_relation_list_;
  917.   } Query;
  918.   typedef struct InsertStmt
  919.   {
  920.     NodeTag    type;
  921.             .
  922.             .
  923.             .
  924.     bool       unionall;      
  925. +   List       *intersectClause;  
  926.   } InsertStmt;
  927. end{verbatim}
  928. %
  929. <step> Add the new keywords {tt EXCEPT} and {tt INTERSECT} to the
  930. file {tt $ldots$/src/backend/parser/keywords.c}:
  931. %
  932. begin{verbatim}
  933.   static ScanKeyword ScanKeywords[] = {
  934.     {"abort", ABORT_TRANS},
  935.     {"action", ACTION},
  936.               .
  937.               .
  938.               .     
  939.     {"end", END_TRANS},
  940. +   {"except", EXCEPT},
  941.               .
  942.               .
  943.               .     
  944.     {"instead", INSTEAD},
  945. +   {"intersect", INTERSECT},
  946.               .
  947.               .
  948.               .     
  949.   };
  950. end{verbatim}
  951. %
  952. <step> <productname>Postgres</productname> contains functions to convert the internal
  953. representation of a {it parsetree} or {it plantree} into an ASCII
  954. representation (that can easily be printed to the screen (for
  955. debugging purposes) or be stored in a file) and vice versa. These
  956. functions have to be adapted to be able to deal with {it intersects}
  957. and {it excepts}. These functions can be found in the files {tt
  958. $ldots$/src/backend/nodes/outfuncs.c} and {tt
  959. $ldots$/src/backend/nodes/readfuncs.c}:
  960. %
  961. begin{verbatim}
  962.   static void
  963.   _outQuery(StringInfo str, Query *node)
  964.   {
  965.                             .
  966.                             .
  967.                             .
  968.     appendStringInfo(str, " :unionClause ");
  969.     _outNode(str, node->unionClause);
  970. +   appendStringInfo(str, " :intersectClause ");
  971. +   _outNode(str, node->intersectClause);
  972.   }
  973.   static Query *
  974.   _readQuery()
  975.   {
  976.                             .
  977.                             .
  978.                             .
  979.     token = lsptok(NULL, &length);
  980.     local_node->unionClause = nodeRead(true);
  981. +   token = lsptok(NULL, &length);
  982. +   local_node->intersectClause = nodeRead(true);
  983.     return (local_node);
  984.   }
  985. end{verbatim}
  986. %
  987. <step> The function {tt ExecReScan()} is called whenever a new
  988. execution of a given {it plan} has to be started (i.e. whenever we
  989. have to start from the beginning with the first tuple again). The call
  990. to this function happens implicitly. For the special kind of
  991. subqueries we are using for the rewritten queries (see example
  992. ref{transform_intersect}) we have to take that also 
  993. {tt Group} nodes are processed. The function can be found in the file
  994. {tt $ldots$/backend/executor/execAmi.c}.
  995. %
  996. begin{verbatim}
  997.   void
  998.   ExecReScan(Plan *node, ExprContext *exprCtxt, 
  999.              Plan *parent)
  1000.   {
  1001.                             .
  1002.                             .
  1003.                             .
  1004.      switch (nodeTag(node))
  1005.      {
  1006.                             .
  1007.                             .
  1008.                             .
  1009. end{verbatim}
  1010. pagebreak
  1011. begin{verbatim}
  1012. +      case T_Group:
  1013. +             ExecReScanGroup((Group *) node, 
  1014. +                              exprCtxt, parent);
  1015. +             break;
  1016.                             .
  1017.                             .
  1018.                             .
  1019.      }
  1020.   }
  1021. end{verbatim}
  1022. %
  1023. <step> The function {tt ExecReScanGroup()} is called by {tt
  1024. ExecReScan()} described above whenever a {tt Group} node is detected
  1025. and can be found in the file {tt
  1026. $ldots$/src/backend/executor/nodeGroup.c} . It has been created for
  1027. the {it intersect} and {it except} logic although it is actually
  1028. needed by the special kind of subselect (see above).
  1029. %
  1030. begin{verbatim}
  1031.   void
  1032.   ExecReScanGroup(Group *node, ExprContext *exprCtxt, 
  1033.                   Plan *parent)
  1034.   {
  1035.     GroupState *grpstate = node->grpstate;
  1036.   
  1037.     grpstate->grp_useFirstTuple = FALSE;
  1038.     grpstate->grp_done = FALSE;
  1039.     grpstate->grp_firstTuple = (HeapTupleData *)NIL;
  1040.   
  1041.     /*
  1042.      * if chgParam of subnode is not null then plan 
  1043.      * will be re-scanned by first ExecProcNode.
  1044.      */
  1045.     if (((Plan *) node)->lefttree->chgParam == NULL)
  1046.       ExecReScan(((Plan *) node)->lefttree, 
  1047.                  exprCtxt, (Plan *) node);
  1048.   }
  1049. end{verbatim}
  1050. %
  1051. end{itemize}
  1052. subsubsection{Parser}
  1053. The {it parser} defined in the file {tt
  1054. $ldots$/src/backend/parser/gram.y} had to be modified in two ways:
  1055. %
  1056. begin{itemize}
  1057. %
  1058. <step> The grammar had to be adapted to support the usage of
  1059. parenthesis (to be able to specify the order of execution of the set
  1060. operators). 
  1061. %
  1062. <step> The code building up the data structures handed back by the
  1063. {it parser} had to be inserted.
  1064. %
  1065. end{itemize}
  1066. %
  1067. Here is a part of the grammar which is responsible for {tt select}
  1068. statements having the code building up the data structures inserted:
  1069. %
  1070. pagebreak
  1071. %
  1072. begin{verbatim}
  1073.   SelectStmt :  select_w_o_sort sort_clause
  1074.       {
  1075.                             .
  1076.                             .
  1077.                             .
  1078.          /* $1 holds the tree built up by the
  1079.           * rule 'select_w_o_sort'
  1080.           */
  1081.          Node *op = (Node *) $1;
  1082.          if IsA($1, SelectStmt) 
  1083.          {
  1084.            SelectStmt *n = (SelectStmt *)$1;
  1085.            n->sortClause = $2;
  1086.            $$ = (Node *)n;
  1087.          }
  1088.          else
  1089.          {
  1090.            /* Create a "flat list" of the operator
  1091.             * tree built up by 'select_w_o_sort' and
  1092.             * let select_list point to it 
  1093.             */
  1094.            create_select_list((Node *)op, 
  1095.                               &select_list, 
  1096.                               &unionall_present);
  1097.            /* Replace all the A_Expr nodes in the 
  1098.             * operator tree by Expr nodes.
  1099.             */
  1100.             op = A_Expr_to_Expr(op, &intersect_present);
  1101.                             .
  1102.                             .
  1103.                             .
  1104.             /* Get the leftmost SelectStmt node (which 
  1105.              * automatically represents the first Select 
  1106.              * Statement of the query!) */
  1107.             first_select = 
  1108.                    (SelectStmt *)lfirst(select_list);
  1109.             /* Attach the list of all SelectStmt nodes 
  1110.              * to unionClause 
  1111.              */
  1112.             first_select->unionClause = select_list;
  1113.             /* Attach the whole operator tree to 
  1114.              * intersectClause */
  1115.             first_select->intersectClause = 
  1116.                                          (List *) op;
  1117.             /* finally attach the sort clause */
  1118.             first_select->sortClause = $2;
  1119.   
  1120.             /* Now hand it back! */
  1121.             $$ = (Node *)first_select;
  1122.           }               
  1123.       }
  1124.   ; 
  1125. end{verbatim}
  1126. pagebreak
  1127. begin{verbatim}
  1128.   select_w_o_sort :  '(' select_w_o_sort ')'
  1129.       {
  1130.         $$ = $2; 
  1131.       }
  1132.   |  SubSelect
  1133.       {
  1134.         $$ = $1; 
  1135.       }
  1136.   |  select_w_o_sort EXCEPT select_w_o_sort
  1137.       {
  1138.         $$ = (Node *)makeA_Expr(AND,NULL,$1,
  1139.                          makeA_Expr(NOT,NULL,NULL,$3));
  1140.       }
  1141.   |  select_w_o_sort UNION opt_union select_w_o_sort
  1142.       {       
  1143.         if (IsA($4, SelectStmt))
  1144.         {
  1145.           SelectStmt *n = (SelectStmt *)$4;
  1146.           n->unionall = $3;
  1147.         }
  1148.         $$ = (Node *)makeA_Expr(OR,NULL,$1,$4);
  1149.       }
  1150.   |  select_w_o_sort INTERSECT select_w_o_sort
  1151.       {
  1152.         $$ = (Node *)makeA_Expr(AND,NULL,$1,$3);
  1153.       }
  1154.   ; 
  1155. end{verbatim}
  1156. % pagebreak
  1157. begin{verbatim}
  1158.   SubSelect :  SELECT opt_unique res_target_list2
  1159.                result from_clause where_clause
  1160.                group_clause having_clause
  1161.     {
  1162.       SelectStmt *n = makeNode(SelectStmt);
  1163.       n->unique = $2;
  1164.               .
  1165.               .
  1166.               .
  1167.       n->havingClause = $8;
  1168.       $$ = (Node *)n;
  1169.     }
  1170.   ;
  1171. end{verbatim}
  1172. %
  1173. The keywords {tt SELECT}, {tt EXCEPT}, {tt UNION}, {tt INTERSECT}, {tt
  1174. '('} and {tt ')'} are {it terminal symbols} and {tt SelectStmt},
  1175. {tt select_w_o_sort}, {tt sort_clause}, {tt opt_union}, {tt
  1176. SubSelect}, {tt opt_unique}, {tt res_target_list2}, {tt result},
  1177. {tt from_clause}, {tt where_clause}, {tt group_clause}, {tt
  1178. having_clause} are {it nonterminal symbols}. The symbols {tt
  1179. EXCEPT}, {tt UNION} and {tt INTERSECT} are {it left
  1180. associative} meaning that a statement like:
  1181. %
  1182. begin{verbatim}
  1183.   select * from A
  1184.   union 
  1185.   select * from B
  1186.   union
  1187.   select * from C;
  1188. end{verbatim}
  1189. %
  1190. pagebreak
  1191. will be treated as:
  1192. %
  1193. begin{verbatim}
  1194.   ((select * from A
  1195.     union
  1196.     select * from B)
  1197.     union
  1198.     select * from C)
  1199. end{verbatim}
  1200. %
  1201. The {tt select_w_o_sort} rule builds up an {it operator tree}
  1202. using nodes of type {tt A_Expr}. For every {it union} an {tt OR}
  1203. node is created, for every {it intersect} an {tt AND} node and for
  1204. every {it except} and {tt AND NOT} node building up a representation
  1205. of a formula in propositional logic. If the query parsed did not
  1206. contain any set operations the rule hands back a {tt SelectStmt} node
  1207. representing the query otherwise the top node of the {it operator
  1208. tree} is returned. Figure
  1209. ref{union_intersect_select_w_o_sort} shows a typical {it operator tree}
  1210. returned by the {tt select_w_o_sort} rule.
  1211. begin{figure}[ht]
  1212. begin{flushright}
  1213. epsfig{figure=figures/union_intersect_select_w_o_sort.ps}
  1214. caption{{it Operator tree} for $(A cup B) backslash (C cap D)$}
  1215. label{union_intersect_select_w_o_sort}
  1216. end{flushright}
  1217. end{figure}
  1218. noindent The rule {tt SelectStmt} transforms the {it operator tree} built of
  1219. {tt A_Expr} nodes into an {it operator tree} using {tt Expr} nodes
  1220. by a call to the function {tt A_Expr_to_Expr()} which additionally
  1221. replaces every {tt OR} node by an {tt AND} node and vice
  1222. versa. This is performed in order to be able to use the function {tt
  1223. cnfify()} later on. \
  1224. \
  1225. The {it transformations} following the {it parser} expect a {tt
  1226. SelectStmt} node to be returned by the rule {tt SelectStmt} and not
  1227. an {it operator tree}.  So if the rule {tt select_w_o_sort} hands
  1228. back such a node (meaning that the query did not contain any set
  1229. operations) we just have to attach the data structure built up by the
  1230. {tt sort_clause} rule and are finished, but when we get an {it
  1231. operator tree} we have to perform the following steps:
  1232. %
  1233. begin{itemize}
  1234. %
  1235. <step> Create a flat list of all {tt SelectStmt} nodes of the {it
  1236. operator tree} (by a call to the function {tt create_select_list()})
  1237. and attach the list to the field
  1238. mbox{{tt unionClause}} of the leftmost {tt SelectStmt} (see next step).
  1239. %
  1240. <step> Find the leftmost leaf ({tt SelectStmt} node) of the {it operator
  1241. tree} (this is automatically the first member of the above created
  1242. list because of the technique {tt create_select_list()} uses to
  1243. create the list).
  1244. %
  1245. <step> Attach the whole {it operator tree} (including the leftmost node
  1246. itself) to the field mbox{{tt intersectClause}} of the leftmost {tt
  1247. SelectStmt} node.
  1248. %
  1249. <step> Attach the data structure built up by the {tt sort_clause}
  1250. rule to the field {tt sortClause} of the leftmost {tt SelectStmt} node.
  1251. %
  1252. <step> Hand back the leftmost {tt SelectStmt} node (with
  1253. the {it operator tree}, the list of all {tt SelectStmt} nodes and the {tt
  1254. sortClause} attached to it).
  1255. %
  1256. end{itemize}
  1257. %
  1258. noindent Figure ref{union_intersect_select} shows the final data structure
  1259. derived from the {it operator tree} shown in figure
  1260. ref{union_intersect_select_w_o_sort} handed back by the {tt SelectStmt} rule:
  1261. %
  1262. begin{figure}[ht]
  1263. begin{flushright}
  1264. epsfig{figure=figures/union_intersect_select.ps}
  1265. caption{Data structure handed back by {tt SelectStmt} rule}
  1266. label{union_intersect_select}
  1267. end{flushright}
  1268. end{figure}
  1269. pagebreak
  1270. noindent Here is a description of the above used functions. They can
  1271. be found in the file {tt $ldots$/src/backend/parser/anlayze.c}.
  1272. %
  1273. begin{itemize}
  1274. %
  1275. <step> {tt create_select_list()}: \
  1276. This function steps through the {it tree} handed to it by the
  1277. parameter {tt ptr} and creates a list of all {tt SelectStmt} nodes
  1278. found. The list is handed back by the parameter {tt
  1279. select_list}. The function uses a recursive {it depth first search}
  1280. algorithm to examine the {it tree} leading to the fact that the
  1281. leftmost {tt SelectStmt} node will appear first in the created list.
  1282. %
  1283. begin{verbatim}
  1284.   void 
  1285.   create_select_list(Node *ptr, List **select_list, 
  1286.                      bool *unionall_present)
  1287.   {
  1288.     if(IsA(ptr, SelectStmt)) 
  1289.     {
  1290.       *select_list = lappend(*select_list, ptr);    
  1291.       if(((SelectStmt *)ptr)->unionall == TRUE) 
  1292.         *unionall_present = TRUE;    
  1293.       return;    
  1294.     }
  1295.   
  1296.     /* Recursively call for all arguments. 
  1297.      * A NOT expr has no lexpr! 
  1298.      */
  1299.     if (((A_Expr *)ptr)->lexpr != NULL) 
  1300.       create_select_list(((A_Expr *)ptr)->lexpr, 
  1301.                        select_list, unionall_present);
  1302.     create_select_list(((A_Expr *)ptr)->rexpr, 
  1303.                        select_list, unionall_present);
  1304. }
  1305. end{verbatim}
  1306. %
  1307. <step> {tt A_Expr_to_Expr()}: \
  1308. This function recursively steps through the {it operator tree} handed
  1309. to it by the parameter {tt ptr} and replaces {tt A_Expr} nodes by
  1310. {tt Expr} nodes. Additionally it exchanges {tt AND} nodes with {tt
  1311. OR} nodes and vice versa.  The reason for this exchange is easy to
  1312. understand. We implement {it intersect} and {it except} clauses by
  1313. rewriting these queries to semantically equivalent queries that use
  1314. {tt IN} and {tt NOT IN} subselects. To be able to use all three
  1315. operations ({it unions}, {it intersects} and {it excepts}) in one
  1316. complex query, we have to translate the queries into {it Disjunctive
  1317. Normal Form} (DNF). Unfortunately there is no function {tt dnfify()},
  1318. but there is a function {tt cnfify()} which produces DNF when we
  1319. exchange {tt AND} nodes with {tt OR} nodes and vice versa before
  1320. calling {tt cnfify()} and exchange them again in the result.  
  1321. %
  1322. begin{verbatim}
  1323.   Node *
  1324.   A_Expr_to_Expr(Node *ptr, 
  1325.                  bool *intersect_present)
  1326.   {
  1327.     Node *result;
  1328.   
  1329.     switch(nodeTag(ptr))
  1330.     {
  1331.       case T_A_Expr:
  1332.       {
  1333.         A_Expr *a = (A_Expr *)ptr;
  1334.         
  1335.         switch (a->oper)
  1336.         {
  1337.           case AND:
  1338.           {
  1339.             Expr *expr = makeNode(Expr);
  1340.             Node *lexpr = 
  1341.                A_Expr_to_Expr(((A_Expr *)ptr)->lexpr, 
  1342.                               intersect_present);
  1343.             Node *rexpr = 
  1344.                A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, 
  1345.                               intersect_present);
  1346.             *intersect_present = TRUE;
  1347.               
  1348.             expr->typeOid = BOOLOID;
  1349.             expr->opType = OR_EXPR;
  1350.             expr->args = makeList(lexpr, rexpr, -1);
  1351.             result = (Node *) expr;
  1352.             break;            
  1353.           }               
  1354.           case OR:
  1355.           {
  1356.             Expr *expr = makeNode(Expr);
  1357.             Node *lexpr = 
  1358.                A_Expr_to_Expr(((A_Expr *)ptr)->lexpr, 
  1359.                               intersect_present);
  1360.             Node *rexpr = 
  1361.                A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, 
  1362.                               intersect_present);
  1363.             expr->typeOid = BOOLOID;
  1364.             expr->opType = AND_EXPR;
  1365.             expr->args = makeList(lexpr, rexpr, -1);
  1366.             result = (Node *) expr;
  1367.             break;            
  1368.           }
  1369.           case NOT:
  1370.           {
  1371.             Expr *expr = makeNode(Expr);
  1372.             Node *rexpr = 
  1373.                A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, 
  1374.                               intersect_present);
  1375.             expr->typeOid = BOOLOID;
  1376.             expr->opType = NOT_EXPR;
  1377.             expr->args = makeList(rexpr, -1);
  1378.             result = (Node *) expr;
  1379.             break;            
  1380.           }
  1381.         }       
  1382.         break;  
  1383.       }
  1384.       default:
  1385.       {
  1386.         result = ptr;
  1387.       }      
  1388.     }
  1389.   }
  1390.   return result;  
  1391. }
  1392. end{verbatim}
  1393. %
  1394. end{itemize}
  1395. noindent Note that the {tt stmtmulti} and {tt OptStmtMulti} rules had to be
  1396. changed in order to avoid {it shift/reduce} conflicts. The old rules
  1397. allowed an invalid syntax (e.g. the concatenation of two statements
  1398. without a ';' inbetween) which will be prevented now. The new rules
  1399. have the second line commented out as shown below:
  1400. %
  1401. begin{verbatim}  
  1402.   stmtmulti       :  stmtmulti stmt ';'
  1403.                /* |  stmtmulti stmt */
  1404.                   |  stmt ';'
  1405.                   ;
  1406.   OptStmtMulti    :  OptStmtMulti OptimizableStmt ';'
  1407.                /* |  OptStmtMulti OptimizableStmt */
  1408.                   |  OptimizableStmt ';'
  1409.                   ;
  1410. end{verbatim}
  1411. %
  1412. subsubsection{Transformations}
  1413. This step normally transforms every {tt SelectStmt} node found into a
  1414. {tt Query} node and does a lot of transformations to the {it targetlist},
  1415. the {tt where} qualification etc. As mentioned above this stage
  1416. expects a {tt SelectStmt} node and cannot handle an {tt A_Expr}
  1417. node. That's why we did the changes to the {it operator tree} shown in
  1418. figure ref{union_intersect_select}. \
  1419. \
  1420. In this stage only very few changes have been necessary: 
  1421. %
  1422. begin{itemize}
  1423. <step> The transformation of the list attached to {tt unionClause} is
  1424. prevented. The raw list is now passed through instead and the necessary
  1425. transformations are performed at a later point in time.
  1426. <step> The additionally introduced field {tt intersectClause} is also
  1427. passed untouched through this stage.
  1428. end{itemize}   
  1429. noindent The changes described in the above paragraph have been
  1430. applied to the functions {tt transformInsertStmt()} and {tt
  1431. transformSelectStmt()} which are contained in the file {tt
  1432. $ldots$/src/backend/parser/analyze.c}:
  1433. %
  1434. begin{itemize}
  1435. %
  1436. <step> {tt transformInsertStmt()}:
  1437. %
  1438. begin{verbatim}
  1439.   static Query *
  1440.   transformInsertStmt(ParseState *pstate, 
  1441.                       InsertStmt *stmt)
  1442.   {
  1443.                             .
  1444.                             .
  1445.                             .
  1446. end{verbatim}
  1447. pagebreak
  1448. begin{verbatim}
  1449.     /* Just pass through the unionClause and 
  1450.      * intersectClause. We will process it in 
  1451.      * the function Except_Intersect_Rewrite() 
  1452.      */
  1453.     qry->unionClause = stmt->unionClause;
  1454.     qry->intersectClause = stmt->intersectClause;
  1455.                             .
  1456.                             .
  1457.                             .
  1458.     return (Query *) qry;
  1459.   }
  1460. end{verbatim}
  1461. %
  1462. <step> {tt transformSelectStmt()}:
  1463. %
  1464. begin{verbatim}
  1465.   static Query *
  1466.   transformSelectStmt(ParseState *pstate, 
  1467.                       SelectStmt *stmt)
  1468.   {
  1469.                             .
  1470.                             .
  1471.                             .
  1472.     /* Just pass through the unionClause and 
  1473.      * intersectClause. We will process it in 
  1474.      * the function Except_Intersect_Rewrite() 
  1475.      */
  1476.     qry->unionClause = stmt->unionClause;
  1477.     qry->intersectClause = stmt->intersectClause;
  1478.                             .
  1479.                             .
  1480.                             .
  1481.     return (Query *) qry;
  1482.   }
  1483. end{verbatim}
  1484. %
  1485. end{itemize}
  1486. subsubsection{The Rewrite System}
  1487. In this stage the information contained in the {it operator tree} attached
  1488. to the topmost {tt SelectStmt} node is used to form a tree of {tt
  1489. Query} nodes representing the rewritten query (i.e. the semantically
  1490. equivalent query that contains only {it union} but no {it intersect}
  1491. or {it except} operations). \
  1492. \
  1493. The following steps have to be performed:
  1494. %
  1495. begin{itemize}
  1496. <step> Save the {tt sortClause}, {tt uniqueFlag}, {tt targetList}
  1497. fields etc. of the topmost {tt Query} node because the topmost node
  1498. may change during the rewrite process (remember (only) the topmost
  1499. {tt SelectStmt} node has already been transformed to a {tt Query}
  1500. node).
  1501. %
  1502. <step> Recursively step through the {it operator tree} and transform 
  1503. every {tt SelectStmt} node to a {tt Query} node using the function
  1504. {tt intersect_tree_analyze()} described below. The one node already
  1505. transformed (the topmost node) is still contained in the {it operator
  1506. tree} and must not be transformed again because this would cause
  1507. troubles in the {it transforming logic}.
  1508. %
  1509. begin{figure}[ht]
  1510. begin{center}
  1511. epsfig{figure=figures/union_intersect_dnf.ps}
  1512. caption{Data structure of $(A cup B) backslash C$  after transformation to DNF}
  1513. label{union_intersect_dnf}
  1514. end{center}
  1515. end{figure}
  1516. %
  1517. <step> Transform the new {it operator tree} into DNF (disjunctive normal
  1518. form). <productname>Postgres</productname> does not provide any function for the transformation
  1519. into DNF but it provides a function {tt cnfify()} that performs a
  1520. transformation into CNF (conjunctive normal form). So we can easily
  1521. make use of this function when we exchange every {tt OR} with an {tt
  1522. AND} and vice versa before calling {tt cnfify()} as we did already in
  1523. the {it parser} (compare figure ref{union_intersect_select_w_o_sort}
  1524. to figure ref{union_intersect_select}). When {tt cnfify()} is called
  1525. with a special flag, the {tt removeAndFlag} set to {tt true} it
  1526. returns a list where the entries can be thought of being connected
  1527. together by {tt ANDs}, so the explicit {tt AND} nodes are removed.
  1528. After {tt cnfify()} has been called we normally would have to
  1529. exchange {tt OR} and {tt AND} nodes again. We skip this step by
  1530. simply treating every {tt OR} node as an {tt AND} node throughout
  1531. the following steps (remember, that there are no {tt AND} nodes left
  1532. that have to be treated as {tt OR} nodes because of the {tt
  1533. removeAndFlag}).
  1534. noindent Figure ref{union_intersect_dnf} shows what the data
  1535. structure looks like after the transformation to DNF has taken place
  1536. for the following query:
  1537. %
  1538. begin{verbatim}
  1539.   (select * from A
  1540.    union
  1541.    select * from B)
  1542.    except
  1543.    select * from C;
  1544. end{verbatim}
  1545. %
  1546. <step> For every entry of the list returned by {tt cnfify()} (i.e. for every  
  1547. {it operator tree} which may only contain {tt OR} and {tt NOT}
  1548. operator nodes and {tt Query} nodes as leaves) contained in the {tt
  1549. union_list} perform the following steps:
  1550. %
  1551. begin{itemize}
  1552. %
  1553. <step> Check if the {it targetlists} of all {tt Query} nodes appearing are
  1554. compatible (i.e. all {it targetlists} have the same number of attributes
  1555. and the corresponding attributes are of the same type)
  1556. %
  1557. <step> There must be at least one positive {tt
  1558. OR} node (i.e. at least one {tt OR} node which is not preceded by a
  1559. {tt NOT} node). Create a list of all {tt Query} nodes (or of {tt
  1560. Query} nodes preceded by {tt NOT} nodes if {tt OR NOT} is found)
  1561. with the non negated node first using the function {tt
  1562. create_list()} described below.
  1563. %
  1564. <step> The first (non negated) node of the list will be the topmost   
  1565. {tt Query} node of the current {it union} operand. For all other
  1566. nodes found in the list add an {tt IN} subselect ({tt NOT IN}
  1567. subselect if the {tt Query} node is preceded by a {tt NOT}) to the
  1568. {tt where} qualification of the topmost node. Adding a
  1569. subselect to the {tt where} qualification is done by logically
  1570. {tt AND}ing it to the original qualification. 
  1571. %
  1572. <step> Append the {tt Query} node setup in the last steps to a list which
  1573. is hold by the pointer {tt union_list}.
  1574. end{itemize}
  1575. %
  1576. <step> Take the first node of {tt union_list} as the new topmost node
  1577. of the whole query and attach the rest of  the list to the
  1578. field {tt unionClause} of this topmost node. Since the new topmost
  1579. node might differ from the original one (i.e. from the node which was
  1580. topmost when we entered the {it rewrite stage}) we have to attach the
  1581. fields saved in the first step to the new topmost node (i.e. the {tt
  1582. sortClause}, {tt targetList}, {tt unionFlag}, etc.).
  1583. %
  1584. <step> Hand the new topmost {tt Query} node back. Now the normal
  1585. {it query rewriting} takes place (in order to handle views if
  1586. present) and then the {it planner/optimizer} and {it executor}
  1587. functions are called to get a result. There have no changes been made
  1588. to the code of these stages.
  1589. %
  1590. end{itemize}
  1591. Figure ref{union_operand} shows the rewritten data structure of the
  1592. query:
  1593. begin{verbatim}
  1594.    select C1, C2 from A
  1595.    intersect
  1596.    select C1, C3 from C;
  1597. end{verbatim}
  1598. %
  1599. % clearpage
  1600. %
  1601. noindent against the tables defined in example ref{simple_set_ops}.
  1602. The rewritten data structure represents the query:
  1603. begin{verbatim}
  1604.   select C1, C2 form A
  1605.   where (C1, C2) in 
  1606.         (select C1,C3 from C);
  1607. end{verbatim}
  1608. %
  1609. noindent The field {tt lefttree} of the {tt Sublink} node points to a list
  1610. where every entry points to a {tt VAR} node of the {it targetlist} of the
  1611. topmost node (node A). The field {tt oper} of the {tt Sublink} node
  1612. points to a list holding a pointer to an {tt Expr} node for every
  1613. attribute of the topmost {it targetlist}. Every {tt Expr} node is used to
  1614. compare a {tt VAR} node of the topmost {it targetlist} with the
  1615. corresponding {tt VAR} node of the subselect's {it targetlist}. So the
  1616. first argument of every {tt Expr} node points to a {tt VAR} node of
  1617. the topmost {it targetlist} and the second argument points to the
  1618. corresponding {tt VAR} node of the subselect's {it targetlist}.
  1619. %
  1620. begin{figure}[ht]
  1621. begin{flushright}
  1622. epsfig{figure=figures/union_operand.ps}
  1623. caption{Data structure of $A cap C$ after query rewriting}
  1624. label{union_operand}
  1625. end{flushright}
  1626. end{figure}
  1627. %
  1628. clearpage
  1629. %
  1630. noindent If the user's query involves {it union} as well as {it
  1631. intersect} or {it except} there will be more {tt Query} nodes of the
  1632. form shown in figure ref{union_operand}. One will be the topmost node
  1633. (as described above) and the others will be collected in a list which
  1634. is attached to the field {tt unionClause} of the topmost node. (The
  1635. {it intersectClause} fields of all {tt Query} nodes will be set to
  1636. {tt NULL} because they are no longer needed.) \
  1637. \
  1638. %
  1639. The function {tt pg_parse_and_plan()} is responsible for invoking the
  1640. rewrite procedure. It can be found in the file {tt
  1641. $ldots$/src/backend/tcop/postgres.c}.
  1642. %
  1643. begin{verbatim}
  1644.   List *
  1645.   pg_parse_and_plan(char *query_string, Oid *typev,
  1646.                     int nargs, 
  1647.                     List **queryListP,
  1648.                     CommandDest dest) 
  1649.   {
  1650.                             .
  1651.                             .
  1652.                             .
  1653.     /* Rewrite Union, Intersect and Except Queries
  1654.      * to normal Union Queries using IN and NOT 
  1655.      * IN subselects */
  1656.     if(querytree->intersectClause != NIL) 
  1657.     {       
  1658.       querytree = Except_Intersect_Rewrite(querytree);
  1659.     }
  1660.                             .
  1661.                             .
  1662.                             .
  1663.   }
  1664. end{verbatim}
  1665. %
  1666. Here are the functions that have been added to perform the
  1667. functionality described above. They can be found in the file {tt
  1668. $ldots$/src/backend/rewrite/rewriteHandler.c}.
  1669. %
  1670. begin{itemize}
  1671. <step> {tt Except_Intersect_Rewrite()} \
  1672. Rewrites queries involving {it union clauses}, {it intersect
  1673. clauses} and {it except clauses} to semantiacally equivalent queries
  1674. that use {tt IN} and {tt NOT IN} subselects instead.
  1675. The {it operator tree} is attached to {tt intersectClause} (see rule
  1676. {tt SelectStmt} above) of the {it parsetree} given as an
  1677. argument. First we save some clauses (the {tt sortClause}, the {tt
  1678. unique flag} etc.).  Then we translate the {it operator tree} to DNF
  1679. ({it Disjunctive Normal Form}) by {tt cnfify()}. Note that {tt
  1680. cnfify()} produces CNF but as we exchanged {tt AND} nodes with {tt
  1681. OR} nodes within function {tt A_Expr_to_Expr()} earlier we get DNF
  1682. when we exchange {tt AND} nodes and {tt OR} nodes again in the
  1683. result. Now we create a new (rewritten) query by examining the new
  1684. {it operator tree} which is in DNF now. For every {tt AND} node we
  1685. create an entry in the {it union list} and for every {tt OR} node we
  1686. create an {tt IN} subselect. ({tt NOT IN} subselects are created for
  1687. {tt OR NOT} nodes). The first entry of the {it union list} is handed
  1688. back but before that the saved clauses ({tt sortClause} etc.) are
  1689. restored to the new top node. Note that the new top node can differ
  1690. from the one of the {it parsetree} given as argument because of the
  1691. translation into DNF. That's why we had to save the {tt sortClause}
  1692. etc.
  1693. %
  1694. pagebreak
  1695. %
  1696. begin{verbatim}
  1697.   Query *                                                         
  1698.   Except_Intersect_Rewrite (Query *parsetree)                     
  1699.   {                                                               
  1700.                               .
  1701.                               .
  1702.                               .
  1703.     /* Save some fields, to be able to restore them               
  1704.      * to the resulting top node at the end of the                
  1705.      * function                                                   
  1706.      */                                                           
  1707.     sortClause = parsetree->sortClause;                           
  1708.     uniqueFlag = parsetree->uniqueFlag;                           
  1709.     into = parsetree->into;                                       
  1710.     isBinary = parsetree->isBinary;                               
  1711.     isPortal = parsetree->isPortal;                               
  1712.                                                                   
  1713.     /* Transform the SelectStmt nodes into Query nodes            
  1714.      * as usually done by transformSelectStmt() earlier.          
  1715.      * /                                                          
  1716.     intersectClause =                                             
  1717.       (List *)intersect_tree_analyze(                             
  1718.               (Node *)parsetree->intersectClause,                 
  1719.               (Node *)lfirst(parsetree->unionClause),             
  1720.               (Node *)parsetree);                                 
  1721.                               .                                   
  1722.                               .                                   
  1723.                               .                                   
  1724.     /* Transform the operator tree to DNF */
  1725.     intersectClause = 
  1726.                 cnfify((Expr *)intersectClause, true);                      
  1727.     /* For every entry of the intersectClause list we             
  1728.      * generate one entry in the union_list                       
  1729.      */                                                           
  1730.     foreach(intersect, intersectClause)                           
  1731.     {                                                             
  1732.       /* For every OR we create an IN subselect and               
  1733.        * for every OR NOT we create a NOT IN subselect,           
  1734.        */                                                         
  1735.       intersect_list = NIL;                                       
  1736.       create_list((Node *)lfirst(intersect),                      
  1737.                   &intersect_list);
  1738.       /* The first node will become the Select Query 
  1739.        * node, all other nodes are transformed into 
  1740.        * subselects under this node!                                         
  1741.        */                                                         
  1742.       intersect_node = (Query *)lfirst(intersect_list);           
  1743.       intersect_list = lnext(intersect_list);                     
  1744.                               .                                   
  1745.                               .                                   
  1746.                               .                                   
  1747.       /* Transform all remaining nodes into subselects
  1748.        * and add them to the qualifications of the 
  1749.        * Select Query node                                               
  1750.        */                                                         
  1751.       while(intersect_list != NIL)                                
  1752.       {                                                           
  1753.         n = makeNode(SubLink);                                    
  1754.                                                                   
  1755.         /* Here we got an OR so transform it to an                
  1756.          * IN subselect                                           
  1757.          */                                                       
  1758.         if(IsA(lfirst(intersect_list), Query))                    
  1759.         {                                                         
  1760.                               .                                   
  1761.                               .                                   
  1762.                               .                                   
  1763.           n->subselect = lfirst(intersect_list);                  
  1764.           op = "=";                                               
  1765.           n->subLinkType = ANY_SUBLINK;                           
  1766.           n->useor = false;                                       
  1767.         }                                                         
  1768.         /* Here we got an OR NOT node so transform        
  1769.          * it to a NOT IN  subselect                                      
  1770.          */                                                       
  1771.         else                                                      
  1772.         {                                                         
  1773.                               .                                   
  1774.                               .                                   
  1775.                               .                                   
  1776.           n->subselect = 
  1777.              (Node *)lfirst(((Expr *)
  1778.                    lfirst(intersect_list))->args);       
  1779.           op = "<>";                                              
  1780.           n->subLinkType = ALL_SUBLINK;                           
  1781.           n->useor = true;                                        
  1782.         }
  1783.         /* Prepare the lefthand side of the Sublinks:             
  1784.          * All the entries of the targetlist must be              
  1785.          * (IN) or must not be (NOT IN) the subselect             
  1786.          */                                                       
  1787.         foreach(elist, intersect_node->targetList)                
  1788.         {                                                         
  1789.           Node        *expr = lfirst(elist);                      
  1790.           TargetEntry *tent = (TargetEntry *)expr;                
  1791.                                                                   
  1792.           n->lefthand = 
  1793.                  lappend(n->lefthand, tent->expr);         
  1794.         }
  1795.         /* The first arguments of oper also have to be            
  1796.          * created for the sublink (they are the same             
  1797.          * as the lefthand side!)                                 
  1798.          */                                                       
  1799.         left_expr = n->lefthand;                                  
  1800.         right_expr = 
  1801.              ((Query *)(n->subselect))->targetList;
  1802.         foreach(elist, left_expr)                                 
  1803.         {                                                         
  1804.           Node         *lexpr = lfirst(elist);                    
  1805.           Node         *rexpr = lfirst(right_expr);               
  1806.           TargetEntry *tent = (TargetEntry *) rexpr;              
  1807.           Expr         *op_expr;                                  
  1808.                                                                   
  1809.           op_expr = make_op(op, lexpr, tent->expr);         
  1810.           n->oper = lappend(n->oper, op_expr);                    
  1811.           right_expr = lnext(right_expr);                         
  1812.         }
  1813.         /* If the Select Query node has aggregates                
  1814.          * in use add all the subselects to the                   
  1815.          * HAVING qual else to the WHERE qual                     
  1816.          */                                                       
  1817.         if(intersect_node->hasAggs == false)                      
  1818.         {                                                         
  1819.           AddQual(intersect_node, (Node *)n);                     
  1820.         }                                                         
  1821.         else                                                      
  1822.         {                                                         
  1823.           AddHavingQual(intersect_node, (Node *)n);               
  1824.         }
  1825.         /* Now we got sublinks */                                 
  1826.         intersect_node->hasSubLinks = true;                       
  1827.         intersect_list = lnext(intersect_list);                   
  1828.       }
  1829.       intersect_node->intersectClause = NIL;                      
  1830.       union_list = lappend(union_list, intersect_node);           
  1831.     }                                                             
  1832.     /* The first entry to union_list is our                       
  1833.      * new top node                                               
  1834.      */                                                           
  1835.     result = (Query *)lfirst(union_list);                         
  1836.                                                                   
  1837.     /* attach the rest to unionClause */                          
  1838.     result->unionClause = lnext(union_list);                      
  1839.                                                                   
  1840.     /* Attach all the items saved in the                          
  1841.      * beginning of the function */                               
  1842.     result->sortClause = sortClause;                              
  1843.     result->uniqueFlag = uniqueFlag;                              
  1844.     result->into = into;                                          
  1845.     result->isPortal = isPortal;                                  
  1846.     result->isBinary = isBinary;                                  
  1847.                               .                                   
  1848.                               .                                   
  1849.                               .                                   
  1850.     return  result;                                               
  1851.   }
  1852. end{verbatim}
  1853. %
  1854. <step> {tt create_list()} \
  1855. Create a list of nodes that are either {tt Query} nodes or {tt NOT}
  1856. nodes followed by a {tt Query} node. The {it tree} given in {tt
  1857. ptr} contains at least one {it non negated} {tt Query} node. This
  1858. node is put to the beginning of the list.
  1859. %
  1860. begin{verbatim}
  1861.   void create_list(Node *ptr, 
  1862.                    List **intersect_list)
  1863.   {
  1864.     List *arg;   
  1865.     if(IsA(ptr,Query))
  1866.     {
  1867.       /* The non negated node is attached at the 
  1868.        * beginning (lcons) */
  1869.       *intersect_list = lcons(ptr, *intersect_list);
  1870.       return;      
  1871.     }  
  1872.     if(IsA(ptr,Expr))
  1873.     {
  1874.       if(((Expr *)ptr)->opType == NOT_EXPR)
  1875.       {
  1876.         /* negated nodes are appended to the 
  1877.          * end (lappend) 
  1878.          */
  1879.         *intersect_list = 
  1880.                lappend(*intersect_list, ptr);        
  1881.         return;         
  1882.       }
  1883.       else
  1884.       {
  1885.         foreach(arg, ((Expr *)ptr)->args)
  1886.         {
  1887.           create_list(lfirst(arg), intersect_list);
  1888.         }     
  1889.         return;         
  1890.       }
  1891.       return;      
  1892.     }
  1893.   }
  1894. end{verbatim}
  1895. %
  1896. <step> {tt intersect_tree_analyze()} \
  1897. %
  1898. The nodes given in {tt tree} are not transformed yet so process them
  1899. using {tt parse_analyze()}.  The node given in {tt first_select}
  1900. has already been processed, so don't transform it again but return a
  1901. pointer to the already processed version given in {tt parsetree}
  1902. instead.
  1903. %
  1904. begin{verbatim}
  1905.   Node *intersect_tree_analyze(Node *tree, 
  1906.                 Node *first_select, Node *parsetree)
  1907.   {
  1908.     Node *result; 
  1909.     List *arg;
  1910.     if(IsA(tree, SelectStmt))
  1911.     {
  1912.       List *qtrees;
  1913.       /* If we get to the tree given in first_select 
  1914.        * return parsetree instead of performing 
  1915.        * parse_analyze() */
  1916.       if(tree == first_select)
  1917.       {
  1918.         result = parsetree;
  1919.       }
  1920.       else 
  1921.       {    
  1922.         /* transform the unprocessed Query nodes */ 
  1923.         qtrees = parse_analyze(lcons(tree, NIL), NULL);
  1924.         result = (Node *) lfirst(qtrees);
  1925.       }      
  1926.     }  
  1927.     if(IsA(tree,Expr))
  1928.     {
  1929.       /* Call recursively for every argument */
  1930.        foreach(arg, ((Expr *)tree)->args)
  1931.        {
  1932.          lfirst(arg) = 
  1933.              intersect_tree_analyze(lfirst(arg), 
  1934.                           first_select, parsetree);
  1935.        }
  1936.        result = tree;      
  1937.     }
  1938.     return result;  
  1939.   }
  1940. end{verbatim}
  1941. %
  1942. end{itemize}
  1943. **********************************************************
  1944. **********************************************************
  1945. **********************************************************
  1946. **********************************************************
  1947. **********************************************************
  1948. -->
  1949.  </chapter>
  1950. <!-- Keep this comment at the end of the file
  1951. Local variables:
  1952. mode: sgml
  1953. sgml-omittag:nil
  1954. sgml-shorttag:t
  1955. sgml-minimize-attributes:nil
  1956. sgml-always-quote-attributes:t
  1957. sgml-indent-step:1
  1958. sgml-indent-data:t
  1959. sgml-parent-document:nil
  1960. sgml-default-dtd-file:"./reference.ced"
  1961. sgml-exposed-tags:nil
  1962. sgml-local-catalogs:"/usr/lib/sgml/catalog"
  1963. sgml-local-ecat-files:nil
  1964. End:
  1965. -->