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: }

Defined functions

view defined in line 9; used 2 times
vrscan defined in line 315; used 1 times
Last modified: 1986-04-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1017
Valid CSS Valid XHTML 1.0 Strict