diff --git a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml
index 59cf9c65e7..7376804403 100644
--- a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml
+++ b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml
@@ -26,6 +26,7 @@ ALTER FOREIGN DATA WRAPPER name
[ VALIDATOR validator_function | NO VALIDATOR ]
[ OPTIONS ( [ ADD | SET | DROP ] option ['value'] [, ... ]) ]
ALTER FOREIGN DATA WRAPPER name OWNER TO new_owner
+ALTER FOREIGN DATA WRAPPER name RENAME TO new_name
@@ -122,6 +123,24 @@ ALTER FOREIGN DATA WRAPPER name OWN
+
+
+ new_owner
+
+
+ The user name of the new owner of the foreign-data wrapper.
+
+
+
+
+
+ new_name
+
+
+ The new name for the foreign-data wrapper.
+
+
+
@@ -150,7 +169,8 @@ ALTER FOREIGN DATA WRAPPER dbi VALIDATOR bob.myvalidator;
ALTER FOREIGN DATA WRAPPER conforms to ISO/IEC
9075-9 (SQL/MED), except that the HANDLER,
- VALIDATOR> and OWNER TO> clauses are extensions.
+ VALIDATOR>, OWNER TO>, and RENAME
+ clauses are extensions.
diff --git a/doc/src/sgml/ref/alter_server.sgml b/doc/src/sgml/ref/alter_server.sgml
index c27b4c06a1..248efd9163 100644
--- a/doc/src/sgml/ref/alter_server.sgml
+++ b/doc/src/sgml/ref/alter_server.sgml
@@ -24,6 +24,7 @@ PostgreSQL documentation
ALTER SERVER server_name [ VERSION 'new_version' ]
[ OPTIONS ( [ ADD | SET | DROP ] option ['value'] [, ... ] ) ]
ALTER SERVER server_name OWNER TO new_owner
+ALTER SERVER server_name RENAME TO new_name
@@ -82,6 +83,24 @@ ALTER SERVER server_name OWNER TO <
+
+
+ new_owner
+
+
+ The user name of the new owner of the foreign server.
+
+
+
+
+
+ new_name
+
+
+ The new name for the foreign server.
+
+
+
@@ -108,6 +127,8 @@ ALTER SERVER foo VERSION '8.4' OPTIONS (SET host 'baz');
ALTER SERVER conforms to ISO/IEC 9075-9 (SQL/MED).
+ The OWNER TO and RENAME forms are
+ PostgreSQL extensions.
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index eb0584e991..f9be3a9a4e 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -65,6 +65,14 @@ ExecRenameStmt(RenameStmt *stmt)
RenameDatabase(stmt->subname, stmt->newname);
break;
+ case OBJECT_FDW:
+ RenameForeignDataWrapper(stmt->subname, stmt->newname);
+ break;
+
+ case OBJECT_FOREIGN_SERVER:
+ RenameForeignServer(stmt->subname, stmt->newname);
+ break;
+
case OBJECT_FUNCTION:
RenameFunction(stmt->object, stmt->objarg, stmt->newname);
break;
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index b30ff40923..5e58713da7 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -200,6 +200,82 @@ GetUserOidFromMapping(const char *username, bool missing_ok)
}
+/*
+ * Rename foreign-data wrapper
+ */
+void
+RenameForeignDataWrapper(const char *oldname, const char *newname)
+{
+ HeapTuple tup;
+ Relation rel;
+
+ rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
+
+ tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(oldname));
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" does not exist", oldname)));
+
+ /* make sure the new name doesn't exist */
+ if (SearchSysCacheExists1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(newname)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" already exists", newname)));
+
+ /* must be owner of FDW */
+ if (!pg_foreign_data_wrapper_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FDW,
+ oldname);
+
+ /* rename */
+ namestrcpy(&(((Form_pg_foreign_data_wrapper) GETSTRUCT(tup))->fdwname), newname);
+ simple_heap_update(rel, &tup->t_self, tup);
+ CatalogUpdateIndexes(rel, tup);
+
+ heap_close(rel, NoLock);
+ heap_freetuple(tup);
+}
+
+
+/*
+ * Rename foreign server
+ */
+void
+RenameForeignServer(const char *oldname, const char *newname)
+{
+ HeapTuple tup;
+ Relation rel;
+
+ rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
+
+ tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(oldname));
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("server \"%s\" does not exist", oldname)));
+
+ /* make sure the new name doesn't exist */
+ if (SearchSysCacheExists1(FOREIGNSERVERNAME, CStringGetDatum(newname)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("server \"%s\" already exists", newname)));
+
+ /* must be owner of server */
+ if (!pg_foreign_server_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ oldname);
+
+ /* rename */
+ namestrcpy(&(((Form_pg_foreign_server) GETSTRUCT(tup))->srvname), newname);
+ simple_heap_update(rel, &tup->t_self, tup);
+ CatalogUpdateIndexes(rel, tup);
+
+ heap_close(rel, NoLock);
+ heap_freetuple(tup);
+}
+
+
/*
* Change foreign-data wrapper owner.
*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 2a497d1b79..c3e0ee1877 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6434,6 +6434,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->newname = $6;
$$ = (Node *)n;
}
+ | ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_FDW;
+ n->subname = $5;
+ n->newname = $8;
+ $$ = (Node *)n;
+ }
| ALTER FUNCTION function_with_argtypes RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
@@ -6485,6 +6493,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->newname = $6;
$$ = (Node *)n;
}
+ | ALTER SERVER name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_FOREIGN_SERVER;
+ n->subname = $3;
+ n->newname = $6;
+ $$ = (Node *)n;
+ }
| ALTER TABLE relation_expr RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 70d3a8fe02..1390351697 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -146,6 +146,8 @@ extern text *serialize_deflist(List *deflist);
extern List *deserialize_deflist(Datum txt);
/* commands/foreigncmds.c */
+extern void RenameForeignServer(const char *oldname, const char *newname);
+extern void RenameForeignDataWrapper(const char *oldname, const char *newname);
extern void AlterForeignServerOwner(const char *name, Oid newOwnerId);
extern void AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId);
extern void CreateForeignDataWrapper(CreateFdwStmt *stmt);
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index 314748c6d4..122e28532a 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -177,6 +177,17 @@ RESET ROLE;
postgresql | foreign_data_user | - | postgresql_fdw_validator | | |
(3 rows)
+ALTER FOREIGN DATA WRAPPER foo RENAME TO foo1;
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Handler | Validator | Access privileges | FDW Options | Description
+------------+-------------------------+---------+--------------------------+-------------------+------------------------------+-------------
+ dummy | foreign_data_user | - | - | | | useless
+ foo1 | regress_test_role_super | - | - | | (b '3', c '4', a '2', d '5') |
+ postgresql | foreign_data_user | - | postgresql_fdw_validator | | |
+(3 rows)
+
+ALTER FOREIGN DATA WRAPPER foo1 RENAME TO foo;
-- DROP FOREIGN DATA WRAPPER
DROP FOREIGN DATA WRAPPER nonexistent; -- ERROR
ERROR: foreign-data wrapper "nonexistent" does not exist
@@ -427,6 +438,26 @@ privileges for foreign-data wrapper foo
t2 | regress_test_role | foo | | | | |
(10 rows)
+ALTER SERVER s8 RENAME to s8new;
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | FDW Options | Description
+-------+-----------------------+----------------------+-----------------------------------------+--------+---------+--------------------------------------+-------------
+ s1 | regress_test_indirect | foo | foreign_data_user=U/foreign_data_user +| | 1.1 | (servername 's1') |
+ | | | regress_test_role=U/foreign_data_user | | | |
+ s2 | foreign_data_user | foo | | | 1.1 | (host 'a', dbname 'b') |
+ s3 | foreign_data_user | foo | | oracle | | ("tns name" 'orcl', port '1521') |
+ s4 | foreign_data_user | foo | | oracle | | (host 'a', dbname 'b') |
+ s5 | foreign_data_user | foo | | | 15.0 | |
+ s6 | foreign_data_user | foo | foreign_data_user=U/foreign_data_user +| | 16.0 | (host 'a', dbname 'b') |
+ | | | regress_test_role2=U*/foreign_data_user | | | |
+ s7 | foreign_data_user | foo | | oracle | 17.0 | (host 'a', dbname 'b') |
+ s8new | foreign_data_user | postgresql | | | | (dbname 'db1', connect_timeout '30') |
+ t1 | regress_test_role | foo | | | | |
+ t2 | regress_test_role | foo | | | | |
+(10 rows)
+
+ALTER SERVER s8new RENAME to s8;
-- DROP SERVER
DROP SERVER nonexistent; -- ERROR
ERROR: server "nonexistent" does not exist
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
index bfdb32afdc..e99e7079b1 100644
--- a/src/test/regress/sql/foreign_data.sql
+++ b/src/test/regress/sql/foreign_data.sql
@@ -84,6 +84,10 @@ ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD e '6'); -- ERROR
RESET ROLE;
\dew+
+ALTER FOREIGN DATA WRAPPER foo RENAME TO foo1;
+\dew+
+ALTER FOREIGN DATA WRAPPER foo1 RENAME TO foo;
+
-- DROP FOREIGN DATA WRAPPER
DROP FOREIGN DATA WRAPPER nonexistent; -- ERROR
DROP FOREIGN DATA WRAPPER IF EXISTS nonexistent;
@@ -181,6 +185,10 @@ RESET ROLE;
DROP ROLE regress_test_indirect; -- ERROR
\des+
+ALTER SERVER s8 RENAME to s8new;
+\des+
+ALTER SERVER s8new RENAME to s8;
+
-- DROP SERVER
DROP SERVER nonexistent; -- ERROR
DROP SERVER IF EXISTS nonexistent;