1: # include <ingres.h> 2: # include <aux.h> 3: # include <catalog.h> 4: # include <symbol.h> 5: # include <tree.h> 6: # include "../decomp/globs.h" 7: # include "strategy.h" 8: # include <btree.h> 9: # include <sccs.h> 10: # include <errors.h> 11: 12: SCCSID(@(#)strategy.c 8.4 2/8/85) 13: 14: /* 15: ** STRATEGY 16: ** 17: ** Attempts to limit access scan to less than the entire De.ov_source 18: ** relation by finding a key which can be used for associative 19: ** access to the De.ov_source reln or an index thereon. The key is 20: ** constructed from domain-value specifications found in the 21: ** clauses of the qualification list using sub-routine findsimp 22: ** in findsimp.c and other subroutines in file key.c 23: */ 24: 25: strategy() 26: { 27: register int i, j, allexact; 28: struct accessparam sourceparm, indexparm; 29: struct index itup, rtup; 30: struct key lowikey[MAXKEYS+1], highikey[MAXKEYS+1]; 31: struct key lowbkey[MAXKEYS+1], highbkey[MAXKEYS+1]; 32: register DESC *d; 33: DESC *openindex(); 34: extern DESC Inddes; 35: char *tp; 36: long l_lid[MAXLID], h_lid[MAXLID]; 37: int keytype; 38: long last_lid(); 39: long page, l, t; 40: int lidsize; 41: struct locator tidloc; 42: extern int Btree_fd; 43: 44: # ifdef xOTR1 45: if (tTf(70, 0)) 46: printf("STRATEGY\tSource=%.12s\tNewq = %d\n", 47: De.ov_source ? De.ov_source->reldum.relid : "(none)", 48: De.de_newq); 49: # endif 50: 51: while (De.de_newq) /* if De.de_newq=TRUE then compute a new strategy */ 52: /* NOTE: This while loop is executed only once */ 53: { 54: De.ov_scanr = De.ov_source; 55: 56: if (!De.ov_scanr) 57: return (1); /* return immediately if there is no source relation */ 58: 59: De.ov_fmode = NOKEY; /* assume a find mode with no key */ 60: 61: if (!De.ov_qlist) 62: break; /* if no qualification then you must scan entire rel */ 63: /* 64: ** Here we check for the special condition 65: ** of a where clause consisting only of a tid. 66: */ 67: if (tid_only_test()) 68: return(1); 69: 70: /* copy structure of source relation into sourceparm */ 71: paramd(De.ov_source, &sourceparm); 72: 73: /* if source is unkeyed and has no sec index then give up */ 74: if (sourceparm.mode == NOKEY && De.ov_source->reldum.relindxd <= 0 && !De.ov_source->reldum.reldim) 75: break; 76: 77: /* find all simple clauses if any */ 78: if (!findsimps()) 79: break; /* break if there are no simple clauses */ 80: 81: /* Four steps are now performed to try and find a key. 82: ** First if the relation is hashed then an exact key is search for 83: ** 84: ** Second if there are secondary indexes, then a search is made 85: ** for an exact key. If that fails then a check is made for 86: ** a range key. The result of the rangekey check is saved. 87: ** 88: ** A step to check for possible use of Btrees is made here, 89: ** although in actuality, an exact btreekey search is used 90: ** after an exact range key search but before a range key search. 91: ** A BTree range search is used only as a last alternative 92: ** to a no key search. 93: ** 94: ** Third if the relation is an ISAM a check is made for 95: ** an exact key or a range key. 96: ** 97: ** Fourth if there is a secondary index, then if step two 98: ** found a key, that key is used. 99: ** 100: ** Lastly, give up and scan the entire relation 101: */ 102: 103: /* step one. Try to find exact key on primary */ 104: if (exactkey(&sourceparm, De.ov_lkey_struct)) 105: { 106: De.ov_fmode = EXACTKEY; 107: break; 108: } 109: 110: /* step two. If there is an index, try to find an exactkey on one of them */ 111: if (De.ov_source->reldum.relindxd > 0) 112: { 113: 114: opencatalog("indexes", OR_READ); 115: setkey(&Inddes, &itup, De.ov_source->reldum.relid, IRELIDP); 116: setkey(&Inddes, &itup, De.ov_source->reldum.relowner, IOWNERP); 117: if (i = find(&Inddes, EXACTKEY, &De.ov_lotid, &De.ov_hitid, (char *)&itup)) 118: syserr("strategy:find indexes %d", i); 119: 120: while (!(i = get(&Inddes, &De.ov_lotid, &De.ov_hitid, (char *)&itup, NXTTUP))) 121: { 122: # ifdef xOTR1 123: if (tTf(70, 3)) 124: printup(&Inddes, (char *)&itup); 125: # endif 126: if (!bequal(itup.irelidp, De.ov_source->reldum.relid, MAXNAME) || 127: !bequal(itup.iownerp, De.ov_source->reldum.relowner, 2)) 128: continue; 129: parami(&itup, &indexparm); 130: if (exactkey(&indexparm, De.ov_lkey_struct)) 131: { 132: De.ov_fmode = EXACTKEY; 133: d = openindex(itup.irelidi); 134: /* temp check for 6.0 index */ 135: if ((int) d->reldum.relindxd == -1) 136: ov_err(BADSECINDX); 137: De.ov_scanr = d; 138: break; 139: } 140: if (De.ov_fmode == LRANGEKEY) 141: continue; /* a range key on a s.i. has already been found */ 142: if (allexact = rangekey(&indexparm, lowikey, highikey)) 143: { 144: bmove((char *)&itup, (char *)&rtup, sizeof itup); /* save tuple */ 145: De.ov_fmode = LRANGEKEY; 146: } 147: } 148: if (i < 0) 149: syserr("stragery:bad get from index-rel %d", i); 150: /* If an exactkey on a secondary index was found, look no more. */ 151: if (De.ov_fmode == EXACTKEY) 152: break; 153: } 154: 155: /* attempt to use Btree in aiding search */ 156: if (i = btreekey(lowbkey, highbkey)) 157: { 158: if (i > 0) 159: De.ov_fmode = BTREEKEY; 160: else if (De.ov_fmode != LRANGEKEY) 161: /* use range key search over btree range search */ 162: { 163: keytype = i; 164: De.ov_fmode = BTREERANGE; 165: } 166: } 167: 168: /* step three. Look for a range key on primary */ 169: if (i = rangekey(&sourceparm, De.ov_lkey_struct, De.ov_hkey_struct)) 170: { 171: if (i < 0) 172: De.ov_fmode = EXACTKEY; 173: else if (De.ov_fmode == BTREEKEY) 174: /* use exact btree search over range search */ 175: { 176: bmove((char *) lowbkey, (char *) De.ov_lkey_struct, sizeof lowbkey); 177: bmove((char *) highbkey, (char *) De.ov_hkey_struct, sizeof highbkey); 178: } 179: else 180: De.ov_fmode = LRANGEKEY; 181: break; 182: } 183: 184: if (De.ov_fmode == BTREEKEY) 185: { 186: bmove((char *) lowbkey, (char *) De.ov_lkey_struct, sizeof lowbkey); 187: bmove((char *) highbkey, (char *) De.ov_hkey_struct, sizeof highbkey); 188: break; 189: } 190: 191: /* last step. If a secondary index range key was found, use it */ 192: if (De.ov_fmode == LRANGEKEY) 193: { 194: if (allexact < 0) 195: De.ov_fmode = EXACTKEY; 196: d = openindex(rtup.irelidi); 197: /* temp check for 6.0 index */ 198: if ((int) d->reldum.relindxd == -1) 199: ov_err(BADSECINDX); 200: De.ov_scanr = d; 201: bmove((char *)lowikey, (char *)De.ov_lkey_struct, sizeof lowikey); 202: bmove((char *)highikey, (char *)De.ov_hkey_struct, sizeof highikey); 203: break; 204: } 205: 206: /* nothing will work. give up! */ 207: break; 208: 209: } 210: 211: /* check for De.de_newq = FALSE and no source relation */ 212: if (!De.ov_scanr) 213: return (1); 214: /* 215: ** At this point the strategy is determined. 216: ** 217: ** If De.ov_fmode is EXACTKEY then De.ov_lkey_struct contains 218: ** the pointers to the keys. 219: ** 220: ** If De.ov_fmode is LRANGEKEY then De.ov_lkey_struct contains 221: ** the pointers to the low keys and De.ov_hkey_struct 222: ** contains pointers to the high keys. 223: ** 224: ** If De.ov_fmode is BTREEKEY then De.ov_lkey_struct contains 225: ** pointers to the key lid. 226: ** 227: ** If De.ov_fmode is BTREERANGE then lowbkey contains pointers 228: ** to the low key lid and highbkey contains pointers to the 229: ** high key lid. 230: ** 231: ** If De.ov_fmode is NOKEY, then a full scan will be performed 232: */ 233: # ifdef xOTR1 234: if (tTf(70, -1)) 235: printf("De.ov_fmode= %d\n",De.ov_fmode); 236: # endif 237: 238: if (De.ov_fmode == BTREERANGE) 239: /* requires special type of search to limit tid scan */ 240: { 241: for (i = 0; i < De.ov_scanr->reldum.reldim; ++i) 242: { 243: l_lid[i] = 0; 244: h_lid[i] = 0; 245: } 246: lidsize = LIDSIZE * De.ov_scanr->reldum.reldim; 247: /* get low lids */ 248: if (keytype == -1 || keytype == -3) 249: { 250: tp = De.ov_keyl + De.ov_scanr->reldum.relwid - lidsize; 251: bmove(l_lid, tp, lidsize); 252: setallkey(lowbkey, De.ov_keyl); 253: bmove(tp, l_lid, lidsize); 254: } 255: /* get high lids */ 256: if (keytype == -2 || keytype == -3) 257: { 258: tp = De.ov_keyh + De.ov_scanr->reldum.relwid - lidsize; 259: bmove(h_lid, tp, lidsize); 260: setallkey(highbkey, De.ov_keyh); 261: bmove(tp, h_lid, lidsize); 262: } 263: Btree_fd = De.ov_scanr->btree_fd; 264: /* scan through lids to fill in unprovided lids and to check 265: ** for lids that are too big 266: */ 267: page = RT; 268: for (i = 0; i < De.ov_scanr->reldum.reldim; ++i) 269: { 270: if (l_lid[i] <= 0) 271: l_lid[i] = 1; 272: l = last_lid(page) - 1; 273: if (h_lid < 0) 274: return(0); 275: if (!h_lid[i] || h_lid[i] > l) 276: h_lid[i] = l; 277: if ((t = get_tid(page, h_lid[i], &tidloc)) < 0) 278: syserr("bad gettid in strategy, lid = %ld\n", h_lid[i]); 279: page = t; 280: } 281: /* check whether lo > hi */ 282: for (i = 0; i < De.ov_scanr->reldum.reldim; ++i) 283: if (l_lid[i] < h_lid[i]) 284: break; 285: else if (l_lid[i] > h_lid[i]) 286: return(0); 287: # ifdef xOTR1 288: if (tTf(70,0)) 289: for (i = 0 ; i < De.ov_scanr->reldum.reldim; ++i) 290: printf("hi = %ld, lo = %ld\n", h_lid[i], l_lid[i]); 291: # endif 292: /* find the smallest and largest possible tids of the lids 293: ** within the provided range */ 294: btreerange(De.ov_scanr, l_lid, h_lid, &De.ov_lotid, &De.ov_hitid); 295: } 296: else 297: { 298: /* set up the key tuples */ 299: if (De.ov_fmode != NOKEY) 300: { 301: if (setallkey(De.ov_lkey_struct, De.ov_keyl)) 302: return (0); /* query false. There is a simple 303: ** clause which can never be satisfied. 304: ** These simple clauses can be choosey! 305: */ 306: } 307: 308: if (i = find(De.ov_scanr, De.ov_fmode, &De.ov_lotid, &De.ov_hitid, De.ov_keyl)) 309: syserr("strategy:find1 %.12s, %d", De.ov_scanr->reldum.relid, i); 310: 311: if (De.ov_fmode == LRANGEKEY) 312: { 313: setallkey(De.ov_hkey_struct, De.ov_keyh); 314: if (i = find(De.ov_scanr, HRANGEKEY, &De.ov_lotid, &De.ov_hitid, De.ov_keyh)) 315: syserr("strategy:find2 %.12s, %d", De.ov_scanr->reldum.relid, i); 316: } 317: } 318: 319: # ifdef xOTR1 320: if (tTf(70, 1)) 321: { 322: printf("Lo"); 323: dumptid(&De.ov_lotid); 324: printf("Hi"); 325: dumptid(&De.ov_hitid); 326: } 327: # endif 328: 329: return (1); 330: }