# 2.11BSD#431 - /usr/ingres/source/support/creatdb.c

##### Functions

    changedb          X
    check             X
    flaglkup          X
    flagval           X
    getname           X
    getstat           X
    main              X
    makeadmin         X
    makedb            X
    makefile          X
    makereln          X
    readadmin         X
    readdbtemp        X
    roctal            X
    rubproc           X

##### Variables

    Dbsoff            X
    Dbson             X
    Dbstat            X
    Delim             X
    Flags             X
    Rellist           X

##### Macros

    MAXDBTEMP         X
    MAXRELNS          X

##### struct's

    flag              X
    reldes            X

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

#### Defined functions

changedb defined in line 1604; used 1 times

- in line 475

check defined in line 1314; used 1 times

- in line 347

flaglkup defined in line 1418; used 3 times

- in line 263, 322, 1487

flagval defined in line 1478; used 10 times

- in line 364(2), 370, 382, 474, 789, 1405, 1443, 1617, 1739

getname defined in line 940; used 3 times

- in line 632, 655, 663

getstat defined in line 747; used 3 times

- in line 613-615(2), 639

main defined in line 241; never used
makeadmin defined in line 1110; used 2 times

- in line 1049-1050(2)

makedb defined in line 1028; used 1 times

- in line 477

makefile defined in line 1195; used 2 times

- in line 1043, 1644

makereln defined in line 1258; used 2 times

- in line 1057, 1645

readadmin defined in line 1733; never used
readdbtemp defined in line 599; used 1 times

- in line 471

roctal defined in line 878; used 3 times

- in line 772, 798, 804

rubproc defined in line 519; never used

#### Defined variables

Dbsoff defined in line 228; used 3 times

- in line 613, 1613, 1623

Dbson defined in line 228; used 3 times

- in line 613, 1613, 1623

Dbstat defined in line 227; used 2 times

- in line 613, 1048

Delim defined in line 236; used 15 times

- in line 614-617(3), 647-648(2), 658-665(4), 763(2), 779, 801, 901, 964

Flags defined in line 1408; used 1 times

- in line 1431

Rellist defined in line 235; used 6 times

- in line 623, 1041, 1049-1055(3), 1630

#### Defined struct's

flag defined in line 1401; used 4 times

- in line 1408(2), 1424(2)

reldes defined in line 229; used 16 times

- in line 235(2), 602(2), 1031(2), 1196-1198(4), 1259-1261(4), 1606(2)

#### Defined macros

MAXDBTEMP defined in line 220; used 2 times

- in line 601, 672

MAXRELNS defined in line 219; used 1 times

- in line 235

Last modified: 1995-02-12 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3387 |