aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/dbcommands.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2022-01-24 14:23:15 -0500
committerRobert Haas <rhaas@postgresql.org>2022-01-24 14:23:43 -0500
commitaa01051418f10afbdfa781b8dc109615ca785ff9 (patch)
treea359d71ad8e32785ca71fe1f0c79dbec4efb9bf6 /src/backend/commands/dbcommands.c
parent4f0bcc735038e96404fae59aa16ef9beaf6bb0aa (diff)
downloadpostgresql-aa01051418f10afbdfa781b8dc109615ca785ff9.tar.gz
postgresql-aa01051418f10afbdfa781b8dc109615ca785ff9.zip
pg_upgrade: Preserve database OIDs.
Commit 9a974cbcba005256a19991203583a94b4f9a21a9 arranged to preserve relfilenodes and tablespace OIDs. For similar reasons, also arrange to preserve database OIDs. One problem is that, up until now, the OIDs assigned to the template0 and postgres databases have not been fixed. This could be a problem when upgrading, because pg_upgrade might try to migrate a database from the old cluster to the new cluster while keeping the OID and find a different database with that OID, resulting in a failure. If it finds a database with the same name and the same OID that's OK: it will be dropped and recreated. But the same OID and a different name is a problem. To prevent that, fix the OIDs for postgres and template0 to specific values less than 16384. To avoid running afoul of this rule, these values should not be changed in future releases. It's not a problem that these OIDs aren't fixed in existing releases, because the OIDs that we're assigning here weren't used for either of these databases in any previous release. Thus, there's no chance that an upgrade of a cluster from any previous release will collide with the OIDs we're assigning here. And going forward, the OIDs will always be fixed, so the only potential collision is with a system database having the same name and the same OID, which is OK. This patch lets users assign a specific OID to a database as well, provided however that it can't be less than 16384. I (rhaas) thought it might be better not to expose this capability to users, but the consensus was otherwise, so the syntax is documented. Letting users assign OIDs below 16384 would not be OK, though, because a user-created database with a low-numbered OID might collide with a system-created database in a future release. We therefore prohibit that. Shruthi KC, based on an earlier patch from Antonin Houska, reviewed and with some adjustments by me. Discussion: http://postgr.es/m/CA+TgmoYgTwYcUmB=e8+hRHOFA0kkS6Kde85+UNdon6q7bt1niQ@mail.gmail.com Discussion: http://postgr.es/m/CAASxf_Mnwm1Dh2vd5FAhVX6S1nwNSZUB1z12VddYtM++H2+p7w@mail.gmail.com
Diffstat (limited to 'src/backend/commands/dbcommands.c')
-rw-r--r--src/backend/commands/dbcommands.c57
1 files changed, 52 insertions, 5 deletions
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index da8345561d8..e950e4c458a 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -115,7 +115,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
HeapTuple tuple;
Datum new_record[Natts_pg_database];
bool new_record_nulls[Natts_pg_database];
- Oid dboid;
+ Oid dboid = InvalidOid;
Oid datdba;
ListCell *option;
DefElem *dtablespacename = NULL;
@@ -215,6 +215,30 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
errhint("Consider using tablespaces instead."),
parser_errposition(pstate, defel->location)));
}
+ else if (strcmp(defel->defname, "oid") == 0)
+ {
+ dboid = defGetInt32(defel);
+
+ /*
+ * We don't normally permit new databases to be created with
+ * system-assigned OIDs. pg_upgrade tries to preserve database
+ * OIDs, so we can't allow any database to be created with an
+ * OID that might be in use in a freshly-initialized cluster
+ * created by some future version. We assume all such OIDs will
+ * be from the system-managed OID range.
+ *
+ * As an exception, however, we permit any OID to be assigned when
+ * allow_system_table_mods=on (so that initdb can assign system
+ * OIDs to template0 and postgres) or when performing a binary
+ * upgrade (so that pg_upgrade can preserve whatever OIDs it finds
+ * in the source cluster).
+ */
+ if (dboid < FirstNormalObjectId &&
+ !allowSystemTableMods && !IsBinaryUpgrade)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE)),
+ errmsg("OIDs less than %u are reserved for system objects", FirstNormalObjectId));
+ }
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -502,11 +526,34 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
*/
pg_database_rel = table_open(DatabaseRelationId, RowExclusiveLock);
- do
+ /*
+ * If database OID is configured, check if the OID is already in use or
+ * data directory already exists.
+ */
+ if (OidIsValid(dboid))
{
- dboid = GetNewOidWithIndex(pg_database_rel, DatabaseOidIndexId,
- Anum_pg_database_oid);
- } while (check_db_file_conflict(dboid));
+ char *existing_dbname = get_database_name(dboid);
+
+ 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));
+ }
/*
* Insert a new tuple into pg_database. This establishes our ownership of