diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 0f20f38c..34a1d58a 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -5954,7 +5954,22 @@ build_remattrmap(Relation relation, List *va_cols, if (attrcnt > 0) appendStringInfoString(column_list, ", "); - appendStringInfoString(column_list, quote_identifier(remote_attname)); + + /* + * Use array-element quoting, not SQL identifier quoting. The + * column_list is interpolated into a text[] array literal, where + * backslash is an escape character. quote_identifier() does not + * escape backslashes, so column names containing them would be + * silently mangled by the array parser (e.g. "a\b" → "ab"). + */ + appendStringInfoChar(column_list, '"'); + for (const char *p = remote_attname; *p; p++) + { + if (*p == '"' || *p == '\\') + appendStringInfoChar(column_list, '\\'); + appendStringInfoChar(column_list, *p); + } + appendStringInfoChar(column_list, '"'); remattrmap[attrcnt].local_attnum = attnum; strncpy(remattrmap[attrcnt].local_attname, attname, NAMEDATALEN);