]> granicus.if.org Git - postgresql/commitdiff
Extend CREATE DATABASE to allow selection of a template database to be
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Nov 2000 18:37:49 +0000 (18:37 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Nov 2000 18:37:49 +0000 (18:37 +0000)
cloned, rather than always cloning template1.  Modify initdb to generate
two identical databases rather than one, template0 and template1.
Connections to template0 are disallowed, so that it will always remain
in its virgin as-initdb'd state.  pg_dumpall now dumps databases with
restore commands that say CREATE DATABASE foo WITH TEMPLATE = template0.
This allows proper behavior when there is user-added data in template1.
initdb forced!

23 files changed:
doc/src/sgml/ref/create_database.sgml
src/backend/commands/dbcommands.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/postmaster/postmaster.c
src/backend/tcop/utility.c
src/backend/utils/init/postinit.c
src/backend/utils/mb/mbutils.c
src/backend/utils/misc/database.c
src/bin/initdb/initdb.sh
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/pg_dumpall.sh
src/include/catalog/catversion.h
src/include/catalog/pg_attribute.h
src/include/catalog/pg_class.h
src/include/catalog/pg_database.h
src/include/commands/dbcommands.h
src/include/mb/pg_wchar.h
src/include/nodes/parsenodes.h
src/test/regress/expected/opr_sanity.out

index d9e371b1be8b257fb9de1740cf88caa503f12e25..0bae8450c161edc40a03f67ad3da10fdc6c11f72 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_database.sgml,v 1.15 2000/10/05 19:48:17 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_database.sgml,v 1.16 2000/11/14 18:37:40 tgl Exp $
 Postgres documentation
 -->
 
@@ -23,7 +23,10 @@ Postgres documentation
    <date>1999-12-11</date>
   </refsynopsisdivinfo>
   <synopsis>
-CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATION = '<replaceable class="parameter">dbpath</replaceable>' ]
+CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
+    [ WITH [ LOCATION = '<replaceable class="parameter">dbpath</replaceable>' ]
+           [ TEMPLATE = <replaceable class="parameter">template</replaceable> ]
+           [ ENCODING = <replaceable class="parameter">encoding</replaceable> ] ]
   </synopsis>
 
   <refsect2 id="R2-SQL-CREATEDATABASE-1">
@@ -48,8 +51,30 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
       <term><replaceable class="parameter">dbpath</replaceable></term>
       <listitem>
        <para>
-       An alternate location where to store the new database in the filesystem.
-        See below for caveats.
+       An alternate filesystem location in which to store the new database,
+       specified as a string literal;
+       or <literal>DEFAULT</literal> to use the default location.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">template</replaceable></term>
+      <listitem>
+       <para>
+        Name of template from which to create the new database,
+       or <literal>DEFAULT</literal> to use the default template
+       (<literal>template1</literal>).
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">encoding</replaceable></term>
+      <listitem>
+       <para>
+        Multibyte encoding method to use in the new database.  Specify
+       a string literal name (e.g., <literal>'SQL_ASCII'</literal>),
+       or an integer encoding number, or <literal>DEFAULT</literal>
+       to use the default encoding.
        </para>
       </listitem>
      </varlistentry>
@@ -98,11 +123,10 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
      </varlistentry>
 
      <varlistentry>
-      <term><computeroutput>ERROR:  Single quotes are not allowed in database names.</computeroutput></term>
-      <term><computeroutput>ERROR:  Single quotes are not allowed in database paths.</computeroutput></term>
+      <term><computeroutput>ERROR:  database path may not contain single quotes</computeroutput></term>
       <listitem>
        <para>
-       The database <replaceable class="parameter">name</replaceable> and
+       The database location
         <replaceable class="parameter">dbpath</replaceable> cannot contain
         single quotes. This is required so that the shell commands that
         create the database directory can execute safely.
@@ -111,18 +135,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
      </varlistentry>
 
      <varlistentry>
-      <term><computeroutput>ERROR:  The path 'xxx' is invalid.</computeroutput></term>
-      <listitem>
-       <para>
-        The expansion of the specified <replaceable class="parameter">dbpath</replaceable>
-        (see below) failed. Check the path you entered or make sure that the
-        environment variable you are referencing does exist.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><computeroutput>ERROR:  createdb: May not be called in a transaction block.</computeroutput></term>
+      <term><computeroutput>ERROR:  CREATE DATABASE: may not be called in a transaction block</computeroutput></term>
       <listitem>
        <para>
         If you have an explicit transaction block in progress you cannot call
@@ -133,6 +146,9 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
 
      <varlistentry>
       <term><computeroutput>ERROR:  Unable to create database directory '<replaceable>path</replaceable>'.</computeroutput></term>
+     </varlistentry>
+
+     <varlistentry>
       <term><computeroutput>ERROR:  Could not initialize database directory.</computeroutput></term>
       <listitem>
        <para>
@@ -169,10 +185,10 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
    command.
   </para>
   <para>
-   If the path contains a slash, the leading part is interpreted
-   as an environment variable, which must be known to the
+   If the path name does not contain a slash, it is interpreted
+   as an environment variable name, which must be known to the
    server process. This way the database administrator can
-   exercise control over at which locations databases can be created.
+   exercise control over locations in which databases can be created.
    (A customary choice is, e.g., '<envar>PGDATA2</envar>'.)
    If the server is compiled with <literal>ALLOW_ABSOLUTE_DBPATHS</literal>
    (not so by default), absolute path names, as identified by
@@ -181,6 +197,29 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
    are allowed as well.
   </para>
 
+  <para>
+   By default, the new database will be created by cloning the standard
+   system database <literal>template1</>.  A different template can be
+   specified by writing <literal>TEMPLATE =</>
+   <replaceable class="parameter">name</replaceable>.  In particular,
+   by writing <literal>TEMPLATE = template0</>, you can create a virgin
+   database containing only the standard objects predefined by your
+   version of Postgres.  This is useful if you wish to avoid copying
+   any installation-local objects that may have been added to template1.
+  </para>
+
+  <para>
+   The optional encoding parameter allows selection of the database encoding,
+   if your server was compiled with multibyte encoding support.  When not
+   specified, it defaults to the encoding used by the selected template
+   database.
+  </para>
+
+  <para>
+   Optional parameters can be written in any order, not only the order
+   illustrated above.
+  </para>
+
   <refsect2 id="R2-SQL-CREATEDATABASE-3">
    <refsect2info>
     <date>1999-12-11</date>
@@ -221,6 +260,33 @@ comment from Olly; response from Thomas...
    Not sure if the dump/reload would guarantee that
    the alternate data area gets refreshed though...
 -->
+
+  <para>
+   Although it is possible to copy a database other than template1 by
+   specifying its name as the template, this is not (yet) intended as
+   a general-purpose COPY DATABASE facility.  In particular, it is
+   essential that the source database be idle (no data-altering transactions
+   in progress)
+   for the duration of the copying operation.  CREATE DATABASE will check
+   that no backend processes (other than itself) are connected to
+   the source database at the start of the operation, but this does not
+   guarantee that changes cannot be made while the copy proceeds.  Therefore,
+   we recommend that databases used as templates be treated as read-only.
+  </para>
+
+  <para>
+   Two useful flags exist in <literal>pg_database</literal> for each
+   database: <literal>datistemplate</literal> and
+   <literal>datallowconn</literal>.  <literal>datistemplate</literal>
+   may be set to indicate that a database is intended as a template for
+   CREATE DATABASE.  If this flag is set, the database may be cloned by
+   any user with CREATEDB privileges; if it is not set, only superusers
+   and the owner of the database may clone it.
+   If <literal>datallowconn</literal> is false, then no new connections
+   to that database will be allowed (but existing sessions are not killed
+   simply by setting the flag false).  The <literal>template0</literal>
+   database is normally marked this way to prevent modification of it.
+  </para>
   </refsect2>
  </refsect1>
 
index 2442679250f5efef73de1eadd44a6d74664bb2cd..70fd952db63ad3bf6a029c73a790b45239f0671b 100644 (file)
@@ -8,12 +8,11 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.66 2000/11/12 20:51:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.67 2000/11/14 18:37:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
-#include "commands/dbcommands.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -27,6 +26,7 @@
 #include "catalog/pg_database.h"
 #include "catalog/pg_shadow.h"
 #include "commands/comment.h"
