1: # include   <stdio.h>
   2: # include   <ingres.h>
   3: # include   <pv.h>
   4: # include   <aux.h>
   5: # include   <access.h>
   6: # include   <batch.h>
   7: # include   <lock.h>
   8: # include   <opsys.h>
   9: # include   <func.h>
  10: # include   <version.h>
  11: # include   <symbol.h>
  12: # include   <catalog.h>
  13: # include   <btree.h>
  14: # include   <sccs.h>
  15: # include   <errors.h>
  16: 
  17: SCCSID(@(#)modify.c	8.8	5/7/85)
  18: 
  19: extern  short   tTdbu[];
  20: extern  int modify();
  21: extern  int null_fn();
  22: 
  23: struct fn_def ModifyFn =
  24: {
  25:     "MODIFY",
  26:     modify,
  27:     null_fn,
  28:     null_fn,
  29:     NULL,
  30:     0,
  31:     tTdbu,
  32:     100,
  33:     'Z',
  34:     0
  35: };
  36: 
  37: /*
  38: **  MODIFY -- converts any relation to the specified
  39: **		storage structure
  40: **
  41: **	arguments:
  42: **	0 - relation name
  43: **	1 - storage structure ("heap", "cheap", "hash", "chash",
  44: **		"isam", "cisam")
  45: **	2 - "name" for attribute names, or "num" for numbers
  46: **	3 - key1
  47: **	4 - key2
  48: **	    .
  49: **	    .
  50: **	i - null
  51: **	i+1 - option name (e.g., "fillfactor")
  52: **	i+2 - option value
  53: **	    .
  54: **	    .
  55: **
  56: **	If all the options default, parameter i -> pc are omitted.
  57: **	If no keys are provided, parameter 2 is omitted.
  58: */
  59: 
  60: int     F_fac, Mn_pages, Mx_pages;
  61: char        Lid[MAXLID][MAXNAME];
  62: int     NLidKeys;
  63: int     LidKey[MAXLID];
  64: 
  65: struct modtab
  66: {
  67:     char    *type;
  68:     char    newrelspec;
  69:     char    yeskeys;
  70:     char    sortit;
  71:     char    yes_seq;
  72:     int f_fac;
  73:     int mn_pages;
  74:     int mx_pages;
  75: };
  76: 
  77: 
  78: struct modtab   Modtab[] =
  79: {
  80:     /* type		spec	keys	sort	seq	ffac	min	max */
  81: 
  82:     "heap",     M_HEAP, FALSE,  FALSE,  FALSE,  0,  0,  0,
  83:     "cheap",    -M_HEAP,FALSE,  FALSE,  FALSE,  0,  0,  0,
  84:     "hash",     M_HASH, TRUE,   TRUE,   FALSE,  50, 10, -1,
  85:     "chash",    -M_HASH,TRUE,   TRUE,   FALSE,  75, 1,  -1,
  86:     "isam",     M_ISAM, TRUE,   TRUE,   FALSE,  80, 0,  0,
  87:     "cisam",    -M_ISAM,TRUE,   TRUE,   FALSE,  100,    0,  0,
  88:     "heapsort", M_HEAP, TRUE,   TRUE,   TRUE,   0,  0,  0,
  89:     "cheapsort",    -M_HEAP,TRUE,   TRUE,   TRUE,   0,  0,  0,
  90:     "truncated",    M_TRUNC,FALSE,  FALSE,  FALSE,  0,  0,  0,
  91:     "ordered",  M_ORDER,TRUE,   FALSE,  FALSE,  0,  0,  0,
  92:     0
  93: };
  94: 
  95: struct mod_info
  96: {
  97:     char    outfile[MAXNAME + 4];   /* result file filled by ksort */
  98:     char    formfile[MAXNAME + 4];  /* file with descriptor for ksort */
  99:     char    infile[MAXNAME + 4];    /* input file for ksort (relation itself */
 100:     char    reltemp[MAXNAME + 4];   /* file holding new relation */
 101:     char    spfile[MAXNAME + 4], spflag;    /* isam spool file for overflow */
 102:     char    btree[MAXNAME + 4]; /* file holding temporary btree structure */
 103:     char    temp_sort[MAXNAME + 4]; /* file holding result of special isam
 104: 					** required when ordering on a field
 105: 					*/
 106: };
 107: 
 108: struct mod_info Mod_info;
 109: 
 110: extern DESC Btreesec;
 111: extern int Btree_fd;
 112: 
 113: 
 114: 
 115: modify(pc, pv)
 116: int pc;
 117: PARM    *pv;
 118: {
 119:     register int        i, j;
 120:     register char       *rname;
 121:     register struct modtab  *mp;
 122:     struct modtab       *p;
 123:     int         sorted, dim;
 124:     DESC            dold, dnew;
 125:     long            temptid;
 126:     extern int      Noupdt;
 127:     extern DESC     Attdes;
 128:     struct attribute    atttup, attkey;
 129:     TID         tid;
 130:     int         lidkey, numatts;
 131:     extern char     *trim_relname();
 132:     extern char     *iocv();
 133: 
 134: 
 135: #	ifdef xZTR1
 136:     if (tTf(34, -1))
 137:     {
 138:         printf("enter modify\n");
 139:         prvect(pc, pv);
 140:     }
 141: #	endif
 142: 
 143:     pv[pc].pv_val.pv_str = NULL;
 144: 
 145:     /* check for nice parameters */
 146:     if (pc < 2)
 147:         syserr("MODIFY: pc %d", pc);
 148: 
 149:     /* save relation name for error messages */
 150:     rname = (pv++)->pv_val.pv_str;  /* *pv now pointes to storage spec */
 151: 
 152:     /* check for good relation */
 153:     i = openr(&dold, OR_READ, rname);
 154:     if (i == AMOPNVIEW_ERR)
 155:         return (error(NOMODVIEW, rname, 0));
 156:     if (i > 0)
 157:         /* reln does not exist */
 158:         return (error(NOREL, rname, 0));
 159:     else if (i < 0)
 160:         syserr("MODIFY: openr (%.14s) %d", rname, i);
 161:     /* can only modify a relation you own and isn't a sys rel */
 162: 
 163:     if (!bequal(Usercode, dold.reldum.relowner, UCODE_SZ))
 164:     {
 165:         i = NOOWN;
 166:     }
 167:     if ((dold.reldum.relstat & S_CATALOG) && Noupdt)
 168:     {
 169:         i = NOMODSYSREL;
 170:     }
 171:     if (i)
 172:     {
 173:         closer(&dold);
 174:         return (error(i, rname, 0));
 175:     }
 176: 
 177:     /*
 178: 	** Form descriptor for new relation. Here we need to
 179: 	** separate the pages from the old and new relations.
 180: 	** Since pages are identified by the TID of the relation
 181: 	** relation tuple, both old and new have the same identifiers.
 182: 	** To avoid this problem, a special TID is hand crafted for
 183: 	** the new relation.
 184: 	*/
 185:     bmove(&dold, &dnew, sizeof dnew);
 186:     dnew.reltid.s_tupid.line_id = (char) -2;    /* choose impossible reltid */
 187:     /* assume new relation isn't ordered */
 188:     if (dold.reldum.reldim)
 189:     {
 190:         dnew.reldum.relatts -= dold.reldum.reldim;
 191:         dnew.reldum.relwid -= dold.reldum.reldim * LIDSIZE;
 192:         dnew.reldum.reldim = 0;
 193:     }
 194: 
 195:     /* In case of an interrupt from a previous modify,
 196: 	** there might be pages around. Get rid of them.
 197: 	*/
 198:     cleanrel(&dnew);
 199: 
 200:     ingresname(dold.reldum.relid, dold.reldum.relowner, Mod_info.infile);
 201:     dim = 0;
 202:     NLidKeys = 0;
 203: 
 204:     /* scan for entry in relspec table */
 205:     for (mp = Modtab; mp->type; mp++)
 206:     {
 207:         if (bequal(mp->type, pv->pv_val.pv_str, 7) && bequal("ordered", pv->pv_val.pv_str, 7))
 208:         {
 209:             if ((dim = atoi(pv->pv_val.pv_str + 7)) <= 0 || dim > MAXLID)
 210:             {
 211:                 closer(&dold);
 212:                 return(error(BADORDDIM, rname, iocv(dim), 0));
 213:             }
 214:             break;
 215:         }
 216:         if (sequal(mp->type, pv->pv_val.pv_str))
 217:             break;
 218:     }
 219: 
 220:     /* if not found, error */
 221:     if (!mp->type)
 222:     {
 223:         closer(&dold);
 224:         return (error(BADSTORAGE, rname, pv->pv_val.pv_str, 0));    /* bad relspec */
 225:     }
 226: 
 227:     if (mp->newrelspec == M_ORDER && dold.reldum.relindxd == SECINDEX)
 228:     /* can't order an index relation */
 229:     {
 230:         closer(&dold);
 231:         return(error(NOORDINDX, rname,0));
 232:     }
 233: 
 234:     if (mp->newrelspec == M_ORDER)
 235:     {
 236:         dnew.reldum.reldim = dim;
 237:         for (i = 0; i < dim; ++i)
 238:         {
 239:             ++dnew.reldum.relatts;
 240:             dnew.relxtra[dnew.reldum.relatts] = 0;
 241:             dnew.reloff[dnew.reldum.relatts] = dnew.reldum.relwid;
 242:             dnew.relfrmt[dnew.reldum.relatts] = INT;
 243:             dnew.relfrml[dnew.reldum.relatts] = LIDSIZE;
 244:             dnew.reldum.relwid += LIDSIZE;
 245:         }
 246:         concat(BTREE, Fileset, Mod_info.btree);
 247:         create_btree(Mod_info.btree);
 248:         dnew.btree_fd = Btree_fd;
 249:         /* ok to order ascending/descending */
 250:         mp->yes_seq = TRUE;
 251:     }
 252:     else
 253:     {
 254:         dnew.reldum.relspec = mp->newrelspec;
 255:         if (dold.reldum.reldim)
 256:         {
 257:             dold.reldum.relatts -= dold.reldum.reldim;
 258:             dold.reldum.relwid -= dold.reldum.reldim * LIDSIZE;
 259:             dold.reldum.reldim = 0;
 260:             closer(dold.relbtree);
 261:             close(dold.btree_fd);
 262:         }
 263:     }
 264: 
 265:     if (dnew.reldum.relspec == M_TRUNC)
 266:         dnew.reldum.relspec = M_HEAP;
 267: 
 268:     pv++;   /* now points to first parameter */
 269: 
 270:     /* get the key domains information */
 271:     if ((i = getkeys(&pv, rname, &dnew, mp)) > 0)
 272:     {
 273:         closer(&dold);
 274:         return (i); /* user error */
 275:     }
 276: 
 277:     j = 0;
 278:     for (i = 0; i < NLidKeys; ++i)
 279:         if (LidKey[i] > dold.reldum.relatts - dold.reldum.reldim)
 280:         {
 281:             j = 1;
 282:             break;
 283:         }
 284: 
 285:     if (!j && dold.reldum.reldim)
 286:     /* treat old relation as if not ordered since lid field not needed */
 287:     {
 288:         dold.reldum.relatts -= dold.reldum.reldim;
 289:         dold.reldum.relwid -= dold.reldum.reldim * LIDSIZE;
 290:         dold.reldum.reldim = 0;
 291:         closer(dold.relbtree);
 292:         close(dold.btree_fd);
 293:     }
 294: 
 295:     if (!dnew.reldum.reldim || !NLidKeys)
 296:     {
 297:         F_fac = mp->f_fac;
 298:         Mn_pages = mp->mn_pages;
 299:         Mx_pages = mp->mx_pages;
 300:     }
 301:     else
 302:     /* set parameters to that of storage type of relation to be ordered */
 303:     {
 304:         for (p = Modtab; p->type; p++)
 305:             if (dnew.reldum.relspec == p->newrelspec)
 306:                 break;
 307:         F_fac = p->f_fac;
 308:         Mn_pages = p->mn_pages;
 309:         Mx_pages = p->mx_pages;
 310:     }
 311: 
 312:     if (mp->newrelspec != M_ORDER)
 313:         for (i = 0; i < dnew.reldum.reldim; ++i)
 314:             Lid[i][0] = NULL;
 315:     else
 316:         for (i = 1; i <= dnew.reldum.reldim; ++i)
 317:             concat("lid", iocv(i), Lid[i-1]);
 318: 
 319:     /* get fillfactor and other options if any */
 320:     if (i = getfill(&dnew, pv, rname, mp))
 321:     {
 322:         closer(&dold);
 323:         return (i); /* user error */
 324:     }
 325: 
 326:     /* check for duplicate attribute name */
 327:     if (mp->newrelspec == M_ORDER)
 328:     {
 329:         opencatalog("attribute", OR_READ);
 330:         setkey(&Attdes, &attkey, dnew.reldum.relid, ATTRELID);
 331:         setkey(&Attdes, &attkey, dnew.reldum.relowner, ATTOWNER);
 332:         numatts = dold.reldum.relatts - dold.reldum.reldim;
 333:         for (i = 0; i < dnew.reldum.reldim; ++i)
 334:         {
 335:             setkey(&Attdes, &attkey, Lid[i], ATTNAME);
 336:             if (getequal(&Attdes, &attkey, &atttup, &tid) == 0)
 337:             {
 338:                 if (atttup.attid <= numatts)
 339:                 /* ok to duplicate attributes that will be removed */
 340:                 {
 341:                     closer(&dold);
 342:                     return(error(INVALIDATTR, rname, Lid[i], 0));
 343:                 }
 344:             }
 345:         }
 346:     }
 347: 
 348:     /* lock the relation relation */
 349:     if (Lockrel)
 350:     {
 351:         get_p_tid(&dold, &temptid);
 352:         setrll(A_SLP, temptid, M_EXCL);
 353:     }
 354: 
 355:     if (!dnew.reldum.reldim || NLidKeys > 0)
 356:         /* compute new relation parameters & build descriptor */
 357:         make_newrel(&dnew);
 358: 
 359:     if (sorted = ((mp->sortit || NLidKeys > 0) && (dold.reldum.reltups != 0)))
 360:     {
 361:         sortrel(&dold, &dnew);
 362:         dold.reldum.relindxd = 0;
 363:     }
 364: 
 365:     if (!dnew.reldum.reldim || NLidKeys > 0)
 366:         /* physically create the new relation */
 367:         if (formatpg(&dnew, dnew.reldum.relprim) != 0)
 368:             syserr("modify: formatpg");
 369: 
 370:     /* clear relgiven field; if heap remove any keys */
 371:     clearkeys(&dnew);
 372: 
 373:     if (abs(dnew.reldum.relspec) == M_HEAP)
 374:         for (i = 1; i <= dnew.reldum.relatts; i++)
 375:             dnew.relxtra[i] = 0;
 376: 
 377:     if (NLidKeys > 0 && dnew.reldum.relspec == M_ISAM)
 378:         sort_isam(&dold, &dnew);
 379: 
 380:     if (mp->newrelspec != M_TRUNC)
 381:         fill_rel(&dold, &dnew, sorted);
 382: 
 383:     closer(&dold);  /* error return is impossible */
 384:     if (abs(dnew.reldum.relspec) == M_ISAM && (!dnew.reldum.reldim || NLidKeys > 0))
 385:     {
 386:         j = dnew.reldum.reldim;
 387:         dnew.reldum.reldim = 0;
 388:         if (i = bldindex(&dnew))
 389:             syserr("bldindex: %.14s %d", dnew.reldum.relid, i);
 390:         dnew.reldum.reldim = j;
 391:         unspool(&dold, &dnew);
 392:     }
 393: 
 394:     /*
 395: 	** New relation is now complete. The system relations need to
 396: 	** be updated. First destroy all buffers with pages from the
 397: 	** new relation.
 398: 	*/
 399:     if (i = cleanrel(&dnew))
 400:         syserr("modify:clean new %d,%.14s", i, dnew.reldum.relid);
 401: 
 402:     fill_batch(&dold, &dnew);
 403: 
 404:     /*
 405: 	** Close the file for the new relation. This must be
 406: 	** done after the fill_batch in case we are modifing
 407: 	** the attribute relation.
 408: 	*/
 409:     if (!dnew.reldum.reldim || NLidKeys > 0)
 410:         close(dnew.relfp);
 411:     dnew.relopn = 0;
 412:     ruboff("modify");
 413:     modupdate();
 414:     if (mp->newrelspec == M_ORDER)
 415:     {
 416:         close(dnew.btree_fd);
 417:         make_bsec(dnew.reldum.relid, dim);
 418:     }
 419:     rubon();
 420: 
 421:     if (Lockrel)
 422:         unlrl(temptid);
 423: 
 424:     return (0);
 425: }
 426: 
 427: 
 428: /*
 429: **	GETKEYS - get key domains information
 430: **
 431: **	Parameters:
 432: **		ppv - parameter vector with info about keys
 433: **		relname - relation name
 434: **		d - new descriptor for the relation
 435: **		mp - mod table
 436: **
 437: **	Return Codes:
 438: **		0 - ok
 439: **		>0 - error from modseqkey
 440: */
 441: getkeys(ppv, relname, d, mp)
 442: PARM        **ppv;
 443: char        *relname;
 444: register DESC   *d;
 445: struct modtab   *mp;
 446: {
 447:     register PARM       *pv;
 448:     register char       *cp;
 449:     int         namemode, sort_only, as_ds;
 450:     int         i, j, keyno, keywid;
 451:     struct attribute    attkey, atttup;
 452:     struct index        ikey, itup;
 453:     TID         tid;
 454:     extern DESC     Attdes, Inddes;
 455:     extern char     *iocv();
 456: 
 457:     pv = *ppv;  /* copy list of params */
 458: 
 459:     if (mp->newrelspec != M_ORDER)
 460:         /* zero key info (ordering does not change keyed fields) */
 461:         for (i = 0; i <= d->reldum.relatts; i++)
 462:             d->relxtra[i] = 0;
 463:     for (i = 0; i <= d->reldum.relatts; ++i)
 464:         d->relgiven[i] = 0;
 465: 
 466:     /* determine whether there are any keys at all */
 467:     keywid = 0;
 468:     keyno = 0;
 469:     sort_only = FALSE;
 470:     cp = pv->pv_val.pv_str;
 471: 
 472:     if (cp == NULL || *cp == NULL)
 473:     {
 474:         /* no key information. default as needed */
 475:         if (mp->yeskeys && mp->newrelspec != M_ORDER)
 476:         {
 477:             cp = "\1";  /* default to first key */
 478:             namemode = FALSE;
 479:         }
 480:         else
 481:             pv++;   /* point one to far */
 482:     }
 483:     else
 484:     {
 485:         /* check for name mode */
 486:         if (namemode = sequal(cp, "name"))
 487:         {
 488: 
 489:             /* check attribute names, and convert them to numbers */
 490:             opencatalog("attribute", OR_READ);
 491:             setkey(&Attdes, &attkey, Mod_info.infile, ATTRELID);
 492:             setkey(&Attdes, &attkey, Usercode, ATTOWNER);
 493:         }
 494:         pv++;   /* inc to next key */
 495:         cp = (pv++)->pv_val.pv_str;
 496:     }
 497: 
 498:     /* scan for attribute names */
 499:     for (; cp != NULL; cp = (pv++)->pv_val.pv_str)
 500:     {
 501:         /* check for separator between keys & options */
 502:         if (*cp == NULL)
 503:         {
 504:             pv++;   /* point two past NULL */
 505:             break;
 506:         }
 507: 
 508:         if (NLidKeys >= d->reldum.reldim && mp->newrelspec == M_ORDER)
 509:         {
 510:             /* more than one field specified as ordering key */
 511:             closeall(0l, 0l);
 512:             return(error(TOOMANYORDKEYS, relname, 0));
 513:         }
 514: 
 515:         if (namemode)
 516:         {
 517:             /* check for "sort only" attribute */
 518:             if (*cp == '#')
 519:             {
 520:                 cp++;   /* inc to start of name */
 521:                 sort_only = TRUE;
 522:             }
 523: 
 524:             /* check for ascending/descending modifier */
 525:             if ((as_ds = modseqkey(cp, relname, mp->yes_seq)) > 0)
 526:                 return (as_ds); /* error */
 527: 
 528:             setkey(&Attdes, &attkey, cp, ATTNAME);
 529:             i = getequal(&Attdes, &attkey, &atttup, &tid);
 530:             if (i < 0)
 531:                 syserr("MODIFY: geteq(att) %d", i);
 532:             if (i > 0)
 533:             {
 534:                 closeall(0l, 0l);
 535:                 return (error(INVALIDATTR, relname, cp, 0));    /* bad att name */
 536:             }
 537:             i = atttup.attid;
 538:             if (i > d->reldum.relatts)
 539:             {
 540:                 /* attempting to key on lid field which will be
 541: 				** removed
 542: 				*/
 543:                 closeall(0l,0l);
 544:                 return(error(ATTRREMV, relname, cp, 0));
 545:             }
 546:         }
 547:         else
 548:         {
 549:             i = *cp;
 550:             as_ds = 0;
 551:         }
 552: 
 553:         keyno++;
 554:         /* add new key to descriptor */
 555:         if (mp->newrelspec == M_ORDER)
 556:             LidKey[NLidKeys++] = i;
 557:         if (!sort_only && mp->newrelspec != M_ORDER)
 558:         {
 559:             d->relxtra[i] = keyno;
 560:             keywid += (d->relfrml[i] & I1MASK);
 561:         }
 562:         if (d->relgiven[i])
 563:         {
 564:             closeall(0l, 0l);
 565:             return (error(DUPKEY, relname, cp, 0)); /* duplicate attribute */
 566:         }
 567:         d->relgiven[i] = as_ds == 0 ? keyno : -keyno;
 568:     }
 569:     pv--;   /* back up one to point to "-1" terminator */
 570: 
 571: 
 572:     if (abs(d->reldum.relspec) == M_ISAM && keywid > (MAXTUP / 2 - 4))
 573:     {
 574:         closeall(0l, 0l);
 575:         return (error(TOOWIDEISAM, relname, iocv(keywid), 0));
 576:     }
 577: 
 578:     /* if a heap, there can be no keys */
 579:     if (!mp->yeskeys && keyno != 0)
 580:     {
 581:         closeall(0l, 0l);
 582:         return (error(NOKEYSHEAP, relname, mp->type, 0));   /* no keys allowed on heap */
 583:     }
 584:     /* fill out default sort on remainder of keys */
 585:     if (mp->yeskeys)
 586:         for (i = 1; i <= d->reldum.relatts; i++)
 587:             if (d->relgiven[i] == 0)
 588:                 d->relgiven[i] = ++keyno;
 589:     *ppv = pv;
 590:     return (0);
 591: }
 592: 
 593: 
 594: /*
 595: **	MODSEQKEY - verify that sequence specified is valid
 596: **
 597: **	Parameters:
 598: **		domain - list of domains
 599: **		relname - relation name
 600: **		seq_ok - whether it is ok to specify the sequence
 601: **				ascending or descending
 602: **
 603: **	Return Codes:
 604: **		0 - ok
 605: **		> 0 - error in sequence specified
 606: **
 607: **	Called by:
 608: **		getkeys
 609: */
 610: modseqkey(domain, relname, seq_ok)
 611: char    *domain;
 612: char    *relname;
 613: int seq_ok;
 614: {
 615:     register char   *cp, c;
 616:     register int    ret;
 617: 
 618:     ret = 0;
 619: 
 620:     for (cp = domain; c = *cp++; )
 621:         if (c == ':')
 622:             break;
 623: 
 624:     if (c != '\0')
 625:     {
 626:         /* replace ":" with null */
 627:         *(cp - 1) = '\0';
 628: 
 629:         /* verify sequence is valid */
 630:         if (!seq_ok)
 631:         {
 632:             closeall(0l, 0l);
 633:             ret = error(BADSEQSPEC, relname, cp, domain, 0);
 634:         }
 635:         else if (sequal("descending", cp) || sequal("d", cp))
 636:             ret = -1;
 637:         else if (!(sequal("ascending", cp) || sequal("a", cp)))
 638:         {
 639:             closeall(0l, 0l);
 640:             ret = error(INVALIDSEQ, relname, cp, domain, 0);
 641:         }
 642:     }
 643: 
 644:     return (ret);
 645: }
 646: /*
 647: **	GETFILL -- Get fill factor and minimum pages parameters
 648: **		from argument list, convert them from ascii to integer
 649: **		and store them in global variables.  If the global
 650: **		variable for the corresponding parameter is zero,
 651: **		it means that that parameter is not allowed and an
 652: **		error is generated.
 653: */
 654: 
 655: /*ARGSUSED*/
 656: getfill(d, pv, rel, mp)
 657: DESC        *d;
 658: register PARM   *pv;
 659: char        *rel;
 660: struct modtab   *mp;
 661: {
 662:     register char       *p1;
 663:     register int        err;
 664:     char            *p2;
 665:     int         i, j;
 666:     int         fill_flag, min_flag, max_flag, lid_flag[MAXLID];
 667: 
 668:     err = 0;
 669:     fill_flag = min_flag = max_flag = FALSE;
 670:     for (i = 0; i < d->reldum.reldim; ++i)
 671:         lid_flag[i] = FALSE;
 672: 
 673:     while ((p1 = (pv++)->pv_val.pv_str) != NULL)
 674:     {
 675:         p2 = (pv++)->pv_val.pv_str;
 676:         if (sequal(p1, "fillfactor"))
 677:         {
 678:             if (F_fac == 0 || fill_flag)
 679:             {
 680:                 err = NOTALLOWED;
 681:                 break;
 682:             }
 683:             p1 = p2;
 684:             F_fac = atoi(p1);
 685:             if (F_fac > 100 || F_fac < 1)
 686:             {
 687:                 err = FILLBOUND;
 688:                 break;
 689:             }
 690:             fill_flag = TRUE;
 691:             continue;
 692:         }
 693:         if (sequal(p1, "minpages"))
 694:         {
 695:             if (Mn_pages == 0 || min_flag)
 696:             {
 697:                 err = NOTALLOWED;
 698:                 break;
 699:             }
 700:             p1 = p2;
 701:             Mn_pages = atoi(p1);
 702:             if (Mn_pages < 1)
 703:             {
 704:                 err = MINPGBOUND;
 705:                 break;
 706:             }
 707:             if (max_flag && (Mn_pages > Mx_pages))
 708:             {
 709:                 err = MINGTMAX;
 710:                 break;
 711:             }
 712:             min_flag = TRUE;
 713:             continue;
 714:         }
 715:         if (sequal(p1, "maxpages"))
 716:         {
 717:             if (Mx_pages == 0 || max_flag)
 718:             {
 719:                 err = NOTALLOWED;
 720:                 break;
 721:             }
 722:             p1 = p2;
 723:             Mx_pages = atoi(p1);
 724:             if (Mx_pages < 1)
 725:             {
 726:                 err = MAXPGBOUND;
 727:                 break;
 728:             }
 729:             if (min_flag && (Mn_pages > Mx_pages))
 730:             {
 731:                 err = MINGTMAX;
 732:                 break;
 733:             }
 734:             max_flag = TRUE;
 735:             continue;
 736:         }
 737:         for ( i  = 1; i <= d->reldum.reldim && !err; ++i)
 738:             if (sequal(p1, ztack("lid", iocv(i))))
 739:             {
 740:                 if (lid_flag[i-1] || *Lid[i-1] == NULL)
 741:                 {
 742:                     err = NOTALLOWED;
 743:                     break;
 744:                 }
 745:                 for (j = 0; j < d->reldum.reldim; ++j)
 746:                     if (i - 1 != j && sequal(p2, Lid[j]) && lid_flag[j])
 747:                     {
 748:                         err = NOTALLOWED;
 749:                         break;
 750:                     }
 751:                 p1 = p2;
 752:                 smove(p1, Lid[i - 1]);
 753:                 lid_flag[i - 1] = TRUE;
 754:                 break;
 755:             }
 756:             if (err)
 757:                 break;
 758:         if (i <= d->reldum.reldim)
 759:             continue;
 760:         err = NEEDFILL;
 761:         break;
 762:     }
 763:     if (err)
 764:     {
 765:         closeall(0l, 0l);
 766:         return (error(err, rel, p1, 0));
 767:     }
 768:     return (0);
 769: }
 770: /*
 771: **  MAKE_NEWREL -- Create a file for the modified relation
 772: **	and build one or more primary pages for the
 773: **	relation based on its storage structure and the
 774: **	number of tuples it must hold.
 775: */
 776: 
 777: make_newrel(desc)
 778: register DESC   *desc;
 779: {
 780:     register int    tups_p_page;
 781:     int     width;
 782: 
 783:     concat(MODTEMP, Fileset, Mod_info.reltemp);
 784:     close(creat(Mod_info.reltemp, FILEMODE));
 785:     if ((desc->relfp = open(Mod_info.reltemp, O_RDWR)) < 0)
 786:         syserr("MAKE_NEWREL: open %.14s %d", Mod_info.reltemp, desc->relfp);
 787:     desc->relopn = (desc->relfp + 1) * -5;
 788:     desc->reldum.relprim = 1;
 789:     if (abs(desc->reldum.relspec) == M_HASH && F_fac > 0 && Mn_pages > 0)
 790:     {
 791:         /*
 792: 		** Determine the number of primary pages. The following
 793: 		** first determines the number of tuples/page which the
 794: 		** relation should have in order to get the requested
 795: 		** fillfactor. Then that number is divided into the
 796: 		** number of tuples to get the number of primary pages.
 797: 		** To avoid round off, it must guaranteed that the
 798: 		** number of tuples per page must be at least 1.
 799: 		**
 800: 		** primary_pages = #tuples / (#tuples/page * fillfactor)
 801: 		*/
 802:         width = desc->reldum.relwid + 2 - LIDSIZE * desc->reldum.reldim;
 803:         tups_p_page = (((MAXTUP+2) / width) * F_fac) / 100;
 804:         if (tups_p_page == 0)
 805:             tups_p_page = 1;
 806:          /* we add one to simulate a ceiling function */
 807:         desc->reldum.relprim = desc->reldum.reltups / tups_p_page + 1;
 808:         if (desc->reldum.relprim < Mn_pages)
 809:             desc->reldum.relprim = Mn_pages;
 810:         if (Mx_pages > 0 && desc->reldum.relprim > Mx_pages)
 811:             desc->reldum.relprim = Mx_pages;
 812: #		ifdef xZTR1
 813:         if (tTf(36, 0))
 814:             printf("using %ld prim pages\n", desc->reldum.relprim);
 815: #		endif
 816:     }
 817:     desc->reldum.reltups = 0;
 818:     return (0);
 819: }
 820: /*
 821: **	SORTREL - Call KSORT to sort the given relation.  SORTREL
 822: **		sets up the descriptor struct specifying the sort
 823: **		keys and tells KSORT whether or not the hash key should
 824: **		be included as a sort key.
 825: */
 826: 
 827: sortrel(odesc, desc)
 828: DESC        *odesc;
 829: register DESC   *desc;
 830: {
 831:     extern char *Pathname;
 832:     register int    i;
 833:     char        buf[50];
 834:     DESC        tempdesc;
 835:     char        *temp;
 836:     int     len;
 837:     short       smalli;
 838: 
 839:     concat(ISAM_SORTED, Fileset, Mod_info.outfile);
 840:     if (close(creat(Mod_info.outfile, FILEMODE)))
 841:         syserr("SORTREL: creat %.14s", Mod_info.outfile);
 842:     bmove(odesc, &tempdesc, sizeof *odesc);
 843:     for (i = 1; i <= desc->reldum.relatts; ++i)
 844:     /* set up temporary descriptor for ksort with new keyed fields */
 845:     {
 846:         tempdesc.relxtra[i] = desc->relxtra[i];
 847:         tempdesc.relgiven[i] = desc->relgiven[i];
 848:     }
 849: 
 850:     if (abs(desc->reldum.relspec) == M_HASH && !desc->reldum.reldim)
 851:     {
 852:         /* sort on hash bucket first, (if ordering sort on ordering key, not bucket) */
 853:         tempdesc.relgiven[0] = 1;
 854:         for (i = 1; i <= desc->reldum.relatts; i++)
 855:             tempdesc.relgiven[i]++;
 856:     }
 857: 
 858: # ifdef xZTR2
 859:     if (tTf(36, 4))
 860:     {
 861:         printf("sortrel: ");
 862:         printdesc(&tempdesc);
 863:     }
 864: # endif
 865: 
 866:     /* flush buffers used by modify so that ksort can't look at them */
 867:     flush_rel(desc, TRUE);
 868:     resetacc(NULL);
 869: 
 870:     /* copy Fileset so it can't get trashed */
 871: 
 872:     len = length(Fileset) + 1;
 873:     temp = (char *) need(Qbuf, len);
 874:     bmove(Fileset, temp, len);
 875: 
 876:     initp();
 877:     setp(PV_STR, temp);
 878:     setp(PV_STR, Mod_info.infile);
 879:     setp(PV_STR, Mod_info.outfile);
 880: 
 881:     /* Descriptor for new relation */
 882:     setp(PV_STR, tempdesc.reldum.relid);
 883:     setp(PV_STR, tempdesc.reldum.relowner);
 884:     setp(PV_INT, tempdesc.reldum.relspec);
 885:     setp(PV_INT, tempdesc.reldum.relindxd);
 886:     setp(PV_INT, tempdesc.reldum.relstat2);
 887:     setp(PV_INT, tempdesc.reldum.relstat);
 888:     setp(PV_INT, (short) tempdesc.reldum.relsave);
 889:     setp(PV_INT, (short) tempdesc.reldum.reltups);
 890:     setp(PV_INT, tempdesc.reldum.relatts);
 891:     setp(PV_INT, tempdesc.reldum.relwid);
 892:     setp(PV_INT, (short) tempdesc.reldum.relprim);
 893:     setp(PV_INT, (short) tempdesc.reldum.relfree);
 894:     setp(PV_INT, (short) tempdesc.reldum.relstamp);
 895:     setp(PV_INT, tempdesc.reldum.reldim);
 896: 
 897:     setp(PV_STR, tempdesc.relvname);
 898:     setp(PV_INT, tempdesc.relfp);
 899:     setp(PV_INT, tempdesc.relopn);
 900:     setp(PV_INT, (short) tempdesc.reladds);
 901:     setp(PV_INT, tempdesc.reltid.ltid);
 902:     for (i = 0; i <= tempdesc.reldum.relatts; ++i)
 903:     {
 904:         smalli = (short) tempdesc.reloff[i];
 905:         setp(PV_INT, smalli);
 906:         smalli = (short) tempdesc.relfrmt[i];
 907:         setp(PV_INT, smalli);
 908:         smalli = (short) tempdesc.relfrml[i];
 909:         setp(PV_INT, smalli);
 910:         smalli = (short) tempdesc.relxtra[i];
 911:         setp(PV_INT, smalli);
 912:         smalli = (short) tempdesc.relgiven[i];
 913:         setp(PV_INT, smalli);
 914:     }
 915: 
 916:     if (tempdesc.reldum.reldim > 0)
 917:     {
 918:         setp(PV_STR, odesc->relbtree->reldum.relid);
 919:         setp(PV_STR, odesc->relbtree->reldum.relowner);
 920:         setp(PV_INT, odesc->relbtree->reldum.relspec);
 921:         setp(PV_INT, odesc->relbtree->reldum.relindxd);
 922:         setp(PV_INT, odesc->relbtree->reldum.relstat2);
 923:         setp(PV_INT, odesc->relbtree->reldum.relstat);
 924:         setp(PV_INT, (short) odesc->relbtree->reldum.relsave);
 925:         setp(PV_INT, (short) odesc->relbtree->reldum.reltups);
 926:         setp(PV_INT, odesc->relbtree->reldum.relatts);
 927:         setp(PV_INT, odesc->relbtree->reldum.relwid);
 928:         setp(PV_INT, (short) odesc->relbtree->reldum.relprim);
 929:         setp(PV_INT, (short) odesc->relbtree->reldum.relfree);
 930:         setp(PV_INT, (short) odesc->relbtree->reldum.relstamp);
 931:         setp(PV_INT, odesc->relbtree->reldum.reldim);
 932: 
 933:         setp(PV_STR, odesc->relbtree->relvname);
 934:         setp(PV_INT, odesc->relbtree->relfp);
 935:         setp(PV_INT, odesc->relbtree->relopn);
 936:         setp(PV_INT, (short) odesc->relbtree->reladds);
 937:         setp(PV_INT, odesc->relbtree->reltid.ltid);
 938: 
 939:         for (i = 0; i <= odesc->relbtree->reldum.relatts; ++i)
 940:         {
 941:             smalli = (short) odesc->relbtree->reloff[i];
 942:             setp(PV_INT, smalli);
 943:             smalli = (short) odesc->relbtree->relfrmt[i];
 944:             setp(PV_INT, smalli);
 945:             smalli = (short) odesc->relbtree->relfrml[i];
 946:             setp(PV_INT, smalli);
 947:             smalli = (short) odesc->relbtree->relxtra[i];
 948:             setp(PV_INT, smalli);
 949:             smalli = (short) odesc->relbtree->relgiven[i];
 950:             setp(PV_INT, smalli);
 951:         }
 952:     }
 953: 
 954:     call(mdKSORT, NULL);
 955: 
 956:     /* flush buffers used by ksort so that modify can't look at them */
 957:     flush_rel(desc, TRUE);
 958:     resetacc(NULL);
 959: 
 960: # ifdef xZTR1
 961:     if (tTf(36,9))
 962:         printf("SORTREL: done calling ksort\n");
 963: #endif
 964:     return (0);
 965: }
 966: /*
 967: **	SORT_ISAM -- Sorts an isam relation back to its original order
 968: **	so that it will be inserted into the relation in the proper order.
 969: **	It is presently not in order because it has been sorted according
 970: **	to a specified field for ordering.
 971: */
 972: sort_isam(sdesc, desc)
 973: DESC *sdesc;
 974: DESC *desc;
 975: {
 976:     long        lid[MAXLID];
 977:     register int    i, j, k;
 978:     char        tup_buf[MAXTUP], last_tup[MAXTUP], *dp, *sp;
 979:     FILE        *sfp, *fp;
 980:     TID     tid, tidpos;
 981:     DESC        tempdesc;
 982:     int     w;
 983: 
 984:     if (desc->reldum.reldim > 0)
 985:         Btree_fd = desc->btree_fd;
 986:     concat(STEMP, Fileset, Mod_info.temp_sort);
 987:     if ((sfp = fopen(Mod_info.temp_sort, "w")) == NULL)
 988:         syserr("sort_isam: can't open %s", Mod_info.temp_sort);
 989:     if ((fp = fopen(Mod_info.outfile, "r")) == NULL)
 990:         syserr("sort_isam: can't open %s", Mod_info.outfile);
 991:     for (i = 0; i < desc->reldum.reldim; lid[i++] = 0);
 992:     /* create input file for sort with proper lid attached to each tuple */
 993:     w = sdesc->reldum.relwid - LIDSIZE * sdesc->reldum.reldim;
 994:     for ( ; ; )
 995:     {
 996:         i = fread(tup_buf, 1, sdesc->reldum.relwid, fp);
 997:         if (i == 0)
 998:             break;
 999:         if (i != sdesc->reldum.relwid)
1000:             syserr("sort_isam: read error in %s", Mod_info.outfile);
1001:         for (j = 0; j < desc->reldum.reldim; ++j)
1002:             if (j < NLidKeys && j < desc->reldum.reldim - 1)
1003:             {
1004:                 dp = tup_buf + (sdesc->reloff[LidKey[j]] & I1MASK);
1005:                 sp = last_tup + (sdesc->reloff[LidKey[j]] & I1MASK);
1006:                 if (!bequal(dp, sp, sdesc->relfrml[LidKey[j]]) || !lid[j])
1007:                 {
1008:                     ++lid[j];
1009:                     for (k = j + 1; k < desc->reldum.reldim; ++k)
1010:                         lid[k] = 0;
1011:                     break;
1012:                 }
1013:             }
1014:             else
1015:             {
1016:                 if (!lid[0])
1017:                 {
1018:                     lid[0] = 1;
1019:                     if (!(desc->reldum.reldim - 1))
1020:                         break;
1021:                 }
1022:                 ++lid[desc->reldum.reldim - 1];
1023:                 break;
1024:             }
1025:         bmove(tup_buf, last_tup, sdesc->reldum.relwid);
1026:         /* reserve a slot in btree for tuple */
1027:         insert_mbtree(desc, Mod_info.btree, lid, &tid, &tidpos);
1028:         bmove(lid, tup_buf + w, LIDSIZE * desc->reldum.reldim);
1029:         if (fwrite(tup_buf, 1, sdesc->reldum.relwid + LIDSIZE * desc->reldum.reldim, sfp) != sdesc->reldum.relwid + LIDSIZE * desc->reldum.reldim)
1030:             syserr("sort_isam: write error in %s", Mod_info.temp_sort);
1031:     }
1032:     fclose(fp);
1033:     fclose(sfp);
1034:     /* set up new descriptor accounting for lid field */
1035:     bmove(sdesc, &tempdesc, sizeof *sdesc);
1036:     tempdesc.reldum.relspec = M_ORDER;
1037:     for (i = 0; i < desc->reldum.reldim; ++i)
1038:     {
1039:         tempdesc.reldum.relwid += LIDSIZE;
1040:         ++tempdesc.reldum.relatts;
1041:         tempdesc.reloff[tempdesc.reldum.relatts] = tempdesc.reldum.relwid - LIDSIZE;
1042:         tempdesc.relfrmt[tempdesc.reldum.relatts] = INT;
1043:         tempdesc.relfrml[tempdesc.reldum.relatts] = LIDSIZE;
1044:     }
1045:     j = 0;
1046:     /* use old keying attributes for specifying sort order */
1047:     clearkeys(&tempdesc);
1048:     for (i = 1; i <= sdesc->reldum.relatts; ++i)
1049:         if (sdesc->relxtra[i])
1050:         {
1051:             tempdesc.relgiven[i] = sdesc->relxtra[i];
1052:             ++j;
1053:         }
1054:     for (i = 1; i <= tempdesc.reldum.relatts; ++i)
1055:         if (!tempdesc.relgiven[i])
1056:             tempdesc.relgiven[i] = ++j;
1057:     sortfile(Mod_info.temp_sort, &tempdesc, FALSE);
1058:     if (unlink(Mod_info.outfile) < 0)
1059:         syserr("can't unlink %s", Mod_info.outfile);
1060:     if (link(ztack(REPL_OUT, Fileset), Mod_info.outfile) == -1)
1061:         syserr("can't link %s to %s", ztack(REPL_OUT, Fileset), Mod_info.outfile);
1062:     if (unlink(Mod_info.temp_sort) < 0)
1063:         syserr("sort_isam: can't unlink %s", Mod_info.temp_sort);
1064:     if (unlink(ztack(REPL_OUT, Fileset)) < 0)
1065:         syserr("sort_isam: can't unlink replout file");
1066: }
1067: /*
1068: **	FILL_REL -- Fill the new relation with tuples from either
1069: **		the old relation or the output file of KSORT.
1070: */
1071: 
1072: fill_rel(sdesc, desc, sortit)
1073: register DESC   *sdesc, *desc;
1074: char            sortit;
1075: {
1076:     register int    i;
1077:     char        tup_buf[MAXTUP], last_tup[MAXTUP], tup[2 * LIDSIZE];
1078:     char        junk[4], newreltype, anytups, chkdups;
1079:     int     need, j, k;
1080:     long        lnum, lid[MAXLID], l, page, t;
1081:     TID     tid, stid, stidlim, ntid, tidpos, btid;
1082:     FILE        *fp, *spfp;
1083:     char        *dp, *sp;
1084:     int     w, temp;
1085:     struct locator  tidloc;
1086: 
1087:     newreltype = abs(desc->reldum.relspec);
1088:     if (sortit)
1089:     {
1090:         if ((fp = fopen(Mod_info.outfile, "r")) == NULL)
1091:             syserr("FILL_REL: fopen %.14s", Mod_info.outfile);
1092:     }
1093:     else
1094:     {
1095:         cleanrel(sdesc);    /* make sure each page is read fresh */
1096:         find(sdesc, NOKEY, &stid, &stidlim);
1097:     }
1098:     if (newreltype == M_ISAM && (NLidKeys > 0 || !desc->reldum.reldim))
1099:     {
1100:         lnum = 0;
1101:         stuff_page(&tid, &lnum);
1102:         tid.line_id = 0;
1103:         get_page(desc, &tid);
1104:         concat(ISAM_SPOOL, Fileset, Mod_info.spfile);
1105:         /* assume that spool file is not needed */
1106:         spfp = NULL;
1107:         Mod_info.spflag = FALSE;
1108:         if (F_fac == 0)
1109:             F_fac = 100;
1110:         /* setup relgiven field for kcompare later on */
1111:         for (i = 1; i <= desc->reldum.relatts; i++)
1112:             desc->relgiven[i] = desc->relxtra[i];
1113:         if (desc->reldum.reldim)
1114:             Btree_fd = desc->btree_fd;
1115:     }
1116:     desc->reladds = 0;
1117:     for (i = 0; i < desc->reldum.reldim; lid[i++] = 0)
1118:         continue;
1119:     anytups = FALSE;
1120:     chkdups = !sortit && (newreltype != M_ORDER);
1121: # ifdef xZTR2
1122:     if (tTf(36, 3))
1123:     {
1124:         printf("  FILLREL: ");
1125:         printdesc(sdesc);
1126:         printdesc(desc);
1127:     }
1128: # endif
1129:     for (;;)
1130:     {
1131:         w = (newreltype == M_ISAM) ? sdesc->reldum.relwid + desc->reldum.reldim * LIDSIZE : sdesc->reldum.relwid;
1132:         if (sortit)
1133:         {
1134:             i = fread(tup_buf, 1, w, fp);
1135:             if (i == 0)
1136:                 break;
1137:             if (i != w)
1138:                 syserr("FILL_REL: fread A %d", i);
1139:             if (newreltype == M_HASH && !desc->reldum.reldim)
1140:                 if (fread(junk, 1, 4, fp) != 4)
1141:                     syserr("FILL_REL: fread B");
1142:         }
1143:         else
1144:         {
1145: #			ifdef xZTR2
1146:             if (tTf(36, 1))
1147:             {
1148:                 printf("FILL_REL: stid ");
1149:                 dumptid(&stid);
1150:                 printf("FILL_REL: stidlim ");
1151:                 dumptid(&stidlim);
1152:             }
1153: #			endif
1154:             i = get(sdesc, &stid, &stidlim, tup_buf, TRUE);
1155: #			ifdef xZTR2
1156:             if (tTf(36, 1))
1157:             {
1158:                 printf("FILLREL: get %d ", i);
1159:                 printup(sdesc, tup_buf);
1160:             }
1161: #			endif
1162:             if (i < 0)
1163:                 syserr("FILL_REL: get %d", i);
1164:             if (i == 1)
1165:                 break;
1166:         }
1167:         if (newreltype != M_ISAM || (newreltype == M_ISAM && NLidKeys == 0 && desc->reldum.reldim > 0))
1168:         {
1169:             for (j = 0; j < desc->reldum.reldim; ++j)
1170:                 if (j < NLidKeys && j < desc->reldum.reldim - 1)
1171:                 {
1172:                     dp = tup_buf + (sdesc->reloff[LidKey[j]] & I1MASK);
1173:                     sp = last_tup + (sdesc->reloff[LidKey[j]] & I1MASK);
1174:                     if (!bequal(dp, sp, sdesc->relfrml[LidKey[j]]) || !lid[j])
1175:                     {
1176:                         ++lid[j];
1177:                         for (k = j + 1; k < desc->reldum.reldim; ++k)
1178:                             lid[k] = 0;
1179:                         break;
1180:                     }
1181:                 }
1182:                 else
1183:                 {
1184:                     if (!lid[0])
1185:                     {
1186:                         lid[0] = 1;
1187:                         if (!(desc->reldum.reldim -1))
1188:                             break;
1189:                     }
1190:                     ++lid[desc->reldum.reldim - 1];
1191:                     break;
1192:                 }
1193:             Btree_fd = desc->btree_fd;
1194:             if (!desc->reldum.reldim || NLidKeys > 0)
1195:             {
1196:                 /* assume unordered so btree inserts done
1197: 				** separately */
1198:                 temp = 0;
1199:                 if (desc->reldum.reldim > 0)
1200:                 {
1201:                     temp = desc->reldum.reldim;
1202:                     desc->reldum.reldim = 0;
1203:                     desc->reldum.relwid -= temp * LIDSIZE;
1204:                 }
1205:                 if ((i = insert(desc, &tid, tup_buf, chkdups)) < 0)
1206:                     syserr("FILL_REL: insert %d", i);
1207:                 if (NLidKeys > 0)
1208:                 {
1209:                     bmove(&tid, &stid, LIDSIZE);
1210:                     desc->reldum.reldim = temp;
1211:                     desc->reldum.relwid += temp * LIDSIZE;
1212:                     insert_mbtree(desc, Mod_info.btree, lid, &tid, &tidpos);
1213:                 }
1214:             }
1215:             if (desc->reldum.reldim && !NLidKeys)
1216:             {
1217:                 /* new relation not changed, only lids added */
1218:                 page = RT;
1219:                 for (j = 0; j < desc->reldum.reldim - 1; ++j)
1220:                 {
1221:                     if (!lid[j])
1222:                         lid[j] = 1;
1223:                     if ((t = get_tid(page, lid[j], &tidloc)) < 0)
1224:                     {
1225:                         insert_btree(Mod_info.btree, page, lid[j], &ntid, &tidpos, j + 2);
1226:                         bmove(&ntid, &page, LIDSIZE);
1227:                     }
1228:                     else
1229:                         bmove(&t, &page, LIDSIZE);
1230:                 }
1231:                 insert_btree(Mod_info.btree, page, lid[abs(desc->reldum.reldim) - 1], &stid, &tidpos, FALSE);
1232:             }
1233:             bmove(tup_buf, last_tup, sdesc->reldum.relwid);
1234:             if (desc->reldum.reldim > 0)
1235:             {
1236:                 dp = tup_buf + desc->reldum.relwid - desc->reldum.reldim * LIDSIZE;
1237:                 bmove(lid, dp, LIDSIZE * desc->reldum.reldim);
1238:             }
1239: #			ifdef xZTR2
1240:             if (tTf(36, 2))
1241:             {
1242:                 printf("FILL_REL: insert ");
1243:                 printup(desc, tup_buf);
1244:                 printf("FILL_REL: insert ret %d at", i);
1245:                 dumptid(&tid);
1246:             }
1247: #			endif
1248:             continue;
1249:         }
1250:         if (anytups)
1251:             i = kcompare(desc, tup_buf, last_tup);
1252:         else
1253:         {
1254:             anytups = TRUE;
1255:             i = 1;
1256:         }
1257:         bmove(tup_buf, last_tup, desc->reldum.relwid);
1258:         need = canonical(desc, tup_buf);
1259:         if (i == 0 && need > space_left(Acc_head))
1260:         {
1261:             /* spool out this tuple. will go on overflow page later */
1262:             if (spfp == NULL)
1263:             {
1264:                 if ((spfp = fopen(Mod_info.spfile, "w")) == NULL)
1265:                     syserr("FILL_REL: fopen %.14s", Mod_info.spfile);
1266:                 Mod_info.spflag = TRUE;
1267:             }
1268:             if (fwrite(tup_buf, 1, desc->reldum.relwid, spfp) != desc->reldum.relwid)
1269:                 syserr("FILL_REL: putb spool");
1270:             continue;
1271:         }
1272:         j = (100 - F_fac) * MAXTUP / 100;
1273:         if (j < need)
1274:             j = need;
1275:         if (i != 0 && j > space_left(Acc_head))
1276:         {
1277:             if (i = add_prim(desc, &tid))
1278:                 syserr("FILL_REL: force ovflo %d", i);
1279:         }
1280:         tid.line_id = newlino(need);
1281:         put_tuple(&tid, Acctuple, need);
1282:         if (NLidKeys > 0)
1283:         {
1284:             bmove(tup_buf + desc->reldum.relwid - LIDSIZE * desc->reldum.reldim, lid, LIDSIZE * desc->reldum.reldim);
1285:             page = RT;
1286:             for (j = 0; j < desc->reldum.reldim; ++j)
1287:             {
1288:                 if ((t = get_tid(page, lid[j], &tidloc)) < 0)
1289:                     syserr("get_tid error in modify isam ordered");
1290:                 page = t;
1291:             }
1292:             stuff_page(&btid, &tidloc.pageno);
1293:             btid.line_id = tidloc.page.node.leafnode.tid_loc[tidloc.offset];
1294:             /* place proper tid in tree */
1295:             replace_btree(tid, &btid);
1296:         }
1297:         desc->reladds++;
1298:     }
1299:     if (sortit)
1300:     {
1301:         fclose(fp);
1302:         unlink(Mod_info.outfile);
1303:     }
1304:     if (newreltype == M_ISAM && desc->reldum.reldim <= 0)
1305:     {
1306:         if (i = pageflush(Acc_head))
1307:             syserr("fill_rel:pg clean %d", i);
1308:         if (spfp != NULL)
1309:             fclose(spfp);
1310:     }
1311:     if (!desc->reldum.reldim || NLidKeys > 0)
1312:         desc->reldum.reltups = desc->reladds;
1313:     desc->reladds = 0;
1314:     return (0);
1315: }
1316: 
1317: 
1318: /*
1319: **	BLDINDEX -
1320: **
1321: **	Parameters:
1322: **		d - descriptor for relation
1323: **
1324: **	Return Codes:
1325: **		0 - ok
1326: **		<0 - error
1327: **
1328: **	Trace Flags:
1329: **		Z38.7, Z38.8
1330: **
1331: **	Called by:
1332: **		modify
1333: **
1334: */
1335: bldindex(d)
1336: register DESC   *d;
1337: {
1338:     register TID    *tid;
1339:     register int    tmp;
1340:     TID     tidx;
1341:     struct accbuf   dirbuf;
1342:     int     keywid, level, savespec, keyx[MAXDOM];
1343:     int     offset, len;
1344:     char        tuple[MAXTUP], temptup[MAXTUP], *key;
1345:     long        pageid, start, stop, newstart, newstop;
1346: 
1347:     tid = &tidx;
1348:     keywid = 0;
1349:     for (tmp = 0; tmp < MAXDOM; tmp++)
1350:         keyx[tmp] = 0;
1351:     for (tmp = 1; tmp <= d->reldum.relatts; tmp++)
1352:         if (d->relxtra[tmp] > 0)
1353:         {
1354:             keyx[d->relxtra[tmp] - 1] = tmp;
1355:             keywid += d->relfrml[tmp] & I1MASK;
1356:         }
1357: 
1358:     /* Determine the last page of the relation. This will
1359: 	** only work if all pages have been written out. Fill_rel
1360: 	** must guarantee that all pages have been written
1361: 	*/
1362:     level = 0;
1363:     last_page(d, tid, 0);
1364:     pluck_page(tid, &stop);
1365:     start = 0;
1366:     dirbuf.filedesc = d->relfp;
1367:     dirbuf.rel_tupid = d->reltid.ltid;
1368:     savespec = d->reldum.relspec;
1369:     for (;;)
1370:     {
1371: #		ifdef xZTR2
1372:         if (tTf(38, 7))
1373:             printf("isam: level %d\n", level);
1374: #		endif
1375:         dirbuf.ovflopg = start;
1376:         dirbuf.mainpg = level;
1377:         dirbuf.thispage = stop + 1;
1378:         dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf);
1379:         offset = dirbuf.linetab[0];
1380:         dirbuf.bufstatus = BUF_DIRTY | BUF_DIRECT;
1381: 
1382:         dirbuf.nxtlino = 0;
1383:         newstart = stop + 1;
1384:         newstop = newstart;
1385:         for (pageid = start; pageid <= stop; pageid++)
1386:         {
1387: #			ifdef xZTR2
1388:             if (tTf(38, 8))
1389:                 printf("isam:get key from %ld\n", pageid);
1390: #			endif
1391:             stuff_page(tid, &pageid);
1392:             tid->line_id = 0;
1393:             if (tmp = get(d, tid, tid, tuple, FALSE))
1394:             {
1395:                 /*
1396: 				** If the relation is empty, then page 0 will
1397: 				** return AMINVL_ERR on a get(). Form a blank tuple
1398: 				** and use it to create a one tuple directory
1399: 				*/
1400:                 if (pageid == 0 && tmp == AMINVL_ERR)
1401:                 {
1402:                     clr_tuple(d, tuple);
1403:                 }
1404:                 else
1405:                 {
1406:                     return (-2);
1407:                 }
1408:             }
1409: 
1410:             /*
1411: 			** If this is the first level then form the tuple
1412: 			** from the mainpage of the relation. Otherwise
1413: 			** the tuple is the first tuple of a directory page
1414: 			** and it is already correctly formed.
1415: 			*/
1416:             if (level == 0)
1417:             {
1418:                 key = temptup;
1419:                 for (tmp = 0; keyx[tmp] != 0; tmp++)
1420:                 {
1421:                     len = d->relfrml[keyx[tmp]] & I1MASK;
1422:                     bmove(&tuple[d->reloff[keyx[tmp]]], key, len);
1423:                     key += len;
1424:                 }
1425:                 key = temptup;
1426:             }
1427:             else
1428:                 key = tuple;
1429: 
1430:             if (keywid > space_left(&dirbuf))
1431:             {
1432:                 if (pageflush(&dirbuf))
1433:                     return (-3);
1434:                 dirbuf.thispage++;
1435:                 newstop = dirbuf.thispage;
1436:                 dirbuf.ovflopg = pageid;
1437:                 dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf);
1438:                 offset = dirbuf.linetab[0];
1439:                 dirbuf.bufstatus = BUF_DIRTY;
1440:                 dirbuf.nxtlino = 0;
1441:             }
1442:             /* copy key to directory page */
1443:             bmove(key, (char *) &dirbuf + offset, keywid);
1444: 
1445:             /* update next line number */
1446:             offset += keywid;
1447:             dirbuf.nxtlino++;
1448:             dirbuf.linetab[-dirbuf.nxtlino] = offset;
1449:         }
1450:         if (pageflush(&dirbuf))
1451:             return (-4);
1452:         if (newstart == newstop)
1453:             break;
1454:         d->reldum.relspec = abs(d->reldum.relspec);
1455:         level++;
1456:         start = newstart;
1457:         stop = newstop;
1458:     }
1459:     d->reldum.relspec = savespec;
1460:     d->reldum.relprim = newstart;
1461:     return (0);
1462: }
1463: /*
1464: **	UNSPOOL -- Take tuples saved in spool file and insert them
1465: **		in new relation.  This is only for ISAM relations.
1466: */
1467: 
1468: unspool(sdesc, desc)
1469: register DESC   *sdesc, *desc;
1470: {
1471:     register int    i, j;
1472:     TID     tid, btid;
1473:     char        tup_buf[MAXTUP], tup[2 * LIDSIZE];
1474:     FILE        *spfp;
1475:     long        lid[MAXLID], page, t;
1476:     int     w;
1477:     struct locator  tidpos;
1478: 
1479:     w = sdesc->reldum.relwid + desc->reldum.reldim * LIDSIZE;
1480:     if (Mod_info.spflag)
1481:     {
1482:         if ((spfp = fopen(Mod_info.spfile, "r")) == NULL)
1483:             syserr("UNSPOOL: fopen spool");
1484:         while ((i = fread(tup_buf, 1, w, spfp)) == w)
1485:         {
1486:             if ((i = insert(desc, &tid, tup_buf, FALSE)) < 0)
1487:                 syserr("UNSPOOL: insert %.14s %d", desc->reldum.relid, i);
1488:             if (NLidKeys > 0)
1489:             {
1490:                 bmove(tup_buf + desc->reldum.relwid - LIDSIZE * desc->reldum.reldim, lid, LIDSIZE * desc->reldum.reldim);
1491:                 page = RT;
1492:                 for (j = 0; j < desc->reldum.reldim; ++j)
1493:                 {
1494:                     if ((t = get_tid(page, lid[j], &tidpos)) < 0)
1495:                         syserr("get_tid error in unspool");
1496:                     page = t;
1497:                 }
1498:                 stuff_page(&btid, &tidpos.pageno);
1499:                 btid.line_id = tidpos.page.node.leafnode.tid_loc[tidpos.offset];
1500:                 replace_btree(tid, &btid);
1501:             }
1502:         }
1503:         if (i != 0)
1504:             syserr("UNSPOOL: read %d", i);
1505:         fclose(spfp);
1506:         unlink(Mod_info.spfile);
1507:     }
1508:     desc->reldum.reltups += desc->reladds;
1509:     desc->reladds = 0;
1510:     return (0);
1511: }
1512: /*
1513: **	FILL_BATCH -- Create and fill a batch file containing the
1514: **		updates for the system catalog so that MODIFY will
1515: **		be recoverable if the system crashes.
1516: */
1517: 
1518: fill_batch(odesc, desc)
1519: DESC        *odesc;
1520: register DESC   *desc;
1521: {
1522:     register DESC       *dessys;
1523:     register int        i, k;
1524:     struct relation     reltup, rkey;
1525:     TID         tid, lotid, hitid;
1526:     struct attribute    atttup, akey;
1527:     int         numatts, j;
1528:     char            prebatch[MAXNAME + 4], modbatch[MAXNAME + 4];
1529: 
1530:     if (bequal(desc->reldum.relid, "relation    ", 12))
1531:     {
1532:         clearkeys(desc);
1533:         setkey(desc, &rkey, desc->reldum.relid, RELID);
1534:         setkey(desc, &rkey, desc->reldum.relowner, RELOWNER);
1535:         if (i = getequal(desc, &rkey, &reltup, &tid))
1536:             syserr("FILL_BATCH: geteq rel rel %d", i);
1537:         bmove(&tid, &desc->reltid, sizeof desc->reltid);
1538:     }
1539:     else
1540:         bmove(&odesc->reltid, &desc->reltid, sizeof desc->reltid);
1541:     resetacc(Acc_head);
1542:     concat(MOD_PREBATCH, Fileset, prebatch);
1543:     close(creat(prebatch, FILEMODE));
1544:     if ((Batch_fp = open(prebatch, O_RDWR)) < 0)
1545:         syserr("FILL_BATCH: open %.14s %d", prebatch, Batch_fp);
1546:     smove(Fileset, Batchbuf.file_id);
1547:     Batch_cnt = 0;
1548:     wrbatch(desc, sizeof *desc);
1549:     if (bequal(desc->reldum.relid, "attribute   ", 12))
1550:         dessys = desc;
1551:     else
1552:         dessys = &Admin.adattd;
1553:     clearkeys(dessys);
1554:     setkey(dessys, &akey, desc->reldum.relid, ATTRELID);
1555:     setkey(dessys, &akey, desc->reldum.relowner, ATTOWNER);
1556:     if (i = find(dessys, EXACTKEY, &lotid, &hitid, &akey))
1557:         syserr("FILL_BATCH: find %d", i);
1558: 
1559:     /* if ordered relation, one of attributes is LID field */
1560:     numatts = j = desc->reldum.relatts - desc->reldum.reldim;
1561: 
1562:     while(!(i = get(dessys, &lotid, &hitid, &atttup, TRUE)) && j > 0)
1563:         if (!kcompare(dessys, &akey, &atttup))
1564:             if (atttup.attid <= numatts)
1565:             {
1566:                 j--;
1567:                 atttup.attxtra = desc->relxtra[atttup.attid];
1568:                 wrbatch(&lotid, sizeof lotid);
1569:                 wrbatch(&atttup, sizeof atttup);
1570:             }
1571:     for (k = 1; k <= desc->reldum.reldim; ++k)
1572:     /* create new tuple corresponding to LID field; LID field is the
1573: 	** last field of relation, a 4-byte integer
1574: 	*/
1575:     {
1576:         smove(desc->reldum.relid, atttup.attrelid);
1577:         bmove(desc->reldum.relowner, atttup.attowner, 2);
1578:         atttup.attid = numatts + k;
1579:         smove(Lid[k - 1], atttup.attname);
1580:         pad(atttup.attname, MAXNAME);
1581:         atttup.attoff = desc->reldum.relwid - (desc->reldum.reldim - k + 1) * LIDSIZE;
1582:         atttup.attfrmt = INT;
1583:         atttup.attfrml = LIDSIZE;
1584:         atttup.attxtra = 0;
1585:         wrbatch(&atttup, sizeof atttup);
1586:     }
1587:     if (i < 0 || j > 0)
1588:         syserr("FILL_BATCH: get att %d count %d", i, j);
1589:     /* get rid of attribute pages */
1590:     cleanrel(dessys);
1591:     flushbatch();
1592:     close(Batch_fp);
1593:     concat(MODBATCH, Fileset, modbatch);
1594:     if (link(prebatch, modbatch) == -1)
1595:         syserr("FILL_BATCH: can't link %.14s %.14s",
1596:             prebatch, modbatch);
1597:     unlink(prebatch);
1598:     return (0);
1599: 
1600: }
1601: 
1602: /*
1603: **	MAKE_BSEC -- Creates the seecondary btree relation by first creating
1604: **		a heaped relation.  The main relation tids are found by
1605: **		scanning the leaves of the btree.  The relation is then
1606: **		modified to an isam relation.
1607: */
1608: 
1609: make_bsec(relname, dim)
1610: char *relname;
1611: int dim;
1612: {
1613:     PARM        pv[8];
1614:     register int    i;
1615:     DESC        bdesc;
1616:     TID     tid, btid;
1617:     long        mtid, page, t, next;
1618:     char        tuple[2 * LIDSIZE], btree[MAXNAME], btreefile[MAXNAME + 4];
1619:     struct locator  tidpos;
1620:     extern char *iocv();
1621:     extern DESC Reldes;
1622: 
1623:     pv[0].pv_val.pv_str = "0000002";
1624:     capital(trim_relname(relname), btree);
1625:     pv[1].pv_val.pv_str = btree;
1626:     pv[2].pv_val.pv_str = "mtid";
1627:     pv[3].pv_val.pv_str = "i4";
1628:     pv[4].pv_val.pv_str = "btid";
1629:     pv[5].pv_val.pv_str = "i4";
1630:     pv[6].pv_type = PV_EOF;
1631:     if (create(6, pv))
1632:         syserr("can't create btreesec %s", pv[1].pv_val.pv_str);
1633: 
1634:     if (noclose(&Reldes))
1635:         syserr("noclose in make_bsec");
1636: 
1637:     if (i = openr(&bdesc, OR_WRITE, btree))
1638:         syserr("opening bsec relation %d", i);
1639:     btreename(relname, btreefile);
1640:     if ((Btree_fd = open(btreefile, O_RDWR)) < 0)
1641:         syserr("make_bsec: can't open %s", btreefile);
1642:     page = RT;
1643:     for (i = 0; i < dim - 1; ++i)
1644:     {
1645:         t = get_tid(page, 1, &tidpos);
1646:         if (t < 0)
1647:             break;  /* lid value doesn't exist */
1648:         bmove(&t, &page, LIDSIZE);
1649:     }
1650:     if (t >= 0) /* only do inserts if there are lids! */
1651:     {
1652:         do
1653:         {
1654:             get_node(page, &tidpos.page);
1655:             next = tidpos.page.nexttree;
1656:             get_tid(page, 1, &tidpos);
1657:             page = tidpos.pageno;
1658:             for (;;)
1659:             /* scan through leaves of btree */
1660:             {
1661:                 stuff_page(&btid, &page);
1662:                 for (i = 0; i < tidpos.page.nelmts; ++i)
1663:                 {
1664:                     btid.line_id = tidpos.page.node.leafnode.tid_loc[i];
1665:                     mtid = tidpos.page.node.leafnode.tid_pos[btid.line_id];
1666:                     /* form tuple */
1667:                     bmove(&mtid, tuple, LIDSIZE);
1668:                     bmove(&btid, tuple + LIDSIZE, LIDSIZE);
1669:                     if (insert(&bdesc, &tid, tuple, TRUE) < 0)
1670:                         syserr("insert error in btreesec");
1671:                 }
1672:                 page = tidpos.page.node.leafnode.nextleaf;
1673:                 if (page == NULL)
1674:                     break;
1675:                 else
1676:                     get_node(page, &tidpos.page);
1677:             }
1678:         } while (page = next);
1679:     }
1680:     close(Btree_fd);
1681:     closer(&bdesc);
1682: 
1683:     /* modify to isam on mtid */
1684:     pv[0].pv_val.pv_str = btree;
1685:     pv[1].pv_val.pv_str = "isam";
1686:     pv[2].pv_val.pv_str = "name";
1687:     pv[3].pv_val.pv_str = "mtid";
1688:     pv[4].pv_val.pv_str = "\0";
1689:     pv[5].pv_val.pv_str = "fillfactor";
1690:     /* use fillfactor provided for main relation */
1691:     if (F_fac == 0)
1692:         pv[6].pv_val.pv_str = iocv(80);
1693:     else
1694:         pv[6].pv_val.pv_str = iocv(F_fac);
1695:     pv[7].pv_type = PV_EOF;
1696:     if (modify(7, pv))
1697:         syserr("can't modify btreesec to isam");
1698: }

Defined functions

bldindex defined in line 1335; used 1 times
fill_batch defined in line 1518; used 1 times
fill_rel defined in line 1072; used 1 times
getfill defined in line 656; used 1 times
getkeys defined in line 441; used 1 times
make_bsec defined in line 1609; used 1 times
make_newrel defined in line 777; used 1 times
modify defined in line 115; used 3 times
modseqkey defined in line 610; used 1 times
sort_isam defined in line 972; used 1 times
sortrel defined in line 827; used 1 times
unspool defined in line 1468; used 1 times

Defined variables

F_fac defined in line 60; used 13 times
Lid defined in line 61; used 8 times
LidKey defined in line 63; used 8 times
Mn_pages defined in line 60; used 10 times
Mod_info defined in line 108; used 42 times
ModifyFn defined in line 23; never used
Modtab defined in line 78; used 2 times
Mx_pages defined in line 60; used 10 times
NLidKeys defined in line 62; used 21 times

Defined struct's

mod_info defined in line 95; used 2 times
  • in line 108(2)
modtab defined in line 65; used 10 times
Last modified: 1986-04-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2584
Valid CSS Valid XHTML 1.0 Strict