1 /*-------------------------------------------------------------------------
4 * Database management commands (create/drop database).
7 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.144 2004/08/30 03:50:24 tgl Exp $
14 *-------------------------------------------------------------------------
22 #include "access/genam.h"
23 #include "access/heapam.h"
24 #include "catalog/catname.h"
25 #include "catalog/catalog.h"
26 #include "catalog/pg_database.h"
27 #include "catalog/pg_shadow.h"
28 #include "catalog/pg_tablespace.h"
29 #include "catalog/indexing.h"
30 #include "commands/comment.h"
31 #include "commands/dbcommands.h"
32 #include "commands/tablespace.h"
33 #include "mb/pg_wchar.h"
34 #include "miscadmin.h"
35 #include "storage/fd.h"
36 #include "storage/freespace.h"
37 #include "storage/sinval.h"
38 #include "utils/acl.h"
39 #include "utils/array.h"
40 #include "utils/builtins.h"
41 #include "utils/fmgroids.h"
42 #include "utils/guc.h"
43 #include "utils/lsyscache.h"
44 #include "utils/syscache.h"
47 /* non-export function prototypes */
48 static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
49 int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
50 TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
52 static bool have_createdb_privilege(void);
53 static void remove_dbtablespaces(Oid db_id);
60 createdb(const CreatedbStmt *stmt)
69 TransactionId src_vacuumxid;
70 TransactionId src_frozenxid;
71 Oid src_deftablespace;
72 Oid dst_deftablespace;
73 Relation pg_database_rel;
75 TupleDesc pg_database_dsc;
76 Datum new_record[Natts_pg_database];
77 char new_record_nulls[Natts_pg_database];
81 DefElem *dtablespacename = NULL;
82 DefElem *downer = NULL;
83 DefElem *dtemplate = NULL;
84 DefElem *dencoding = NULL;
85 char *dbname = stmt->dbname;
87 char *dbtemplate = NULL;
91 char buf[2 * MAXPGPATH + 100];
94 /* don't call this in a transaction block */
95 PreventTransactionChain((void *) stmt, "CREATE DATABASE");
97 /* Extract options from the statement node tree */
98 foreach(option, stmt->options)
100 DefElem *defel = (DefElem *) lfirst(option);
102 if (strcmp(defel->defname, "tablespace") == 0)
106 (errcode(ERRCODE_SYNTAX_ERROR),
107 errmsg("conflicting or redundant options")));
108 dtablespacename = defel;
110 else if (strcmp(defel->defname, "owner") == 0)
114 (errcode(ERRCODE_SYNTAX_ERROR),
115 errmsg("conflicting or redundant options")));
118 else if (strcmp(defel->defname, "template") == 0)
122 (errcode(ERRCODE_SYNTAX_ERROR),
123 errmsg("conflicting or redundant options")));
126 else if (strcmp(defel->defname, "encoding") == 0)
130 (errcode(ERRCODE_SYNTAX_ERROR),
131 errmsg("conflicting or redundant options")));
134 else if (strcmp(defel->defname, "location") == 0)
137 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
138 errmsg("LOCATION is not supported anymore"),
139 errhint("Consider using tablespaces instead.")));
142 elog(ERROR, "option \"%s\" not recognized",
146 if (downer && downer->arg)
147 dbowner = strVal(downer->arg);
148 if (dtemplate && dtemplate->arg)
149 dbtemplate = strVal(dtemplate->arg);
150 if (dencoding && dencoding->arg)
152 const char *encoding_name;
154 if (IsA(dencoding->arg, Integer))
156 encoding = intVal(dencoding->arg);
157 encoding_name = pg_encoding_to_char(encoding);
158 if (strcmp(encoding_name, "") == 0 ||
159 pg_valid_server_encoding(encoding_name) < 0)
161 (errcode(ERRCODE_UNDEFINED_OBJECT),
162 errmsg("%d is not a valid encoding code",
165 else if (IsA(dencoding->arg, String))
167 encoding_name = strVal(dencoding->arg);
168 if (pg_valid_server_encoding(encoding_name) < 0)
170 (errcode(ERRCODE_UNDEFINED_OBJECT),
171 errmsg("%s is not a valid encoding name",
173 encoding = pg_char_to_encoding(encoding_name);
176 elog(ERROR, "unrecognized node type: %d",
177 nodeTag(dencoding->arg));
180 /* obtain sysid of proposed owner */
182 datdba = get_usesysid(dbowner); /* will ereport if no such user */
184 datdba = GetUserId();
186 if (datdba == GetUserId())
188 /* creating database for self: can be superuser or createdb */
189 if (!superuser() && !have_createdb_privilege())
191 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
192 errmsg("permission denied to create database")));
196 /* creating database for someone else: must be superuser */
197 /* note that the someone else need not have any permissions */
200 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
201 errmsg("must be superuser to create database for another user")));
205 * Check for db name conflict. There is a race condition here, since
206 * another backend could create the same DB name before we commit.
207 * However, holding an exclusive lock on pg_database for the whole
208 * time we are copying the source database doesn't seem like a good
209 * idea, so accept possibility of race to create. We will check again
210 * after we grab the exclusive lock.
212 if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
214 (errcode(ERRCODE_DUPLICATE_DATABASE),
215 errmsg("database \"%s\" already exists", dbname)));
218 * Lookup database (template) to be cloned.
221 dbtemplate = "template1"; /* Default template database name */
223 if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
224 &src_istemplate, &src_lastsysoid,
225 &src_vacuumxid, &src_frozenxid, &src_deftablespace))
227 (errcode(ERRCODE_UNDEFINED_DATABASE),
228 errmsg("template database \"%s\" does not exist", dbtemplate)));
231 * Permission check: to copy a DB that's not marked datistemplate, you
232 * must be superuser or the owner thereof.
236 if (!superuser() && GetUserId() != src_owner)
238 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
239 errmsg("permission denied to copy database \"%s\"",
244 * The source DB can't have any active backends, except this one
245 * (exception is to allow CREATE DB while connected to template1).
246 * Otherwise we might copy inconsistent data. This check is not
247 * bulletproof, since someone might connect while we are copying...
249 if (DatabaseHasActiveBackends(src_dboid, true))
251 (errcode(ERRCODE_OBJECT_IN_USE),
252 errmsg("source database \"%s\" is being accessed by other users",
255 /* If encoding is defaulted, use source's encoding */
257 encoding = src_encoding;
259 /* Some encodings are client only */
260 if (!PG_VALID_BE_ENCODING(encoding))
262 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
263 errmsg("invalid server encoding %d", encoding)));
265 /* Resolve default tablespace for new database */
266 if (dtablespacename && dtablespacename->arg)
268 char *tablespacename;
271 tablespacename = strVal(dtablespacename->arg);
272 dst_deftablespace = get_tablespace_oid(tablespacename);
273 if (!OidIsValid(dst_deftablespace))
275 (errcode(ERRCODE_UNDEFINED_OBJECT),
276 errmsg("tablespace \"%s\" does not exist",
278 /* check permissions */
279 aclresult = pg_tablespace_aclcheck(dst_deftablespace, GetUserId(),
281 if (aclresult != ACLCHECK_OK)
282 aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
287 /* Use template database's default tablespace */
288 dst_deftablespace = src_deftablespace;
289 /* Note there is no additional permission check in this path */
293 * Preassign OID for pg_database tuple, so that we can compute db
299 * Force dirty buffers out to disk, to ensure source database is
300 * up-to-date for the copy. (We really only need to flush buffers for
301 * the source database...)
306 * Close virtual file descriptors so the kernel has more available for
307 * the system() calls below.
312 * Iterate through all tablespaces of the template database, and copy
313 * each one to the new database.
315 * If we are trying to change the default tablespace of the template, we
316 * require that the template not have any files in the new default
317 * tablespace. This avoids the need to merge two subdirectories. This
318 * could probably be improved later.
320 rel = heap_openr(TableSpaceRelationName, AccessShareLock);
321 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
322 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
324 Oid srctablespace = HeapTupleGetOid(tuple);
330 /* No need to copy global tablespace */
331 if (srctablespace == GLOBALTABLESPACE_OID)
334 srcpath = GetDatabasePath(src_dboid, srctablespace);
336 if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode))
338 /* Assume we can ignore it */
343 if (srctablespace == src_deftablespace)
344 dsttablespace = dst_deftablespace;
346 dsttablespace = srctablespace;
348 dstpath = GetDatabasePath(dboid, dsttablespace);
350 if (stat(dstpath, &st) == 0 || errno != ENOENT)
352 remove_dbtablespaces(dboid);
354 (errmsg("could not initialize database directory"),
355 errdetail("Directory \"%s\" already exists.", dstpath)));
361 * Copy this subdirectory to the new location
363 * XXX use of cp really makes this code pretty grotty, particularly
364 * with respect to lack of ability to report errors well. Someday
365 * rewrite to do it for ourselves.
368 /* We might need to use cp -R one day for portability */
369 snprintf(buf, sizeof(buf), "cp -r '%s' '%s'",
371 if (system(buf) != 0)
373 remove_dbtablespaces(dboid);
375 (errmsg("could not initialize database directory"),
376 errdetail("Failing system command was: %s", buf),
377 errhint("Look in the postmaster's stderr log for more information.")));
380 if (copydir(srcpath, dstpath) != 0)
382 /* copydir should already have given details of its troubles */
383 remove_dbtablespaces(dboid);
385 (errmsg("could not initialize database directory")));
389 /* Record the filesystem change in XLOG */
391 xl_dbase_create_rec xlrec;
392 XLogRecData rdata[3];
395 rdata[0].buffer = InvalidBuffer;
396 rdata[0].data = (char *) &xlrec;
397 rdata[0].len = offsetof(xl_dbase_create_rec, src_path);
398 rdata[0].next = &(rdata[1]);
400 rdata[1].buffer = InvalidBuffer;
401 rdata[1].data = (char *) srcpath;
402 rdata[1].len = strlen(srcpath) + 1;
403 rdata[1].next = &(rdata[2]);
405 rdata[2].buffer = InvalidBuffer;
406 rdata[2].data = (char *) dstpath;
407 rdata[2].len = strlen(dstpath) + 1;
408 rdata[2].next = NULL;
410 (void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_CREATE, rdata);
414 heap_close(rel, AccessShareLock);
417 * Now OK to grab exclusive lock on pg_database.
419 pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
421 /* Check to see if someone else created same DB name meanwhile. */
422 if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
424 /* Don't hold lock while doing recursive remove */
425 heap_close(pg_database_rel, AccessExclusiveLock);
426 remove_dbtablespaces(dboid);
428 (errcode(ERRCODE_DUPLICATE_DATABASE),
429 errmsg("database \"%s\" already exists", dbname)));
433 * Insert a new tuple into pg_database
435 pg_database_dsc = RelationGetDescr(pg_database_rel);
438 MemSet(new_record, 0, sizeof(new_record));
439 MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
441 new_record[Anum_pg_database_datname - 1] =
442 DirectFunctionCall1(namein, CStringGetDatum(dbname));
443 new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba);
444 new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
445 new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
446 new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
447 new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
448 new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
449 new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
450 new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
453 * We deliberately set datconfig and datacl to defaults (NULL), rather
454 * than copying them from the template database. Copying datacl would
455 * be a bad idea when the owner is not the same as the template's
456 * owner. It's more debatable whether datconfig should be copied.
458 new_record_nulls[Anum_pg_database_datconfig - 1] = 'n';
459 new_record_nulls[Anum_pg_database_datacl - 1] = 'n';
461 tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
463 HeapTupleSetOid(tuple, dboid); /* override heap_insert's OID
466 simple_heap_insert(pg_database_rel, tuple);
469 CatalogUpdateIndexes(pg_database_rel, tuple);
471 /* Close pg_database, but keep lock till commit */
472 heap_close(pg_database_rel, NoLock);
475 * Force dirty buffers out to disk, so that newly-connecting backends
476 * will see the new database in pg_database right away. (They'll see
477 * an uncommitted tuple, but they don't care; see GetRawDatabaseInfo.)
487 dropdb(const char *dbname)
493 SysScanDesc pgdbscan;
497 PreventTransactionChain((void *) dbname, "DROP DATABASE");
501 if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)
503 (errcode(ERRCODE_OBJECT_IN_USE),
504 errmsg("cannot drop the currently open database")));
507 * Obtain exclusive lock on pg_database. We need this to ensure that
508 * no new backend starts up in the target database while we are
509 * deleting it. (Actually, a new backend might still manage to start
510 * up, because it will read pg_database without any locking to
511 * discover the database's OID. But it will detect its error in
512 * ReverifyMyDatabase and shut down before any serious damage is done.
515 pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
517 if (!get_db_info(dbname, &db_id, &db_owner, NULL,
518 &db_istemplate, NULL, NULL, NULL, NULL))
520 (errcode(ERRCODE_UNDEFINED_DATABASE),
521 errmsg("database \"%s\" does not exist", dbname)));
523 if (GetUserId() != db_owner && !superuser())
524 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
528 * Disallow dropping a DB that is marked istemplate. This is just to
529 * prevent people from accidentally dropping template0 or template1;
530 * they can do so if they're really determined ...
534 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
535 errmsg("cannot drop a template database")));
538 * Check for active backends in the target database.
540 if (DatabaseHasActiveBackends(db_id, false))
542 (errcode(ERRCODE_OBJECT_IN_USE),
543 errmsg("database \"%s\" is being accessed by other users",
547 * Find the database's tuple by OID (should be unique).
550 ObjectIdAttributeNumber,
551 BTEqualStrategyNumber, F_OIDEQ,
552 ObjectIdGetDatum(db_id));
554 pgdbscan = systable_beginscan(pgdbrel, DatabaseOidIndex, true,
555 SnapshotNow, 1, &key);
557 tup = systable_getnext(pgdbscan);
558 if (!HeapTupleIsValid(tup))
561 * This error should never come up since the existence of the
562 * database is checked earlier
564 elog(ERROR, "database \"%s\" doesn't exist despite earlier reports to the contrary",
568 /* Remove the database's tuple from pg_database */
569 simple_heap_delete(pgdbrel, &tup->t_self);
571 systable_endscan(pgdbscan);
574 * Delete any comments associated with the database
576 * NOTE: this is probably dead code since any such comments should have
577 * been in that database, not mine.
579 DeleteComments(db_id, RelationGetRelid(pgdbrel), 0);
582 * Close pg_database, but keep exclusive lock till commit to ensure
583 * that any new backend scanning pg_database will see the tuple dead.
585 heap_close(pgdbrel, NoLock);
588 * Drop pages for this database that are in the shared buffer cache.
589 * This is important to ensure that no remaining backend tries to
590 * write out a dirty buffer to the dead database later...
595 * Also, clean out any entries in the shared free space map.
597 FreeSpaceMapForgetDatabase(db_id);
600 * Remove all tablespace subdirs belonging to the database.
602 remove_dbtablespaces(db_id);
605 * Force dirty buffers out to disk, so that newly-connecting backends
606 * will see the database tuple marked dead in pg_database right away.
607 * (They'll see an uncommitted deletion, but they don't care; see
608 * GetRawDatabaseInfo.)
618 RenameDatabase(const char *oldname, const char *newname)
629 * Obtain AccessExclusiveLock so that no new session gets started
630 * while the rename is in progress.
632 rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
635 Anum_pg_database_datname,
636 BTEqualStrategyNumber, F_NAMEEQ,
637 NameGetDatum(oldname));
638 scan = systable_beginscan(rel, DatabaseNameIndex, true,
639 SnapshotNow, 1, &key);
641 tup = systable_getnext(scan);
642 if (!HeapTupleIsValid(tup))
644 (errcode(ERRCODE_UNDEFINED_DATABASE),
645 errmsg("database \"%s\" does not exist", oldname)));
648 * XXX Client applications probably store the current database
649 * somewhere, so renaming it could cause confusion. On the other
650 * hand, there may not be an actual problem besides a little
651 * confusion, so think about this and decide.
653 if (HeapTupleGetOid(tup) == MyDatabaseId)
655 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
656 errmsg("current database may not be renamed")));
659 * Make sure the database does not have active sessions. Might not be
660 * necessary, but it's consistent with other database operations.
662 if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false))
664 (errcode(ERRCODE_OBJECT_IN_USE),
665 errmsg("database \"%s\" is being accessed by other users",
668 /* make sure the new name doesn't exist */
670 Anum_pg_database_datname,
671 BTEqualStrategyNumber, F_NAMEEQ,
672 NameGetDatum(newname));
673 scan2 = systable_beginscan(rel, DatabaseNameIndex, true,
674 SnapshotNow, 1, &key2);
675 if (HeapTupleIsValid(systable_getnext(scan2)))
677 (errcode(ERRCODE_DUPLICATE_DATABASE),
678 errmsg("database \"%s\" already exists", newname)));
679 systable_endscan(scan2);
682 if (!pg_database_ownercheck(HeapTupleGetOid(tup), GetUserId()))
683 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
686 /* must have createdb */
687 if (!have_createdb_privilege())
689 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
690 errmsg("permission denied to rename database")));
693 newtup = heap_copytuple(tup);
694 namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname);
695 simple_heap_update(rel, &newtup->t_self, newtup);
696 CatalogUpdateIndexes(rel, newtup);
698 systable_endscan(scan);
699 heap_close(rel, NoLock);
702 * Force dirty buffers out to disk, so that newly-connecting backends
703 * will see the renamed database in pg_database right away. (They'll
704 * see an uncommitted tuple, but they don't care; see
705 * GetRawDatabaseInfo.)
712 * ALTER DATABASE name SET ...
715 AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
723 Datum repl_val[Natts_pg_database];
724 char repl_null[Natts_pg_database];
725 char repl_repl[Natts_pg_database];
727 valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
729 rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
730 ScanKeyInit(&scankey,
731 Anum_pg_database_datname,
732 BTEqualStrategyNumber, F_NAMEEQ,
733 NameGetDatum(stmt->dbname));
734 scan = systable_beginscan(rel, DatabaseNameIndex, true,
735 SnapshotNow, 1, &scankey);
736 tuple = systable_getnext(scan);
737 if (!HeapTupleIsValid(tuple))
739 (errcode(ERRCODE_UNDEFINED_DATABASE),
740 errmsg("database \"%s\" does not exist", stmt->dbname)));
743 || ((Form_pg_database) GETSTRUCT(tuple))->datdba == GetUserId()))
744 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
747 MemSet(repl_repl, ' ', sizeof(repl_repl));
748 repl_repl[Anum_pg_database_datconfig - 1] = 'r';
750 if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL)
753 repl_null[Anum_pg_database_datconfig - 1] = 'n';
754 repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0;
762 repl_null[Anum_pg_database_datconfig - 1] = ' ';
764 datum = heap_getattr(tuple, Anum_pg_database_datconfig,
765 RelationGetDescr(rel), &isnull);
767 a = isnull ? NULL : DatumGetArrayTypeP(datum);
770 a = GUCArrayAdd(a, stmt->variable, valuestr);
772 a = GUCArrayDelete(a, stmt->variable);
775 repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a);
777 repl_null[Anum_pg_database_datconfig - 1] = 'n';
780 newtuple = heap_modifytuple(tuple, rel, repl_val, repl_null, repl_repl);
781 simple_heap_update(rel, &tuple->t_self, newtuple);
784 CatalogUpdateIndexes(rel, newtuple);
786 systable_endscan(scan);
787 heap_close(rel, NoLock);
792 * ALTER DATABASE name OWNER TO newowner
795 AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
801 Form_pg_database datForm;
803 rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
804 ScanKeyInit(&scankey,
805 Anum_pg_database_datname,
806 BTEqualStrategyNumber, F_NAMEEQ,
807 NameGetDatum(dbname));
808 scan = systable_beginscan(rel, DatabaseNameIndex, true,
809 SnapshotNow, 1, &scankey);
810 tuple = systable_getnext(scan);
811 if (!HeapTupleIsValid(tuple))
813 (errcode(ERRCODE_UNDEFINED_DATABASE),
814 errmsg("database \"%s\" does not exist", dbname)));
816 datForm = (Form_pg_database) GETSTRUCT(tuple);
819 * If the new owner is the same as the existing owner, consider the
820 * command to have succeeded. This is to be consistent with other
823 if (datForm->datdba != newOwnerSysId)
825 Datum repl_val[Natts_pg_database];
826 char repl_null[Natts_pg_database];
827 char repl_repl[Natts_pg_database];
833 /* changing owner's database for someone else: must be superuser */
834 /* note that the someone else need not have any permissions */
837 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
838 errmsg("must be superuser to change owner")));
840 memset(repl_null, ' ', sizeof(repl_null));
841 memset(repl_repl, ' ', sizeof(repl_repl));
843 repl_repl[Anum_pg_database_datdba - 1] = 'r';
844 repl_val[Anum_pg_database_datdba - 1] = Int32GetDatum(newOwnerSysId);
847 * Determine the modified ACL for the new owner. This is only
848 * necessary when the ACL is non-null.
850 aclDatum = heap_getattr(tuple,
851 Anum_pg_database_datacl,
852 RelationGetDescr(rel),
856 newAcl = aclnewowner(DatumGetAclP(aclDatum),
857 datForm->datdba, newOwnerSysId);
858 repl_repl[Anum_pg_database_datacl - 1] = 'r';
859 repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl);
862 newtuple = heap_modifytuple(tuple, rel, repl_val, repl_null, repl_repl);
863 simple_heap_update(rel, &newtuple->t_self, newtuple);
864 CatalogUpdateIndexes(rel, newtuple);
866 heap_freetuple(newtuple);
869 systable_endscan(scan);
870 heap_close(rel, NoLock);
879 get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
880 int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
881 TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
892 /* Caller may wish to grab a better lock on pg_database beforehand... */
893 relation = heap_openr(DatabaseRelationName, AccessShareLock);
895 ScanKeyInit(&scanKey,
896 Anum_pg_database_datname,
897 BTEqualStrategyNumber, F_NAMEEQ,
900 scan = systable_beginscan(relation, DatabaseNameIndex, true,
901 SnapshotNow, 1, &scanKey);
903 tuple = systable_getnext(scan);
905 gottuple = HeapTupleIsValid(tuple);
908 Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
910 /* oid of the database */
912 *dbIdP = HeapTupleGetOid(tuple);
913 /* sysid of the owner */
915 *ownerIdP = dbform->datdba;
916 /* character encoding */
918 *encodingP = dbform->encoding;
919 /* allowed as template? */
921 *dbIsTemplateP = dbform->datistemplate;
922 /* last system OID used in database */
924 *dbLastSysOidP = dbform->datlastsysoid;
925 /* limit of vacuumed XIDs */
927 *dbVacuumXidP = dbform->datvacuumxid;
928 /* limit of frozen XIDs */
930 *dbFrozenXidP = dbform->datfrozenxid;
931 /* default tablespace for this database */
933 *dbTablespace = dbform->dattablespace;
936 systable_endscan(scan);
937 heap_close(relation, AccessShareLock);
943 have_createdb_privilege(void)
948 utup = SearchSysCache(SHADOWSYSID,
949 Int32GetDatum(GetUserId()),
952 if (!HeapTupleIsValid(utup))
955 retval = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
957 ReleaseSysCache(utup);
963 * Remove tablespace directories
965 * We don't know what tablespaces db_id is using, so iterate through all
966 * tablespaces removing <tablespace>/db_id
969 remove_dbtablespaces(Oid db_id)
975 rel = heap_openr(TableSpaceRelationName, AccessShareLock);
976 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
977 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
979 Oid dsttablespace = HeapTupleGetOid(tuple);
983 /* Don't mess with the global tablespace */
984 if (dsttablespace == GLOBALTABLESPACE_OID)
987 dstpath = GetDatabasePath(db_id, dsttablespace);
989 if (stat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode))
991 /* Assume we can ignore it */
996 if (!rmtree(dstpath, true))
998 (errmsg("could not remove database directory \"%s\"",
1001 /* Record the filesystem change in XLOG */
1003 xl_dbase_drop_rec xlrec;
1004 XLogRecData rdata[2];
1006 xlrec.db_id = db_id;
1007 rdata[0].buffer = InvalidBuffer;
1008 rdata[0].data = (char *) &xlrec;
1009 rdata[0].len = offsetof(xl_dbase_drop_rec, dir_path);
1010 rdata[0].next = &(rdata[1]);
1012 rdata[1].buffer = InvalidBuffer;
1013 rdata[1].data = (char *) dstpath;
1014 rdata[1].len = strlen(dstpath) + 1;
1015 rdata[1].next = NULL;
1017 (void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_DROP, rdata);
1024 heap_close(rel, AccessShareLock);
1029 * get_database_oid - given a database name, look up the OID
1031 * Returns InvalidOid if database name not found.
1033 * This is not actually used in this file, but is exported for use elsewhere.
1036 get_database_oid(const char *dbname)
1038 Relation pg_database;
1039 ScanKeyData entry[1];
1044 /* There's no syscache for pg_database, so must look the hard way */
1045 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1046 ScanKeyInit(&entry[0],
1047 Anum_pg_database_datname,
1048 BTEqualStrategyNumber, F_NAMEEQ,
1049 CStringGetDatum(dbname));
1050 scan = systable_beginscan(pg_database, DatabaseNameIndex, true,
1051 SnapshotNow, 1, entry);
1053 dbtuple = systable_getnext(scan);
1055 /* We assume that there can be at most one matching tuple */
1056 if (HeapTupleIsValid(dbtuple))
1057 oid = HeapTupleGetOid(dbtuple);
1061 systable_endscan(scan);
1062 heap_close(pg_database, AccessShareLock);
1069 * get_database_name - given a database OID, look up the name
1071 * Returns a palloc'd string, or NULL if no such database.
1073 * This is not actually used in this file, but is exported for use elsewhere.
1076 get_database_name(Oid dbid)
1078 Relation pg_database;
1079 ScanKeyData entry[1];
1084 /* There's no syscache for pg_database, so must look the hard way */
1085 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1086 ScanKeyInit(&entry[0],
1087 ObjectIdAttributeNumber,
1088 BTEqualStrategyNumber, F_OIDEQ,
1089 ObjectIdGetDatum(dbid));
1090 scan = systable_beginscan(pg_database, DatabaseOidIndex, true,
1091 SnapshotNow, 1, entry);
1093 dbtuple = systable_getnext(scan);
1095 /* We assume that there can be at most one matching tuple */
1096 if (HeapTupleIsValid(dbtuple))
1097 result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname));
1101 systable_endscan(scan);
1102 heap_close(pg_database, AccessShareLock);
1108 * DATABASE resource manager's routines
1111 dbase_redo(XLogRecPtr lsn, XLogRecord *record)
1113 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1115 if (info == XLOG_DBASE_CREATE)
1117 xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) XLogRecGetData(record);
1118 char *dst_path = xlrec->src_path + strlen(xlrec->src_path) + 1;
1122 char buf[2 * MAXPGPATH + 100];
1126 * Our theory for replaying a CREATE is to forcibly drop the
1127 * target subdirectory if present, then re-copy the source data.
1128 * This may be more work than needed, but it is simple to
1131 if (stat(dst_path, &st) == 0 && S_ISDIR(st.st_mode))
1133 if (!rmtree(dst_path, true))
1135 (errmsg("could not remove database directory \"%s\"",
1140 * Force dirty buffers out to disk, to ensure source database is
1141 * up-to-date for the copy. (We really only need to flush buffers for
1142 * the source database...)
1149 * Copy this subdirectory to the new location
1151 * XXX use of cp really makes this code pretty grotty, particularly
1152 * with respect to lack of ability to report errors well. Someday
1153 * rewrite to do it for ourselves.
1156 /* We might need to use cp -R one day for portability */
1157 snprintf(buf, sizeof(buf), "cp -r '%s' '%s'",
1158 xlrec->src_path, dst_path);
1159 if (system(buf) != 0)
1161 (errmsg("could not initialize database directory"),
1162 errdetail("Failing system command was: %s", buf),
1163 errhint("Look in the postmaster's stderr log for more information.")));
1165 if (copydir(xlrec->src_path, dst_path) != 0)
1167 /* copydir should already have given details of its troubles */
1169 (errmsg("could not initialize database directory")));
1173 else if (info == XLOG_DBASE_DROP)
1175 xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) XLogRecGetData(record);
1178 * Drop pages for this database that are in the shared buffer
1181 DropBuffers(xlrec->db_id);
1183 if (!rmtree(xlrec->dir_path, true))
1185 (errmsg("could not remove database directory \"%s\"",
1189 elog(PANIC, "dbase_redo: unknown op code %u", info);
1193 dbase_undo(XLogRecPtr lsn, XLogRecord *record)
1195 elog(PANIC, "dbase_undo: unimplemented");
1199 dbase_desc(char *buf, uint8 xl_info, char *rec)
1201 uint8 info = xl_info & ~XLR_INFO_MASK;
1203 if (info == XLOG_DBASE_CREATE)
1205 xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
1206 char *dst_path = xlrec->src_path + strlen(xlrec->src_path) + 1;
1208 sprintf(buf + strlen(buf), "create db: %u copy \"%s\" to \"%s\"",
1209 xlrec->db_id, xlrec->src_path, dst_path);
1211 else if (info == XLOG_DBASE_DROP)
1213 xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
1215 sprintf(buf + strlen(buf), "drop db: %u directory: \"%s\"",
1216 xlrec->db_id, xlrec->dir_path);
1219 strcat(buf, "UNKNOWN");