+#include "commands/dbcommands.h"
 #include "miscadmin.h"
 #include "storage/sinval.h"            /* for DatabaseHasActiveBackends */
 #include "utils/builtins.h"
 
 
 /* non-export function prototypes */
+static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
+                                               int *encodingP, bool *dbIsTemplateP,
+                                               Oid *dbLastSysOidP, char *dbpath);
 static bool get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb);
-static bool get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP);
-static char * resolve_alt_dbpath(const char * dbpath, Oid dboid);
-static bool remove_dbdirs(const char * real_loc, const char * altloc);
+static char *resolve_alt_dbpath(const char *dbpath, Oid dboid);
+static bool remove_dbdirs(const char *real_loc, const char *altloc);
 
 /*
  * CREATE DATABASE
  */
 
 void
-createdb(const char *dbname, const char *dbpath, int encoding)
+createdb(const char *dbname, const char *dbpath,
+                const char *dbtemplate, int encoding)
 {
+       char       *nominal_loc;
+       char       *alt_loc;
+       char       *target_dir;
+       char            src_loc[MAXPGPATH];
        char            buf[2 * MAXPGPATH + 100];
-       char       *altloc;
-       char       *real_loc;
        int                     ret;
        bool            use_super,
                                use_createdb;
+       Oid                     src_dboid;
+       int4            src_owner;
+       int                     src_encoding;
+       bool            src_istemplate;
+       Oid                     src_lastsysoid;
+       char            src_dbpath[MAXPGPATH];
        Relation        pg_database_rel;
        HeapTuple       tuple;
        TupleDesc       pg_database_dsc;
        Datum           new_record[Natts_pg_database];
-       char            new_record_nulls[Natts_pg_database] = {' ', ' ', ' ', ' ', ' '};
+       char            new_record_nulls[Natts_pg_database];
        Oid                     dboid;
 
        if (!get_user_info(GetUserId(), &use_super, &use_createdb))
@@ -66,122 +77,195 @@ createdb(const char *dbname, const char *dbpath, int encoding)
        if (!use_createdb && !use_super)
                elog(ERROR, "CREATE DATABASE: permission denied");
 
-       if (get_db_info(dbname, NULL, NULL, NULL))
-               elog(ERROR, "CREATE DATABASE: database \"%s\" already exists", dbname);
-
        /* don't call this in a transaction block */
        if (IsTransactionBlock())
                elog(ERROR, "CREATE DATABASE: may not be called in a transaction block");
 
        /*
-        * Insert a new tuple into pg_database
+        * Check for db name conflict.  There is a race condition here, since
+        * another backend could create the same DB name before we commit.
+        * However, holding an exclusive lock on pg_database for the whole time
+        * we are copying the source database doesn't seem like a good idea,
+        * so accept possibility of race to create.  We will check again after
+        * we grab the exclusive lock.
         */
-       pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
-       pg_database_dsc = RelationGetDescr(pg_database_rel);
+       if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL))
+               elog(ERROR, "CREATE DATABASE: database \"%s\" already exists", dbname);
 
-       /* 
-        * Preassign OID for pg_database tuple, so that we know current
-        * OID counter value
+       /*
+        * Lookup database (template) to be cloned.
         */
-       dboid = newoid();
+       if (!dbtemplate)
+               dbtemplate = "template1"; /* Default template database name */
 
-       /* Form tuple */
-       new_record[Anum_pg_database_datname - 1] =
-               DirectFunctionCall1(namein, CStringGetDatum(dbname));
-       new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(GetUserId());
-       new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
-       /* Save current OID val */
-       new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(dboid);
-       /* no nulls here, GetRawDatabaseInfo doesn't like them */
-       new_record[Anum_pg_database_datpath - 1] =
-               DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
+       if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
+                                        &src_istemplate, &src_lastsysoid, src_dbpath))
+               elog(ERROR, "CREATE DATABASE: template \"%s\" does not exist",
+                        dbtemplate);
+       /*
+        * Permission check: to copy a DB that's not marked datistemplate,
+        * you must be superuser or the owner thereof.
+        */
+       if (!src_istemplate)
+       {
+               if (!use_super && GetUserId() != src_owner)
+                       elog(ERROR, "CREATE DATABASE: permission to copy \"%s\" denied",
+                                dbtemplate);
+       }
+       /*
+        * Determine physical path of source database
+        */
+       alt_loc = resolve_alt_dbpath(src_dbpath, src_dboid);
+       if (!alt_loc)
+               alt_loc = GetDatabasePath(src_dboid);
+       strcpy(src_loc, alt_loc);
 
-       tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
+       /*
+        * The source DB can't have any active backends, except this one
+        * (exception is to allow CREATE DB while connected to template1).
+        * Otherwise we might copy inconsistent data.  This check is not
+        * bulletproof, since someone might connect while we are copying...
+        */
+       if (DatabaseHasActiveBackends(src_dboid, true))
+               elog(ERROR, "CREATE DATABASE: source database \"%s\" is being accessed by other users", dbtemplate);
 
-       tuple->t_data->t_oid = dboid;   /* override heap_insert */
+       /* If encoding is defaulted, use source's encoding */
+       if (encoding < 0)
+               encoding = src_encoding;
 
+       /* 
+        * Preassign OID for pg_database tuple, so that we can compute db path.
+        */
+       dboid = newoid();
 
        /*
-        * Update table
+        * Compute nominal location (where we will try to access the database),
+        * and resolve alternate physical location if one is specified.
         */
-       heap_insert(pg_database_rel, tuple);
-
-       real_loc = GetDatabasePath(tuple->t_data->t_oid);
-       altloc = resolve_alt_dbpath(dbpath, tuple->t_data->t_oid);
+       nominal_loc = GetDatabasePath(dboid);
+       alt_loc = resolve_alt_dbpath(dbpath, dboid);
 
-       if (strchr(real_loc, '\'') && strchr(altloc, '\''))
+       if (strchr(nominal_loc, '\''))
+               elog(ERROR, "database path may not contain single quotes");
+       if (alt_loc && strchr(alt_loc, '\''))
+               elog(ERROR, "database path may not contain single quotes");
+       if (strchr(src_loc, '\''))
                elog(ERROR, "database path may not contain single quotes");
        /* ... otherwise we'd be open to shell exploits below */
 
-       /*
-        * Update indexes (there aren't any currently)
-        */
-#ifdef Num_pg_database_indices
-       if (RelationGetForm(pg_database_rel)->relhasindex)
-       {
-               Relation        idescs[Num_pg_database_indices];
-
-               CatalogOpenIndices(Num_pg_database_indices,
-                                                  Name_pg_database_indices, idescs);
-               CatalogIndexInsert(idescs, Num_pg_database_indices, pg_database_rel,
-                                                  tuple);
-               CatalogCloseIndices(Num_pg_database_indices, idescs);
-       }
+#ifdef XLOG
+       /* Try to force any dirty buffers out to disk */
+       BufferSync();
 #endif
 
-       heap_close(pg_database_rel, NoLock);
-
        /*
         * Close virtual file descriptors so the kernel has more available for
         * the mkdir() and system() calls below.
         */
        closeAllVfds();
 
-       /* Copy the template database to the new location */
+       /*
+        * Check we can create the target directory --- but then remove it
+        * because we rely on cp(1) to create it for real.
+        */
+       target_dir = alt_loc ? alt_loc : nominal_loc;
 
-       if (mkdir((altloc ? altloc : real_loc), S_IRWXU) != 0)
-               elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %s",
-                        (altloc ? altloc : real_loc), strerror(errno));
+       if (mkdir(target_dir, S_IRWXU) != 0)
+               elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %m",
+                        target_dir);
+       rmdir(target_dir);
 
-       if (altloc)
+       /* Make the symlink, if needed */
+       if (alt_loc)
        {
-               if (symlink(altloc, real_loc) != 0)
-                       elog(ERROR, "CREATE DATABASE: could not link %s to %s: %s",
-                                real_loc, altloc, strerror(errno));
+               if (symlink(alt_loc, nominal_loc) != 0)
+                       elog(ERROR, "CREATE DATABASE: could not link '%s' to '%s': %m",
+                                nominal_loc, alt_loc);
        }
 
