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(@(#)util.c 8.1 12/31/84) 9: 10: /* 11: ** TRIMQLEND -- trim QLEND node off of qualification 12: ** 13: ** The QLEND node, and possible the AND node preceeding it, 14: ** are trimmed off. The result of this routine should be 15: ** a very ordinary tree like you might see in some textbook. 16: ** 17: ** A fast not on the algorithm: the pointer 't' points to the 18: ** current node (the one which we are checking for a QLEND). 19: ** 's' points to 't's parent, and 'r' points to 's's parent; 20: ** 'r' is NULL at the top of the tree. 21: ** 22: ** This routine works correctly on trees with no QLEND in 23: ** the first place, returning the original tree. 24: ** 25: ** If there is a QLEND, it must be on the far right branch 26: ** of the tree, that is, the tree must be INGRES-canonical. 27: ** 28: ** Parameters: 29: ** qual -- the qualification to be trimmed. 30: ** 31: ** Returns: 32: ** A pointer to the new qualification. 33: ** NULL if the qualification was null once the 34: ** QLEND is stripped. 35: ** 36: ** Side Effects: 37: ** The tree pointed to by 'qual' may be modified. 38: ** 39: ** Trace Flags: 40: ** none 41: */ 42: 43: QTREE * 44: trimqlend(qual) 45: QTREE *qual; 46: { 47: register QTREE *t; 48: register QTREE *s; 49: register QTREE *r; 50: 51: t = qual; 52: 53: /* check for the simple null qualification case */ 54: if (t == NULL || t->sym.type == QLEND) 55: return (NULL); 56: 57: /* scan tree for QLEND node */ 58: for (r = NULL, s = t; (t = t->right) != NULL; r = s, s = t) 59: { 60: if (t->sym.type == QLEND) 61: { 62: /* trim of QLEND and AND node */ 63: if (r == NULL) 64: { 65: /* only one AND -- return its operand */ 66: return (s->left); 67: } 68: 69: r->right = s->left; 70: break; 71: } 72: } 73: 74: /* return tree with final AND node and QLEND node pruned */ 75: return (qual); 76: } 77: /* 78: ** APPQUAL -- append qualification to tree 79: ** 80: ** The qualification is conjoined to the qualificaion of the 81: ** tree which is passed. 82: ** 83: ** Parameters: 84: ** qual -- a pointer to the qualification to be appended. 85: ** root -- a pointer to the tree to be appended to. 86: ** 87: ** Returns: 88: ** none 89: ** 90: ** Side Effects: 91: ** Both 'qual' ad 'root' may be modified. Note that 92: ** 'qual' is linked into 'root', and must be 93: ** retained. 94: ** 95: ** Trace Flags: 96: ** 13 97: */ 98: 99: appqual(qual, root) 100: QTREE *qual; 101: QTREE *root; 102: { 103: register QTREE *p; 104: register QTREE *r; 105: 106: r = root; 107: # ifdef xQTR3 108: if (r == NULL) 109: syserr("appqual: NULL root"); 110: # endif 111: 112: /* 113: ** Find node before QLEND node 114: ** p points the node we are examining, r points to 115: ** it's parent. 116: */ 117: 118: while ((p = r->right) != NULL && p->sym.type != QLEND) 119: { 120: # ifdef xQTR3 121: if (p->sym.type != AND) 122: syserr("appqual: node %d", p->sym.type); 123: # endif 124: r = p; 125: } 126: 127: /* link in qualification */ 128: r->right = qual; 129: } 130: /* 131: ** QMERROR -- issue fatal error message and abort query 132: ** 133: ** This call is almost exactly like 'error' (which is called), 134: ** but never returns: the return is done by 'reset'. Also, the 135: ** R_up pipe is flushed. 136: ** 137: ** Parameters: 138: ** errno -- the error number. 139: ** qmode -- the query mode to pass as $0, -1 if none. 140: ** vn -- the varno of the relation name to pass as 141: ** $1, -1 if none. 142: ** p1 to p5 -- the parameters $2 through $6 143: ** 144: ** Returns: 145: ** non-local (via reset()) 146: ** 147: ** Side Effects: 148: ** The error message is generated. 149: ** 150: ** Trace Flags: 151: ** none 152: */ 153: 154: char *QmdName[] = 155: { 156: "[ERROR]", /* 0 = mdRETTERM */ 157: "RETRIEVE", /* 1 = mdRETR */ 158: "APPEND", /* 2 = mdAPP */ 159: "REPLACE", /* 3 = mdREPL */ 160: "DELETE", /* 4 = mdDEL */ 161: "", /* 5 = mdCOPY */ 162: "", /* 6 = mdCREATE */ 163: "", /* 7 = mdDESTROY */ 164: "", /* 8 = mdHELP */ 165: "", /* 9 = mdINDEX */ 166: "", /* 10 = mdMODIFY */ 167: "", /* 11 = mdPRINT */ 168: "", /* 12 = mdRANGE */ 169: "", /* 13 = mdSAVE */ 170: "DEFINE", /* 14 = mdDEFINE */ 171: "RET_UNIQUE", /* 15 = mdRET_UNI */ 172: "", /* 16 = mdVIEW */ 173: "", /* 17 = mdUPDATE */ 174: "", /* 18 = mdRESETREL */ 175: "", /* 19 = mdERIC */ 176: "", /* 20 = mdNETQRY */ 177: "", /* 21 = mdMOVEREL */ 178: "", /* 22 = mdPROT */ 179: "", /* 23 = mdINTEG */ 180: "", /* 24 = mdDCREATE */ 181: }; 182: 183: 184: qmerror(errno, qmode, vn, p1, p2, p3, p4, p5, p6) 185: int errno; 186: int qmode; 187: int vn; 188: char *p1, *p2, *p3, *p4, *p5, *p6; 189: { 190: register char *x1; 191: register char *x2; 192: char xbuf[MAXNAME + 1]; 193: register int i; 194: extern char *trim_relname(); 195: 196: /* set up qmode and varno parameters */ 197: x1 = x2 = ""; 198: i = qmode; 199: if (i >= 0) 200: x1 = QmdName[i]; 201: i = vn; 202: if (i >= 0) 203: smove(trim_relname(Qt.qt_rangev[i].rngvdesc->reldum.relid), 204: x2 = xbuf); 205: 206: /* issue the error message and exit */ 207: error(errno, x1, x2, p1, p2, p3, p4, p5, p6, 0); 208: syserr("qmerror"); 209: } 210: /* 211: ** LSETBIT -- set a bit in a domain set 212: ** 213: ** Parameters: 214: ** bitno -- the bit number to set (0 -> 127) 215: ** xset -- the set to set it in. 216: ** 217: ** Returns: 218: ** none 219: ** 220: ** Side Effects: 221: ** none 222: */ 223: 224: lsetbit(bitno, xset) 225: int bitno; 226: int xset[8]; 227: { 228: register int b; 229: register int n; 230: register int *x; 231: 232: x = xset; 233: 234: b = bitno; 235: n = b >> LOG2WORDSIZE; 236: b &= WORDSIZE - 1; 237: 238: x[n] |= 1 << b; 239: } 240: /* 241: ** MERGEVAR -- merge variable numbers to link terms 242: ** 243: ** One specified variable gets mapped into another, effectively 244: ** merging those two variables. This is used for protection 245: ** and integrity, since the constraint read from the tree 246: ** must coincide with one of the variables in the query tree. 247: ** 248: ** Parameters: 249: ** va -- the variable which will dissappear. 250: ** vb -- the variable which 'va' gets mapped into. 251: ** root -- the root of the tree to map. 252: ** 253: ** Returns: 254: ** none 255: ** 256: ** Side Effects: 257: ** The tree pointed at by 'root' gets VAR and RESDOM 258: ** nodes mapped. 259: ** Range table entry for 'va' is deallocated. 260: ** The 'Qt.qt_remap' vector gets reset and left in an 261: ** undefined state. 262: ** 263: ** Trace Flags: 264: ** 72 265: */ 266: 267: mergevar(a, b, root) 268: register int a; 269: register int b; 270: QTREE *root; 271: { 272: register int i; 273: 274: # ifdef xQTR1 275: if (tTf(72, 0)) 276: { 277: printf("\nmergevar(%d->%d)", a, b); 278: treepr(root, NULL); 279: } 280: # endif 281: 282: /* 283: ** Insure that 'a' and 'b' are consistant, that is, 284: ** that they both are in range, are defined, and range over 285: ** the same relation. 286: */ 287: 288: if (a < 0 || b < 0 || a >= MAXVAR + 1 || b >= MAXVAR + 1) 289: syserr("mergevar: range %d %d", a, b); 290: if (Qt.qt_rangev[a].rngvdesc == NULL || Qt.qt_rangev[b].rngvdesc == NULL) 291: syserr("mergevar: undef %d %d", a, b); 292: if (!bequal(Qt.qt_rangev[a].rngvdesc->reldum.relid, 293: Qt.qt_rangev[b].rngvdesc->reldum.relid, MAXNAME) || 294: !bequal(Qt.qt_rangev[a].rngvdesc->reldum.relowner, 295: Qt.qt_rangev[b].rngvdesc->reldum.relowner, 2)) 296: { 297: syserr("mergevar: incon %.14s %.14s", 298: Qt.qt_rangev[a].rngvdesc->reldum.relid, 299: Qt.qt_rangev[b].rngvdesc->reldum.relid); 300: } 301: 302: /* 303: ** To do the actual mapping, we will set up 'Qt.qt_remap' and 304: ** call 'mapvars()'. This is because I am too lazy to 305: ** do it myself. 306: */ 307: 308: for (i = 0; i < MAXRANGE; i++) 309: Qt.qt_remap[i] = i; 310: Qt.qt_remap[a] = b; 311: mapvars(root); 312: 313: /* delete a from the range table */ 314: declare(a, NULL); 315: } 316: /* 317: ** MAKEZERO -- make a node with value 'zero' 318: ** 319: ** A node is created with value representing the zero value 320: ** for the specified type, that is, 0 for integers, 0.0 for 321: ** floats, and the blank string for chars. 322: ** 323: ** Parameters: 324: ** typ -- the node type. 325: ** 326: ** Returns: 327: ** a pointer to the zero node. 328: ** 329: ** Side Effects: 330: ** space is grabbed from Qbuf 331: */ 332: 333: QTREE * 334: makezero(typ) 335: int typ; 336: { 337: register int l; 338: register QTREE *s; 339: int symbuf[(sizeof *s) / sizeof l]; /*word aligned*/ 340: extern char *need(); 341: 342: s = (QTREE *) symbuf; 343: s->sym.type = typ; 344: 345: switch (typ) 346: { 347: case INT: 348: s->sym.len = l = 2; 349: s->sym.value.sym_data.i2type = 0; 350: break; 351: 352: case FLOAT: 353: s->sym.len = l = 4; 354: s->sym.value.sym_data.f4type = 0.0; 355: break; 356: 357: case CHAR: 358: s->sym.len = l = 2; 359: s->sym.value.sym_data.i2type = ' '; /* (two spaces) */ 360: break; 361: 362: default: 363: syserr("makezero: typ %d", typ); 364: } 365: 366: /* duplicate the node into Qbuf */ 367: l += 2 + 2 * QT_HDR_SIZ; /* size of type + len + left + right */ 368: s = (QTREE *) need(Qbuf, l); 369: bmove(symbuf, s, l); 370: return (s); 371: }