typedefstruct
{
Oid src_dboid; /* source (template) DB */
Oid dest_dboid; /* DB we are trying to create */
CreateDBStrategy strategy; /* create db strategy */
} createdb_failure_params;
typedefstruct
{
Oid dest_dboid; /* DB we are trying to move */
Oid dest_tsoid; /* tablespace we are trying to move to */
} movedb_failure_params;
/* *Informationaboutarelationtobecopiedwhencreatingadatabase.
*/ typedefstruct CreateDBRelInfo
{
RelFileLocator rlocator; /* physical relation identifier */
Oid reloid; /* relation oid */ bool permanent; /* relation is permanent or unlogged */
} CreateDBRelInfo;
/* non-export function prototypes */ staticvoid createdb_failure_callback(int code, Datum arg); staticvoid movedb(constchar *dbname, constchar *tblspcname); staticvoid movedb_failure_callback(int code, Datum arg); staticbool get_db_info(constchar *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, bool *dbHasLoginEvtP,
TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP,
Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbLocale, char **dbIcurules, char *dbLocProvider, char **dbCollversion); staticvoid remove_dbtablespaces(Oid db_id); staticbool check_db_file_conflict(Oid db_id); staticint errdetail_busy_db(int notherbackends, int npreparedxacts); staticvoid CreateDatabaseUsingWalLog(Oid src_dboid, Oid dst_dboid, Oid src_tsid,
Oid dst_tsid); static List *ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath); static List *ScanSourceDatabasePgClassPage(Page page, Buffer buf, Oid tbid,
Oid dbid, char *srcpath,
List *rlocatorlist, Snapshot snapshot); static CreateDBRelInfo *ScanSourceDatabasePgClassTuple(HeapTupleData *tuple,
Oid tbid, Oid dbid, char *srcpath); staticvoid CreateDirAndVersionFile(char *dbpath, Oid dbid, Oid tsid, bool isRedo); staticvoid CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid,
Oid src_tsid, Oid dst_tsid); staticvoid recovery_create_dbdir(char *path, bool only_tblspc);
/* *CreateanewdatabaseusingtheWAL_LOGstrategy. * *Eachcopiedblockisseparatelywrittentothewrite-aheadlog.
*/ staticvoid
CreateDatabaseUsingWalLog(Oid src_dboid, Oid dst_dboid,
Oid src_tsid, Oid dst_tsid)
{ char *srcpath; char *dstpath;
List *rlocatorlist = NULL;
ListCell *cell;
LockRelId srcrelid;
LockRelId dstrelid;
RelFileLocator srcrlocator;
RelFileLocator dstrlocator;
CreateDBRelInfo *relinfo;
/* Get source and destination database paths. */
srcpath = GetDatabasePath(src_dboid, src_tsid);
dstpath = GetDatabasePath(dst_dboid, dst_tsid);
/* Copy relmap file from source database to the destination database. */
RelationMapCopy(dst_dboid, dst_tsid, srcpath, dstpath);
/* Get list of relfilelocators to copy from the source database. */
rlocatorlist = ScanSourceDatabasePgClass(src_tsid, src_dboid, srcpath);
Assert(rlocatorlist != NIL);
/* Get pg_class relfilenumber. */
relfilenumber = RelationMapOidToFilenumberForDatabase(srcpath,
RelationRelationId);
/* Don't read data into shared_buffers without holding a relation lock. */
relid.dbId = dbid;
relid.relId = RelationRelationId;
LockRelationId(&relid, AccessShareLock);
/* Prepare a RelFileLocator for the pg_class relation. */
rlocator.spcOid = tbid;
rlocator.dbOid = dbid;
rlocator.relNumber = relfilenumber;
/* We must have a valid relfilenumber. */ if (!RelFileNumberIsValid(relfilenumber))
elog(ERROR, "relation with OID %u does not have a valid relfilenumber",
classForm->oid);
/* Prepare a rel info element and add it to the list. */
relinfo = (CreateDBRelInfo *) palloc(sizeof(CreateDBRelInfo)); if (OidIsValid(classForm->reltablespace))
relinfo->rlocator.spcOid = classForm->reltablespace; else
relinfo->rlocator.spcOid = tbid;
/* Create database directory. */ if (MakePGDirectory(dbpath) < 0)
{ /* Failure other than already exists or not in WAL replay? */ if (errno != EEXIST || !isRedo)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create directory \"%s\": %m", dbpath)));
}
if (fd < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create file \"%s\": %m", versionfile)));
/* Write PG_MAJORVERSION in the PG_VERSION file. */
pgstat_report_wait_start(WAIT_EVENT_VERSION_FILE_WRITE);
errno = 0; if ((int) write(fd, buf, nbytes) != nbytes)
{ /* If write didn't set errno, assume problem is no disk space. */ if (errno == 0)
errno = ENOSPC;
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m", versionfile)));
}
pgstat_report_wait_end();
pgstat_report_wait_start(WAIT_EVENT_VERSION_FILE_SYNC); if (pg_fsync(fd) != 0)
ereport(data_sync_elevel(ERROR),
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", versionfile)));
fsync_fname(dbpath, true);
pgstat_report_wait_end();
/* Close the version file. */
CloseTransientFile(fd);
/* If we are not in WAL replay then write the WAL. */ if (!isRedo)
{
xl_dbase_create_wal_log_rec xlrec;
/* obtain OID of proposed owner */ if (dbowner)
datdba = get_role_oid(dbowner, false); else
datdba = GetUserId();
/* *Tocreateadatabase,musthavecreatedbprivilegeandmustbeableto *becomethetargetrole(thisdoesnotimplythatthetargetroleitself *musthavecreatedbprivilege).Thelatterprovisionguardsagainst *"giveaway"attacks.Notethatasuperuserwillalwayshavebothof *theseprivilegesafortiori.
*/ if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create database")));
check_can_set_role(GetUserId(), datdba);
/* *Lookupdatabase(template)tobecloned,andobtainsharelockonit. *ShareLockallowstwoCREATEDATABASEstoworkfromthesametemplate *concurrently,whileensuringnooneisbusydroppingitinparallel *(whichwouldbeVeryBadsincewe'dlikelygetanincompletecopy *withoutknowingit).Thisalsopreventsanynewconnectionsfrombeing *madetothesourceuntilwefinishcopyingit,sowecanbesureit *won'tchangeunderneathus.
*/ if (!dbtemplate)
dbtemplate = "template1"; /* Default template database name */
if (!get_db_info(dbtemplate, ShareLock,
&src_dboid, &src_owner, &src_encoding,
&src_istemplate, &src_allowconn, &src_hasloginevt,
&src_frozenxid, &src_minmxid, &src_deftablespace,
&src_collate, &src_ctype, &src_locale, &src_icurules, &src_locprovider,
&src_collversion))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("template database \"%s\" does not exist",
dbtemplate)));
/* *Ifthesourcedatabasewasintheprocessofbeingdropped,wecan't *useitasatemplate.
*/ if (database_is_invalid_oid(src_dboid))
ereport(ERROR,
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot use invalid database \"%s\" as template", dbtemplate),
errhint("Use DROP DATABASE to drop invalid databases."));
/* *Permissioncheck:tocopyaDBthat'snotmarkeddatistemplate,you *mustbesuperuserortheownerthereof.
*/ if (!src_istemplate)
{ if (!object_ownercheck(DatabaseRelationId, src_dboid, GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to copy database \"%s\"",
dbtemplate)));
}
/* Validate the database creation strategy. */ if (strategyEl && strategyEl->arg)
{ char *strategy;
/* If encoding or locales are defaulted, use source's setting */ if (encoding < 0)
encoding = src_encoding; if (dbcollate == NULL)
dbcollate = src_collate; if (dbctype == NULL)
dbctype = src_ctype; if (dblocprovider == '\0')
dblocprovider = src_locprovider; if (dblocale == NULL && dblocprovider == src_locprovider)
dblocale = src_locale; if (dbicurules == NULL)
dbicurules = src_icurules;
/* Some encodings are client only */ if (!PG_VALID_BE_ENCODING(encoding))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid server encoding %d", encoding)));
/* Check that the chosen locales are valid, and get canonical spellings */ if (!check_locale(LC_COLLATE, dbcollate, &canonname))
{ if (dblocprovider == COLLPROVIDER_BUILTIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid LC_COLLATE locale name: \"%s\"", dbcollate),
errhint("If the locale name is specific to the builtin provider, use BUILTIN_LOCALE."))); elseif (dblocprovider == COLLPROVIDER_ICU)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid LC_COLLATE locale name: \"%s\"", dbcollate),
errhint("If the locale name is specific to the ICU provider, use ICU_LOCALE."))); else
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid LC_COLLATE locale name: \"%s\"", dbcollate)));
}
dbcollate = canonname; if (!check_locale(LC_CTYPE, dbctype, &canonname))
{ if (dblocprovider == COLLPROVIDER_BUILTIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid LC_CTYPE locale name: \"%s\"", dbctype),
errhint("If the locale name is specific to the builtin provider, use BUILTIN_LOCALE."))); elseif (dblocprovider == COLLPROVIDER_ICU)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid LC_CTYPE locale name: \"%s\"", dbctype),
errhint("If the locale name is specific to the ICU provider, use ICU_LOCALE."))); else
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid LC_CTYPE locale name: \"%s\"", dbctype)));
}
/* validate provider-specific parameters */ if (dblocprovider != COLLPROVIDER_BUILTIN)
{ if (builtinlocaleEl)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("BUILTIN_LOCALE cannot be specified unless locale provider is builtin")));
}
if (dblocprovider != COLLPROVIDER_ICU)
{ if (iculocaleEl)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ICU locale cannot be specified unless locale provider is ICU")));
if (dbicurules)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ICU rules cannot be specified unless locale provider is ICU")));
}
/* validate and canonicalize locale for the provider */ if (dblocprovider == COLLPROVIDER_BUILTIN)
{ /* *Thiswouldhappeniftemplate0usesthelibcproviderbutthenew *databaseusesbuiltin.
*/ if (!dblocale)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("LOCALE or BUILTIN_LOCALE must be specified")));
dblocale = builtin_validate_locale(encoding, dblocale);
} elseif (dblocprovider == COLLPROVIDER_ICU)
{ if (!(is_encoding_supported_by_icu(encoding)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("encoding \"%s\" is not supported with ICU provider",
pg_encoding_to_char(encoding))));
/* *Thiswouldhappeniftemplate0usesthelibcproviderbutthenew *databaseusesicu.
*/ if (!dblocale)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("LOCALE or ICU_LOCALE must be specified")));
if (langtag && strcmp(dblocale, langtag) != 0)
{
ereport(NOTICE,
(errmsg("using standard form \"%s\" for ICU locale \"%s\"",
langtag, dblocale)));
dblocale = langtag;
}
}
icu_validate_locale(dblocale);
}
/* for libc, locale comes from datcollate and datctype */ if (dblocprovider == COLLPROVIDER_LIBC)
dblocale = NULL;
/* *Checkthatthenewencodingandlocalesettingsmatchthesource *database.Weinsistonthisbecausewesimplycopythesourcedata--- *anynon-ASCIIdatawouldbewronglyencoded,andanyindexessorted *accordingtothesourcelocalewouldbewrong. * *However,weassumethattemplate0doesn'tcontainanynon-ASCIIdata *noranyindexesthatdependoncollationorctype,sotemplate0canbe *usedastemplateforcreatingadatabasewithanyencodingorlocale.
*/ if (strcmp(dbtemplate, "template0") != 0)
{ if (encoding != src_encoding)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("new encoding (%s) is incompatible with the encoding of the template database (%s)",
pg_encoding_to_char(encoding),
pg_encoding_to_char(src_encoding)),
errhint("Use the same encoding as in the template database, or use template0 as template.")));
if (strcmp(dbcollate, src_collate) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("new collation (%s) is incompatible with the collation of the template database (%s)",
dbcollate, src_collate),
errhint("Use the same collation as in the template database, or use template0 as template.")));
if (strcmp(dbctype, src_ctype) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("new LC_CTYPE (%s) is incompatible with the LC_CTYPE of the template database (%s)",
dbctype, src_ctype),
errhint("Use the same LC_CTYPE as in the template database, or use template0 as template.")));
if (dblocprovider != src_locprovider)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("new locale provider (%s) does not match locale provider of the template database (%s)",
collprovider_name(dblocprovider), collprovider_name(src_locprovider)),
errhint("Use the same locale provider as in the template database, or use template0 as template.")));
if (dblocprovider == COLLPROVIDER_ICU)
{ char *val1; char *val2;
Assert(dblocale);
Assert(src_locale); if (strcmp(dblocale, src_locale) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("new ICU locale (%s) is incompatible with the ICU locale of the template database (%s)",
dblocale, src_locale),
errhint("Use the same ICU locale as in the template database, or use template0 as template.")));
val1 = dbicurules; if (!val1)
val1 = "";
val2 = src_icurules; if (!val2)
val2 = ""; if (strcmp(val1, val2) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("new ICU collation rules (%s) are incompatible with the ICU collation rules of the template database (%s)",
val1, val2),
errhint("Use the same ICU collation rules as in the template database, or use template0 as template.")));
}
}
actual_versionstr = get_collation_actual_version(dblocprovider, locale); if (!actual_versionstr)
ereport(ERROR,
(errmsg("template database \"%s\" has a collation version, but no actual collation version could be determined",
dbtemplate)));
if (strcmp(actual_versionstr, src_collversion) != 0)
ereport(ERROR,
(errmsg("template database \"%s\" has a collation version mismatch",
dbtemplate),
errdetail("The template database was created using collation version %s, " "but the operating system provides version %s.",
src_collversion, actual_versionstr),
errhint("Rebuild all objects in the template database that use the default collation and run " "ALTER DATABASE %s REFRESH COLLATION VERSION, " "or build PostgreSQL with the right library version.",
quote_identifier(dbtemplate))));
}
if (dbcollversion == NULL)
dbcollversion = src_collversion;
/* pg_global must never be the default tablespace */ if (dst_deftablespace == GLOBALTABLESPACE_OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("pg_global cannot be used as default tablespace")));
if (stat(srcpath, &st) == 0 &&
S_ISDIR(st.st_mode) &&
!directory_is_empty(srcpath))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot assign new default tablespace \"%s\"",
tablespacename),
errdetail("There is a conflict because database \"%s\" already has some tables in this tablespace.",
dbtemplate)));
pfree(srcpath);
}
} else
{ /* Use template database's default tablespace */
dst_deftablespace = src_deftablespace; /* Note there is no additional permission check in this path */
}
/* *Ifbuiltwithappropriateswitch,whinewhenregression-testing *conventionsfordatabasenamesareviolated.Butdon'tcomplainduring *initdb.
*/ #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS if (IsUnderPostmaster && strstr(dbname, "regression") == NULL)
elog(WARNING, "databases created by regression test cases should have names including \"regression\""); #endif
if (existing_dbname != NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE)),
errmsg("database OID %u is already in use by database \"%s\"",
dboid, existing_dbname));
if (check_db_file_conflict(dboid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE)),
errmsg("data directory with the specified OID %u already exists", dboid));
} else
{ /* Select an OID for the new database if is not explicitly configured. */ do
{
dboid = GetNewOidWithIndex(pg_database_rel, DatabaseOidIndexId,
Anum_pg_database_oid);
} while (check_db_file_conflict(dboid));
}
if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
&db_istemplate, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
{ if (!missing_ok)
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", dbname)));
} else
{ /* Close pg_database, release the lock, since we changed nothing */
table_close(pgdbrel, RowExclusiveLock);
ereport(NOTICE,
(errmsg("database \"%s\" does not exist, skipping",
dbname))); return;
}
}
/* *Permissionchecks
*/ if (!object_ownercheck(DatabaseRelationId, db_id, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
dbname);
/* DROP hook for the database being removed */
InvokeObjectDropHook(DatabaseRelationId, db_id, 0);
/* *DisallowdroppingaDBthatismarkedistemplate.Thisisjustto *preventpeoplefromaccidentallydroppingtemplate0ortemplate1;they *candosoifthey'rereallydetermined...
*/ if (db_istemplate)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot drop a template database")));
/* Obviously can't drop my own database */ if (db_id == MyDatabaseId)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("cannot drop the currently open database")));
/* *Checkwhetherthereareactivelogicalslotsthatrefertothe *to-be-droppeddatabase.Thedatabaselockweareholdingpreventsthe *creationofnewslotsusingthedatabaseorexistingslotsbecoming *active.
*/
(void) ReplicationSlotsCountDBSlots(db_id, &nslots, &nslots_active); if (nslots_active)
{
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("database \"%s\" is used by an active logical replication slot",
dbname),
errdetail_plural("There is %d active slot.", "There are %d active slots.",
nslots_active, nslots_active)));
}
/* *Checkiftherearesubscriptionsdefinedinthetargetdatabase. * *Wecan'tdropthemautomaticallybecausetheymightbeholding *resourcesinotherdatabases/instances.
*/ if ((nsubscriptions = CountDBSubscriptions(db_id)) > 0)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("database \"%s\" is being used by logical replication subscription",
dbname),
errdetail_plural("There is %d subscription.", "There are %d subscriptions.",
nsubscriptions, nsubscriptions)));
/* *Attempttoterminateallexistingconnectionstothetargetdatabaseif *theuserhasrequestedtodoso.
*/ if (force)
TerminateOtherDBBackends(db_id);
/* *Checkforotherbackendsinthetargetdatabase.(Becauseweholdthe *databaselock,nonewonescanstartafterthis.) * *AsinCREATEDATABASE,checkthisafterothererrorconditions.
*/ if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("database \"%s\" is being accessed by other users",
dbname),
errdetail_busy_db(notherbackends, npreparedxacts)));
if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", oldname)));
/* must be owner */ if (!object_ownercheck(DatabaseRelationId, db_id, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
oldname);
/* must have createdb rights */ if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename database")));
/* *Ifbuiltwithappropriateswitch,whinewhenregression-testing *conventionsfordatabasenamesareviolated.
*/ #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS if (strstr(newname, "regression") == NULL)
elog(WARNING, "databases created by regression test cases should have names including \"regression\""); #endif
/* *XXXClientapplicationsprobablystorethecurrentdatabasesomewhere, *sorenamingitcouldcauseconfusion.Ontheotherhand,theremaynot *beanactualproblembesidesalittleconfusion,sothinkaboutthis *anddecide.
*/ if (db_id == MyDatabaseId)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("current database cannot be renamed")));
/* *Makesurethedatabasedoesnothaveactivesessions.Thisisthesame *concernasabove,butappliedtoothersessions. * *AsinCREATEDATABASE,checkthisafterothererrorconditions.
*/ if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("database \"%s\" is being accessed by other users",
oldname),
errdetail_busy_db(notherbackends, npreparedxacts)));
/* *Permissionchecks
*/ if (!object_ownercheck(DatabaseRelationId, db_id, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
dbname);
/* *Obviouslycan'tmovethetablesofmyowndatabase
*/ if (db_id == MyDatabaseId)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("cannot change the tablespace of the currently open database")));
/* *pg_globalmustneverbethedefaulttablespace
*/ if (dst_tblspcoid == GLOBALTABLESPACE_OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("pg_global cannot be used as default tablespace")));
/* *Checkforotherbackendsinthetargetdatabase.(Becauseweholdthe *databaselock,nonewonescanstartafterthis.) * *AsinCREATEDATABASE,checkthisafterothererrorconditions.
*/ if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_IN_USE),
errmsg("database \"%s\" is being accessed by other users",
dbname),
errdetail_busy_db(notherbackends, npreparedxacts)));
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("some relations of database \"%s\" are already in tablespace \"%s\"",
dbname, tblspcname),
errhint("You must move them back to the database's default tablespace before using this command.")));
}
FreeDir(dstdir);
/* *Thedirectoryexistsbutisempty.Wemustremoveitbeforeusing *thecopydirfunction.
*/ if (rmdir(dst_dbpath) != 0)
elog(ERROR, "could not remove directory \"%s\": %m",
dst_dbpath);
}
/* Start new transaction for the remaining work; don't need a snapshot */
StartTransactionCommand();
/* *Removefilesfromtheoldtablespace
*/ if (!rmtree(src_dbpath, true))
ereport(WARNING,
(errmsg("some useless files may be left behind in old database directory \"%s\"",
src_dbpath)));
if (dtablespace)
{ /* *WhiletheSETTABLESPACEsyntaxdoesn'tallowanyotheroptions, *somebodycouldwrite"WITHTABLESPACE...".Forbidanyother *optionsfrombeingspecifiedinthatcase.
*/ if (list_length(stmt->options) != 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("option \"%s\" cannot be specified with other options",
dtablespace->defname),
parser_errposition(pstate, dtablespace->location))); /* this case isn't allowed within a transaction block */
PreventInTransactionBlock(isTopLevel, "ALTER DATABASE SET TABLESPACE");
movedb(stmt->dbname, defGetString(dtablespace)); return InvalidOid;
}
if (distemplate && distemplate->arg)
dbistemplate = defGetBoolean(distemplate); if (dallowconnections && dallowconnections->arg)
dballowconnections = defGetBoolean(dallowconnections); if (dconnlimit && dconnlimit->arg)
{
dbconnlimit = defGetInt32(dconnlimit); if (dbconnlimit < DATCONNLIMIT_UNLIMITED)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid connection limit: %d", dbconnlimit)));
}
if (database_is_invalid_form(datform))
{
ereport(FATAL,
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot alter invalid database \"%s\"", stmt->dbname),
errhint("Use DROP DATABASE to drop invalid databases."));
}
if (!object_ownercheck(DatabaseRelationId, dboid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
stmt->dbname);
/* *Inordertoavoidgettinglockedoutandhavingtogothrough *standalonemode,werefusetodisallowconnectionstothedatabase *we'recurrentlyconnectedto.Lockoutcanstillhappenwithconcurrent *sessionsbutthelikelinessofthatisnothighenoughtoworryabout.
*/ if (!dballowconnections && dboid == MyDatabaseId)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot disallow connections for current database")));
if (datForm->datlocprovider == COLLPROVIDER_LIBC)
{
datum = heap_getattr(tuple, Anum_pg_database_datcollate, RelationGetDescr(rel), &isnull); if (isnull)
elog(ERROR, "unexpected null in pg_database");
} else
{
datum = heap_getattr(tuple, Anum_pg_database_datlocale, RelationGetDescr(rel), &isnull); if (isnull)
elog(ERROR, "unexpected null in pg_database");
}
/* *Ifthenewowneristhesameastheexistingowner,considerthe *commandtohavesucceeded.Thisistobeconsistentwithother *objects.
*/ if (datForm->datdba != newOwnerId)
{
Datum repl_val[Natts_pg_database]; bool repl_null[Natts_pg_database] = {0}; bool repl_repl[Natts_pg_database] = {0};
Acl *newAcl;
Datum aclDatum; bool isNull;
HeapTuple newtuple;
/* Otherwise, must be owner of the existing object */ if (!object_ownercheck(DatabaseRelationId, db_id, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
dbname);
/* Must be able to become new owner */
check_can_set_role(GetUserId(), newOwnerId);
/* *musthavecreatedbrights * *NOTE:Thisisdifferentfromotheralter-ownerchecksinthatthe *currentuserischeckedforcreatedbprivilegesinsteadofthe *destinationowner.ThisisconsistentwiththeCREATEcasefor *databases.Becausesuperuserswillalwayshavethisright,weneed *nospecialcaseforthem.
*/ if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to change owner of database")));
/* Close pg_database, but keep lock till commit */
table_close(rel, NoLock);
return address;
}
Datum
pg_database_collation_actual_version(PG_FUNCTION_ARGS)
{
Oid dbid = PG_GETARG_OID(0);
HeapTuple tp; char datlocprovider;
Datum datum; char *version;
tp = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(dbid)); if (!HeapTupleIsValid(tp))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("database with OID %u does not exist", dbid)));
if (datlocprovider == COLLPROVIDER_LIBC)
datum = SysCacheGetAttrNotNull(DATABASEOID, tp, Anum_pg_database_datcollate); else
datum = SysCacheGetAttrNotNull(DATABASEOID, tp, Anum_pg_database_datlocale);
version = get_collation_actual_version(datlocprovider,
TextDatumGetCString(datum));
ReleaseSysCache(tp);
if (version)
PG_RETURN_TEXT_P(cstring_to_text(version)); else
PG_RETURN_NULL();
}
/* *Helperfunctions
*/
/* *Lookupinfoaboutthedatabasenamed"name".Ifthedatabaseexists, *obtainthespecifiedlocktypeonit,fillinanyoftheremaining *parametersthataren'tNULL,andreturntrue.Ifnosuchdatabase, *returnfalse.
*/ staticbool
get_db_info(constchar *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, bool *dbHasLoginEvtP,
TransactionId *dbFrozenXidP, MultiXactId *dbMinMultiP,
Oid *dbTablespace, char **dbCollate, char **dbCtype, char **dbLocale, char **dbIcurules, char *dbLocProvider, char **dbCollversion)
{ bool result = false;
Relation relation;
Assert(name);
/* Caller may wish to grab a better lock on pg_database beforehand... */
relation = table_open(DatabaseRelationId, AccessShareLock);
/* *Loopcoverstherarecasewherethedatabaseisrenamedbeforewecan *lockit.Wetryagainjustincasewecanfindanewoneofthesame *name.
*/ for (;;)
{
ScanKeyData scanKey;
SysScanDesc scan;
HeapTuple tuple;
Oid dbOid;
if (strcmp(name, NameStr(dbform->datname)) == 0)
{
Datum datum; bool isnull;
/* oid of the database */ if (dbIdP)
*dbIdP = dbOid; /* oid of the owner */ if (ownerIdP)
*ownerIdP = dbform->datdba; /* character encoding */ if (encodingP)
*encodingP = dbform->encoding; /* allowed as template? */ if (dbIsTemplateP)
*dbIsTemplateP = dbform->datistemplate; /* Has on login event trigger? */ if (dbHasLoginEvtP)
*dbHasLoginEvtP = dbform->dathasloginevt; /* allowing connections? */ if (dbAllowConnP)
*dbAllowConnP = dbform->datallowconn; /* limit of frozen XIDs */ if (dbFrozenXidP)
*dbFrozenXidP = dbform->datfrozenxid; /* minimum MultiXactId */ if (dbMinMultiP)
*dbMinMultiP = dbform->datminmxid; /* default tablespace for this database */ if (dbTablespace)
*dbTablespace = dbform->dattablespace; /* default locale settings for this database */ if (dbLocProvider)
*dbLocProvider = dbform->datlocprovider; if (dbCollate)
{
datum = SysCacheGetAttrNotNull(DATABASEOID, tuple, Anum_pg_database_datcollate);
*dbCollate = TextDatumGetCString(datum);
} if (dbCtype)
{
datum = SysCacheGetAttrNotNull(DATABASEOID, tuple, Anum_pg_database_datctype);
*dbCtype = TextDatumGetCString(datum);
} if (dbLocale)
{
datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datlocale, &isnull); if (isnull)
*dbLocale = NULL; else
*dbLocale = TextDatumGetCString(datum);
} if (dbIcurules)
{
datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_daticurules, &isnull); if (isnull)
*dbIcurules = NULL; else
*dbIcurules = TextDatumGetCString(datum);
} if (dbCollversion)
{
datum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datcollversion, &isnull); if (isnull)
*dbCollversion = NULL; else
*dbCollversion = TextDatumGetCString(datum);
}
ReleaseSysCache(tuple);
result = true; break;
} /* can only get here if it was just renamed */
ReleaseSysCache(tuple);
}
if (lockmode != NoLock)
UnlockSharedObject(DatabaseRelationId, dbOid, 0, lockmode);
}
table_close(relation, AccessShareLock);
return result;
}
/* Check if current user has createdb privileges */ bool
have_createdb_privilege(void)
{ bool result = false;
HeapTuple utup;
/* Superusers can always do everything */ if (superuser()) returntrue;
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId())); if (HeapTupleIsValid(utup))
{
result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb;
ReleaseSysCache(utup);
} return result;
}
/* *Removetablespacedirectories * *Wedon'tknowwhattablespacesdb_idisusing,soiteratethroughall *tablespacesremoving<tablespace>/db_id
*/ staticvoid
remove_dbtablespaces(Oid db_id)
{
Relation rel;
TableScanDesc scan;
HeapTuple tuple;
List *ltblspc = NIL;
ListCell *cell; int ntblspc; int i;
Oid *tablespace_ids;
/* *Issueasuitableerrdetailmessageforabusydatabase
*/ staticint
errdetail_busy_db(int notherbackends, int npreparedxacts)
{ if (notherbackends > 0 && npreparedxacts > 0)
/* *Wedon'tdealwithsingularversuspluralhere,sincegettext *doesn'tsupportmultiplepluralsinonestring.
*/
errdetail("There are %d other session(s) and %d prepared transaction(s) using the database.",
notherbackends, npreparedxacts); elseif (notherbackends > 0)
errdetail_plural("There is %d other session using the database.", "There are %d other sessions using the database.",
notherbackends,
notherbackends); else
errdetail_plural("There is %d prepared transaction using the database.", "There are %d prepared transactions using the database.",
npreparedxacts,
npreparedxacts); return0; /* just to keep ereport macro happy */
}
/* We assume that there can be at most one matching tuple */ if (HeapTupleIsValid(dbtuple))
oid = ((Form_pg_database) GETSTRUCT(dbtuple))->oid; else
oid = InvalidOid;
/* *OurtheoryforreplayingaCREATEistoforciblydropthetarget *subdirectoryifpresent,thenre-copythesourcedata.Thismaybe *moreworkthanneeded,butitissimpletoimplement.
*/ if (stat(dst_path, &st) == 0 && S_ISDIR(st.st_mode))
{ if (!rmtree(dst_path, true)) /* If this failed, copydir() below is going to error. */
ereport(WARNING,
(errmsg("some useless files may be left behind in old database directory \"%s\"",
dst_path)));
}
/* *Iftheparentofthetargetpathdoesn'texist,createitnow.This *enablesustocreatethetargetunderneathlater.
*/
parent_path = pstrdup(dst_path);
get_parent_directory(parent_path); if (stat(parent_path, &st) < 0)
{ if (errno != ENOENT)
ereport(FATAL,
errmsg("could not stat directory \"%s\": %m",
dst_path));
/* create the parent directory if needed and valid */
recovery_create_dbdir(parent_path, true);
}
pfree(parent_path);
/* Drop any database-specific replication slots */
ReplicationSlotsDropDBSlots(xlrec->db_id);
/* Drop pages for this database that are in the shared buffer cache */
DropDatabaseBuffers(xlrec->db_id);
/* Also, clean out any fsync requests that might be pending in md.c */
ForgetDatabaseSyncRequests(xlrec->db_id);
/* Clean out the xlog relcache too */
XLogDropDatabase(xlrec->db_id);
/* Close all smgr fds in all backends. */
WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE));
for (i = 0; i < xlrec->ntablespaces; i++)
{
dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_ids[i]);
/* And remove the physical files */ if (!rmtree(dst_path, true))
ereport(WARNING,
(errmsg("some useless files may be left behind in old database directory \"%s\"",
dst_path)));
pfree(dst_path);
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.117Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.