|
|
1.1 ! root 1: ! 2: # include <stdio.h> ! 3: # include <ingres.h> ! 4: # include <aux.h> ! 5: # include <version.h> ! 6: # include <access.h> ! 7: # include <symbol.h> ! 8: # include <opsys.h> ! 9: # include <pv.h> ! 10: # include <sccs.h> ! 11: # include <sys/dir.h> ! 12: ! 13: SCCSID(@(#)creatdb.c 7.7 9/26/83) ! 14: ! 15: /* ! 16: ** CREATDB -- create database (or modify database status) ! 17: ** ! 18: ** This program creates a new database. It takes the name of ! 19: ** the new database (syntax defined below) and a series of ! 20: ** flags (also defined below). ! 21: ** ! 22: ** In order to perform this command, you must be enabled by ! 23: ** having the U_CREATDB bit set in the user status word ! 24: ** of the users file. ! 25: ** ! 26: ** The -m flag specifies that the directory for the database ! 27: ** already exists. It stands for "mounted-file-system", ! 28: ** because this is presumably when you might use this feature. ! 29: ** The directory must be empty. ! 30: ** ! 31: ** The -e flag specifies that the database already exists. ! 32: ** It must be in all ways a valid database. This mode allows ! 33: ** you to turn flags on and off, as controlled by the other ! 34: ** flags. ! 35: ** ! 36: ** Usage: ! 37: ** creatdb [flags] databasename ! 38: ** ! 39: ** Positional Parameters: ! 40: ** databasename -- the name of the database to create. ! 41: ** It must conform to all the usual rules ! 42: ** about names. Notice that this is more ! 43: ** restrictive than UNIX usually is: names ! 44: ** must begin with an alpha, and must be ! 45: ** composed of alphanumerics. It may be ! 46: ** at most 14 characters long. Underscore ! 47: ** counts as an alphabetic. ! 48: ** ! 49: ** Flags: ! 50: ** -m ! 51: ** This is a mounted filesystem. Actually, ! 52: ** this just means that the directory in which ! 53: ** the database is to reside already exists. ! 54: ** It must be empty. ! 55: ** -e ! 56: ** This database exists. When the -e flag is ! 57: ** specified, the database is brought up to date, ! 58: ** rather than created. Things which may be ! 59: ** changed with the -e flag is anything that ! 60: ** affects the database status or the relation ! 61: ** status bits. ! 62: ** -uXX ! 63: ** Run as user XX (usercode or login name). This ! 64: ** flag may only be used by the INGRES superuser. ! 65: ** Normally, the database administrator for the ! 66: ** new database is the user who performs the ! 67: ** command, but the -u flag allows INGRES to ! 68: ** give the database to someone else. Thus, it ! 69: ** is possible for someone to be a DBA without ! 70: ** having the U_CREATDB bit set. ! 71: ** -Fpathname ! 72: ** Use the named file as the database template. ! 73: ** This is, of course, for debugging use only. ! 74: ** +-c ! 75: ** Turn concurrency control on/off. The default ! 76: ** for a new database depends on the dbtmplt file, ! 77: ** but as of this writing it defaults on. ! 78: ** +-q ! 79: ** Turn query modification on/off. ! 80: ** +-l ! 81: ** Turn protection violation logging on/off. ! 82: ** ! 83: ** Files: ! 84: ** .../files/dbtmplt<VERSION> ! 85: ** This file drives the entire program. The ! 86: ** syntax of this file is defined below in ! 87: ** readdbtemp(). Briefly, it tells the database ! 88: ** status, the relations in an 'empty' database, ! 89: ** and the status and format of those relations. ! 90: ** .../data/base ! 91: ** This directory is the directory in which all ! 92: ** databases eventually reside. Each database is ! 93: ** a subdirectory of this directory. ! 94: ** ! 95: ** Return Codes: ! 96: ** zero -- success ! 97: ** else -- failure. ! 98: ** ! 99: ** Defined Constants: ! 100: ** MAXRELNS ! 101: ** This defines the maximum number of relations ! 102: ** which may be declared in the dbtmplt file. ! 103: ** MAXDBTEMP ! 104: ** The maximum size of the dbtmplt file. This ! 105: ** determines the maximum number of characters ! 106: ** which may be in the file. ! 107: ** ! 108: ** Compilation Flags: ! 109: ** xB_UNIX -- if defined, says that we have a "Berkeley ! 110: ** UNIX" system, with no group id's. If ! 111: ** undefined, specifies either a version seven ! 112: ** UNIX (with 16-bit group id's) or version six ! 113: ** UNIX (with 8-bit group id's); either way, ! 114: ** "setgid(getgid())" will work. ! 115: ** ! 116: ** Trace Flags: ! 117: ** -Tn, as below: ! 118: ** ! 119: ** 1 -- makereln() ! 120: ** 2 -- create() ! 121: ** 10 -- makeadmin() ! 122: ** 12 -- makefile() ! 123: ** 20 -- makedb() ! 124: ** ! 125: ** Compilation Instructions: ! 126: ** % setup creatdb ! 127: ** ! 128: ** - which translates to - ! 129: ** ! 130: ** % cc -n -O creatdb.c error.c ../../lib/dbulib \ ! 131: ** ../../lib/access ../../lib/utility ! 132: ** % chmod 4711 a.out ! 133: */ ! 134: ! 135: ! 136: ! 137: ! 138: # define MAXRELNS 20 ! 139: # define MAXDBTEMP 2000 ! 140: ! 141: /* relation & attribute reln descriptors used in access methods */ ! 142: extern DESC Reldes; ! 143: extern DESC Attdes; ! 144: ! 145: extern int Status; /* user status, set by initucode */ ! 146: int Dbstat; /* database status */ ! 147: int Dbson, Dbsoff; /* same: bits turned on, bits turned off */ ! 148: typedef struct reldes ! 149: { ! 150: int bitson; ! 151: int bitsoff; ! 152: PARM parmv[PV_MAXPC]; ! 153: } RELDES; ! 154: RELDES Rellist[MAXRELNS]; ! 155: char Delim; ! 156: extern char *Dbpath; ! 157: short tTdbu[100]; ! 158: ! 159: ! 160: ! 161: main(argc, argv) ! 162: int argc; ! 163: char *argv[]; ! 164: { ! 165: register int i; ! 166: int admin; ! 167: char adminbuf[100]; ! 168: extern struct admin Admin; ! 169: extern int errno; ! 170: auto int code; ! 171: struct relation relk; ! 172: char *database; ! 173: char **av; ! 174: register char *p; ! 175: char *user_ovrd; ! 176: int faterr; ! 177: register int *flagv; ! 178: char *dbtmpfile; ! 179: extern char *Parmvect[]; ! 180: extern char *Flagvect[]; ! 181: int exists; ! 182: int *flaglkup(); ! 183: char *ztack(); ! 184: extern char *rindex(); ! 185: # ifdef DIRBLKSIZ ! 186: DIR *dir_ptr; /* pointer to '.' */ ! 187: struct direct *dir; /* directory entry */ ! 188: # else DIRBLKSIZ ! 189: struct dir direct; ! 190: # endif DIRBLKSIZ ! 191: ! 192: argv[argc] = NULL; ! 193: ! 194: # ifdef xSTR1 ! 195: tTrace(argv, 'T', tTdbu, 100); ! 196: # endif ! 197: ! 198: /* ! 199: ** Do a lot of magic initialization. ! 200: ** ! 201: ** 'exists' get set to -1 if the database does not exist ! 202: ** at all, 1 if it exists, and 0 if it does not ! 203: ** exist but there is an indirect pointer to it. ! 204: */ ! 205: ! 206: exists = 0; ! 207: i = initucode(argc, argv, TRUE, NULL, -1); ! 208: switch (i) ! 209: { ! 210: case 0: ! 211: case 5: ! 212: exists = 1; ! 213: break; ! 214: ! 215: case 6: ! 216: exists = 0; ! 217: ! 218: case 1: ! 219: break; ! 220: ! 221: case 2: ! 222: printf("You are not authorized to create this database\n"); ! 223: exit(-1); ! 224: ! 225: case 3: ! 226: printf("You are not a valid INGRES user\n"); ! 227: exit(-1); ! 228: ! 229: case 4: ! 230: printf("No database name specified\n"); ! 231: usage: ! 232: printf("Usage: creatdb [-uname] [-e] [-m] [+-c] [+-q] dbname\n"); ! 233: exit(-1); ! 234: ! 235: default: ! 236: syserr("initucode %d", i); ! 237: } ! 238: ! 239: faterr = 0; ! 240: dbtmpfile = 0; ! 241: for (av = Flagvect; (p = *av) != NULL; av++) ! 242: { ! 243: if (p[0] != '-' && p[0] != '+') ! 244: syserr("flag %s", p); ! 245: switch (p[1]) ! 246: { ! 247: case 'F': /* dbtmplt file */ ! 248: if (p[2] == 0) ! 249: goto badflag; ! 250: dbtmpfile = &p[2]; ! 251: break; ! 252: ! 253: case 'T': /* trace flag */ ! 254: break; ! 255: ! 256: default: ! 257: if (flagv = flaglkup(p[1], p[0])) ! 258: { ! 259: if (p[0] == '+') ! 260: *flagv = 1; ! 261: else ! 262: *flagv = -1; ! 263: continue; ! 264: } ! 265: badflag: ! 266: printf("bad flag %s\n", p); ! 267: faterr++; ! 268: continue; ! 269: ! 270: } ! 271: if (p[0] == '+') ! 272: goto badflag; ! 273: } ! 274: ! 275: /* check for legality of database name */ ! 276: database = Parmvect[0]; ! 277: if (Parmvect[1] != NULL) ! 278: { ! 279: printf("Too many parameters to creatdb"); ! 280: goto usage; ! 281: } ! 282: if (!check(database)) ! 283: { ! 284: printf("Illegal database name %s\n", database); ! 285: exit(-1); ! 286: } ! 287: ! 288: if ((Status & U_CREATDB) == 0) ! 289: { ! 290: printf("You are not allowed this command\n"); ! 291: exit(-1); ! 292: } ! 293: ! 294: /* end of input checking */ ! 295: if (faterr != 0) ! 296: exit(2); ! 297: ! 298: /* now see if it should have been there */ ! 299: if (flagval('m') || flagval('e')) ! 300: { ! 301: if (exists <= 0) ! 302: { ! 303: printf("Database %s does not exist\n", database); ! 304: exit(-1); ! 305: } ! 306: ! 307: # ifdef xSTR3 ! 308: if (tTf(1, 14)) ! 309: printf("Dbpath = '%s'\n", Dbpath); ! 310: # endif ! 311: if (chdir(Dbpath) < 0) ! 312: syserr("chdir %s", Dbpath); ! 313: ! 314: if (!flagval('e')) ! 315: { ! 316: # ifdef DIRBLKSIZ ! 317: ! 318: /* make certain that it is empty */ ! 319: if ( (dir_ptr = opendir(".")) == NULL ) ! 320: syserr(0,"Can't open '.'"); ! 321: for ( dir = readdir(dir_ptr) ; dir != NULL ; dir = readdir(dir_ptr) ) ! 322: { ! 323: if ( strcmp(".",dir->d_name) && strcmp("..",dir->d_name) ) ! 324: syserr(0, "%s is not empty", database); ! 325: } ! 326: closedir(dir_ptr); ! 327: ! 328: # else DIRBLKSIZ ! 329: /* make certain that it is empty */ ! 330: freopen(".", "r", stdin); ! 331: /* Skip "." and ".." entries */ ! 332: fread(&direct, sizeof (struct dir), 1, stdin); ! 333: fread(&direct, sizeof (struct dir), 1, stdin); ! 334: while ( fread(&direct, sizeof (struct dir), 1, stdin) != EOF) ! 335: { ! 336: if ( direct.d_ino != 0) ! 337: syserr(0, "%s is not empty", database); ! 338: } ! 339: # endif DIRBLKSIZ ! 340: } ! 341: else ! 342: { ! 343: /* check for correct owner */ ! 344: acc_init(); ! 345: if (!bequal(Usercode, Admin.adhdr.adowner, 2)) ! 346: syserr(0, "You are not the DBA for this database"); ! 347: } ! 348: } ! 349: else ! 350: { ! 351: if (exists > 0) ! 352: { ! 353: printf("Database %s already exists\n", database); ! 354: exit(-1); ! 355: } ! 356: ! 357: /* create it */ ! 358: i = fork(); ! 359: if (i < 0) ! 360: syserr("fork err"); ! 361: if (i == 0) ! 362: { ! 363: /* split off directory */ ! 364: *(p = rindex(Dbpath, '/')) = '\0'; ! 365: chdir(Dbpath); ! 366: if (setuid(getuid())) ! 367: syserr("setuid"); ! 368: # ifndef xB_UNIX ! 369: if (setgid(getgid())) ! 370: syserr("setgid"); ! 371: # endif ! 372: # ifdef xV7_UNIX ! 373: umask(00); ! 374: # endif ! 375: *p++ = '/'; ! 376: execl("/bin/mkdir", "/bin/mkdir", p, 0); ! 377: execl("/usr/bin/mkdir", "/usr/bin/mkdir", p, 0); ! 378: syserr("exec /bin/mkdir"); ! 379: } ! 380: while (wait(&code) != -1) ! 381: continue; ! 382: ! 383: /* move into data/base directory */ ! 384: if (chdir(Dbpath) < 0) ! 385: syserr("chdir %s: probably bad default mode in mkdir", ! 386: Dbpath); ! 387: ! 388: /* change the mode of the database */ ! 389: i = fork(); ! 390: if (i < 0) ! 391: syserr("fork 2"); ! 392: if (i == 0) ! 393: { ! 394: setuid(getuid()); ! 395: if (chmod(".", 0777)) ! 396: syserr("chmod"); ! 397: exit(0); ! 398: } ! 399: ! 400: while (wait(&code) != -1) ! 401: ; ! 402: if ((code & 0377) != 0) ! 403: exit(code); ! 404: } ! 405: ! 406: /* reset 'errno', set from possibly bad chdir */ ! 407: errno = 0; ! 408: ! 409: /* determine name of dbtmplt file and open */ ! 410: if (dbtmpfile == NULL) ! 411: { ! 412: /* create dbtmplt file name */ ! 413: dbtmpfile = ztack(ztack(Pathname, "/files/dbtmplt"), VERSION); ! 414: } ! 415: if (freopen(dbtmpfile, "r", stdin) == NULL) ! 416: syserr("dbtmplt open %s", dbtmpfile); ! 417: ! 418: readdbtemp(); ! 419: ! 420: /* check for type -- update database status versus create */ ! 421: if (flagval('e')) ! 422: changedb(); ! 423: else ! 424: makedb(); ! 425: ! 426: /* close the cache descriptors */ ! 427: # ifdef xSTR3 ! 428: if (tTf(50, 0)) ! 429: { ! 430: printf("Attdes.reltid = "); ! 431: dumptid(&Attdes.reltid); ! 432: printf("Reldes.reltid = "); ! 433: dumptid(&Reldes.reltid); ! 434: } ! 435: # endif ! 436: if (i = closer(&Attdes)) ! 437: syserr("creatdb: closer(att) %d", i); ! 438: if (i = closer(&Reldes)) ! 439: syserr("creatdb: closer(rel) %d", i); ! 440: ! 441: /* bring tupcount in 'admin' file to date */ ! 442: Admin.adreld.reldum.reltups = Reldes.reldum.reltups; ! 443: Admin.adattd.reldum.reltups = Attdes.reldum.reltups; ! 444: ! 445: /* set other fields as appropriate */ ! 446: Admin.adreld.relfp = Admin.adattd.relfp = -1; ! 447: Admin.adreld.relopn = Admin.adattd.relopn = 0; ! 448: Admin.adhdr.adlength = sizeof Admin.adhdr; ! 449: Admin.adhdr.adreldsz = Admin.adhdr.adattdsz = sizeof Admin.adreld; ! 450: Admin.adhdr.adversion = DBVERCODE; ! 451: ! 452: if ((admin = creat("admin", FILEMODE)) < 0) ! 453: syserr("main: creat admin"); ! 454: if (write(admin, &Admin, sizeof Admin) != sizeof Admin) ! 455: syserr("main: write Admin"); ! 456: close(admin); ! 457: ! 458: /* exit successfully */ ! 459: exit(0); ! 460: } ! 461: /* ! 462: ** Rubout processing. ! 463: */ ! 464: ! 465: rubproc() ! 466: { ! 467: exit(-2); ! 468: } ! 469: /* ! 470: ** READDBTEMP -- read the dbtmplt file and build internal form ! 471: ** ! 472: ** This routine reads the dbtmplt file (presumably openned as ! 473: ** the standard input) and initializes the Dbstat (global database ! 474: ** status word) and Rellist variables. ! 475: ** ! 476: ** Rellist is an array of argument vectors, exactly as passed to ! 477: ** 'create'. ! 478: ** ! 479: ** The syntax of the dbtmplt file is as follows: ! 480: ** ! 481: ** The first line is a single status word (syntax defined below) ! 482: ** which is the database status. ! 483: ** ! 484: ** The rest of the file is sets of lines separated by blank lines. ! 485: ** Each set of lines define one relation. Two blank lines in a ! 486: ** row or an end-of-file define the end of the file. Each set ! 487: ** of lines is broken down: ! 488: ** ! 489: ** The first line is in the following format: ! 490: ** relname:status ! 491: ** which defines the relation name and the relation status for ! 492: ** this relation (syntax defined in 'getstat' below). Status ! 493: ** may be omitted, in which case a default status is assumed. ! 494: ** ! 495: ** Second through n'th lines of each set define the attributes. ! 496: ** They are of the form: ! 497: ** attname format ! 498: ** separated by a single tab. 'Format' is the same as on a ! 499: ** 'create' statement in QUEL. ! 500: ** ! 501: ** Notice that we force the S_CATALOG bit to be on in any ! 502: ** case. This is because the changedb() routine will fail ! 503: ** if the -e flag is ever used on this database if any ! 504: ** relation appears to be a user relation. ! 505: ** ! 506: ** Parameters: ! 507: ** none ! 508: ** ! 509: ** Returns: ! 510: ** none ! 511: ** ! 512: ** Side Effects: ! 513: ** Dbstat gets the database status. ! 514: ** Rellist is created with a list of the relations, ! 515: ** (as parameter vectors -01:2st as passed to ! 516: ** create). The entry after the last entry ! 517: ** has its pv[0] == NULL. ! 518: ** ! 519: ** Called By: ! 520: ** main ! 521: ** ! 522: ** Trace Flags: ! 523: ** none ! 524: */ ! 525: ! 526: readdbtemp() ! 527: { ! 528: static char buf[MAXDBTEMP]; ! 529: register RELDES *r; ! 530: register PARM *q; ! 531: register int i; ! 532: int j; ! 533: char *p; ! 534: int defrstat; ! 535: auto int bitson, bitsoff; ! 536: ! 537: /* read database status */ ! 538: defrstat = S_CATALOG | S_NOUPDT | S_CONCUR | S_PROTALL; ! 539: bitson = bitsoff = 0; ! 540: Dbstat = getstat(A_DBCONCUR, &Dbson, &Dbsoff); ! 541: if (Delim == ':') ! 542: defrstat = getstat(defrstat, &bitson, &bitsoff); ! 543: if (Delim != '\n') ! 544: syserr("readdbtemp: bad Dbstat %c", Delim); ! 545: ! 546: /* compute default relation status */ ! 547: ! 548: /* start reading relation info */ ! 549: p = buf; ! 550: for (r = Rellist; ; r++) ! 551: { ! 552: r->bitson = bitson; ! 553: r->bitsoff = bitsoff; ! 554: ! 555: q = r->parmv; ! 556: ! 557: /* get relation name */ ! 558: q[1].pv_type = PV_STR; ! 559: q[1].pv_val.pv_str = p; ! 560: p += getname(p) + 1; ! 561: ! 562: /* test for end of dbtmplt file */ ! 563: if (q[1].pv_val.pv_str[0] == 0) ! 564: break; ! 565: ! 566: /* get relation status */ ! 567: i = getstat(defrstat, &r->bitson, &r->bitsoff); ! 568: i |= S_CATALOG; /* guarantee system catalog */ ! 569: q->pv_type = PV_STR; ! 570: q++->pv_val.pv_str = p; ! 571: *p++ = ((i >> 15) & 1) + '0'; ! 572: for (j = 12; j >= 0; j -= 3) ! 573: *p++ = ((i >> j) & 07) + '0'; ! 574: *p++ = 0; ! 575: q++; ! 576: if (Delim != '\n') ! 577: syserr("readdbtemp: bad rel %c", Delim); ! 578: ! 579: /* read attribute names and formats */ ! 580: for (;;) ! 581: { ! 582: /* get attribute name */ ! 583: q->pv_type = PV_STR; ! 584: q++->pv_val.pv_str = p; ! 585: p += getname(p) + 1; ! 586: if (q[-1].pv_val.pv_str[0] == 0) ! 587: break; ! 588: if (Delim != '\t') ! 589: syserr("readdbtemp: bad att %s, d='%c'", ! 590: q[-1].pv_val.pv_str, Delim); ! 591: ! 592: /* get attribute type */ ! 593: q->pv_type = PV_STR; ! 594: q++->pv_val.pv_str = p; ! 595: p += getname(p) + 1; ! 596: if (Delim != '\n') ! 597: syserr("readdbtemp: bad type %c", Delim); ! 598: } ! 599: ! 600: /* insert end of argv signal */ ! 601: (--q)->pv_type = PV_EOF; ! 602: ! 603: /* ad-hoc overflow test */ ! 604: if (p >= &buf[MAXDBTEMP]) ! 605: syserr("readdbtemp: overflow"); ! 606: } ! 607: /* mark the end of list */ ! 608: q[1].pv_type = PV_EOF; ! 609: } ! 610: /* ! 611: ** GETSTAT -- Get status word ! 612: ** ! 613: ** A status word is read from the standard input (presumably ! 614: ** 'dbtmplt'). The string read is interpreted as an octal ! 615: ** number. The syntax is: ! 616: ** N{+c+N[~N]} ! 617: ** where N is a number, + is a plus or a minus sign, and c is ! 618: ** a flag. '+c+N1[~N2]' groups are interpreted as follows: ! 619: ** If flag 'c' is set (assuming the preceeding character is a +, ! 620: ** clear if it is a -), then set (clear) bits N1. If tilde N2 ! 621: ** is present, then if flag 'c' is unset (called as '-c' ('+c')) ! 622: ** clear (set) bits N2; if ~N2 is not present, clear (set) ! 623: ** bits N1. ! 624: ** ! 625: ** For example, an entry might be (but probably isn't): ! 626: ** 1-c-1+q+6~2 ! 627: ** having the following meaning: ! 628: ** ! 629: ** 1. Default to the 1 bit set. ! 630: ** ! 631: ** 2. If the -c flag is specified, clear the '1' bit. If the ! 632: ** +c flag is specified, set the '1' bit. If it is unspecified, ! 633: ** leave the '1' bit alone. ! 634: ** ! 635: ** 3. If the +q flag is specified, set the '2' bit and the '4' ! 636: ** bit. If the -q flag is specified, clear the '2' bit (but leave ! 637: ** the '4' bit alone). If the +-q flag is unspecified, leave ! 638: ** those bits alone. ! 639: ** ! 640: ** Thus, a database with this entry is initially created with ! 641: ** the 1 bit on. The '4' bit is a history, which says if the ! 642: ** 'q' flag has ever been set, while the '2' bit tells if it is ! 643: ** currently set. ! 644: ** ! 645: ** Parameters: ! 646: ** def -- the default to return if there is no number ! 647: ** there at all. ! 648: ** bitson -- a pointer to a word to contain all the ! 649: ** bits to be turned on -- used for the -e flag. ! 650: ** bitsoff -- same, for bits turned off. ! 651: ** ! 652: ** Returns: ! 653: ** The value of the status word. ! 654: ** There are no error returns. ! 655: ** ! 656: ** Side Effects: ! 657: ** File activity. ! 658: ** ! 659: ** Called By: ! 660: ** readdbtemp ! 661: ** ! 662: ** Trace Flags: ! 663: ** none ! 664: */ ! 665: ! 666: getstat(def, bitson, bitsoff) ! 667: int def; ! 668: int *bitson; ! 669: int *bitsoff; ! 670: { ! 671: register int c; ! 672: register int stat; ! 673: register int i; ! 674: int setbits; ! 675: int clrbits; ! 676: char ctlch; ! 677: ! 678: /* reset bits being turned on and off */ ! 679: *bitson = *bitsoff = 0; ! 680: ! 681: /* check to see if a base status wolushs defined */ ! 682: if (Delim == '\n' || (Delim = c = getchar()) < '0' || c > '7') ! 683: { ! 684: /* no, use default */ ! 685: stat = def; ! 686: } ! 687: else ! 688: { ! 689: /* read base status field */ ! 690: ungetc(c, stdin); ! 691: stat = roctal(); ! 692: } ! 693: ! 694: /* scan '+c+N' entries */ ! 695: for (;;) ! 696: { ! 697: /* check for a flag present */ ! 698: c = Delim; ! 699: if (c == '\n' || c == ':') ! 700: return (stat); ! 701: if (c != '+' && c != '-') ! 702: { ! 703: badfmt: ! 704: syserr("getstat: bad fmt %c", c); ! 705: } ! 706: ! 707: /* we have some flag -- get it's value */ ! 708: i = flagval(getchar()); ! 709: ! 710: /* save sign char on flag */ ! 711: ctlch = c; ! 712: ! 713: /* get sign on associated number and the number */ ! 714: c = getchar(); ! 715: if (c != '+' && c != '-') ! 716: goto badfmt; ! 717: setbits = roctal(); ! 718: ! 719: /* test whether action on -X same as on +X */ ! 720: if (Delim == '~') ! 721: { ! 722: /* they have different bits (see above) */ ! 723: clrbits = roctal(); ! 724: } ! 725: else ! 726: { ! 727: /* on 'creatdb -e -X', use opposite bits of +X */ ! 728: clrbits = setbits; ! 729: } ! 730: ! 731: /* test for any effect at all */ ! 732: if (i == 0) ! 733: continue; ! 734: ! 735: /* test whether we should process the '+N' */ ! 736: if ((ctlch == '-') ? (i < 0) : (i > 0)) ! 737: i = setbits; ! 738: else ! 739: { ! 740: i = clrbits; ! 741: ! 742: /* switch sense of bit action */ ! 743: if (c == '+') ! 744: c = '-'; ! 745: else ! 746: c = '+'; ! 747: } ! 748: ! 749: if (c == '+') ! 750: { ! 751: stat |= i; ! 752: *bitson |= i; ! 753: } ! 754: else ! 755: { ! 756: stat &= ~i; ! 757: *bitsoff |= i; ! 758: } ! 759: } ! 760: } ! 761: /* ! 762: ** ROCTAL -- Read an octal number from standard input. ! 763: ** ! 764: ** This routine just reads a single octal number from the standard ! 765: ** input and returns its value. It will only read up to a non- ! 766: ** octal digit. It will also skip initial and trailing blanks. ! 767: ** 'Delim' is set to the next character in the input stream. ! 768: ** ! 769: ** Parameters: ! 770: ** none ! 771: ** ! 772: ** Returns: ! 773: ** value of octal number in the input stream. ! 774: ** ! 775: ** Side Effects: ! 776: ** 'Delim' is set to the delimiter which terminated the ! 777: ** number. ! 778: ** File activity on stdin. ! 779: ** ! 780: ** Called By: ! 781: ** getstat() ! 782: ** ! 783: ** Trace Flags: ! 784: ** none ! 785: */ ! 786: ! 787: roctal() ! 788: { ! 789: register int c; ! 790: register int val; ! 791: ! 792: val = 0; ! 793: ! 794: /* skip initial blanks */ ! 795: while ((c = getchar()) == ' ') ! 796: continue; ! 797: ! 798: /* get numeric value */ ! 799: while (c >= '0' && c <= '7') ! 800: { ! 801: val = (val << 3) | (c - '0'); ! 802: c = getchar(); ! 803: } ! 804: ! 805: /* skip trailing blanks */ ! 806: while (c == ' ') ! 807: c = getchar(); ! 808: ! 809: /* set Delim and return numeric value */ ! 810: Delim = c; ! 811: return (val); ! 812: } ! 813: /* ! 814: ** GETNAME -- get name from standard input ! 815: ** ! 816: ** This function reads a name from the standard input. A ! 817: ** name is defined as a string of letters and digits. ! 818: ** ! 819: ** The character which caused the scan to terminate is stored ! 820: ** into 'Delim'. ! 821: ** ! 822: ** Parameters: ! 823: ** ptr -- a pointer to the buffer in which to dump the ! 824: ** name. ! 825: ** ! 826: ** Returns: ! 827: ** The length of the string. ! 828: ** ! 829: ** Side Effects: ! 830: ** File activity on standard input. ! 831: ** ! 832: ** Called By: ! 833: ** readdbtemp ! 834: ** ! 835: ** Trace Flags: ! 836: ** none ! 837: */ ! 838: ! 839: getname(ptr) ! 840: char *ptr; ! 841: { ! 842: register int len; ! 843: register int c; ! 844: register char *p; ! 845: ! 846: len = 0; ! 847: ! 848: for (p = ptr; (c = getchar()) != EOF; len++) ! 849: { ! 850: /* check for end of name */ ! 851: if ((c < 'a' || c > 'z') && ! 852: (c < '0' || c > '9')) ! 853: break; ! 854: ! 855: /* store character into buffer */ ! 856: *p++ = c; ! 857: } ! 858: ! 859: /* null-terminate the string */ ! 860: *p = '\0'; ! 861: ! 862: /* store the delimiting character and return length of string */ ! 863: Delim = c; ! 864: return (len); ! 865: } ! 866: /* ! 867: ** MAKEDB -- make a database from scratch ! 868: ** ! 869: ** This is the code to make a database if the -e flag is off. ! 870: ** ! 871: ** The first step is to make a copy of the admin file ! 872: ** in the internal 'Admin' struct. This is the code which ! 873: ** subsequently gets used by openr and opencatalog. Notice ! 874: ** that the admin file is not written out; this happens after ! 875: ** makedb returns. ! 876: ** ! 877: ** Next, the physical files are created with one initial (empty) ! 878: ** page. This has to happen before the 'create' call so ! 879: ** that it will be possible to flush 'relation' and 'attribute' ! 880: ** relation pages during the creates of the 'relation' and ! 881: ** 'attribute' relations. Other relations don't need this, ! 882: ** but it is more convenient to be symmetric. ! 883: ** ! 884: ** The next step is to create the relations. Of course, all ! 885: ** this really is is inserting stuff into the system catalogs. ! 886: ** ! 887: ** When we are all done we open the relation relation for the ! 888: ** admin cache (which of course should exist now). Thus, ! 889: ** the closer's in main (which must be around to update the ! 890: ** tuple count) will work right. ! 891: ** ! 892: ** Parameters: ! 893: ** none ! 894: ** ! 895: ** Returns: ! 896: ** none ! 897: ** ! 898: ** Side Effects: ! 899: ** A database is created!! ! 900: ** Several files will be created in the current directory, ! 901: ** one for each relation mentioned in the ! 902: ** 'dbtmplt' file. ! 903: ** The 'Admin' struct will be filled in. ! 904: ** ! 905: ** Called By: ! 906: ** main ! 907: ** ! 908: ** Trace Flags: ! 909: ** 20 ! 910: */ ! 911: ! 912: makedb() ! 913: { ! 914: DESC d; ! 915: register RELDES *r; ! 916: ! 917: # ifdef xSTR3 ! 918: if (tTf(51, 0)) ! 919: printf(">>makedb, Usercode = %s (%u)\n", Usercode, Usercode); ! 920: # endif ! 921: ! 922: /* create the physical files */ ! 923: for (r = Rellist; r->parmv[1].pv_type != PV_EOF; r++) ! 924: { ! 925: makefile(r); ! 926: } ! 927: ! 928: /* initialize the admin file internal cache */ ! 929: bmove(Usercode, Admin.adhdr.adowner, 2); ! 930: Admin.adhdr.adflags = Dbstat; ! 931: makeadmin(&Admin.adreld, Rellist[0].parmv); ! 932: makeadmin(&Admin.adattd, Rellist[1].parmv); ! 933: ! 934: /* done with admin initialization */ ! 935: ! 936: /* initialize relations */ ! 937: for (r = Rellist; r->parmv[1].pv_type != PV_EOF; r++) ! 938: { ! 939: makereln(r); ! 940: } ! 941: } ! 942: /* ! 943: ** MAKEADMIN -- manually initialize descriptor for admin file ! 944: ** ! 945: ** The relation descriptor pointed to by 'pv' is turned into ! 946: ** a descriptor, returned in 'd'. Presumably, this descriptor ! 947: ** is later written out to the admin file. ! 948: ** ! 949: ** Notice that the 'reltid' field is filled in sequentially. ! 950: ** This means that the relations put into the admin file ! 951: ** must be created in the same order that they are 'made' ! 952: ** (by this routine), that the format of tid's must not ! 953: ** change, and that there can not be over one page worth of ! 954: ** relations in the admin file. Our current system currently ! 955: ** handles this easily. ! 956: ** ! 957: ** Parameters: ! 958: ** d -- the descriptor to get the result. ! 959: ** pv -- a parm vector in 'create' format, which drives ! 960: ** this routine. ! 961: ** ! 962: ** Returns: ! 963: ** none ! 964: ** ! 965: ** Side Effects: ! 966: ** none ! 967: ** ! 968: ** Called By: ! 969: ** main ! 970: ** ! 971: ** Trace Flags: ! 972: ** 10 ! 973: */ ! 974: ! 975: ! 976: ! 977: makeadmin(d, pv) ! 978: DESC *d; ! 979: PARM pv[]; ! 980: { ! 981: register DESC *des; ! 982: register PARM *p; ! 983: register int i; ! 984: auto int len; ! 985: static int lineno; ! 986: char fname[MAXNAME + 3]; ! 987: ! 988: des = d; ! 989: p = pv; ! 990: ! 991: # ifdef xSTR2 ! 992: if (tTf(10, -1)) ! 993: { ! 994: printf("creating %s in admin\n", p[1].pv_val.pv_str); ! 995: } ! 996: # endif ! 997: i = oatoi(p++->pv_val.pv_str); ! 998: ingresname(p++->pv_val.pv_str, Usercode, fname); ! 999: bmove(fname, des->reldum.relid, MAXNAME + 2); ! 1000: des->reldum.relstat = i; ! 1001: des->reldum.relatts = 0; ! 1002: des->reldum.relwid = 0; ! 1003: des->reldum.relspec = M_HEAP; ! 1004: des->reltid.ltid = 0; ! 1005: des->reltid.s_tupid.line_id = lineno++; ! 1006: des->relfp = open(fname, 2); ! 1007: if (des->relfp < 0) ! 1008: syserr("makeadmin: open %s", fname); ! 1009: des->relopn = (des->relfp + 1) * -5; ! 1010: ! 1011: /* initialize domain info */ ! 1012: for (; p++->pv_type != PV_EOF; p++) ! 1013: { ! 1014: register char c; ! 1015: ! 1016: c = p[0].pv_val.pv_str[0]; ! 1017: if (c != 'i' && c != 'c' && c != 'f') ! 1018: syserr("dbtmplt: type err on %s", p[0].pv_val.pv_str); ! 1019: des->relfrmt[++(des->reldum.relatts)] = c; ! 1020: len = atoi(&p[0].pv_val.pv_str[1]); ! 1021: des->relfrml[des->reldum.relatts] = len; ! 1022: des->reloff[des->reldum.relatts] = des->reldum.relwid; ! 1023: des->reldum.relwid += len; ! 1024: } ! 1025: } ! 1026: /* ! 1027: ** MAKEFILE -- make an 'empty' file for a relation ! 1028: ** ! 1029: ** This routine creates a file with a single (empty) page ! 1030: ** on it -- it is part of the 'create' code, essentially. ! 1031: ** ! 1032: ** Parameters: ! 1033: ** rr -- a pointer to the 'reldes' structure for this ! 1034: ** relation (file). ! 1035: ** ! 1036: ** Returns: ! 1037: ** none ! 1038: ** ! 1039: ** Side Effects: ! 1040: ** A file with one page is created. ! 1041: ** ! 1042: ** Called By: ! 1043: ** makedb ! 1044: ** changedb ! 1045: ** ! 1046: ** Trace Flags: ! 1047: ** 12 ! 1048: */ ! 1049: ! 1050: makefile(r) ! 1051: register RELDES *r; ! 1052: { ! 1053: DESC d; ! 1054: register int i; ! 1055: ! 1056: ingresname(r->parmv[1].pv_val.pv_str, Usercode, d.reldum.relid); ! 1057: # ifdef xSTR1 ! 1058: if (tTf(12, 0)) ! 1059: printf("creat %s\n", d.reldum.relid); ! 1060: # endif ! 1061: if ((d.relfp = creat(d.reldum.relid, FILEMODE)) < 0) ! 1062: syserr("creat %s", d.reldum.relid); ! 1063: if ((i = formatpg(&d, (long) 1)) != 0) ! 1064: syserr("makefile: formatpg %d", i); ! 1065: close(d.relfp); ! 1066: } ! 1067: /* ! 1068: ** MAKERELN -- make a relation ! 1069: ** ! 1070: ** This is the second half of the create, started by 'makefile'. ! 1071: ** ! 1072: ** This routine just sets up argument vectors and calls create, ! 1073: ** which does the real work. ! 1074: ** ! 1075: ** Parameters: ! 1076: ** rr -- a pointer to the Rellist entry for the relation ! 1077: ** to be created. ! 1078: ** ! 1079: ** Returns: ! 1080: ** none ! 1081: ** ! 1082: ** Side Effects: ! 1083: ** Information will be inserted into the 'relation' and ! 1084: ** 'attribute' relations. ! 1085: ** ! 1086: ** Called By: ! 1087: ** makedb ! 1088: ** changedb ! 1089: ** ! 1090: ** Trace Flags: ! 1091: ** 1 ! 1092: */ ! 1093: ! 1094: makereln(r) ! 1095: register RELDES *r; ! 1096: { ! 1097: register int pc; ! 1098: register PARM *pv; ! 1099: int i; ! 1100: ! 1101: pc = 0; ! 1102: for (pv = r->parmv; pv->pv_type != PV_EOF; pv++) ! 1103: pc++; ! 1104: pv = r->parmv; ! 1105: i = create(pc, pv); ! 1106: if (i != 0) ! 1107: syserr("create %d", i); ! 1108: } ! 1109: /* ! 1110: ** CHECK -- check database name syntax ! 1111: ** ! 1112: ** The name of a database is checked for validity. A valid ! 1113: ** database name is not more than 14 characters long, begins ! 1114: ** with an alphabetic character, and contains only alpha- ! 1115: ** numerics. Underscore is considered numeric. ! 1116: ** ! 1117: ** Parameters: ! 1118: ** p -- the string to check. ! 1119: ** ! 1120: ** Returns: ! 1121: ** TRUE -- ok. ! 1122: ** FALSE -- failure. ! 1123: ** ! 1124: ** Side Effects: ! 1125: ** none ! 1126: ** ! 1127: ** Called By: ! 1128: ** main ! 1129: ** ! 1130: ** Trace Flags: ! 1131: ** none ! 1132: */ ! 1133: ! 1134: check(p) ! 1135: char *p; ! 1136: { ! 1137: register char c; ! 1138: ! 1139: /* check string length */ ! 1140: if (length(p) > 14) ! 1141: return (FALSE); ! 1142: ! 1143: /* check the first character of the string for alphabetic */ ! 1144: c = *p++; ! 1145: if (c < 'a' || c > 'z') ! 1146: return (FALSE); ! 1147: ! 1148: /* check the rest for alphanumeric */ ! 1149: while ((c = *p++) != 0) ! 1150: { ! 1151: if (c == '_') ! 1152: continue; ! 1153: if (c >= '0' && c <= '9') ! 1154: continue; ! 1155: if (c >= 'a' && c <= 'z') ! 1156: continue; ! 1157: return (FALSE); ! 1158: } ! 1159: return (TRUE); ! 1160: } ! 1161: /* ! 1162: ** FLAGLKUP -- look up user flag ! 1163: ** ! 1164: ** This routine helps support a variety of user flags. The ! 1165: ** routine takes a given user flag and looks it up (via a ! 1166: ** very crude linear search) in the 'Flags' vector, and ! 1167: ** returns a pointer to the value. ! 1168: ** ! 1169: ** The 'flag' struct defines the flags. The 'flagname' field ! 1170: ** is the character which is the flag id, for example, 'c' ! 1171: ** in the flag '-c'. The 'flagtype' field defines how the ! 1172: ** flag may appear; if negative, only '-c' may appear, if ! 1173: ** positive, only '+c' may appear; if zero, either form may ! 1174: ** appear. Finally, the 'flagval' field is the value of the ! 1175: ** flag -- it may default any way the user wishes. ! 1176: ** ! 1177: ** Parameters: ! 1178: ** flagname -- the name (as defined above) of the ! 1179: ** flag to be looked up. ! 1180: ** plusminus -- a character, '+' means the '+x' form ! 1181: ** was issued, '-' means the '-x' form was ! 1182: ** issued, something else means *don't care*. ! 1183: ** If an illegal form was issued (that is, ! 1184: ** that does not match the 'flagtype' field ! 1185: ** in the structure), the "not found" return ! 1186: ** is taken. ! 1187: ** ! 1188: ** Returns: ! 1189: ** NULL -- flag not found, or was incorrect type, ! 1190: ** as when the '+x' form is specified in the ! 1191: ** parameters, but the 'Flags' struct says ! 1192: ** that only a '-x' form may appear. ! 1193: ** else -- pointer to the 'flagval' field of the correct ! 1194: ** field in the 'Flags' vector. ! 1195: ** ! 1196: ** Side Effects: ! 1197: ** none ! 1198: ** ! 1199: ** Called By: ! 1200: ** main ! 1201: ** flagval ! 1202: ** ! 1203: ** Trace Flags: ! 1204: ** none ! 1205: */ ! 1206: ! 1207: struct flag ! 1208: { ! 1209: char flagname; /* the name of the flag */ ! 1210: char flagtype; /* -1: -x form; +1: +x form; 0: both */ ! 1211: int flagval; /* user-defined value of the flag */ ! 1212: }; ! 1213: ! 1214: struct flag Flags[] = ! 1215: { ! 1216: 'q', 0, 0, ! 1217: 'l', 0, 0, ! 1218: 'c', 0, 0, ! 1219: 'e', -1, 0, ! 1220: 'm', -1, 0, ! 1221: 0 ! 1222: }; ! 1223: ! 1224: int * ! 1225: flaglkup(flagname, plusminus) ! 1226: char flagname; ! 1227: char plusminus; ! 1228: { ! 1229: register char f; ! 1230: register struct flag *p; ! 1231: register char pm; ! 1232: ! 1233: f = flagname; ! 1234: pm = plusminus; ! 1235: ! 1236: /* look up flag in vector */ ! 1237: for (p = Flags; p->flagname != f; p++) ! 1238: { ! 1239: if (p->flagname == 0) ! 1240: return (NULL); ! 1241: } ! 1242: ! 1243: /* found in list -- check type */ ! 1244: if ((pm == '+' && p->flagtype < 0) || ! 1245: (pm == '-' && p->flagtype > 0)) ! 1246: return (NULL); ! 1247: ! 1248: /* type is OK -- return pointer to value */ ! 1249: return (&p->flagval); ! 1250: } ! 1251: /* ! 1252: ** FLAGVAL -- return value of a flag ! 1253: ** ! 1254: ** Similar to 'flaglkup', except that the value is returned ! 1255: ** instead of the address, and no error return can occur. ! 1256: ** ! 1257: ** Parameters: ! 1258: ** f -- the flag to look up (see flaglkup). ! 1259: ** ! 1260: ** Returns: ! 1261: ** The value of flag 'f'. ! 1262: ** ! 1263: ** Side Effects: ! 1264: ** none ! 1265: ** ! 1266: ** Called By: ! 1267: ** readdbtemp() ! 1268: ** main() ! 1269: ** ! 1270: ** Trace Flags: ! 1271: ** none ! 1272: */ ! 1273: ! 1274: flagval(f) ! 1275: register char f; ! 1276: { ! 1277: register char *p; ! 1278: int *flaglkup(); ! 1279: ! 1280: /* get value of flag */ ! 1281: p = (char *)flaglkup(f, 0); ! 1282: ! 1283: /* test for error return, syserr if so */ ! 1284: if (p == NULL) ! 1285: syserr("flagval: flag %c", f); ! 1286: ! 1287: /* return value */ ! 1288: return (*p); ! 1289: } ! 1290: /* ! 1291: ** CHANGEDB -- change status bits for database/relations ! 1292: ** ! 1293: ** In this function we change the status bits for use with the ! 1294: ** -e flag. ! 1295: ** ! 1296: ** This module always uses the differential status ! 1297: ** change information, so that existing bits are not touched. ! 1298: ** ! 1299: ** We check to see that invalid updates, such as turning off ! 1300: ** query modification when it is already on, can not occur. ! 1301: ** This is because of potential syserr's when the system is ! 1302: ** later run, e.g., because of views without instantiations. ! 1303: ** ! 1304: ** In the second step, the database status is updated. This is ! 1305: ** done strictly in-core, and will be updated in the database ! 1306: ** after we return. ! 1307: ** ! 1308: ** The list of valid relations are then scanned. For each ! 1309: ** relation listed, a series of steps occurs: ! 1310: ** ! 1311: ** (1) The relation is checked for existance. If it does not ! 1312: ** exist, it is created, and we return to the beginning of the ! 1313: ** loop. Notice that we don't have to change modes in this ! 1314: ** case, since it already has been done. ! 1315: ** ! 1316: ** (2) If the relation does exist, we check to see that it ! 1317: ** is a system catalog. If it is not, we have an error, since ! 1318: ** this is a user relation which just happenned to have the ! 1319: ** same name. We inform the user and give up. ! 1320: ** ! 1321: ** (3) If the relation exists, is a system catalog, and all ! 1322: ** that, then we check the changes we need to make in the ! 1323: ** bits. If no change need be made, we continue the loop; ! 1324: ** otherwise, we change the bits and replace the tuple in ! 1325: ** the relation relation. ! 1326: ** ! 1327: ** (4) If the relation being updated was the "relation" or ! 1328: ** "attribute" relation, we change the Admin struct accordingly. ! 1329: ** ! 1330: ** Notice that the result of all this is that all relations ! 1331: ** which might ever be used exist and have the correct status. ! 1332: ** ! 1333: ** Notice that it is fatal for either the attribute or relation ! 1334: ** relations to not exist, since the file is created at the ! 1335: ** same time that relation descriptors are filled in. This ! 1336: ** should not be a problem, since this is only called on an ! 1337: ** existing database. ! 1338: ** ! 1339: ** As a final note, we open the attribute relation cache not ! 1340: ** because we use it, but because we want to do a closer ! 1341: ** in main() to insure that the tupcount is updated in all ! 1342: ** cases. ! 1343: ** ! 1344: ** Parameters: ! 1345: ** none ! 1346: ** ! 1347: ** Returns: ! 1348: ** none ! 1349: ** ! 1350: ** Side Effects: ! 1351: ** The database is brought up to date, as described ! 1352: ** above. ! 1353: ** Tuples may be added or changed in system catalogs. ! 1354: ** Files may be created. ! 1355: ** ! 1356: ** Called By: ! 1357: ** main ! 1358: ** ! 1359: ** Trace Flags: ! 1360: ** 40 ! 1361: */ ! 1362: ! 1363: changedb() ! 1364: { ! 1365: register RELDES *r; ! 1366: struct relation relk, relt; ! 1367: TID tid; ! 1368: register int i; ! 1369: ! 1370: # ifdef xSTR1 ! 1371: if (tTf(40, 0)) ! 1372: printf(">>> changedb: Dbson=%o, Dbsoff=%o\n", Dbson, Dbsoff); ! 1373: # endif ! 1374: ! 1375: /* check to see we aren't doing anything illegal */ ! 1376: if (flagval('q') < 0) ! 1377: { ! 1378: syserr(0, "I'm sorry, it is not possible to turn query modification off"); ! 1379: } ! 1380: ! 1381: /* update the database status field */ ! 1382: Admin.adhdr.adflags = (Admin.adhdr.adflags | Dbson) & ~Dbsoff; ! 1383: ! 1384: /* open the system catalog caches */ ! 1385: opencatalog("relation", 2); ! 1386: opencatalog("attribute", 0); ! 1387: ! 1388: /* scan the relation list:- Rellist */ ! 1389: for (r = Rellist; r->parmv[1].pv_type != PV_EOF; r++) ! 1390: { ! 1391: /* see if this relation exists */ ! 1392: clearkeys(&Reldes); ! 1393: setkey(&Reldes, &relk, r->parmv[1].pv_val.pv_str, RELID); ! 1394: i = getequal(&Reldes, &relk, &relt, &tid); ! 1395: ! 1396: if (i < 0) ! 1397: syserr("changedb: getequal"); ! 1398: ! 1399: if (i > 0) ! 1400: { ! 1401: /* doesn't exist, create it */ ! 1402: printf("Creating relation %s\n", r->parmv[1].pv_val.pv_str); ! 1403: makefile(r); ! 1404: makereln(r); ! 1405: } ! 1406: else ! 1407: { ! 1408: /* exists -- check to make sure it is the right one */ ! 1409: if ((relt.relstat & S_CATALOG) == 0) ! 1410: { ! 1411: /* exists as a user reln -- tough luck buster */ ! 1412: printf("Relation %s already exists -- I cannot bring this database\n", r->parmv[1].pv_val.pv_str); ! 1413: printf(" up to date. Sorry.\n"); ! 1414: exit(3); ! 1415: } ! 1416: ! 1417: /* it exists and is the right one -- update status */ ! 1418: if (r->bitson == 0 && r->bitsoff == 0) ! 1419: continue; ! 1420: ! 1421: /* actual work need be done */ ! 1422: relt.relstat = (relt.relstat | r->bitson) & ~r->bitsoff; ! 1423: ! 1424: /* replace tuple in relation relation */ ! 1425: i = replace(&Reldes, &tid, &relt, FALSE); ! 1426: if (i != 0) ! 1427: syserr("changedb: replace %d", i); ! 1428: ! 1429: /* update Admin struct if "relation" or "attribute" */ ! 1430: if (sequal(r->parmv[1].pv_val.pv_str, "relation")) ! 1431: Admin.adreld.reldum.relstat = relt.relstat; ! 1432: else if (sequal(r->parmv[1].pv_val.pv_str, "attribute")) ! 1433: Admin.adattd.reldum.relstat = relt.relstat; ! 1434: } ! 1435: } ! 1436: } ! 1437: /* ! 1438: ** READADMIN -- read the admin file into the 'Admin' cache ! 1439: ** ! 1440: ** This routine opens and reads the 'Admin' cache from the ! 1441: ** 'admin' file in the current directory. ! 1442: ** ! 1443: ** This version of the routine is modified for creatdb -- ! 1444: ** the '-e' flag is checked, and nothing is performed ! 1445: ** unless it is set. ! 1446: ** ! 1447: ** If not set, the 'relation' and 'attribute' relations ! 1448: ** are opened, and the descriptors for them in the Admin ! 1449: ** struct are filled in with their file descriptors. ! 1450: ** ! 1451: ** Parameters: ! 1452: ** none ! 1453: ** ! 1454: ** Returns: ! 1455: ** none ! 1456: ** ! 1457: ** Side Effects: ! 1458: ** The 'Admin' struct is filled in. ! 1459: ** The 'relation...xx' and 'attribute...xx' files are ! 1460: ** opened. ! 1461: ** ! 1462: ** Called By: ! 1463: ** acc_init (accbuf.c) ! 1464: ** changedb ! 1465: ** ! 1466: ** Trace Flags: ! 1467: ** none ! 1468: */ ! 1469: ! 1470: readadmin() ! 1471: { ! 1472: register int i; ! 1473: char relname[MAXNAME + 4]; ! 1474: ! 1475: /* read the stuff from the admin file */ ! 1476: if (flagval('e')) ! 1477: { ! 1478: i = open("admin", 0); ! 1479: if (i < 0) ! 1480: syserr("readadmin: open admin %d", i); ! 1481: checkadmin(i); ! 1482: close(i); ! 1483: ! 1484: /* open the physical files for 'relation' and 'attribute' */ ! 1485: ingresname("relation", Admin.adhdr.adowner, relname); ! 1486: if ((Admin.adreld.relfp = open(relname, 2)) < 0) ! 1487: syserr("readadmin: open `%.14s'", relname); ! 1488: ingresname("attribute", Admin.adhdr.adowner, relname); ! 1489: if ((Admin.adattd.relfp = open(relname, 2)) < 0) ! 1490: syserr("readadmin: open `%.14s'", relname); ! 1491: Admin.adreld.relopn = (Admin.adreld.relfp + 1) * -5; ! 1492: Admin.adattd.relopn = (Admin.adattd.relfp + 1) * 5; ! 1493: } ! 1494: ! 1495: return (0); ! 1496: } ! 1497: ! 1498: ! 1499:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.