# include # include # include # include # include # include # include # include # include # include # include # include # include # include # include SCCSID(@(#)modify.c 8.8 5/7/85) extern short tTdbu[]; extern int modify(); extern int null_fn(); struct fn_def ModifyFn = { "MODIFY", modify, null_fn, null_fn, NULL, 0, tTdbu, 100, 'Z', 0 }; /* ** MODIFY -- converts any relation to the specified ** storage structure ** ** arguments: ** 0 - relation name ** 1 - storage structure ("heap", "cheap", "hash", "chash", ** "isam", "cisam") ** 2 - "name" for attribute names, or "num" for numbers ** 3 - key1 ** 4 - key2 ** . ** . ** i - null ** i+1 - option name (e.g., "fillfactor") ** i+2 - option value ** . ** . ** ** If all the options default, parameter i -> pc are omitted. ** If no keys are provided, parameter 2 is omitted. */ int F_fac, Mn_pages, Mx_pages; char Lid[MAXLID][MAXNAME]; int NLidKeys; int LidKey[MAXLID]; struct modtab { char *type; char newrelspec; char yeskeys; char sortit; char yes_seq; int f_fac; int mn_pages; int mx_pages; }; struct modtab Modtab[] = { /* type spec keys sort seq ffac min max */ "heap", M_HEAP, FALSE, FALSE, FALSE, 0, 0, 0, "cheap", -M_HEAP,FALSE, FALSE, FALSE, 0, 0, 0, "hash", M_HASH, TRUE, TRUE, FALSE, 50, 10, -1, "chash", -M_HASH,TRUE, TRUE, FALSE, 75, 1, -1, "isam", M_ISAM, TRUE, TRUE, FALSE, 80, 0, 0, "cisam", -M_ISAM,TRUE, TRUE, FALSE, 100, 0, 0, "heapsort", M_HEAP, TRUE, TRUE, TRUE, 0, 0, 0, "cheapsort", -M_HEAP,TRUE, TRUE, TRUE, 0, 0, 0, "truncated", M_TRUNC,FALSE, FALSE, FALSE, 0, 0, 0, "ordered", M_ORDER,TRUE, FALSE, FALSE, 0, 0, 0, 0 }; struct mod_info { char outfile[MAXNAME + 4]; /* result file filled by ksort */ char formfile[MAXNAME + 4]; /* file with descriptor for ksort */ char infile[MAXNAME + 4]; /* input file for ksort (relation itself */ char reltemp[MAXNAME + 4]; /* file holding new relation */ char spfile[MAXNAME + 4], spflag; /* isam spool file for overflow */ char btree[MAXNAME + 4]; /* file holding temporary btree structure */ char temp_sort[MAXNAME + 4]; /* file holding result of special isam ** required when ordering on a field */ }; struct mod_info Mod_info; extern DESC Btreesec; extern int Btree_fd; modify(pc, pv) int pc; PARM *pv; { register int i, j; register char *rname; register struct modtab *mp; struct modtab *p; int sorted, dim; DESC dold, dnew; long temptid; extern int Noupdt; extern DESC Attdes; struct attribute atttup, attkey; TID tid; int lidkey, numatts; extern char *trim_relname(); extern char *iocv(); # ifdef xZTR1 if (tTf(34, -1)) { printf("enter modify\n"); prvect(pc, pv); } # endif pv[pc].pv_val.pv_str = NULL; /* check for nice parameters */ if (pc < 2) syserr("MODIFY: pc %d", pc); /* save relation name for error messages */ rname = (pv++)->pv_val.pv_str; /* *pv now pointes to storage spec */ /* check for good relation */ i = openr(&dold, OR_READ, rname); if (i == AMOPNVIEW_ERR) return (error(NOMODVIEW, rname, 0)); if (i > 0) /* reln does not exist */ return (error(NOREL, rname, 0)); else if (i < 0) syserr("MODIFY: openr (%.14s) %d", rname, i); /* can only modify a relation you own and isn't a sys rel */ if (!bequal(Usercode, dold.reldum.relowner, UCODE_SZ)) { i = NOOWN; } if ((dold.reldum.relstat & S_CATALOG) && Noupdt) { i = NOMODSYSREL; } if (i) { closer(&dold); return (error(i, rname, 0)); } /* ** Form descriptor for new relation. Here we need to ** separate the pages from the old and new relations. ** Since pages are identified by the TID of the relation ** relation tuple, both old and new have the same identifiers. ** To avoid this problem, a special TID is hand crafted for ** the new relation. */ bmove(&dold, &dnew, sizeof dnew); dnew.reltid.s_tupid.line_id = (char) -2; /* choose impossible reltid */ /* assume new relation isn't ordered */ if (dold.reldum.reldim) { dnew.reldum.relatts -= dold.reldum.reldim; dnew.reldum.relwid -= dold.reldum.reldim * LIDSIZE; dnew.reldum.reldim = 0; } /* In case of an interrupt from a previous modify, ** there might be pages around. Get rid of them. */ cleanrel(&dnew); ingresname(dold.reldum.relid, dold.reldum.relowner, Mod_info.infile); dim = 0; NLidKeys = 0; /* scan for entry in relspec table */ for (mp = Modtab; mp->type; mp++) { if (bequal(mp->type, pv->pv_val.pv_str, 7) && bequal("ordered", pv->pv_val.pv_str, 7)) { if ((dim = atoi(pv->pv_val.pv_str + 7)) <= 0 || dim > MAXLID) { closer(&dold); return(error(BADORDDIM, rname, iocv(dim), 0)); } break; } if (sequal(mp->type, pv->pv_val.pv_str)) break; } /* if not found, error */ if (!mp->type) { closer(&dold); return (error(BADSTORAGE, rname, pv->pv_val.pv_str, 0)); /* bad relspec */ } if (mp->newrelspec == M_ORDER && dold.reldum.relindxd == SECINDEX) /* can't order an index relation */ { closer(&dold); return(error(NOORDINDX, rname,0)); } if (mp->newrelspec == M_ORDER) { dnew.reldum.reldim = dim; for (i = 0; i < dim; ++i) { ++dnew.reldum.relatts; dnew.relxtra[dnew.reldum.relatts] = 0; dnew.reloff[dnew.reldum.relatts] = dnew.reldum.relwid; dnew.relfrmt[dnew.reldum.relatts] = INT; dnew.relfrml[dnew.reldum.relatts] = LIDSIZE; dnew.reldum.relwid += LIDSIZE; } concat(BTREE, Fileset, Mod_info.btree); create_btree(Mod_info.btree); dnew.btree_fd = Btree_fd; /* ok to order ascending/descending */ mp->yes_seq = TRUE; } else { dnew.reldum.relspec = mp->newrelspec; if (dold.reldum.reldim) { dold.reldum.relatts -= dold.reldum.reldim; dold.reldum.relwid -= dold.reldum.reldim * LIDSIZE; dold.reldum.reldim = 0; closer(dold.relbtree); close(dold.btree_fd); } } if (dnew.reldum.relspec == M_TRUNC) dnew.reldum.relspec = M_HEAP; pv++; /* now points to first parameter */ /* get the key domains information */ if ((i = getkeys(&pv, rname, &dnew, mp)) > 0) { closer(&dold); return (i); /* user error */ } j = 0; for (i = 0; i < NLidKeys; ++i) if (LidKey[i] > dold.reldum.relatts - dold.reldum.reldim) { j = 1; break; } if (!j && dold.reldum.reldim) /* treat old relation as if not ordered since lid field not needed */ { dold.reldum.relatts -= dold.reldum.reldim; dold.reldum.relwid -= dold.reldum.reldim * LIDSIZE; dold.reldum.reldim = 0; closer(dold.relbtree); close(dold.btree_fd); } if (!dnew.reldum.reldim || !NLidKeys) { F_fac = mp->f_fac; Mn_pages = mp->mn_pages; Mx_pages = mp->mx_pages; } else /* set parameters to that of storage type of relation to be ordered */ { for (p = Modtab; p->type; p++) if (dnew.reldum.relspec == p->newrelspec) break; F_fac = p->f_fac; Mn_pages = p->mn_pages; Mx_pages = p->mx_pages; } if (mp->newrelspec != M_ORDER) for (i = 0; i < dnew.reldum.reldim; ++i) Lid[i][0] = NULL; else for (i = 1; i <= dnew.reldum.reldim; ++i) concat("lid", iocv(i), Lid[i-1]); /* get fillfactor and other options if any */ if (i = getfill(&dnew, pv, rname, mp)) { closer(&dold); return (i); /* user error */ } /* check for duplicate attribute name */ if (mp->newrelspec == M_ORDER) { opencatalog("attribute", OR_READ); setkey(&Attdes, &attkey, dnew.reldum.relid, ATTRELID); setkey(&Attdes, &attkey, dnew.reldum.relowner, ATTOWNER); numatts = dold.reldum.relatts - dold.reldum.reldim; for (i = 0; i < dnew.reldum.reldim; ++i) { setkey(&Attdes, &attkey, Lid[i], ATTNAME); if (getequal(&Attdes, &attkey, &atttup, &tid) == 0) { if (atttup.attid <= numatts) /* ok to duplicate attributes that will be removed */ { closer(&dold); return(error(INVALIDATTR, rname, Lid[i], 0)); } } } } /* lock the relation relation */ if (Lockrel) { get_p_tid(&dold, &temptid); setrll(A_SLP, temptid, M_EXCL); } if (!dnew.reldum.reldim || NLidKeys > 0) /* compute new relation parameters & build descriptor */ make_newrel(&dnew); if (sorted = ((mp->sortit || NLidKeys > 0) && (dold.reldum.reltups != 0))) { sortrel(&dold, &dnew); dold.reldum.relindxd = 0; } if (!dnew.reldum.reldim || NLidKeys > 0) /* physically create the new relation */ if (formatpg(&dnew, dnew.reldum.relprim) != 0) syserr("modify: formatpg"); /* clear relgiven field; if heap remove any keys */ clearkeys(&dnew); if (abs(dnew.reldum.relspec) == M_HEAP) for (i = 1; i <= dnew.reldum.relatts; i++) dnew.relxtra[i] = 0; if (NLidKeys > 0 && dnew.reldum.relspec == M_ISAM) sort_isam(&dold, &dnew); if (mp->newrelspec != M_TRUNC) fill_rel(&dold, &dnew, sorted); closer(&dold); /* error return is impossible */ if (abs(dnew.reldum.relspec) == M_ISAM && (!dnew.reldum.reldim || NLidKeys > 0)) { j = dnew.reldum.reldim; dnew.reldum.reldim = 0; if (i = bldindex(&dnew)) syserr("bldindex: %.14s %d", dnew.reldum.relid, i); dnew.reldum.reldim = j; unspool(&dold, &dnew); } /* ** New relation is now complete. The system relations need to ** be updated. First destroy all buffers with pages from the ** new relation. */ if (i = cleanrel(&dnew)) syserr("modify:clean new %d,%.14s", i, dnew.reldum.relid); fill_batch(&dold, &dnew); /* ** Close the file for the new relation. This must be ** done after the fill_batch in case we are modifing ** the attribute relation. */ if (!dnew.reldum.reldim || NLidKeys > 0) close(dnew.relfp); dnew.relopn = 0; ruboff("modify"); modupdate(); if (mp->newrelspec == M_ORDER) { close(dnew.btree_fd); make_bsec(dnew.reldum.relid, dim); } rubon(); if (Lockrel) unlrl(temptid); return (0); } /* ** GETKEYS - get key domains information ** ** Parameters: ** ppv - parameter vector with info about keys ** relname - relation name ** d - new descriptor for the relation ** mp - mod table ** ** Return Codes: ** 0 - ok ** >0 - error from modseqkey */ getkeys(ppv, relname, d, mp) PARM **ppv; char *relname; register DESC *d; struct modtab *mp; { register PARM *pv; register char *cp; int namemode, sort_only, as_ds; int i, j, keyno, keywid; struct attribute attkey, atttup; struct index ikey, itup; TID tid; extern DESC Attdes, Inddes; extern char *iocv(); pv = *ppv; /* copy list of params */ if (mp->newrelspec != M_ORDER) /* zero key info (ordering does not change keyed fields) */ for (i = 0; i <= d->reldum.relatts; i++) d->relxtra[i] = 0; for (i = 0; i <= d->reldum.relatts; ++i) d->relgiven[i] = 0; /* determine whether there are any keys at all */ keywid = 0; keyno = 0; sort_only = FALSE; cp = pv->pv_val.pv_str; if (cp == NULL || *cp == NULL) { /* no key information. default as needed */ if (mp->yeskeys && mp->newrelspec != M_ORDER) { cp = "\1"; /* default to first key */ namemode = FALSE; } else pv++; /* point one to far */ } else { /* check for name mode */ if (namemode = sequal(cp, "name")) { /* check attribute names, and convert them to numbers */ opencatalog("attribute", OR_READ); setkey(&Attdes, &attkey, Mod_info.infile, ATTRELID); setkey(&Attdes, &attkey, Usercode, ATTOWNER); } pv++; /* inc to next key */ cp = (pv++)->pv_val.pv_str; } /* scan for attribute names */ for (; cp != NULL; cp = (pv++)->pv_val.pv_str) { /* check for separator between keys & options */ if (*cp == NULL) { pv++; /* point two past NULL */ break; } if (NLidKeys >= d->reldum.reldim && mp->newrelspec == M_ORDER) { /* more than one field specified as ordering key */ closeall(0l, 0l); return(error(TOOMANYORDKEYS, relname, 0)); } if (namemode) { /* check for "sort only" attribute */ if (*cp == '#') { cp++; /* inc to start of name */ sort_only = TRUE; } /* check for ascending/descending modifier */ if ((as_ds = modseqkey(cp, relname, mp->yes_seq)) > 0) return (as_ds); /* error */ setkey(&Attdes, &attkey, cp, ATTNAME); i = getequal(&Attdes, &attkey, &atttup, &tid); if (i < 0) syserr("MODIFY: geteq(att) %d", i); if (i > 0) { closeall(0l, 0l); return (error(INVALIDATTR, relname, cp, 0)); /* bad att name */ } i = atttup.attid; if (i > d->reldum.relatts) { /* attempting to key on lid field which will be ** removed */ closeall(0l,0l); return(error(ATTRREMV, relname, cp, 0)); } } else { i = *cp; as_ds = 0; } keyno++; /* add new key to descriptor */ if (mp->newrelspec == M_ORDER) LidKey[NLidKeys++] = i; if (!sort_only && mp->newrelspec != M_ORDER) { d->relxtra[i] = keyno; keywid += (d->relfrml[i] & I1MASK); } if (d->relgiven[i]) { closeall(0l, 0l); return (error(DUPKEY, relname, cp, 0)); /* duplicate attribute */ } d->relgiven[i] = as_ds == 0 ? keyno : -keyno; } pv--; /* back up one to point to "-1" terminator */ if (abs(d->reldum.relspec) == M_ISAM && keywid > (MAXTUP / 2 - 4)) { closeall(0l, 0l); return (error(TOOWIDEISAM, relname, iocv(keywid), 0)); } /* if a heap, there can be no keys */ if (!mp->yeskeys && keyno != 0) { closeall(0l, 0l); return (error(NOKEYSHEAP, relname, mp->type, 0)); /* no keys allowed on heap */ } /* fill out default sort on remainder of keys */ if (mp->yeskeys) for (i = 1; i <= d->reldum.relatts; i++) if (d->relgiven[i] == 0) d->relgiven[i] = ++keyno; *ppv = pv; return (0); } /* ** MODSEQKEY - verify that sequence specified is valid ** ** Parameters: ** domain - list of domains ** relname - relation name ** seq_ok - whether it is ok to specify the sequence ** ascending or descending ** ** Return Codes: ** 0 - ok ** > 0 - error in sequence specified ** ** Called by: ** getkeys */ modseqkey(domain, relname, seq_ok) char *domain; char *relname; int seq_ok; { register char *cp, c; register int ret; ret = 0; for (cp = domain; c = *cp++; ) if (c == ':') break; if (c != '\0') { /* replace ":" with null */ *(cp - 1) = '\0'; /* verify sequence is valid */ if (!seq_ok) { closeall(0l, 0l); ret = error(BADSEQSPEC, relname, cp, domain, 0); } else if (sequal("descending", cp) || sequal("d", cp)) ret = -1; else if (!(sequal("ascending", cp) || sequal("a", cp))) { closeall(0l, 0l); ret = error(INVALIDSEQ, relname, cp, domain, 0); } } return (ret); } /* ** GETFILL -- Get fill factor and minimum pages parameters ** from argument list, convert them from ascii to integer ** and store them in global variables. If the global ** variable for the corresponding parameter is zero, ** it means that that parameter is not allowed and an ** error is generated. */ /*ARGSUSED*/ getfill(d, pv, rel, mp) DESC *d; register PARM *pv; char *rel; struct modtab *mp; { register char *p1; register int err; char *p2; int i, j; int fill_flag, min_flag, max_flag, lid_flag[MAXLID]; err = 0; fill_flag = min_flag = max_flag = FALSE; for (i = 0; i < d->reldum.reldim; ++i) lid_flag[i] = FALSE; while ((p1 = (pv++)->pv_val.pv_str) != NULL) { p2 = (pv++)->pv_val.pv_str; if (sequal(p1, "fillfactor")) { if (F_fac == 0 || fill_flag) { err = NOTALLOWED; break; } p1 = p2; F_fac = atoi(p1); if (F_fac > 100 || F_fac < 1) { err = FILLBOUND; break; } fill_flag = TRUE; continue; } if (sequal(p1, "minpages")) { if (Mn_pages == 0 || min_flag) { err = NOTALLOWED; break; } p1 = p2; Mn_pages = atoi(p1); if (Mn_pages < 1) { err = MINPGBOUND; break; } if (max_flag && (Mn_pages > Mx_pages)) { err = MINGTMAX; break; } min_flag = TRUE; continue; } if (sequal(p1, "maxpages")) { if (Mx_pages == 0 || max_flag) { err = NOTALLOWED; break; } p1 = p2; Mx_pages = atoi(p1); if (Mx_pages < 1) { err = MAXPGBOUND; break; } if (min_flag && (Mn_pages > Mx_pages)) { err = MINGTMAX; break; } max_flag = TRUE; continue; } for ( i = 1; i <= d->reldum.reldim && !err; ++i) if (sequal(p1, ztack("lid", iocv(i)))) { if (lid_flag[i-1] || *Lid[i-1] == NULL) { err = NOTALLOWED; break; } for (j = 0; j < d->reldum.reldim; ++j) if (i - 1 != j && sequal(p2, Lid[j]) && lid_flag[j]) { err = NOTALLOWED; break; } p1 = p2; smove(p1, Lid[i - 1]); lid_flag[i - 1] = TRUE; break; } if (err) break; if (i <= d->reldum.reldim) continue; err = NEEDFILL; break; } if (err) { closeall(0l, 0l); return (error(err, rel, p1, 0)); } return (0); } /* ** MAKE_NEWREL -- Create a file for the modified relation ** and build one or more primary pages for the ** relation based on its storage structure and the ** number of tuples it must hold. */ make_newrel(desc) register DESC *desc; { register int tups_p_page; int width; concat(MODTEMP, Fileset, Mod_info.reltemp); close(creat(Mod_info.reltemp, FILEMODE)); if ((desc->relfp = open(Mod_info.reltemp, O_RDWR)) < 0) syserr("MAKE_NEWREL: open %.14s %d", Mod_info.reltemp, desc->relfp); desc->relopn = (desc->relfp + 1) * -5; desc->reldum.relprim = 1; if (abs(desc->reldum.relspec) == M_HASH && F_fac > 0 && Mn_pages > 0) { /* ** Determine the number of primary pages. The following ** first determines the number of tuples/page which the ** relation should have in order to get the requested ** fillfactor. Then that number is divided into the ** number of tuples to get the number of primary pages. ** To avoid round off, it must guaranteed that the ** number of tuples per page must be at least 1. ** ** primary_pages = #tuples / (#tuples/page * fillfactor) */ width = desc->reldum.relwid + 2 - LIDSIZE * desc->reldum.reldim; tups_p_page = (((MAXTUP+2) / width) * F_fac) / 100; if (tups_p_page == 0) tups_p_page = 1; /* we add one to simulate a ceiling function */ desc->reldum.relprim = desc->reldum.reltups / tups_p_page + 1; if (desc->reldum.relprim < Mn_pages) desc->reldum.relprim = Mn_pages; if (Mx_pages > 0 && desc->reldum.relprim > Mx_pages) desc->reldum.relprim = Mx_pages; # ifdef xZTR1 if (tTf(36, 0)) printf("using %ld prim pages\n", desc->reldum.relprim); # endif } desc->reldum.reltups = 0; return (0); } /* ** SORTREL - Call KSORT to sort the given relation. SORTREL ** sets up the descriptor struct specifying the sort ** keys and tells KSORT whether or not the hash key should ** be included as a sort key. */ sortrel(odesc, desc) DESC *odesc; register DESC *desc; { extern char *Pathname; register int i; char buf[50]; DESC tempdesc; char *temp; int len; short smalli; concat(ISAM_SORTED, Fileset, Mod_info.outfile); if (close(creat(Mod_info.outfile, FILEMODE))) syserr("SORTREL: creat %.14s", Mod_info.outfile); bmove(odesc, &tempdesc, sizeof *odesc); for (i = 1; i <= desc->reldum.relatts; ++i) /* set up temporary descriptor for ksort with new keyed fields */ { tempdesc.relxtra[i] = desc->relxtra[i]; tempdesc.relgiven[i] = desc->relgiven[i]; } if (abs(desc->reldum.relspec) == M_HASH && !desc->reldum.reldim) { /* sort on hash bucket first, (if ordering sort on ordering key, not bucket) */ tempdesc.relgiven[0] = 1; for (i = 1; i <= desc->reldum.relatts; i++) tempdesc.relgiven[i]++; } # ifdef xZTR2 if (tTf(36, 4)) { printf("sortrel: "); printdesc(&tempdesc); } # endif /* flush buffers used by modify so that ksort can't look at them */ flush_rel(desc, TRUE); resetacc(NULL); /* copy Fileset so it can't get trashed */ len = length(Fileset) + 1; temp = (char *) need(Qbuf, len); bmove(Fileset, temp, len); initp(); setp(PV_STR, temp); setp(PV_STR, Mod_info.infile); setp(PV_STR, Mod_info.outfile); /* Descriptor for new relation */ setp(PV_STR, tempdesc.reldum.relid); setp(PV_STR, tempdesc.reldum.relowner); setp(PV_INT, tempdesc.reldum.relspec); setp(PV_INT, tempdesc.reldum.relindxd); setp(PV_INT, tempdesc.reldum.relstat2); setp(PV_INT, tempdesc.reldum.relstat); setp(PV_INT, (short) tempdesc.reldum.relsave); setp(PV_INT, (short) tempdesc.reldum.reltups); setp(PV_INT, tempdesc.reldum.relatts); setp(PV_INT, tempdesc.reldum.relwid); setp(PV_INT, (short) tempdesc.reldum.relprim); setp(PV_INT, (short) tempdesc.reldum.relfree); setp(PV_INT, (short) tempdesc.reldum.relstamp); setp(PV_INT, tempdesc.reldum.reldim); setp(PV_STR, tempdesc.relvname); setp(PV_INT, tempdesc.relfp); setp(PV_INT, tempdesc.relopn); setp(PV_INT, (short) tempdesc.reladds); setp(PV_INT, tempdesc.reltid.ltid); for (i = 0; i <= tempdesc.reldum.relatts; ++i) { smalli = (short) tempdesc.reloff[i]; setp(PV_INT, smalli); smalli = (short) tempdesc.relfrmt[i]; setp(PV_INT, smalli); smalli = (short) tempdesc.relfrml[i]; setp(PV_INT, smalli); smalli = (short) tempdesc.relxtra[i]; setp(PV_INT, smalli); smalli = (short) tempdesc.relgiven[i]; setp(PV_INT, smalli); } if (tempdesc.reldum.reldim > 0) { setp(PV_STR, odesc->relbtree->reldum.relid); setp(PV_STR, odesc->relbtree->reldum.relowner); setp(PV_INT, odesc->relbtree->reldum.relspec); setp(PV_INT, odesc->relbtree->reldum.relindxd); setp(PV_INT, odesc->relbtree->reldum.relstat2); setp(PV_INT, odesc->relbtree->reldum.relstat); setp(PV_INT, (short) odesc->relbtree->reldum.relsave); setp(PV_INT, (short) odesc->relbtree->reldum.reltups); setp(PV_INT, odesc->relbtree->reldum.relatts); setp(PV_INT, odesc->relbtree->reldum.relwid); setp(PV_INT, (short) odesc->relbtree->reldum.relprim); setp(PV_INT, (short) odesc->relbtree->reldum.relfree); setp(PV_INT, (short) odesc->relbtree->reldum.relstamp); setp(PV_INT, odesc->relbtree->reldum.reldim); setp(PV_STR, odesc->relbtree->relvname); setp(PV_INT, odesc->relbtree->relfp); setp(PV_INT, odesc->relbtree->relopn); setp(PV_INT, (short) odesc->relbtree->reladds); setp(PV_INT, odesc->relbtree->reltid.ltid); for (i = 0; i <= odesc->relbtree->reldum.relatts; ++i) { smalli = (short) odesc->relbtree->reloff[i]; setp(PV_INT, smalli); smalli = (short) odesc->relbtree->relfrmt[i]; setp(PV_INT, smalli); smalli = (short) odesc->relbtree->relfrml[i]; setp(PV_INT, smalli); smalli = (short) odesc->relbtree->relxtra[i]; setp(PV_INT, smalli); smalli = (short) odesc->relbtree->relgiven[i]; setp(PV_INT, smalli); } } call(mdKSORT, NULL); /* flush buffers used by ksort so that modify can't look at them */ flush_rel(desc, TRUE); resetacc(NULL); # ifdef xZTR1 if (tTf(36,9)) printf("SORTREL: done calling ksort\n"); #endif return (0); } /* ** SORT_ISAM -- Sorts an isam relation back to its original order ** so that it will be inserted into the relation in the proper order. ** It is presently not in order because it has been sorted according ** to a specified field for ordering. */ sort_isam(sdesc, desc) DESC *sdesc; DESC *desc; { long lid[MAXLID]; register int i, j, k; char tup_buf[MAXTUP], last_tup[MAXTUP], *dp, *sp; FILE *sfp, *fp; TID tid, tidpos; DESC tempdesc; int w; if (desc->reldum.reldim > 0) Btree_fd = desc->btree_fd; concat(STEMP, Fileset, Mod_info.temp_sort); if ((sfp = fopen(Mod_info.temp_sort, "w")) == NULL) syserr("sort_isam: can't open %s", Mod_info.temp_sort); if ((fp = fopen(Mod_info.outfile, "r")) == NULL) syserr("sort_isam: can't open %s", Mod_info.outfile); for (i = 0; i < desc->reldum.reldim; lid[i++] = 0); /* create input file for sort with proper lid attached to each tuple */ w = sdesc->reldum.relwid - LIDSIZE * sdesc->reldum.reldim; for ( ; ; ) { i = fread(tup_buf, 1, sdesc->reldum.relwid, fp); if (i == 0) break; if (i != sdesc->reldum.relwid) syserr("sort_isam: read error in %s", Mod_info.outfile); for (j = 0; j < desc->reldum.reldim; ++j) if (j < NLidKeys && j < desc->reldum.reldim - 1) { dp = tup_buf + (sdesc->reloff[LidKey[j]] & I1MASK); sp = last_tup + (sdesc->reloff[LidKey[j]] & I1MASK); if (!bequal(dp, sp, sdesc->relfrml[LidKey[j]]) || !lid[j]) { ++lid[j]; for (k = j + 1; k < desc->reldum.reldim; ++k) lid[k] = 0; break; } } else { if (!lid[0]) { lid[0] = 1; if (!(desc->reldum.reldim - 1)) break; } ++lid[desc->reldum.reldim - 1]; break; } bmove(tup_buf, last_tup, sdesc->reldum.relwid); /* reserve a slot in btree for tuple */ insert_mbtree(desc, Mod_info.btree, lid, &tid, &tidpos); bmove(lid, tup_buf + w, LIDSIZE * desc->reldum.reldim); if (fwrite(tup_buf, 1, sdesc->reldum.relwid + LIDSIZE * desc->reldum.reldim, sfp) != sdesc->reldum.relwid + LIDSIZE * desc->reldum.reldim) syserr("sort_isam: write error in %s", Mod_info.temp_sort); } fclose(fp); fclose(sfp); /* set up new descriptor accounting for lid field */ bmove(sdesc, &tempdesc, sizeof *sdesc); tempdesc.reldum.relspec = M_ORDER; for (i = 0; i < desc->reldum.reldim; ++i) { tempdesc.reldum.relwid += LIDSIZE; ++tempdesc.reldum.relatts; tempdesc.reloff[tempdesc.reldum.relatts] = tempdesc.reldum.relwid - LIDSIZE; tempdesc.relfrmt[tempdesc.reldum.relatts] = INT; tempdesc.relfrml[tempdesc.reldum.relatts] = LIDSIZE; } j = 0; /* use old keying attributes for specifying sort order */ clearkeys(&tempdesc); for (i = 1; i <= sdesc->reldum.relatts; ++i) if (sdesc->relxtra[i]) { tempdesc.relgiven[i] = sdesc->relxtra[i]; ++j; } for (i = 1; i <= tempdesc.reldum.relatts; ++i) if (!tempdesc.relgiven[i]) tempdesc.relgiven[i] = ++j; sortfile(Mod_info.temp_sort, &tempdesc, FALSE); if (unlink(Mod_info.outfile) < 0) syserr("can't unlink %s", Mod_info.outfile); if (link(ztack(REPL_OUT, Fileset), Mod_info.outfile) == -1) syserr("can't link %s to %s", ztack(REPL_OUT, Fileset), Mod_info.outfile); if (unlink(Mod_info.temp_sort) < 0) syserr("sort_isam: can't unlink %s", Mod_info.temp_sort); if (unlink(ztack(REPL_OUT, Fileset)) < 0) syserr("sort_isam: can't unlink replout file"); } /* ** FILL_REL -- Fill the new relation with tuples from either ** the old relation or the output file of KSORT. */ fill_rel(sdesc, desc, sortit) register DESC *sdesc, *desc; char sortit; { register int i; char tup_buf[MAXTUP], last_tup[MAXTUP], tup[2 * LIDSIZE]; char junk[4], newreltype, anytups, chkdups; int need, j, k; long lnum, lid[MAXLID], l, page, t; TID tid, stid, stidlim, ntid, tidpos, btid; FILE *fp, *spfp; char *dp, *sp; int w, temp; struct locator tidloc; newreltype = abs(desc->reldum.relspec); if (sortit) { if ((fp = fopen(Mod_info.outfile, "r")) == NULL) syserr("FILL_REL: fopen %.14s", Mod_info.outfile); } else { cleanrel(sdesc); /* make sure each page is read fresh */ find(sdesc, NOKEY, &stid, &stidlim); } if (newreltype == M_ISAM && (NLidKeys > 0 || !desc->reldum.reldim)) { lnum = 0; stuff_page(&tid, &lnum); tid.line_id = 0; get_page(desc, &tid); concat(ISAM_SPOOL, Fileset, Mod_info.spfile); /* assume that spool file is not needed */ spfp = NULL; Mod_info.spflag = FALSE; if (F_fac == 0) F_fac = 100; /* setup relgiven field for kcompare later on */ for (i = 1; i <= desc->reldum.relatts; i++) desc->relgiven[i] = desc->relxtra[i]; if (desc->reldum.reldim) Btree_fd = desc->btree_fd; } desc->reladds = 0; for (i = 0; i < desc->reldum.reldim; lid[i++] = 0) continue; anytups = FALSE; chkdups = !sortit && (newreltype != M_ORDER); # ifdef xZTR2 if (tTf(36, 3)) { printf(" FILLREL: "); printdesc(sdesc); printdesc(desc); } # endif for (;;) { w = (newreltype == M_ISAM) ? sdesc->reldum.relwid + desc->reldum.reldim * LIDSIZE : sdesc->reldum.relwid; if (sortit) { i = fread(tup_buf, 1, w, fp); if (i == 0) break; if (i != w) syserr("FILL_REL: fread A %d", i); if (newreltype == M_HASH && !desc->reldum.reldim) if (fread(junk, 1, 4, fp) != 4) syserr("FILL_REL: fread B"); } else { # ifdef xZTR2 if (tTf(36, 1)) { printf("FILL_REL: stid "); dumptid(&stid); printf("FILL_REL: stidlim "); dumptid(&stidlim); } # endif i = get(sdesc, &stid, &stidlim, tup_buf, TRUE); # ifdef xZTR2 if (tTf(36, 1)) { printf("FILLREL: get %d ", i); printup(sdesc, tup_buf); } # endif if (i < 0) syserr("FILL_REL: get %d", i); if (i == 1) break; } if (newreltype != M_ISAM || (newreltype == M_ISAM && NLidKeys == 0 && desc->reldum.reldim > 0)) { for (j = 0; j < desc->reldum.reldim; ++j) if (j < NLidKeys && j < desc->reldum.reldim - 1) { dp = tup_buf + (sdesc->reloff[LidKey[j]] & I1MASK); sp = last_tup + (sdesc->reloff[LidKey[j]] & I1MASK); if (!bequal(dp, sp, sdesc->relfrml[LidKey[j]]) || !lid[j]) { ++lid[j]; for (k = j + 1; k < desc->reldum.reldim; ++k) lid[k] = 0; break; } } else { if (!lid[0]) { lid[0] = 1; if (!(desc->reldum.reldim -1)) break; } ++lid[desc->reldum.reldim - 1]; break; } Btree_fd = desc->btree_fd; if (!desc->reldum.reldim || NLidKeys > 0) { /* assume unordered so btree inserts done ** separately */ temp = 0; if (desc->reldum.reldim > 0) { temp = desc->reldum.reldim; desc->reldum.reldim = 0; desc->reldum.relwid -= temp * LIDSIZE; } if ((i = insert(desc, &tid, tup_buf, chkdups)) < 0) syserr("FILL_REL: insert %d", i); if (NLidKeys > 0) { bmove(&tid, &stid, LIDSIZE); desc->reldum.reldim = temp; desc->reldum.relwid += temp * LIDSIZE; insert_mbtree(desc, Mod_info.btree, lid, &tid, &tidpos); } } if (desc->reldum.reldim && !NLidKeys) { /* new relation not changed, only lids added */ page = RT; for (j = 0; j < desc->reldum.reldim - 1; ++j) { if (!lid[j]) lid[j] = 1; if ((t = get_tid(page, lid[j], &tidloc)) < 0) { insert_btree(Mod_info.btree, page, lid[j], &ntid, &tidpos, j + 2); bmove(&ntid, &page, LIDSIZE); } else bmove(&t, &page, LIDSIZE); } insert_btree(Mod_info.btree, page, lid[abs(desc->reldum.reldim) - 1], &stid, &tidpos, FALSE); } bmove(tup_buf, last_tup, sdesc->reldum.relwid); if (desc->reldum.reldim > 0) { dp = tup_buf + desc->reldum.relwid - desc->reldum.reldim * LIDSIZE; bmove(lid, dp, LIDSIZE * desc->reldum.reldim); } # ifdef xZTR2 if (tTf(36, 2)) { printf("FILL_REL: insert "); printup(desc, tup_buf); printf("FILL_REL: insert ret %d at", i); dumptid(&tid); } # endif continue; } if (anytups) i = kcompare(desc, tup_buf, last_tup); else { anytups = TRUE; i = 1; } bmove(tup_buf, last_tup, desc->reldum.relwid); need = canonical(desc, tup_buf); if (i == 0 && need > space_left(Acc_head)) { /* spool out this tuple. will go on overflow page later */ if (spfp == NULL) { if ((spfp = fopen(Mod_info.spfile, "w")) == NULL) syserr("FILL_REL: fopen %.14s", Mod_info.spfile); Mod_info.spflag = TRUE; } if (fwrite(tup_buf, 1, desc->reldum.relwid, spfp) != desc->reldum.relwid) syserr("FILL_REL: putb spool"); continue; } j = (100 - F_fac) * MAXTUP / 100; if (j < need) j = need; if (i != 0 && j > space_left(Acc_head)) { if (i = add_prim(desc, &tid)) syserr("FILL_REL: force ovflo %d", i); } tid.line_id = newlino(need); put_tuple(&tid, Acctuple, need); if (NLidKeys > 0) { bmove(tup_buf + desc->reldum.relwid - LIDSIZE * desc->reldum.reldim, lid, LIDSIZE * desc->reldum.reldim); page = RT; for (j = 0; j < desc->reldum.reldim; ++j) { if ((t = get_tid(page, lid[j], &tidloc)) < 0) syserr("get_tid error in modify isam ordered"); page = t; } stuff_page(&btid, &tidloc.pageno); btid.line_id = tidloc.page.node.leafnode.tid_loc[tidloc.offset]; /* place proper tid in tree */ replace_btree(tid, &btid); } desc->reladds++; } if (sortit) { fclose(fp); unlink(Mod_info.outfile); } if (newreltype == M_ISAM && desc->reldum.reldim <= 0) { if (i = pageflush(Acc_head)) syserr("fill_rel:pg clean %d", i); if (spfp != NULL) fclose(spfp); } if (!desc->reldum.reldim || NLidKeys > 0) desc->reldum.reltups = desc->reladds; desc->reladds = 0; return (0); } /* ** BLDINDEX - ** ** Parameters: ** d - descriptor for relation ** ** Return Codes: ** 0 - ok ** <0 - error ** ** Trace Flags: ** Z38.7, Z38.8 ** ** Called by: ** modify ** */ bldindex(d) register DESC *d; { register TID *tid; register int tmp; TID tidx; struct accbuf dirbuf; int keywid, level, savespec, keyx[MAXDOM]; int offset, len; char tuple[MAXTUP], temptup[MAXTUP], *key; long pageid, start, stop, newstart, newstop; tid = &tidx; keywid = 0; for (tmp = 0; tmp < MAXDOM; tmp++) keyx[tmp] = 0; for (tmp = 1; tmp <= d->reldum.relatts; tmp++) if (d->relxtra[tmp] > 0) { keyx[d->relxtra[tmp] - 1] = tmp; keywid += d->relfrml[tmp] & I1MASK; } /* Determine the last page of the relation. This will ** only work if all pages have been written out. Fill_rel ** must guarantee that all pages have been written */ level = 0; last_page(d, tid, 0); pluck_page(tid, &stop); start = 0; dirbuf.filedesc = d->relfp; dirbuf.rel_tupid = d->reltid.ltid; savespec = d->reldum.relspec; for (;;) { # ifdef xZTR2 if (tTf(38, 7)) printf("isam: level %d\n", level); # endif dirbuf.ovflopg = start; dirbuf.mainpg = level; dirbuf.thispage = stop + 1; dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf); offset = dirbuf.linetab[0]; dirbuf.bufstatus = BUF_DIRTY | BUF_DIRECT; dirbuf.nxtlino = 0; newstart = stop + 1; newstop = newstart; for (pageid = start; pageid <= stop; pageid++) { # ifdef xZTR2 if (tTf(38, 8)) printf("isam:get key from %ld\n", pageid); # endif stuff_page(tid, &pageid); tid->line_id = 0; if (tmp = get(d, tid, tid, tuple, FALSE)) { /* ** If the relation is empty, then page 0 will ** return AMINVL_ERR on a get(). Form a blank tuple ** and use it to create a one tuple directory */ if (pageid == 0 && tmp == AMINVL_ERR) { clr_tuple(d, tuple); } else { return (-2); } } /* ** If this is the first level then form the tuple ** from the mainpage of the relation. Otherwise ** the tuple is the first tuple of a directory page ** and it is already correctly formed. */ if (level == 0) { key = temptup; for (tmp = 0; keyx[tmp] != 0; tmp++) { len = d->relfrml[keyx[tmp]] & I1MASK; bmove(&tuple[d->reloff[keyx[tmp]]], key, len); key += len; } key = temptup; } else key = tuple; if (keywid > space_left(&dirbuf)) { if (pageflush(&dirbuf)) return (-3); dirbuf.thispage++; newstop = dirbuf.thispage; dirbuf.ovflopg = pageid; dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf); offset = dirbuf.linetab[0]; dirbuf.bufstatus = BUF_DIRTY; dirbuf.nxtlino = 0; } /* copy key to directory page */ bmove(key, (char *) &dirbuf + offset, keywid); /* update next line number */ offset += keywid; dirbuf.nxtlino++; dirbuf.linetab[-dirbuf.nxtlino] = offset; } if (pageflush(&dirbuf)) return (-4); if (newstart == newstop) break; d->reldum.relspec = abs(d->reldum.relspec); level++; start = newstart; stop = newstop; } d->reldum.relspec = savespec; d->reldum.relprim = newstart; return (0); } /* ** UNSPOOL -- Take tuples saved in spool file and insert them ** in new relation. This is only for ISAM relations. */ unspool(sdesc, desc) register DESC *sdesc, *desc; { register int i, j; TID tid, btid; char tup_buf[MAXTUP], tup[2 * LIDSIZE]; FILE *spfp; long lid[MAXLID], page, t; int w; struct locator tidpos; w = sdesc->reldum.relwid + desc->reldum.reldim * LIDSIZE; if (Mod_info.spflag) { if ((spfp = fopen(Mod_info.spfile, "r")) == NULL) syserr("UNSPOOL: fopen spool"); while ((i = fread(tup_buf, 1, w, spfp)) == w) { if ((i = insert(desc, &tid, tup_buf, FALSE)) < 0) syserr("UNSPOOL: insert %.14s %d", desc->reldum.relid, i); if (NLidKeys > 0) { bmove(tup_buf + desc->reldum.relwid - LIDSIZE * desc->reldum.reldim, lid, LIDSIZE * desc->reldum.reldim); page = RT; for (j = 0; j < desc->reldum.reldim; ++j) { if ((t = get_tid(page, lid[j], &tidpos)) < 0) syserr("get_tid error in unspool"); page = t; } stuff_page(&btid, &tidpos.pageno); btid.line_id = tidpos.page.node.leafnode.tid_loc[tidpos.offset]; replace_btree(tid, &btid); } } if (i != 0) syserr("UNSPOOL: read %d", i); fclose(spfp); unlink(Mod_info.spfile); } desc->reldum.reltups += desc->reladds; desc->reladds = 0; return (0); } /* ** FILL_BATCH -- Create and fill a batch file containing the ** updates for the system catalog so that MODIFY will ** be recoverable if the system crashes. */ fill_batch(odesc, desc) DESC *odesc; register DESC *desc; { register DESC *dessys; register int i, k; struct relation reltup, rkey; TID tid, lotid, hitid; struct attribute atttup, akey; int numatts, j; char prebatch[MAXNAME + 4], modbatch[MAXNAME + 4]; if (bequal(desc->reldum.relid, "relation ", 12)) { clearkeys(desc); setkey(desc, &rkey, desc->reldum.relid, RELID); setkey(desc, &rkey, desc->reldum.relowner, RELOWNER); if (i = getequal(desc, &rkey, &reltup, &tid)) syserr("FILL_BATCH: geteq rel rel %d", i); bmove(&tid, &desc->reltid, sizeof desc->reltid); } else bmove(&odesc->reltid, &desc->reltid, sizeof desc->reltid); resetacc(Acc_head); concat(MOD_PREBATCH, Fileset, prebatch); close(creat(prebatch, FILEMODE)); if ((Batch_fp = open(prebatch, O_RDWR)) < 0) syserr("FILL_BATCH: open %.14s %d", prebatch, Batch_fp); smove(Fileset, Batchbuf.file_id); Batch_cnt = 0; wrbatch(desc, sizeof *desc); if (bequal(desc->reldum.relid, "attribute ", 12)) dessys = desc; else dessys = &Admin.adattd; clearkeys(dessys); setkey(dessys, &akey, desc->reldum.relid, ATTRELID); setkey(dessys, &akey, desc->reldum.relowner, ATTOWNER); if (i = find(dessys, EXACTKEY, &lotid, &hitid, &akey)) syserr("FILL_BATCH: find %d", i); /* if ordered relation, one of attributes is LID field */ numatts = j = desc->reldum.relatts - desc->reldum.reldim; while(!(i = get(dessys, &lotid, &hitid, &atttup, TRUE)) && j > 0) if (!kcompare(dessys, &akey, &atttup)) if (atttup.attid <= numatts) { j--; atttup.attxtra = desc->relxtra[atttup.attid]; wrbatch(&lotid, sizeof lotid); wrbatch(&atttup, sizeof atttup); } for (k = 1; k <= desc->reldum.reldim; ++k) /* create new tuple corresponding to LID field; LID field is the ** last field of relation, a 4-byte integer */ { smove(desc->reldum.relid, atttup.attrelid); bmove(desc->reldum.relowner, atttup.attowner, 2); atttup.attid = numatts + k; smove(Lid[k - 1], atttup.attname); pad(atttup.attname, MAXNAME); atttup.attoff = desc->reldum.relwid - (desc->reldum.reldim - k + 1) * LIDSIZE; atttup.attfrmt = INT; atttup.attfrml = LIDSIZE; atttup.attxtra = 0; wrbatch(&atttup, sizeof atttup); } if (i < 0 || j > 0) syserr("FILL_BATCH: get att %d count %d", i, j); /* get rid of attribute pages */ cleanrel(dessys); flushbatch(); close(Batch_fp); concat(MODBATCH, Fileset, modbatch); if (link(prebatch, modbatch) == -1) syserr("FILL_BATCH: can't link %.14s %.14s", prebatch, modbatch); unlink(prebatch); return (0); } /* ** MAKE_BSEC -- Creates the seecondary btree relation by first creating ** a heaped relation. The main relation tids are found by ** scanning the leaves of the btree. The relation is then ** modified to an isam relation. */ make_bsec(relname, dim) char *relname; int dim; { PARM pv[8]; register int i; DESC bdesc; TID tid, btid; long mtid, page, t, next; char tuple[2 * LIDSIZE], btree[MAXNAME], btreefile[MAXNAME + 4]; struct locator tidpos; extern char *iocv(); extern DESC Reldes; pv[0].pv_val.pv_str = "0000002"; capital(trim_relname(relname), btree); pv[1].pv_val.pv_str = btree; pv[2].pv_val.pv_str = "mtid"; pv[3].pv_val.pv_str = "i4"; pv[4].pv_val.pv_str = "btid"; pv[5].pv_val.pv_str = "i4"; pv[6].pv_type = PV_EOF; if (create(6, pv)) syserr("can't create btreesec %s", pv[1].pv_val.pv_str); if (noclose(&Reldes)) syserr("noclose in make_bsec"); if (i = openr(&bdesc, OR_WRITE, btree)) syserr("opening bsec relation %d", i); btreename(relname, btreefile); if ((Btree_fd = open(btreefile, O_RDWR)) < 0) syserr("make_bsec: can't open %s", btreefile); page = RT; for (i = 0; i < dim - 1; ++i) { t = get_tid(page, 1, &tidpos); if (t < 0) break; /* lid value doesn't exist */ bmove(&t, &page, LIDSIZE); } if (t >= 0) /* only do inserts if there are lids! */ { do { get_node(page, &tidpos.page); next = tidpos.page.nexttree; get_tid(page, 1, &tidpos); page = tidpos.pageno; for (;;) /* scan through leaves of btree */ { stuff_page(&btid, &page); for (i = 0; i < tidpos.page.nelmts; ++i) { btid.line_id = tidpos.page.node.leafnode.tid_loc[i]; mtid = tidpos.page.node.leafnode.tid_pos[btid.line_id]; /* form tuple */ bmove(&mtid, tuple, LIDSIZE); bmove(&btid, tuple + LIDSIZE, LIDSIZE); if (insert(&bdesc, &tid, tuple, TRUE) < 0) syserr("insert error in btreesec"); } page = tidpos.page.node.leafnode.nextleaf; if (page == NULL) break; else get_node(page, &tidpos.page); } } while (page = next); } close(Btree_fd); closer(&bdesc); /* modify to isam on mtid */ pv[0].pv_val.pv_str = btree; pv[1].pv_val.pv_str = "isam"; pv[2].pv_val.pv_str = "name"; pv[3].pv_val.pv_str = "mtid"; pv[4].pv_val.pv_str = "\0"; pv[5].pv_val.pv_str = "fillfactor"; /* use fillfactor provided for main relation */ if (F_fac == 0) pv[6].pv_val.pv_str = iocv(80); else pv[6].pv_val.pv_str = iocv(F_fac); pv[7].pv_type = PV_EOF; if (modify(7, pv)) syserr("can't modify btreesec to isam"); }