home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / source / qrymod / view.c < prev   
Encoding:
C/C++ Source or Header  |  1985-02-08  |  11.7 KB  |  379 lines

  1. # include    <ingres.h>
  2. # include    <aux.h>
  3. # include    <symbol.h>
  4. # include    <tree.h>
  5. # include    "qrymod.h"
  6. # include    <sccs.h>
  7. # include    <errors.h>
  8.  
  9. SCCSID(@(#)view.c    8.2    2/8/85)
  10.  
  11. /*
  12. **  VIEW.C -- view processing
  13. **
  14. **    This module does the view processing.  Basically, it operates
  15. **    by detecting all references to views and replacing them by
  16. **    references to real relations.  There are a number of cases
  17. **    when it cannot do this, to whit:
  18. **
  19. **    Syntactic problems:  the view may have a domain defined as
  20. **    a non-simple value (that is, not a simple attribute), which
  21. **    is then required to take on a value.  For example, if the
  22. **    view is defined as
  23. **        range of x is baserel
  24. **        define v (d = x.a / 3)
  25. **    and then referenced as
  26. **        append to v (d = 7)
  27. **    would result after query modification as
  28. **        range of x is baserel
  29. **        append to baserel (a / 3 = 7)
  30. **    which is not acceptable.  Of course, there is a range of cases
  31. **    where this can be fixed, but (for the time being) we will just
  32. **    throw them all out.
  33. **
  34. **    Disappearing tuple anomaly:  the implicit qualification on
  35. **    a view allows tuples to disappear even when not a duplicate.
  36. **    For example, take a view defined as:
  37. **        range of x is baserel
  38. **        define v (d = x.a) where x.a = 4
  39. **    and issue the query
  40. **        append to v (d = 5)
  41. **    The tuple will be inserted into the base relation, but will not
  42. **    be included in the view.  To solve that problem, we disallow
  43. **    updates to domains included in the qualification of the query.
  44. **    Note that this includes implicit updates, that is, an append
  45. **    with the domain missing (which implicitly appends a zero or
  46. **    blank domain).
  47. **
  48. **    Cross product problem:  a view which is defined as a cross
  49. **    product of two relations has several update anomalies.  For
  50. **    example, take R1 and R2 as:
  51. **              R1 | a | b      R2 | b | c
  52. **              ---|---|---     ---|---|---
  53. **                 | 7 | 0         | 0 | 3
  54. **                 | 8 | 0         | 0 | 4
  55. **    and issue the view definition
  56. **        range of m is R1
  57. **        range of n is R2
  58. **        define v (m.a, m.b, n.c) where m.b = n.b
  59. **    which will define a view which looks like
  60. **              view | a | b | c
  61. **              -----|---|---|---
  62. **                   | 7 | 0 | 3
  63. **                   | 7 | 0 | 4
  64. **                   | 8 | 0 | 3
  65. **                   | 8 | 0 | 4
  66. **    Now try issuing
  67. **        range of v is v
  68. **        delete v where v.a = 8 and v.c = 4
  69. **    which will try to give a view which looks like:
  70. **              view | a | b | c
  71. **              -----|---|---|---
  72. **                   | 7 | 0 | 3
  73. **                   | 7 | 0 | 4
  74. **                   | 8 | 0 | 3
  75. **    which is of course unexpressible in R1 and R2.
  76. **
  77. **    Multiple query problem:  certain updates will require gener-
  78. **    ating multiple queries to satisfy the update on the view.
  79. **    Although this can be made to work, it won't now.  Cases are
  80. **    replaces where the target list contains more than one
  81. **    relation, and appends to a view over more than one relation.
  82. **
  83. **    To solve these problems, we dissallow the following cases:
  84. **
  85. **    I.  In a REPLACE or APPEND statement, if a 'v.d' appears
  86. **        on the LHS in the target list of the query and
  87. **        the a-fcn for 'v.d' is not a simple attribute.
  88. **    II.  In REPLACE or APPEND statements, if a 'v.d' appears
  89. **        on the LHS in a target list of the query and in
  90. **        the qualification of the view.
  91. **    III.  In a DELETE or APPEND statement, if the view ranges
  92. **        over more than one relation.
  93. **    IV.  In a REPLACE statement, if the query resulting after
  94. **        modification of the tree, but before appending the
  95. **        view qualification Qv, has more than one variable.
  96. **    V.  In any update, if an aggregate or aggregate function
  97. **        appears anywhere in the target list of the view.
  98. **
  99. **    Note the assumption that the definition of a consistant update
  100. **    is:
  101. **        "An update is consistant if the result of
  102. **         performing the update on the view and then
  103. **         materializing that view is the same as the
  104. **         result of materializing the view and then
  105. **         performing the update."
  106. **
  107. **    Trace Flags:
  108. **        30 -> 39
  109. */
  110. /*
  111. **  VIEW -- driver for view processing
  112. **
  113. **    This routine does the view processing portion of qrymod.
  114. **    Since the 'tree' catalog can contain relations which are
  115. **    themselves views, it iterates over itself until no views
  116. **    are found.  Presumably this cannot result in an infinite
  117. **    loop, although in fact it probably can; this should be
  118. **    dealt with at some time.
  119. **
  120. **    For each range variable declared, it is checked whether
  121. **    that variable is a view.  If not, it is ignored.
  122. **    Then the tree which defines
  123. **    this view is fetched from the "tree" catalog by 'gettree',
  124. **    which also defines any variables required by this tree
  125. **    and adjusts the tree so that the varno's contained in the
  126. **    tree correspond to the varno's in the range table.
  127. **
  128. **    'Subsvars' and 'vrscan' really do it.  Given the root of the tree
  129. **    to be modified, the variable number to be eliminated, and the
  130. **    target list for a replacement tree, they actually do the
  131. **    tacking of 'new tree' onto 'old tree'.  After it is done,
  132. **    there should be no references to the old variable at all
  133. **    in the tree.  'Subsvars' scans for VAR nodes (which are
  134. **    retrieve-only, and hence are always alright); 'vrscan' scans
  135. **    the left hand branch of the tree (the RESDOM nodes) and
  136. **    substitutes them.
  137. **
  138. **    'Appqual' appends the qualification for the view (if any)
  139. **    onto the tree.  Finally, the variable for the view (which
  140. **    had all references to it eliminated by 'subsvars') is un-
  141. **    defined, so that that slot in the range table can be re-
  142. **    used by later scans.
  143. **
  144. **    Parameters:
  145. **        root -- root of the tree to be modified.
  146. **
  147. **    Returns:
  148. **        Root of modified tree.
  149. **
  150. **    Side Effects:
  151. **        The range table is updated to delete any views and
  152. **            add any base relations needed to support them.
  153. **        Activity occurs in the 'tree' catalog to get the trees
  154. **            needed to define the views.
  155. **        The tree pointed to by 'root' is modified.
  156. **
  157. **    Trace Flags:
  158. **        30
  159. */
  160.  
  161. QTREE *
  162. view(root)
  163. QTREE    *root;
  164. {
  165.     register int    i;
  166.     DESC        desc;
  167.     register int    vn;
  168.     register QTREE    *vtree;
  169.     int        viewfound;
  170.     extern QTREE    *gettree();
  171.     extern QTREE    *norml();
  172.     auto QTREE    *r;
  173.  
  174. #    ifdef xQTR1
  175.     tTfp(30, -1, "\n->VIEW\n\n");
  176. #    endif
  177.  
  178.     r = root;
  179.  
  180.     /* scan range table until no views */
  181.     viewfound = TRUE;
  182.     while (viewfound)
  183.     {
  184. #        ifdef xQTR2
  185.         tTfp(30, 1, "scanning Qt.qt_rangev\n");
  186. #        endif
  187.  
  188.         /* scan range table for views */
  189.         viewfound = FALSE;
  190.  
  191.         /* make new resultvar old resultvar for non-update */
  192.         Qm.qm_newresvar = Qt.qt_resvar;
  193.  
  194.         /* scan all variables in range table */
  195.         for (vn = 0; vn < MAXVAR + 1; vn++)
  196.         {
  197.             /* check for empty entry in range table */
  198.             if (Qt.qt_rangev[vn].rngvdesc == NULL)
  199.                 continue;
  200.  
  201.             /* see if it is a view or base relation */
  202.             if (!bitset(S_VIEW, Qt.qt_rangev[vn].rngvdesc->reldum.relstat))
  203.                 continue;
  204. #            ifdef xQTR1
  205.             if (tTf(30, 3))
  206.                 printf("view vn %d: %.12s\n", vn,
  207.                     Qt.qt_rangev[vn].rngvdesc->reldum.relid);
  208. #            endif
  209.  
  210.             vtree = gettree(Qt.qt_rangev[vn].rngvdesc->reldum.relid,
  211.                     Qt.qt_rangev[vn].rngvdesc->reldum.relowner,
  212.                     mdVIEW, 0, FALSE);
  213. #            ifdef xQTR3
  214.             if (tTf(30, 5))
  215.                 treepr(vtree, "Viewdef");
  216. #            endif
  217.  
  218.             /* check for updating with aggregates */
  219.             if (Qt.qt_qmode != mdRETR && aggcheck(vtree))
  220.                 qmerror(NOUPDATEAGG, Qt.qt_qmode, Qt.qt_resvar, 0);    /* cannot update views with aggregates */
  221.  
  222.             /* scan view replacing RESDOM nodes */
  223.             if (Qt.qt_qmode != mdRETR && vn == Qt.qt_resvar)
  224.                 vrscan(&r->left, vtree);
  225.  
  226.             /* scan view replacing VAR nodes */
  227.             subsvars(&r, vn, vtree->left, mdVIEW);
  228.  
  229.             /* test for non-functional replace */
  230.             if (Qt.qt_qmode == mdREPL && bitcnt(varset(r) | (1 << Qm.qm_newresvar)) > 1)
  231.                 qmerror(NONFUNCUPDATE, Qt.qt_qmode, Qt.qt_resvar, 0);    /* non-functional update */
  232.  
  233.             /* append new qualification */
  234.             appqual(vtree->right, r);
  235.  
  236.             /* delete view range variable */
  237.             declare(vn, NULL);
  238.  
  239.             /* mark the view as having been processed */
  240.             viewfound = TRUE;
  241.  
  242.             /* change 'Qt.qt_resvar' to be the base rel var */
  243.             Qt.qt_resvar = Qm.qm_newresvar;
  244.         }
  245.     }
  246.  
  247.     /* renormalize the tree (just in case) */
  248.     r->right = norml(trimqlend(r->right));
  249.  
  250. #    ifdef xQTR1
  251.     if (tTf(30, 15))
  252.         treepr(r, "VIEW->");
  253. #    endif
  254.  
  255.     return (r);
  256. }
  257. /*
  258. **  VRSCAN -- scan query tree and replace RESDOM nodes
  259. **
  260. **    The query tree issued is scanned and RESDOM nodes are
  261. **    converted to conform to the underlying base relations.
  262. **    There are many checks in here, and things can fail
  263. **    easily.
  264. **
  265. **    The first check is for more than one relation in a
  266. **    DELETE or APPEND command.  This would require expanding
  267. **    the query into at least two queries.  For DELETE commands,
  268. **    this is the only check.  (Note that by this time 'aggcheck'
  269. **    has aborted anything which would cause problems with
  270. **    aggregates.)
  271. **
  272. **    For append commands, we abort immediately if there is
  273. **    a qualification on the view, since the inserted tuple(s)
  274. **    might not (all) appear in the view.
  275. **
  276. **    For all other queries, the target list of the query submitted
  277. **    is scanned down the left hand side (the RESDOM list).
  278. **    For each RESDOM, that variable is looked up in the view
  279. **    definition.  If the definition of it is not a simple
  280. **    attribute, the query is aborted.
  281. **
  282. **    Then, if the variable appears anywhere in the qualification
  283. **    of the view, the query is aborted.
  284. **
  285. **    Finally, we keep track of the varno which should become the
  286. **    new number two (that is, the Qt.qt_resvar).  If there are two
  287. **    candidates for this position, we promptly abort.
  288. **
  289. **    And as the last step, we actually change the 'resno' for
  290. **    this RESDOM.
  291. **
  292. **    When we exit the loop which scans RESDOM's, we change the
  293. **    'Qt.qt_resvar' to be the new variable which we have selected.
  294. **
  295. **    Notice that there are a number of overly restrictive
  296. **    conditions on runability.  Notably, there are large classes
  297. **    of queries which can run consistantly but which violate
  298. **    either the not-in-qualification condition or the aggregate-
  299. **    free condition.
  300. **
  301. **    Parameters:
  302. **        root -- the root of the tree to be updated.
  303. **        vtree -- the tree which defines the view.
  304. **
  305. **    Returns:
  306. **        none (maybe non-local on error)
  307. **
  308. **    Side Effects:
  309. **        The tree pointed to by 'root' is modified.
  310. **
  311. **    Trace Flags:
  312. **        33
  313. */
  314.  
  315. vrscan(root, vtree)
  316. QTREE    *root;
  317. QTREE    *vtree;
  318. {
  319.     register QTREE    *t;
  320.     register QTREE    *v;
  321.     int        i;
  322.     extern QTREE    *qscan();
  323.     extern QTREE    *vfind();
  324.     register QTREE    *p;
  325.  
  326.     t = root;
  327.     v = vtree;
  328.  
  329.     /* check DELETE and APPEND cases of > 1 relation */
  330.     if (Qt.qt_qmode == mdDEL || Qt.qt_qmode == mdAPP)
  331.     {
  332.         /* scan target list of view for > 1 relation */
  333.         if (bitcnt(i = varset(v->left)) != 1)
  334.             qmerror(MOREQUERY, Qt.qt_qmode, Qt.qt_resvar, 0);    /* query would result in > 1 query */
  335.  
  336.         /* this is the only check in this module for DELETES */
  337.         if (Qt.qt_qmode == mdDEL)
  338.         {
  339.             /* set Qt.qt_resvar to underlying (single) relation */
  340.             Qm.qm_newresvar = bitpos(i);
  341.             return;
  342.         }
  343.  
  344.     }
  345.  
  346.     /* scan target list of query */
  347.     i = -1;
  348.     while ((t = t->left)->sym.type != TREE)
  349.     {
  350.         if (t->sym.type != RESDOM)
  351.             syserr("vrscan: bad TL node %d", t->sym.type);
  352.  
  353.         /* check for 'tid' attribute (stuck in by DEL and REPL) */
  354.         if (t->sym.value.sym_resdom.resno == 0)
  355.             continue;
  356.  
  357.         /* find definition for this domain in the view */
  358.         p = vfind(t->sym.value.sym_resdom.resno, v->left);
  359.  
  360.         /* check for simple attribute */
  361.         if (p->sym.type != VAR)
  362.             qmerror(NOUPDATEDOM, Qt.qt_qmode, Qt.qt_resvar, 0);    /* non-simple attribute */
  363.  
  364.  
  365.         /* check for trying to do update on two relations again */
  366.         /* this test should only be true for REPLACE commands */
  367.         if (i < 0)
  368.             i = p->sym.value.sym_var.varno;
  369.         else if (i != p->sym.value.sym_var.varno)
  370.             qmerror(MOREQUERY, Qt.qt_qmode, Qt.qt_resvar, 0);    /* query on two relations */
  371.  
  372.         /* finally, do the substitution of resno's */
  373.         t->sym.value.sym_resdom.resno = p->sym.value.sym_var.attno;
  374.     }
  375.  
  376.     /* change the result variable for the query to the underlying */
  377.     Qm.qm_newresvar = i;
  378. }
  379.