# 2.11BSD#431 - /usr/ingres/source/qrymod/view.c

##### Functions

    view              X
    vrscan            X

##### Variables

    Newresvar         X

       1: # include   "../ingres.h"
       2: # include   "../aux.h"
       3: # include   "../symbol.h"
       4: # include   "../tree.h"
       5: # include   "qrymod.h"
       6:
       7: /*
       8: **  VIEW.C -- view processing
       9: **
      10: **	This module does the view processing.  Basically, it operates
      11: **	by detecting all references to views and replacing them by
      12: **	references to real relations.  There are a number of cases
      13: **	when it cannot do this, to whit:
      14: **
      15: **	Syntactic problems:  the view may have a domain defined as
      16: **	a non-simple value (that is, not a simple attribute), which
      17: **	is then required to take on a value.  For example, if the
      18: **	view is defined as
      19: **		range of x is baserel
      20: **		define v (d = x.a / 3)
      21: **	and then referenced as
      22: **		append to v (d = 7)
      23: **	would result after query modification as
      24: **		range of x is baserel
      25: **		append to baserel (a / 3 = 7)
      26: **	which is not acceptable.  Of course, there is a range of cases
      27: **	where this can be fixed, but (for the time being) we will just
      28: **	throw them all out.
      29: **
      30: **	Disappearing tuple anomaly:  the implicit qualification on
      31: **	a view allows tuples to disappear even when not a duplicate.
      32: **	For example, take a view defined as:
      33: **		range of x is baserel
      34: **		define v (d = x.a) where x.a = 4
      35: **	and issue the query
      36: **		append to v (d = 5)
      37: **	The tuple will be inserted into the base relation, but will not
      38: **	be included in the view.  To solve that problem, we disallow
      39: **	updates to domains included in the qualification of the query.
      40: **	Note that this includes implicit updates, that is, an append
      41: **	with the domain missing (which implicitly appends a zero or
      42: **	blank domain).
      43: **
      44: **	Cross product problem:  a view which is defined as a cross
      45: **	product of two relations has several update anomalies.  For
      46: **	example, take R1 and R2 as:
      47: **              R1 | a | b      R2 | b | c
      48: **              ---|---|---     ---|---|---
      49: **                 | 7 | 0         | 0 | 3
      50: **                 | 8 | 0         | 0 | 4
      51: **	and issue the view definition
      52: **		range of m is R1
      53: **		range of n is R2
      54: **		define v (m.a, m.b, n.c) where m.b = n.b
      55: **	which will define a view which looks like
      56: **              view | a | b | c
      57: **              -----|---|---|---
      58: **                   | 7 | 0 | 3
      59: **                   | 7 | 0 | 4
      60: **                   | 8 | 0 | 3
      61: **                   | 8 | 0 | 4
      62: **	Now try issuing
      63: **		range of v is v
      64: **		delete v where v.a = 8 and v.c = 4
      65: **	which will try to give a view which looks like:
      66: **              view | a | b | c
      67: **              -----|---|---|---
      68: **                   | 7 | 0 | 3
      69: **                   | 7 | 0 | 4
      70: **                   | 8 | 0 | 3
      71: **	which is of course unexpressible in R1 and R2.
      72: **
      73: **	Multiple query problem:  certain updates will require gener-
      74: **	ating multiple queries to satisfy the update on the view.
      75: **	Although this can be made to work, it won't now.  Cases are
      76: **	replaces where the target list contains more than one
      77: **	relation, and appends to a view over more than one relation.
      78: **
      79: **	To solve these problems, we dissallow the following cases:
      80: **
      81: **	I.  In a REPLACE or APPEND statement, if a 'v.d' appears
      82: **		on the LHS in the target list of the query and
      83: **		the a-fcn for 'v.d' is not a simple attribute.
      84: **	II.  In REPLACE or APPEND statements, if a 'v.d' appears
      85: **		on the LHS in a target list of the query and in
      86: **		the qualification of the view.
      87: **	III.  In a DELETE or APPEND statement, if the view ranges
      88: **		over more than one relation.
      89: **	IV.  In a REPLACE statement, if the query resulting after
      90: **		modification of the tree, but before appending the
      91: **		view qualification Qv, has more than one variable.
      92: **	V.  In any update, if an aggregate or aggregate function
      93: **		appears anywhere in the target list of the view.
      94: **
      95: **	Note the assumption that the definition of a consistant update
      96: **	is:
      97: **		"An update is consistant if the result of
      98: **		 performing the update on the view and then
      99: **		 materializing that view is the same as the
     100: **		 result of materializing the view and then
     101: **		 performing the update."
     102: **
     103: **	Defines:
     104: **		view -- the driver for the view algorithm.
     105: **		vrscan -- to scan the query tree and substitute
     106: **			RESDOM nodes (plus much validity checking).
     107: **		Newresvar -- the new 'Resultvar' on updates.
     108: **
     109: **	Requires:
     110: **		gettree -- to get a query tree from the 'tree' catalog
     111: **			and prepare it for use (mainly by coming up
     112: **			with unique variable numbers).
     113: **		appqual -- to append a qualification onto the query
     114: **			tree.
     115: **		subsvars -- to scan the query tree and do the actual
     116: **			substitution of VAR nodes.
     117: **		trscan -- other routines to scan the tree for
     118: **			various conditions.
     119: **
     120: **	Required By:
     121: **		qrymod.c
     122: **
     123: **	Trace Flags:
     124: **		30 -> 39
     125: **
     126: **	Diagnostics:
     127: **		3310: cannot update some domain -- An update occured
     128: **			which would result with an expression on the
     129: **			LHS of an IS, that is, a non-simple attribute.
     130: **		3320: domain occurs in qualification of view -- The
     131: **			disappearing tuple anomolie makes it impossible
     132: **			to update any domains which occur in the
     133: **			qualification of a view.
     134: **		3330: update would result in more than one query --
     135: **			The view ranges over more than one relation,
     136: **			and this update would require that more than
     137: **			one query result.
     138: **		3340: views do not have TID's -- You have attempted
     139: **			to reference (for retrieve or update) the
     140: **			TID of a view (which is undefined).
     141: **		3350: cannot update an aggregate value -- An update
     142: **			tried to change the value of an aggregate
     143: **			value, similar to error 3310 above.
     144: **		3360: that update might be non-functional -- A really
     145: **			bizarre one.  This error occurs on REPLACE's
     146: **			which are on a single relation, but which
     147: **			include another relation in the qualification.
     148: **			That is, the set of variables in the target
     149: **			list includes only one variable (and so is not
     150: **			caught as error 3330), but the result of
     151: **			query modification leaves a query over two
     152: **			relations.
     153: **
     154: **	Syserrs:
     155: **		"subsvars: bad attno %d" -- an attribute number for a
     156: **			view came down in the query tree, but there
     157: **			was no substitution for it in the view defn
     158: **			query tree.  Probably means inconsistant
     159: **			catalogs (attribute v. tree).
     160: **
     161: **	History:
     162: **		2/14/79 -- version 6.2/0 release.
     163: */
     164:
     165:
     166: int Newresvar;  /* new result variable, becomes Resultvar */
     167: /*
     168: **  VIEW -- driver for view processing
     169: **
     170: **	This routine does the view processing portion of qrymod.
     171: **	Since the 'tree' catalog can contain relations which are
     172: **	themselves views, it iterates over itself until no views
     173: **	are found.  Presumably this cannot result in an infinite
     174: **	loop, although in fact it probably can; this should be
     175: **	dealt with at some time.
     176: **
     177: **	For each range variable declared, it is checked whether
     178: **	that variable is a view.  If not, it is ignored.
     179: **	Then the tree which defines
     180: **	this view is fetched from the "tree" catalog by 'gettree',
     181: **	which also defines any variables required by this tree
     182: **	and adjusts the tree so that the varno's contained in the
     183: **	tree correspond to the varno's in the range table.
     184: **
     185: **	'Subsvars' and 'vrscan' really do it.  Given the root of the tree
     186: **	to be modified, the variable number to be eliminated, and the
     187: **	target list for a replacement tree, they actually do the
     188: **	tacking of 'new tree' onto 'old tree'.  After it is done,
     189: **	there should be no references to the old variable at all
     190: **	in the tree.  'Subsvars' scans for VAR nodes (which are
     191: **	retrieve-only, and hence are always alright); 'vrscan' scans
     192: **	the left hand branch of the tree (the RESDOM nodes) and
     193: **	substitutes them.
     194: **
     195: **	'Appqual' appends the qualification for the view (if any)
     196: **	onto the tree.  Finally, the variable for the view (which
     197: **	had all references to it eliminated by 'subsvars') is un-
     198: **	defined, so that that slot in the range table can be re-
     199: **	used by later scans.
     200: **
     201: **	Parameters:
     202: **		root -- root of the tree to be modified.
     203: **
     204: **	Returns:
     205: **		Root of modified tree.
     206: **
     207: **	Side Effects:
     208: **		The range table is updated to delete any views and
     209: **			add any base relations needed to support them.
     210: **		Activity occurs in the 'tree' catalog to get the trees
     211: **			needed to define the views.
     212: **		The tree pointed to by 'root' is modified.
     213: **
     214: **	Requires:
     215: **		gettree -- to get the tree from the 'tree' catalog.
     216: **		subsvars -- to do the actual substitution of VAR nodes
     217: **			in the tree.
     218: **		vrscan -- to substitute RESDOM nodes.
     219: **		appqual -- to append the qualification to the tree.
     220: **		Rangev -- the range table; used for getting relation
     221: **			names.
     222: **		Newresvar -- becomes the new 'Resultvar' on updates.
     223: **
     224: **	Required By:
     225: **		qrymod
     226: **
     227: **	Trace Flags:
     228: **		30
     229: **
     230: **	Diagnostics:
     231: **		(All from lower level routines)
     232: */
     233:
     234: QTREE *
     235: view(root)
     236: QTREE   *root;
     237: {
     238:     register int        i;
     239:     struct descriptor   desc;
     240:     register int        vn;
     241:     register QTREE      *vtree;
     242:     int         viewfound;
     243:     extern QTREE        *gettree(), *norml();
     244:     auto QTREE      *r;
     245:
     246: #	ifdef xQTR1
     247:     tTfp(30, -1, "\n->VIEW\n\n");
     248: #	endif
     249:
     250:     r = root;
     251:
     252:     /* scan range table until no views */
     253:     viewfound = TRUE;
     254:     while (viewfound)
     255:     {
     256: #		ifdef xQTR2
     257:         tTfp(30, 1, "scanning Rangev\n");
     258: #		endif
     259:
     260:         /* scan range table for views */
     261:         viewfound = FALSE;
     262:
     263:         /* make new resultvar old resultvar for non-update */
     264:         Newresvar = Resultvar;
     265:
     266:         /* scan all variables in range table */
     267:         for (vn = 0; vn < MAXVAR + 1; vn++)
     268:         {
     269:             /* check for empty entry in range table */
     270:             if (!Rangev[vn].rused)
     271:                 continue;
     272:
     273:             /* see if it is a view or base relation */
     274:             if ((Rangev[vn].rstat & S_VIEW) == 0)
     275:                 continue;
     276: #			ifdef xQTR1
     277:             if (tTf(30, 3))
     278:                 printf("view vn %d: %.12s\n", vn, Rangev[vn].relid);
     279: #			endif
     280:
     281:             vtree = gettree(Rangev[vn].relid, Rangev[vn].rowner, mdVIEW, 0, FALSE);
     282: #			ifdef xQTR3
     283:             if (tTf(30, 5))
     284:                 treepr(vtree, "Viewdef");
     285: #			endif
     286:
     287:             /* check for updating with aggregates */
     288:             if (Qmode != mdRETR && aggcheck(vtree))
     289:                 ferror(3350, Qmode, Resultvar, 0);  /* cannot update views with aggregates */
     290:
     291:             /* scan view replacing RESDOM nodes */
     292:             if (Qmode != mdRETR && vn == Resultvar)
     293:                 vrscan(&r->left, vtree);
     294:
     295:             /* scan view replacing VAR nodes */
     296:             subsvars(&r, vn, vtree->left, mdVIEW);
     297:
     298:             /* test for non-functional replace */
     299:             if (Qmode == mdREPL && bitcnt(varset(r) | (1 << Newresvar)) > 1)
     300:                 ferror(3360, Qmode, Resultvar, 0);  /* non-functional update */
     301:
     302:             /* append new qualification */
     303:             appqual(vtree->right, r);
     304:
     305:             /* delete view range variable */
     306:             Rangev[vn].rused = FALSE;
     307:
     308:             /* mark the view as having been processed */
     309:             viewfound = TRUE;
     310:
     311:             /* change 'Resultvar' to be the base rel var */
     312:             Resultvar = Newresvar;
     313:         }
     314:     }
     315:
     316:     /* renormalize the tree (just in case) */
     317:     r->right = norml(trimqlend(r->right));
     318:
     319: #	ifdef xQTR1
     320:     if (tTf(30, 15))
     321:         treepr(r, "VIEW->");
     322: #	endif
     323:
     324:     return (r);
     325: }
     326: /*
     327: **  VRSCAN -- scan query tree and replace RESDOM nodes
     328: **
     329: **	The query tree issued is scanned and RESDOM nodes are
     330: **	converted to conform to the underlying base relations.
     331: **	There are many checks in here, and things can fail
     332: **	easily.
     333: **
     334: **	The first check is for more than one relation in a
     335: **	DELETE or APPEND command.  This would require expanding
     336: **	the query into at least two queries.  For DELETE commands,
     337: **	this is the only check.  (Note that by this time 'aggcheck'
     338: **	has aborted anything which would cause problems with
     339: **	aggregates.)
     340: **
     341: **	For append commands, we abort immediately if there is
     342: **	a qualification on the view, since the inserted tuple(s)
     343: **	might not (all) appear in the view.
     344: **
     345: **	For all other queries, the target list of the query submitted
     346: **	is scanned down the left hand side (the RESDOM list).
     347: **	For each RESDOM, that variable is looked up in the view
     348: **	definition.  If the definition of it is not a simple
     349: **	attribute, the query is aborted.
     350: **
     351: **	Then, if the variable appears anywhere in the qualification
     352: **	of the view, the query is aborted.
     353: **
     354: **	Finally, we keep track of the varno which should become the
     355: **	new number two (that is, the Resultvar).  If there are two
     356: **	candidates for this position, we promptly abort.
     357: **
     358: **	And as the last step, we actually change the 'resno' for
     359: **	this RESDOM.
     360: **
     361: **	When we exit the loop which scans RESDOM's, we change the
     362: **	'Resultvar' to be the new variable which we have selected.
     363: **
     364: **	Notice that there are a number of overly restrictive
     365: **	conditions on runability.  Notably, there are large classes
     366: **	of queries which can run consistantly but which violate
     367: **	either the not-in-qualification condition or the aggregate-
     368: **	free condition.
     369: **
     370: **	Parameters:
     371: **		root -- the root of the tree to be updated.
     372: **		vtree -- the tree which defines the view.
     373: **
     374: **	Returns:
     375: **		none (maybe non-local on error)
     376: **
     377: **	Side Effects:
     378: **		The tree pointed to by 'root' is modified.
     379: **
     380: **	Requires:
     381: **		bitcnt
     382: **		varset -- to create a bit map of variables used in
     383: **			a subtree.
     384: **		Qmode, Resultvar
     385: **		ferror
     386: **		vfind -- to find the definition for an attribute
     387: **			in the view.
     388: **		qscan -- to scan the qualification for the first
     389: **			VAR node for a specific 'varno.attno'.
     390: **		Newresvar -- marked with the new result variable for
     391: **			this query.
     392: **
     393: **	Called By:
     394: **		view
     395: **
     396: **	Trace Flags:
     397: **		33
     398: **
     399: **	Diagnostics:
     400: **		3310: non-simple attribute -- an update occured which
     401: **			would result in an expression on the LHS of an
     402: **			equals in the resulting query.
     403: **		3320: attribute in qualification -- an attribute was
     404: **			updated which occured in the qualification of
     405: **			the view; there is a chance that the tuple
     406: **			being updated might disappear from the view.
     407: **		3330: query would result in more than one query -- a
     408: **			view was defined on the join of two base relns;
     409: **			to run the query would require updates on both
     410: **			of these base relations (in two queries).
     411: **
     412: **	Syserrs:
     413: **		vrscan: bad TL %d -- Some node other than TREE or
     414: **			RESDOM appeared in the target list of the
     415: **			query.
     416: */
     417:
     418: vrscan(root, vtree)
     419: QTREE   *root;
     420: QTREE   *vtree;
     421: {
     422:     register QTREE  *t;
     423:     register QTREE  *v;
     424:     int     i;
     425:     extern QTREE    *qscan();
     426:     extern QTREE    *vfind();
     427:     register QTREE  *p;
     428:
     429:     t = root;
     430:     v = vtree;
     431:
     432:     /* check DELETE and APPEND cases of > 1 relation */
     433:     if (Qmode == mdDEL || Qmode == mdAPP)
     434:     {
     435:         /* scan target list of view for > 1 relation */
     436:         if (bitcnt(i = varset(v->left)) != 1)
     437:             ferror(3330, Qmode, Resultvar, 0);  /* query would result in > 1 query */
     438:
     439:         /* this is the only check in this module for DELETES */
     440:         if (Qmode == mdDEL)
     441:         {
     442:             /* set Resultvar to underlying (single) relation */
     443:             Newresvar = bitpos(i);
     444:             return;
     445:         }
     446:
     447:         /* check for a qualification on an append */
     448:         if (v->right->sym.type != QLEND)
     449:             ferror(3320, Qmode, Resultvar, 0);  /* attribute in qualification of view */
     450:     }
     451:
     452:     /* scan target list of query */
     453:     i = -1;
     454:     while ((t = t->left)->sym.type != TREE)
     455:     {
     456:         if (t->sym.type != RESDOM)
     457:             syserr("vrscan: bad TL node %d", t->sym.type);
     458:
     459:         /* check for 'tid' attribute (stuck in by DEL and REPL) */
     460:         if (((struct qt_res *)t)->resno == 0)
     461:         {
     462:             continue;
     463:         }
     464:
     465:         /* find definition for this domain in the view */
     466:         p = vfind(((struct qt_res *)t)->resno, v->left);
     467:
     468:         /* check for simple attribute */
     469:         if (p->sym.type != VAR)
     470:             ferror(3310, Qmode, Resultvar, 0);  /* non-simple attribute */
     471:
     472:         /* scan qualification of view for this attribute */
     473:         if (qscan(v->right, ((struct qt_var *)p)->varno, ((struct qt_var *)p)->attno) != NULL)
     474:             ferror(3320, Qmode, Resultvar, 0);  /* attribute in qualification of view */
     475:
     476:         /* check for trying to do update on two relations again */
     477:         /* this test should only be true for REPLACE commands */
     478:         if (i < 0)
     479:             i = ((struct qt_var *)p)->varno;
     480:         else if (i != ((struct qt_var *)p)->varno)
     481:             ferror(3330, Qmode, Resultvar, 0);  /* query on two relations */
     482:
     483:         /* finally, do the substitution of resno's */
     484:         ((struct qt_res *)t)->resno = ((struct qt_var *)p)->attno;
     485:     }
     486:
     487:     /* change the result variable for the query to the underlying */
     488:     Newresvar = i;
     489: }

#### Defined functions

view defined in line 234; used 2 times

- in /usr/ingres/source/qrymod/qrymod.c line 43, 53

vrscan defined in line 418; used 1 times

- in line 293

#### Defined variables

Newresvar defined in line 166; used 5 times

- in line 264, 299, 312, 443, 488

Last modified: 1995-02-19 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1216 |