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