-       snprintf(buf, sizeof(buf), "cp '%s'/* '%s'",
-                        GetDatabasePath(TemplateDbOid), real_loc);
+       /* Copy the template database to the new location */
+       snprintf(buf, sizeof(buf), "cp -r '%s' '%s'", src_loc, target_dir);
 
        ret = system(buf);
        /* Some versions of SunOS seem to return ECHILD after a system() call */
        if (ret != 0 && errno != ECHILD)
        {
-               if (remove_dbdirs(real_loc, altloc))
+               if (remove_dbdirs(nominal_loc, alt_loc))
                        elog(ERROR, "CREATE DATABASE: could not initialize database directory");
                else
                        elog(ERROR, "CREATE DATABASE: could not initialize database directory; delete failed as well");
        }
 
-#ifdef XLOG
-       BufferSync();
+       /*
+        * Now OK to grab exclusive lock on pg_database.
+        */
+       pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+
+       /* Check to see if someone else created same DB name meanwhile. */
+       if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL))
+       {
+               remove_dbdirs(nominal_loc, alt_loc);
+               elog(ERROR, "CREATE DATABASE: database \"%s\" already exists", dbname);
+       }
+
+       /*
+        * Insert a new tuple into pg_database
+        */
+       pg_database_dsc = RelationGetDescr(pg_database_rel);
+
+       /* Form tuple */
+       new_record[Anum_pg_database_datname - 1] =
+               DirectFunctionCall1(namein, CStringGetDatum(dbname));
+       new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(GetUserId());
+       new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
+       new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
+       new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
+       new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
+       /* no nulls here, GetRawDatabaseInfo doesn't like them */
+       new_record[Anum_pg_database_datpath - 1] =
+               DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
+
+       memset(new_record_nulls, ' ', sizeof(new_record_nulls));
+
+       tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
+
+       tuple->t_data->t_oid = dboid;   /* override heap_insert's OID selection */
+
+       heap_insert(pg_database_rel, tuple);
+
+       /*
+        * Update indexes (there aren't any currently)
+        */
+#ifdef Num_pg_database_indices
+       if (RelationGetForm(pg_database_rel)->relhasindex)
+       {
+               Relation        idescs[Num_pg_database_indices];
+
+               CatalogOpenIndices(Num_pg_database_indices,
+                                                  Name_pg_database_indices, idescs);
+               CatalogIndexInsert(idescs, Num_pg_database_indices, pg_database_rel,
+                                                  tuple);
+               CatalogCloseIndices(Num_pg_database_indices, idescs);
+       }
 #endif
-}
 
+       /* Close pg_database, but keep lock till commit */
+       heap_close(pg_database_rel, NoLock);
+}
 
 
 /*
  * DROP DATABASE
  */
-
 void
 dropdb(const char *dbname)
 {
        int4            db_owner;
+       bool            db_istemplate;
        bool            use_super;
        Oid                     db_id;
-       char       *altloc;
-       char       *real_loc;
+       char       *alt_loc;
+       char       *nominal_loc;
        char        dbpath[MAXPGPATH];
        Relation        pgdbrel;
        HeapScanDesc pgdbscan;
@@ -190,9 +274,6 @@ dropdb(const char *dbname)
 
        AssertArg(dbname);
 
-       if (strcmp(dbname, "template1") == 0)
-               elog(ERROR, "DROP DATABASE: may not be executed on the template1 database");
-
        if (strcmp(dbname, DatabaseName) == 0)
                elog(ERROR, "DROP DATABASE: cannot be executed on the currently open database");
 
@@ -202,15 +283,6 @@ dropdb(const char *dbname)
        if (!get_user_info(GetUserId(), &use_super, NULL))
                elog(ERROR, "current user name is invalid");
 
-       if (!get_db_info(dbname, dbpath, &db_id, &db_owner))
-               elog(ERROR, "DROP DATABASE: database \"%s\" does not exist", dbname);
-
-       if (GetUserId() != db_owner && !use_super)
-               elog(ERROR, "DROP DATABASE: permission denied");
-
-       real_loc = GetDatabasePath(db_id);
-       altloc = resolve_alt_dbpath(dbpath, db_id);
-
        /*
         * Obtain exclusive lock on pg_database.  We need this to ensure that
         * no new backend starts up in the target database while we are
@@ -222,14 +294,29 @@ dropdb(const char *dbname)
         */
        pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
 
+       if (!get_db_info(dbname, &db_id, &db_owner, NULL,
+                                        &db_istemplate, NULL, dbpath))
+               elog(ERROR, "DROP DATABASE: database \"%s\" does not exist", dbname);
+
+       if (!use_super && GetUserId() != db_owner)
+               elog(ERROR, "DROP DATABASE: permission denied");
+
+       /*
+        * Disallow dropping a DB that is marked istemplate.  This is just
+        * to prevent people from accidentally dropping template0 or template1;
+        * they can do so if they're really determined ...
+        */
+       if (db_istemplate)
+               elog(ERROR, "DROP DATABASE: database is marked as a template");
+
+       nominal_loc = GetDatabasePath(db_id);
+       alt_loc = resolve_alt_dbpath(dbpath, db_id);
+
        /*
         * Check for active backends in the target database.
         */
        if (DatabaseHasActiveBackends(db_id, false))
-       {
-               heap_close(pgdbrel, AccessExclusiveLock);
                elog(ERROR, "DROP DATABASE: database \"%s\" is being accessed by other users", dbname);
-       }
 
        /*
         * Find the database's tuple by OID (should be unique, we trust).
@@ -242,8 +329,6 @@ dropdb(const char *dbname)
        tup = heap_getnext(pgdbscan, 0);
        if (!HeapTupleIsValid(tup))
        {
-               heap_close(pgdbrel, AccessExclusiveLock);
-
                /*
                 * This error should never come up since the existence of the
                 * database is checked earlier
@@ -252,9 +337,6 @@ dropdb(const char *dbname)
                         dbname);
        }
 
-       /* Delete any comments associated with the database */
-       DeleteComments(db_id);
-
        /* Remove the database's tuple from pg_database */
        heap_delete(pgdbrel, &tup->t_self, NULL);
 
@@ -266,6 +348,9 @@ dropdb(const char *dbname)
         */
        heap_close(pgdbrel, NoLock);
 
+       /* Delete any comments associated with the database */
+       DeleteComments(db_id);
+
        /*
         * Drop pages for this database that are in the shared buffer cache.
         * This is important to ensure that no remaining backend tries to
@@ -273,16 +358,10 @@ dropdb(const char *dbname)
         */
        DropBuffers(db_id);
 
-       /*
-        * Close virtual file descriptors so the kernel has more available for
-        * the system() call below.
-        */
-       closeAllVfds();
-
        /*
         * Remove the database's subdirectory and everything in it.
         */
-       remove_dbdirs(real_loc, altloc);
+       remove_dbdirs(nominal_loc, alt_loc);
 }
 
 
@@ -292,28 +371,32 @@ dropdb(const char *dbname)
  */
 
 static bool
-get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP)
+get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
+                       int *encodingP, bool *dbIsTemplateP,
+                       Oid *dbLastSysOidP, char *dbpath)
 {
        Relation        relation;
-       HeapTuple       tuple;
        ScanKeyData scanKey;
        HeapScanDesc scan;
+       HeapTuple       tuple;
 
        AssertArg(name);
 
-       relation = heap_openr(DatabaseRelationName, AccessExclusiveLock /* ??? */ );
+       /* Caller may wish to grab a better lock on pg_database beforehand... */
+       relation = heap_openr(DatabaseRelationName, AccessShareLock);
 
        ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
                                                   F_NAMEEQ, NameGetDatum(name));
 
        scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scanKey);
        if (!HeapScanIsValid(scan))
-               elog(ERROR, "Cannot begin scan of %s.", DatabaseRelationName);
+               elog(ERROR, "Cannot begin scan of %s", DatabaseRelationName);
 
        tuple = heap_getnext(scan, 0);
 
        if (HeapTupleIsValid(tuple))
        {
+               Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
                text       *tmptext;
                bool            isnull;
 
@@ -322,22 +405,23 @@ get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP)
                        *dbIdP = tuple->t_data->t_oid;
                /* uid of the owner */
                if (ownerIdP)
