Hi, hackers.
If you create a foreign table referencing itself on a loopback server,
an unpleasant error occurs:
```sql
create extension if not exists postgres_fdw;
drop server if exists loopback cascade ;
create server loopback
foreign data wrapper postgres_fdw
options (dbname 'postgres', host 'localhost');
create user mapping for current_user server loopback;
create foreign table test_self (id int)
server loopback options (table_name 'test_self');
--> Ok
insert into test_self select 1;
--> Err
/*
[08001] ERROR: could not connect to server "loopback"
Detail: connection to server on socket "/tmp/.s.PGSQL.54321" failed:
FATAL: sorry, too many clients already
Where: remote SQL command: INSERT INTO public.test_self(id) VALUES ($1)
remote SQL command: INSERT INTO public.test_self(id) VALUES ($1)
remote SQL command: INSERT INTO public.test_self(id) VALUES ( ...
*/
```
The proposed patch fixes this error.
```sql
create foreign table test_self (id int)
server loopback options (table_name 'test_self');
--> Err
/*
[42P16] ERROR: foreign table "test_self" cannot reference itself
Hint: Foreign table pointing to the same table on the same database
creates circular reference
*/
```
John.
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index c4852be2eb2..5b48932d3f6 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -1545,6 +1545,42 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)
fdw = GetForeignDataWrapper(server->fdwid);
+ if (stmt->options != NIL) {
+ char *table_name = NULL;
+ ListCell *lc;
+
+ foreach(lc, stmt->options) {
+ DefElem *def = (DefElem *) lfirst(lc);
+ if (strcmp(def->defname, "table_name") == 0) {
+ table_name = defGetString(def);
+ break;
+ }
+ }
+
+ if (table_name && strcmp(stmt->base.relation->relname, table_name) == 0) {
+ /* Check if the server is pointing to the same database */
+ char *server_dbname = NULL;
+
+ foreach(lc, server->options) {
+ DefElem *def = (DefElem *) lfirst(lc);
+ if (strcmp(def->defname, "dbname") == 0) {
+ server_dbname = defGetString(def);
+ break;
+ }
+ }
+
+ if (server_dbname == NULL ||
+ strcmp(server_dbname, get_database_name(MyDatabaseId)) == 0) {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("foreign table \"%s\" cannot reference itself",
+ stmt->base.relation->relname),
+ errhint("Foreign table pointing to the same table on the same database "
+ "creates circular reference")));
+ }
+ }
+ }
+
/*
* Insert tuple into pg_foreign_table.
*/