1: # include "../ingres.h" 2: # include "../aux.h" 3: # include "../unix.h" 4: # include "../access.h" 5: # include "../tree.h" 6: # include "../symbol.h" 7: # include "decomp.h" 8: # include "../ovqp/ovqp.h" 9: 10: 11: /* 12: ** CALL_OVQP -- Routines which interface to the One Variable Query Processor. 13: ** 14: ** This file contains the routines associated with sending queries 15: ** and receiving results from OVQP. The interface to these routines is 16: ** still messy. Call_ovqp is given the query, mode, and result relation 17: ** as parameters and gets the source relation, and two flags 18: ** (Newq, Newr) as globals. The routines include: 19: ** 20: ** Call_ovqp -- Sends a One-var query to ovqp and flushes the pipe. 21: ** 22: ** Readresult -- Reads the result from a one-var query. 23: ** 24: ** Endovqp -- Informs ovqp that the query is over. Helps to synchronize 25: ** the batch file (if any). 26: ** 27: */ 28: 29: 30: int Qvptr; /* index into available Qvect space in ovqpnod() */ 31: struct symbol *Qvect[MAXNODES]; 32: char *Ovqpbuf; 33: 34: char D_ovqp70 = 1; /* used for loading only. forces call_ovqp70 to be 35: ** loaded instead of call_ovqp 36: */ 37: 38: 39: 40: call_ovqp(qtree, mode, resultnum) 41: struct querytree *qtree; 42: int mode; 43: int resultnum; 44: 45: /* 46: ** Call_ovqp -- send query down pipe to ovqp and flush pipe. 47: ** Inputs are: 48: ** mode retrieve, append, etc. 49: ** resultnum result relation id 50: ** qtree the query 51: ** Sourcevar (global) if >= 0 then source var 52: ** Newq send NEWQ symbol 53: ** Newr send NEWR symbol 54: */ 55: 56: { 57: register struct querytree *tree; 58: register int i; 59: char *rangename(); 60: struct symbol s; 61: extern int derror(); 62: extern int Batchupd; 63: extern struct descriptor Inddes; 64: char ovqpbuf[LBUFSIZE]; 65: struct descriptor *readopen(), *specopen(); 66: 67: # ifdef xOTM 68: if (tTf(76, 1)) 69: timtrace(7, 0); 70: # endif 71: 72: tree = qtree; 73: # ifdef xDTR1 74: if (tTf(8, -1)) 75: { 76: if (tTf(8, 0)) 77: printf("CALL_OVQP-\n"); 78: if (tTf(8, 1)) 79: { 80: if (Newq) 81: printree(tree, "new query to ovqp"); 82: else 83: printf("query same as previous\n"); 84: } 85: if (tTf(8, 2)) 86: { 87: printf("Sourcevar=%d\t", Sourcevar); 88: if (Sourcevar >= 0) 89: printf("relid=%s\t", rangename(Sourcevar)); 90: if (resultnum >= 0) 91: printf("Resultname=%s", rnum_convert(resultnum)); 92: if (((struct qt_root *)tree)->rootuser) 93: printf(", userqry"); 94: printf("\n"); 95: } 96: } 97: # endif 98: 99: 100: 101: /* assign mode of this query */ 102: Ov_qmode = mode; 103: 104: if (Newr) 105: { 106: Newr = FALSE; 107: } 108: 109: if (resultnum >= 0) 110: Result = specopen(resultnum); 111: else 112: Result = NULL; 113: 114: if (Sourcevar >= 0) 115: Source = readopen(Sourcevar); 116: else 117: Source = NULL; 118: 119: /* assume this will be direct update */ 120: Userqry = Buflag = FALSE; 121: 122: if (((struct qt_root *)tree)->rootuser) 123: { 124: Userqry = TRUE; 125: /* handle batch file */ 126: if (Result && Ov_qmode != mdRETR) 127: { 128: if (Batchupd || Result->relindxd > 0) 129: { 130: if (Bopen == 0) 131: { 132: if (Result->relindxd > 0) 133: opencatalog("indexes", 0); 134: if (i = openbatch(Result, &Inddes, Ov_qmode)) 135: syserr("call_ovqp:opn batch %d", i); 136: Bopen = TRUE; 137: } 138: Buflag = TRUE; 139: } 140: } 141: } 142: 143: /* now write the query list itself */ 144: if (Newq) 145: { 146: Ovqpbuf = ovqpbuf; 147: initbuf(Ovqpbuf, LBUFSIZE, LISTFULL, &derror); 148: Qvptr = 0; 149: Alist = Bylist = Qlist = Tlist = NULL; 150: Targvc = ((struct qt_root *)tree)->lvarc; 151: Qualvc = bitcnt(((struct qt_root *)tree)->rvarm); 152: Agcount = 0; 153: 154: if (tree->sym.type == AGHEAD) 155: { 156: Alist = &Qvect[0]; 157: if (tree->left->sym.type == BYHEAD) 158: { 159: mklist(tree->left->right); 160: ovqpnod(tree->left); /* BYHEAD node */ 161: Bylist = &Qvect[Qvptr]; 162: mklist(tree->left->left); 163: } 164: else 165: mklist(tree->left); 166: } 167: else 168: { 169: if (tree->left->sym.type != TREE) 170: { 171: Tlist = &Qvect[0]; 172: mklist(tree->left); 173: } 174: } 175: 176: /* now for the qualification */ 177: ovqpnod(tree); /* ROOT node */ 178: 179: if (tree->right->sym.type != QLEND) 180: { 181: Qlist = &Qvect[Qvptr]; 182: mklist(tree->right); 183: } 184: ovqpnod(Qle); /* QLEND node */ 185: } 186: 187: /* Now call ovqp */ 188: if (strategy()) 189: { 190: 191: # ifdef xOTM 192: if (tTf(76, 2)) 193: timtrace(9, 0); 194: # endif 195: 196: i = scan(); /* scan the relation */ 197: 198: # ifdef xOTM 199: if (tTf(76, 2)) 200: timtrace(10, 0); 201: # endif 202: 203: } 204: else 205: i = EMPTY; 206: 207: # ifdef xOTM 208: if (tTf(76, 1)) 209: timtrace(8, 0); 210: # endif 211: 212: 213: /* return result of query */ 214: return (i == NONEMPTY); /* TRUE if tuple satisfied */ 215: } 216: 217: 218: 219: struct retcode Retcode; /* return code structure */ 220: 221: endovqp(ack) 222: int ack; 223: 224: /* 225: ** Endovqp -- Inform ovqp that processing is complete. "Ack" indicates 226: ** whether to wait for an acknowledgement from ovqp. The overall 227: ** mode of the query is sent followed by an EXIT command. 228: ** 229: ** Ovqp decides whether to use batch update or not. If ack == ACK 230: ** then endovqp will read a RETVAL symbol from ovqp and return 231: ** a token which specifies whether to call the update processor or not. 232: */ 233: 234: { 235: register int i, j; 236: extern int Qry_mode; 237: 238: if (ack != RUBACK) 239: { 240: if (Equel && Qry_mode == mdRETTERM) 241: equeleol(EXIT); /* signal end of retrieve to equel process */ 242: } 243: 244: i = NOUPDATE; 245: 246: if (ack == ACK) 247: { 248: if (Bopen) 249: { 250: closebatch(); 251: Bopen = FALSE; 252: i = UPDATE; 253: } 254: } 255: else 256: { 257: if (Bopen) 258: { 259: rmbatch(); 260: Bopen = FALSE; 261: } 262: } 263: 264: Retcode.rc_tupcount = Tupsfound; 265: 266: closecatalog(FALSE); 267: 268: return (i); 269: } 270: 271: 272: 273: ovqpnod(n) 274: struct querytree *n; 275: 276: /* 277: ** Add node n to ovqp's list 278: */ 279: 280: { 281: register struct symbol *s; 282: register struct querytree *q; 283: register int i; 284: extern struct querytree *ckvar(), *need(); 285: 286: q = n; 287: s = &q->sym; 288: 289: /* VAR nodes must be specially processed */ 290: if (s->type == VAR) 291: { 292: /* locate currently active VAR */ 293: q = ckvar(q); 294: 295: /* Allocate an ovqp var node for the VAR */ 296: s = (struct symbol *) need(Ovqpbuf, 8); 297: s->len = 6; 298: s->value[0] = ((struct qt_var *)q)->attno; 299: ((struct qt_v *)s)->vtype = ((struct qt_var *)q)->frmt; 300: ((struct qt_v *)s)->vlen = ((struct qt_var *)q)->frml; 301: 302: /* If VAR has been substituted for, get value */ 303: if (((struct qt_var *)q)->valptr) 304: { 305: 306: /* This is a substituted variable */ 307: if (((struct qt_var *)q)->varno == Sourcevar) 308: syserr("ovqpnod:bd sub %d,%d", ((struct qt_var *)q)->varno, Sourcevar); 309: 310: s->type = S_VAR; 311: ((struct qt_v *)s)->vpoint = (int *) ((struct qt_var *)q)->valptr; 312: } 313: else 314: { 315: /* Var for one variable query */ 316: if (((struct qt_var *)q)->varno != Sourcevar) 317: syserr("ovqpnod:src var %d,%d", ((struct qt_var *)q)->varno, Sourcevar); 318: s->type = VAR; 319: if (((struct qt_var *)q)->attno) 320: ((struct qt_v *)s)->vpoint = (int *) (Intup + Source->reloff[((struct qt_var *)q)->attno]); 321: else 322: ((struct qt_v *)s)->vpoint = (int *) &Intid; 323: } 324: 325: } 326: if (s->type == AOP) 327: Agcount++; 328: 329: /* add symbol to list */ 330: if (Qvptr > MAXNODES - 1) 331: ov_err(NODOVFLOW); 332: Qvect[Qvptr++] = s; 333: } 334: 335: 336: readagg_result(result) 337: struct querytree *result[]; 338: 339: /* 340: ** 341: */ 342: 343: { 344: register struct querytree **r, *aop; 345: register int i; 346: 347: 348: Tend = Outtup; 349: r = result; 350: 351: while (aop = *r++) 352: { 353: i = aop->sym.len & I1MASK; 354: 355: if (aop->sym.type == CHAR) 356: pad(Tend, i); 357: 358: bmove(Tend, aop->sym.value, i); 359: 360: Tend += i; 361: # ifdef xDTR1 362: if (tTf(8, 3)) 363: writenod(aop); 364: # endif 365: } 366: } 367: 368: 369: ov_err(code) 370: int code; 371: { 372: derror(code); 373: } 374: 375: 376: struct descriptor *openindex(name) 377: char *name; 378: { 379: register struct descriptor *d; 380: register int varno; 381: struct descriptor *readopen(); 382: 383: varno = SECINDVAR; 384: Rangev[varno].relnum = rnum_assign(name); 385: d = readopen(varno); 386: return (d); 387: } 388: 389: 390: /* 391: ** Use "closer()" for closing relations. See 392: ** desc_close in openrs.c for details. 393: */ 394: extern int closer(); 395: int (*Des_closefunc)() = closer; 396: 397: init_decomp() 398: { 399: static struct accbuf xtrabufs[12]; 400: 401: acc_addbuf(xtrabufs, 12); 402: } 403: 404: 405: startdecomp() 406: { 407: /* called at the start of each user query */ 408: Retcode.rc_tupcount = 0; 409: initrange(); 410: rnum_init(); 411: startovqp(); 412: } 413: 414: 415: 416: /* 417: ** Files_avail -- returns how many file descriptors are available 418: ** for decomposition. For decomp combined with ovqp, the fixed 419: ** overhead for files is: 420: ** 421: ** 4 -- pipes 422: ** 1 -- relation relation 423: ** 1 -- attribute relation 424: ** 1 -- standard output 425: ** 1 -- concurrency 426: ** 1 -- indexes relation 427: ** 428: ** Optional overhead is: 429: ** 430: ** 1 -- for Equel data pipe 431: ** 1 -- for batch file on updates 432: */ 433: 434: files_avail(mode) 435: int mode; 436: { 437: register int i; 438: 439: i = MAXFILES - 9; 440: if (Equel) 441: i--; 442: if (mode != mdRETR) 443: i--; 444: return (i); 445: }