1 /*-------------------------------------------------------------------------
4 * Database management commands (create/drop database).
7 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.120 2003/08/04 00:43:16 momjian Exp $
14 *-------------------------------------------------------------------------
23 #include "access/genam.h"
24 #include "access/heapam.h"
25 #include "catalog/catname.h"
26 #include "catalog/catalog.h"
27 #include "catalog/pg_database.h"
28 #include "catalog/pg_shadow.h"
29 #include "catalog/indexing.h"
30 #include "commands/comment.h"
31 #include "commands/dbcommands.h"
32 #include "miscadmin.h"
33 #include "storage/freespace.h"
34 #include "storage/sinval.h"
35 #include "utils/acl.h"
36 #include "utils/array.h"
37 #include "utils/builtins.h"
38 #include "utils/fmgroids.h"
39 #include "utils/guc.h"
40 #include "utils/lsyscache.h"
41 #include "utils/syscache.h"
43 #include "mb/pg_wchar.h" /* encoding check */
46 /* non-export function prototypes */
47 static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
48 int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
49 TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
51 static bool have_createdb_privilege(void);
52 static char *resolve_alt_dbpath(const char *dbpath, Oid dboid);
53 static bool remove_dbdirs(const char *real_loc, const char *altloc);
60 createdb(const CreatedbStmt *stmt)
65 char src_loc[MAXPGPATH];
66 char buf[2 * MAXPGPATH + 100];
72 TransactionId src_vacuumxid;
73 TransactionId src_frozenxid;
74 char src_dbpath[MAXPGPATH];
75 Relation pg_database_rel;
77 TupleDesc pg_database_dsc;
78 Datum new_record[Natts_pg_database];
79 char new_record_nulls[Natts_pg_database];
83 DefElem *downer = NULL;
84 DefElem *dpath = NULL;
85 DefElem *dtemplate = NULL;
86 DefElem *dencoding = NULL;
87 char *dbname = stmt->dbname;
90 char *dbtemplate = NULL;
93 /* Extract options from the statement node tree */
94 foreach(option, stmt->options)
96 DefElem *defel = (DefElem *) lfirst(option);
98 if (strcmp(defel->defname, "owner") == 0)
102 (errcode(ERRCODE_SYNTAX_ERROR),
103 errmsg("conflicting or redundant options")));
106 else if (strcmp(defel->defname, "location") == 0)
110 (errcode(ERRCODE_SYNTAX_ERROR),
111 errmsg("conflicting or redundant options")));
114 else if (strcmp(defel->defname, "template") == 0)
118 (errcode(ERRCODE_SYNTAX_ERROR),
119 errmsg("conflicting or redundant options")));
122 else if (strcmp(defel->defname, "encoding") == 0)
126 (errcode(ERRCODE_SYNTAX_ERROR),
127 errmsg("conflicting or redundant options")));
131 elog(ERROR, "option \"%s\" not recognized",
135 if (downer && downer->arg)
136 dbowner = strVal(downer->arg);
137 if (dpath && dpath->arg)
138 dbpath = strVal(dpath->arg);
139 if (dtemplate && dtemplate->arg)
140 dbtemplate = strVal(dtemplate->arg);
141 if (dencoding && dencoding->arg)
143 const char *encoding_name;
145 if (IsA(dencoding->arg, Integer))
147 encoding = intVal(dencoding->arg);
148 encoding_name = pg_encoding_to_char(encoding);
149 if (strcmp(encoding_name, "") == 0 ||
150 pg_valid_server_encoding(encoding_name) < 0)
152 (errcode(ERRCODE_UNDEFINED_OBJECT),
153 errmsg("%d is not a valid encoding code",
156 else if (IsA(dencoding->arg, String))
158 encoding_name = strVal(dencoding->arg);
159 if (pg_valid_server_encoding(encoding_name) < 0)
161 (errcode(ERRCODE_UNDEFINED_OBJECT),
162 errmsg("%s is not a valid encoding name",
164 encoding = pg_char_to_encoding(encoding_name);
167 elog(ERROR, "unrecognized node type: %d",
168 nodeTag(dencoding->arg));
171 /* obtain sysid of proposed owner */
173 datdba = get_usesysid(dbowner); /* will ereport if no such user */
175 datdba = GetUserId();
177 if (datdba == GetUserId())
179 /* creating database for self: can be superuser or createdb */
180 if (!superuser() && !have_createdb_privilege())
182 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
183 errmsg("permission denied to create database")));
187 /* creating database for someone else: must be superuser */
188 /* note that the someone else need not have any permissions */
191 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
192 errmsg("must be superuser to create database for another user")));
195 /* don't call this in a transaction block */
196 PreventTransactionChain((void *) stmt, "CREATE DATABASE");
198 /* alternate location requires symlinks */
202 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
203 errmsg("cannot use an alternate location on this platform")));
207 * Check for db name conflict. There is a race condition here, since
208 * another backend could create the same DB name before we commit.
209 * However, holding an exclusive lock on pg_database for the whole
210 * time we are copying the source database doesn't seem like a good
211 * idea, so accept possibility of race to create. We will check again
212 * after we grab the exclusive lock.
214 if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
216 (errcode(ERRCODE_DUPLICATE_DATABASE),
217 errmsg("database \"%s\" already exists", dbname)));
220 * Lookup database (template) to be cloned.
223 dbtemplate = "template1"; /* Default template database name */
225 if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
226 &src_istemplate, &src_lastsysoid,
227 &src_vacuumxid, &src_frozenxid,
230 (errcode(ERRCODE_UNDEFINED_DATABASE),
231 errmsg("template \"%s\" does not exist", dbtemplate)));
234 * Permission check: to copy a DB that's not marked datistemplate, you
235 * must be superuser or the owner thereof.
239 if (!superuser() && GetUserId() != src_owner)
241 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
242 errmsg("permission denied to copy database \"%s\"",
247 * Determine physical path of source database
249 alt_loc = resolve_alt_dbpath(src_dbpath, src_dboid);
251 alt_loc = GetDatabasePath(src_dboid);
252 strcpy(src_loc, alt_loc);
255 * The source DB can't have any active backends, except this one
256 * (exception is to allow CREATE DB while connected to template1).
257 * Otherwise we might copy inconsistent data. This check is not
258 * bulletproof, since someone might connect while we are copying...
260 if (DatabaseHasActiveBackends(src_dboid, true))
262 (errcode(ERRCODE_OBJECT_IN_USE),
263 errmsg("source database \"%s\" is being accessed by other users",
266 /* If encoding is defaulted, use source's encoding */
268 encoding = src_encoding;
270 /* Some encodings are client only */
271 if (!PG_VALID_BE_ENCODING(encoding))
273 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
274 errmsg("invalid backend encoding %d", encoding)));
277 * Preassign OID for pg_database tuple, so that we can compute db
283 * Compute nominal location (where we will try to access the
284 * database), and resolve alternate physical location if one is
287 * If an alternate location is specified but is the same as the normal
288 * path, just drop the alternate-location spec (this seems friendlier
289 * than erroring out). We must test this case to avoid creating a
290 * circular symlink below.
292 nominal_loc = GetDatabasePath(dboid);
293 alt_loc = resolve_alt_dbpath(dbpath, dboid);
295 if (alt_loc && strcmp(alt_loc, nominal_loc) == 0)
301 if (strchr(nominal_loc, '\''))
303 (errcode(ERRCODE_INVALID_NAME),
304 errmsg("database path may not contain single quotes")));
305 if (alt_loc && strchr(alt_loc, '\''))
307 (errcode(ERRCODE_INVALID_NAME),
308 errmsg("database path may not contain single quotes")));
309 if (strchr(src_loc, '\''))
311 (errcode(ERRCODE_INVALID_NAME),
312 errmsg("database path may not contain single quotes")));
313 /* ... otherwise we'd be open to shell exploits below */
316 * Force dirty buffers out to disk, to ensure source database is
317 * up-to-date for the copy. (We really only need to flush buffers for
318 * the source database...)
323 * Close virtual file descriptors so the kernel has more available for
324 * the mkdir() and system() calls below.
329 * Check we can create the target directory --- but then remove it
330 * because we rely on cp(1) to create it for real.
332 target_dir = alt_loc ? alt_loc : nominal_loc;
334 if (mkdir(target_dir, S_IRWXU) != 0)
336 (errcode_for_file_access(),
337 errmsg("could not create database directory \"%s\": %m",
339 if (rmdir(target_dir) != 0)
341 (errcode_for_file_access(),
342 errmsg("could not remove temp directory \"%s\": %m",
345 /* Make the symlink, if needed */
348 #ifdef HAVE_SYMLINK /* already throws error above */
349 if (symlink(alt_loc, nominal_loc) != 0)
352 (errcode_for_file_access(),
353 errmsg("could not link \"%s\" to \"%s\": %m",
354 nominal_loc, alt_loc)));
357 /* Copy the template database to the new location */
359 snprintf(buf, sizeof(buf), "cp -r '%s' '%s'", src_loc, target_dir);
360 if (system(buf) != 0)
362 if (copydir(src_loc, target_dir) != 0)
365 if (remove_dbdirs(nominal_loc, alt_loc))
366 elog(ERROR, "could not initialize database directory");
368 elog(ERROR, "could not initialize database directory; delete failed as well");
372 * Now OK to grab exclusive lock on pg_database.
374 pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
376 /* Check to see if someone else created same DB name meanwhile. */
377 if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
379 /* Don't hold lock while doing recursive remove */
380 heap_close(pg_database_rel, AccessExclusiveLock);
381 remove_dbdirs(nominal_loc, alt_loc);
383 (errcode(ERRCODE_DUPLICATE_DATABASE),
384 errmsg("database \"%s\" already exists", dbname)));
388 * Insert a new tuple into pg_database
390 pg_database_dsc = RelationGetDescr(pg_database_rel);
393 MemSet(new_record, 0, sizeof(new_record));
394 MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
396 new_record[Anum_pg_database_datname - 1] =
397 DirectFunctionCall1(namein, CStringGetDatum(dbname));
398 new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba);
399 new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
400 new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
401 new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
402 new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
403 new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
404 new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
405 /* do not set datpath to null, GetRawDatabaseInfo won't cope */
406 new_record[Anum_pg_database_datpath - 1] =
407 DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
410 * We deliberately set datconfig and datacl to defaults (NULL), rather
411 * than copying them from the template database. Copying datacl would
412 * be a bad idea when the owner is not the same as the template's
413 * owner. It's more debatable whether datconfig should be copied.
415 new_record_nulls[Anum_pg_database_datconfig - 1] = 'n';
416 new_record_nulls[Anum_pg_database_datacl - 1] = 'n';
418 tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
420 HeapTupleSetOid(tuple, dboid); /* override heap_insert's OID
423 simple_heap_insert(pg_database_rel, tuple);
426 CatalogUpdateIndexes(pg_database_rel, tuple);
428 /* Close pg_database, but keep lock till commit */
429 heap_close(pg_database_rel, NoLock);
432 * Force dirty buffers out to disk, so that newly-connecting backends
433 * will see the new database in pg_database right away. (They'll see
434 * an uncommitted tuple, but they don't care; see GetRawDatabaseInfo.)
444 dropdb(const char *dbname)
451 char dbpath[MAXPGPATH];
453 SysScanDesc pgdbscan;
459 if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)
461 (errcode(ERRCODE_OBJECT_IN_USE),
462 errmsg("cannot drop the currently open database")));
464 PreventTransactionChain((void *) dbname, "DROP DATABASE");
467 * Obtain exclusive lock on pg_database. We need this to ensure that
468 * no new backend starts up in the target database while we are
469 * deleting it. (Actually, a new backend might still manage to start
470 * up, because it will read pg_database without any locking to
471 * discover the database's OID. But it will detect its error in
472 * ReverifyMyDatabase and shut down before any serious damage is done.
475 pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
477 if (!get_db_info(dbname, &db_id, &db_owner, NULL,
478 &db_istemplate, NULL, NULL, NULL, dbpath))
480 (errcode(ERRCODE_UNDEFINED_DATABASE),
481 errmsg("database \"%s\" does not exist", dbname)));
483 if (GetUserId() != db_owner && !superuser())
484 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
488 * Disallow dropping a DB that is marked istemplate. This is just to
489 * prevent people from accidentally dropping template0 or template1;
490 * they can do so if they're really determined ...
494 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
495 errmsg("cannot drop a template database")));
497 nominal_loc = GetDatabasePath(db_id);
498 alt_loc = resolve_alt_dbpath(dbpath, db_id);
501 * Check for active backends in the target database.
503 if (DatabaseHasActiveBackends(db_id, false))
505 (errcode(ERRCODE_OBJECT_IN_USE),
506 errmsg("database \"%s\" is being accessed by other users",
510 * Find the database's tuple by OID (should be unique).
512 ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
513 F_OIDEQ, ObjectIdGetDatum(db_id));
515 pgdbscan = systable_beginscan(pgdbrel, DatabaseOidIndex, true, SnapshotNow, 1, &key);
517 tup = systable_getnext(pgdbscan);
518 if (!HeapTupleIsValid(tup))
521 * This error should never come up since the existence of the
522 * database is checked earlier
524 elog(ERROR, "database \"%s\" doesn't exist despite earlier reports to the contrary",
528 /* Remove the database's tuple from pg_database */
529 simple_heap_delete(pgdbrel, &tup->t_self);
531 systable_endscan(pgdbscan);
534 * Delete any comments associated with the database
536 * NOTE: this is probably dead code since any such comments should have
537 * been in that database, not mine.
539 DeleteComments(db_id, RelationGetRelid(pgdbrel), 0);
542 * Close pg_database, but keep exclusive lock till commit to ensure
543 * that any new backend scanning pg_database will see the tuple dead.
545 heap_close(pgdbrel, NoLock);
548 * Drop pages for this database that are in the shared buffer cache.
549 * This is important to ensure that no remaining backend tries to
550 * write out a dirty buffer to the dead database later...
555 * Also, clean out any entries in the shared free space map.
557 FreeSpaceMapForgetDatabase(db_id);
560 * Remove the database's subdirectory and everything in it.
562 remove_dbdirs(nominal_loc, alt_loc);
565 * Force dirty buffers out to disk, so that newly-connecting backends
566 * will see the database tuple marked dead in pg_database right away.
567 * (They'll see an uncommitted deletion, but they don't care; see
568 * GetRawDatabaseInfo.)
578 RenameDatabase(const char *oldname, const char *newname)
589 * Obtain AccessExclusiveLock so that no new session gets started
590 * while the rename is in progress.
592 rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
594 ScanKeyEntryInitialize(&key, 0, Anum_pg_database_datname,
595 F_NAMEEQ, NameGetDatum(oldname));
596 scan = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &key);
598 tup = systable_getnext(scan);
599 if (!HeapTupleIsValid(tup))
601 (errcode(ERRCODE_UNDEFINED_DATABASE),
602 errmsg("database \"%s\" does not exist", oldname)));
605 * XXX Client applications probably store the current database
606 * somewhere, so renaming it could cause confusion. On the other
607 * hand, there may not be an actual problem besides a little
608 * confusion, so think about this and decide.
610 if (HeapTupleGetOid(tup) == MyDatabaseId)
612 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
613 errmsg("current database may not be renamed")));
616 * Make sure the database does not have active sessions. Might not be
617 * necessary, but it's consistent with other database operations.
619 if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false))
621 (errcode(ERRCODE_OBJECT_IN_USE),
622 errmsg("database \"%s\" is being accessed by other users",
625 /* make sure the new name doesn't exist */
626 ScanKeyEntryInitialize(&key2, 0, Anum_pg_database_datname,
627 F_NAMEEQ, NameGetDatum(newname));
628 scan2 = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &key2);
629 if (HeapTupleIsValid(systable_getnext(scan2)))
631 (errcode(ERRCODE_DUPLICATE_DATABASE),
632 errmsg("database \"%s\" already exists", newname)));
633 systable_endscan(scan2);
636 if (!pg_database_ownercheck(HeapTupleGetOid(tup), GetUserId()))
637 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
640 /* must have createdb */
641 if (!have_createdb_privilege())
643 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
644 errmsg("permission denied to rename database")));
647 newtup = heap_copytuple(tup);
648 namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname);
649 simple_heap_update(rel, &tup->t_self, newtup);
650 CatalogUpdateIndexes(rel, newtup);
652 systable_endscan(scan);
653 heap_close(rel, NoLock);
656 * Force dirty buffers out to disk, so that newly-connecting backends
657 * will see the renamed database in pg_database right away. (They'll
658 * see an uncommitted tuple, but they don't care; see
659 * GetRawDatabaseInfo.)
666 * ALTER DATABASE name SET ...
669 AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
677 Datum repl_val[Natts_pg_database];
678 char repl_null[Natts_pg_database];
679 char repl_repl[Natts_pg_database];
681 valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
683 rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
684 ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname,
685 F_NAMEEQ, NameGetDatum(stmt->dbname));
686 scan = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &scankey);
687 tuple = systable_getnext(scan);
688 if (!HeapTupleIsValid(tuple))
690 (errcode(ERRCODE_UNDEFINED_DATABASE),
691 errmsg("database \"%s\" does not exist", stmt->dbname)));
694 || ((Form_pg_database) GETSTRUCT(tuple))->datdba == GetUserId()))
695 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
698 MemSet(repl_repl, ' ', sizeof(repl_repl));
699 repl_repl[Anum_pg_database_datconfig - 1] = 'r';
701 if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL)
704 repl_null[Anum_pg_database_datconfig - 1] = 'n';
705 repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0;
713 repl_null[Anum_pg_database_datconfig - 1] = ' ';
715 datum = heap_getattr(tuple, Anum_pg_database_datconfig,
716 RelationGetDescr(rel), &isnull);
718 a = isnull ? ((ArrayType *) NULL) : DatumGetArrayTypeP(datum);
721 a = GUCArrayAdd(a, stmt->variable, valuestr);
723 a = GUCArrayDelete(a, stmt->variable);
726 repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a);
728 repl_null[Anum_pg_database_datconfig - 1] = 'n';
731 newtuple = heap_modifytuple(tuple, rel, repl_val, repl_null, repl_repl);
732 simple_heap_update(rel, &tuple->t_self, newtuple);
735 CatalogUpdateIndexes(rel, newtuple);
737 systable_endscan(scan);
738 heap_close(rel, RowExclusiveLock);
748 get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
749 int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
750 TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
761 /* Caller may wish to grab a better lock on pg_database beforehand... */
762 relation = heap_openr(DatabaseRelationName, AccessShareLock);
764 ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
765 F_NAMEEQ, NameGetDatum(name));
767 scan = systable_beginscan(relation, DatabaseNameIndex, true, SnapshotNow, 1, &scanKey);
769 tuple = systable_getnext(scan);
771 gottuple = HeapTupleIsValid(tuple);
774 Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
776 /* oid of the database */
778 *dbIdP = HeapTupleGetOid(tuple);
779 /* sysid of the owner */
781 *ownerIdP = dbform->datdba;
782 /* character encoding */
784 *encodingP = dbform->encoding;
785 /* allowed as template? */
787 *dbIsTemplateP = dbform->datistemplate;
788 /* last system OID used in database */
790 *dbLastSysOidP = dbform->datlastsysoid;
791 /* limit of vacuumed XIDs */
793 *dbVacuumXidP = dbform->datvacuumxid;
794 /* limit of frozen XIDs */
796 *dbFrozenXidP = dbform->datfrozenxid;
797 /* database path (as registered in pg_database) */
803 datum = heap_getattr(tuple,
804 Anum_pg_database_datpath,
805 RelationGetDescr(relation),
809 text *pathtext = DatumGetTextP(datum);
810 int pathlen = VARSIZE(pathtext) - VARHDRSZ;
812 Assert(pathlen >= 0 && pathlen < MAXPGPATH);
813 strncpy(dbpath, VARDATA(pathtext), pathlen);
814 *(dbpath + pathlen) = '\0';
821 systable_endscan(scan);
822 heap_close(relation, AccessShareLock);
828 have_createdb_privilege(void)
833 utup = SearchSysCache(SHADOWSYSID,
834 Int32GetDatum(GetUserId()),
837 if (!HeapTupleIsValid(utup))
840 retval = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
842 ReleaseSysCache(utup);
849 resolve_alt_dbpath(const char *dbpath, Oid dboid)
855 if (dbpath == NULL || dbpath[0] == '\0')
858 if (first_path_separator(dbpath))
860 if (!is_absolute_path(dbpath))
862 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
863 errmsg("relative paths are not allowed as database locations")));
864 #ifndef ALLOW_ABSOLUTE_DBPATHS
866 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
867 errmsg("absolute paths are not allowed as database locations")));
873 /* must be environment variable */
874 char *var = getenv(dbpath);
878 (errcode(ERRCODE_UNDEFINED_OBJECT),
879 errmsg("postmaster environment variable \"%s\" not found",
881 if (!is_absolute_path(var))
883 (errcode(ERRCODE_INVALID_NAME),
884 errmsg("postmaster environment variable \"%s\" must be absolute path",
889 len = strlen(prefix) + 6 + sizeof(Oid) * 8 + 1;
890 if (len >= MAXPGPATH - 100)
892 (errcode(ERRCODE_INVALID_NAME),
893 errmsg("alternate path is too long")));
896 snprintf(ret, len, "%s/base/%u", prefix, dboid);
903 remove_dbdirs(const char *nominal_loc, const char *alt_loc)
905 const char *target_dir;
906 char buf[MAXPGPATH + 100];
909 target_dir = alt_loc ? alt_loc : nominal_loc;
912 * Close virtual file descriptors so the kernel has more available for
913 * the system() call below.
920 if (unlink(nominal_loc) != 0)
923 (errcode_for_file_access(),
924 errmsg("could not remove \"%s\": %m", nominal_loc)));
930 snprintf(buf, sizeof(buf), "rm -rf '%s'", target_dir);
932 snprintf(buf, sizeof(buf), "rmdir /s /q \"%s\"", target_dir);
935 if (system(buf) != 0)
938 (errcode_for_file_access(),
939 errmsg("could not remove database directory \"%s\": %m",
949 * get_database_oid - given a database name, look up the OID
951 * Returns InvalidOid if database name not found.
953 * This is not actually used in this file, but is exported for use elsewhere.
956 get_database_oid(const char *dbname)
958 Relation pg_database;
959 ScanKeyData entry[1];
964 /* There's no syscache for pg_database, so must look the hard way */
965 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
966 ScanKeyEntryInitialize(&entry[0], 0x0,
967 Anum_pg_database_datname, F_NAMEEQ,
968 CStringGetDatum(dbname));
969 scan = systable_beginscan(pg_database, DatabaseNameIndex, true, SnapshotNow, 1, entry);
971 dbtuple = systable_getnext(scan);
973 /* We assume that there can be at most one matching tuple */
974 if (HeapTupleIsValid(dbtuple))
975 oid = HeapTupleGetOid(dbtuple);
979 systable_endscan(scan);
980 heap_close(pg_database, AccessShareLock);
987 * get_database_name - given a database OID, look up the name
989 * Returns InvalidOid if database name not found.
991 * This is not actually used in this file, but is exported for use elsewhere.
994 get_database_name(Oid dbid)
996 Relation pg_database;
997 ScanKeyData entry[1];
1002 /* There's no syscache for pg_database, so must look the hard way */
1003 pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1004 ScanKeyEntryInitialize(&entry[0], 0x0,
1005 ObjectIdAttributeNumber, F_OIDEQ,
1006 ObjectIdGetDatum(dbid));
1007 scan = systable_beginscan(pg_database, DatabaseOidIndex, true, SnapshotNow, 1, entry);
1009 dbtuple = systable_getnext(scan);
1011 /* We assume that there can be at most one matching tuple */
1012 if (HeapTupleIsValid(dbtuple))
1013 result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname));
1017 systable_endscan(scan);
1018 heap_close(pg_database, AccessShareLock);