1: # include "../ingres.h" 2: # include "../aux.h" 3: # include "../symbol.h" 4: # include "../tree.h" 5: # include "../pipes.h" 6: # include "qrymod.h" 7: 8: /* 9: ** UTIL.C -- qrymod support routines 10: ** 11: ** This module contains a set of support routines for use 12: ** by the query modification routines. 13: ** 14: ** Defined Constants: 15: ** none 16: ** 17: ** Defines: 18: ** trimqlend() -- trim QLEND node off of qualification. 19: ** appqual() -- append qualification to tree. 20: ** ferror() -- issue fatal error 21: ** lsetbit() -- set bit in large set. 22: ** mergevar() -- merge variables to link terms 23: ** makezero() -- make a zero node 24: ** 25: ** Required By: 26: ** almost all 27: ** 28: ** Trace Flags: 29: ** 00 -> 19 30: ** 31: ** History: 32: ** 2/14/79 -- version 6.2/0 release. 33: */ 34: /* 35: ** TRIMQLEND -- trim QLEND node off of qualification 36: ** 37: ** The QLEND node, and possible the AND node preceeding it, 38: ** are trimmed off. The result of this routine should be 39: ** a very ordinary tree like you might see in some textbook. 40: ** 41: ** A fast not on the algorithm: the pointer 't' points to the 42: ** current node (the one which we are checking for a QLEND). 43: ** 's' points to 't's parent, and 'r' points to 's's parent; 44: ** 'r' is NULL at the top of the tree. 45: ** 46: ** This routine works correctly on trees with no QLEND in 47: ** the first place, returning the original tree. 48: ** 49: ** If there is a QLEND, it must be on the far right branch 50: ** of the tree, that is, the tree must be INGRES-canonical. 51: ** 52: ** Parameters: 53: ** qual -- the qualification to be trimmed. 54: ** 55: ** Returns: 56: ** A pointer to the new qualification. 57: ** NULL if the qualification was null once the 58: ** QLEND is stripped. 59: ** 60: ** Side Effects: 61: ** The tree pointed to by 'qual' may be modified. 62: ** 63: ** Called By: 64: ** protect() 65: ** appqual() 66: ** maybe others. 67: ** 68: ** Trace Flags: 69: ** none 70: ** 71: ** Syserrs: 72: ** none 73: */ 74: 75: QTREE * 76: trimqlend(qual) 77: QTREE *qual; 78: { 79: register QTREE *t; 80: register QTREE *s; 81: register QTREE *r; 82: 83: t = qual; 84: 85: /* check for the simple null qualification case */ 86: if (t == NULL || t->sym.type == QLEND) 87: return (NULL); 88: 89: /* scan tree for QLEND node */ 90: for (r = NULL, s = t; (t = t->right) != NULL; r = s, s = t) 91: { 92: if (t->sym.type == QLEND) 93: { 94: /* trim of QLEND and AND node */ 95: if (r == NULL) 96: { 97: /* only one AND -- return its operand */ 98: return (s->left); 99: } 100: 101: r->right = s->left; 102: break; 103: } 104: } 105: 106: /* return tree with final AND node and QLEND node pruned */ 107: return (qual); 108: } 109: /* 110: ** APPQUAL -- append qualification to tree 111: ** 112: ** The qualification is conjoined to the qualificaion of the 113: ** tree which is passed. 114: ** 115: ** Parameters: 116: ** qual -- a pointer to the qualification to be appended. 117: ** root -- a pointer to the tree to be appended to. 118: ** 119: ** Returns: 120: ** none 121: ** 122: ** Side Effects: 123: ** Both 'qual' ad 'root' may be modified. Note that 124: ** 'qual' is linked into 'root', and must be 125: ** retained. 126: ** 127: ** Requires: 128: ** tree() -- to create a new AND node. 129: ** 130: ** Called By: 131: ** view 132: ** protect 133: ** integrity 134: ** 135: ** Trace Flags: 136: ** 13 137: */ 138: 139: appqual(qual, root) 140: QTREE *qual; 141: QTREE *root; 142: { 143: register QTREE *p; 144: register QTREE *r; 145: 146: r = root; 147: # ifdef xQTR3 148: if (r == NULL) 149: syserr("appqual: NULL root"); 150: # endif 151: 152: /* 153: ** Find node before QLEND node 154: ** p points the node we are examining, r points to 155: ** it's parent. 156: */ 157: 158: while ((p = r->right) != NULL && p->sym.type != QLEND) 159: { 160: # ifdef xQTR3 161: if (p->sym.type != AND) 162: syserr("appqual: node %d", p->sym.type); 163: # endif 164: r = p; 165: } 166: 167: /* link in qualification */ 168: r->right = qual; 169: } 170: /* 171: ** FERROR -- issue fatal error message and abort query 172: ** 173: ** This call is almost exactly like 'error' (which is called), 174: ** but never returns: the return is done by 'reset'. Also, the 175: ** R_up pipe is flushed. 176: ** 177: ** Parameters: 178: ** errno -- the error number. 179: ** qmode -- the query mode to pass as $0, -1 if none. 180: ** vn -- the varno of the relation name to pass as 181: ** $1, -1 if none. 182: ** p1 to p5 -- the parameters $2 through $6 183: ** 184: ** Returns: 185: ** non-local (via reset()) 186: ** 187: ** Side Effects: 188: ** The error message is generated. 189: ** 190: ** Defines: 191: ** ferror 192: ** Qmdname -- the names of the various Qmodes. 193: ** 194: ** Requires: 195: ** error 196: ** reset 197: ** Pipe 198: ** rdpipe 199: ** wrpipe 200: ** Nullsync -- send null query on error -- defined 201: ** in main.c 202: ** nullsync -- routine to do same -- defined in 203: ** issue.c. 204: ** 205: ** Called By: 206: ** MANY 207: ** 208: ** Trace Flags: 209: ** none 210: ** 211: ** Diagnostics: 212: ** none of it's own. 213: ** 214: ** Syserrs: 215: ** none 216: */ 217: 218: extern struct pipfrmt Pipe; 219: char *Qmdname[] = 220: { 221: "[ERROR]", /* 0 = mdRETTERM */ 222: "RETRIEVE", /* 1 = mdRETR */ 223: "APPEND", /* 2 = mdAPP */ 224: "REPLACE", /* 3 = mdREPL */ 225: "DELETE", /* 4 = mdDEL */ 226: "", /* 5 = mdCOPY */ 227: "", /* 6 = mdCREATE */ 228: "", /* 7 = mdDESTROY */ 229: "", /* 8 = mdHELP */ 230: "", /* 9 = mdINDEX */ 231: "", /* 10 = mdMODIFY */ 232: "", /* 11 = mdPRINT */ 233: "", /* 12 = mdRANGE */ 234: "", /* 13 = mdSAVE */ 235: "DEFINE", /* 14 = mdDEFINE */ 236: "RET_UNIQUE", /* 15 = mdRET_UNI */ 237: "", /* 16 = mdVIEW */ 238: "", /* 17 = mdUPDATE */ 239: "", /* 18 = mdRESETREL */ 240: "", /* 19 = mdERIC */ 241: "", /* 20 = mdNETQRY */ 242: "", /* 21 = mdMOVEREL */ 243: "", /* 22 = mdPROT */ 244: "", /* 23 = mdINTEG */ 245: "", /* 24 = mdDCREATE */ 246: }; 247: 248: 249: ferror(errno, qmode, vn, p1, p2, p3, p4, p5, p6) 250: int errno; 251: int qmode; 252: int vn; 253: char *p1, *p2, *p3, *p4, *p5, *p6; 254: { 255: register char *x1; 256: register char *x2; 257: char xbuf[MAXNAME + 1]; 258: register int i; 259: extern char *trim_relname(); 260: extern int Nullsync; 261: struct retcode *rc, *nullsync(); 262: 263: /* flush the upward read pipe */ 264: rdpipe(P_SYNC, &Pipe, R_up); 265: 266: /* set up qmode and varno parameters */ 267: x1 = x2 = ""; 268: i = qmode; 269: if (i >= 0) 270: x1 = Qmdname[i]; 271: i = vn; 272: if (i >= 0) 273: smove(trim_relname(Rangev[i].relid), x2 = xbuf); 274: 275: /* issue the error message */ 276: error(errno, x1, x2, p1, p2, p3, p4, p5, p6, 0); 277: 278: /* issue null query if running Equel */ 279: if (Nullsync) 280: rc = nullsync(); 281: else 282: rc = NULL; 283: 284: /* sync to above */ 285: wrpipe(P_PRIME, &Pipe, 0, 0, 0); 286: if (rc != NULL) 287: wrpipe(P_NORM, &Pipe, W_up, rc, sizeof *rc); 288: wrpipe(P_END, &Pipe, W_up); 289: 290: /* return to main loop for next query */ 291: reset(); 292: } 293: /* 294: ** XERROR -- interface from need() to ferror() 295: ** 296: ** Parameters: 297: ** err -- the error number. 298: ** 299: ** Returns: 300: ** never 301: ** 302: ** Side Effects: 303: ** see ferror 304: */ 305: 306: xerror(err) 307: int err; 308: { 309: ferror(err, -1, -1, 0); 310: } 311: /* 312: ** LSETBIT -- set a bit in a domain set 313: ** 314: ** Parameters: 315: ** bitno -- the bit number to set (0 -> 127) 316: ** xset -- the set to set it in. 317: ** 318: ** Returns: 319: ** none 320: ** 321: ** Side Effects: 322: ** none 323: ** 324: ** Called By: 325: ** makedset() 326: ** 327: ** History: 328: ** 8/21/78 (eric) -- written. 329: */ 330: 331: lsetbit(bitno, xset) 332: int bitno; 333: int xset[8]; 334: { 335: register int b; 336: register int n; 337: register int *x; 338: 339: x = xset; 340: 341: b = bitno; 342: n = b >> LOG2WORDSIZE; 343: b &= WORDSIZE - 1; 344: 345: x[n] |= 1 << b; 346: } 347: /* 348: ** MERGEVAR -- merge variable numbers to link terms 349: ** 350: ** One specified variable gets mapped into another, effectively 351: ** merging those two variables. This is used for protection 352: ** and integrity, since the constraint read from the tree 353: ** must coincide with one of the variables in the query tree. 354: ** 355: ** Parameters: 356: ** va -- the variable which will dissappear. 357: ** vb -- the variable which 'va' gets mapped into. 358: ** root -- the root of the tree to map. 359: ** 360: ** Returns: 361: ** none 362: ** 363: ** Side Effects: 364: ** The tree pointed at by 'root' gets VAR and RESDOM 365: ** nodes mapped. 366: ** Range table entry for 'va' is deallocated. 367: ** The 'Remap' vector gets reset and left in an 368: ** undefined state. 369: ** 370: ** Requires: 371: ** clrrange -- to clear the 'Remap' vector (called with 372: ** a FALSE parameter, so 'Rangev' is not cleared). 373: ** mapvars -- to do the actual mapping. 374: ** Remap -- to define the mapping for mapvars(). 375: ** Rangev -- to check consistency and to clear the entry 376: ** for variable 'va'. 377: ** 378: ** Called By: 379: ** protect.c 380: ** integrity.c 381: ** 382: ** Trace Flags: 383: ** 16 384: ** 385: ** Diagnostics: 386: ** none 387: ** 388: ** Syserrs: 389: ** mergevar: range %d %d 390: ** Either 'va' or 'vb' was out of range. 391: ** mergevar: incon %s %s 392: ** The variables for 'va' and 'vb' must range 393: ** over the same relation. The strings are the 394: ** relation names if this does not hold. 395: ** mergevar: undef %d %d 396: ** The variables 'va' and 'vb' must both 397: ** be defined. 398: */ 399: 400: mergevar(va, vb, root) 401: int va; 402: int vb; 403: QTREE *root; 404: { 405: register int a; 406: register int b; 407: 408: a = va; 409: b = vb; 410: 411: # ifdef xQTR1 412: if (tTf(16, 0)) 413: { 414: printf("\nmergevar(%d->%d)", a, b); 415: treepr(root, NULL); 416: } 417: # endif 418: 419: /* 420: ** Insure that 'va' and 'vb' are consistant, that is, 421: ** that they both are in range, are defined, and range over 422: ** the same relation. 423: */ 424: 425: if (a < 0 || b < 0 || a >= MAXVAR + 1 || b >= MAXVAR + 1) 426: syserr("mergevar: range %d %d", a, b); 427: if (!Rangev[a].rused || !Rangev[b].rused) 428: syserr("mergevar: undef %d %d", a, b); 429: if (!bequal(Rangev[a].relid, Rangev[b].relid, MAXNAME) || 430: !bequal(Rangev[a].rowner, Rangev[b].rowner, 2)) 431: syserr("mergevar: incon %.14s %.14s", Rangev[a].relid, 432: Rangev[b].relid); 433: 434: /* 435: ** To do the actual mapping, we will set up 'Remap' and 436: ** call 'mapvars()'. This is because I am too lazy to 437: ** do it myself. 438: */ 439: 440: clrrange(FALSE); 441: Remap[a] = b; 442: mapvars(root); 443: 444: /* delete a from the range table */ 445: Rangev[a].rused = FALSE; 446: } 447: /* 448: ** MAKEZERO -- make a node with value 'zero' 449: ** 450: ** A node is created with value representing the zero value 451: ** for the specified type, that is, 0 for integers, 0.0 for 452: ** floats, and the blank string for chars. 453: ** 454: ** Parameters: 455: ** typ -- the node type. 456: ** 457: ** Returns: 458: ** a pointer to the zero node. 459: ** 460: ** Side Effects: 461: ** space is grabbed from Qbuf 462: ** 463: ** Requires: 464: ** Qbuf -- for space. 465: ** need() -- to get that space. 466: ** 467: ** History: 468: ** 11/21/78 (eric) -- written. 469: */ 470: 471: QTREE * 472: makezero(typ) 473: int typ; 474: { 475: register int l; 476: register struct symbol *s; 477: int symbuf[(sizeof *s + 4) / sizeof l]; 478: char *need(); 479: 480: s = (struct symbol *) &symbuf; 481: s->type = typ; 482: 483: switch (typ) 484: { 485: case INT: 486: s->len = l = 2; 487: i2deref(s->value) = 0; 488: break; 489: 490: case FLOAT: 491: s->len = l = 4; 492: f4deref(s->value) = 0.0; 493: break; 494: 495: case CHAR: 496: s->len = l = 2; 497: i2deref(s->value) = 0x2020; /* (two spaces) */ 498: break; 499: 500: default: 501: syserr("makezero: typ %d", typ); 502: } 503: 504: /* duplicate the node into Qbuf */ 505: l += sizeof *s; 506: s = (struct symbol *) need(Qbuf, l); 507: bmove(&symbuf, s, l); 508: return ((QTREE *) s); 509: }