-               {
-                       *ownerIdP = (int4) heap_getattr(tuple,
-                                                                                       Anum_pg_database_datdba,
-                                                                                       RelationGetDescr(relation),
-                                                                                       &isnull);
-                       if (isnull)
-                               *ownerIdP = -1; /* hopefully no one has that id already ;) */
-               }
+                       *ownerIdP = dbform->datdba;
+               /* multibyte encoding */
+               if (encodingP)
+                       *encodingP = dbform->encoding;
+               /* allowed as template? */
+               if (dbIsTemplateP)
+                       *dbIsTemplateP = dbform->datistemplate;
+               /* last system OID used in database */
+               if (dbLastSysOidP)
+                       *dbLastSysOidP = dbform->datlastsysoid;
                /* database path (as registered in pg_database) */
                if (dbpath)
                {
-                       tmptext = (text *) heap_getattr(tuple,
-                                                                                       Anum_pg_database_datpath,
-                                                                                       RelationGetDescr(relation),
-                                                                                       &isnull);
-
+                       tmptext = DatumGetTextP(heap_getattr(tuple,
+                                                                                                Anum_pg_database_datpath,
+                                                                                                RelationGetDescr(relation),
+                                                                                                &isnull));
                        if (!isnull)
                        {
                                Assert(VARSIZE(tmptext) - VARHDRSZ < MAXPGPATH);
@@ -349,16 +433,9 @@ get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP)
                                strcpy(dbpath, "");
                }
        }
-       else
-       {
-               if (dbIdP)
-                       *dbIdP = InvalidOid;
-       }
 
        heap_endscan(scan);
-
-       /* We will keep the lock on the relation until end of transaction. */
-       heap_close(relation, NoLock);
+       heap_close(relation, AccessShareLock);
 
        return HeapTupleIsValid(tuple);
 }
@@ -396,6 +473,8 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
 
        if (strchr(dbpath, '/'))
        {
+               if (dbpath[0] != '/')
+                       elog(ERROR, "Relative paths are not allowed as database locations");
 #ifndef ALLOW_ABSOLUTE_DBPATHS
                elog(ERROR, "Absolute paths are not allowed as database locations");
 #endif
@@ -406,9 +485,9 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
                /* must be environment variable */
                char * var = getenv(dbpath);
                if (!var)
-                       elog(ERROR, "environment variable %s not set", dbpath);
+                       elog(ERROR, "Postmaster environment variable '%s' not set", dbpath);
                if (var[0] != '/')
-                       elog(ERROR, "environment variable %s must be absolute path", dbpath);
+                       elog(ERROR, "Postmaster environment variable '%s' must be absolute path", dbpath);
                prefix = var;
        }
 
@@ -421,24 +500,36 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
 
 
 static bool
-remove_dbdirs(const char * real_loc, const char * altloc)
+remove_dbdirs(const char * nominal_loc, const char * alt_loc)
 {
+       const char   *target_dir;
        char buf[MAXPGPATH + 100];
        bool success = true;
 
-       if (altloc)
+       target_dir = alt_loc ? alt_loc : nominal_loc;
+
+       /*
+        * Close virtual file descriptors so the kernel has more available for
+        * the system() call below.
+        */
+       closeAllVfds();
+
+       if (alt_loc)
+       {
                /* remove symlink */
-               if (unlink(real_loc) != 0)
+               if (unlink(nominal_loc) != 0)
                {
-                       elog(NOTICE, "could not remove '%s': %s", real_loc, strerror(errno));
+                       elog(NOTICE, "could not remove '%s': %m", nominal_loc);
                        success = false;
                }
+       }
+
+       snprintf(buf, sizeof(buf), "rm -rf '%s'", target_dir);
 
-       snprintf(buf, sizeof(buf), "rm -rf '%s'", altloc ? altloc : real_loc);
        if (system(buf) != 0 && errno != ECHILD)
        {
                elog(NOTICE, "database directory '%s' could not be removed",
-                        altloc ? altloc : real_loc);
+                        target_dir);
                success = false;
        }
 
index 3490ef8062444041078fd83d2166b5839323b601..9c342b5dc1e4c9e9f7ce422726f5a7cdda6b44e3 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.131 2000/11/12 00:36:57 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.132 2000/11/14 18:37:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2231,6 +2231,8 @@ _copyCreatedbStmt(CreatedbStmt *from)
                newnode->dbname = pstrdup(from->dbname);
        if (from->dbpath)
                newnode->dbpath = pstrdup(from->dbpath);
+       if (from->dbtemplate)
+               newnode->dbtemplate = pstrdup(from->dbtemplate);
        newnode->encoding = from->encoding;
 
        return newnode;
index 8fb81a45c0b61487540d66573a55f80320d9ebf0..aac0902a028b1426fbc54129dabcc7ca39419525 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.81 2000/11/12 00:36:57 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.82 2000/11/14 18:37:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1087,6 +1087,8 @@ _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
                return false;
        if (!equalstr(a->dbpath, b->dbpath))
                return false;
+       if (!equalstr(a->dbtemplate, b->dbtemplate))
+               return false;
        if (a->encoding != b->encoding)
                return false;
 
index 5572828d2590470e8dd0425afc400cd74c4df73d..3c4a2e00c9c2c9ccf516ba978450eaf9ff2bae23 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.208 2000/11/08 22:09:58 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.209 2000/11/14 18:37:49 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -56,8 +56,8 @@
 #include "miscadmin.h"
 #include "mb/pg_wchar.h"
 #else
-#define GetTemplateEncoding()  0               /* SQL_ASCII */
-#define GetTemplateEncodingName()      "SQL_ASCII"
+#define GetStandardEncoding()  0               /* SQL_ASCII */
+#define GetStandardEncodingName()      "SQL_ASCII"
 #endif
 
 extern List *parsetree;                        /* final parse result is delivered here */
@@ -146,8 +146,7 @@ static void doNegateFloat(Value *v);
 %type <node>    alter_column_action
 %type <ival>    drop_behavior
 
-%type <str>            createdb_opt_location
-%type <ival>    createdb_opt_encoding
+%type <list>   createdb_opt_list, createdb_opt_item
 
 %type <ival>   opt_lock, lock_type
 %type <boolean>        opt_lmode, opt_force
@@ -347,7 +346,7 @@ static void doNegateFloat(Value *v);
                OFFSET, OIDS, OPERATOR, OWNER, PASSWORD, PROCEDURAL,
                REINDEX, RENAME, RESET, RETURNS, ROW, RULE,
                SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID,
-               TEMP, TOAST, TRUNCATE, TRUSTED, 
+               TEMP, TEMPLATE, TOAST, TRUNCATE, TRUSTED, 
                UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
 
 /* The grammar thinks these are keywords, but they are not in the keywords.c
@@ -687,7 +686,8 @@ CreateSchemaStmt:  CREATE SCHEMA UserId
                                        CreatedbStmt *n = makeNode(CreatedbStmt);
                                        n->dbname = $3;
                                        n->dbpath = NULL;
-                                       n->encoding = GetTemplateEncoding();
+                                       n->dbtemplate = NULL;
+                                       n->encoding = -1;
                                        $$ = (Node *)n;
                                }
                ;
@@ -2924,16 +2924,34 @@ LoadStmt:  LOAD file_name
  *
  *****************************************************************************/
 
-CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_location createdb_opt_encoding
+CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_list
                                {
                                        CreatedbStmt *n = makeNode(CreatedbStmt);
-
-                                       if ($5 == NULL && $6 == -1)
-                                               elog(ERROR, "CREATE DATABASE WITH requires at least one option");
+                                       List   *l;
 
                                        n->dbname = $3;
-                                       n->dbpath = $5;
-                                       n->encoding = ($6 == -1) ? GetTemplateEncoding() : $6;
+                                       /* set default options */
+                                       n->dbpath = NULL;
+                                       n->dbtemplate = NULL;
+                                       n->encoding = -1;
+                                       /* process additional options */
+                                       foreach(l, $5)
+                                       {
+                                               List   *optitem = (List *) lfirst(l);
+
+                                               switch (lfirsti(optitem))
+                                               {
+                                                       case 1:
+                                                               n->dbpath = (char *) lsecond(optitem);
+                                                               break;
+                                                       case 2:
+                                                               n->dbtemplate = (char *) lsecond(optitem);
+                                                               break;
+                                                       case 3:
+                                                               n->encoding = lfirsti(lnext(optitem));
+                                                               break;
+                                               }
+                                       }
                                        $$ = (Node *)n;
                                }
                | CREATE DATABASE database_name
