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