Annotation of 43BSD/ingres/source/qrymod/view.c, revision 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.