Commit 2cf48ca0 authored by Tom Lane's avatar Tom Lane

Extend CREATE DATABASE to allow selection of a template database to be

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!
parent 8a9315ca
<!-- <!--
$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 Postgres documentation
--> -->
...@@ -23,7 +23,10 @@ Postgres documentation ...@@ -23,7 +23,10 @@ Postgres documentation
<date>1999-12-11</date> <date>1999-12-11</date>
</refsynopsisdivinfo> </refsynopsisdivinfo>
<synopsis> <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> </synopsis>
<refsect2 id="R2-SQL-CREATEDATABASE-1"> <refsect2 id="R2-SQL-CREATEDATABASE-1">
...@@ -48,8 +51,30 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO ...@@ -48,8 +51,30 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
<term><replaceable class="parameter">dbpath</replaceable></term> <term><replaceable class="parameter">dbpath</replaceable></term>
<listitem> <listitem>
<para> <para>
An alternate location where to store the new database in the filesystem. An alternate filesystem location in which to store the new database,
See below for caveats. 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -98,11 +123,10 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO ...@@ -98,11 +123,10 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><computeroutput>ERROR: Single quotes are not allowed in database names.</computeroutput></term> <term><computeroutput>ERROR: database path may not contain single quotes</computeroutput></term>
<term><computeroutput>ERROR: Single quotes are not allowed in database paths.</computeroutput></term>
<listitem> <listitem>
<para> <para>
The database <replaceable class="parameter">name</replaceable> and The database location
<replaceable class="parameter">dbpath</replaceable> cannot contain <replaceable class="parameter">dbpath</replaceable> cannot contain
single quotes. This is required so that the shell commands that single quotes. This is required so that the shell commands that
create the database directory can execute safely. create the database directory can execute safely.
...@@ -111,18 +135,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO ...@@ -111,18 +135,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><computeroutput>ERROR: The path 'xxx' is invalid.</computeroutput></term> <term><computeroutput>ERROR: CREATE DATABASE: may not be called in a transaction block</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>
<listitem> <listitem>
<para> <para>
If you have an explicit transaction block in progress you cannot call 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 ...@@ -133,6 +146,9 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
<varlistentry> <varlistentry>
<term><computeroutput>ERROR: Unable to create database directory '<replaceable>path</replaceable>'.</computeroutput></term> <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> <term><computeroutput>ERROR: Could not initialize database directory.</computeroutput></term>
<listitem> <listitem>
<para> <para>
...@@ -169,10 +185,10 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO ...@@ -169,10 +185,10 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
command. command.
</para> </para>
<para> <para>
If the path contains a slash, the leading part is interpreted If the path name does not contain a slash, it is interpreted
as an environment variable, which must be known to the as an environment variable name, which must be known to the
server process. This way the database administrator can 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>'.) (A customary choice is, e.g., '<envar>PGDATA2</envar>'.)
If the server is compiled with <literal>ALLOW_ABSOLUTE_DBPATHS</literal> If the server is compiled with <literal>ALLOW_ABSOLUTE_DBPATHS</literal>
(not so by default), absolute path names, as identified by (not so by default), absolute path names, as identified by
...@@ -181,6 +197,29 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO ...@@ -181,6 +197,29 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> [ WITH LOCATIO
are allowed as well. are allowed as well.
</para> </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"> <refsect2 id="R2-SQL-CREATEDATABASE-3">
<refsect2info> <refsect2info>
<date>1999-12-11</date> <date>1999-12-11</date>
...@@ -221,6 +260,33 @@ comment from Olly; response from Thomas... ...@@ -221,6 +260,33 @@ comment from Olly; response from Thomas...
Not sure if the dump/reload would guarantee that Not sure if the dump/reload would guarantee that
the alternate data area gets refreshed though... 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> </refsect2>
</refsect1> </refsect1>
......
...@@ -8,12 +8,11 @@ ...@@ -8,12 +8,11 @@
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include "commands/dbcommands.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -27,6 +26,7 @@ ...@@ -27,6 +26,7 @@
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "commands/comment.h" #include "commands/comment.h"
#include "commands/dbcommands.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/sinval.h" /* for DatabaseHasActiveBackends */ #include "storage/sinval.h" /* for DatabaseHasActiveBackends */
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -35,29 +35,40 @@ ...@@ -35,29 +35,40 @@
/* non-export function prototypes */ /* 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_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 char * resolve_alt_dbpath(const char * dbpath, Oid dboid); static bool remove_dbdirs(const char *real_loc, const char *altloc);
static bool remove_dbdirs(const char * real_loc, const char * altloc);
/* /*
* CREATE DATABASE * CREATE DATABASE
*/ */
void 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 buf[2 * MAXPGPATH + 100];
char *altloc;
char *real_loc;
int ret; int ret;
bool use_super, bool use_super,
use_createdb; 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; Relation pg_database_rel;
HeapTuple tuple; HeapTuple tuple;
TupleDesc pg_database_dsc; TupleDesc pg_database_dsc;
Datum new_record[Natts_pg_database]; Datum new_record[Natts_pg_database];
char new_record_nulls[Natts_pg_database] = {' ', ' ', ' ', ' ', ' '}; char new_record_nulls[Natts_pg_database];
Oid dboid; Oid dboid;
if (!get_user_info(GetUserId(), &use_super, &use_createdb)) if (!get_user_info(GetUserId(), &use_super, &use_createdb))
...@@ -66,122 +77,195 @@ createdb(const char *dbname, const char *dbpath, int encoding) ...@@ -66,122 +77,195 @@ createdb(const char *dbname, const char *dbpath, int encoding)
if (!use_createdb && !use_super) if (!use_createdb && !use_super)
elog(ERROR, "CREATE DATABASE: permission denied"); 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 */ /* don't call this in a transaction block */
if (IsTransactionBlock()) if (IsTransactionBlock())
elog(ERROR, "CREATE DATABASE: may not be called in a transaction block"); 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); if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL))
pg_database_dsc = RelationGetDescr(pg_database_rel); elog(ERROR, "CREATE DATABASE: database \"%s\" already exists", dbname);
/* /*
* Preassign OID for pg_database tuple, so that we know current * Lookup database (template) to be cloned.
* OID counter value
*/ */
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 : ""));
tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls); 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->t_data->t_oid = dboid; /* override heap_insert */ /*
* 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);
/* If encoding is defaulted, use source's encoding */
if (encoding < 0)
encoding = src_encoding;
/* /*
* Update table * Preassign OID for pg_database tuple, so that we can compute db path.
*/ */
heap_insert(pg_database_rel, tuple); dboid = newoid();
real_loc = GetDatabasePath(tuple->t_data->t_oid); /*
altloc = resolve_alt_dbpath(dbpath, tuple->t_data->t_oid); * Compute nominal location (where we will try to access the database),
* and resolve alternate physical location if one is specified.
*/
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"); elog(ERROR, "database path may not contain single quotes");
/* ... otherwise we'd be open to shell exploits below */ /* ... otherwise we'd be open to shell exploits below */
/* #ifdef XLOG
* Update indexes (there aren't any currently) /* Try to force any dirty buffers out to disk */
*/ BufferSync();
#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 #endif
heap_close(pg_database_rel, NoLock);
/* /*
* Close virtual file descriptors so the kernel has more available for * Close virtual file descriptors so the kernel has more available for
* the mkdir() and system() calls below. * the mkdir() and system() calls below.
*/ */
closeAllVfds(); 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) if (mkdir(target_dir, S_IRWXU) != 0)
elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %s", elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %m",
(altloc ? altloc : real_loc), strerror(errno)); target_dir);
rmdir(target_dir);
if (altloc) /* Make the symlink, if needed */
if (alt_loc)
{ {
if (symlink(altloc, real_loc) != 0) if (symlink(alt_loc, nominal_loc) != 0)
elog(ERROR, "CREATE DATABASE: could not link %s to %s: %s", elog(ERROR, "CREATE DATABASE: could not link '%s' to '%s': %m",
real_loc, altloc, strerror(errno)); nominal_loc, alt_loc);
} }
snprintf(buf, sizeof(buf), "cp '%s'/* '%s'", /* Copy the template database to the new location */
GetDatabasePath(TemplateDbOid), real_loc); snprintf(buf, sizeof(buf), "cp -r '%s' '%s'", src_loc, target_dir);
ret = system(buf); ret = system(buf);
/* Some versions of SunOS seem to return ECHILD after a system() call */ /* Some versions of SunOS seem to return ECHILD after a system() call */
if (ret != 0 && errno != ECHILD) 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"); elog(ERROR, "CREATE DATABASE: could not initialize database directory");
else else
elog(ERROR, "CREATE DATABASE: could not initialize database directory; delete failed as well"); 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 #endif
}
/* Close pg_database, but keep lock till commit */
heap_close(pg_database_rel, NoLock);
}
/* /*
* DROP DATABASE * DROP DATABASE
*/ */
void void
dropdb(const char *dbname) dropdb(const char *dbname)
{ {
int4 db_owner; int4 db_owner;
bool db_istemplate;
bool use_super; bool use_super;
Oid db_id; Oid db_id;
char *altloc; char *alt_loc;
char *real_loc; char *nominal_loc;
char dbpath[MAXPGPATH]; char dbpath[MAXPGPATH];
Relation pgdbrel; Relation pgdbrel;
HeapScanDesc pgdbscan; HeapScanDesc pgdbscan;
...@@ -190,9 +274,6 @@ dropdb(const char *dbname) ...@@ -190,9 +274,6 @@ dropdb(const char *dbname)
AssertArg(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) if (strcmp(dbname, DatabaseName) == 0)
elog(ERROR, "DROP DATABASE: cannot be executed on the currently open database"); elog(ERROR, "DROP DATABASE: cannot be executed on the currently open database");
...@@ -202,15 +283,6 @@ dropdb(const char *dbname) ...@@ -202,15 +283,6 @@ dropdb(const char *dbname)
if (!get_user_info(GetUserId(), &use_super, NULL)) if (!get_user_info(GetUserId(), &use_super, NULL))
elog(ERROR, "current user name is invalid"); 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 * Obtain exclusive lock on pg_database. We need this to ensure that
* no new backend starts up in the target database while we are * no new backend starts up in the target database while we are
...@@ -222,14 +294,29 @@ dropdb(const char *dbname) ...@@ -222,14 +294,29 @@ dropdb(const char *dbname)
*/ */
pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock); 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. * Check for active backends in the target database.
*/ */
if (DatabaseHasActiveBackends(db_id, false)) if (DatabaseHasActiveBackends(db_id, false))
{
heap_close(pgdbrel, AccessExclusiveLock);
elog(ERROR, "DROP DATABASE: database \"%s\" is being accessed by other users", dbname); 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). * Find the database's tuple by OID (should be unique, we trust).
...@@ -242,8 +329,6 @@ dropdb(const char *dbname) ...@@ -242,8 +329,6 @@ dropdb(const char *dbname)
tup = heap_getnext(pgdbscan, 0); tup = heap_getnext(pgdbscan, 0);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
{ {
heap_close(pgdbrel, AccessExclusiveLock);
/* /*
* This error should never come up since the existence of the * This error should never come up since the existence of the
* database is checked earlier * database is checked earlier
...@@ -252,9 +337,6 @@ dropdb(const char *dbname) ...@@ -252,9 +337,6 @@ dropdb(const char *dbname)
dbname); dbname);
} }
/* Delete any comments associated with the database */
DeleteComments(db_id);
/* Remove the database's tuple from pg_database */ /* Remove the database's tuple from pg_database */
heap_delete(pgdbrel, &tup->t_self, NULL); heap_delete(pgdbrel, &tup->t_self, NULL);
...@@ -266,6 +348,9 @@ dropdb(const char *dbname) ...@@ -266,6 +348,9 @@ dropdb(const char *dbname)
*/ */
heap_close(pgdbrel, NoLock); 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. * Drop pages for this database that are in the shared buffer cache.
* This is important to ensure that no remaining backend tries to * This is important to ensure that no remaining backend tries to
...@@ -273,16 +358,10 @@ dropdb(const char *dbname) ...@@ -273,16 +358,10 @@ dropdb(const char *dbname)
*/ */
DropBuffers(db_id); 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 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) ...@@ -292,28 +371,32 @@ dropdb(const char *dbname)
*/ */
static bool 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; Relation relation;
HeapTuple tuple;
ScanKeyData scanKey; ScanKeyData scanKey;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple;
AssertArg(name); 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, ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
F_NAMEEQ, NameGetDatum(name)); F_NAMEEQ, NameGetDatum(name));
scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scanKey); scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scanKey);
if (!HeapScanIsValid(scan)) if (!HeapScanIsValid(scan))
elog(ERROR, "Cannot begin scan of %s.", DatabaseRelationName); elog(ERROR, "Cannot begin scan of %s", DatabaseRelationName);
tuple = heap_getnext(scan, 0); tuple = heap_getnext(scan, 0);
if (HeapTupleIsValid(tuple)) if (HeapTupleIsValid(tuple))
{ {
Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
text *tmptext; text *tmptext;
bool isnull; bool isnull;
...@@ -322,22 +405,23 @@ get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP) ...@@ -322,22 +405,23 @@ get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP)
*dbIdP = tuple->t_data->t_oid; *dbIdP = tuple->t_data->t_oid;
/* uid of the owner */ /* uid of the owner */
if (ownerIdP) if (ownerIdP)
{ *ownerIdP = dbform->datdba;
*ownerIdP = (int4) heap_getattr(tuple, /* multibyte encoding */
Anum_pg_database_datdba, if (encodingP)
RelationGetDescr(relation), *encodingP = dbform->encoding;
&isnull); /* allowed as template? */
if (isnull) if (dbIsTemplateP)
*ownerIdP = -1; /* hopefully no one has that id already ;) */ *dbIsTemplateP = dbform->datistemplate;
} /* last system OID used in database */
if (dbLastSysOidP)
*dbLastSysOidP = dbform->datlastsysoid;
/* database path (as registered in pg_database) */ /* database path (as registered in pg_database) */
if (dbpath) if (dbpath)
{ {
tmptext = (text *) heap_getattr(tuple, tmptext = DatumGetTextP(heap_getattr(tuple,
Anum_pg_database_datpath, Anum_pg_database_datpath,
RelationGetDescr(relation), RelationGetDescr(relation),
&isnull); &isnull));
if (!isnull) if (!isnull)
{ {
Assert(VARSIZE(tmptext) - VARHDRSZ < MAXPGPATH); Assert(VARSIZE(tmptext) - VARHDRSZ < MAXPGPATH);
...@@ -349,16 +433,9 @@ get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP) ...@@ -349,16 +433,9 @@ get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP)
strcpy(dbpath, ""); strcpy(dbpath, "");
} }
} }
else
{
if (dbIdP)
*dbIdP = InvalidOid;
}
heap_endscan(scan); heap_endscan(scan);
heap_close(relation, AccessShareLock);
/* We will keep the lock on the relation until end of transaction. */
heap_close(relation, NoLock);
return HeapTupleIsValid(tuple); return HeapTupleIsValid(tuple);
} }
...@@ -396,6 +473,8 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid) ...@@ -396,6 +473,8 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
if (strchr(dbpath, '/')) if (strchr(dbpath, '/'))
{ {
if (dbpath[0] != '/')
elog(ERROR, "Relative paths are not allowed as database locations");
#ifndef ALLOW_ABSOLUTE_DBPATHS #ifndef ALLOW_ABSOLUTE_DBPATHS
elog(ERROR, "Absolute paths are not allowed as database locations"); elog(ERROR, "Absolute paths are not allowed as database locations");
#endif #endif
...@@ -406,9 +485,9 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid) ...@@ -406,9 +485,9 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
/* must be environment variable */ /* must be environment variable */
char * var = getenv(dbpath); char * var = getenv(dbpath);
if (!var) if (!var)
elog(ERROR, "environment variable %s not set", dbpath); elog(ERROR, "Postmaster environment variable '%s' not set", dbpath);
if (var[0] != '/') 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; prefix = var;
} }
...@@ -421,24 +500,36 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid) ...@@ -421,24 +500,36 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
static bool 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]; char buf[MAXPGPATH + 100];
bool success = true; 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 */ /* 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; 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) if (system(buf) != 0 && errno != ECHILD)
{ {
elog(NOTICE, "database directory '%s' could not be removed", elog(NOTICE, "database directory '%s' could not be removed",
altloc ? altloc : real_loc); target_dir);
success = false; success = false;
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -2231,6 +2231,8 @@ _copyCreatedbStmt(CreatedbStmt *from)
newnode->dbname = pstrdup(from->dbname); newnode->dbname = pstrdup(from->dbname);
if (from->dbpath) if (from->dbpath)
newnode->dbpath = pstrdup(from->dbpath); newnode->dbpath = pstrdup(from->dbpath);
if (from->dbtemplate)
newnode->dbtemplate = pstrdup(from->dbtemplate);
newnode->encoding = from->encoding; newnode->encoding = from->encoding;
return newnode; return newnode;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -1087,6 +1087,8 @@ _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
return false; return false;
if (!equalstr(a->dbpath, b->dbpath)) if (!equalstr(a->dbpath, b->dbpath))
return false; return false;
if (!equalstr(a->dbtemplate, b->dbtemplate))
return false;
if (a->encoding != b->encoding) if (a->encoding != b->encoding)
return false; return false;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -56,8 +56,8 @@ ...@@ -56,8 +56,8 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#else #else
#define GetTemplateEncoding() 0 /* SQL_ASCII */ #define GetStandardEncoding() 0 /* SQL_ASCII */
#define GetTemplateEncodingName() "SQL_ASCII" #define GetStandardEncodingName() "SQL_ASCII"
#endif #endif
extern List *parsetree; /* final parse result is delivered here */ extern List *parsetree; /* final parse result is delivered here */
...@@ -146,8 +146,7 @@ static void doNegateFloat(Value *v); ...@@ -146,8 +146,7 @@ static void doNegateFloat(Value *v);
%type <node> alter_column_action %type <node> alter_column_action
%type <ival> drop_behavior %type <ival> drop_behavior
%type <str> createdb_opt_location %type <list> createdb_opt_list, createdb_opt_item
%type <ival> createdb_opt_encoding
%type <ival> opt_lock, lock_type %type <ival> opt_lock, lock_type
%type <boolean> opt_lmode, opt_force %type <boolean> opt_lmode, opt_force
...@@ -347,7 +346,7 @@ static void doNegateFloat(Value *v); ...@@ -347,7 +346,7 @@ static void doNegateFloat(Value *v);
OFFSET, OIDS, OPERATOR, OWNER, PASSWORD, PROCEDURAL, OFFSET, OIDS, OPERATOR, OWNER, PASSWORD, PROCEDURAL,
REINDEX, RENAME, RESET, RETURNS, ROW, RULE, REINDEX, RENAME, RESET, RETURNS, ROW, RULE,
SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID, 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 UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
/* The grammar thinks these are keywords, but they are not in the keywords.c /* The grammar thinks these are keywords, but they are not in the keywords.c
...@@ -687,7 +686,8 @@ CreateSchemaStmt: CREATE SCHEMA UserId ...@@ -687,7 +686,8 @@ CreateSchemaStmt: CREATE SCHEMA UserId
CreatedbStmt *n = makeNode(CreatedbStmt); CreatedbStmt *n = makeNode(CreatedbStmt);
n->dbname = $3; n->dbname = $3;
n->dbpath = NULL; n->dbpath = NULL;
n->encoding = GetTemplateEncoding(); n->dbtemplate = NULL;
n->encoding = -1;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -2924,16 +2924,34 @@ LoadStmt: LOAD file_name ...@@ -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); CreatedbStmt *n = makeNode(CreatedbStmt);
List *l;
if ($5 == NULL && $6 == -1)
elog(ERROR, "CREATE DATABASE WITH requires at least one option");
n->dbname = $3; n->dbname = $3;
n->dbpath = $5; /* set default options */
n->encoding = ($6 == -1) ? GetTemplateEncoding() : $6; 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; $$ = (Node *)n;
} }
| CREATE DATABASE database_name | CREATE DATABASE database_name
...@@ -2941,27 +2959,51 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb ...@@ -2941,27 +2959,51 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb
CreatedbStmt *n = makeNode(CreatedbStmt); CreatedbStmt *n = makeNode(CreatedbStmt);
n->dbname = $3; n->dbname = $3;
n->dbpath = NULL; n->dbpath = NULL;
n->encoding = GetTemplateEncoding(); n->dbtemplate = NULL;
n->encoding = -1;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
createdb_opt_location: LOCATION '=' Sconst { $$ = $3; } createdb_opt_list: createdb_opt_item
| LOCATION '=' DEFAULT { $$ = NULL; } { $$ = makeList1($1); }
| /*EMPTY*/ { $$ = NULL; } | 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 #ifdef MULTIBYTE
$$ = pg_char_to_encoding($3); encoding = pg_char_to_encoding($3);
if ($$ == -1) if (encoding == -1)
elog(ERROR, "%s is not a valid encoding name", $3); elog(ERROR, "%s is not a valid encoding name", $3);
#else #else
if (strcasecmp($3, GetTemplateEncodingName()) != 0) if (strcasecmp($3, GetStandardEncodingName()) != 0)
elog(ERROR, "Multi-byte support is not enabled"); elog(ERROR, "Multi-byte support is not enabled");
$$ = GetTemplateEncoding(); encoding = GetStandardEncoding();
#endif #endif
$$ = lconsi(3, makeListi1(encoding));
} }
| ENCODING '=' Iconst | ENCODING '=' Iconst
{ {
...@@ -2969,18 +3011,14 @@ createdb_opt_encoding: ENCODING '=' Sconst ...@@ -2969,18 +3011,14 @@ createdb_opt_encoding: ENCODING '=' Sconst
if (!pg_get_encent_by_encoding($3)) if (!pg_get_encent_by_encoding($3))
elog(ERROR, "%d is not a valid encoding code", $3); elog(ERROR, "%d is not a valid encoding code", $3);
#else #else
if ($3 != GetTemplateEncoding()) if ($3 != GetStandardEncoding())
elog(ERROR, "Multi-byte support is not enabled"); elog(ERROR, "Multi-byte support is not enabled");
#endif #endif
$$ = $3; $$ = lconsi(3, makeListi1($3));
} }
| ENCODING '=' DEFAULT | ENCODING '=' DEFAULT
{ {
$$ = GetTemplateEncoding(); $$ = lconsi(3, makeListi1(-1));
}
| /*EMPTY*/
{
$$ = -1;
} }
; ;
...@@ -5495,6 +5533,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; } ...@@ -5495,6 +5533,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; }
| STDOUT { $$ = "stdout"; } | STDOUT { $$ = "stdout"; }
| SYSID { $$ = "sysid"; } | SYSID { $$ = "sysid"; }
| TEMP { $$ = "temp"; } | TEMP { $$ = "temp"; }
| TEMPLATE { $$ = "template"; }
| TEMPORARY { $$ = "temporary"; } | TEMPORARY { $$ = "temporary"; }
| TIMEZONE_HOUR { $$ = "timezone_hour"; } | TIMEZONE_HOUR { $$ = "timezone_hour"; }
| TIMEZONE_MINUTE { $$ = "timezone_minute"; } | TIMEZONE_MINUTE { $$ = "timezone_minute"; }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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[] = { ...@@ -247,6 +247,7 @@ static ScanKeyword ScanKeywords[] = {
{"sysid", SYSID}, {"sysid", SYSID},
{"table", TABLE}, {"table", TABLE},
{"temp", TEMP}, {"temp", TEMP},
{"template", TEMPLATE},
{"temporary", TEMPORARY}, {"temporary", TEMPORARY},
{"then", THEN}, {"then", THEN},
{"time", TIME}, {"time", TIME},
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -279,14 +279,8 @@ checkDataDir(const char *checkdir) ...@@ -279,14 +279,8 @@ checkDataDir(const char *checkdir)
exit(2); exit(2);
} }
#ifdef OLD_FILE_NAMING snprintf(path, sizeof(path), "%s%cglobal%cpg_control",
snprintf(path, sizeof(path), "%s%cbase%ctemplate1%cpg_class", checkdir, SEP_CHAR, SEP_CHAR);
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
fp = AllocateFile(path, PG_BINARY_R); fp = AllocateFile(path, PG_BINARY_R);
if (fp == NULL) if (fp == NULL)
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -604,7 +604,8 @@ ProcessUtility(Node *parsetree,
set_ps_display(commandTag = "CREATE DATABASE"); set_ps_display(commandTag = "CREATE DATABASE");
createdb(stmt->dbname, stmt->dbpath, stmt->encoding); createdb(stmt->dbname, stmt->dbpath,
stmt->dbtemplate, stmt->encoding);
} }
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -79,6 +79,7 @@ ReverifyMyDatabase(const char *name)
HeapScanDesc pgdbscan; HeapScanDesc pgdbscan;
ScanKeyData key; ScanKeyData key;
HeapTuple tup; HeapTuple tup;
Form_pg_database dbform;
/* /*
* Because we grab AccessShareLock here, we can be sure that destroydb * Because we grab AccessShareLock here, we can be sure that destroydb
...@@ -106,25 +107,24 @@ ReverifyMyDatabase(const char *name) ...@@ -106,25 +107,24 @@ ReverifyMyDatabase(const char *name)
*/ */
DropBuffers(MyDatabaseId); DropBuffers(MyDatabaseId);
/* Now I can commit hara-kiri with a clear conscience... */ /* 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); 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 * 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 * encoding info out of the pg_database tuple.
* "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.)
*/ */
#ifdef MULTIBYTE #ifdef MULTIBYTE
SetDatabaseEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding); SetDatabaseEncoding(dbform->encoding);
SetTemplateEncoding(((Form_pg_database) GETSTRUCT(tup))->encoding);
#endif #endif
heap_endscan(pgdbscan); heap_endscan(pgdbscan);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* client encoding and server internal encoding. * client encoding and server internal encoding.
* (currently mule internal code (mic) is used) * (currently mule internal code (mic) is used)
* Tatsuo Ishii * 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" #include "postgres.h"
...@@ -271,6 +271,7 @@ pg_mbcliplen(const unsigned char *mbstr, int len, int limit) ...@@ -271,6 +271,7 @@ pg_mbcliplen(const unsigned char *mbstr, int len, int limit)
* fuctions for utils/init * fuctions for utils/init
*/ */
static int DatabaseEncoding = MULTIBYTE; static int DatabaseEncoding = MULTIBYTE;
void void
SetDatabaseEncoding(int encoding) SetDatabaseEncoding(int encoding)
{ {
...@@ -289,17 +290,3 @@ getdatabaseencoding(PG_FUNCTION_ARGS) ...@@ -289,17 +290,3 @@ getdatabaseencoding(PG_FUNCTION_ARGS)
{ {
PG_RETURN_NAME(pg_encoding_to_char(DatabaseEncoding)); 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);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -186,7 +186,7 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
max = PageGetMaxOffsetNumber(pg); max = PageGetMaxOffsetNumber(pg);
/* look at each tuple on the page */ /* look at each tuple on the page */
for (i = 0; i <= max; i++) for (i = 0; i < max; i++)
{ {
int offset; int offset;
...@@ -221,8 +221,11 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path) ...@@ -221,8 +221,11 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
* database OID from a flat file, handled the same way we * database OID from a flat file, handled the same way we
* handle the password relation? * handle the password relation?
*/ */
if (TransactionIdIsValid((TransactionId) tup.t_data->t_xmax)) if (tup.t_data->t_infomask & HEAP_XMIN_INVALID)
continue; 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. * Okay, see if this is the one we want.
...@@ -241,6 +244,10 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path) ...@@ -241,6 +244,10 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
} }
} }
/* failed to find it... */
*db_id = InvalidOid;
*path = '\0';
done: done:
close(dbfd); close(dbfd);
pfree(pg); pfree(pg);
......
...@@ -7,15 +7,16 @@ ...@@ -7,15 +7,16 @@
# #
# To create the database cluster, we create the directory that contains # To create the database cluster, we create the directory that contains
# all its data, create the files that hold the global tables, create # all its data, create the files that hold the global tables, create
# a few other control files for it, and create one database: the # a few other control files for it, and create two databases: the
# template database. # template0 and template1 databases.
# #
# The template database is an ordinary PostgreSQL database. Its data # The template databases are ordinary PostgreSQL databases. template0
# never changes, though. It exists to make it easy for PostgreSQL to # is never supposed to change after initdb, whereas template1 can be
# create other databases -- it just copies. # 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 # 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 # To create all those things, we run the postgres (backend) program and
# feed it data from the bki files that were installed. # feed it data from the bki files that were installed.
...@@ -23,7 +24,7 @@ ...@@ -23,7 +24,7 @@
# #
# Copyright (c) 1994, Regents of the University of California # 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 ...@@ -203,7 +204,7 @@ do
;; ;;
--template|-t) --template|-t)
template_only=yes 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. # The sysid of the database superuser. Can be freely changed.
--sysid|-i) --sysid|-i)
...@@ -277,7 +278,7 @@ if [ "$usage" ]; then ...@@ -277,7 +278,7 @@ if [ "$usage" ]; then
echo " -i, --sysid SYSID Database sysid for the superuser" echo " -i, --sysid SYSID Database sysid for the superuser"
echo "Less commonly used options: " echo "Less commonly used options: "
echo " -L DIRECTORY Where to find the input files" 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 " -d, --debug Generate lots of debugging output"
echo " -n, --noclean Do not clean up after errors" echo " -n, --noclean Do not clean up after errors"
echo echo
...@@ -451,7 +452,7 @@ fi ...@@ -451,7 +452,7 @@ fi
BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG" BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG"
FIRSTRUN="-boot -x1 -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" [ "$debug" = yes ] && echo "Running: $PGPATH/postgres $FIRSTRUN template1"
cat "$TEMPLATE1_BKI" \ cat "$TEMPLATE1_BKI" \
...@@ -465,6 +466,10 @@ echo $short_version > "$PGDATA"/base/1/PG_VERSION || exit_nicely ...@@ -465,6 +466,10 @@ echo $short_version > "$PGDATA"/base/1/PG_VERSION || exit_nicely
########################################################################## ##########################################################################
# #
# CREATE GLOBAL TABLES # 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 ] if [ "$template_only" != yes ]
then then
...@@ -491,7 +496,7 @@ fi ...@@ -491,7 +496,7 @@ fi
# #
# CREATE VIEWS and other things # CREATE VIEWS and other things
echo echo "Initializing pg_shadow."
PGSQL_OPT="-o /dev/null -O -F -D$PGDATA" PGSQL_OPT="-o /dev/null -O -F -D$PGDATA"
...@@ -532,6 +537,7 @@ fi ...@@ -532,6 +537,7 @@ fi
echo "Enabling unlimited row width for system tables." echo "Enabling unlimited row width for system tables."
echo "ALTER TABLE pg_attrdef CREATE TOAST TABLE" \ echo "ALTER TABLE pg_attrdef CREATE TOAST TABLE" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "ALTER TABLE pg_description CREATE TOAST TABLE" \ echo "ALTER TABLE pg_description CREATE TOAST TABLE" \
...@@ -546,7 +552,8 @@ echo "ALTER TABLE pg_statistic CREATE TOAST TABLE" \ ...@@ -546,7 +552,8 @@ echo "ALTER TABLE pg_statistic CREATE TOAST TABLE" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_user." echo "Creating system views."
echo "CREATE VIEW pg_user AS \ echo "CREATE VIEW pg_user AS \
SELECT \ SELECT \
usename, \ usename, \
...@@ -560,7 +567,6 @@ echo "CREATE VIEW pg_user AS \ ...@@ -560,7 +567,6 @@ echo "CREATE VIEW pg_user AS \
FROM pg_shadow" \ FROM pg_shadow" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_rules."
echo "CREATE VIEW pg_rules AS \ echo "CREATE VIEW pg_rules AS \
SELECT \ SELECT \
C.relname AS tablename, \ C.relname AS tablename, \
...@@ -571,7 +577,6 @@ echo "CREATE VIEW pg_rules AS \ ...@@ -571,7 +577,6 @@ echo "CREATE VIEW pg_rules AS \
AND C.oid = R.ev_class;" \ AND C.oid = R.ev_class;" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_views."
echo "CREATE VIEW pg_views AS \ echo "CREATE VIEW pg_views AS \
SELECT \ SELECT \
C.relname AS viewname, \ C.relname AS viewname, \
...@@ -585,7 +590,6 @@ echo "CREATE VIEW pg_views AS \ ...@@ -585,7 +590,6 @@ echo "CREATE VIEW pg_views AS \
)" \ )" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_tables."
echo "CREATE VIEW pg_tables AS \ echo "CREATE VIEW pg_tables AS \
SELECT \ SELECT \
C.relname AS tablename, \ C.relname AS tablename, \
...@@ -601,7 +605,6 @@ echo "CREATE VIEW pg_tables AS \ ...@@ -601,7 +605,6 @@ echo "CREATE VIEW pg_tables AS \
)" \ )" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Creating view pg_indexes."
echo "CREATE VIEW pg_indexes AS \ echo "CREATE VIEW pg_indexes AS \
SELECT \ SELECT \
C.relname AS tablename, \ C.relname AS tablename, \
...@@ -622,14 +625,27 @@ cat $TEMPFILE \ ...@@ -622,14 +625,27 @@ cat $TEMPFILE \
rm -f "$TEMPFILE" || exit_nicely rm -f "$TEMPFILE" || exit_nicely
echo "Setting lastsysoid." echo "Setting lastsysoid."
echo "Update pg_database Set datlastsysoid = (Select max(oid) From pg_description) \ echo "UPDATE pg_database SET \
Where datname = 'template1'" \ datistemplate = 't', \
datlastsysoid = (SELECT max(oid) FROM pg_description) \
WHERE datname = 'template1'" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "Vacuuming database." echo "Vacuuming database."
echo "VACUUM ANALYZE" \ echo "VACUUM ANALYZE" \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely | "$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
########################################################################## ##########################################################################
# #
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* *
* *
* IDENTIFICATION * 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 * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
* *
...@@ -129,6 +129,8 @@ ...@@ -129,6 +129,8 @@
#include "pg_dump.h" #include "pg_dump.h"
#include "pg_backup.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 dumpComment(Archive *outfile, const char *target, const char *oid);
static void dumpSequence(Archive *fout, TableInfo tbinfo); static void dumpSequence(Archive *fout, TableInfo tbinfo);
static void dumpACL(Archive *fout, TableInfo tbinfo); static void dumpACL(Archive *fout, TableInfo tbinfo);
...@@ -140,7 +142,7 @@ static char *checkForQuote(const char *s); ...@@ -140,7 +142,7 @@ static char *checkForQuote(const char *s);
static void clearTableInfo(TableInfo *, int); static void clearTableInfo(TableInfo *, int);
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i, static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
TypeInfo *tinfo, int numTypes); TypeInfo *tinfo, int numTypes);
static int findLastBuiltinOid(const char*); static Oid findLastBuiltinOid(const char*);
static void setMaxOid(Archive *fout); static void setMaxOid(Archive *fout);
static void AddAcl(char *aclbuf, const char *keyword); static void AddAcl(char *aclbuf, const char *keyword);
...@@ -156,7 +158,7 @@ extern int optind, ...@@ -156,7 +158,7 @@ extern int optind,
/* global decls */ /* global decls */
bool g_verbose; /* User wants verbose narration of our bool g_verbose; /* User wants verbose narration of our
* activities. */ * 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 */ Archive *g_fout; /* the script file */
PGconn *g_conn; /* the database connection */ PGconn *g_conn; /* the database connection */
...@@ -2784,7 +2786,7 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs, ...@@ -2784,7 +2786,7 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
{ {
/* skip all the builtin types */ /* skip all the builtin types */
if (atoi(tinfo[i].oid) < g_last_builtin_oid) if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
continue; continue;
/* skip relation types */ /* skip relation types */
...@@ -2899,7 +2901,7 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs, ...@@ -2899,7 +2901,7 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
for (i = 0; i < ntups; i++) 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) if (lanoid <= g_last_builtin_oid)
continue; continue;
...@@ -3127,7 +3129,7 @@ dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators, ...@@ -3127,7 +3129,7 @@ dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
resetPQExpBuffer(sort2); resetPQExpBuffer(sort2);
/* skip all the builtin oids */ /* skip all the builtin oids */
if (atoi(oprinfo[i].oid) < g_last_builtin_oid) if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
continue; continue;
/* /*
...@@ -3222,7 +3224,7 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs, ...@@ -3222,7 +3224,7 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
resetPQExpBuffer(details); resetPQExpBuffer(details);
/* skip all the builtin oids */ /* skip all the builtin oids */
if (atoi(agginfo[i].oid) < g_last_builtin_oid) if (atooid(agginfo[i].oid) <= g_last_builtin_oid)
continue; continue;
appendPQExpBuffer(details, appendPQExpBuffer(details,
...@@ -3907,12 +3909,12 @@ setMaxOid(Archive *fout) ...@@ -3907,12 +3909,12 @@ setMaxOid(Archive *fout)
* we do this by retrieving datlastsysoid from the pg_database entry for this database, * we do this by retrieving datlastsysoid from the pg_database entry for this database,
*/ */
static int static Oid
findLastBuiltinOid(const char* dbname) findLastBuiltinOid(const char* dbname)
{ {
PGresult *res; PGresult *res;
int ntups; int ntups;
int last_oid; Oid last_oid;
PQExpBuffer query = createPQExpBuffer(); PQExpBuffer query = createPQExpBuffer();
resetPQExpBuffer(query); resetPQExpBuffer(query);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
* *
...@@ -177,7 +177,7 @@ typedef struct _oprInfo ...@@ -177,7 +177,7 @@ typedef struct _oprInfo
/* global decls */ /* global decls */
extern bool g_force_quotes; /* double-quotes for identifiers flag */ extern bool g_force_quotes; /* double-quotes for identifiers flag */
extern bool g_verbose; /* verbose 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 */ extern Archive *g_fout; /* the script file */
/* placeholders for comment starting and ending delimiters */ /* placeholders for comment starting and ending delimiters */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# and "pg_group" tables, which belong to the whole installation rather # and "pg_group" tables, which belong to the whole installation rather
# than any one individual database. # 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` CMDNAME=`basename $0`
...@@ -151,7 +151,7 @@ echo "${BS}connect template1" ...@@ -151,7 +151,7 @@ echo "${BS}connect template1"
# #
# Dump users (but not the user created by initdb) # 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 echo
$PSQL -d template1 -At <<__END__ $PSQL -d template1 -At <<__END__
...@@ -163,7 +163,7 @@ SELECT ...@@ -163,7 +163,7 @@ SELECT
|| CASE WHEN valuntil IS NOT NULL THEN ' VALID UNTIL '''::text || CASE WHEN valuntil IS NOT NULL THEN ' VALID UNTIL '''::text
|| CAST(valuntil AS TIMESTAMP) || '''' ELSE '' END || ';' || CAST(valuntil AS TIMESTAMP) || '''' ELSE '' END || ';'
FROM pg_shadow FROM pg_shadow
WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template1'); WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');
__END__ __END__
echo echo
...@@ -187,39 +187,25 @@ done ...@@ -187,39 +187,25 @@ done
test "$accounts_only" = yes && exit 0 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. # 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 ' ' \ $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';" | \ -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 DBPATH; do while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do
echo echo
echo "--" echo "--"
echo "-- Database $DATABASE" echo "-- Database $DATABASE"
echo "--" echo "--"
echo "${BS}connect template1 $DBOWNER" echo "${BS}connect template1 $DBOWNER"
if [ "$cleanschema" = yes ] ; then if [ "$cleanschema" = yes -a "$DATABASE" != template1 ] ; then
echo "DROP DATABASE \"$DATABASE\";" echo "DROP DATABASE \"$DATABASE\";"
fi fi
createdbcmd="CREATE DATABASE \"$DATABASE\"" if [ "$DATABASE" != template1 ] ; then
if [ x"$DBPATH" != x"" ] || [ x"$MULTIBYTE" != x"" ]; then createdbcmd="CREATE DATABASE \"$DATABASE\" WITH TEMPLATE = template0"
createdbcmd="$createdbcmd WITH"
fi
if [ x"$DBPATH" != x"" ] ; then if [ x"$DBPATH" != x"" ] ; then
createdbcmd="$createdbcmd LOCATION = '$DBPATH'" createdbcmd="$createdbcmd LOCATION = '$DBPATH'"
fi fi
...@@ -227,6 +213,7 @@ while read DATABASE DBOWNER ENCODING DBPATH; do ...@@ -227,6 +213,7 @@ while read DATABASE DBOWNER ENCODING DBPATH; do
createdbcmd="$createdbcmd ENCODING = '$ENCODING'" createdbcmd="$createdbcmd ENCODING = '$ENCODING'"
fi fi
echo "$createdbcmd;" echo "$createdbcmd;"
fi
echo "${BS}connect $DATABASE $DBOWNER" echo "${BS}connect $DATABASE $DBOWNER"
$PGDUMP "$DATABASE" $PGDUMP "$DATABASE"
...@@ -234,6 +221,9 @@ while read DATABASE DBOWNER ENCODING DBPATH; do ...@@ -234,6 +221,9 @@ while read DATABASE DBOWNER ENCODING DBPATH; do
echo "pg_dump failed on $DATABASE, exiting" 1>&2 echo "pg_dump failed on $DATABASE, exiting" 1>&2
exit 1 exit 1
fi fi
if [ x"$ISTEMPLATE" = xt ] ; then
echo "UPDATE pg_database SET datistemplate = 't' WHERE datname = '$DATABASE';"
fi
done done
exit 0 exit 0
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200011112 #define CATALOG_VERSION_NO 200011131
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * 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)); ...@@ -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 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 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 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 datistemplate 16 0 1 4 0 -1 -1 t p f c 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 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 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 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)); DATA(insert OID = 0 ( 1262 xmin 28 0 4 -3 0 -1 -1 t p f i f f));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * 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 ...@@ -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(""); 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_ )); 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(""); 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(""); 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_ )); 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(""); DESCR("");
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -36,6 +36,8 @@ CATALOG(pg_database) BOOTSTRAP ...@@ -36,6 +36,8 @@ CATALOG(pg_database) BOOTSTRAP
NameData datname; NameData datname;
int4 datdba; int4 datdba;
int4 encoding; int4 encoding;
bool datistemplate; /* allowed as template for CREATE DATABASE? */
bool datallowconn; /* new connections allowed? */
Oid datlastsysoid; Oid datlastsysoid;
text datpath; /* VARIABLE LENGTH FIELD */ text datpath; /* VARIABLE LENGTH FIELD */
} FormData_pg_database; } FormData_pg_database;
...@@ -51,15 +53,17 @@ typedef FormData_pg_database *Form_pg_database; ...@@ -51,15 +53,17 @@ typedef FormData_pg_database *Form_pg_database;
* compiler constants for 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_datname 1
#define Anum_pg_database_datdba 2 #define Anum_pg_database_datdba 2
#define Anum_pg_database_encoding 3 #define Anum_pg_database_encoding 3
#define Anum_pg_database_datlastsysoid 4 #define Anum_pg_database_datistemplate 4
#define Anum_pg_database_datpath 5 #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 "" )); DATA(insert OID = 1 ( template1 PGUID ENCODING t t 0 "" ));
DESCR(""); DESCR("Default template database");
#define TemplateDbOid 1 #define TemplateDbOid 1
......
...@@ -7,14 +7,15 @@ ...@@ -7,14 +7,15 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef DBCOMMANDS_H
#define 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); extern void dropdb(const char *dbname);
#endif /* DBCOMMANDS_H */ #endif /* DBCOMMANDS_H */
/* $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 #ifndef PG_WCHAR_H
#define PG_WCHAR_H #define PG_WCHAR_H
...@@ -152,8 +152,6 @@ extern int pg_char_to_encoding(const char *); ...@@ -152,8 +152,6 @@ extern int pg_char_to_encoding(const char *);
extern int GetDatabaseEncoding(void); extern int GetDatabaseEncoding(void);
extern void SetDatabaseEncoding(int); extern void SetDatabaseEncoding(int);
extern void SetTemplateEncoding(int);
extern int GetTemplateEncoding(void);
extern unsigned short BIG5toCNS(unsigned short, unsigned char *); extern unsigned short BIG5toCNS(unsigned short, unsigned char *);
extern unsigned short CNStoBIG5(unsigned short, unsigned char); extern unsigned short CNStoBIG5(unsigned short, unsigned char);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -645,9 +645,10 @@ typedef struct LoadStmt
typedef struct CreatedbStmt typedef struct CreatedbStmt
{ {
NodeTag type; NodeTag type;
char *dbname; /* database to create */ char *dbname; /* name of database to create */
char *dbpath; /* location of database */ char *dbpath; /* location of database (NULL = default) */
int encoding; /* default encoding (see regex/pg_wchar.h) */ char *dbtemplate; /* template to use (NULL = default) */
int encoding; /* MULTIBYTE encoding (-1 = use default) */
} CreatedbStmt; } CreatedbStmt;
/* ---------------------- /* ----------------------
......
...@@ -482,8 +482,8 @@ WHERE p1.aggtransfn = p2.oid AND ...@@ -482,8 +482,8 @@ WHERE p1.aggtransfn = p2.oid AND
(p2.pronargs = 1 AND p1.aggbasetype = 0))); (p2.pronargs = 1 AND p1.aggbasetype = 0)));
oid | aggname | oid | proname oid | aggname | oid | proname
-------+---------+-----+------------- -------+---------+-----+-------------
16996 | max | 768 | int4larger 16998 | max | 768 | int4larger
17010 | min | 769 | int4smaller 17012 | min | 769 | int4smaller
(2 rows) (2 rows)
-- Cross-check finalfn (if present) against its entry in pg_proc. -- Cross-check finalfn (if present) against its entry in pg_proc.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment