From 46a28f1b14ee9d42cdec82d24c962a1274bbd076 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 13 Jan 2000 18:26:18 +0000 Subject: [PATCH] Fixed everything in and surrounding createdb and dropdb to make it more error-proof. Rearranged some old code and removed dead sections. --- src/backend/catalog/aclchk.c | 19 +- src/backend/commands/dbcommands.c | 477 ++++++++++++++---------------- src/backend/parser/gram.y | 104 ++++--- src/backend/storage/smgr/md.c | 6 +- src/backend/tcop/utility.c | 6 +- src/backend/utils/init/miscinit.c | 194 ++---------- src/backend/utils/init/postinit.c | 300 +++++-------------- src/backend/utils/misc/database.c | 135 +++------ src/backend/utils/mmgr/palloc.c | 4 +- src/include/c.h | 3 +- src/include/commands/dbcommands.h | 15 +- src/include/miscadmin.h | 40 ++- src/include/utils/elog.h | 8 +- src/include/utils/palloc.h | 4 +- 14 files changed, 473 insertions(+), 842 deletions(-) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index ad767e7424..e5fcf1434c 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.32 1999/11/24 16:52:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.33 2000/01/13 18:26:04 petere Exp $ * * NOTES * See acl.h. @@ -358,23 +358,6 @@ pg_aclcheck(char *relname, char *usename, AclMode mode) usename); id = (AclId) ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid; - /* - * for the 'pg_database' relation, check the usecreatedb field before - * checking normal permissions - */ - if (strcmp(DatabaseRelationName, relname) == 0 && - (((Form_pg_shadow) GETSTRUCT(tuple))->usecreatedb)) - { - - /* - * note that even though the user can now append to the - * pg_database table, there is still additional permissions - * checking in dbcommands.c - */ - if ((mode & ACL_WR) || (mode & ACL_AP)) - return ACLCHECK_OK; - } - /* * Deny anyone permission to update a system catalog unless * pg_shadow.usecatupd is set. (This is to let superusers protect diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 4565e25a9c..ce2058fcb4 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -7,102 +7,155 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.48 1999/12/20 01:11:37 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.49 2000/01/13 18:26:05 petere Exp $ * *------------------------------------------------------------------------- */ -#include -#include -#include - #include "postgres.h" +#include "commands/dbcommands.h" + +#include +#include +#include +#include +#include +#include +#include #include "access/heapam.h" +#include "access/htup.h" +#include "access/skey.h" +#include "access/xact.h" #include "catalog/catname.h" +#include "catalog/indexing.h" #include "catalog/pg_database.h" #include "catalog/pg_shadow.h" #include "commands/comment.h" -#include "commands/dbcommands.h" #include "miscadmin.h" -#include "storage/sinval.h" -#include "tcop/tcopprot.h" +#include "storage/bufmgr.h" /* for DropBuffers */ +#include "storage/fd.h" /* for closeAllVfds */ +#include "storage/sinval.h" /* for DatabaseHasActiveBackends */ +#include "utils/builtins.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/rel.h" #include "utils/syscache.h" /* non-export function prototypes */ -static void check_permissions(char *command, char *dbpath, char *dbname, - Oid *dbIdP, int4 *userIdP); -static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel); -static void stop_vacuum(char *dbpath, char *dbname); +static bool +get_user_info(const char *name, int4 *use_sysid, bool *use_super, bool *use_createdb); + +static bool +get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP); + + + +/* + * CREATE DATABASE + */ void -createdb(char *dbname, char *dbpath, int encoding, CommandDest dest) +createdb(const char *dbname, const char *dbpath, int encoding) { - Oid db_id; + char buf[2 * MAXPGPATH + 100]; + char *loc; int4 user_id; - char buf[MAXPGPATH + 100]; - char *lp, - loc[MAXPGPATH]; + bool use_super, use_createdb; - /* no single quotes in dbname */ - if (strchr(dbname, '\'') != NULL) - elog(ERROR, "Single quotes are not allowed in database names."); - if (dbpath && strchr(dbpath, '\'') != NULL) - elog(ERROR, "Single quotes are not allowed in database paths."); + Relation pg_database_rel; + HeapTuple tuple; + TupleDesc pg_database_dsc; - /* - * If this call returns, the database does not exist and we're allowed - * to create databases. - */ - check_permissions("createdb", dbpath, dbname, &db_id, &user_id); + Datum new_record[Natts_pg_database]; + char new_record_nulls[Natts_pg_database] = { ' ', ' ', ' ', ' ' }; - /* close virtual file descriptors so we can do system() calls */ + + if (!get_user_info(GetPgUserName(), &user_id, &use_super, &use_createdb)) + elog(ERROR, "Current user name is invalid."); + + if (!use_createdb && !use_super) + elog(ERROR, "CREATE DATABASE: Permission denied."); + + if (get_db_info(dbname, NULL, NULL, NULL)) + elog(ERROR, "CREATE DATABASE: Database \"%s\" already exists.", dbname); + + /* close virtual file descriptors so the kernel has more available for + the system() calls */ closeAllVfds(); - /* Make directory name for this new database */ - if ((dbpath != NULL) && (strcmp(dbpath, dbname) != 0)) - { - if (*(dbpath + strlen(dbpath) - 1) == SEP_CHAR) - *(dbpath + strlen(dbpath) - 1) = '\0'; - snprintf(loc, sizeof(loc), "%s%c%s", dbpath, SEP_CHAR, dbname); - } - else - strcpy(loc, dbname); + /* Generate directory name for the new database */ + if (dbpath == NULL) + dbpath = dbname; - lp = ExpandDatabasePath(loc); + loc = ExpandDatabasePath(dbpath); - if (lp == NULL) - elog(ERROR, "The path '%s' is invalid.\n" - "This may be due to a missing environment variable" - " on the server.", loc); - - /* no single quotes in expanded path */ - if (strchr(lp, '\'') != NULL) - elog(ERROR, "Single quotes are not allowed in database paths."); + 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); /* don't call this in a transaction block */ if (IsTransactionBlock()) - elog(ERROR, "createdb: May not be called in a transaction block."); + elog(ERROR, "CREATE DATABASE: May not be called in a transaction block."); else BeginTransactionBlock(); - snprintf(buf, sizeof(buf), - "INSERT INTO pg_database (datname, datdba, encoding, datpath)" - " VALUES ('%s', '%d', '%d', '%s')", dbname, user_id, encoding, loc); + /* + * Insert a new tuple into pg_database + */ + pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock); + pg_database_dsc = RelationGetDescr(pg_database_rel); - pg_exec_query_dest(buf, dest, false); + /* Form tuple */ + new_record[Anum_pg_database_datname-1] = NameGetDatum(dbname); + new_record[Anum_pg_database_datdba-1] = Int32GetDatum(user_id); + new_record[Anum_pg_database_encoding-1] = Int32GetDatum(encoding); + new_record[Anum_pg_database_datpath-1] = PointerGetDatum(textin((char *)dbpath)); - if (mkdir(lp, S_IRWXU) != 0) { + tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls); + + /* + * Update table + */ + 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 + + heap_close(pg_database_rel, NoLock); + + /* Copy the template database to the new location */ + + if (mkdir(loc, S_IRWXU) != 0) { UserAbortTransactionBlock(); - elog(ERROR, "Unable to create database directory '%s'.", lp); + elog(ERROR, "CREATE DATABASE: Unable to create database directory '%s': %s", loc, strerror(errno)); } - snprintf(buf, sizeof(buf), "%s %s%cbase%ctemplate1%c* '%s'", - COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, lp); + snprintf(buf, sizeof(buf), "cp %s%cbase%ctemplate1%c* '%s'", + DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, loc); if (system(buf) != 0) { - rmdir(lp); + int ret; + snprintf(buf, sizeof(buf), "rm -rf '%s'", loc); + ret = system(buf); UserAbortTransactionBlock(); - elog(ERROR, "Could not initialize database directory."); + if (ret == 0) + elog(ERROR, "CREATE DATABASE: Could not initialize database directory."); + else + elog(ERROR, "CREATE DATABASE: Could not initialize database directory. Delete failed as well."); } if (IsTransactionBlock()) @@ -111,45 +164,56 @@ createdb(char *dbname, char *dbpath, int encoding, CommandDest dest) +/* + * DROP DATABASE + */ + void -dropdb(char *dbname, CommandDest dest) +dropdb(const char *dbname) { - int4 user_id; + int4 user_id, db_owner; + bool use_super; Oid db_id; char *path, dbpath[MAXPGPATH], buf[MAXPGPATH + 100]; + Relation pgdbrel; HeapScanDesc pgdbscan; ScanKeyData key; HeapTuple tup; - /* no single quotes in dbname */ - if (strchr(dbname, '\'') != NULL) - elog(ERROR, "Single quotes are not allowed in database names."); + AssertArg(dbname); - /* - * If this call returns, the database exists and we're allowed to - * remove it. - */ - check_permissions("dropdb", dbpath, dbname, &db_id, &user_id); + if (strcmp(dbname, "template1") == 0) + elog(ERROR, "DROP DATABASE: May not be executed on the template database."); - /* do as much checking as we can... */ - if (!OidIsValid(db_id)) - elog(FATAL, "pg_database instance has an invalid OID"); + if (strcmp(dbname, DatabaseName) == 0) + elog(ERROR, "DROP DATABASE: Cannot be executed on the currently open database."); + + if (!get_user_info(GetPgUserName(), &user_id, &use_super, NULL)) + elog(ERROR, "Current user name is invalid."); + + if (!get_db_info(dbname, dbpath, &db_id, &db_owner)) + elog(ERROR, "DROP DATABASE: Database \"%s\" does not exist.", dbname); + + if (user_id != db_owner && !use_super) + elog(ERROR, "DROP DATABASE: Permission denied."); + + /* close virtual file descriptors so the kernel has more available for + the system() calls */ + closeAllVfds(); path = ExpandDatabasePath(dbpath); if (path == NULL) - elog(ERROR, "The path '%s' is invalid.\n" - "This may be due to a missing environment variable" - " on the server.", path); - - /* stop the vacuum daemon (dead code...) */ - stop_vacuum(dbpath, dbname); + 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); /* don't call this in a transaction block */ if (IsTransactionBlock()) - elog(ERROR, "dropdb: May not be called in a transaction block."); + elog(ERROR, "DROP DATABASE: May not be called in a transaction block."); else BeginTransactionBlock(); @@ -170,8 +234,7 @@ dropdb(char *dbname, CommandDest dest) if (DatabaseHasActiveBackends(db_id)) { heap_close(pgdbrel, AccessExclusiveLock); UserAbortTransactionBlock(); - elog(ERROR, "Database '%s' has running backends, can't drop it.", - dbname); + elog(ERROR, "DROP DATABASE: Database \"%s\" is being accessed by other users.", dbname); } /* @@ -187,19 +250,16 @@ dropdb(char *dbname, CommandDest dest) { heap_close(pgdbrel, AccessExclusiveLock); UserAbortTransactionBlock(); - elog(ERROR, "Database '%s', OID %u, not found in pg_database", - dbname, db_id); + /* This error should never come up since the existence of the + database is checked earlier */ + elog(ERROR, "DROP DATABASE: Database \"%s\" doesn't exist despite earlier reports to the contrary.", + dbname); } - /*** Delete any comments associated with the database ***/ - + /* Delete any comments associated with the database */ DeleteComments(db_id); - /* - * Houston, we have launch commit... - * - * Remove the database's tuple from pg_database. - */ + /* Remove the database's tuple from pg_database */ heap_delete(pgdbrel, &tup->t_self, NULL); heap_endscan(pgdbscan); @@ -222,7 +282,7 @@ dropdb(char *dbname, CommandDest dest) */ snprintf(buf, sizeof(buf), "rm -rf '%s'", path); if (system(buf)!=0) - elog(NOTICE, "The database directory '%s' could not be removed.", path); + elog(NOTICE, "DROP DATABASE: The database directory '%s' could not be removed.", path); if (IsTransactionBlock()) EndTransactionBlock(); @@ -230,186 +290,103 @@ dropdb(char *dbname, CommandDest dest) -static HeapTuple -get_pg_dbtup(char *command, char *dbname, Relation dbrel) +/* + * Helper functions + */ + +static bool +get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP) { - HeapTuple dbtup; - HeapTuple tup; - HeapScanDesc scan; + Relation relation; + HeapTuple tuple; ScanKeyData scanKey; + HeapScanDesc scan; + + AssertArg(name); + + relation = heap_openr(DatabaseRelationName, AccessExclusiveLock/*???*/); ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname, - F_NAMEEQ, NameGetDatum(dbname)); + F_NAMEEQ, NameGetDatum(name)); - scan = heap_beginscan(dbrel, 0, SnapshotNow, 1, &scanKey); + scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scanKey); if (!HeapScanIsValid(scan)) - elog(ERROR, "%s: cannot begin scan of pg_database", command); + elog(ERROR, "Cannot begin scan of %s.", DatabaseRelationName); - /* - * since we want to return the tuple out of this proc, and we're going - * to close the relation, copy the tuple and return the copy. - */ - tup = heap_getnext(scan, 0); + tuple = heap_getnext(scan, 0); - if (HeapTupleIsValid(tup)) - dbtup = heap_copytuple(tup); + if (HeapTupleIsValid(tuple)) + { + text *tmptext; + bool isnull; + + /* oid of the database */ + if (dbIdP) + *dbIdP = tuple->t_data->t_oid; + /* uid of the owner */ + if (ownerIdP) + { + *ownerIdP = (int4) heap_getattr(tuple, + Anum_pg_database_datdba, + RelationGetDescr(relation), + &isnull); + if (isnull) + *ownerIdP = -1; /* hopefully no one has that id already ;) */ + } + /* database path (as registered in pg_database) */ + if (dbpath) + { + tmptext = (text *) heap_getattr(tuple, + Anum_pg_database_datpath, + RelationGetDescr(relation), + &isnull); + + if (!isnull) + { + Assert(VARSIZE(tmptext) - VARHDRSZ < MAXPGPATH); + + strncpy(dbpath, VARDATA(tmptext), VARSIZE(tmptext) - VARHDRSZ); + *(dbpath + VARSIZE(tmptext) - VARHDRSZ) = '\0'; + } + else + strcpy(dbpath, ""); + } + } else - dbtup = tup; + { + if (dbIdP) + *dbIdP = InvalidOid; + } heap_endscan(scan); - return dbtup; + + /* We will keep the lock on the relation until end of transaction. */ + heap_close(relation, NoLock); + + return HeapTupleIsValid(tuple); } -/* - * check_permissions() -- verify that the user is permitted to do this. - * - * If the user is not allowed to carry out this operation, this routine - * elog(ERROR, ...)s, which will abort the xact. As a side effect, the - * user's pg_user tuple OID is returned in userIdP and the target database's - * OID is returned in dbIdP. - */ -static void -check_permissions(char *command, - char *dbpath, - char *dbname, - Oid *dbIdP, - int4 *userIdP) + +static bool +get_user_info(const char * name, int4 *use_sysid, bool *use_super, bool *use_createdb) { - Relation dbrel; - HeapTuple dbtup, - utup; - int4 dbowner = 0; - char use_createdb; - bool dbfound; - bool use_super; - char *userName; - text *dbtext; - char path[MAXPGPATH]; + HeapTuple utup; - userName = GetPgUserName(); + AssertArg(name); utup = SearchSysCacheTuple(SHADOWNAME, - PointerGetDatum(userName), + PointerGetDatum(name), 0, 0, 0); - Assert(utup); - *userIdP = ((Form_pg_shadow) GETSTRUCT(utup))->usesysid; - use_super = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; - use_createdb = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb; - /* Check to make sure user has permission to use createdb */ - if (!use_createdb) - { - elog(ERROR, "user '%s' is not allowed to create/drop databases", - userName); - } + if (!HeapTupleIsValid(utup)) + return false; - /* Make sure we are not mucking with the template database */ - if (!strcmp(dbname, "template1")) - elog(ERROR, "%s: cannot be executed on the template database", command); + if (use_sysid) + *use_sysid = ((Form_pg_shadow) GETSTRUCT(utup))->usesysid; + if (use_super) + *use_super = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; + if (use_createdb) + *use_createdb = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb; - /* Check to make sure database is not the currently open database */ - if (!strcmp(dbname, DatabaseName)) - elog(ERROR, "%s: cannot be executed on an open database", command); - - /* Check to make sure database is owned by this user */ - - /* - * Acquire exclusive lock on pg_database from the beginning, even though - * we only need read access right here, to avoid potential deadlocks - * from upgrading our lock later. (Is this still necessary? Could we - * use something weaker than exclusive lock?) - */ - dbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock); - - dbtup = get_pg_dbtup(command, dbname, dbrel); - dbfound = HeapTupleIsValid(dbtup); - - if (dbfound) - { - dbowner = (int4) heap_getattr(dbtup, - Anum_pg_database_datdba, - RelationGetDescr(dbrel), - (char *) NULL); - *dbIdP = dbtup->t_data->t_oid; - dbtext = (text *) heap_getattr(dbtup, - Anum_pg_database_datpath, - RelationGetDescr(dbrel), - (char *) NULL); - - strncpy(path, VARDATA(dbtext), (VARSIZE(dbtext) - VARHDRSZ)); - *(path + VARSIZE(dbtext) - VARHDRSZ) = '\0'; - } - else - *dbIdP = InvalidOid; - - /* We will keep the lock on dbrel until end of transaction. */ - heap_close(dbrel, NoLock); - - /* - * Now be sure that the user is allowed to do this. - */ - - if (dbfound && !strcmp(command, "createdb")) - { - - elog(ERROR, "createdb: database '%s' already exists", dbname); - - } - else if (!dbfound && !strcmp(command, "dropdb")) - { - - elog(ERROR, "dropdb: database '%s' does not exist", dbname); - - } - else if (dbfound && !strcmp(command, "dropdb") - && dbowner != *userIdP && use_super == false) - { - - elog(ERROR, "%s: database '%s' is not owned by you", command, dbname); - - } - - if (dbfound && !strcmp(command, "dropdb")) - strcpy(dbpath, path); -} /* check_permissions() */ - -/* - * stop_vacuum -- stop the vacuum daemon on the database, if one is running. - * - * This is currently dead code, since we don't *have* vacuum daemons. - * If you want to re-enable it, think about the interlock against deleting - * a database out from under running backends, in dropdb() above. - */ -static void -stop_vacuum(char *dbpath, char *dbname) -{ -#ifdef NOT_USED - char filename[MAXPGPATH]; - FILE *fp; - int pid; - - if (strchr(dbpath, SEP_CHAR) != 0) - { - snprintf(filename, sizeof(filename), "%s%cbase%c%s%c%s.vacuum", - DataDir, SEP_CHAR, SEP_CHAR, dbname, SEP_CHAR, dbname); - } - else - snprintf(filename, sizeof(filename), "%s%c%s.vacuum", - dbpath, SEP_CHAR, dbname); - -#ifndef __CYGWIN32__ - if ((fp = AllocateFile(filename, "r")) != NULL) -#else - if ((fp = AllocateFile(filename, "rb")) != NULL) -#endif - { - fscanf(fp, "%d", &pid); - FreeFile(fp); - if (kill(pid, SIGKILLDAEMON1) < 0) - { - elog(ERROR, "can't kill vacuum daemon (pid %d) on '%s'", - pid, dbname); - } - } -#endif + return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e26244e6e7..e21a26dcd6 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.123 1999/12/16 17:24:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.124 2000/01/13 18:26:07 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -131,7 +131,8 @@ static Node *doNegate(Node *n); RuleActionStmtOrEmpty, ConstraintsSetStmt, CreateGroupStmt, AlterGroupStmt, DropGroupStmt -%type opt_database1, opt_database2, location, encoding +%type createdb_opt_location +%type createdb_opt_encoding %type opt_lock, lock_type %type opt_lmode @@ -156,7 +157,7 @@ static Node *doNegate(Node *n); all_Op, MathOp, opt_name, opt_unique, OptUseOp, opt_class, SpecialRuleRelation -%type opt_level +%type opt_level, opt_encoding %type privileges, operation_commalist, grantee %type operation, TriggerOneEvent @@ -709,7 +710,7 @@ VariableSetStmt: SET ColId TO var_value n->value = $5; $$ = (Node *) n; } - | SET NAMES encoding + | SET NAMES opt_encoding { #ifdef MULTIBYTE VariableSetStmt *n = makeNode(VariableSetStmt); @@ -717,7 +718,7 @@ VariableSetStmt: SET ColId TO var_value n->value = $3; $$ = (Node *) n; #else - elog(ERROR, "SET NAMES is not supported"); + elog(ERROR, "SET NAMES is not supported."); #endif } ; @@ -735,6 +736,11 @@ zone_value: Sconst { $$ = $1; } | LOCAL { $$ = NULL; } ; +opt_encoding: Sconst { $$ = $1; } + | DEFAULT { $$ = NULL; } + | /*EMPTY*/ { $$ = NULL; } + ; + VariableShowStmt: SHOW ColId { VariableShowStmt *n = makeNode(VariableShowStmt); @@ -2508,31 +2514,24 @@ LoadStmt: LOAD file_name /***************************************************************************** * - * QUERY: - * createdb dbname + * CREATE DATABASE + * * *****************************************************************************/ -CreatedbStmt: CREATE DATABASE database_name WITH opt_database1 opt_database2 - { - CreatedbStmt *n = makeNode(CreatedbStmt); - if ($5 == NULL && $6 == NULL) { - elog(ERROR, "CREATE DATABASE WITH requires at least an option"); - } +CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb_opt_encoding + { + CreatedbStmt *n; + + if ($5 == NULL && $6 == -1) + elog(ERROR, "CREATE DATABASE WITH requires at least one option."); + + n = makeNode(CreatedbStmt); n->dbname = $3; n->dbpath = $5; #ifdef MULTIBYTE - if ($6 != NULL) { - n->encoding = pg_char_to_encoding($6); - if (n->encoding < 0) { - elog(ERROR, "invalid encoding name %s", $6); - } - } else { - n->encoding = GetTemplateEncoding(); - } + n->encoding = $6; #else - if ($6 != NULL) - elog(ERROR, "WITH ENCODING is not supported"); n->encoding = 0; #endif $$ = (Node *)n; @@ -2551,28 +2550,57 @@ CreatedbStmt: CREATE DATABASE database_name WITH opt_database1 opt_database2 } ; -opt_database1: LOCATION '=' location { $$ = $3; } +createdb_opt_location: LOCATION '=' Sconst { $$ = $3; } + | LOCATION '=' DEFAULT { $$ = NULL; } | /*EMPTY*/ { $$ = NULL; } ; -opt_database2: ENCODING '=' encoding { $$ = $3; } - | /*EMPTY*/ { $$ = NULL; } - ; +createdb_opt_encoding: + ENCODING '=' Sconst + { +#ifdef MULTIBYTE + int i; + i = pg_char_to_encoding($3); + if (i == -1) + elog(ERROR, "%s is not a valid encoding name.", $3); + $$ = i; +#else + elog(ERROR, "WITH ENCODING is not supported."); +#endif + } + | ENCODING '=' Iconst + { +#ifdef MULTIBYTE + if (!pg_get_encent_by_encoding($3)) + elog(ERROR, "%d is not a valid encoding code.", $3); + $$ = $3; +#else + elog(ERROR, "WITH ENCODING is not supported."); +#endif + } + | ENCODING '=' DEFAULT + { +#ifdef MULTIBYTE + $$ = GetTemplateEncoding(); +#else + $$ = -1; +#endif + } + | /*EMPTY*/ + { +#ifdef MULTIBYTE + $$ = GetTemplateEncoding(); +#else + $$= -1; +#endif + } + ; -location: Sconst { $$ = $1; } - | DEFAULT { $$ = NULL; } - | /*EMPTY*/ { $$ = NULL; } - ; - -encoding: Sconst { $$ = $1; } - | DEFAULT { $$ = NULL; } - | /*EMPTY*/ { $$ = NULL; } - ; /***************************************************************************** * - * QUERY: - * dropdb dbname + * DROP DATABASE + * * *****************************************************************************/ diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index af887c95ca..a7bcd1b6ec 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.61 2000/01/10 06:30:51 inoue Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.62 2000/01/13 18:26:09 petere Exp $ * *------------------------------------------------------------------------- */ @@ -623,8 +623,6 @@ mdblindwrt(char *dbstr, /* user table? then put in user database area... */ else if (dbid == MyDatabaseId) { - extern char *DatabasePath; - path = (char *) palloc(strlen(DatabasePath) + 2 * sizeof(NameData) + 2 + nchars); if (segno == 0) sprintf(path, "%s%c%s", DatabasePath, SEP_CHAR, relstr); @@ -663,8 +661,6 @@ mdblindwrt(char *dbstr, /* user table? then put in user database area... */ else if (dbid == MyDatabaseId) { - extern char *DatabasePath; - path = (char *) palloc(strlen(DatabasePath) + 2 * sizeof(NameData) + 2); sprintf(path, "%s%c%s", DatabasePath, SEP_CHAR, relstr); } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index e6d609ee94..0a97e3acac 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.76 1999/12/20 01:19:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.77 2000/01/13 18:26:10 petere Exp $ * *------------------------------------------------------------------------- */ @@ -592,7 +592,7 @@ ProcessUtility(Node *parsetree, PS_SET_STATUS(commandTag = "CREATE DATABASE"); CHECK_IF_ABORTED(); - createdb(stmt->dbname, stmt->dbpath, stmt->encoding, dest); + createdb(stmt->dbname, stmt->dbpath, stmt->encoding); } break; @@ -602,7 +602,7 @@ ProcessUtility(Node *parsetree, PS_SET_STATUS(commandTag = "DROP DATABASE"); CHECK_IF_ABORTED(); - dropdb(stmt->dbname, dest); + dropdb(stmt->dbname); } break; diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 1de751e950..22ae84bacd 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -7,10 +7,12 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.38 2000/01/09 12:15:57 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.39 2000/01/13 18:26:11 petere Exp $ * *------------------------------------------------------------------------- */ +#include "postgres.h" + #include #include #include @@ -19,177 +21,21 @@ #include #include #include +#include -#include "postgres.h" #include "catalog/catname.h" #include "catalog/pg_shadow.h" #include "miscadmin.h" #include "utils/syscache.h" -/* - * EnableAbortEnvVarName - * Enables system abort iff set to a non-empty string in environment. - */ -#define EnableAbortEnvVarName "POSTGRESABORT" - -extern char *getenv(const char *name); /* XXX STDLIB */ - -/* from globals.c */ -extern char *UserName; - #ifdef CYR_RECODE unsigned char RecodeForwTable[128]; unsigned char RecodeBackTable[128]; - #endif +ProcessingMode Mode = InitProcessing; -/* - * Define USE_ENVIRONMENT to get PGDATA, etc. from environment variables. - * This is the default on UNIX platforms. - */ -#define USE_ENVIRONMENT - -/* ---------------------------------------------------------------- - * some of the 19 ways to leave postgres - * ---------------------------------------------------------------- - */ - -/* - * ExitPostgres - * Exit POSTGRES with a status code. - * - * Note: - * This function never returns. - * ... - * - * Side effects: - * ... - * - * Exceptions: - * none - */ -void -ExitPostgres(ExitStatus status) -{ - proc_exit(status); -} - -/* - * AbortPostgres - * Abort POSTGRES dumping core. - * - * Note: - * This function never returns. - * ... - * - * Side effects: - * Core is dumped iff EnableAbortEnvVarName is set to a non-empty string. - * ... - * - * Exceptions: - * none - */ -#ifdef NOT_USED -void -AbortPostgres() -{ - char *abortValue = getenv(EnableAbortEnvVarName); - - if (PointerIsValid(abortValue) && abortValue[0] != '\0') - abort(); - else - proc_exit(FatalExitStatus); -} - - -/* ---------------- - * StatusBackendExit - * ---------------- - */ -void -StatusBackendExit(int status) -{ - /* someday, do some real cleanup and then call the LISP exit */ - /* someday, call StatusPostmasterExit if running without postmaster */ - proc_exit(status); -} - -/* ---------------- - * StatusPostmasterExit - * ---------------- - */ -void -StatusPostmasterExit(int status) -{ - /* someday, do some real cleanup and then call the LISP exit */ - proc_exit(status); -} - -#endif - - -/* ---------------------------------------------------------------- - * processing mode support stuff (used to be in pmod.c) - * ---------------------------------------------------------------- - */ -static ProcessingMode Mode = InitProcessing; - -/* - * IsBootstrapProcessingMode - * True iff processing mode is BootstrapProcessing. - */ -bool -IsBootstrapProcessingMode() -{ - return (bool) (Mode == BootstrapProcessing); -} - -/* - * IsInitProcessingMode - * True iff processing mode is InitProcessing. - */ -bool -IsInitProcessingMode() -{ - return (bool) (Mode == InitProcessing); -} - -/* - * IsNormalProcessingMode - * True iff processing mode is NormalProcessing. - */ -bool -IsNormalProcessingMode() -{ - return (bool) (Mode == NormalProcessing); -} - -/* - * SetProcessingMode - * Sets mode of processing as specified. - * - * Exceptions: - * BadArg if called with invalid mode. - * - * Note: - * Mode is InitProcessing before the first time this is called. - */ -void -SetProcessingMode(ProcessingMode mode) -{ - AssertArg(mode == BootstrapProcessing || mode == InitProcessing || - mode == NormalProcessing); - - Mode = mode; -} - -ProcessingMode -GetProcessingMode() -{ - return Mode; -} /* ---------------------------------------------------------------- * database path / name support stuff @@ -197,22 +43,26 @@ GetProcessingMode() */ void -SetDatabasePath(char *path) +SetDatabasePath(const char *path) { - /* use malloc since this is done before memory contexts are set up */ - if (DatabasePath) - free(DatabasePath); - DatabasePath = malloc(strlen(path) + 1); - strcpy(DatabasePath, path); + free(DatabasePath); + /* use strdup since this is done before memory contexts are set up */ + if (path) + { + DatabasePath = strdup(path); + AssertState(DatabasePath); + } } void -SetDatabaseName(char *name) +SetDatabaseName(const char *name) { - if (DatabaseName) - free(DatabaseName); - DatabaseName = malloc(strlen(name) + 1); - strcpy(DatabaseName, name); + free(DatabaseName); + if (name) + { + DatabaseName = strdup(name); + AssertState(DatabaseName); + } } #ifndef MULTIBYTE @@ -431,7 +281,7 @@ static Oid UserId = InvalidOid; int GetUserId() { - Assert(OidIsValid(UserId)); + AssertState(OidIsValid(UserId)); return UserId; } @@ -441,7 +291,7 @@ SetUserId() HeapTuple userTup; char *userName; - Assert(!OidIsValid(UserId));/* only once */ + AssertState(!OidIsValid(UserId));/* only once */ /* * Don't do scans if we're bootstrapping, none of the system catalogs diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 346bdb4b8b..9e533dcd8e 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -7,22 +7,8 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.54 1999/12/22 00:07:16 inoue Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.55 2000/01/13 18:26:11 petere Exp $ * - * NOTES - * InitPostgres() is the function called from PostgresMain - * which does all non-trival initialization, mainly by calling - * all the other initialization functions. InitPostgres() - * is only used within the "postgres" backend and so that routine - * is in tcop/postgres.c InitPostgres() is needed in cinterface.a - * because things like the bootstrap backend program need it. Hence - * you find that in this file... - * - * If you feel the need to add more initialization code, it should be - * done in InitPostgres() or someplace lower. Do not start - * putting stuff in PostgresMain - if you do then someone - * will have to clean it up later, and it's not going to be me! - * -cim 10/3/90 * *------------------------------------------------------------------------- */ @@ -55,193 +41,13 @@ void BaseInit(void); -static void VerifySystemDatabase(void); -static void VerifyMyDatabase(void); -static void ReverifyMyDatabase(char *name); +static void ReverifyMyDatabase(const char *name); static void InitCommunication(void); -static void InitMyDatabaseInfo(char *name); -static void InitUserid(void); - static IPCKey PostgresIpcKey; -/* ---------------------------------------------------------------- - * InitPostgres support - * ---------------------------------------------------------------- - */ +/*** InitPostgres support ***/ -/* -------------------------------- - * InitMyDatabaseInfo() -- Find and record the OID of the database we are - * to open. - * - * The database's oid forms half of the unique key for the system - * caches and lock tables. We therefore want it initialized before - * we open any relations, since opening relations puts things in the - * cache. To get around this problem, this code opens and scans the - * pg_database relation by hand. - * - * This algorithm relies on the fact that first attribute in the - * pg_database relation schema is the database name. It also knows - * about the internal format of tuples on disk and the length of - * the datname attribute. It knows the location of the pg_database - * file. - * Actually, the code looks as though it is using the pg_database - * tuple definition to locate the database name, so the above statement - * seems to be no longer correct. - thomas 1997-11-01 - * - * This code is called from InitPostgres(), before we chdir() to the - * local database directory and before we open any relations. - * Used to be called after the chdir(), but we now want to confirm - * the location of the target database using pg_database info. - * - thomas 1997-11-01 - * -------------------------------- - */ -static void -InitMyDatabaseInfo(char *name) -{ - char *path, - myPath[MAXPGPATH]; - - SetDatabaseName(name); - GetRawDatabaseInfo(name, &MyDatabaseId, myPath); - - if (!OidIsValid(MyDatabaseId)) - elog(FATAL, - "Database %s does not exist in %s", - DatabaseName, - DatabaseRelationName); - - path = ExpandDatabasePath(myPath); - SetDatabasePath(path); -} /* InitMyDatabaseInfo() */ - - -/* - * DoChdirAndInitDatabaseNameAndPath - * Set current directory to the database directory for the database - * named . - * Also set global variables DatabasePath and DatabaseName to those - * values. Also check for proper version of database system and - * database. Exit program via elog() if anything doesn't check out. - * - * Arguments: - * Path and name are invalid if it invalid as a string. - * Path is "badly formatted" if it is not a string containing a path - * to a writable directory. - * Name is "badly formatted" if it contains more than 16 characters or if - * it is a bad file name (e.g., it contains a '/' or an 8-bit character). - * - * Exceptions: - * BadState if called more than once. - * BadArg if both path and name are "badly formatted" or invalid. - * BadArg if path and name are both "inconsistent" and valid. - * - * This routine is inappropriate in bootstrap mode, since the directories - * and version files need not exist yet if we're in bootstrap mode. - */ -static void -VerifySystemDatabase() -{ - char *reason; - /* Failure reason returned by some function. NULL if no failure */ - int fd; - char errormsg[MAXPGPATH+100]; - - errormsg[0] = '\0'; - -#ifndef __CYGWIN32__ - if ((fd = open(DataDir, O_RDONLY, 0)) == -1) -#else - if ((fd = open(DataDir, O_RDONLY | O_DIROPEN, 0)) == -1) -#endif - snprintf(errormsg, sizeof(errormsg), - "Database system does not exist. " - "PGDATA directory '%s' not found.\n\tNormally, you " - "create a database system by running initdb.", - DataDir); - else - { - close(fd); - ValidatePgVersion(DataDir, &reason); - if (reason != NULL) - snprintf(errormsg, sizeof(errormsg), - "InitPostgres could not validate that the database" - " system version is compatible with this level of" - " Postgres.\n\tYou may need to run initdb to create" - " a new database system.\n\t%s", reason); - } - if (errormsg[0] != '\0') - elog(FATAL, errormsg); - /* Above does not return */ -} /* VerifySystemDatabase() */ - - -static void -VerifyMyDatabase() -{ - const char *name; - const char *myPath; - - /* Failure reason returned by some function. NULL if no failure */ - char *reason; - int fd; - char errormsg[MAXPGPATH+100]; - - name = DatabaseName; - myPath = DatabasePath; - -#ifndef __CYGWIN32__ - if ((fd = open(myPath, O_RDONLY, 0)) == -1) -#else - if ((fd = open(myPath, O_RDONLY | O_DIROPEN, 0)) == -1) -#endif - snprintf(errormsg, sizeof(errormsg), - "Database '%s' does not exist." - "\n\tWe know this because the directory '%s' does not exist." - "\n\tYou can create a database with the SQL command" - " CREATE DATABASE.\n\tTo see what databases exist," - " look at the subdirectories of '%s/base/'.", - name, myPath, DataDir); - else - { - close(fd); - ValidatePgVersion(myPath, &reason); - if (reason != NULL) - snprintf(errormsg, sizeof(errormsg), - "InitPostgres could not validate that the database" - " version is compatible with this level of Postgres" - "\n\teven though the database system as a whole" - " appears to be at a compatible level." - "\n\tYou may need to recreate the database with SQL" - " commands DROP DATABASE and CREATE DATABASE." - "\n\t%s", reason); - else - { - - /* - * The directories and PG_VERSION files are in order. - */ - int rc; /* return code from some function we call */ - -#ifdef FILEDEBUG - printf("Try changing directory for database %s to %s\n", name, myPath); -#endif - - rc = chdir(myPath); - if (rc < 0) - snprintf(errormsg, sizeof(errormsg), - "InitPostgres unable to change " - "current directory to '%s', errno = %s (%d).", - myPath, strerror(errno), errno); - else - errormsg[0] = '\0'; - } - } - - if (errormsg[0] != '\0') - elog(FATAL, errormsg); - /* Above does not return */ -} /* VerifyMyDatabase() */ /* -------------------------------- * ReverifyMyDatabase @@ -266,7 +72,7 @@ VerifyMyDatabase() * -------------------------------- */ static void -ReverifyMyDatabase(char *name) +ReverifyMyDatabase(const char *name) { Relation pgdbrel; HeapScanDesc pgdbscan; @@ -324,18 +130,7 @@ ReverifyMyDatabase(char *name) heap_close(pgdbrel, AccessShareLock); } -/* -------------------------------- - * InitUserid - * - * initializes crap associated with the user id. - * -------------------------------- - */ -static void -InitUserid() -{ - setuid(geteuid()); - SetUserId(); -} + /* -------------------------------- * InitCommunication @@ -416,6 +211,8 @@ InitCommunication() } } + + /* -------------------------------- * InitPostgres * Initialize POSTGRES. @@ -431,14 +228,9 @@ int lockingOff = 0; /* backend -L switch */ /* */ void -InitPostgres(char *name) /* database name */ +InitPostgres(const char *dbname) { - bool bootstrap; /* true if BootstrapProcessing */ - - /* - * See if we're running in BootstrapProcessing mode - */ - bootstrap = IsBootstrapProcessingMode(); + bool bootstrap = IsBootstrapProcessingMode(); /* ---------------- * initialize the backend local portal stack used by @@ -449,9 +241,7 @@ InitPostgres(char *name) /* database name */ */ be_portalinit(); - /* - * initialize the local buffer manager - */ + /* initialize the local buffer manager */ InitLocalBuffer(); #ifndef XLOG @@ -459,32 +249,72 @@ InitPostgres(char *name) /* database name */ on_shmem_exit(FlushBufferPool, (caddr_t) NULL); #endif + SetDatabaseName(dbname); /* ---------------- * initialize the database id used for system caches and lock tables * ---------------- */ if (bootstrap) { - SetDatabasePath(ExpandDatabasePath(name)); - SetDatabaseName(name); + SetDatabasePath(ExpandDatabasePath(dbname)); LockDisable(true); } else { - VerifySystemDatabase(); - InitMyDatabaseInfo(name); - VerifyMyDatabase(); + char *reason; + char *fullpath, + datpath[MAXPGPATH]; + + /* Verify if DataDir is ok */ + if (access(DataDir, F_OK) == -1) + elog(FATAL, "Database system not found. Data directory '%s' does not exist.", + DataDir); + + ValidatePgVersion(DataDir, &reason); + if (reason != NULL) + elog(FATAL, reason); + + /*----------------- + * Find oid and path of the database we're about to open. Since we're + * not yet up and running we have to use the hackish GetRawDatabaseInfo. + * + * OLD COMMENTS: + * The database's oid forms half of the unique key for the system + * caches and lock tables. We therefore want it initialized before + * we open any relations, since opening relations puts things in the + * cache. To get around this problem, this code opens and scans the + * pg_database relation by hand. + */ + + GetRawDatabaseInfo(dbname, &MyDatabaseId, datpath); + + if (!OidIsValid(MyDatabaseId)) + elog(FATAL, + "Database \"%s\" does not exist in the system catalog.", + dbname); + + fullpath = ExpandDatabasePath(datpath); + if (!fullpath) + elog(FATAL, "Database path could not be resolved."); + + /* Verify the database path */ + + if (access(fullpath, F_OK) == -1) + elog(FATAL, "Database \"%s\" does not exist. The data directory '%s' is missing.", + dbname, fullpath); + + ValidatePgVersion(fullpath, &reason); + if (reason != NULL) + elog(FATAL, "%s", reason); + + if(chdir(fullpath) == -1) + elog(FATAL, "Unable to change directory to '%s': %s", fullpath, strerror(errno)); + + SetDatabasePath(fullpath); } /* * Code after this point assumes we are in the proper directory! - * - * So, how do we implement alternate locations for databases? There are - * two possible locations for tables and we need to look in - * DataDir/pg_database to find the true location of an individual - * database. We can brute-force it as done in InitMyDatabaseInfo(), or - * we can be patient and wait until we open pg_database gracefully. - * Will try that, but may not work... - thomas 1997-11-01 */ /* @@ -549,12 +379,14 @@ InitPostgres(char *name) /* database name */ /* start a new transaction here before access to db */ if (!bootstrap) StartTransactionCommand(); + /* * Set ourselves to the proper user id and figure out our postgres * user id. If we ever add security so that we check for valid * postgres users, we might do it here. */ - InitUserid(); + setuid(geteuid()); + SetUserId(); if (lockingOff) LockDisable(true); @@ -565,7 +397,7 @@ InitPostgres(char *name) /* database name */ * infrastructure is up, so just do it at the end. */ if (!bootstrap) - ReverifyMyDatabase(name); + ReverifyMyDatabase(dbname); } void diff --git a/src/backend/utils/misc/database.c b/src/backend/utils/misc/database.c index 62a4303f71..d68f6ed4d7 100644 --- a/src/backend/utils/misc/database.c +++ b/src/backend/utils/misc/database.c @@ -7,100 +7,43 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.33 1999/12/16 22:19:55 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.34 2000/01/13 18:26:13 petere Exp $ * *------------------------------------------------------------------------- */ -#include -#include - #include "postgres.h" +#include +#include +#include +#include +#include + #include "access/xact.h" +#include "catalog/catname.h" #include "catalog/pg_database.h" #include "miscadmin.h" #include "utils/syscache.h" -#ifdef NOT_USED -/* GetDatabaseInfo() - * Pull database information from pg_database. + +/* + * ExpandDatabasePath resolves a proposed database path (obtained from + * pg_database.datpath) to a full absolute path for further consumption. + * NULL means an error, which the caller should process. One reason for + * such an error would be an absolute alternative path when no absolute + * paths are alllowed. */ -int -GetDatabaseInfo(char *name, int4 *owner, char *path) -{ - Oid dbowner, - dbid; - char dbpath[MAXPGPATH]; - text *dbtext; - - Relation dbrel; - HeapTuple dbtup; - HeapTuple tup; - HeapScanDesc scan; - ScanKeyData scanKey; - - dbrel = heap_openr(DatabaseRelationName, AccessShareLock); - - ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname, - F_NAMEEQ, NameGetDatum(name)); - - scan = heap_beginscan(dbrel, 0, SnapshotNow, 1, &scanKey); - if (!HeapScanIsValid(scan)) - elog(ERROR, "GetDatabaseInfo: cannot begin scan of %s", DatabaseRelationName); - - /* - * Since we're going to close the relation, copy the tuple. - */ - tup = heap_getnext(scan, 0); - - if (HeapTupleIsValid(tup)) - dbtup = heap_copytuple(tup); - else - dbtup = tup; - - heap_endscan(scan); - - if (!HeapTupleIsValid(dbtup)) - { - elog(NOTICE, "GetDatabaseInfo: %s entry not found %s", - DatabaseRelationName, name); - heap_close(dbrel, AccessShareLock); - return TRUE; - } - - dbowner = (Oid) heap_getattr(dbtup, - Anum_pg_database_datdba, - RelationGetDescr(dbrel), - (char *) NULL); - dbid = dbtup->t_oid; - - dbtext = (text *) heap_getattr(dbtup, - Anum_pg_database_datpath, - RelationGetDescr(dbrel), - (char *) NULL); - - memcpy(dbpath, VARDATA(dbtext), (VARSIZE(dbtext) - VARHDRSZ)); - *(dbpath + (VARSIZE(dbtext) - VARHDRSZ)) = '\0'; - - heap_close(dbrel, AccessShareLock); - - owner = palloc(sizeof(Oid)); - *owner = dbowner; - path = pstrdup(dbpath); /* doesn't do the right thing! */ - - return FALSE; -} /* GetDatabaseInfo() */ - -#endif char * -ExpandDatabasePath(char *dbpath) +ExpandDatabasePath(const char *dbpath) { char buf[MAXPGPATH]; - char *cp; - char *envvar; + const char *cp; int len; + AssertArg(dbpath); + Assert(DataDir); + if (strlen(dbpath) >= MAXPGPATH) return NULL; /* ain't gonna fit nohow */ @@ -120,17 +63,14 @@ ExpandDatabasePath(char *dbpath) /* path delimiter somewhere? then has leading environment variable */ else if ((cp = strchr(dbpath, SEP_CHAR)) != NULL) { + const char *envvar; + len = cp - dbpath; strncpy(buf, dbpath, len); buf[len] = '\0'; envvar = getenv(buf); - - /* - * problem getting environment variable? let calling routine - * handle it - */ if (envvar == NULL) - return envvar; + return NULL; snprintf(buf, sizeof(buf), "%s%cbase%c%s", envvar, SEP_CHAR, SEP_CHAR, (cp + 1)); @@ -142,10 +82,29 @@ ExpandDatabasePath(char *dbpath) DataDir, SEP_CHAR, SEP_CHAR, dbpath); } + /* check for illegal characters in dbpath */ + for(cp = buf; *cp; cp++) + { + /* The following characters will not be allowed anywhere in the database + path. (Do not include the slash here.) */ + char illegal_dbpath_chars[] = + "\001\002\003\004\005\006\007\010" + "\011\012\013\014\015\016\017\020" + "\021\022\023\024\025\026\027\030" + "\031\032\033\034\035\036\037" + "'."; + + const char *cx; + for (cx = illegal_dbpath_chars; *cx; cx++) + if (*cp == *cx) + return NULL; + } + return pstrdup(buf); } /* ExpandDatabasePath() */ + /* -------------------------------- * GetRawDatabaseInfo() -- Find the OID and path of the database. * @@ -161,10 +120,9 @@ ExpandDatabasePath(char *dbpath) * -------------------------------- */ void -GetRawDatabaseInfo(char *name, Oid *db_id, char *path) +GetRawDatabaseInfo(const char *name, Oid *db_id, char *path) { int dbfd; - int fileflags; int nbytes; int max, i; @@ -174,16 +132,15 @@ GetRawDatabaseInfo(char *name, Oid *db_id, char *path) char *dbfname; Form_pg_database tup_db; - dbfname = (char *) palloc(strlen(DataDir) + strlen("pg_database") + 2); - sprintf(dbfname, "%s%cpg_database", DataDir, SEP_CHAR); - fileflags = O_RDONLY; + dbfname = (char *) palloc(strlen(DataDir) + strlen(DatabaseRelationName) + 2); + sprintf(dbfname, "%s%c%s", DataDir, SEP_CHAR, DatabaseRelationName); #ifndef __CYGWIN32__ if ((dbfd = open(dbfname, O_RDONLY, 0)) < 0) #else if ((dbfd = open(dbfname, O_RDONLY | O_BINARY, 0)) < 0) #endif - elog(FATAL, "Cannot open %s", dbfname); + elog(FATAL, "cannot open %s: %s", dbfname, strerror(errno)); pfree(dbfname); diff --git a/src/backend/utils/mmgr/palloc.c b/src/backend/utils/mmgr/palloc.c index afc52b4b5b..c1bb88771a 100644 --- a/src/backend/utils/mmgr/palloc.c +++ b/src/backend/utils/mmgr/palloc.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.15 1999/10/23 03:13:24 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.16 2000/01/13 18:26:14 petere Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,7 @@ */ char * -pstrdup(char *string) +pstrdup(const char *string) { char *nstr; int len; diff --git a/src/include/c.h b/src/include/c.h index 53fe14e70a..e80b9fd285 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -7,7 +7,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: c.h,v 1.62 1999/12/20 00:51:21 tgl Exp $ + * $Id: c.h,v 1.63 2000/01/13 18:26:15 petere Exp $ * *------------------------------------------------------------------------- */ @@ -767,7 +767,6 @@ extern char *vararg_format(const char *fmt,...); /* These are for things that are one way on Unix and another on NT */ #define NULL_DEV "/dev/null" -#define COPY_CMD "cp" #define SEP_CHAR '/' /* defines for dynamic linking on Win32 platform */ diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h index 165b20505f..90245d338a 100644 --- a/src/include/commands/dbcommands.h +++ b/src/include/commands/dbcommands.h @@ -6,23 +6,14 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: dbcommands.h,v 1.11 1999/12/10 03:56:06 momjian Exp $ + * $Id: dbcommands.h,v 1.12 2000/01/13 18:26:16 petere Exp $ * *------------------------------------------------------------------------- */ #ifndef DBCOMMANDS_H #define DBCOMMANDS_H -#include -#include "tcop/dest.h" - -/* - * Originally from tmp/daemon.h. The functions declared in daemon.h does not - * exist; hence removed. -- AY 7/29/94 - */ -#define SIGKILLDAEMON1 SIGTERM - -extern void createdb(char *dbname, char *dbpath, int encoding, CommandDest); -extern void dropdb(char *dbname, CommandDest); +extern void createdb(const char *dbname, const char *dbpath, int encoding); +extern void dropdb(const char *dbname); #endif /* DBCOMMANDS_H */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 4212c50dc5..ee88a8a5ef 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -11,7 +11,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: miscadmin.h,v 1.46 2000/01/09 12:19:27 ishii Exp $ + * $Id: miscadmin.h,v 1.47 2000/01/13 18:26:15 petere Exp $ * * NOTES * some of the information in this file will be moved to @@ -47,6 +47,8 @@ extern long MyCancelKey; extern char OutputFileName[]; +extern char *UserName; + /* * done in storage/backendid.h for now. * @@ -110,13 +112,12 @@ extern char *DatabaseName; extern char *DatabasePath; /* in utils/misc/database.c */ -extern void GetRawDatabaseInfo(char *name, Oid *db_id, char *path); -extern int GetDatabaseInfo(char *name, int4 *owner, char *path); -extern char *ExpandDatabasePath(char *path); +extern void GetRawDatabaseInfo(const char *name, Oid *db_id, char *path); +extern char *ExpandDatabasePath(const char *path); /* now in utils/init/miscinit.c */ -extern void SetDatabaseName(char *name); -extern void SetDatabasePath(char *path); +extern void SetDatabaseName(const char *name); +extern void SetDatabasePath(const char *path); /* even if MB is not enabled, this function is neccesary * since pg_proc.h does have. @@ -184,16 +185,27 @@ typedef int16 ExitStatus; extern bool PostgresIsInitialized; -extern void InitPostgres(char *name); +extern void InitPostgres(const char *dbname); -/* in miscinit.c */ -extern void ExitPostgres(ExitStatus status); +/* one of the ways to get out of here */ +#define ExitPostgres(status) proc_exec(status) + +/* processing mode support stuff */ +extern ProcessingMode Mode; + +#define IsBootstrapProcessingMode() ((bool)(Mode == BootstrapProcessing)) +#define IsInitProcessingMode() ((bool)(Mode == InitProcessing)) +#define IsNormalProcessingMode() ((bool)(Mode == NormalProcessing)) + +#define SetProcessingMode(mode) \ + do { \ + AssertArg(mode == BootstrapProcessing || mode == InitProcessing || \ + mode == NormalProcessing); \ + Mode = mode; \ + } while(0) + +#define GetProcessingMode() Mode -extern bool IsBootstrapProcessingMode(void); -extern bool IsInitProcessingMode(void); -extern bool IsNormalProcessingMode(void); -extern void SetProcessingMode(ProcessingMode mode); -extern ProcessingMode GetProcessingMode(void); /* * "postmaster.pid" is a file containing postmaster's pid, being diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index e69ef11d7a..54239b4548 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: elog.h,v 1.13 1999/09/27 15:48:12 vadim Exp $ + * $Id: elog.h,v 1.14 2000/01/13 18:26:17 petere Exp $ * *------------------------------------------------------------------------- */ @@ -22,7 +22,13 @@ #define LOG DEBUG #define NOIND (-3) /* debug message, don't indent as far */ +#ifndef __GNUC__ extern void elog(int lev, const char *fmt, ...); +#else +/* This extension allows gcc to check the format string for consistency with + the supplied arguments. */ +extern void elog(int lev, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +#endif #ifndef PG_STANDALONE extern int DebugFileOpen(void); diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 5ea3d9bb84..9f3a51b421 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: palloc.h,v 1.10 1999/07/14 01:20:30 momjian Exp $ + * $Id: palloc.h,v 1.11 2000/01/13 18:26:18 petere Exp $ * *------------------------------------------------------------------------- */ @@ -32,6 +32,6 @@ #endif /* PALLOC_IS_MALLOC */ /* like strdup except uses palloc */ -extern char *pstrdup(char *pointer); +extern char *pstrdup(const char *pointer); #endif /* PALLOC_H */