Annotation of 42BSD/ingres/source/support/creatdb.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.