1 /*-------------------------------------------------------------------------
4 * Database management commands (create/drop database).
7 * Portions Copyright (c) 1996-2003, 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.139 2004/08/01 20:30:48 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;
90 char buf[2 * MAXPGPATH + 100];
93 /* don't call this in a transaction block */
94 PreventTransactionChain((void *) stmt, "CREATE DATABASE");
96 /* Extract options from the statement node tree */
97 foreach(option, stmt->options)
99 DefElem *defel = (DefElem *) lfirst(option);
101 if (strcmp(defel->defname, "tablespace") == 0)
105 (errcode(ERRCODE_SYNTAX_ERROR),
106 errmsg("conflicting or redundant options")));
107 dtablespacename = defel;
109 else if (strcmp(defel->defname, "owner") == 0)
113 (errcode(ERRCODE_SYNTAX_ERROR),
114 errmsg("conflicting or redundant options")));
117 else if (strcmp(defel->defname, "template") == 0)
121 (errcode(ERRCODE_SYNTAX_ERROR),
122 errmsg("conflicting or redundant options")));
125 else if (strcmp(defel->defname, "encoding") == 0)
129 (errcode(ERRCODE_SYNTAX_ERROR),
130 errmsg("conflicting or redundant options")));
133 else if (strcmp(defel->defname, "location") == 0)
136 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
137 errmsg("LOCATION is not supported anymore"),
138 errhint("Consider using tablespaces instead.")));
141 elog(ERROR, "option \"%s\" not recognized",
145 if (downer && downer->arg)
146 dbowner = strVal(downer->arg);
147 if (dtemplate && dtemplate->arg)
148 dbtemplate = strVal(dtemplate->arg);
149 if (dencoding && dencoding->arg)
151 const char *encoding_name;
153 if (IsA(dencoding->arg, Integer))
155 encoding = intVal(dencoding->arg);
156 encoding_name = pg_encoding_to_char(encoding);
157 if (strcmp(encoding_name, "") == 0 ||
158 pg_valid_server_encoding(encoding_name) < 0)
160 (errcode(ERRCODE_UNDEFINED_OBJECT),
161 errmsg("%d is not a valid encoding code",
164 else if (IsA(dencoding->arg, String))
166 encoding_name = strVal(dencoding->arg);
167 if (pg_valid_server_encoding(encoding_name) < 0)
169 (errcode(ERRCODE_UNDEFINED_OBJECT),
170 errmsg("%s is not a valid encoding name",
172 encoding = pg_char_to_encoding(encoding_name);
175 elog(ERROR, "unrecognized node type: %d",
176 nodeTag(dencoding->arg));
179 /* obtain sysid of proposed owner */
181 datdba = get_usesysid(dbowner); /* will ereport if no such user */
183 datdba = GetUserId();
185 if (datdba == GetUserId())
187 /* creating database for self: can be superuser or createdb */
188 if (!superuser() && !have_createdb_privilege())
190 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
191 errmsg("permission denied to create database")));
195 /* creating database for someone else: must be superuser */
196 /* note that the someone else need not have any permissions */
199 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
200 errmsg("must be superuser to create database for another user")));
204 * Check for db name conflict. There is a race condition here, since
205 * another backend could create the same DB name before we commit.
206 * However, holding an exclusive lock on pg_database for the whole
207 * time we are copying the source database doesn't seem like a good
208 * idea, so accept possibility of race to create. We will check again
209 * after we grab the exclusive lock.
211 if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
213 (errcode(ERRCODE_DUPLICATE_DATABASE),
214 errmsg("database \"%s\" already exists", dbname)));
217 * Lookup database (template) to be cloned.
220 dbtemplate = "template1"; /* Default template database name */
222 if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
223 &src_istemplate, &src_lastsysoid,
224 &src_vacuumxid, &src_frozenxid, &src_deftablespace))
226 (errcode(ERRCODE_UNDEFINED_DATABASE),
227 errmsg("template database \"%s\" does not exist", dbtemplate)));
230 * Permission check: to copy a DB that's not marked datistemplate, you
231 * must be superuser or the owner thereof.
235 if (!superuser() && GetUserId() != src_owner)
237 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
238 errmsg("permission denied to copy database \"%s\"",
243 * The source DB can't have any active backends, except this one
244 * (exception is to allow CREATE DB while connected to template1).
245 * Otherwise we might copy inconsistent data. This check is not
246 * bulletproof, since someone might connect while we are copying...
248 if (DatabaseHasActiveBackends(src_dboid, true))
250 (errcode(ERRCODE_OBJECT_IN_USE),
251 errmsg("source database \"%s\" is being accessed by other users",
254 /* If encoding is defaulted, use source's encoding */
256 encoding = src_encoding;
258 /* Some encodings are client only */
259 if (!PG_VALID_BE_ENCODING(encoding))
261 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
262 errmsg("invalid server encoding %d", encoding)));
264 /* Resolve default tablespace for new database */
265 if (dtablespacename && dtablespacename->arg)
267 char *tablespacename;
270 tablespacename = strVal(dtablespacename->arg);
271 dst_deftablespace = get_tablespace_oid(tablespacename);
272 if (!OidIsValid(dst_deftablespace))
274 (errcode(ERRCODE_UNDEFINED_OBJECT),
275 errmsg("tablespace \"%s\" does not exist",
277 /* check permissions */
278 aclresult = pg_tablespace_aclcheck(dst_deftablespace, GetUserId(),
280 if (aclresult != ACLCHECK_OK)
281 aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
286 /* Use template database's default tablespace */
287 dst_deftablespace = src_deftablespace;
288 /* Note there is no additional permission check in this path */
292 * Preassign OID for pg_database tuple, so that we can compute db
298 * Force dirty buffers out to disk, to ensure source database is
299 * up-to-date for the copy. (We really only need to flush buffers for
300 * the source database...)
305 * Close virtual file descriptors so the kernel has more available for
306 * the system() calls below.
311 * Iterate through all tablespaces of the template database, and
312 * copy each one to the new database.
314 * If we are trying to change the default tablespace of the template,
315 * we require that the template not have any files in the new default
316 * tablespace. This avoids the need to merge two subdirectories.
317 * This could probably be improved later.
319 rel = heap_openr(TableSpaceRelationName, AccessShareLock);
320 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
321 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
323 Oid srctablespace = HeapTupleGetOid(tuple);
329 /* No need to copy global tablespace */
330 if (srctablespace == GLOBALTABLESPACE_OID)
333 srcpath = GetDatabasePath(src_dboid, srctablespace);
335 if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode))
337 /* Assume we can ignore it */
342 if (srctablespace == src_deftablespace)
343 dsttablespace = dst_deftablespace;
345 dsttablespace = srctablespace;
347 dstpath = GetDatabasePath(dboid, dsttablespace);
349 if (stat(dstpath, &st) == 0 || errno != ENOENT)
351 remove_dbtablespaces(dboid);
353 (errmsg("could not initialize database directory"),
354 errdetail("Directory \"%s\" already exists.", dstpath)));
359 * Copy this subdirectory to the new location
361 * XXX use of cp really makes this code pretty grotty, particularly
362 * with respect to lack of ability to report errors well. Someday
363 * rewrite to do it for ourselves.
366 /* We might need to use cp -R one day for portability */
367 snprintf(buf, sizeof(buf), "cp -r '%s' '%s'",
369 if (system(buf) != 0)
371 remove_dbtablespaces(dboid);
373 (errmsg("could not initialize database directory"),
374 errdetail("Failing system command was: %s", buf),
375 errhint("Look in the postmaster's stderr log for more information.")));
378 if (copydir(srcpath, dstpath) != 0)
380 /* copydir should already have given details of its troubles */
381 remove_dbtablespaces(dboid);
383 (errmsg("could not initialize database directory")));
388 heap_close(rel, AccessShareLock);
391 * Now OK to grab exclusive lock on pg_database.
393 pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
395 /* Check to see if someone else created same DB name meanwhile. */
396 if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
398 /* Don't hold lock while doing recursive remove */
399 heap_close(pg_database_rel, AccessExclusiveLock);
400 remove_dbtablespaces(dboid);
402 (errcode(ERRCODE_DUPLICATE_DATABASE),
403 errmsg("database \"%s\" already exists", dbname)));
407 * Insert a new tuple into pg_database
409 pg_database_dsc = RelationGetDescr(pg_database_rel);
412 MemSet(new_record, 0, sizeof(new_record));
413 MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
415 new_record[Anum_pg_database_datname - 1] =
416 DirectFunctionCall1(namein, CStringGetDatum(dbname));
417 new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba);
418 new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
419 new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
420 new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
421 new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
422 new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
423 new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
424 new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
427 * We deliberately set datconfig and datacl to defaults (NULL), rather
428 * than copying them from the template database. Copying datacl would
429 * be a bad idea when the owner is not the same as the template's
430 * owner. It's more debatable whether datconfig should be copied.
432 new_record_nulls[Anum_pg_database_datconfig - 1] = 'n';
433 new_record_nulls[Anum_pg_database_datacl - 1] = 'n';
435 tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
437 HeapTupleSetOid(tuple, dboid); /* override heap_insert's OID
440 simple_heap_insert(pg_database_rel, tuple);
443 CatalogUpdateIndexes(pg_database_rel, tuple);
445 /* Close pg_database, but keep lock till commit */
446 heap_close(pg_database_rel, NoLock);
449 * Force dirty buffers out to disk, so that newly-connecting backends
450 * will see the new database in pg_database right away. (They'll see
451 * an uncommitted tuple, but they don't care; see GetRawDatabaseInfo.)
461 dropdb(const char *dbname)
467 SysScanDesc pgdbscan;
471 PreventTransactionChain((void *) dbname, "DROP DATABASE");
475 if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)
477 (errcode(ERRCODE_OBJECT_IN_USE),
478 errmsg("cannot drop the currently open database")));
481 * Obtain exclusive lock on pg_database. We need this to ensure that
482 * no new backend starts up in the target database while we are
483 * deleting it. (Actually, a new backend might still manage to start
484 * up, because it will read pg_database without any locking to
485 * discover the database's OID. But it will detect its error in
486 * ReverifyMyDatabase and shut down before any serious damage is done.
489 pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
491 if (!get_db_info(dbname, &db_id, &db_owner, NULL,
492 &db_istemplate, NULL, NULL, NULL, NULL))
494 (errcode(ERRCODE_UNDEFINED_DATABASE),
495 errmsg("database \"%s\" does not exist", dbname)));
497 if (GetUserId() != db_owner && !superuser())
498 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
502 * Disallow dropping a DB that is marked istemplate. This is just to
503 * prevent people from accidentally dropping template0 or template1;
504 * they can do so if they're really determined ...
508 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
509 errmsg("cannot drop a template database")));
512 * Check for active backends in the target database.
514 if (DatabaseHasActiveBackends(db_id, false))
516 (errcode(ERRCODE_OBJECT_IN_USE),
517 errmsg("database \"%s\" is being accessed by other users",
521 * Find the database's tuple by OID (should be unique).
524 ObjectIdAttributeNumber,
525 BTEqualStrategyNumber, F_OIDEQ,
526 ObjectIdGetDatum(db_id));
528 pgdbscan = systable_beginscan(pgdbrel, DatabaseOidIndex, true,
529 SnapshotNow, 1, &key);
531 tup = systable_getnext(pgdbscan);
532 if (!HeapTupleIsValid(tup))
535 * This error should never come up since the existence of the
536 * database is checked earlier
538 elog(ERROR, "database \"%s\" doesn't exist despite earlier reports to the contrary",
542 /* Remove the database's tuple from pg_database */
543 simple_heap_delete(pgdbrel, &tup->t_self);
545 systable_endscan(pgdbscan);
548 * Delete any comments associated with the database
550 * NOTE: this is probably dead code since any such comments should have
551 * been in that database, not mine.
553 DeleteComments(db_id, RelationGetRelid(pgdbrel), 0);
556 * Close pg_database, but keep exclusive lock till commit to ensure
557 * that any new backend scanning pg_database will see the tuple dead.
559 heap_close(pgdbrel, NoLock);
562 * Drop pages for this database that are in the shared buffer cache.
563 * This is important to ensure that no remaining backend tries to
564 * write out a dirty buffer to the dead database later...
569 * Also, clean out any entries in the shared free space map.
571 FreeSpaceMapForgetDatabase(db_id);
574 * Remove all tablespace subdirs belonging to the database.
576 remove_dbtablespaces(db_id);
579 * Force dirty buffers out to disk, so that newly-connecting backends
580 * will see the database tuple marked dead in pg_database right away.
581 * (They'll see an uncommitted deletion, but they don't care; see
582 * GetRawDatabaseInfo.)
592 RenameDatabase(const char *oldname, const char *newname)
603 * Obtain AccessExclusiveLock so that no new session gets started
604 * while the rename is in progress.
606 rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
609 Anum_pg_database_datname,
610 BTEqualStrategyNumber, F_NAMEEQ,
611 NameGetDatum(oldname));
612 scan = systable_beginscan(rel, DatabaseNameIndex, true,
613 SnapshotNow, 1, &key);
615 tup = systable_getnext(scan);
616 if (!HeapTupleIsValid(tup))
618 (errcode(ERRCODE_UNDEFINED_DATABASE),
619 errmsg("database \"%s\" does not exist", oldname)));
622 * XXX Client applications probably store the current database
623 * somewhere, so renaming it could cause confusion. On the other
624 * hand, there may not be an actual problem besides a little
625 * confusion, so think about this and decide.
627 if (HeapTupleGetOid(tup) == MyDatabaseId)
629 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
630 errmsg("current database may not be renamed")));
633 * Make sure the database does not have active sessions. Might not be
634 * necessary, but it's consistent with other database operations.
636 if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false))
638 (errcode(ERRCODE_OBJECT_IN_USE),
639 errmsg("database \"%s\" is being accessed by other users",
642 /* make sure the new name doesn't exist */
644 Anum_pg_database_datname,
645 BTEqualStrategyNumber, F_NAMEEQ,
646 NameGetDatum(newname));
647 scan2 = systable_beginscan(rel, DatabaseNameIndex, true,
648 SnapshotNow, 1, &key2);
649 if (HeapTupleIsValid(systable_getnext(scan2)))
651 (errcode(ERRCODE_DUPLICATE_DATABASE),
652 errmsg("database \"%s\" already exists", newname)));
653 systable_endscan(scan2);
656 if (!pg_database_ownercheck(HeapTupleGetOid(tup), GetUserId()))
657 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
660 /* must have createdb */
661 if (!have_createdb_privilege())
663 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
664 errmsg("permission denied to rename database")));
667 newtup = heap_copytuple(tup);
668 namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname);
669 simple_heap_update(rel, &newtup->t_self, newtup);
670 CatalogUpdateIndexes(rel, newtup);
672 systable_endscan(scan);
673 heap_close(rel, NoLock);
676 * Force dirty buffers out to disk, so that newly-connecting backends
677 * will see the renamed database in pg_database right away. (They'll
678 * see an uncommitted tuple, but they don't care; see
679 * GetRawDatabaseInfo.)
686 * ALTER DATABASE name SET ...
689 AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
697 Datum repl_val[Natts_pg_database];
698 char repl_null[Natts_pg_database];
699 char repl_repl[Natts_pg_database];
701 valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
703 rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
704 ScanKeyInit(&scankey,
705 Anum_pg_database_datname,
706 BTEqualStrategyNumber, F_NAMEEQ,
707 NameGetDatum(stmt->dbname));
708 scan = systable_beginscan(rel, DatabaseNameIndex, true,
709 SnapshotNow, 1, &scankey);
710 tuple = systable_getnext(scan);
711 if (!HeapTupleIsValid(tuple))
713 (errcode(ERRCODE_UNDEFINED_DATABASE),
714 errmsg("database \"%s\" does not exist", stmt->dbname)));
717 || ((Form_pg_database) GETSTRUCT(tuple))->datdba == GetUserId()))
718 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
721 MemSet(repl_repl, ' ', sizeof(repl_repl));
722 repl_repl[Anum_pg_database_datconfig - 1] = 'r';
724 if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL)
727 repl_null[Anum_pg_database_datconfig - 1] = 'n';
728 repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0;
736 repl_null[Anum_pg_database_datconfig - 1] = ' ';
738 datum = heap_getattr(tuple, Anum_pg_database_datconfig,
739 RelationGetDescr(rel), &isnull);
741 a = isnull ? NULL : DatumGetArrayTypeP(datum);
744 a = GUCArrayAdd(a, stmt->variable, valuestr);
746 a = GUCArrayDelete(a, stmt->variable);
749 repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a);
751 repl_null[Anum_pg_database_datconfig - 1] = 'n';
754 newtuple = heap_modifytuple(tuple, rel, repl_val, repl_null, repl_repl);
755 simple_heap_update(rel, &tuple->t_self, newtuple);
758 CatalogUpdateIndexes(rel, newtuple);
760 systable_endscan(scan);
761 heap_close(rel, NoLock);
766 * ALTER DATABASE name OWNER TO newowner
769 AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
775 Form_pg_database datForm;
777 rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
778 ScanKeyInit(&scankey,
779 Anum_pg_database_datname,
780 BTEqualStrategyNumber, F_NAMEEQ,
781 NameGetDatum(dbname));
782 scan = systable_beginscan(rel, DatabaseNameIndex, true,
783 SnapshotNow, 1, &scankey);
784 tuple = systable_getnext(scan);
785 if (!HeapTupleIsValid(tuple))
787 (errcode(ERRCODE_UNDEFINED_DATABASE),
788 errmsg("database \"%s\" does not exist", dbname)));
790 datForm = (Form_pg_database) GETSTRUCT(tuple);
793 * If the new owner is the same as the existing owner, consider the
794 * command to have succeeded. This is to be consistent with other objects.
796 if (datForm->datdba != newOwnerSysId)
798 Datum repl_val[Natts_pg_database];
799 char repl_null[Natts_pg_database];
800 char repl_repl[Natts_pg_database];
806 /* changing owner's database for someone else: must be superuser */
807 /* note that the someone else need not have any permissions */
810 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
811 errmsg("must be superuser to change owner")));
813 memset(repl_null, ' ', sizeof(repl_null));
814 memset(repl_repl, ' ', sizeof(repl_repl));
816 repl_repl[Anum_pg_database_datdba - 1] = 'r';
817 repl_val[Anum_pg_database_datdba - 1] = Int32GetDatum(newOwnerSysId);
820 * Determine the modified ACL for the new owner. This is only
821 * necessary when the ACL is non-null.
823 aclDatum = heap_getattr(tuple,
824 Anum_pg_database_datacl,
825 RelationGetDescr(rel),
829 newAcl = aclnewowner(DatumGetAclP(aclDatum),
830 datForm->datdba, newOwnerSysId);
831 repl_repl[Anum_pg_database_datacl - 1] = 'r';
832 repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl);
835 newtuple = heap_modifytuple(tuple, rel, repl_val, repl_null, repl_repl);
836 simple_heap_update(rel, &newtuple->t_self, newtuple);
837 CatalogUpdateIndexes(rel, newtuple);
839 heap_freetuple(newtuple);
842 systable_endscan(scan);
843 heap_close(rel, NoLock);
852 get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
853 int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
854 TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
865 /* Caller may wish to grab a better lock on pg_database beforehand... */
866 relation = heap_openr(DatabaseRelationName, AccessShareLock);
868 ScanKeyInit(&scanKey,
869 Anum_pg_database_datname,
870 BTEqualStrategyNumber, F_NAMEEQ,
873 scan = systable_beginscan(relation, DatabaseNameIndex, true,
874 SnapshotNow, 1, &scanKey);
876 tuple = systable_getnext(scan);
878 gottuple = HeapTupleIsValid(tuple);
881 Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
883 /* oid of the database */
885 *dbIdP = HeapTupleGetOid(tuple);
886 /* sysid of the owner */
888 *ownerIdP = dbform->datdba;
889 /* character encoding */
891 *encodingP = dbform->encoding;
892 /* allowed as template? */
894 *dbIsTemplateP = dbform->datistemplate;
895 /* last system OID used in database */
897 *dbLastSysOidP = dbform->datlastsysoid;
898 /* limit of vacuumed XIDs */
900 *dbVacuumXidP = dbform->datvacuumxid;
901 /* limit of frozen XIDs */
903 *dbFrozenXidP = dbform->datfrozenxid;
904 /* default tablespace for this database */
906 *dbTablespace = dbform->dattablespace;
909 systable_endscan(scan);
910 heap_close(relation, AccessShareLock);
916 have_createdb_privilege(void)
921 utup = SearchSysCache(SHADOWSYSID,
922 Int32GetDatum(GetUserId()),
925 if (!HeapTupleIsValid(utup))
928 retval = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
930 ReleaseSysCache(utup);
936 * Remove tablespace directories
938 * We don't know what tablespaces db_id is using, so iterate through all
939 * tablespaces removing <tablespace>/db_id
942 remove_dbtablespaces(Oid db_id)
948 rel = heap_openr(TableSpaceRelationName, AccessShareLock);
949 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
950 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
952 Oid dsttablespace = HeapTupleGetOid(tuple);
956 /* Don't mess with the global tablespace */
957 if (dsttablespace == GLOBALTABLESPACE_OID)
960 dstpath = GetDatabasePath(db_id, dsttablespace);
962 if (stat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode))
964 /* Assume we can ignore it */
969 if (!rmtree(dstpath, true))
972 (errmsg("could not remove database directory \"%s\"",
974 errhint("Look in the postmaster's stderr log for more information.")));
981 heap_close(rel, AccessShareLock);
986 * get_database_oid - given a database name, look up the OID
988 * Returns InvalidOid if database name not found.
990 * This is not actually used in this file, but is exported for use elsewhere.
993 get_database_oid(const char *dbname)
995 Relation pg_database;
996 ScanKeyData entry[1];
1001 /* There's no syscache for pg_database, so must look the hard way */
1002 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1003 ScanKeyInit(&entry[0],
1004 Anum_pg_database_datname,
1005 BTEqualStrategyNumber, F_NAMEEQ,
1006 CStringGetDatum(dbname));
1007 scan = systable_beginscan(pg_database, DatabaseNameIndex, true,
1008 SnapshotNow, 1, entry);
1010 dbtuple = systable_getnext(scan);
1012 /* We assume that there can be at most one matching tuple */
1013 if (HeapTupleIsValid(dbtuple))
1014 oid = HeapTupleGetOid(dbtuple);
1018 systable_endscan(scan);
1019 heap_close(pg_database, AccessShareLock);
1026 * get_database_name - given a database OID, look up the name
1028 * Returns a palloc'd string, or NULL if no such database.
1030 * This is not actually used in this file, but is exported for use elsewhere.
1033 get_database_name(Oid dbid)
1035 Relation pg_database;
1036 ScanKeyData entry[1];
1041 /* There's no syscache for pg_database, so must look the hard way */
1042 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1043 ScanKeyInit(&entry[0],
1044 ObjectIdAttributeNumber,
1045 BTEqualStrategyNumber, F_OIDEQ,
1046 ObjectIdGetDatum(dbid));
1047 scan = systable_beginscan(pg_database, DatabaseOidIndex, true,
1048 SnapshotNow, 1, entry);
1050 dbtuple = systable_getnext(scan);
1052 /* We assume that there can be at most one matching tuple */
1053 if (HeapTupleIsValid(dbtuple))
1054 result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname));
1058 systable_endscan(scan);
1059 heap_close(pg_database, AccessShareLock);