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.
 	 */

Reply via email to