@@ -2941,27 +2959,51 @@ CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_location createdb
                                        CreatedbStmt *n = makeNode(CreatedbStmt);
                                        n->dbname = $3;
                                        n->dbpath = NULL;
-                                       n->encoding = GetTemplateEncoding();
+                                       n->dbtemplate = NULL;
+                                       n->encoding = -1;
                                        $$ = (Node *)n;
                                }
                ;
 
-createdb_opt_location:  LOCATION '=' Sconst            { $$ = $3; }
-               | LOCATION '=' DEFAULT                                  { $$ = NULL; }
-               | /*EMPTY*/                                                             { $$ = NULL; }
+createdb_opt_list:  createdb_opt_item
+                               { $$ = makeList1($1); }
+               | createdb_opt_list createdb_opt_item
+                               { $$ = lappend($1, $2); }
                ;
 
-createdb_opt_encoding:  ENCODING '=' Sconst
+/*
+ * createdb_opt_item returns 2-element lists, with the first element
+ * being an integer code to indicate which item was specified.
+ */
+createdb_opt_item:  LOCATION '=' Sconst
                                {
+                                       $$ = lconsi(1, makeList1($3));
+                               }
+               | LOCATION '=' DEFAULT
+                               {
+                                       $$ = lconsi(1, makeList1((char *) NULL));
+                               }
+               | TEMPLATE '=' name
+                               {
+                                       $$ = lconsi(2, makeList1($3));
+                               }
+               | TEMPLATE '=' DEFAULT
+                               {
+                                       $$ = lconsi(2, makeList1((char *) NULL));
+                               }
+               | ENCODING '=' Sconst
+                               {
+                                       int             encoding;
 #ifdef MULTIBYTE
-                                       $$ = pg_char_to_encoding($3);
-                                       if ($$ == -1)
+                                       encoding = pg_char_to_encoding($3);
+                                       if (encoding == -1)
                                                elog(ERROR, "%s is not a valid encoding name", $3);
 #else
-                                       if (strcasecmp($3, GetTemplateEncodingName()) != 0)
+                                       if (strcasecmp($3, GetStandardEncodingName()) != 0)
                                                elog(ERROR, "Multi-byte support is not enabled");
-                                       $$ = GetTemplateEncoding();
+                                       encoding = GetStandardEncoding();
 #endif
+                                       $$ = lconsi(3, makeListi1(encoding));
                                }
                | ENCODING '=' Iconst
                                {
@@ -2969,18 +3011,14 @@ createdb_opt_encoding:  ENCODING '=' Sconst
                                        if (!pg_get_encent_by_encoding($3))
                                                elog(ERROR, "%d is not a valid encoding code", $3);
 #else
-                                       if ($3 != GetTemplateEncoding())
+                                       if ($3 != GetStandardEncoding())
                                                elog(ERROR, "Multi-byte support is not enabled");
 #endif
-                                       $$ = $3;
+                                       $$ = lconsi(3, makeListi1($3));
                                }
                | ENCODING '=' DEFAULT
                                {
-                                       $$ = GetTemplateEncoding();
-                               }
-               | /*EMPTY*/
-                               {
-                                       $$ = -1;
+                                       $$ = lconsi(3, makeListi1(-1));
                                }
                ;
 
@@ -5495,6 +5533,7 @@ TokenId:  ABSOLUTE                                                { $$ = "absolute"; }
                | STDOUT                                                { $$ = "stdout"; }
                | SYSID                                                 { $$ = "sysid"; }
                | TEMP                                                  { $$ = "temp"; }
+               | TEMPLATE                                              { $$ = "template"; }
                | TEMPORARY                                             { $$ = "temporary"; }
                | TIMEZONE_HOUR                                 { $$ = "timezone_hour"; }
                | TIMEZONE_MINUTE                               { $$ = "timezone_minute"; }
index f3e4d85e4c5dfd38a3358305fd66a0ee7be8c1bf..19ec40f15bacd9f3e06345732745cff5a814c8f3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.84 2000/11/08 21:28:06 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.85 2000/11/14 18:37:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -247,6 +247,7 @@ static ScanKeyword ScanKeywords[] = {
        {"sysid", SYSID},
        {"table", TABLE},
        {"temp", TEMP},
+       {"template", TEMPLATE},
        {"temporary", TEMPORARY},
        {"then", THEN},
        {"time", TIME},
index 3a140488e4e03572e3ed7843ab25afe2bdb77ef6..68f7c06cd0f4a4efd357a97add8c2be6a74d84c9 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.186 2000/11/14 18:11:31 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.187 2000/11/14 18:37:42 tgl Exp $
  *
  * NOTES
  *
@@ -279,14 +279,8 @@ checkDataDir(const char *checkdir)
                exit(2);
        }
 
-#ifdef OLD_FILE_NAMING
-       snprintf(path, sizeof(path), "%s%cbase%ctemplate1%cpg_class",
-                        checkdir, SEP_CHAR, SEP_CHAR, SEP_CHAR);
-#else
-       snprintf(path, sizeof(path), "%s%cbase%c%u%c%u",
-                        checkdir, SEP_CHAR, SEP_CHAR, 
-                        TemplateDbOid, SEP_CHAR, RelOid_pg_class);
-#endif
+       snprintf(path, sizeof(path), "%s%cglobal%cpg_control",
+                        checkdir, SEP_CHAR, SEP_CHAR);
 
        fp = AllocateFile(path, PG_BINARY_R);
        if (fp == NULL)
index 79ac7c0f1573382a866a076035985fbb4fc6290e..63a43315286429a7fae2ac0d6a0a2e0af8a1a6f8 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.101 2000/11/08 16:31:06 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.102 2000/11/14 18:37:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -604,7 +604,8 @@ ProcessUtility(Node *parsetree,
 
                                set_ps_display(commandTag = "CREATE DATABASE");
 
-                               createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
+                               createdb(stmt->dbname, stmt->dbpath,
+                                                stmt->dbtemplate, stmt->encoding);
                        }
                        break;
 
index f786eb1d10dc2440f100032a63f3677858fad382..3a9e5a1797b909b310145510038f9541cf006226 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.70 2000/11/12 20:51:52 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.71 2000/11/14 18:37:44 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -79,6 +79,7 @@ ReverifyMyDatabase(const char *name)
        HeapScanDesc pgdbscan;
        ScanKeyData key;
        HeapTuple       tup;
+       Form_pg_database dbform;
 
        /*
         * Because we grab AccessShareLock here, we can be sure that destroydb
@@ -106,25 +107,24 @@ ReverifyMyDatabase(const char *name)
                 */
                DropBuffers(MyDatabaseId);
                /* Now I can commit hara-kiri with a clear conscience... */
-               elog(FATAL, "Database '%s', OID %u, has disappeared from pg_database",
+               elog(FATAL, "Database \"%s\", OID %u, has disappeared from pg_database",
                         name, MyDatabaseId);
        }
 
+       /*
+        * Also check that the database is currently allowing connections.
+        */
+       dbform = (Form_pg_database) GETSTRUCT(tup);
+       if (! dbform->datallowconn)
+               elog(FATAL, "Database \"%s\" is not currently accepting connections",
+                        name);
+
        /*
         * OK, we're golden.  Only other to-do item is to save the MULTIBYTE
-        * encoding info out of the pg_database tuple.  Note we also set the
-        * "template encoding", which is the default encoding for any CREATE
-        * DATABASE commands executed in this backend; essentially, you get
-        * the same encoding of the database you connected to as the default.
-        * (This replaces code that unreliably grabbed template1's encoding
-        * out of pg_database.  We could do an extra scan to find template1's
-        * tuple, but for 99.99% of all backend startups it'd be wasted cycles
-        * --- and the 'createdb' script connects to template1 anyway, so
-        * there's no difference.)
+        * encoding info out of the pg_database tuple.
         */
 #ifdef MULTIBYTE
-       SetDatabaseEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding);
-       SetTemplateEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding);
+       SetDatabaseEncoding(dbform->encoding);
 #endif
 
        heap_endscan(pgdbscan);
