1 /*-------------------------------------------------------------------------
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.2 1997/11/24 05:32:18 momjian Exp $
12 *-------------------------------------------------------------------------
20 #include "miscadmin.h" /* for DataDir */
21 #include "access/heapam.h"
22 #include "access/htup.h"
23 #include "access/relscan.h"
24 #include "utils/rel.h"
25 #include "utils/elog.h"
26 #include "catalog/catname.h"
27 #include "catalog/pg_proc.h"
28 #include "catalog/pg_user.h"
29 #include "catalog/pg_database.h"
30 #include "utils/syscache.h"
31 #include "commands/dbcommands.h"
32 #include "tcop/tcopprot.h"
33 #include "storage/bufmgr.h"
34 #include "storage/lmgr.h"
35 #include "storage/fd.h"
38 /* non-export function prototypes */
40 check_permissions(char *command, char *dbpath, char *dbname,
41 Oid *dbIdP, Oid *userIdP);
42 static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel);
43 static void stop_vacuum(char *dbpath, char *dbname);
46 createdb(char *dbname, char *dbpath)
55 * If this call returns, the database does not exist and we're allowed
56 * to create databases.
58 check_permissions("createdb", dbpath, dbname, &db_id, &user_id);
60 /* close virtual file descriptors so we can do system() calls */
63 /* Now create directory for this new database */
64 if ((dbpath != NULL) && (strcmp(dbpath,dbname) != 0))
66 if (*(dbpath+strlen(dbpath)-1) == SEP_CHAR)
67 *(dbpath+strlen(dbpath)-1) = '\0';
68 sprintf(loc, "%s%c%s", dbpath, SEP_CHAR, dbname);
75 lp = ExpandDatabasePath(loc);
78 elog(WARN,"Unable to locate path '%s'"
79 "\n\tThis may be due to a missing environment variable"
80 " in the server",loc);
82 if (mkdir(lp,S_IRWXU) != 0)
83 elog(WARN,"Unable to create database directory %s",lp);
85 sprintf(buf, "%s %s%cbase%ctemplate1%c* %s",
86 COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, lp);
90 sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
91 values (\'%s\'::char16, \'%d\'::oid, \'%s\'::text);",
92 dbname, user_id, dbname);
95 sprintf(buf, "insert into pg_database (datname, datdba, datpath)"
96 " values (\'%s\', \'%d\', \'%s\');", dbname, user_id, loc);
98 pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
102 destroydb(char *dbname)
107 char dbpath[MAXPGPATH+1];
111 * If this call returns, the database exists and we're allowed to
114 check_permissions("destroydb", dbpath, dbname, &db_id, &user_id);
116 if (!OidIsValid(db_id))
118 elog(FATAL, "impossible: pg_database instance with invalid OID.");
121 /* stop the vacuum daemon */
122 stop_vacuum(dbpath, dbname);
124 path = ExpandDatabasePath(dbpath);
126 elog(WARN,"Unable to locate path '%s'"
127 "\n\tThis may be due to a missing environment variable"
128 " in the server",dbpath);
131 * remove the pg_database tuple FIRST, this may fail due to
132 * permissions problems
134 sprintf(buf, "delete from pg_database where pg_database.oid = \'%d\'::oid",
136 pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
139 * remove the data directory. If the DELETE above failed, this will
143 sprintf(buf, "rm -r %s", path);
146 /* drop pages for this database that are in the shared buffer cache */
151 get_pg_dbtup(char *command, char *dbname, Relation dbrel)
159 ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
160 NameEqualRegProcedure, NameGetDatum(dbname));
162 scan = heap_beginscan(dbrel, 0, false, 1, &scanKey);
163 if (!HeapScanIsValid(scan))
164 elog(WARN, "%s: cannot begin scan of pg_database.", command);
167 * since we want to return the tuple out of this proc, and we're going
168 * to close the relation, copy the tuple and return the copy.
170 tup = heap_getnext(scan, 0, &buf);
172 if (HeapTupleIsValid(tup))
174 dbtup = heap_copytuple(tup);
185 * check_permissions() -- verify that the user is permitted to do this.
187 * If the user is not allowed to carry out this operation, this routine
188 * elog(WARN, ...)s, which will abort the xact. As a side effect, the
189 * user's pg_user tuple OID is returned in userIdP and the target database's
190 * OID is returned in dbIdP.
194 check_permissions(char *command,
203 Oid dbowner = (Oid) 0;
209 char path[MAXPGPATH+1];
211 userName = GetPgUserName();
212 utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
214 *userIdP = ((Form_pg_user) GETSTRUCT(utup))->usesysid;
215 use_super = ((Form_pg_user) GETSTRUCT(utup))->usesuper;
216 use_createdb = ((Form_pg_user) GETSTRUCT(utup))->usecreatedb;
218 /* Check to make sure user has permission to use createdb */
221 elog(WARN, "user \"%s\" is not allowed to create/destroy databases",
225 /* Make sure we are not mucking with the template database */
226 if (!strcmp(dbname, "template1"))
228 elog(WARN, "%s cannot be executed on the template database.", command);
231 /* Check to make sure database is not the currently open database */
232 if (!strcmp(dbname, GetDatabaseName()))
234 elog(WARN, "%s cannot be executed on an open database", command);
237 /* Check to make sure database is owned by this user */
240 * need the reldesc to get the database owner out of dbtup and to set
241 * a write lock on it.
243 dbrel = heap_openr(DatabaseRelationName);
245 if (!RelationIsValid(dbrel))
246 elog(FATAL, "%s: cannot open relation \"%-.*s\"",
247 command, DatabaseRelationName);
250 * Acquire a write lock on pg_database from the beginning to avoid
251 * upgrading a read lock to a write lock. Upgrading causes long
252 * delays when multiple 'createdb's or 'destroydb's are run simult.
255 RelationSetLockForWrite(dbrel);
256 dbtup = get_pg_dbtup(command, dbname, dbrel);
257 dbfound = HeapTupleIsValid(dbtup);
261 dbowner = (Oid) heap_getattr(dbtup, InvalidBuffer,
262 Anum_pg_database_datdba,
263 RelationGetTupleDescriptor(dbrel),
265 *dbIdP = dbtup->t_oid;
266 dbtext = (text *) heap_getattr(dbtup, InvalidBuffer,
267 Anum_pg_database_datpath,
268 RelationGetTupleDescriptor(dbrel),
271 strncpy(path, VARDATA(dbtext), (VARSIZE(dbtext)-VARHDRSZ));
272 *(path+VARSIZE(dbtext)-VARHDRSZ) = '\0';
282 * Now be sure that the user is allowed to do this.
285 if (dbfound && !strcmp(command, "createdb"))
288 elog(WARN, "createdb: database %s already exists.", dbname);
291 else if (!dbfound && !strcmp(command, "destroydb"))
294 elog(WARN, "destroydb: database %s does not exist.", dbname);
297 else if (dbfound && !strcmp(command, "destroydb")
298 && dbowner != *userIdP && use_super == false)
301 elog(WARN, "%s: database %s is not owned by you.", command, dbname);
305 if (dbfound && !strcmp(command, "destroydb"))
306 strcpy(dbpath, path);
307 } /* check_permissions() */
310 * stop_vacuum() -- stop the vacuum daemon on the database, if one is running.
313 stop_vacuum(char *dbpath, char *dbname)
319 if (strchr(dbpath, SEP_CHAR) != 0)
321 sprintf(filename, "%s%cbase%c%s%c%s.vacuum", DataDir, SEP_CHAR, SEP_CHAR,
322 dbname, SEP_CHAR, dbname);
326 sprintf(filename, "%s%c%s.vacuum", dbpath, SEP_CHAR, dbname);
329 if ((fp = AllocateFile(filename, "r")) != NULL)
331 fscanf(fp, "%d", &pid);
333 if (kill(pid, SIGKILLDAEMON1) < 0)
335 elog(WARN, "can't kill vacuum daemon (pid %d) on %s",