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

unix.superglobalmegacorp.com

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