|
|
1.1 ! root 1: # include <pv.h> ! 2: # include <ingres.h> ! 3: # include <aux.h> ! 4: # include <access.h> ! 5: # include <batch.h> ! 6: # include <lock.h> ! 7: # include <fileio.h> ! 8: # include <opsys.h> ! 9: # include <func.h> ! 10: # include <sccs.h> ! 11: ! 12: SCCSID(@(#)nmodify.c 7.2 6/4/83) ! 13: ! 14: extern short tTdbu[]; ! 15: extern int modify(); ! 16: extern int null_fn(); ! 17: ! 18: struct fn_def ModifyFn = ! 19: { ! 20: "MODIFY", ! 21: modify, ! 22: null_fn, ! 23: null_fn, ! 24: NULL, ! 25: 0, ! 26: tTdbu, ! 27: 100, ! 28: 'Z', ! 29: 0 ! 30: }; ! 31: ! 32: /* ! 33: ** MODIFY -- converts any relation to the specified ! 34: ** storage structure ! 35: ** ! 36: ** arguments: ! 37: ** 0 - relation name ! 38: ** 1 - storage structure ("heap", "cheap", "hash", "chash", ! 39: ** "isam", "cisam", "btree") ! 40: ** 2 - "name" for attribute names, or "num" for numbers ! 41: ** 3 - key1 ! 42: ** 4 - key2 ! 43: ** . ! 44: ** . ! 45: ** i - null ! 46: ** i+1 - option name (e.g., "fillfactor") ! 47: ** i+2 - option value ! 48: ** . ! 49: ** . ! 50: ** ! 51: ** If all the options default, parameter i -> pc are omitted. ! 52: ** If no keys are provided, parameter 2 is omitted. ! 53: ** ! 54: ** History: ! 55: ** 12/28/78 (rse) -- added descending sort option ! 56: ** 9/12/78 -- (marc) modified to give error message ! 57: ** 5519 when someone tries to modify a view. ! 58: ** For this I split the openr mode 0 into 2, ! 59: ** mode -1 then -2. ! 60: ** 9/25/78 -- (marc) 2 openr's replaced by one ! 61: ** as view error code put in openr ! 62: ** ! 63: */ ! 64: ! 65: int F_fac, Mn_pages, Mx_pages; ! 66: ! 67: struct modtab ! 68: { ! 69: char *type; ! 70: char newrelspec; ! 71: char yeskeys; ! 72: char sortit; ! 73: char yes_seq; ! 74: int f_fac; ! 75: int mn_pages; ! 76: int mx_pages; ! 77: }; ! 78: ! 79: ! 80: struct modtab Modtab[] = ! 81: { ! 82: /* type spec keys sort seq ffac min max */ ! 83: ! 84: "heap", M_HEAP, FALSE, FALSE, FALSE, 0, 0, 0, ! 85: "cheap", -M_HEAP,FALSE, FALSE, FALSE, 0, 0, 0, ! 86: "hash", M_HASH, TRUE, TRUE, FALSE, 50, 10, -1, ! 87: "chash", -M_HASH,TRUE, TRUE, FALSE, 75, 1, -1, ! 88: "isam", M_ISAM, TRUE, TRUE, FALSE, 80, 0, 0, ! 89: "cisam", -M_ISAM,TRUE, TRUE, FALSE, 100, 0, 0, ! 90: "btree", M_BTREE, TRUE, TRUE, FALSE, 66, 0, 0, ! 91: "heapsort", M_HEAP, TRUE, TRUE, TRUE, 0, 0, 0, ! 92: "cheapsort", -M_HEAP,TRUE, TRUE, TRUE, 0, 0, 0, ! 93: "truncated", M_TRUNC,FALSE, FALSE, FALSE, 0, 0, 0, ! 94: 0 ! 95: }; ! 96: ! 97: struct mod_info ! 98: { ! 99: char outfile[MAXNAME + 4]; /* result file filled by ksort */ ! 100: char formfile[MAXNAME + 4]; /* file with descriptor for ksort */ ! 101: char infile[MAXNAME + 4]; /* input file for ksort (relation itself */ ! 102: char reltemp[MAXNAME + 4]; /* file holding new relation */ ! 103: char spfile[MAXNAME + 4], spflag; /* isam spool file for overflow */ ! 104: }; ! 105: ! 106: struct mod_info Mod_info; ! 107: ! 108: modify(pc, pv) ! 109: int pc; ! 110: PARM *pv; ! 111: { ! 112: register int i; ! 113: register char *rname; ! 114: register struct modtab *mp; ! 115: int sorted; ! 116: DESC dold, dnew; ! 117: long temptid; ! 118: extern int Noupdt; ! 119: ! 120: ! 121: # ifdef xZTR1 ! 122: if (tTf(34, -1)) ! 123: { ! 124: printf("enter modify\n"); ! 125: prvect(pc, pv); ! 126: } ! 127: # endif ! 128: ! 129: pv[pc].pv_val.pv_str = NULL; ! 130: ! 131: /* check for nice parameters */ ! 132: if (pc < 2) ! 133: syserr("MODIFY: pc %d", pc); ! 134: ! 135: /* save relation name for error messages */ ! 136: rname = (pv++)->pv_val.pv_str; /* *pv now pointes to storage spec */ ! 137: ! 138: /* check for good relation */ ! 139: i = openr(&dold, 0, rname); ! 140: if (i == AMOPNVIEW_ERR) ! 141: return (error(5519, rname, 0)); ! 142: if (i > 0) ! 143: /* reln does not exist */ ! 144: return (error(5500, rname, 0)); ! 145: else if (i < 0) ! 146: syserr("MODIFY: openr (%.14s) %d", rname, i); ! 147: /* can only modify a relation you own and isn't a sys rel */ ! 148: ! 149: if (!bequal(Usercode, dold.reldum.relowner, 2)) ! 150: { ! 151: i = 5501; ! 152: } ! 153: if ((dold.reldum.relstat & S_CATALOG) && Noupdt) ! 154: { ! 155: i = 5504; ! 156: } ! 157: if (i) ! 158: { ! 159: closer(&dold); ! 160: return (error(i, rname, 0)); ! 161: } ! 162: ! 163: /* ! 164: ** Form descriptor for new relation. Here we need to ! 165: ** separate the pages from the old and new relations. ! 166: ** Since pages are identified by the TID of the relation ! 167: ** relation tuple, both old and new have the same identifiers. ! 168: ** To avoid this problem, a special TID is hand crafted for ! 169: ** the new relation. ! 170: */ ! 171: bmove(&dold, &dnew, sizeof dnew); ! 172: dnew.reltid.line_id = (char) -2; /* choose impossible reltid */ ! 173: ! 174: /* In case of an interrupt from a previous modify, ! 175: ** there might be pages around. Get rid of them. ! 176: */ ! 177: cleanrel(&dnew); ! 178: ! 179: ingresname(dold.reldum.relid, dold.reldum.relowner, Mod_info.infile); ! 180: ! 181: /* scan for entry in relspec table */ ! 182: for (mp = Modtab; mp->type; mp++) ! 183: if (sequal(mp->type, pv->pv_val.pv_str)) ! 184: break; ! 185: ! 186: /* if not found, error */ ! 187: if (!mp->type) ! 188: { ! 189: closer(&dold); ! 190: return (error(5510, rname, pv->pv_val.pv_str, 0)); /* bad relspec */ ! 191: } ! 192: dnew.reldum.relspec = mp->newrelspec; ! 193: ! 194: if (dnew.reldum.relspec == M_TRUNC) ! 195: dnew.reldum.relspec = M_HEAP; ! 196: ! 197: pv++; /* now points to first parameter */ ! 198: ! 199: F_fac = mp->f_fac; ! 200: Mn_pages = mp->mn_pages; ! 201: Mx_pages = mp->mx_pages; ! 202: ! 203: /* get the key domains information */ ! 204: if (i = getkeys(&pv, rname, &dnew, mp)) ! 205: { ! 206: closer(&dold); ! 207: return (i); /* user error */ ! 208: } ! 209: ! 210: /* get fillfactor and other options if any */ ! 211: if (i = getfill(pv, rname, mp)) ! 212: { ! 213: closer(&dold); ! 214: return (i); /* user error */ ! 215: } ! 216: ! 217: ! 218: /* lock the relation relation */ ! 219: if (Lockrel) ! 220: { ! 221: get_p_tid(&dold, &temptid); ! 222: setrll(A_SLP, temptid, M_EXCL); ! 223: } ! 224: ! 225: /* compute new relation parameters & build descriptor */ ! 226: make_newrel(&dnew); ! 227: ! 228: if (sorted = (mp->sortit && (dold.reldum.reltups != 0))) ! 229: sortrel(&dold, &dnew); ! 230: ! 231: /* physically create the new relation */ ! 232: if (formatpg(&dnew, (dnew.reldum.relspec == M_BTREE) ? dnew.reldum.relprim + 1 : dnew.reldum.relprim) != 0) ! 233: syserr("modify: formatpg"); ! 234: ! 235: /* clear relgiven field; if heap remove any keys */ ! 236: clearkeys(&dnew); ! 237: if (abs(dnew.reldum.relspec) == M_HEAP) ! 238: for (i = 1; i <= dnew.reldum.relatts; i++) ! 239: dnew.relxtra[i] = 0; ! 240: ! 241: if (mp->newrelspec != M_TRUNC) ! 242: fill_rel(&dold, &dnew, sorted); ! 243: ! 244: closer(&dold); /* error return is impossible */ ! 245: if (abs(dnew.reldum.relspec) == M_ISAM) ! 246: { ! 247: if (i = bldindex(&dnew)) ! 248: syserr("bldindex: %.14s %d", dnew.reldum.relid, i); ! 249: unspool(&dnew); ! 250: } ! 251: else if (dnew.reldum.relspec == M_BTREE) ! 252: { ! 253: if (i = bldbindex(&dnew)) ! 254: syserr("bldbindex: %.14s %d", dnew.reldum.relid, i); ! 255: } ! 256: ! 257: /* ! 258: ** New relation is now complete. The system relations need to ! 259: ** be updated. First destroy all buffers with pages from the ! 260: ** new relation. ! 261: */ ! 262: if (i = cleanrel(&dnew)) ! 263: syserr("modify:clean new %d,%.14s", i, dnew.reldum.relid); ! 264: ! 265: fill_batch(&dold, &dnew); ! 266: ! 267: /* ! 268: ** Close the file for the new relation. This must be ! 269: ** done after the fill_batch in case we are modifing ! 270: ** the attribute relation. ! 271: */ ! 272: close(dnew.relfp); ! 273: dnew.relopn = 0; ! 274: ruboff("modify"); ! 275: modupdate(); ! 276: rubon(); ! 277: ! 278: if (Lockrel) ! 279: unlrl(temptid); ! 280: ! 281: # ifdef xZTM ! 282: if (tTf(35, 1)) ! 283: timtrace(16, 0); ! 284: # endif ! 285: return (0); ! 286: } ! 287: ! 288: ! 289: getkeys(ppv, relname, desc, mp) ! 290: PARM **ppv; ! 291: char *relname; ! 292: DESC *desc; ! 293: struct modtab *mp; ! 294: { ! 295: register PARM *pv; ! 296: register char *cp; ! 297: register DESC *d; ! 298: int namemode, sort_only, as_ds; ! 299: int i, keyno, keywid; ! 300: struct attribute attkey, atttup; ! 301: TID tid; ! 302: extern DESC Attdes; ! 303: ! 304: pv = *ppv; /* copy list of params */ ! 305: ! 306: d = desc; ! 307: ! 308: /* zero key info */ ! 309: for (i = 0; i <= d->reldum.relatts; i++) ! 310: d->relxtra[i] = d->relgiven[i] = 0; ! 311: ! 312: /* determine whether there are any keys at all */ ! 313: keyno = 0; ! 314: keywid = 0; ! 315: sort_only = FALSE; ! 316: cp = pv->pv_val.pv_str; ! 317: ! 318: if (cp == NULL || *cp == NULL) ! 319: { ! 320: /* no key information. default as needed */ ! 321: if (mp->yeskeys) ! 322: { ! 323: cp = "\1"; /* default to first key */ ! 324: namemode = FALSE; ! 325: } ! 326: else ! 327: pv++; /* point one to far */ ! 328: } ! 329: else ! 330: { ! 331: /* check for name mode */ ! 332: if (namemode = sequal(cp, "name")) ! 333: { ! 334: ! 335: /* check attribute names, and convert them to numbers */ ! 336: opencatalog("attribute", 0); ! 337: setkey(&Attdes, &attkey, Mod_info.infile, ATTRELID); ! 338: setkey(&Attdes, &attkey, Usercode, ATTOWNER); ! 339: } ! 340: pv++; /* inc to next key */ ! 341: cp = (pv++)->pv_val.pv_str; ! 342: } ! 343: ! 344: ! 345: /* scan for attribute names */ ! 346: for (; cp != NULL; cp = (pv++)->pv_val.pv_str) ! 347: { ! 348: /* check for separator between keys & options */ ! 349: if (*cp == NULL) ! 350: { ! 351: pv++; /* point two past NULL */ ! 352: break; ! 353: } ! 354: ! 355: if (namemode) ! 356: { ! 357: /* check for "sort only" attribute */ ! 358: if (*cp == '#') ! 359: { ! 360: cp++; /* inc to start of name */ ! 361: sort_only = TRUE; ! 362: } ! 363: ! 364: /* check for ascending/descending modifier */ ! 365: if ((as_ds = modseqkey(cp, relname, mp->yes_seq)) > 0) ! 366: return (as_ds); /* error */ ! 367: ! 368: setkey(&Attdes, &attkey, cp, ATTNAME); ! 369: i = getequal(&Attdes, &attkey, &atttup, &tid); ! 370: if (i < 0) ! 371: syserr("MODIFY: geteq(att) %d", i); ! 372: if (i > 0) ! 373: { ! 374: return (error(5511, relname, cp, 0)); /* bad att name */ ! 375: } ! 376: i = atttup.attid; ! 377: } ! 378: else ! 379: { ! 380: i = *cp; ! 381: as_ds = 0; ! 382: } ! 383: ! 384: /* add new key to descriptor */ ! 385: keyno++; ! 386: if (!sort_only) ! 387: { ! 388: d->relxtra[i] = keyno; ! 389: keywid += (d->relfrml[i] & I1MASK); ! 390: } ! 391: if (d->relgiven[i]) ! 392: return (error(5507, relname, cp, 0)); /* duplicate attribute */ ! 393: d->relgiven[i] = as_ds == 0 ? keyno : -keyno; ! 394: } ! 395: pv--; /* back up one to point to "-1" terminator */ ! 396: ! 397: ! 398: if (abs(d->reldum.relspec) == M_ISAM && keywid > (MAXTUP / 2 - 4)) ! 399: { ! 400: return (error(5508, relname, iocv(keywid), 0)); ! 401: } ! 402: ! 403: /* if a heap, there can be no keys */ ! 404: if (!mp->yeskeys && keyno != 0) ! 405: { ! 406: return (error(5502, relname, mp->type, 0)); /* no keys allowed on heap */ ! 407: } ! 408: ! 409: /* fill out default sort on remainder of keys */ ! 410: if (mp->yeskeys) ! 411: for (i = 1; i <= d->reldum.relatts; i++) ! 412: if (d->relgiven[i] == 0) ! 413: d->relgiven[i] = ++keyno; ! 414: *ppv = pv; ! 415: return (0); ! 416: } ! 417: ! 418: ! 419: modseqkey(domain, relname, seq_ok) ! 420: char *domain; ! 421: char *relname; ! 422: int seq_ok; ! 423: { ! 424: register char *cp, c; ! 425: register int ret; ! 426: ! 427: ret = 0; ! 428: ! 429: for (cp = domain; c = *cp++; ) ! 430: if (c == ':') ! 431: break; ! 432: ! 433: if (c != '\0') ! 434: { ! 435: /* replace ":" with null */ ! 436: *(cp - 1) = '\0'; ! 437: ! 438: /* verify sequence is valid */ ! 439: if (!seq_ok) ! 440: ret = error(5520, relname, cp, domain, 0); ! 441: else if (sequal("descending", cp) || sequal("d", cp)) ! 442: ret = -1; ! 443: else if (!(sequal("ascending", cp) || sequal("a", cp))) ! 444: ret = error(5518, relname, cp, domain, 0); ! 445: } ! 446: ! 447: return (ret); ! 448: } ! 449: /* ! 450: ** GETFILL -- Get fill factor and minimum pages parameters ! 451: ** from argument list, convert them from ascii to integer ! 452: ** and store them in global variables. If the global ! 453: ** variable for the corresponding parameter is zero, ! 454: ** it means that that parameter is not allowed and an ! 455: ** error is generated. ! 456: */ ! 457: ! 458: getfill(pvx, rel, mp) ! 459: PARM *pvx; ! 460: char *rel; ! 461: struct modinfo *mp; ! 462: { ! 463: register PARM *pv; ! 464: register char *p1; ! 465: register int err; ! 466: char *p2; ! 467: int fill_flag, min_flag, max_flag; ! 468: ! 469: pv = pvx; ! 470: err = 0; ! 471: fill_flag = min_flag = max_flag = FALSE; ! 472: ! 473: while ((p1 = (pv++)->pv_val.pv_str) != NULL) ! 474: { ! 475: p2 = (pv++)->pv_val.pv_str; ! 476: if (sequal(p1, "fillfactor")) ! 477: { ! 478: if (F_fac == 0 || fill_flag) ! 479: { ! 480: err = 5512; ! 481: break; ! 482: } ! 483: p1 = p2; ! 484: F_fac = atoi(p1); ! 485: if (F_fac > 100 || F_fac < 1) ! 486: { ! 487: err = 5513; ! 488: break; ! 489: } ! 490: fill_flag = TRUE; ! 491: continue; ! 492: } ! 493: if (sequal(p1, "minpages")) ! 494: { ! 495: if (Mn_pages == 0 || min_flag) ! 496: { ! 497: err = 5512; ! 498: break; ! 499: } ! 500: p1 = p2; ! 501: Mn_pages = atoi(p1); ! 502: if (Mn_pages < 1) ! 503: { ! 504: err = 5514; ! 505: break; ! 506: } ! 507: if (max_flag && (Mn_pages > Mx_pages)) ! 508: { ! 509: err = 5517; ! 510: break; ! 511: } ! 512: min_flag = TRUE; ! 513: continue; ! 514: } ! 515: if (sequal(p1, "maxpages")) ! 516: { ! 517: if (Mx_pages == 0 || max_flag) ! 518: { ! 519: err = 5512; ! 520: break; ! 521: } ! 522: p1 = p2; ! 523: Mx_pages = atoi(p1); ! 524: if (Mx_pages < 1) ! 525: { ! 526: err = 5516; ! 527: break; ! 528: } ! 529: if (min_flag && (Mn_pages > Mx_pages)) ! 530: { ! 531: err = 5517; ! 532: break; ! 533: } ! 534: max_flag = TRUE; ! 535: continue; ! 536: } ! 537: err = 5515; ! 538: break; ! 539: } ! 540: if (err) ! 541: return (error(err, rel, p1, 0)); ! 542: return (0); ! 543: } ! 544: /* ! 545: ** MAKE_NEWREL -- Create a file for the modified relation ! 546: ** and build one or more primary pages for the ! 547: ** relation based on its storage structure and the ! 548: ** number of tuples it must hold. ! 549: */ ! 550: ! 551: make_newrel(descx) ! 552: DESC *descx; ! 553: { ! 554: register DESC *desc; ! 555: register int i, tups_p_page; ! 556: ! 557: desc = descx; ! 558: concat(MODTEMP, Fileset, Mod_info.reltemp); ! 559: close(creat(Mod_info.reltemp, FILEMODE)); ! 560: if ((desc->relfp = open(Mod_info.reltemp, 2)) < 0) ! 561: syserr("MAKE_NEWREL: open %.14s %d", Mod_info.reltemp, desc->relfp); ! 562: desc->relopn = (desc->relfp + 1) * -5; ! 563: desc->reldum.relprim = 1; ! 564: if (abs(desc->reldum.relspec) == M_HASH && F_fac > 0 && Mn_pages > 0) ! 565: { ! 566: /* ! 567: ** Determine the number of primary pages. The following ! 568: ** first determines the number of tuples/page which the ! 569: ** relation should have in order to get the requested ! 570: ** fillfactor. Then that number is divided into the ! 571: ** number of tuples to get the number of primary pages. ! 572: ** To avoid round off, it must guaranteed that the ! 573: ** number of tuples per page must be at least 1. ! 574: ** ! 575: ** primary_pages = #tuples / (#tuples/page * fillfactor) ! 576: */ ! 577: tups_p_page = (((MAXTUP+2) / (desc->reldum.relwid+2)) * F_fac) / 100; ! 578: if (tups_p_page == 0) ! 579: tups_p_page = 1; ! 580: /* we add one to simulate a ceiling function */ ! 581: desc->reldum.relprim = desc->reldum.reltups / tups_p_page + 1; ! 582: if (desc->reldum.relprim < Mn_pages) ! 583: desc->reldum.relprim = Mn_pages; ! 584: if (Mx_pages > 0 && desc->reldum.relprim > Mx_pages) ! 585: desc->reldum.relprim = Mx_pages; ! 586: # ifdef xZTR1 ! 587: if (tTf(36, 0)) ! 588: printf("using %ld prim pages\n", desc->reldum.relprim); ! 589: # endif ! 590: } ! 591: desc->reldum.reltups = 0; ! 592: return (0); ! 593: } ! 594: /* ! 595: ** SORTREL - Call KSORT to sort the given relation. SORTREL ! 596: ** sets up the descriptor struct specifying the sort ! 597: ** keys and tells KSORT whether or not the hash key should ! 598: ** be included as a sort key. ! 599: */ ! 600: ! 601: sortrel(odesc, descx) ! 602: DESC *odesc, *descx; ! 603: { ! 604: extern char *Pathname; ! 605: register DESC *desc; ! 606: register int fp, i; ! 607: char savespec; ! 608: char buf[50]; ! 609: ! 610: desc = descx; ! 611: concat(ISAM_SORTED, Fileset, Mod_info.outfile); ! 612: if (close(creat(Mod_info.outfile, FILEMODE))) ! 613: syserr("SORTREL: creat %.14s", Mod_info.outfile); ! 614: concat(ISAM_DESC, Fileset, Mod_info.formfile); ! 615: if ((fp = creat(Mod_info.formfile, FILEMODE)) < 0) ! 616: syserr("SORTREL: creat %.14s %d", Mod_info.formfile, fp); ! 617: if (abs(desc->reldum.relspec) == M_HASH) ! 618: { ! 619: /* sort on hash bucket first */ ! 620: desc->relgiven[0] = 1; ! 621: for (i = 1; i <= desc->reldum.relatts; i++) ! 622: desc->relgiven[i]++; ! 623: } ! 624: savespec = desc->reldum.relspec; ! 625: desc->reldum.relspec = odesc->reldum.relspec; ! 626: ! 627: if (write(fp, desc, sizeof *desc) != sizeof *desc) ! 628: syserr("SORTREL: desc write err"); ! 629: close(fp); ! 630: desc->reldum.relspec = savespec; ! 631: ! 632: i = fork(); ! 633: if (i == -1) ! 634: syserr("SORTREL: fork"); ! 635: if (i == 0) ! 636: { ! 637: for (i = 3; i < NOFILE; i++) ! 638: close(i); ! 639: concat(Pathname, "/bin/ksort", buf); ! 640: execl(buf, buf, Fileset, iocv(tTf(37, -1)), ! 641: Mod_info.formfile, Mod_info.infile, ! 642: Mod_info.outfile, 0); ! 643: syserr("SORTREL: exec %s", buf); ! 644: } ! 645: ! 646: # ifdef xZTR1 ! 647: tTfp(37, 1, "SORTREL: after execl; pid = %d\n", i); ! 648: # endif ! 649: ! 650: if (fp = fullwait(i, "modify")) /* wait for ksort to complete */ ! 651: syserr("modify:ksort failed %d", fp); ! 652: ! 653: # ifdef xZTR1 ! 654: tTfp(37, 2, "SORTREL: after fullwait\n"); ! 655: # endif ! 656: ! 657: unlink(Mod_info.formfile); ! 658: return (0); ! 659: } ! 660: /* ! 661: ** FILL_REL -- Fill the new relation with tuples from either ! 662: ** the old relation or the output file of KSORT. ! 663: */ ! 664: ! 665: fill_rel(sdescx, descx, sortit) ! 666: DESC *sdescx, *descx; ! 667: char sortit; ! 668: { ! 669: register DESC *sdesc, *desc; ! 670: register int i; ! 671: char tup_buf[MAXTUP], last_tup[MAXTUP]; ! 672: char junk[4], newreltype, anytups, chkdups; ! 673: char sortbuf[IOBUFSIZ], spoolbuf[IOBUFSIZ]; ! 674: int need, j; ! 675: long lnum; ! 676: TID tid, stid, stidlim; ! 677: FILE *fp, *spfp; ! 678: ! 679: sdesc = sdescx; ! 680: desc = descx; ! 681: newreltype = abs(desc->reldum.relspec); ! 682: if (sortit) ! 683: { ! 684: if ((fp = fopen(Mod_info.outfile, "read", sortbuf)) == NULL) ! 685: syserr("FILL_REL: fopen %.14s", Mod_info.outfile); ! 686: } ! 687: else ! 688: { ! 689: cleanrel(sdesc); /* make sure each page is read fresh */ ! 690: find(sdesc, NOKEY, &stid, &stidlim); ! 691: } ! 692: if (newreltype == M_ISAM) ! 693: { ! 694: lnum = 0; ! 695: stuff_page(&tid, &lnum); ! 696: tid.line_id = 0; ! 697: get_page(desc, &tid); ! 698: concat(ISAM_SPOOL, Fileset, Mod_info.spfile); ! 699: /* assume that spool file is not needed */ ! 700: spfp = NULL; ! 701: Mod_info.spflag = FALSE; ! 702: if (F_fac == 0) ! 703: F_fac = 100; ! 704: /* setup relgiven field for kcompare later on */ ! 705: for (i = 1; i <= desc->reldum.relatts; i++) ! 706: desc->relgiven[i] = desc->relxtra[i]; ! 707: } ! 708: else if (newreltype == M_BTREE) ! 709: { ! 710: lnum = 1; ! 711: stuff_page(&tid, &lnum); ! 712: tid.line_id = 0; ! 713: get_page(desc, &tid); ! 714: concat(ISAM_SPOOL, Fileset, Mod_info.spfile); ! 715: /* assume that spool file is not needed */ ! 716: spfp = NULL; ! 717: Mod_info.spflag = FALSE; ! 718: if (F_fac == 0) ! 719: F_fac = 100; ! 720: /* setup relgiven field for kcompare later on */ ! 721: for (i = 1; i <= desc->reldum.relatts; i++) ! 722: desc->relgiven[i] = desc->relxtra[i]; ! 723: } ! 724: desc->reladds = 0; ! 725: anytups = FALSE; ! 726: chkdups = !sortit; ! 727: for (;;) ! 728: { ! 729: if (sortit) ! 730: { ! 731: i = fread(fp, tup_buf, desc->reldum.relwid); ! 732: if (i == 0) ! 733: break; ! 734: if (i != desc->reldum.relwid) ! 735: syserr("FILL_REL: fread A %d", i); ! 736: if (newreltype == M_HASH) ! 737: if (fread(fp, junk, 4) != 4) ! 738: syserr("FILL_REL: fread B"); ! 739: } ! 740: else ! 741: { ! 742: # ifdef xZTR2 ! 743: if (tTf(36, 1)) ! 744: { ! 745: printf("FILL_REL: stid "); ! 746: dumptid(&stid); ! 747: printf("FILL_REL: stidlim "); ! 748: dumptid(&stidlim); ! 749: } ! 750: # endif ! 751: i = get(sdesc, &stid, &stidlim, tup_buf, TRUE); ! 752: # ifdef xZTR2 ! 753: if (tTf(36, 1)) ! 754: { ! 755: printf("FILLREL: get %d ", i); ! 756: printup(sdesc, tup_buf); ! 757: } ! 758: # endif ! 759: if (i < 0) ! 760: syserr("FILL_REL: get %d", i); ! 761: if (i == 1) ! 762: break; ! 763: } ! 764: if (newreltype != M_ISAM && newreltype != M_BTREE) ! 765: { ! 766: if ((i = insert(desc, &tid, tup_buf, chkdups)) < 0) ! 767: syserr("FILL_REL: insert %d", i); ! 768: # ifdef xZTR2 ! 769: if (tTf(36, 2)) ! 770: { ! 771: printf("FILL_REL: insert "); ! 772: printup(desc, tup_buf); ! 773: printf("FILL_REL: insert ret %d at", i); ! 774: dumptid(&tid); ! 775: } ! 776: # endif ! 777: continue; ! 778: } ! 779: if (anytups) ! 780: i = kcompare(desc, tup_buf, last_tup); ! 781: else ! 782: { ! 783: anytups = TRUE; ! 784: i = 1; ! 785: } ! 786: bmove(tup_buf, last_tup, desc->reldum.relwid); ! 787: need = canonical(desc, tup_buf); ! 788: if (i == 0 && need > space_left(Acc_head)) ! 789: { ! 790: /* spool out this tuple. will go on overflow page later */ ! 791: if (spfp == NULL) ! 792: { ! 793: if ((spfp = fopen(Mod_info.spfile, "write", spoolbuf)) == NULL) ! 794: syserr("FILL_REL: fopen %.14s", Mod_info.spfile); ! 795: Mod_info.spflag = TRUE; ! 796: } ! 797: if (fwrite(spfp, tup_buf, desc->reldum.relwid) != desc->reldum.relwid) ! 798: syserr("FILL_REL: putb spool"); ! 799: continue; ! 800: } ! 801: j = (100 - F_fac) * MAXTUP / 100; ! 802: if (j < need) ! 803: j = need; ! 804: if (i != 0 && j > space_left(Acc_head)) ! 805: { ! 806: if (i = add_prim(desc, &tid)) ! 807: syserr("FILL_REL: force ovflo %d", i); ! 808: } ! 809: tid.line_id = newlino(need); ! 810: put_tuple(&tid, Acctuple, need); ! 811: desc->reladds++; ! 812: } ! 813: if (sortit) ! 814: { ! 815: fclose(fp); ! 816: unlink(Mod_info.outfile); ! 817: } ! 818: if (newreltype == M_ISAM || newreltype == M_BTREE) ! 819: { ! 820: if (i = pageflush(Acc_head)) ! 821: syserr("fill_rel:pg clean %d", i); ! 822: if (spfp != NULL) ! 823: fclose(spfp); ! 824: } ! 825: desc->reldum.reltups = desc->reladds; ! 826: desc->reladds = 0; ! 827: return (0); ! 828: } ! 829: ! 830: ! 831: bldindex(dx) ! 832: DESC *dx; ! 833: { ! 834: register DESC *d; ! 835: register TID *tid; ! 836: register int tmp; ! 837: TID tidx; ! 838: struct accbuf dirbuf; ! 839: int keywid, level, savespec, keyx[MAXDOM]; ! 840: int offset, len; ! 841: char tuple[MAXTUP], temptup[MAXTUP], *key; ! 842: long pageid, start, stop, newstart, newstop; ! 843: ! 844: d = dx; ! 845: tid = &tidx; ! 846: for (tmp = 0; tmp < MAXDOM; tmp++) ! 847: keyx[tmp] = 0; ! 848: for (tmp = 1; tmp <= d->reldum.relatts; tmp++) ! 849: if (d->relxtra[tmp] > 0) ! 850: { ! 851: keyx[d->relxtra[tmp] - 1] = tmp; ! 852: keywid += d->relfrml[tmp] & I1MASK; ! 853: } ! 854: ! 855: /* Determine the last page of the relation. This will ! 856: ** only work if all pages have been written out. Fill_rel ! 857: ** must guarantee that all pages have been written ! 858: */ ! 859: level = 0; ! 860: last_page(d, tid, 0); ! 861: pluck_page(tid, &stop); ! 862: start = 0; ! 863: dirbuf.filedesc = d->relfp; ! 864: dirbuf.rel_tupid = d->reltid.ltid; ! 865: savespec = d->reldum.relspec; ! 866: for (;;) ! 867: { ! 868: # ifdef xZTR2 ! 869: if (tTf(38, 7)) ! 870: printf("isam: level %d\n", level); ! 871: # endif ! 872: dirbuf.ovflopg = start; ! 873: dirbuf.mainpg = level; ! 874: dirbuf.thispage = stop + 1; ! 875: dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf); ! 876: offset = dirbuf.linetab[0]; ! 877: dirbuf.bufstatus = BUF_DIRTY | BUF_DIRECT; ! 878: ! 879: dirbuf.nxtlino = 0; ! 880: newstart = stop + 1; ! 881: newstop = newstart; ! 882: for (pageid = start; pageid <= stop; pageid++) ! 883: { ! 884: # ifdef xZTR2 ! 885: if (tTf(38, 8)) ! 886: printf("isam:get key from %ld\n", pageid); ! 887: # endif ! 888: stuff_page(tid, &pageid); ! 889: tid->line_id = 0; ! 890: if (tmp = get(d, tid, tid, tuple, FALSE)) ! 891: { ! 892: /* ! 893: ** If the relation is empty, then page 0 will ! 894: ** return AMINVL_ERR on a get(). Form a blank tuple ! 895: ** and use it to create a one tuple directory ! 896: */ ! 897: if (pageid == 0 && tmp == AMINVL_ERR) ! 898: { ! 899: clr_tuple(d, tuple); ! 900: } ! 901: else ! 902: { ! 903: return (-2); ! 904: } ! 905: } ! 906: ! 907: /* ! 908: ** If this is the first level then form the tuple ! 909: ** from the mainpage of the relation. Otherwise ! 910: ** the tuple is the first tuple of a directory page ! 911: ** and it is already correctly formed. ! 912: */ ! 913: if (level == 0) ! 914: { ! 915: key = temptup; ! 916: for (tmp = 0; keyx[tmp] != 0; tmp++) ! 917: { ! 918: len = d->relfrml[keyx[tmp]] & I1MASK; ! 919: bmove(&tuple[d->reloff[keyx[tmp]]], key, len); ! 920: key += len; ! 921: } ! 922: key = temptup; ! 923: } ! 924: else ! 925: key = tuple; ! 926: ! 927: if (keywid > space_left(&dirbuf)) ! 928: { ! 929: if (pageflush(&dirbuf)) ! 930: return (-3); ! 931: dirbuf.thispage++; ! 932: newstop = dirbuf.thispage; ! 933: dirbuf.ovflopg = pageid; ! 934: dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf); ! 935: offset = dirbuf.linetab[0]; ! 936: dirbuf.bufstatus = BUF_DIRTY; ! 937: dirbuf.nxtlino = 0; ! 938: } ! 939: /* copy key to directory page */ ! 940: bmove(key, (char *) &dirbuf + offset, keywid); ! 941: ! 942: /* update next line number */ ! 943: offset += keywid; ! 944: dirbuf.nxtlino++; ! 945: dirbuf.linetab[-dirbuf.nxtlino] = offset; ! 946: } ! 947: if (pageflush(&dirbuf)) ! 948: return (-4); ! 949: if (newstart == newstop) ! 950: break; ! 951: d->reldum.relspec = abs(d->reldum.relspec); ! 952: level++; ! 953: start = newstart; ! 954: stop = newstop; ! 955: } ! 956: d->reldum.relspec = savespec; ! 957: d->reldum.relprim = newstart; ! 958: return (0); ! 959: } ! 960: ! 961: bldbindex(dx) ! 962: register DESC *dx; ! 963: { ! 964: register TID *tid; ! 965: register int tmp; ! 966: TID tidx; ! 967: struct accbuf dirbuf; ! 968: int keywid, level, savespec, keyx[MAXDOM]; ! 969: int offset, len; ! 970: struct pgtuple tuple, temptup; ! 971: char *key; ! 972: long pageid, start, stop, newstart, newstop; ! 973: int fill_leave; ! 974: ! 975: tid = &tidx; ! 976: keywid = 0; ! 977: for (tmp = 0; tmp < MAXDOM; tmp++) ! 978: keyx[tmp] = 0; ! 979: for (tmp = 1; tmp <= d->reldum.relatts; tmp++) ! 980: if (d->relxtra[tmp] > 0) ! 981: { ! 982: keyx[d->relxtra[tmp - 1]] = tmp; ! 983: keywid += d->relfrml[tmp] & I1MASK; ! 984: } ! 985: ! 986: keywid += PGPTRSIZ; ! 987: ! 988: /* determine fill factor for directory pages */ ! 989: ! 990: fill_leave = (100 - F_fac) * MAXTUP / 100; ! 991: if (keywid > fill_leave) ! 992: fill_leave = keywid; ! 993: ! 994: /* Determine the last page of the relation. This will ! 995: ** only work if all pages have been written out. Fill_rel ! 996: ** must guarantee that all pages have been written ! 997: */ ! 998: ! 999: level = 0; ! 1000: last_page(d, tid, 0); ! 1001: pluck_page(tid, &stop); ! 1002: start = 1; /* page 0 is the root */ ! 1003: dirbuf.filedesc = d->relfp; ! 1004: dirbuf.rel_tupid = d->reltid.ltid; ! 1005: savespec = d->reldum.relspec; ! 1006: for (;;) ! 1007: { ! 1008: # ifdef xZTR2 ! 1009: if (tTf(38, 7)) ! 1010: printf("btree: level %d\n", level); ! 1011: # endif ! 1012: dirbuf.mainpg = level; ! 1013: dirbuf.thispage = stop + 1; ! 1014: dirbuf.ovflopg = dirbuf.thispage + 1; ! 1015: dirbuf.linetab[0] = (short) (&dirbuf.firstup[PGPTRSIZ] - (char *) &dirbuf); ! 1016: ! 1017: stuff_page(dirbuf.firstup, &start); /* put first pgnum in */ ! 1018: start++; ! 1019: ! 1020: offset = dirbuf.linetab[0]; ! 1021: dirbuf.bufstatus = BUF_DIRTY | BUF_DIRECT; ! 1022: ! 1023: dirbuf.nxtlino = 0; ! 1024: newstart = stop + 1; ! 1025: newstop = newstart; ! 1026: for (pageid = start; pageid <= stop; pageid++) ! 1027: { ! 1028: # ifdef xZTR2 ! 1029: if (tTf(38, 8)) ! 1030: printf("btree:get key from %ld\n", pageid); ! 1031: # endif ! 1032: stuff_page(tid, &pageid); ! 1033: tid->line_id = 0; ! 1034: if (tmp = get(d, tid, tid, &tuple, FALSE)) ! 1035: { ! 1036: syserr("modify: bldbindex: get %d\n", tmp); ! 1037: } ! 1038: ! 1039: /* ! 1040: ** If this is the first level then form the tuple ! 1041: ** from the mainpage of the relation. Otherwise ! 1042: ** the tuple is the first tuple of a directory page ! 1043: ** and it is already correctly formed. ! 1044: */ ! 1045: if (level == 0) ! 1046: { ! 1047: bndxkey(d, tuple.childtup, &temptup, &pageid, keyx); ! 1048: /* ! 1049: stuff_page(&temptup.childtid, &pageid); ! 1050: key = temptup.childtup; ! 1051: for (tmp = 0; keyx[tmp] != 0; tmp++) ! 1052: { ! 1053: len = d->relfrml[keyx[tmp]] & I1MASK; ! 1054: bmove(&((char *) &tuple)[d->reloff[keyx[tmp]]], key, len); ! 1055: key += len; ! 1056: } ! 1057: */ ! 1058: ! 1059: ! 1060: printf("primary "); ! 1061: key = &temptup; ! 1062: } ! 1063: else ! 1064: { ! 1065: stuff_page(&tuple.childtid, &pageid); ! 1066: key = &tuple; ! 1067: printf("secondary %d: ", level); ! 1068: } ! 1069: ! 1070: printf("adding: "); ! 1071: prbndxkey(d, key, keyx); ! 1072: printf("\n"); ! 1073: ! 1074: if (fill_leave > space_left(&dirbuf)) ! 1075: { ! 1076: if (pageflush(&dirbuf)) ! 1077: return (-3); ! 1078: dirbuf.thispage++; ! 1079: newstop = dirbuf.thispage; ! 1080: dirbuf.ovflopg = dirbuf.thispage + 1; ! 1081: dirbuf.linetab[0] = (short) (&dirbuf.firstup[PGPTRSIZ] - (char *) &dirbuf); ! 1082: ! 1083: stuff_page(dirbuf.firstup, &pageid); ! 1084: ! 1085: offset = dirbuf.linetab[0]; ! 1086: dirbuf.bufstatus = BUF_DIRTY; ! 1087: dirbuf.nxtlino = 0; ! 1088: continue; ! 1089: } ! 1090: /* copy key to directory page */ ! 1091: bmove(key, (char *) &dirbuf + offset, keywid); ! 1092: ! 1093: /* update next line number */ ! 1094: offset += keywid; ! 1095: dirbuf.nxtlino++; ! 1096: dirbuf.linetab[-dirbuf.nxtlino] = offset; ! 1097: } ! 1098: if (newstart == newstop) /* must be root */ ! 1099: dirbuf.thispage = 0; /* root is page 0 */ ! 1100: ! 1101: dirbuf.ovflopg = 0; /* no more pages */ ! 1102: ! 1103: if (pageflush(&dirbuf)) ! 1104: return (-4); ! 1105: ! 1106: if (newstart == newstop) ! 1107: break; ! 1108: d->reldum.relspec = abs(d->reldum.relspec); ! 1109: level++; ! 1110: start = newstart; ! 1111: stop = newstop; ! 1112: } ! 1113: d->reldum.relspec = savespec; ! 1114: d->reldum.relprim = newstart; ! 1115: return (0); ! 1116: } ! 1117: /* ! 1118: ** UNSPOOL -- Take tuples saved in spool file and insert them ! 1119: ** in new relation. This is only for ISAM relations. ! 1120: */ ! 1121: ! 1122: unspool(descx) ! 1123: DESC *descx; ! 1124: { ! 1125: register DESC *desc; ! 1126: register int i; ! 1127: TID tid; ! 1128: char tup_buf[MAXTUP], spoolbuf[IOBUFSIZ]; ! 1129: FILE *spfp; ! 1130: ! 1131: desc = descx; ! 1132: if (Mod_info.spflag) ! 1133: { ! 1134: if ((spfp = fopen(Mod_info.spfile, "read", spoolbuf)) == NULL) ! 1135: syserr("UNSPOOL: fopen spool"); ! 1136: while ((i = fread(spfp, tup_buf, desc->reldum.relwid)) == desc->reldum.relwid) ! 1137: if ((i = insert(desc, &tid, tup_buf, FALSE)) < 0) ! 1138: syserr("UNSPOOL: insert %.14s %d", desc->reldum.relid, i); ! 1139: if (i != 0) ! 1140: syserr("UNSPOOL: read %d", i); ! 1141: fclose(spfp); ! 1142: unlink(Mod_info.spfile); ! 1143: } ! 1144: desc->reldum.reltups += desc->reladds; ! 1145: desc->reladds = 0; ! 1146: return (0); ! 1147: } ! 1148: /* ! 1149: ** FILL_BATCH -- Create and fill a batch file containing the ! 1150: ** updates for the system catalog so that MODIFY will ! 1151: ** be recoverable if the system crashes. ! 1152: */ ! 1153: ! 1154: fill_batch(odesc, descx) ! 1155: DESC *odesc, *descx; ! 1156: { ! 1157: register DESC *desc, *dessys; ! 1158: register int i; ! 1159: struct relation reltup, rkey; ! 1160: TID tid, lotid, hitid; ! 1161: struct attribute atttup, akey; ! 1162: int j; ! 1163: char prebatch[MAXNAME + 4], modbatch[MAXNAME + 4]; ! 1164: ! 1165: desc = descx; ! 1166: if (bequal(desc->reldum.relid, "relation ", 12)) ! 1167: { ! 1168: clearkeys(desc); ! 1169: setkey(desc, &rkey, desc->reldum.relid, RELID); ! 1170: setkey(desc, &rkey, desc->reldum.relowner, RELOWNER); ! 1171: if (i = getequal(desc, &rkey, &reltup, &tid)) ! 1172: syserr("FILL_BATCH: geteq rel rel %d", i); ! 1173: bmove(&tid, &desc->reltid, sizeof desc->reltid); ! 1174: } ! 1175: else ! 1176: bmove(&odesc->reltid, &desc->reltid, sizeof desc->reltid); ! 1177: resetacc(Acc_head); ! 1178: concat(MOD_PREBATCH, Fileset, prebatch); ! 1179: close(creat(prebatch, FILEMODE)); ! 1180: if ((Batch_fp = open(prebatch, 2)) < 0) ! 1181: syserr("FILL_BATCH: open %.14s %d", prebatch, Batch_fp); ! 1182: smove(Fileset, Batchbuf.file_id); ! 1183: Batch_cnt = 0; ! 1184: wrbatch(desc, sizeof *desc); ! 1185: if (bequal(desc->reldum.relid, "attribute ", 12)) ! 1186: dessys = desc; ! 1187: else ! 1188: dessys = &Admin.adattd; ! 1189: clearkeys(dessys); ! 1190: setkey(dessys, &akey, desc->reldum.relid, ATTRELID); ! 1191: setkey(dessys, &akey, desc->reldum.relowner, ATTOWNER); ! 1192: if (i = find(dessys, EXACTKEY, &lotid, &hitid, &akey)) ! 1193: syserr("FILL_BATCH: find %d", i); ! 1194: j = desc->reldum.relatts; ! 1195: while(!(i = get(dessys, &lotid, &hitid, &atttup, TRUE)) && j > 0) ! 1196: if (!kcompare(dessys, &akey, &atttup)) ! 1197: { ! 1198: j--; ! 1199: atttup.attxtra = desc->relxtra[atttup.attid]; ! 1200: wrbatch(&lotid, sizeof lotid); ! 1201: wrbatch(&atttup, sizeof atttup); ! 1202: } ! 1203: if (i < 0 || j > 0) ! 1204: syserr("FILL_BATCH: get att %d count %d", i, j); ! 1205: /* get rid of attribute pages */ ! 1206: cleanrel(dessys); ! 1207: flushbatch(); ! 1208: close(Batch_fp); ! 1209: concat(MODBATCH, Fileset, modbatch); ! 1210: if (link(prebatch, modbatch) == -1) ! 1211: syserr("FILL_BATCH: can't link %.14s %.14s", ! 1212: prebatch, modbatch); ! 1213: unlink(prebatch); ! 1214: return (0); ! 1215: ! 1216: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.