Annotation of 43BSD/ingres/source/qrymod/view.c, revision 1.1.1.1

1.1       root        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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.