index 7cf082dc0cec1662b43289ad5a905b76ebba26b7..ad1322fe52b4c5437d2bc84a277234477a4b2822 100644 (file)
@@ -3,7 +3,7 @@
  * client encoding and server internal encoding.
  * (currently mule internal code (mic) is used)
  * Tatsuo Ishii
- * $Id: mbutils.c,v 1.13 2000/10/30 10:40:28 ishii Exp $ */
+ * $Id: mbutils.c,v 1.14 2000/11/14 18:37:44 tgl Exp $ */
 
 
 #include "postgres.h"
@@ -271,6 +271,7 @@ pg_mbcliplen(const unsigned char *mbstr, int len, int limit)
  * fuctions for utils/init
  */
 static int     DatabaseEncoding = MULTIBYTE;
+
 void
 SetDatabaseEncoding(int encoding)
 {
@@ -289,17 +290,3 @@ getdatabaseencoding(PG_FUNCTION_ARGS)
 {
        PG_RETURN_NAME(pg_encoding_to_char(DatabaseEncoding));
 }
-
-/* set and get template1 database encoding */
-static int     templateEncoding;
-void
-SetTemplateEncoding(int encoding)
-{
-       templateEncoding = encoding;
-}
-
-int
-GetTemplateEncoding()
-{
-       return (templateEncoding);
-}
index f415e5aee1821813588bcad9fb029e51f2d38aa3..364075c8bed80b2a6c888c92ee26491a5a779053 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.40 2000/10/16 14:52:19 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.41 2000/11/14 18:37:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -186,7 +186,7 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
                max = PageGetMaxOffsetNumber(pg);
 
                /* look at each tuple on the page */
-               for (i = 0; i <= max; i++)
+               for (i = 0; i < max; i++)
                {
                        int                     offset;
 
@@ -221,8 +221,11 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
                         * database OID from a flat file, handled the same way we
                         * handle the password relation?
                         */
-                       if (TransactionIdIsValid((TransactionId) tup.t_data->t_xmax))
-                               continue;
+                       if (tup.t_data->t_infomask & HEAP_XMIN_INVALID)
+                               continue;               /* inserting xact known aborted */
+                       if (TransactionIdIsValid((TransactionId) tup.t_data->t_xmax) &&
+                               !(tup.t_data->t_infomask & HEAP_XMAX_INVALID))
+                               continue;               /* deleting xact happened, not known aborted */
 
                        /*
                         * Okay, see if this is the one we want.
@@ -241,6 +244,10 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
                }
        }
 
+       /* failed to find it... */
+       *db_id = InvalidOid;
+       *path = '\0';
+
 done:
        close(dbfd);
        pfree(pg);
index dc500a6e7031ff38969252be8af18038518e94c6..2358c61b5e7031f55c191035f878ff056894bd2d 100644 (file)
@@ -7,15 +7,16 @@
 #
 # To create the database cluster, we create the directory that contains
 # all its data, create the files that hold the global tables, create
-# a few other control files for it, and create one database:  the
-# template database.
+# a few other control files for it, and create two databases: the
+# template0 and template1 databases.
 #
-# The template database is an ordinary PostgreSQL database.  Its data
-# never changes, though.  It exists to make it easy for PostgreSQL to 
-# create other databases -- it just copies.
+# The template databases are ordinary PostgreSQL databases.  template0
+# is never supposed to change after initdb, whereas template1 can be
+# changed to add site-local standard data.  Either one can be copied
+# to produce a new database.
 #
 # Optionally, we can skip creating the complete database cluster and
-# just create (or replace) the template database.
+# just create (or replace) the template databases.
 #
 # To create all those things, we run the postgres (backend) program and
 # feed it data from the bki files that were installed.
@@ -23,7 +24,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.113 2000/11/11 22:59:46 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.114 2000/11/14 18:37:45 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -203,7 +204,7 @@ do
                 ;;
         --template|-t)
                 template_only=yes
-                echo "Updating template1 database only."
+                echo "Updating template0 and template1 databases only."
                 ;;
 # The sysid of the database superuser. Can be freely changed.
         --sysid|-i)
@@ -277,7 +278,7 @@ if [ "$usage" ]; then
     echo "  -i, --sysid SYSID           Database sysid for the superuser"
     echo "Less commonly used options: "
     echo "  -L DIRECTORY                Where to find the input files"
-    echo "  -t, --template              Re-initialize template database only"
+    echo "  -t, --template              Re-initialize template databases only"
     echo "  -d, --debug                 Generate lots of debugging output"
     echo "  -n, --noclean               Do not clean up after errors"
     echo
@@ -451,7 +452,7 @@ fi
 BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG"
 FIRSTRUN="-boot -x1 -C -F -D$PGDATA $BACKEND_TALK_ARG"
 
-echo "Creating template database in $PGDATA/base/1"
+echo "Creating template1 database in $PGDATA/base/1"
 [ "$debug" = yes ] && echo "Running: $PGPATH/postgres $FIRSTRUN template1"
 
 cat "$TEMPLATE1_BKI" \
@@ -465,6 +466,10 @@ echo $short_version > "$PGDATA"/base/1/PG_VERSION || exit_nicely
 ##########################################################################
 #
 # CREATE GLOBAL TABLES
+#
+# XXX --- I do not believe the "template_only" option can actually work.
+# With this coding, it'll fail to make entries for pg_shadow etc. in
+# template1 ... tgl 11/2000
 
 if [ "$template_only" != yes ]
 then
@@ -491,7 +496,7 @@ fi
 #
 # CREATE VIEWS and other things
 
-echo
+echo "Initializing pg_shadow."
 
 PGSQL_OPT="-o /dev/null -O -F -D$PGDATA"
 
@@ -532,6 +537,7 @@ fi
 
 
 echo "Enabling unlimited row width for system tables."
+
 echo "ALTER TABLE pg_attrdef CREATE TOAST TABLE" \
         | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 echo "ALTER TABLE pg_description CREATE TOAST TABLE" \
@@ -546,7 +552,8 @@ echo "ALTER TABLE pg_statistic CREATE TOAST TABLE" \
         | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 
 
-echo "Creating view pg_user."
+echo "Creating system views."
+
 echo "CREATE VIEW pg_user AS \
         SELECT \
             usename, \
@@ -560,7 +567,6 @@ echo "CREATE VIEW pg_user AS \
         FROM pg_shadow" \
         | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 
-echo "Creating view pg_rules."
 echo "CREATE VIEW pg_rules AS \
         SELECT \
             C.relname AS tablename, \
@@ -571,7 +577,6 @@ echo "CREATE VIEW pg_rules AS \
             AND C.oid = R.ev_class;" \
        | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 
-echo "Creating view pg_views."
 echo "CREATE VIEW pg_views AS \
         SELECT \
             C.relname AS viewname, \
@@ -585,7 +590,6 @@ echo "CREATE VIEW pg_views AS \
             )" \
        | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 
-echo "Creating view pg_tables."
 echo "CREATE VIEW pg_tables AS \
         SELECT \
             C.relname AS tablename, \
@@ -601,7 +605,6 @@ echo "CREATE VIEW pg_tables AS \
             )" \
        | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 
-echo "Creating view pg_indexes."
 echo "CREATE VIEW pg_indexes AS \
         SELECT \
             C.relname AS tablename, \
@@ -622,14 +625,27 @@ cat $TEMPFILE \
 rm -f "$TEMPFILE" || exit_nicely
 
 echo "Setting lastsysoid."
-echo "Update pg_database Set datlastsysoid = (Select max(oid) From pg_description) \
-        Where datname = 'template1'" \
+echo "UPDATE pg_database SET \
+       datistemplate = 't', \
+       datlastsysoid = (SELECT max(oid) FROM pg_description) \
+        WHERE datname = 'template1'" \
                | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 
 echo "Vacuuming database."
 echo "VACUUM ANALYZE" \
        | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
 
+echo "Copying template1 to template0."
+echo "CREATE DATABASE template0" \
+       | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
+echo "UPDATE pg_database SET \
+       datistemplate = 't', \
+       datallowconn = 'f' \
+        WHERE datname = 'template0'" \
+               | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
+echo "VACUUM pg_database" \
+       | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
+
 
 ##########################################################################
 #
