OSDN Git Service

Move dbcommands.c to commands/. It should not be in the parser directory.
[pg-rex/syncrep.git] / src / backend / commands / dbcommands.c
1 /*-------------------------------------------------------------------------
2  *
3  * dbcommands.c--
4  *
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.2 1997/11/24 05:32:18 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <sys/stat.h>
18
19 #include "postgres.h"
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"
36
37
38 /* non-export function prototypes */
39 static void
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);
44
45 void
46 createdb(char *dbname, char *dbpath)
47 {
48         Oid                     db_id,
49                                 user_id;
50         char            buf[512];
51         char       *lp,
52                                 loc[512];
53
54         /*
55          * If this call returns, the database does not exist and we're allowed
56          * to create databases.
57          */
58         check_permissions("createdb", dbpath, dbname, &db_id, &user_id);
59
60         /* close virtual file descriptors so we can do system() calls */
61         closeAllVfds();
62
63         /* Now create directory for this new database */
64         if ((dbpath != NULL) && (strcmp(dbpath,dbname) != 0))
65         {
66                 if (*(dbpath+strlen(dbpath)-1) == SEP_CHAR)
67                         *(dbpath+strlen(dbpath)-1) = '\0';
68                 sprintf(loc, "%s%c%s", dbpath, SEP_CHAR, dbname);
69         }
70         else
71         {
72                 strcpy(loc, dbname);
73         }
74
75         lp = ExpandDatabasePath(loc);
76
77         if (lp == NULL)
78                 elog(WARN,"Unable to locate path '%s'"
79                         "\n\tThis may be due to a missing environment variable"
80                         " in the server",loc);
81
82         if (mkdir(lp,S_IRWXU) != 0)
83                 elog(WARN,"Unable to create database directory %s",lp);
84
85         sprintf(buf, "%s %s%cbase%ctemplate1%c* %s",
86                         COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, lp);
87         system(buf);
88
89 #if FALSE
90         sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
91                   values (\'%s\'::char16, \'%d\'::oid, \'%s\'::text);",
92                         dbname, user_id, dbname);
93 #endif
94
95         sprintf(buf, "insert into pg_database (datname, datdba, datpath)"
96                 " values (\'%s\', \'%d\', \'%s\');", dbname, user_id, loc);
97
98         pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
99 }
100
101 void
102 destroydb(char *dbname)
103 {
104         Oid                     user_id,
105                                 db_id;
106         char       *path;
107         char            dbpath[MAXPGPATH+1];
108         char            buf[512];
109
110         /*
111          * If this call returns, the database exists and we're allowed to
112          * remove it.
113          */
114         check_permissions("destroydb", dbpath, dbname, &db_id, &user_id);
115
116         if (!OidIsValid(db_id))
117         {
118                 elog(FATAL, "impossible: pg_database instance with invalid OID.");
119         }
120
121         /* stop the vacuum daemon */
122         stop_vacuum(dbpath, dbname);
123
124         path = ExpandDatabasePath(dbpath);
125     if (path == NULL)
126                 elog(WARN,"Unable to locate path '%s'"
127                         "\n\tThis may be due to a missing environment variable"
128                         " in the server",dbpath);
129
130         /*
131          * remove the pg_database tuple FIRST, this may fail due to
132          * permissions problems
133          */
134         sprintf(buf, "delete from pg_database where pg_database.oid = \'%d\'::oid",
135                         db_id);
136         pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
137
138         /*
139          * remove the data directory. If the DELETE above failed, this will
140          * not be reached
141          */
142
143         sprintf(buf, "rm -r %s", path);
144         system(buf);
145
146         /* drop pages for this database that are in the shared buffer cache */
147         DropBuffers(db_id);
148 }
149
150 static HeapTuple
151 get_pg_dbtup(char *command, char *dbname, Relation dbrel)
152 {
153         HeapTuple       dbtup;
154         HeapTuple       tup;
155         Buffer          buf;
156         HeapScanDesc scan;
157         ScanKeyData scanKey;
158
159         ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
160                                                    NameEqualRegProcedure, NameGetDatum(dbname));
161
162         scan = heap_beginscan(dbrel, 0, false, 1, &scanKey);
163         if (!HeapScanIsValid(scan))
164                 elog(WARN, "%s: cannot begin scan of pg_database.", command);
165
166         /*
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.
169          */
170         tup = heap_getnext(scan, 0, &buf);
171
172         if (HeapTupleIsValid(tup))
173         {
174                 dbtup = heap_copytuple(tup);
175                 ReleaseBuffer(buf);
176         }
177         else
178                 dbtup = tup;
179
180         heap_endscan(scan);
181         return (dbtup);
182 }
183
184 /*
185  *      check_permissions() -- verify that the user is permitted to do this.
186  *
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.
191  */
192
193 static void
194 check_permissions(char *command,
195                                   char *dbpath,
196                                   char *dbname,
197                                   Oid *dbIdP,
198                                   Oid *userIdP)
199 {
200         Relation        dbrel;
201         HeapTuple       dbtup,
202                                 utup;
203         Oid                     dbowner = (Oid) 0;
204         char            use_createdb;
205         bool            dbfound;
206         bool            use_super;
207         char       *userName;
208         text       *dbtext;
209         char            path[MAXPGPATH+1];
210
211         userName = GetPgUserName();
212         utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
213                                                            0, 0, 0);
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;
217
218         /* Check to make sure user has permission to use createdb */
219         if (!use_createdb)
220         {
221                 elog(WARN, "user \"%s\" is not allowed to create/destroy databases",
222                          userName);
223         }
224
225         /* Make sure we are not mucking with the template database */
226         if (!strcmp(dbname, "template1"))
227         {
228                 elog(WARN, "%s cannot be executed on the template database.", command);
229         }
230
231         /* Check to make sure database is not the currently open database */
232         if (!strcmp(dbname, GetDatabaseName()))
233         {
234                 elog(WARN, "%s cannot be executed on an open database", command);
235         }
236
237         /* Check to make sure database is owned by this user */
238
239         /*
240          * need the reldesc to get the database owner out of dbtup and to set
241          * a write lock on it.
242          */
243         dbrel = heap_openr(DatabaseRelationName);
244
245         if (!RelationIsValid(dbrel))
246                 elog(FATAL, "%s: cannot open relation \"%-.*s\"",
247                          command, DatabaseRelationName);
248
249         /*
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.
253          * -mer 7/3/91
254          */
255         RelationSetLockForWrite(dbrel);
256         dbtup = get_pg_dbtup(command, dbname, dbrel);
257         dbfound = HeapTupleIsValid(dbtup);
258
259         if (dbfound)
260         {
261                 dbowner = (Oid) heap_getattr(dbtup, InvalidBuffer,
262                                                                          Anum_pg_database_datdba,
263                                                                          RelationGetTupleDescriptor(dbrel),
264                                                                          (char *) NULL);
265                 *dbIdP = dbtup->t_oid;
266                 dbtext = (text *) heap_getattr(dbtup, InvalidBuffer,
267                                                                  Anum_pg_database_datpath,
268                                                                  RelationGetTupleDescriptor(dbrel),
269                                                                  (char *) NULL);
270
271                 strncpy(path, VARDATA(dbtext), (VARSIZE(dbtext)-VARHDRSZ));
272                  *(path+VARSIZE(dbtext)-VARHDRSZ) = '\0';
273         }
274         else
275         {
276                 *dbIdP = InvalidOid;
277         }
278
279         heap_close(dbrel);
280
281         /*
282          * Now be sure that the user is allowed to do this.
283          */
284
285         if (dbfound && !strcmp(command, "createdb"))
286         {
287
288                 elog(WARN, "createdb: database %s already exists.", dbname);
289
290         }
291         else if (!dbfound && !strcmp(command, "destroydb"))
292         {
293
294                 elog(WARN, "destroydb: database %s does not exist.", dbname);
295
296         }
297         else if (dbfound && !strcmp(command, "destroydb")
298                          && dbowner != *userIdP && use_super == false)
299         {
300
301                 elog(WARN, "%s: database %s is not owned by you.", command, dbname);
302
303         }
304
305         if (dbfound && !strcmp(command, "destroydb"))
306                 strcpy(dbpath, path);
307 } /* check_permissions() */
308
309 /*
310  *      stop_vacuum() -- stop the vacuum daemon on the database, if one is running.
311  */
312 static void
313 stop_vacuum(char *dbpath, char *dbname)
314 {
315         char            filename[256];
316         FILE       *fp;
317         int                     pid;
318
319         if (strchr(dbpath, SEP_CHAR) != 0)
320         {
321                 sprintf(filename, "%s%cbase%c%s%c%s.vacuum", DataDir, SEP_CHAR, SEP_CHAR,
322                         dbname, SEP_CHAR, dbname);
323         }
324         else
325         {
326                 sprintf(filename, "%s%c%s.vacuum", dbpath, SEP_CHAR, dbname);
327         }
328
329         if ((fp = AllocateFile(filename, "r")) != NULL)
330         {
331                 fscanf(fp, "%d", &pid);
332                 FreeFile(fp);
333                 if (kill(pid, SIGKILLDAEMON1) < 0)
334                 {
335                         elog(WARN, "can't kill vacuum daemon (pid %d) on %s",
336                                  pid, dbname);
337                 }
338         }
339 }