Annotation of 42BSD/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: 
                      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.