1 /*-------------------------------------------------------------------------
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.37 1999/07/16 03:12:48 momjian Exp $
12 *-------------------------------------------------------------------------
21 #include "access/heapam.h"
22 #include "catalog/catname.h"
23 #include "catalog/pg_database.h"
24 #include "catalog/pg_shadow.h"
25 #include "miscadmin.h"
26 #include "tcop/tcopprot.h"
27 #include "commands/dbcommands.h"
28 #include "utils/syscache.h"
31 /* non-export function prototypes */
32 static void check_permissions(char *command, char *dbpath, char *dbname,
33 Oid *dbIdP, int4 *userIdP);
34 static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel);
35 static void stop_vacuum(char *dbpath, char *dbname);
38 createdb(char *dbname, char *dbpath, int encoding, CommandDest dest)
47 * If this call returns, the database does not exist and we're allowed
48 * to create databases.
50 check_permissions("createdb", dbpath, dbname, &db_id, &user_id);
52 /* close virtual file descriptors so we can do system() calls */
55 /* Now create directory for this new database */
56 if ((dbpath != NULL) && (strcmp(dbpath, dbname) != 0))
58 if (*(dbpath + strlen(dbpath) - 1) == SEP_CHAR)
59 *(dbpath + strlen(dbpath) - 1) = '\0';
60 snprintf(loc, 512, "%s%c%s", dbpath, SEP_CHAR, dbname);
65 lp = ExpandDatabasePath(loc);
68 elog(ERROR, "Unable to locate path '%s'"
69 "\n\tThis may be due to a missing environment variable"
70 " in the server", loc);
72 if (mkdir(lp, S_IRWXU) != 0)
73 elog(ERROR, "Unable to create database directory '%s'", lp);
75 snprintf(buf, 512, "%s %s%cbase%ctemplate1%c* %s",
76 COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, lp);
80 "insert into pg_database (datname, datdba, encoding, datpath)"
81 " values ('%s', '%d', '%d', '%s');", dbname, user_id, encoding,
84 pg_exec_query_dest(buf, dest, false);
88 destroydb(char *dbname, CommandDest dest)
93 dbpath[MAXPGPATH + 1],
97 * If this call returns, the database exists and we're allowed to
100 check_permissions("destroydb", dbpath, dbname, &db_id, &user_id);
102 if (!OidIsValid(db_id))
103 elog(FATAL, "pg_database instance has an invalid OID");
105 /* stop the vacuum daemon */
106 stop_vacuum(dbpath, dbname);
108 path = ExpandDatabasePath(dbpath);
110 elog(ERROR, "Unable to locate path '%s'"
111 "\n\tThis may be due to a missing environment variable"
112 " in the server", dbpath);
115 * remove the pg_database tuple FIRST, this may fail due to
116 * permissions problems
119 "delete from pg_database where pg_database.oid = \'%u\'::oid", db_id);
120 pg_exec_query_dest(buf, dest, false);
122 /* drop pages for this database that are in the shared buffer cache */
126 * remove the data directory. If the DELETE above failed, this will
129 snprintf(buf, 512, "rm -r %s", path);
134 get_pg_dbtup(char *command, char *dbname, Relation dbrel)
141 ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
142 F_NAMEEQ, NameGetDatum(dbname));
144 scan = heap_beginscan(dbrel, 0, SnapshotNow, 1, &scanKey);
145 if (!HeapScanIsValid(scan))
146 elog(ERROR, "%s: cannot begin scan of pg_database", command);
149 * since we want to return the tuple out of this proc, and we're going
150 * to close the relation, copy the tuple and return the copy.
152 tup = heap_getnext(scan, 0);
154 if (HeapTupleIsValid(tup))
155 dbtup = heap_copytuple(tup);
164 * check_permissions() -- verify that the user is permitted to do this.
166 * If the user is not allowed to carry out this operation, this routine
167 * elog(ERROR, ...)s, which will abort the xact. As a side effect, the
168 * user's pg_user tuple OID is returned in userIdP and the target database's
169 * OID is returned in dbIdP.
173 check_permissions(char *command,
188 char path[MAXPGPATH + 1];
190 userName = GetPgUserName();
191 utup = SearchSysCacheTuple(USENAME,
192 PointerGetDatum(userName),
194 *userIdP = ((Form_pg_shadow) GETSTRUCT(utup))->usesysid;
195 use_super = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
196 use_createdb = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
198 /* Check to make sure user has permission to use createdb */
201 elog(ERROR, "user '%s' is not allowed to create/destroy databases",
205 /* Make sure we are not mucking with the template database */
206 if (!strcmp(dbname, "template1"))
207 elog(ERROR, "%s: cannot be executed on the template database", command);
209 /* Check to make sure database is not the currently open database */
210 if (!strcmp(dbname, DatabaseName))
211 elog(ERROR, "%s: cannot be executed on an open database", command);
213 /* Check to make sure database is owned by this user */
216 * need the reldesc to get the database owner out of dbtup and to set
217 * a write lock on it.
219 dbrel = heap_openr(DatabaseRelationName);
221 if (!RelationIsValid(dbrel))
222 elog(FATAL, "%s: cannot open relation \"%-.*s\"",
223 command, DatabaseRelationName);
226 * Acquire a write lock on pg_database from the beginning to avoid
227 * upgrading a read lock to a write lock. Upgrading causes long
228 * delays when multiple 'createdb's or 'destroydb's are run simult.
231 LockRelation(dbrel, AccessExclusiveLock);
232 dbtup = get_pg_dbtup(command, dbname, dbrel);
233 dbfound = HeapTupleIsValid(dbtup);
237 dbowner = (int4) heap_getattr(dbtup,
238 Anum_pg_database_datdba,
239 RelationGetDescr(dbrel),
241 *dbIdP = dbtup->t_data->t_oid;
242 dbtext = (text *) heap_getattr(dbtup,
243 Anum_pg_database_datpath,
244 RelationGetDescr(dbrel),
247 strncpy(path, VARDATA(dbtext), (VARSIZE(dbtext) - VARHDRSZ));
248 *(path + VARSIZE(dbtext) - VARHDRSZ) = '\0';
256 * Now be sure that the user is allowed to do this.
259 if (dbfound && !strcmp(command, "createdb"))
262 elog(ERROR, "createdb: database '%s' already exists", dbname);
265 else if (!dbfound && !strcmp(command, "destroydb"))
268 elog(ERROR, "destroydb: database '%s' does not exist", dbname);
271 else if (dbfound && !strcmp(command, "destroydb")
272 && dbowner != *userIdP && use_super == false)
275 elog(ERROR, "%s: database '%s' is not owned by you", command, dbname);
279 if (dbfound && !strcmp(command, "destroydb"))
280 strcpy(dbpath, path);
281 } /* check_permissions() */
284 * stop_vacuum() -- stop the vacuum daemon on the database, if one is running.
287 stop_vacuum(char *dbpath, char *dbname)
293 if (strchr(dbpath, SEP_CHAR) != 0)
295 snprintf(filename, 256, "%s%cbase%c%s%c%s.vacuum",
296 DataDir, SEP_CHAR, SEP_CHAR, dbname, SEP_CHAR, dbname);
299 snprintf(filename, 256, "%s%c%s.vacuum", dbpath, SEP_CHAR, dbname);
302 if ((fp = AllocateFile(filename, "r")) != NULL)
304 if ((fp = AllocateFile(filename, "rb")) != NULL)
307 fscanf(fp, "%d", &pid);
309 if (kill(pid, SIGKILLDAEMON1) < 0)
311 elog(ERROR, "can't kill vacuum daemon (pid %d) on '%s'",