|
|
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.