mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-30 19:00:29 +08:00
Reimplement alternative database locations with symlinks. No changes in
user interface.
This commit is contained in:
parent
218f357d82
commit
3304341700
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.63 2000/10/28 16:20:54 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.64 2000/11/08 16:59:49 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -37,12 +35,10 @@
|
|||||||
|
|
||||||
|
|
||||||
/* non-export function prototypes */
|
/* non-export function prototypes */
|
||||||
static bool
|
static bool get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb);
|
||||||
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
|
static bool remove_dbdirs(const char * real_loc, const char * altloc);
|
||||||
get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CREATE DATABASE
|
* CREATE DATABASE
|
||||||
@ -52,8 +48,8 @@ void
|
|||||||
createdb(const char *dbname, const char *dbpath, int encoding)
|
createdb(const char *dbname, const char *dbpath, int encoding)
|
||||||
{
|
{
|
||||||
char buf[2 * MAXPGPATH + 100];
|
char buf[2 * MAXPGPATH + 100];
|
||||||
char *loc;
|
char *altloc;
|
||||||
char locbuf[512];
|
char *real_loc;
|
||||||
int ret;
|
int ret;
|
||||||
bool use_super,
|
bool use_super,
|
||||||
use_createdb;
|
use_createdb;
|
||||||
@ -77,24 +73,6 @@ createdb(const char *dbname, const char *dbpath, int encoding)
|
|||||||
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");
|
||||||
|
|
||||||
#ifdef OLD_FILE_NAMING
|
|
||||||
/* Generate directory name for the new database */
|
|
||||||
if (dbpath == NULL || strcmp(dbpath, dbname) == 0)
|
|
||||||
strcpy(locbuf, dbname);
|
|
||||||
else
|
|
||||||
snprintf(locbuf, sizeof(locbuf), "%s/%s", dbpath, dbname);
|
|
||||||
|
|
||||||
loc = ExpandDatabasePath(locbuf);
|
|
||||||
|
|
||||||
if (loc == NULL)
|
|
||||||
elog(ERROR,
|
|
||||||
"The database path '%s' is invalid. "
|
|
||||||
"This may be due to a character that is not allowed or because the chosen "
|
|
||||||
"path isn't permitted for databases", dbpath);
|
|
||||||
#else
|
|
||||||
locbuf[0] = 0; /* Avoid junk in strings */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert a new tuple into pg_database
|
* Insert a new tuple into pg_database
|
||||||
*/
|
*/
|
||||||
@ -108,13 +86,15 @@ createdb(const char *dbname, const char *dbpath, int encoding)
|
|||||||
dboid = newoid();
|
dboid = newoid();
|
||||||
|
|
||||||
/* Form tuple */
|
/* Form tuple */
|
||||||
new_record[Anum_pg_database_datname - 1] = DirectFunctionCall1(namein,
|
new_record[Anum_pg_database_datname - 1] =
|
||||||
CStringGetDatum(dbname));
|
DirectFunctionCall1(namein, CStringGetDatum(dbname));
|
||||||
new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(GetUserId());
|
new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(GetUserId());
|
||||||
new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
|
new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
|
||||||
new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(dboid); /* Save current OID val */
|
/* Save current OID val */
|
||||||
new_record[Anum_pg_database_datpath - 1] = DirectFunctionCall1(textin,
|
new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(dboid);
|
||||||
CStringGetDatum(locbuf));
|
/* 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);
|
tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
|
||||||
|
|
||||||
@ -126,9 +106,12 @@ createdb(const char *dbname, const char *dbpath, int encoding)
|
|||||||
*/
|
*/
|
||||||
heap_insert(pg_database_rel, tuple);
|
heap_insert(pg_database_rel, tuple);
|
||||||
|
|
||||||
#ifndef OLD_FILE_NAMING
|
real_loc = GetDatabasePath(tuple->t_data->t_oid);
|
||||||
loc = GetDatabasePath(tuple->t_data->t_oid);
|
altloc = resolve_alt_dbpath(dbpath, tuple->t_data->t_oid);
|
||||||
#endif
|
|
||||||
|
if (strchr(real_loc, '\'') && strchr(altloc, '\''))
|
||||||
|
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)
|
* Update indexes (there aren't any currently)
|
||||||
@ -156,41 +139,28 @@ createdb(const char *dbname, const char *dbpath, int encoding)
|
|||||||
|
|
||||||
/* Copy the template database to the new location */
|
/* Copy the template database to the new location */
|
||||||
|
|
||||||
if (mkdir(loc, S_IRWXU) != 0)
|
if (mkdir((altloc ? altloc : real_loc), S_IRWXU) != 0)
|
||||||
elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %s", loc, strerror(errno));
|
elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %s",
|
||||||
|
(altloc ? altloc : real_loc), strerror(errno));
|
||||||
|
|
||||||
#ifdef OLD_FILE_NAMING
|
if (altloc)
|
||||||
snprintf(buf, sizeof(buf), "cp %s%cbase%ctemplate1%c* '%s'",
|
|
||||||
DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, loc);
|
|
||||||
#else
|
|
||||||
{
|
{
|
||||||
char *tmpl = GetDatabasePath(TemplateDbOid);
|
if (symlink(altloc, real_loc) != 0)
|
||||||
|
elog(ERROR, "CREATE DATABASE: could not link %s to %s: %s",
|
||||||
snprintf(buf, sizeof(buf), "cp %s%c* '%s'",
|
real_loc, altloc, strerror(errno));
|
||||||
tmpl, SEP_CHAR, loc);
|
|
||||||
pfree(tmpl);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
snprintf(buf, sizeof(buf), "cp '%s'/* '%s'",
|
||||||
|
GetDatabasePath(TemplateDbOid), real_loc);
|
||||||
|
|
||||||
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 defined(sun)
|
|
||||||
if (ret != 0 && errno != ECHILD)
|
if (ret != 0 && errno != ECHILD)
|
||||||
#else
|
|
||||||
if (ret != 0)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
/* Failed, so try to clean up the created directory ... */
|
if (remove_dbdirs(real_loc, altloc))
|
||||||
snprintf(buf, sizeof(buf), "rm -rf '%s'", loc);
|
|
||||||
ret = system(buf);
|
|
||||||
#if defined(sun)
|
|
||||||
if (ret == 0 || errno == ECHILD)
|
|
||||||
#else
|
|
||||||
if (ret == 0)
|
|
||||||
#endif
|
|
||||||
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
|
#ifdef XLOG
|
||||||
@ -210,9 +180,9 @@ dropdb(const char *dbname)
|
|||||||
int4 db_owner;
|
int4 db_owner;
|
||||||
bool use_super;
|
bool use_super;
|
||||||
Oid db_id;
|
Oid db_id;
|
||||||
char *path,
|
char *altloc;
|
||||||
dbpath[MAXPGPATH],
|
char *real_loc;
|
||||||
buf[MAXPGPATH + 100];
|
char dbpath[MAXPGPATH];
|
||||||
Relation pgdbrel;
|
Relation pgdbrel;
|
||||||
HeapScanDesc pgdbscan;
|
HeapScanDesc pgdbscan;
|
||||||
ScanKeyData key;
|
ScanKeyData key;
|
||||||
@ -221,33 +191,25 @@ dropdb(const char *dbname)
|
|||||||
AssertArg(dbname);
|
AssertArg(dbname);
|
||||||
|
|
||||||
if (strcmp(dbname, "template1") == 0)
|
if (strcmp(dbname, "template1") == 0)
|
||||||
elog(ERROR, "DROP DATABASE: May not be executed on the template1 database");
|
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");
|
||||||
|
|
||||||
if (IsTransactionBlock())
|
if (IsTransactionBlock())
|
||||||
elog(ERROR, "DROP DATABASE: May not be called in a transaction block");
|
elog(ERROR, "DROP DATABASE: may not be called in a transaction block");
|
||||||
|
|
||||||
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))
|
if (!get_db_info(dbname, dbpath, &db_id, &db_owner))
|
||||||
elog(ERROR, "DROP DATABASE: Database \"%s\" does not exist", dbname);
|
elog(ERROR, "DROP DATABASE: database \"%s\" does not exist", dbname);
|
||||||
|
|
||||||
if (GetUserId() != db_owner && !use_super)
|
if (GetUserId() != db_owner && !use_super)
|
||||||
elog(ERROR, "DROP DATABASE: Permission denied");
|
elog(ERROR, "DROP DATABASE: permission denied");
|
||||||
|
|
||||||
#ifdef OLD_FILE_NAMING
|
real_loc = GetDatabasePath(db_id);
|
||||||
path = ExpandDatabasePath(dbpath);
|
altloc = resolve_alt_dbpath(dbpath, db_id);
|
||||||
if (path == NULL)
|
|
||||||
elog(ERROR,
|
|
||||||
"The database path '%s' is invalid. "
|
|
||||||
"This may be due to a character that is not allowed or because the chosen "
|
|
||||||
"path isn't permitted for databases", path);
|
|
||||||
#else
|
|
||||||
path = GetDatabasePath(db_id);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain exclusive lock on pg_database. We need this to ensure that
|
* Obtain exclusive lock on pg_database. We need this to ensure that
|
||||||
@ -266,7 +228,7 @@ dropdb(const char *dbname)
|
|||||||
if (DatabaseHasActiveBackends(db_id))
|
if (DatabaseHasActiveBackends(db_id))
|
||||||
{
|
{
|
||||||
heap_close(pgdbrel, AccessExclusiveLock);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -320,13 +282,7 @@ dropdb(const char *dbname)
|
|||||||
/*
|
/*
|
||||||
* Remove the database's subdirectory and everything in it.
|
* Remove the database's subdirectory and everything in it.
|
||||||
*/
|
*/
|
||||||
snprintf(buf, sizeof(buf), "rm -rf '%s'", path);
|
remove_dbdirs(real_loc, altloc);
|
||||||
#if defined(sun)
|
|
||||||
if (system(buf) != 0 && errno != ECHILD)
|
|
||||||
#else
|
|
||||||
if (system(buf) != 0)
|
|
||||||
#endif
|
|
||||||
elog(NOTICE, "DROP DATABASE: The database directory '%s' could not be removed", path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -426,3 +382,66 @@ get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
resolve_alt_dbpath(const char * dbpath, Oid dboid)
|
||||||
|
{
|
||||||
|
char * prefix;
|
||||||
|
char * ret;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (dbpath == NULL || dbpath[0] == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (strchr(dbpath, '/'))
|
||||||
|
{
|
||||||
|
#ifdef ALLOW_ABSOLUTE_DBPATHS
|
||||||
|
prefix = dbpath;
|
||||||
|
#else
|
||||||
|
elog(ERROR, "Absolute paths are not allowed as database locations");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* must be environment variable */
|
||||||
|
char * var = getenv(dbpath);
|
||||||
|
if (!var)
|
||||||
|
elog(ERROR, "environment variable %s not set", dbpath);
|
||||||
|
if (var[0] != '/')
|
||||||
|
elog(ERROR, "environment variable %s must be absolute path", dbpath);
|
||||||
|
prefix = var;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(prefix) + 6 + sizeof(Oid) * 8 + 1;
|
||||||
|
ret = palloc(len);
|
||||||
|
snprintf(ret, len, "%s/base/%u", prefix, dboid);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
remove_dbdirs(const char * real_loc, const char * altloc)
|
||||||
|
{
|
||||||
|
char buf[MAXPGPATH + 100];
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
if (altloc)
|
||||||
|
/* remove symlink */
|
||||||
|
if (unlink(real_loc) != 0)
|
||||||
|
{
|
||||||
|
elog(NOTICE, "could not remove '%s': %s", real_loc, strerror(errno));
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
@ -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.55 2000/11/06 15:58:46 thomas Exp $
|
* $Id: catversion.h,v 1.56 2000/11/08 16:59:50 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200011060
|
#define CATALOG_VERSION_NO 200011080
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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.13 2000/10/22 18:29:58 tgl Exp $
|
* $Id: pg_database.h,v 1.14 2000/11/08 16:59:50 petere Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -58,7 +58,7 @@ typedef FormData_pg_database *Form_pg_database;
|
|||||||
#define Anum_pg_database_datlastsysoid 4
|
#define Anum_pg_database_datlastsysoid 4
|
||||||
#define Anum_pg_database_datpath 5
|
#define Anum_pg_database_datpath 5
|
||||||
|
|
||||||
DATA(insert OID = 1 ( template1 PGUID ENCODING 0 template1 ));
|
DATA(insert OID = 1 ( template1 PGUID ENCODING 0 "" ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
|
|
||||||
#define TemplateDbOid 1
|
#define TemplateDbOid 1
|
||||||
|
Loading…
Reference in New Issue
Block a user