index a7c1ca9e8a490bd6d883026959e92d67e7f429ee..0d0fba26a2cb471fd9f295d17cc36c91f4ad3c16 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.179 2000/11/13 23:37:52 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.180 2000/11/14 18:37:45 tgl Exp $
  *
  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  *
 #include "pg_dump.h"
 #include "pg_backup.h"
 
+#define atooid(x)  ((Oid) strtoul((x), NULL, 10))
+
 static void dumpComment(Archive *outfile, const char *target, const char *oid);
 static void dumpSequence(Archive *fout, TableInfo tbinfo);
 static void dumpACL(Archive *fout, TableInfo tbinfo);
@@ -140,7 +142,7 @@ static char *checkForQuote(const char *s);
 static void clearTableInfo(TableInfo *, int);
 static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
                        TypeInfo *tinfo, int numTypes);
-static int     findLastBuiltinOid(const char*);
+static Oid     findLastBuiltinOid(const char*);
 static void setMaxOid(Archive *fout);
 
 static void AddAcl(char *aclbuf, const char *keyword);
@@ -156,7 +158,7 @@ extern int  optind,
 /* global decls */
 bool           g_verbose;                      /* User wants verbose narration of our
                                                                 * activities. */
-int                    g_last_builtin_oid; /* value of the last builtin oid */
+Oid                    g_last_builtin_oid; /* value of the last builtin oid */
 Archive           *g_fout;                             /* the script file */
 PGconn    *g_conn;                             /* the database connection */
 
