home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rewrite / ViewDefine.c < prev   
Encoding:
C/C++ Source or Header  |  1992-08-27  |  13.1 KB  |  480 lines

  1. /* 
  2.  * $Header: /private/postgres/src/rewrite/RCS/ViewDefine.c,v 2.9 1992/06/28 03:47:58 mao Exp $
  3.  */
  4.  
  5. #include "access/heapam.h"
  6. #include "catalog/syscache.h"
  7. #include "utils/log.h"
  8. #include "nodes/relation.h"
  9. #include "nodes/relation.a.h"
  10. #include "nodes/primnodes.h"
  11. #include "nodes/primnodes.a.h"
  12. #include "parser/parsetree.h"
  13.  
  14. /* #include "catalog_utils.h" */ 
  15.  
  16. #include "./RewriteManip.h"
  17.  
  18. extern Name tname();
  19. void makeRetrieveViewRuleName();
  20.  
  21. Name
  22. attname ( relname , attnum )
  23.      Name relname;
  24.      int attnum;
  25. {
  26.     Relation relptr;
  27.     HeapTuple atp;
  28.     ObjectId reloid;
  29.     Name varname;
  30.  
  31.     relptr = amopenr (relname );
  32.     reloid = RelationGetRelationId ( relptr );
  33.    
  34.     atp = SearchSysCacheTuple ( ATTNUM, reloid, attnum , NULL, NULL );
  35.     if (!HeapTupleIsValid(atp)) {
  36.     elog(WARN, "getattnvals: no attribute tuple %d %d",
  37.          reloid, attnum);
  38.     return(0);
  39.     }
  40.     varname = (Name)&( ((AttributeTupleForm) GETSTRUCT(atp))->attname );
  41.  
  42.     return ( varname );
  43. }
  44.  
  45. /*---------------------------------------------------------------------
  46.  * DefineVirtualRelation
  47.  *
  48.  * Create the "view" relation.
  49.  * `DefineRelation' does all the work, we just provide the correct
  50.  * arguments!
  51.  *
  52.  * If the relation already exists, then 'DefineRelation' will abort
  53.  * the xact...
  54.  *---------------------------------------------------------------------
  55.  */
  56. DefineVirtualRelation (relname , tlist )
  57. Name relname;
  58. List tlist;
  59. {
  60.     List attrList, t, element;
  61.     List parameters;
  62.     TLE    entry;
  63.     Resdom  res;
  64.     Name resname;
  65.     ObjectId restype;
  66.     Name restypename;
  67.  
  68.     /*
  69.      * create a list with one entry per attribute of this relation.
  70.      * Each entry is a two element list. The first element is the
  71.      * name of the attribute (a string) and the second the name of the type
  72.      * (NOTE: a string, not a type id!).
  73.      */
  74.     attrList = LispNil;
  75.     if (!null(tlist)) {
  76.     foreach (t, tlist ) {
  77.         /*
  78.          * find the names of the attribute & its type
  79.          */
  80.         entry = get_entry((TL)t);
  81.         res   = get_resdom(entry);
  82.         resname = get_resname(res);
  83.         restype = get_restype(res);
  84.         restypename = tname(get_id_type(restype));
  85.         element = lispCons(lispString(restypename), LispNil);
  86.         element = lispCons(lispString(resname), element);
  87.         attrList = nappend1(attrList, element);
  88.     }
  89.     } else {
  90.     elog ( WARN, "attempted to define virtual relation with no attrs");
  91.     }
  92.  
  93.     /*
  94.      * now create the parametesr for keys/inheritance etc.
  95.      * All of them are nil...
  96.      */
  97.     parameters = LispNil;
  98.     parameters = lispCons(LispNil, parameters);    /* keys */
  99.     parameters = lispCons(LispNil, parameters);    /* inheritance stuff */
  100.     parameters = lispCons(LispNil, parameters);    /* is indexable */
  101.     parameters = lispCons(LispNil, parameters);    /* archive type */
  102.     parameters = lispCons(LispNil, parameters);    /* heap store */
  103.     parameters = lispCons(LispNil, parameters);    /* archive store */
  104.  
  105.     /*
  106.      * finally create the relation...
  107.      */
  108.     DefineRelation(relname, parameters, attrList);
  109. }    
  110.  
  111. #ifdef BOGUS
  112. -------------------------------------------------------------------------
  113. /*    DefineVirtualRelation2
  114.  *    - takes a relation name and a targetlist
  115.  *    and generates a string "create relation ( ... )"
  116.  *    by taking the attributes and types from the tlist
  117.  *    and reconstructing the attr-list for create.
  118.  *    then calls "pg-eval" to evaluate the creation,
  119.  */
  120. DefineVirtualRelation2 ( relname , tlist )
  121.      Name relname;
  122.      List tlist;
  123. {
  124.     LispValue element;
  125.     static char querybuf[1024];
  126.     char *index = querybuf;
  127.     int i;
  128.  
  129.     for ( i = 0 ; i < 1024 ; i++ ) {
  130.     querybuf[i] = NULL;
  131.     }
  132.  
  133.     sprintf(querybuf,"create %s(",relname );
  134.     index += strlen(querybuf);
  135.     
  136.     if ( ! null ( tlist )) {
  137.     foreach ( element, tlist ) {
  138.         TLE     entry = get_entry((TL)element);
  139.         Resdom     res   = get_resdom(entry);
  140.         Name    resname = get_resname(res);
  141.         ObjectId    restype = get_restype(res);
  142.         Name    restypename = tname(get_id_type(restype));
  143.  
  144.         sprintf(index,"%s = %s,",resname,restypename);
  145.         index += strlen(index);
  146.     }
  147.     *(index-1) = ')';
  148.     
  149.     } else
  150.     elog ( WARN, "attempted to define virtual relation with no attrs");
  151.     pg_eval(querybuf, (char *) NULL, (ObjectId *) NULL, 0);
  152. }    
  153. -------------------------------------------------------------------------
  154. #endif BOGUS
  155.  
  156. List
  157. my_find ( string, list )
  158.      char *string;
  159.      List list;
  160. {
  161.     List i = NULL;
  162.     List retval = NULL;
  163.  
  164.     for( i = list ; i != NULL; i = CDR(i) ) {
  165.     if ( CAR(i) && IsA (CAR(i),LispList)) {
  166.         retval = my_find ( string,CAR(i));
  167.         if ( retval ) 
  168.           break;
  169.     } else if ( CAR(i) && IsA(CAR(i),LispStr) && 
  170.             !strcmp(CString(CAR(i)),string) ) {
  171.         retval = i;
  172.         break;
  173.     } 
  174.     }
  175.     return(retval);
  176. }
  177.  
  178. /*------------------------------------------------------------------
  179.  * makeViewRetrieveRuleName
  180.  *
  181.  * Given a view name, create the name for the 'on retrieve to "view"'
  182.  * rule.
  183.  * This routine is called when defining/removing a view.
  184.  *
  185.  * NOTE: it quarantees that the name is at most 15 chars long
  186.  *------------------------------------------------------------------
  187.  */
  188. void
  189. makeRetrieveViewRuleName(rule_name, view_name)
  190. Name rule_name;
  191. Name view_name;
  192. {
  193.     char buf[100];
  194.  
  195.     /*
  196.      * make sure that no non-null characters follow the
  197.      * '\0' at the end of the string...
  198.      */
  199.     bzero(buf, sizeof(buf));
  200.     sprintf(buf, "_RET%s", view_name);
  201.     buf[15] = '\0';
  202.     bcopy(buf, &(rule_name->data[0]), 16);
  203. }
  204.  
  205. /*-----------------------------------------------------------------------
  206.  * FormViewRetrieveRule
  207.  *
  208.  * Form the "on retrieve to view" rule...
  209.  * If the view definition is:
  210.  *    define mikeolson (...target_list...) where ...qual....
  211.  * the rule will be:
  212.  *      define rule ret_mileolson is
  213.  *    on retrieve to mike_olson do instead
  214.  *    retrieve (...target_list...) where ...qual....
  215.  *
  216.  *-----------------------------------------------------------------------
  217.  */
  218. #ifdef TUPLE_VIEW
  219. List
  220. FormViewRetrieveRule (view_name, view_parse)
  221. Name view_name;
  222. List view_parse;
  223. {
  224.     
  225.     NameData rname;
  226.     List p, q, target, rt;
  227.     List lispCopy();
  228.  
  229.     /*
  230.      * Create a parse tree that corresponds to the suitable
  231.      * tuple level rule...
  232.      */
  233.     p = LispNil;
  234.     /*
  235.      * this is an instance-level rule... (or tuple-level
  236.      * for the traditionalists)
  237.      */
  238.     p = nappend1(p, lispAtom("instance"));
  239.     /*
  240.      * the second item in the list is the so called 'hint' : "(rule nil)"
  241.      */
  242.     p = nappend1(p, lispCons(lispAtom("rule"), lispCons(LispNil, LispNil)));
  243.     /*
  244.      * rule name now...
  245.      */
  246.     makeRetrieveViewRuleName(&rname, view_name);
  247.     p = nappend1(p, lispString(&(rname.data[0])));
  248.     /*
  249.      * The next item is a big one...
  250.      * First the 'event type' (retrieve), then the 'target' (the
  251.      * view relation), then the 'rule qual' (no qualification in this
  252.      * case), then the 'instead' information (yes, this is an instead
  253.      * rule!) and finally the 'rule actions', whish is nothing else from
  254.      * a list containing the view parse!
  255.      */
  256.     q = LispNil;
  257.     q = nappend1(q, lispAtom("retrieve"));
  258.     target = lispCons(lispString(view_name), LispNil);
  259.     q = nappend1(q, target);
  260.     q = nappend1(q, LispNil);
  261.     q = nappend1(q, lispInteger(1));
  262.     q = nappend1(q, lispCons(lispCopy(view_parse), LispNil));
  263.     p = nappend1(p, q);
  264.     /*
  265.      * now our final item, the range table...
  266.      */
  267.     rt = lispCopy(root_rangetable(parse_root(view_parse)));
  268.     p = nappend1(p, rt);
  269.  
  270.     return(p);
  271.  
  272. }
  273. #endif TUPLE_VIEW
  274. List
  275. FormViewRetrieveRule (view_name, view_parse)
  276. Name view_name;
  277. List view_parse;
  278. {
  279.     
  280.     NameData rname;
  281.     List p, q, target, rt;
  282.     List lispCopy();
  283.  
  284.     /*
  285.      * Create a lisp tree that corresponds to the suitable
  286.      * rewrite rule args for DefineQueryRewrite();
  287.      */
  288.     p = LispNil;
  289.     makeRetrieveViewRuleName(&rname, view_name);
  290.     p = nappend1(p, lispString(&(rname.data[0])));           /* rulename   */
  291.     p = nappend1(p,lispAtom("retrieve"));                    /* event_type */
  292.     p = nappend1(p,lispCons(lispString(view_name),LispNil)); /* event_obj  */
  293.     p = nappend1(p,lispCons(LispNil,LispNil));               /* event_qual */
  294.     p = nappend1(p,lispInteger(1));                          /* is_instead */
  295.     q = nappend1(LispNil, view_parse);
  296.     p = nappend1(p,q);                                       /* (action)   */
  297.     return p;
  298. }
  299. static void
  300. DefineViewRules (view_name, view_parse)
  301. Name view_name;
  302. List view_parse;
  303. {
  304.     List retrieve_rule        = NULL;
  305.     char ruleText[1000];
  306. #ifdef NOTYET
  307.     List replace_rule        = NULL;
  308.     List append_rule        = NULL;
  309.     List delete_rule        = NULL;
  310. #endif
  311.  
  312.     retrieve_rule = 
  313.       FormViewRetrieveRule (view_name, view_parse);
  314.  
  315. #ifdef NOTYET
  316.     
  317.     replace_rule =
  318.       FormViewReplaceRule ( view_name, view_tlist, view_rt, view_qual);
  319.     append_rule = 
  320.       FormViewAppendRule ( view_name, view_tlist, view_rt, view_qual);
  321.     delete_rule = 
  322.       FormViewDeleteRule ( view_name, view_tlist, view_rt, view_qual);
  323.  
  324. #endif
  325.  
  326.     sprintf(ruleText, "retrieve rule for view %s", view_name);
  327.     DefineQueryRewrite(retrieve_rule);
  328. #ifdef TUPLE_VIEW
  329.     prs2DefineTupleRule(retrieve_rule, ruleText);
  330. #endif TUPLE_VIEW
  331. #ifdef NOTYET
  332.     DefineQueryRewrite ( replace_rule );
  333.     DefineQueryRewrite ( append_rule );
  334.     DefineQueryRewrite ( delete_rule );
  335. #endif
  336.  
  337. }     
  338.  
  339. /*---------------------------------------------------------------
  340.  * UpdateRangeTableOfViewParse
  341.  *
  342.  * Update the range table of the given parsetree.
  343.  * This update consists of adding two new entries IN THE BEGINNING
  344.  * of the range table (otherwise the rule system will die a slow,
  345.  * horrible and painful death, and we do not want that now, do we?)
  346.  * one for the CURRENT relation and one for the NEW one (both of
  347.  * them refer in fact to the "view" relation).
  348.  *
  349.  * Of course we must also increase the 'varnos' of all the Var nodes
  350.  * by 2...
  351.  *
  352.  * NOTE: these are destructive changes. It would be difficult to
  353.  * make a complete copy of the parse tree and make the changes
  354.  * in the copy. 'lispCopy' is not enough because it onyl does a high
  355.  * level copy (i.e. the Var nodes remain the same, so the varno offset
  356.  * will update both parsetrees) and I am not confident that
  357.  * 'copyfuncs.c' are bug free...
  358.  *---------------------------------------------------------------
  359.  */
  360. void
  361. UpdateRangeTableOfViewParse(view_name, view_parse)
  362. Name view_name;
  363. List view_parse;
  364. {
  365.     List old_rt;
  366.     List new_rt;
  367.     List root;
  368.     List rt_entry1, rt_entry2;
  369.     List MakeRangeTableEntry();
  370.  
  371.     /*
  372.      * first offset all var nodes by 2
  373.      */
  374.     OffsetVarNodes(view_parse, 2);
  375.  
  376.     /*
  377.      * find the old range table...
  378.      */
  379.     root = parse_root(view_parse);
  380.     old_rt = root_rangetable(root);
  381.  
  382.     /*
  383.      * create the 2 new range table entries and form the new
  384.      * range table...
  385.      * CURRENT first, then NEW....
  386.      */
  387.     rt_entry1 = MakeRangeTableEntry(view_name, LispNil, "*CURRENT*");
  388.     rt_entry2 = MakeRangeTableEntry(view_name, LispNil, "*NEW*");
  389.     new_rt = lispCons(rt_entry2, old_rt);
  390.     new_rt = lispCons(rt_entry1, new_rt);
  391.  
  392.     /*
  393.      * Now the tricky part....
  394.      * Update the range table in place... Be careful here, or
  395.      * hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
  396.      */
  397.     root_rangetable(root) = new_rt;
  398. }
  399.        
  400. /*-------------------------------------------------------------------
  401.  * DefineView
  402.  *
  403.  *    - takes a "viewname", "parsetree" pair and then
  404.  *    1)    construct the "virtual" relation 
  405.  *    2)    commit the command but NOT the transaction,
  406.  *        so that the relation exists
  407.  *        before the rules are defined.
  408.  *    2)    define the "n" rules specified in the PRS2 paper
  409.  *        over the "virtual" relation
  410.  *-------------------------------------------------------------------
  411.  */
  412.  
  413. void
  414. DefineView(view_name, view_parse)
  415. Name view_name;
  416. List view_parse;
  417. {
  418.  
  419.     List view_tlist;
  420.  
  421.     view_tlist = parse_targetlist( view_parse );
  422.  
  423.     /*
  424.      * Create the "view" relation
  425.      * NOTE: if it already exists, the xaxt will be aborted.
  426.      */
  427.     DefineVirtualRelation (view_name ,view_tlist);
  428.  
  429.     /*
  430.      * The relation we have just created is not visible
  431.      * to any other commands running with the same transaction &
  432.      * command id.
  433.      * So, increment the command id counter (but do NOT pfree any
  434.      * memory!!!!)
  435.      */
  436.     CommandCounterIncrement();
  437.  
  438.     /*
  439.      * The range table of 'view_parse' does not contain entries
  440.      * for the "CURRENT" and "NEW" relations.
  441.      * So... add them!
  442.      * NOTE: we make the update in place! After this call 'view_parse' 
  443.      * will never be what it used to be...
  444.      */
  445.     UpdateRangeTableOfViewParse(view_name, view_parse);
  446.     DefineViewRules(view_name, view_parse);
  447. }
  448.  
  449. /*------------------------------------------------------------------
  450.  * RemoveView
  451.  *
  452.  * Remove a view given its name
  453.  *------------------------------------------------------------------
  454.  */
  455. void
  456. RemoveView(view_name)
  457. Name view_name;
  458. {
  459.     NameData rname;
  460.  
  461.     /*
  462.      * first remove all the "view" rules...
  463.      * Currently we only have one!
  464.      */
  465.     makeRetrieveViewRuleName(&rname, view_name);
  466.     RemoveRewriteRule(&rname);
  467. #ifdef TUPLE_VIEW
  468.     prs2RemoveTupleRule(&rname);
  469. #endif TUPLE_VIEW
  470.     /*
  471.      * we don't really need that, but just in case...
  472.      */
  473.     CommandCounterIncrement();
  474.  
  475.     /*
  476.      * now remove the relation.
  477.      */
  478.     RelationNameDestroyHeapRelation(view_name);
  479. }
  480.