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
vrscan defined in line 418; used 1 times

Defined variables

Newresvar defined in line 166; used 5 times
Last modified: 1995-02-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2901
Valid CSS Valid XHTML 1.0 Strict