@@ -2784,7 +2786,7 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
        {
 
                /* skip all the builtin types */
-               if (atoi(tinfo[i].oid) < g_last_builtin_oid)
+               if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
                        continue;
 
                /* skip relation types */
@@ -2899,7 +2901,7 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
 
        for (i = 0; i < ntups; i++)
        {
-               lanoid = atoi(PQgetvalue(res, i, i_oid));
+               lanoid = atooid(PQgetvalue(res, i, i_oid));
                if (lanoid <= g_last_builtin_oid)
                        continue;
 
@@ -3127,7 +3129,7 @@ dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
                resetPQExpBuffer(sort2);
 
                /* skip all the builtin oids */
-               if (atoi(oprinfo[i].oid) < g_last_builtin_oid)
+               if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
                        continue;
 
                /*
@@ -3222,7 +3224,7 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
                resetPQExpBuffer(details);
 
                /* skip all the builtin oids */
-               if (atoi(agginfo[i].oid) < g_last_builtin_oid)
+               if (atooid(agginfo[i].oid) <= g_last_builtin_oid)
                        continue;
 
                appendPQExpBuffer(details,
@@ -3907,12 +3909,12 @@ setMaxOid(Archive *fout)
  * we do this by retrieving datlastsysoid from the pg_database entry for this database,
  */
 
-static int
+static Oid
 findLastBuiltinOid(const char* dbname)
 {
        PGresult   *res;
        int                     ntups;
-       int                     last_oid;
+       Oid                     last_oid;
        PQExpBuffer query = createPQExpBuffer();
 
        resetPQExpBuffer(query);
index 07202bbf1895f2450884f3a295f7b449181e782a..19bfa85c595886bfcc1f83d5131441425f1db478 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.53 2000/10/10 13:55:28 pjw Exp $
+ * $Id: pg_dump.h,v 1.54 2000/11/14 18:37:46 tgl Exp $
  *
  * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
  *
@@ -177,7 +177,7 @@ typedef struct _oprInfo
 /* global decls */
 extern bool g_force_quotes;            /* double-quotes for identifiers flag */
 extern bool g_verbose;                 /* verbose flag */
-extern int     g_last_builtin_oid; /* value of the last builtin oid */
+extern Oid     g_last_builtin_oid; /* value of the last builtin oid */
 extern Archive *g_fout;                        /* the script file */
 
 /* placeholders for comment starting and ending delimiters */
index e16beb4a039a342fb8dde720c5a35ab23a07663f..0429a9c34476e09b18ed05e82f4052e5d5e21e6f 100644 (file)
@@ -6,7 +6,7 @@
 # and "pg_group" tables, which belong to the whole installation rather
 # than any one individual database.
 #
-# $Header: /cvsroot/pgsql/src/bin/pg_dump/Attic/pg_dumpall.sh,v 1.7 2000/11/08 18:23:44 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/pg_dump/Attic/pg_dumpall.sh,v 1.8 2000/11/14 18:37:46 tgl Exp $
 
 CMDNAME=`basename $0`
 
@@ -151,7 +151,7 @@ echo "${BS}connect template1"
 #
 # Dump users (but not the user created by initdb)
 #
-echo "DELETE FROM pg_shadow WHERE usesysid NOT IN (SELECT datdba FROM pg_database WHERE datname = 'template1');"
+echo "DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');"
 echo
 
 $PSQL -d template1 -At <<__END__
@@ -163,7 +163,7 @@ SELECT
   || CASE WHEN valuntil IS NOT NULL THEN ' VALID UNTIL '''::text
     || CAST(valuntil AS TIMESTAMP) || '''' ELSE '' END || ';'
 FROM pg_shadow
-WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template1');
+WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');
 __END__
 echo
 
@@ -187,46 +187,33 @@ done
 test "$accounts_only" = yes && exit 0
 
 
-# First we dump the template in case there are local extensions.
-
-echo
-echo "--"
-echo "-- Database template1"
-echo "--"
-echo "${BS}connect template1"
-$PGDUMP "template1"
-if [ "$?" -ne 0 ] ; then
-    echo "pg_dump failed on template1, exiting" 1>&2
-    exit 1
-fi
-
-
 # For each database, run pg_dump to dump the contents of that database.
+# We skip databases marked not datallowconn, since we'd be unable to
+# connect to them anyway (and besides, we don't want to dump template0).
 
 $PSQL -d template1 -At -F ' ' \
-  -c "SELECT d.datname, u.usename, pg_encoding_to_char(d.encoding), d.datpath FROM pg_database d, pg_shadow u WHERE d.datdba = u.usesysid AND datname <> 'template1';" | \
-while read DATABASE DBOWNER ENCODING DBPATH; do
+  -c "SELECT datname, usename, pg_encoding_to_char(d.encoding), datistemplate, datpath FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) WHERE datallowconn;" | \
+while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do
     echo
     echo "--"
     echo "-- Database $DATABASE"
     echo "--"
     echo "${BS}connect template1 $DBOWNER"
 
-    if [ "$cleanschema" = yes ] ; then
+    if [ "$cleanschema" = yes -a "$DATABASE" != template1 ] ; then
         echo "DROP DATABASE \"$DATABASE\";"
     fi
 
-    createdbcmd="CREATE DATABASE \"$DATABASE\""
-    if [ x"$DBPATH" != x"" ] || [ x"$MULTIBYTE" != x"" ]; then
-        createdbcmd="$createdbcmd WITH"
-    fi
-    if [ x"$DBPATH" != x"" ] ; then
-        createdbcmd="$createdbcmd LOCATION = '$DBPATH'"
+    if [ "$DATABASE" != template1 ] ; then
+       createdbcmd="CREATE DATABASE \"$DATABASE\" WITH TEMPLATE = template0"
+       if [ x"$DBPATH" != x"" ] ; then
+           createdbcmd="$createdbcmd LOCATION = '$DBPATH'"
+       fi
+       if [ x"$MULTIBYTE" != x"" ] ; then
+           createdbcmd="$createdbcmd ENCODING = '$ENCODING'"
+       fi
+       echo "$createdbcmd;"
     fi
-    if [ x"$MULTIBYTE" != x"" ] ; then
-        createdbcmd="$createdbcmd ENCODING = '$ENCODING'"
-    fi
-    echo "$createdbcmd;"
 
     echo "${BS}connect $DATABASE $DBOWNER"
     $PGDUMP "$DATABASE"
@@ -234,6 +221,9 @@ while read DATABASE DBOWNER ENCODING DBPATH; do
         echo "pg_dump failed on $DATABASE, exiting" 1>&2
         exit 1
     fi
+    if [ x"$ISTEMPLATE" = xt ] ; then
+        echo "UPDATE pg_database SET datistemplate = 't' WHERE datname = '$DATABASE';"
+    fi
 done
 
 exit 0
index 67a2beb77c348285664eb7e98415683fda80322d..39919546208b4cdf0cbbd87e603f016ef343755c 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.59 2000/11/12 00:37:00 tgl Exp $
+ * $Id: catversion.h,v 1.60 2000/11/14 18:37:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                             yyyymmddN */
-#define CATALOG_VERSION_NO     200011112
+#define CATALOG_VERSION_NO     200011131
 
 #endif
index de3ccdf5d83cabbfc48a3b1e421f921cb08b538a..f71aca0f0923240ea03c74316b809d94b9056806 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_attribute.h,v 1.66 2000/10/22 17:55:49 pjw Exp $
+ * $Id: pg_attribute.h,v 1.67 2000/11/14 18:37:46 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -281,8 +281,10 @@ DATA(insert OID = 0 ( 1247 tableoid                        26 0  4  -7 0 -1 -1 t p f i f f));
 DATA(insert OID = 0 ( 1262 datname                     19 0 NAMEDATALEN   1 0 -1 -1 f p f i f f));
 DATA(insert OID = 0 ( 1262 datdba                      23 0  4   2 0 -1 -1 t p f i f f));
 DATA(insert OID = 0 ( 1262 encoding                    23 0  4   3 0 -1 -1 t p f i f f));
-DATA(insert OID = 0 ( 1262 datlastsysoid    26 0  4   4 0 -1 -1 t p f i f f));
-DATA(insert OID = 0 ( 1262 datpath                     25 0 -1   5 0 -1 -1 f x f i f f));
+DATA(insert OID = 0 ( 1262 datistemplate    16 0  1   4 0 -1 -1 t p f c f f));
+DATA(insert OID = 0 ( 1262 datallowconn     16 0  1   5 0 -1 -1 t p f c f f));
+DATA(insert OID = 0 ( 1262 datlastsysoid    26 0  4   6 0 -1 -1 t p f i f f));
+DATA(insert OID = 0 ( 1262 datpath                     25 0 -1   7 0 -1 -1 f x f i f f));
 DATA(insert OID = 0 ( 1262 ctid                                27 0  6  -1 0 -1 -1 f p f i f f));
 DATA(insert OID = 0 ( 1262 oid                         26 0  4  -2 0 -1 -1 t p f i f f));
 DATA(insert OID = 0 ( 1262 xmin                                28 0  4  -3 0 -1 -1 t p f i f f));
index 68db583fe3a02a7d4e0e73602a85df12872bcec4..bf9a482f8afe7c300ad96ce3e044ccd87bc6c971 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_class.h,v 1.44 2000/10/24 01:38:41 tgl Exp $
+ * $Id: pg_class.h,v 1.45 2000/11/14 18:37:46 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -142,7 +142,7 @@ DATA(insert OID = 1260 (  pg_shadow 86                PGUID 0 1260 0 0 0 0 f t r 8  0 0 0 0
 DESCR("");
 DATA(insert OID = 1261 (  pg_group 87            PGUID 0 1261 0 0 0 0 f t r 3  0 0 0 0 0 f f f _null_ ));
 DESCR("");
-DATA(insert OID = 1262 (  pg_database 88         PGUID 0 1262 0 0 0 0 f t r 5  0 0 0 0 0 f f f _null_ ));
+DATA(insert OID = 1262 (  pg_database 88         PGUID 0 1262 0 0 0 0 f t r 7  0 0 0 0 0 f f f _null_ ));
 DESCR("");
 DATA(insert OID = 1264 (  pg_variable 90         PGUID 0 1264 0 0 0 0 f t s 1  0 0 0 0 0 f f f _null_ ));
 DESCR("");
index 76127094de8743fa34771c24d27ddb74b724b00c..4f8b4329ae93eeef7406d48ea9b21239332f3057 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_database.h,v 1.14 2000/11/08 16:59:50 petere Exp $
+ * $Id: pg_database.h,v 1.15 2000/11/14 18:37:46 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -36,6 +36,8 @@ CATALOG(pg_database) BOOTSTRAP
        NameData        datname;
        int4            datdba;
        int4            encoding;
+       bool            datistemplate;  /* allowed as template for CREATE DATABASE? */
+       bool            datallowconn;   /* new connections allowed? */
        Oid                     datlastsysoid;
        text            datpath;                /* VARIABLE LENGTH FIELD */
 } FormData_pg_database;
@@ -51,15 +53,17 @@ typedef FormData_pg_database *Form_pg_database;
  *             compiler constants for pg_database
  * ----------------
  */
-#define Natts_pg_database                      5       
+#define Natts_pg_database                              7
 #define Anum_pg_database_datname               1
 #define Anum_pg_database_datdba                        2
 #define Anum_pg_database_encoding              3
-#define Anum_pg_database_datlastsysoid  4
-#define Anum_pg_database_datpath               5
+#define Anum_pg_database_datistemplate  4
+#define Anum_pg_database_datallowconn  5
+#define Anum_pg_database_datlastsysoid  6
+#define Anum_pg_database_datpath               7
 
-DATA(insert OID = 1 (  template1 PGUID ENCODING 0 "" ));
-DESCR("");
+DATA(insert OID = 1 (  template1 PGUID ENCODING t t 0 "" ));
+DESCR("Default template database");
 
 #define TemplateDbOid                  1
 
index 944315035379cad4c01fd90875a789b026b0fc21..903368e3f9c1847a9627af638f1d324c5aacf1ae 100644 (file)
@@ -7,14 +7,15 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dbcommands.h,v 1.13 2000/01/26 05:58:00 momjian Exp $
+ * $Id: dbcommands.h,v 1.14 2000/11/14 18:37:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef DBCOMMANDS_H
 #define DBCOMMANDS_H
 
-extern void createdb(const char *dbname, const char *dbpath, int encoding);
+extern void createdb(const char *dbname, const char *dbpath,
+                                        const char *dbtemplate, int encoding);
 extern void dropdb(const char *dbname);
 
 #endif  /* DBCOMMANDS_H */
index b4b96b679d7cede2d1f9ab469166ca7518b39b84..0b0c2e31377dd5dffeb1121f38fb0caac6d7b929 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pg_wchar.h,v 1.22 2000/10/30 10:41:05 ishii Exp $ */
+/* $Id: pg_wchar.h,v 1.23 2000/11/14 18:37:48 tgl Exp $ */
 
 #ifndef PG_WCHAR_H
 #define PG_WCHAR_H
@@ -152,8 +152,6 @@ extern int  pg_char_to_encoding(const char *);
 
 extern int     GetDatabaseEncoding(void);
 extern void SetDatabaseEncoding(int);
-extern void SetTemplateEncoding(int);
-extern int     GetTemplateEncoding(void);
 extern unsigned short BIG5toCNS(unsigned short, unsigned char *);
 extern unsigned short CNStoBIG5(unsigned short, unsigned char);
 
index 469230e1c625091e19ed7f9e9b54557cea8c3375..a15d4c0ad85c20180d79d6d437c411a87e577b00 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.120 2000/11/12 00:37:01 tgl Exp $
+ * $Id: parsenodes.h,v 1.121 2000/11/14 18:37:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -645,9 +645,10 @@ typedef struct LoadStmt
 typedef struct CreatedbStmt
 {
        NodeTag         type;
-       char       *dbname;                     /* database to create */
-       char       *dbpath;                     /* location of database */
-       int                     encoding;               /* default encoding (see regex/pg_wchar.h) */
+       char       *dbname;                     /* name of database to create */
+       char       *dbpath;                     /* location of database (NULL = default) */
+       char       *dbtemplate;         /* template to use (NULL = default) */
+       int                     encoding;               /* MULTIBYTE encoding (-1 = use default) */
 } CreatedbStmt;
 
 /* ----------------------
index 9fd96b22803b6434ec91dd10e2e6f5eb54f91ea2..08ec85847b7f32976f4353394995edad2ad3d32e 100644 (file)
@@ -482,8 +482,8 @@ WHERE p1.aggtransfn = p2.oid AND
           (p2.pronargs = 1 AND p1.aggbasetype = 0)));
   oid  | aggname | oid |   proname   
 -------+---------+-----+-------------
- 16996 | max     | 768 | int4larger
- 17010 | min     | 769 | int4smaller
+ 16998 | max     | 768 | int4larger
+ 17012 | min     | 769 | int4smaller
 (2 rows)
 
 -- Cross-check finalfn (if present) against its entry in pg_proc.