From 7c1b854e0215f22431f05c07aa541496fb42eb61 Mon Sep 17 00:00:00 2001 From: Oliver Lehmann Date: Mon, 26 Jun 1989 17:44:19 +0000 Subject: [PATCH] ING_DB --- .../contrib/ingres/dbs/src/access/add_ovflo.c | 91 ++ WEGA/contrib/ingres/dbs/src/support/creatdb.c | 1383 +++++++++++++++++ 2 files changed, 1474 insertions(+) create mode 100644 WEGA/contrib/ingres/dbs/src/access/add_ovflo.c create mode 100644 WEGA/contrib/ingres/dbs/src/support/creatdb.c diff --git a/WEGA/contrib/ingres/dbs/src/access/add_ovflo.c b/WEGA/contrib/ingres/dbs/src/access/add_ovflo.c new file mode 100644 index 0000000..5e898c6 --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/access/add_ovflo.c @@ -0,0 +1,91 @@ +# include "gen.h" +# include "../h/dbs.h" +# include "../h/access.h" +# include "../h/aux.h" +# include "../h/lock.h" + +/* ADD_OVFLO -- Allocates an overflow page which will be */ +/* attached to current page. TID must be for current page. */ +/* TID will be updated to id of new overflow page. */ +AAadd_ovflo(d, tid) +register DESC *d; +struct tup_id *tid; +{ + register ACCBUF *b; + register int lk; + register int i; + long mpage; + long newpage; + struct tup_id tidx; + extern ACCBUF *AAchoose_buf(); + + /* save main page pointer so that it may be used when */ + /* setting up new overflow page. */ + mpage = AAcc_head->mainpg; + + if (lk = (AAcclock && (d->relopn < 0 ))) + { + if (AAsetcsl(AAcc_head->rel_tupid) < 0) + return (AMTA_ERR); + AAcclock = FALSE; + } + + /* Determine last page of the relation */ + AAlast_page(d, &tidx, AAcc_head); + AApluck_page(&tidx, &newpage); + newpage++; + + /* choose an available buffer as victim for setting up */ + /* overflow page. */ + if (!(b = AAchoose_buf(d, newpage))) + { + if (lk) + { + AAcclock = TRUE; + AAunlcs(AAcc_head->rel_tupid); + } + return (-1); + } + + /* setup overflow page */ + b->mainpg = mpage; + b->ovflopg = 0; + b->thispage = newpage; + b->linetab[LINETAB(0)] = b->firstup - (char *) b; + b->nxtlino = 0; + b->bufstatus |= BUF_DIRTY; + if (AApageflush(b)) + return (-2); + + /* now that overflow page has successfully been written, */ + /* get the old current page back and link the new overflow page */ + /* to it. */ + /* If the relation is a heap then don't leave the old main */ + /* page around in the buffers. This is done on the belief */ + /* that it will never be accessed again. */ + if (AAgetpage(d, tid)) + return (-3); + + AAcc_head->ovflopg = newpage; + AAcc_head->bufstatus |= BUF_DIRTY; + i = AApageflush(AAcc_head); + if (lk) + { + AAcclock = TRUE; + AAunlcs(AAcc_head->rel_tupid); + } + if (i) + return (-4); + + if (abs(ctoi(d->reldum.relspec)) == M_HEAP) + AAresetacc(AAcc_head); /* no error is possible */ + + /* now bring the overflow page back and make it current. */ + /* if the overflow page is still in AM cache, then this will not */ + /* cause any disk activity. */ + AAstuff_page(tid, &newpage); + if (AAgetpage(d, tid)) + return (-5); + + return (0); +} diff --git a/WEGA/contrib/ingres/dbs/src/support/creatdb.c b/WEGA/contrib/ingres/dbs/src/support/creatdb.c new file mode 100644 index 0000000..53089d5 --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/support/creatdb.c @@ -0,0 +1,1383 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/aux.h" +# include "../h/access.h" +# include "../h/pipes.h" +# include "../h/symbol.h" +# include "../h/lock.h" +# include "../h/bs.h" + +# ifdef P8000 +ret_buf AAjmp_buf; +# else +jmp_buf AAjmp_buf; +# endif + +# ifdef ESER +# define getw gethw + +# ifdef ESER_PSU +union hword +{ + char hw_char[2]; + short hw_short; +}; + +gethw(fp) +FILE *fp; +{ + union hword hw; + + hw.hw_char[0] = getc(fp); + hw.hw_char[1] = getc(fp); + return (hw.hw_short); +} +# endif +# endif + +/* +** CREATDB -- create database (or modify database status) +** +** This program creates a new database. It takes the name of +** the new database (syntax defined below) and a series of +** flags (also defined below). +** +** In order to perform this command, you must be enabled by +** having the U_CREATDB bit set in the user status word +** of the AA_USERS. +** +** The -m flag specifies that the directory for the database +** already exists. It stands for "mounted-file-system", +** because this is presumably when you might use this feature. +** The directory must be empty. +** +** The -e flag specifies that the database already exists. +** It must be in all ways a valid database. This mode allows +** you to turn flags on and off, as controlled by the other +** flags. +** +** Usage: +** creatdb [flags] databasename +** +** Positional Parameters: +** databasename -- the name of the database to create. +** It must conform to all the usual rules +** about names. Notice that this is more +** restrictive than BS usually is: names +** must begin with an alpha, and must be +** composed of alphanumerics. It may be +** at most MAXNAME characters long. Underscore +** counts as an alphabetic. +** +** Flags: +** -m +** This is a mounted filesystem. Actually, +** this just means that the directory in which +** the database is to reside already exists. +** It must be empty. +** -e +** This database exists. When the -e flag is +** specified, the database is brought up to date, +** rather than created. Things which may be +** changed with the -e flag is anything that +** affects the database status or the relation +** status bits. +** -uXX +** Run as user XX (usercode or login name). This +** flag may only be used by the DBS superuser. +** Normally, the database administrator for the +** new database is the user who performs the +** command, but the -u flag allows DBS to +** give the database to someone else. Thus, it +** is possible for someone to be a DBA without +** having the U_CREATDB bit set. +** -Fpathname +** Use the named file as the database template. +** This is, of course, for debugging use only. +** +-c +** Turn concurrency control on/off. The default +** for a new database depends on the DBTMPLTFILE, +** but as of this writing it defaults on. +** +-q +** Turn query modification on/off. +** +-l +** Turn protection violation logging on/off. +** +** Files: +** USE_CREATDB -- to print a "usage: ..." message. +** DBTMPLTFILE +** This file drives the entire program. The +** syntax of this file is defined below in +** readdbtemp(). Briefly, it tells the database +** status, the relations in an 'empty' database, +** and the status and format of those relations. +** .../data/base +** This directory is the directory in which all +** databases eventually reside. Each database is +** a subdirectory of this directory. +** +** Return Codes: +** zero -- success +** else -- failure. +** +** Defined Constants: +** MAXRELNS +** This defines the maximum number of relations +** which may be declared in the DBTMPLTFILE. +** MAXDBTEMP +** The maximum size of the DBTMPLTFILE. This +** determines the maximum number of characters +** which may be in the file. +** +** Requires: +** Much. Notably, be careful about changes to any +** access methods, especially automatic references to +** to the AA_ADMIN file or AA_REL relation. +*/ + +# define MAXRELNS 20 +# define MAXDBTEMP 2000 + +/* AA_REL & AA_ATT reln descriptors used in access methods */ +extern DESC Reldes; +extern DESC Attdes; + +extern int AAdbstat; /* user status, set by initucode */ +extern char *AAdbpath; +extern char *AAztack(); + +int Dbstat; /* database status */ +# ifdef VPGSIZE +int AApgsize = PGSIZE; +int AAmaxtup = MAXTUP; +int AAltsize = 0; +# endif +int Dbson; +int Dbsoff; /* same: bits turned on, bits turned off */ +char Delim; +char DBTMPLTFILE[] = "/sys/etc/dbtmplt"; +char MKDIR[] = "mkdir"; +char SYSNAME[] = "_SYS"; +int s_SYSNAME = sizeof SYSNAME - 1; +char USE_CREATDB[] = "/sys/etc/creatdb_use"; + +struct reldes +{ + int bitson; + int bitsoff; + char *parmv[MAXPARMS]; +}; +struct reldes Rellist[MAXRELNS]; + + +main(argc, argv) +int argc; +char *argv[]; +{ + register int i; + register char *p; + register short *flagv; + register char *dbtmpfile; + register char *database; + register int faterr; + register int exists; + char **av; + int admin; + int code; + struct stat stbuf; + char adminbuf[BUFSIZ]; + extern int errno; + extern struct admin AAdmin; + extern char AAversion[]; + extern char *AAproc_name; + extern char *Parmvect[]; + extern char *Flagvect[]; + extern short *flaglkup(); +# ifdef NON_V7_FS + extern char *read_dir(); + register char *direc; +# endif + + AAproc_name = "CREATDB"; + +# ifdef xSTR1 + AAtTrace(&argc, argv, 'X'); +# endif + + /* + ** The concurrency device will be opened for writing. + ** If the lock device isn't installed, then AAlockdes = -1 + ** and no locking will (or can) occure. + */ + AAlockdes = open(AA_DBS_LOCK, 1); + errno = 0; /* clear in case AA_DBS_LOCK isn't available */ + AALOCKREQ.l_db = 0L; + AALOCKREQ.l_pid = getpid(); + if (AAsetcsl(NO_REL) < 0) + AAsyserr(0, "Zeitweilig koennen keine Datenbanken erzeugt werden"); + exists = 0; + i = initucode(argc, argv, TRUE, (char *) 0, -1); + database = Parmvect[0]; + switch (i) + { + case 0: + case 5: + exists = 1; + break; + + case 6: + exists = -1; + + case 1: + break; + + case 2: + AAsyserr(0, "Sie duerfen auf die Datenbank '%s' nicht zugreifen", database); + + case 3: + AAsyserr(0, "Sie sind kein eingetragener DBS-Nutzer"); + + case 4: + printf("Sie haben keinen Datenbanknamen angegeben\n"); +usage: + /* cat USE_CREATDB */ + AAcat(AAztack(AApath, USE_CREATDB)); +term: + AAunlall(); + fflush(stdout); + exit(-1); + + default: + AAsyserr(22200, AAproc_name, i); + } + + faterr = 0; + dbtmpfile = (char *) 0; + for (av = Flagvect; p = *av; av++) + { + if (p[0] != '-' && p[0] != '+') + AAsyserr(21010, p); + switch (p[1]) + { + case 'F': /* DBTMPLTFILE */ + if (!p[2]) + goto badflag; + dbtmpfile = &p[2]; + break; + +# ifdef VPGSIZE + case '1': /* BLOCKSIZE */ + case '2': + case '4': + case '8': + i = p[1] - '0'; + if (p[2] || i > PGBLKS) + goto badflag; + AApgsize = BLKSIZ * i; + AAltsize = (PGSIZE - AApgsize) / sizeof (short); + break; +# endif + + case 'C': + p[1] = 'c'; + goto def; + + case 'E': + p[1] = 'e'; + goto def; + + case 'M': + p[1] = 'm'; + goto def; + + case 'Q': + p[1] = 'q'; + /* fall through */ + + default: +def: + if (flagv = flaglkup(p[1], p[0])) + { + *flagv = ((p[0] == '+')? 1: -1); + continue; + } +badflag: + printf("Unbekanntes Flag '%s'\n", p); + faterr++; + continue; + + } + if (p[0] == '+') + goto badflag; + } + + /* check for legality of database name */ + if (Parmvect[1]) + { + printf("Zu viele Argumente\n"); + goto usage; + } + if (!check(database)) + AAsyserr(0, "Unerlaubter Datenbankname '%s'", database); + + if (!(AAdbstat & U_CREATDB)) + AAsyserr(0, "Sie duerfen keine Datenbanken erzeugen"); + + /* end of input checking */ + if (faterr) + goto term; + + /* now see if it should have been there */ + if (flagval('m') || flagval('e')) + { +# ifdef xSTR3 + AAtTfp(1, 14, "AAdbpath = '%s'\n", AAdbpath); +# endif + if (flagval('e') && exists <= 0) + AAsyserr(0, "Die Datenbank '%s' existiert nicht", database); + + if (chdir(AAdbpath) < 0) + AAsyserr(0, "Es existiert kein directory fuer die Datenbank '%s'", database); + + if (!flagval('e')) + { + /* make certain that it is empty */ +# ifdef NON_V7_FS + open_dir("."); + while (direc = read_dir()) + { + /* throw out legitimate files */ + if (AAsequal(direc, ".") || AAsequal(direc, "..")) + continue; + AAsyserr(0, "directory '%s' ist nicht leer", database); + } + close_dir(); +# else + freopen(".", "r", stdin); + for (i = 0; i < 16; i++) + getw(stdin); + while ((i = getw(stdin)) != EOF) + { + if (i) + AAsyserr(0, "directory '%s' ist nicht leer", database); + for (i = 0; i < 7; i++) + getw(stdin); + } +# endif + } + else + { + /* check for correct owner */ + AAam_start(); + if (!AAbequal(AAusercode, AAdmin.adhdr.adowner, 2)) + AAsyserr(0, "Sie sind nicht der DBA der Datenbank '%s'", database); + } + } + else + { + if (exists) + AAsyserr(0, "Die Datenbank '%s' existiert bereits", database); + + /* create it */ + fflush(stdout); + if ((i = fork()) < 0) + AAsyserr(21013); + if (!i) + { + /* enter database directory */ + initdbpath((char *) 0, adminbuf, FALSE); + if (chdir(adminbuf) < 0) + AAsyserr(22201, AAproc_name, adminbuf); + + /* arrange for proper permissions */ + if (setuid(getuid())) + AAsyserr(21015); + if (setgid(getgid())) + AAsyserr(21016); + fflush(stdout); + execlp(MKDIR, MKDIR, database, 0); + AAsyserr(21017, MKDIR); + } + while (wait(&code) != -1) + continue; + + if (chdir(AAdbpath) < 0) + AAsyserr(22201, AAproc_name, AAdbpath); + + fflush(stdout); + if ((i = fork()) < 0) + AAsyserr(21019); + if (!i) + { + setuid(getuid()); + if (chmod(".", 0777)) + AAsyserr(21020); + exit(0); + } + + while (wait(&code) != -1) + continue; + if (ctou(code)) + { + fflush(stdout); + AAunlall(); + exit(code); + } + } + + /* reset 'errno', set from possibly bad chdir */ + errno = 0; + + /* Set up locking information. */ + AALOCKREQ.l_db = 0L; + AAunlcs(NO_REL); + stat(".", &stbuf); + AAbmove(&stbuf, &AALOCKREQ.l_db, sizeof (long)); + if (AAsetdbl(A_RTN, M_EXCL) < 0) + AAsyserr(0, "Datenbank zeitweilig nicht verfuegbar"); + + /* determine name of DBTMPLTFILE and open */ + if (!dbtmpfile) + { + AAsmove(AAversion, adminbuf); + for (i = 0; adminbuf[i]; i++) + if (adminbuf[i] == '/') + break; + adminbuf[i] = 0; + dbtmpfile = AAztack(AAztack(AApath, DBTMPLTFILE), adminbuf); + } + if (!freopen(dbtmpfile, "r", stdin)) + AAsyserr(21021); + + readdbtemp(); + + /* check for type -- update database status versus create */ + if (flagval('e')) + changedb(); + else + makedb(); + + /* close the cache descriptors */ +# ifdef xSTR3 + if (AAtTfp(50, 0, "Attdes.reltid = ")) + { + AAdumptid(&Attdes.reltid); + printf("Reldes.reltid = "); + AAdumptid(&Reldes.reltid); + } +# endif + + if (i = AArelclose(&Attdes)) + AAsyserr(21022, i); + + if (i = AArelclose(&Reldes)) + AAsyserr(21023, i); + + /* bring tupcount in AA_ADMIN file to date */ + AAbmove(&Reldes.reldum.reltups, &AAdmin.adreld.reldum.reltups, + sizeof Reldes.reldum.reltups); + AAbmove(&Attdes.reldum.reltups, &AAdmin.adattd.reldum.reltups, sizeof Attdes.reldum.reltups); + + /* clean up some of the fields to catch problems later */ + AAdmin.adreld.relfp = AAdmin.adattd.relfp = -1; + AAdmin.adreld.relopn = AAdmin.adattd.relopn = 0; + + if ((admin = creat(AA_ADMIN, FILEMODE)) < 0) + AAsyserr(21024); + if (write(admin, &AAdmin, sizeof AAdmin) != sizeof AAdmin) + AAsyserr(21025); + close(admin); + + /* exit successfully */ + AAunldb(); + fflush(stdout); + exit(0); +} + + +/* +** Rubout processing. +*/ +rubproc() +{ + AAunlall(); + fflush(stdout); + exit(-2); +} + + +/* +** READDBTEMP -- read the DBTMPLTFILE and build internal form +** +** This routine reads the DBTMPLTFILE (presumably openned as +** the standard input) and initializes the Dbstat (global database +** status word) and Rellist variables. +** +** Rellist is an array of argument vectors, exactly as passed to +** 'create'. +** +** The syntax of the DBTMPLTFILE is as follows: +** +** The first line is a single status word (syntax defined below) +** which is the database status. +** +** The rest of the file is sets of lines separated by blank lines. +** Each set of lines define one relation. Two blank lines in a +** row or an end-of-file define the end of the file. Each set +** of lines is broken down: +** +** The first line is in the following format: +** relname:status +** which defines the relation name and the relation status for +** this relation (syntax defined in 'getstat' below). Status +** may be omitted, in which case a default status is assumed. +** +** Second through n'th lines of each set define the attributes. +** They are of the form: +** attname format +** separated by a single tab. 'Format' is the same as on a +** 'create' statement in QL. +** +** Notice that we force the S_CATALOG bit to be on in any +** case. This is because the changedb() routine will fail +** if the -e flag is ever used on this database if any +** relation appears to be a user relation. +** +** Side Effects: +** Dbstat gets the database status. +** Rellist is created with a list of the relations, +** (as parameter vectors -- just as passed to +** create). The entry after the last entry +** has its pv[0] == (char *) 0. +*/ +readdbtemp() +{ + static char buf[MAXDBTEMP]; + register struct reldes *r; + register char **q; + register int i; + register char *p; + register int j; + register int defrstat; + int bitson; + int bitsoff; + + /* read database status */ + defrstat = S_CATALOG | S_NOUPDT /* | S_CONCUR */ | S_PROTALL; + bitson = bitsoff = 0; + Dbstat = getstat(A_DBCONCUR, &Dbson, &Dbsoff); + if (Delim == ':') + defrstat = getstat(defrstat, &bitson, &bitsoff); + if (Delim != '\n') + AAsyserr(21026, Delim); + + /* compute default relation status */ + + /* start reading relation info */ + p = buf; + for (r = Rellist; ; r++) + { + r->bitson = bitson; + r->bitsoff = bitsoff; + + q = r->parmv; + + /* get relation name */ + q[1] = p; + p += getname(p) + 1; + + /* test for end of DBTMPLTFILE */ + if (!q[1][0]) + break; + + /* get relation status */ + i = getstat(defrstat, &r->bitson, &r->bitsoff); + i |= S_CATALOG; /* guarantee system catalog */ + *q++ = p; + *p++ = ((i >> 15) & 1) + '0'; + for (j = 12; j >= 0; j -= 3) + *p++ = ((i >> j) & 07) + '0'; + *p++ = 0; + q++; + if (Delim != '\n') + AAsyserr(21027, Delim); + + /* read attribute names and formats */ + for ( ; ; ) + { + /* get attribute name */ + *q++ = p; + p += getname(p) + 1; + if (!q[-1][0]) + break; + if (Delim != '\t') + AAsyserr(21028, Delim); + + /* get attribute type */ + *q++ = p; + p += getname(p) + 1; + if (Delim != '\n') + AAsyserr(21029, Delim); + } + + /* insert end of argv signal */ + *--q = (char *) 0; + + /* ad-hoc overflow test */ + if (p >= &buf[MAXDBTEMP]) + AAsyserr(21030); + } + /* mark the end of list */ + q[1] = (char *) 0; +} + + +/* +** GETSTAT -- Get status word +** +** A status word is read from the standard input (presumably +** DBTMPLTFILE). The string read is interpreted as an octal +** number. The syntax is: +** N{+c+N[~N]} +** where N is a number, + is a plus or a minus sign, and c is +** a flag. '+c+N1[~N2]' groups are interpreted as follows: +** If flag 'c' is set (assuming the preceeding character is a +, +** clear if it is a -), then set (clear) bits N1. If tilde N2 +** is present, then if flag 'c' is unset (called as '-c' ('+c')) +** clear (set) bits N2; if ~N2 is not present, clear (set) +** bits N1. +** +** For example, an entry might be (but probably isn't): +** 1-c-1+q+6~2 +** having the following meaning: +** +** 1. Default to the 1 bit set. +** +** 2. If the -c flag is specified, clear the '1' bit. If the +** +c flag is specified, set the '1' bit. If it is unspecified, +** leave the '1' bit alone. +** +** 3. If the +q flag is specified, set the '2' bit and the '4' +** bit. If the -q flag is specified, clear the '2' bit (but leave +** the '4' bit alone). If the +-q flag is unspecified, leave +** those bits alone. +** +** Thus, a database with this entry is initially created with +** the 1 bit on. The '4' bit is a history, which says if the +** 'q' flag has ever been set, while the '2' bit tells if it is +** currently set. +** +** Parameters: +** def -- the default to return if there is no number +** there at all. +** bitson -- a pointer to a word to contain all the +** bits to be turned on -- used for the -e flag. +** bitsoff -- same, for bits turned off. +** +** Returns: +** The value of the status word. +** There are no error returns. +*/ +getstat(def, bitson, bitsoff) +int def; +int *bitson; +int *bitsoff; +{ + register int c; + register int st; + register int i; + register int setbits; + register int clrbits; + register int ctlch; + + /* reset bits being turned on and off */ + *bitson = *bitsoff = 0; + + /* check to see if a base status word is defined */ + if (Delim == '\n' || (Delim = c = getchar()) < '0' || c > '7') + st = def; /* no, use default */ + else + { + /* read base status field */ + ungetc(c, stdin); + st = roctal(); + } + + /* scan '+c+N' entries */ + for ( ; ; ) + { + /* check for a flag present */ + c = Delim; + if (c == '\n' || c == ':') + return (st); + if (c != '+' && c != '-') + { +badfmt: + AAsyserr(21031, c); + } + + /* we have some flag -- get it's value */ + i = flagval(getchar()); + + /* save sign char on flag */ + ctlch = c; + + /* get sign on associated number and the number */ + if ((c = getchar()) != '+' && c != '-') + goto badfmt; + setbits = roctal(); + + /* test whether action on -X same as on +X */ + if (Delim == '~') + clrbits = roctal(); /* they have different bits (see above) */ + else + clrbits = setbits; /* on 'creatdb -e -X', use opposite bits of +X */ + + /* test for any effect at all */ + if (!i) + continue; + + /* test whether we should process the '+N' */ + if ((ctlch == '-')? (i < 0): (i > 0)) + i = setbits; + else + { + i = clrbits; + + /* switch sense of bit action */ + c = (c == '+')? '-': '+'; + } + + if (c == '+') + { + st |= i; + *bitson |= i; + } + else + { + st &= ~i; + *bitsoff |= i; + } + } +} + + +/* +** ROCTAL -- Read an octal number from standard input. +** +** This routine just reads a single octal number from the standard +** input and returns its value. It will only read up to a non- +** octal digit. It will also skip initial and trailing blanks. +** 'Delim' is set to the next character in the input stream. +** +** Returns: +** value of octal number in the input stream. +** +** Side Effects: +** 'Delim' is set to the delimiter which terminated the +** number. +*/ +roctal() +{ + register int c; + register int val; + + val = 0; + + /* skip initial blanks */ + while ((c = getchar()) == ' ') + continue; + + /* get numeric value */ + while (c >= '0' && c <= '7') + { + val = (val << 3) | (c - '0'); + c = getchar(); + } + + /* skip trailing blanks */ + while (c == ' ') + c = getchar(); + + /* set Delim and return numeric value */ + Delim = c; + return (val); +} + + +/* +** GETNAME -- get name from standard input +** +** This function reads a name from the standard input. A +** name is defined as a string of letters and digits. +** +** The character which caused the scan to terminate is stored +** into 'Delim'. +** +** Parameters: +** ptr -- a pointer to the buffer in which to dump the +** name. +** +** Returns: +** The length of the string. +*/ +getname(p) +register char *p; +{ + register int len; + register int c; + + for (len = 0; (c = getchar()) != EOF; len++) + { + /* check for end of name */ + if ((c < '0' || c > '9') && (c < 'a' || c > 'z')) + break; + + /* store character into buffer */ + *p++ = c; + } + + /* null-terminate the string */ + *p = '\0'; + + /* store the delimiting character and return length of string */ + Delim = c; + return (len); +} + + +/* +** MAKEDB -- make a database from scratch +** +** This is the code to make a database if the -e flag is off. +** +** The first step is to make a copy of the AA_ADMIN file +** in the internal 'AAdmin' struct. This is the code which +** subsequently gets used by AArelopen and opencatalog. Notice +** that the AA_ADMIN file is not written out; this happens after +** makedb returns. +** +** Next, the physical files are created with one initial (empty) +** page. This has to happen before the 'create' call so +** that it will be possible to flush AA_REL and AA_ATT +** relation pages during the creates of the AA_REL and +** AA_ATT relations. Other relations don't need this, +** but it is more convenient to be symmetric. +** +** The next step is to create the relations. Of course, all +** this really is is inserting stuff into the system catalogs. +** +** When we are all done we open the AA_REL relation for the +** admin cache (which of course should exist now). Thus, +** the AArelclose's in main (which must be around to update the +** tuple count) will work right. +** +** Side Effects: +** A database is created!! +** Several files will be created in the current directory, +** one for each relation mentioned in the +** DBTMPLTFILE. +** The 'AAdmin' struct will be filled in. +*/ +makedb() +{ + register struct reldes *r; +# ifdef VPGSIZE + register int i; +# endif + +# ifdef xSTR3 + AAtTfp(51, 0, "MAKEDB: AAusercode = %s (0%o)\n", AAusercode, AAusercode); +# endif + + /* create the physical files */ + for (r = Rellist; r->parmv[1]; r++) + makefile(r); + + /* initialize the AA_ADMIN file internal cache */ + AAbmove(AAusercode, AAdmin.adhdr.adowner, 2); +# ifdef VPGSIZE + i = AApgsize / BLKSIZ - 1; + Dbstat |= i << 8; +# endif + AAdmin.adhdr.adflags = Dbstat; + makeadmin(&AAdmin.adreld, Rellist[0].parmv); + makeadmin(&AAdmin.adattd, Rellist[1].parmv); + + /* done with admin initialization */ + + /* initialize relations */ + for (r = Rellist; r->parmv[1]; r++) + makereln(r); +} + + +/* +** MAKEADMIN -- manually initialize descriptor for AA_ADMIN file +** +** The relation descriptor pointed to by 'pv' is turned into +** a descriptor, returned in 'd'. Presumably, this descriptor +** is later written out to the AA_ADMIN file. +** +** Notice that the 'reltid' field is filled in sequentially. +** This means that the relations put into the AA_ADMIN file +** must be created in the same order that they are 'made' +** (by this routine), that the format of tid's must not +** change, and that there can not be over one page worth of +** relations in the AA_ADMIN file. Our current system currently +** handles this easily. +** +** Parameters: +** d -- the descriptor to get the result. +** pv -- a parm vector in 'create' format, which drives +** this routine. +*/ +makeadmin(des, p) +register DESC *des; +register char **p; +{ + static int tid; + register int i; + register int j; + short len; + char fname[MAXNAME + 3]; + +# ifdef xSTR2 + AAtTfp(10, -1, "creating %s in admin\n", p[1]); +# endif + + i = AA_oatoi(*p++); + AAdbname(*p++, AAusercode, fname); + AAbmove(fname, des->reldum.relid, MAXNAME + 2); + des->reldum.relstat = i; + des->reldum.relatts = 0; + des->reldum.relwid = 0; + des->reldum.relspec = M_HEAP; + des->reltid = tid++; + if ((des->relfp = open(fname, 2)) < 0) + AAsyserr(21032, fname); + des->relopn = RELWOPEN(des->relfp); + + /* initialize domain info */ + for ( ; *p++; p++) + { + if ((i = typeconv(p[0][0])) < 0) + AAsyserr(21033, p[0][0]); + j = ++(des->reldum.relatts); + des->relfrmt[j] = i; + if (AA_atoi(&p[0][1], &len)) + AAsyserr(21034, p[0]); + des->relfrml[j] = len; + des->reloff[j] = des->reldum.relwid; + des->reldum.relwid += len; + } +} + + +/* +** MAKEFILE -- make an 'empty' file for a relation +** +** This routine creates a file with a single (empty) page +** on it -- it is part of the 'create' code, essentially. +** +** Parameters: +** rr -- a pointer to the 'reldes' structure for this +** relation (file). +** +** Side Effects: +** A file with one page is created. +*/ +makefile(r) +register struct reldes *r; +{ + DESC d; + long npages; + + AAdbname(r->parmv[1], AAusercode, d.reldum.relid); + +# ifdef xSTR1 + AAtTfp(12, 0, "creat %s\n", d.reldum.relid); +# endif + + if ((d.relfp = creat(d.reldum.relid, FILEMODE)) < 0) + AAsyserr(21035, d.reldum.relid); + + npages = 1; + if (formatpg(&d, npages)) + AAsyserr(21036); + + close(d.relfp); +} + + +/* +** MAKERELN -- make a relation +** +** This is the second half of the create, started by 'makefile'. +** +** This routine just sets up argument vectors and calls create, +** which does the real work. +** +** Parameters: +** rr -- a pointer to the Rellist entry for the relation +** to be created. +** +** Side Effects: +** Information will be inserted into the AA_REL and +** AA_ATT relations. +*/ +makereln(r) +register struct reldes *r; +{ + register int pc; + register char **pv; + register int i; + + for (pc = 0, pv = r->parmv; *pv; pv++) + pc++; + pv = r->parmv; + +# ifdef xSTR1 + if (AAtTf(1, 0)) + AAprargs(pc, pv); +# endif + + if (i = create(pc, pv)) + AAsyserr(21037, i); +} + + +/* +** CHECK -- check database name syntax +** +** The name of a database is checked for validity. A valid +** database name is not more than 14 characters long, begins +** with an alphabetic character, and contains only alpha- +** numerics. Underscore is considered numeric. +** +** Parameters: +** st -- the string to check. +** +** Returns: +** TRUE -- ok. +** FALSE -- failure. +*/ +check(p) +register char *p; +{ + register int c; + + /* check string length */ + if (AAlength(p) > MAXNAME) + return (FALSE); + + /* check the first character of the string for alphabetic */ + if (!(((c = *p++) >= 'a' +# ifdef EBCDIC + && c <= 'i') || (c >= 'j' + && c <= 'r') || (c >= 's' +# endif + && c <= 'z'))) + return (FALSE); + + /* check the rest for alphanumeric */ + while (c = *p++) + { + if (c == '_' || (c >= '0' && c <= '9') || (c >= 'a' +# ifdef EBCDIC + && c <= 'i') || (c >= 'j' + && c <= 'r') || (c >= 's' +# endif + && c <= 'z')) + continue; + return (FALSE); + } + return (TRUE); +} + + +/* +** FLAGLKUP -- look up user flag +** +** This routine helps support a variety of user flags. The +** routine takes a given user flag and looks it up (via a +** very crude linear search) in the 'Flags' vector, and +** returns a pointer to the value. +** +** The 'flag' struct defines the flags. The 'flagname' field +** is the character which is the flag id, for example, 'c' +** in the flag '-c'. The 'flagtype' field defines how the +** flag may appear; if negative, only '-c' may appear, if +** positive, only '+c' may appear; if zero, either form may +** appear. Finally, the 'flagval' field is the value of the +** flag -- it may default any way the user wishes. +** +** Parameters: +** flagname -- the name (as defined above) of the +** flag to be looked up. +** plusminus -- a character, '+' means the '+x' form +** was issued, '-' means the '-x' form was +** issued, something else means *don't care*. +** If an illegal form was issued (that is, +** that does not match the 'flagtype' field +** in the structure), the "not found" return +** is taken. +** +** Returns: +** (int *) 0 -- flag not found, or was incorrect type, +** as when the '+x' form is specified in the +** parameters, but the 'Flags' struct says +** that only a '-x' form may appear. +** else -- pointer to the 'flagval' field of the correct +** field in the 'Flags' vector. +*/ +struct flag +{ + char flagname; /* the name of the flag */ + char flagtype; /* -1: -x form; +1: +x form; 0: both */ + short flagval; /* user-defined value of the flag */ +}; + +struct flag Flags[] = +{ + 'q', 0, 0, + 'l', 0, 0, + 'c', 0, 0, + 'e', -1, 0, + 'm', -1, 0, + 0 +}; + +short *flaglkup(f, pm) +register int f; +register int pm; +{ + register struct flag *p; + + /* look up flag in vector */ + for (p = Flags; p->flagname != f; p++) + if (!p->flagname) + return ((short *) 0); + + /* found in list -- check type */ + if ((pm == '+' && ctoi(p->flagtype) < 0) || (pm == '-' && ctoi(p->flagtype) > 0)) + return ((short *) 0); + + /* type is OK -- return pointer to value */ + return (&p->flagval); +} + + +/* +** FLAGVAL -- return value of a flag +** +** Similar to 'flaglkup', except that the value is returned +** instead of the address, and no error return can occur. +** +** Parameters: +** f -- the flag to look up (see flaglkup). +** +** Returns: +** The value of flag 'f'. +*/ +flagval(f) +register int f; +{ + register short *p; + + /* get value of flag */ + p = flaglkup(f, 0); + + /* test for error return, AAsyserr if so */ + if (!p) + AAsyserr(21038, f); + + /* return value */ + return (*p); +} + + +/* +** CHANGEDB -- change status bits for database/relations +** +** In this function we change the status bits for use with the +** -e flag. +** +** This module always uses the differential status +** change information, so that existing bits are not touched. +** +** We check to see that invalid updates, such as turning off +** query modification when it is already on, can not occur. +** This is because of potential AAsyserr's when the system is +** later run, e.g., because of views without instantiations. +** +** In the second step, the database status is updated. This is +** done strictly in-core, and will be updated in the database +** after we return. +** +** The list of valid relations are then scanned. For each +** relation listed, a series of steps occurs: +** +** (1) The relation is checked for existance. If it does not +** exist, it is created, and we return to the beginning of the +** loop. Notice that we don't have to change modes in this +** case, since it already has been done. +** +** (2) If the relation does exist, we check to see that it +** is a system catalog. If it is not, we have an error, since +** this is a user relation which just happenned to have the +** same name. We inform the user and give up. +** +** (3) If the relation exists, is a system catalog, and all +** that, then we check the changes we need to make in the +** bits. If no change need be made, we continue the loop; +** otherwise, we change the bits and replace the tuple in +** the AA_REL relation. +** +** (4) If the relation being updated was the AA_REL or +** AA_ATT relation, we change the AAdmin struct accordingly. +** +** Notice that the result of all this is that all relations +** which might ever be used exist and have the correct status. +** +** Notice that it is fatal for either the AA_ATT or AA_REL +** relations to not exist, since the file is created at the +** same time that relation descriptors are filled in. This +** should not be a problem, since this is only called on an +** existing database. +** +** As a final note, we open the AA_ATT relation cache not +** because we use it, but because we want to do a AArelclose +** in main() to insure that the tupcount is updated in all +** cases. +** +** Side Effects: +** The database is brought up to date, as described +** above. +** Tuples may be added or changed in system catalogs. +** Files may be created. +*/ +changedb() +{ + register struct reldes *r; + register int i; + struct tup_id tid; + struct relation relk; + struct relation relt; + +# ifdef xSTR1 + AAtTfp(40, 0, "CHANGEDB: Dbson=0%o, Dbsoff=0%o\n", Dbson, Dbsoff); +# endif + + /* check to see we aren't doing anything illegal */ + if (flagval('q') < 0) + AAsyserr(0, " Flag '-q' ist nicht erlaubt"); + + /* update the database status field */ + AAdmin.adhdr.adflags = (AAdmin.adhdr.adflags | Dbson) & ~Dbsoff; + + /* open the system catalog caches */ + opencatalog(AA_REL, 2); + opencatalog(AA_ATT, 0); + + /* scan the relation list:- Rellist */ + for (r = Rellist; r->parmv[1]; r++) + { + /* see if this relation exists */ + AAam_clearkeys(&Reldes); + AAam_setkey(&Reldes, &relk, r->parmv[1], RELID); + if ((i = AAgetequal(&Reldes, &relk, &relt, &tid)) < 0) + AAsyserr(21040); + + if (i > 0) + { + /* doesn't exist, create it */ + printf("Erzeuge Katalog '%s'\n", r->parmv[1]); + makefile(r); + makereln(r); + } + else + { + /* exists -- check to make sure it is the right one */ + if (!(relt.relstat & S_CATALOG)) + { + /* exists as a user reln -- tough luck buster */ + AAsyserr(0, "Katalog '%s' existiert bereits als Nutzerrelation", r->parmv[1]); + } + + /* it exists and is the right one -- update status */ + if (!r->bitson && !r->bitsoff) + continue; + + /* actual work need be done */ + relt.relstat = (relt.relstat | r->bitson) & ~r->bitsoff; + + /* replace tuple in AA_REL relation */ + if (i = AAam_replace(&Reldes, &tid, &relt, FALSE)) + AAsyserr(21041, i); + + /* update AAdmin struct if AA_REL or AA_ATT */ + if (AAsequal(r->parmv[1], AA_REL)) + AAdmin.adreld.reldum.relstat = relt.relstat; + else if (AAsequal(r->parmv[1], AA_ATT)) + AAdmin.adattd.reldum.relstat = relt.relstat; + } + } +} + + +/* +** READADMIN -- read the AA_ADMIN file into the 'AAdmin' cache +** +** This routine opens and reads the 'AAdmin' cache from the +** AA_ADMIN file in the current directory. +** +** This version of the routine is modified for creatdb -- +** the '-e' flag is checked, and nothing is performed +** unless it is set. +** +** If not set, the AA_REL and AA_ATT relations +** are opened, and the descriptors for them in the AAdmin +** struct are filled in with their file descriptors. +** +** Side Effects: +** The 'AAdmin' struct is filled in. +** The AA_REL and AA_ATT files are +** opened. +*/ +AAreadadmin() +{ + register int i; + char relname[MAXNAME + 4]; + + /* read the stuff from the AA_ADMIN file */ + if (flagval('e')) + { + if ((i = open(AA_ADMIN, 0)) < 0) + AAsyserr(21042, i); + if (read(i, &AAdmin, sizeof AAdmin) != sizeof AAdmin) + AAsyserr(21043); + close(i); + + /* open the physical files for AA_REL and AA_ATT */ + AAdbname(AAdmin.adreld.reldum.relid, AAdmin.adreld.reldum.relowner, relname); + if ((AAdmin.adreld.relfp = open(relname, 2)) < 0) + AAsyserr(21044, AAdmin.adreld.relfp); + AAdbname(AAdmin.adattd.reldum.relid, AAdmin.adattd.reldum.relowner, relname); + if ((AAdmin.adattd.relfp = open(relname, 2)) < 0) + AAsyserr(21045, AAdmin.adattd.relfp); + AAdmin.adreld.relopn = RELWOPEN(AAdmin.adreld.relfp); + AAdmin.adattd.relopn = RELROPEN(AAdmin.adattd.relfp); + /* get the page size of data base */ + if ((i = (AAdmin.adhdr.adflags >> 8) + 1) > PGBLKS) + AAsyserr(10010, i, PGBLKS); +# ifdef VPGSIZE + AApgsize = BLKSIZ * i; + /* get the linetab size, the difference */ + AAltsize = (PGSIZE - AApgsize) / sizeof (short); +# endif + } + + return (0); +}