+/*
+ * Rename database
+ */
+void
+RenameDatabase(const char *oldname, const char *newname)
+{
+ HeapTuple tup,
+ newtup;
+ Relation rel;
+ SysScanDesc scan,
+ scan2;
+ ScanKeyData key,
+ key2;
+
+ /*
+ * Obtain AccessExclusiveLock so that no new session gets started
+ * while the rename is in progress.
+ */
+ rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+
+ ScanKeyInit(&key,
+ Anum_pg_database_datname,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ NameGetDatum(oldname));
+ scan = systable_beginscan(rel, DatabaseNameIndex, true,
+ SnapshotNow, 1, &key);
+
+ tup = systable_getnext(scan);
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_DATABASE),
+ errmsg("database \"%s\" does not exist", oldname)));
+
+ /*
+ * XXX Client applications probably store the current database
+ * somewhere, so renaming it could cause confusion. On the other
+ * hand, there may not be an actual problem besides a little
+ * confusion, so think about this and decide.
+ */
+ if (HeapTupleGetOid(tup) == MyDatabaseId)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("current database may not be renamed")));
+
+ /*
+ * Make sure the database does not have active sessions. Might not be
+ * necessary, but it's consistent with other database operations.
+ */
+ if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_IN_USE),
+ errmsg("database \"%s\" is being accessed by other users",
+ oldname)));
+
+ /* make sure the new name doesn't exist */
+ ScanKeyInit(&key2,
+ Anum_pg_database_datname,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ NameGetDatum(newname));
+ scan2 = systable_beginscan(rel, DatabaseNameIndex, true,
+ SnapshotNow, 1, &key2);
+ if (HeapTupleIsValid(systable_getnext(scan2)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_DATABASE),
+ errmsg("database \"%s\" already exists", newname)));
+ systable_endscan(scan2);
+
+ /* must be owner */
+ if (!pg_database_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ oldname);
+
+ /* must have createdb */
+ if (!have_createdb_privilege())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to rename database")));
+
+ /* rename */
+ newtup = heap_copytuple(tup);
+ namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname);
+ simple_heap_update(rel, &newtup->t_self, newtup);
+ CatalogUpdateIndexes(rel, newtup);
+
+ systable_endscan(scan);
+ heap_close(rel, NoLock);
+
+ /*
+ * Force dirty buffers out to disk, so that newly-connecting backends
+ * will see the renamed database in pg_database right away. (They'll
+ * see an uncommitted tuple, but they don't care; see
+ * GetRawDatabaseInfo.)
+ */
+ BufferSync(-1, -1);
+}
+