home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / source / support / creatdb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-18  |  32.4 KB  |  1,426 lines

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