v1-0001-postgres_fdw-Use-foreign-table-owner-s-user-mappi.patch
application/octet-stream
Filename: v1-0001-postgres_fdw-Use-foreign-table-owner-s-user-mappi.patch
Type: application/octet-stream
Part: 0
From a1702c4d496fcda9419c9963acc0e9ed9d8de1c7 Mon Sep 17 00:00:00 2001
From: Fujii Masao <fujii@postgresql.org>
Date: Thu, 14 May 2026 22:25:02 +0900
Subject: [PATCH v1] postgres_fdw: Use foreign table owner's user mapping for
restore_stats
Previously, ANALYZE on a foreign table used different user mappings
depending on the restore_stats option. When restore_stats was disabled,
it used the foreign table owner's user mapping to sample remote data.
But when restore_stats was enabled, it instead used the user mapping of
the role running ANALYZE to fetch remote statistics.
As a result, ANALYZE could fail with "user mapping not found" for users
allowed to analyze the foreign table but lacking their own user mapping,
even if the table owner had a valid mapping. Also using different
mappings depending on restore_stats was confusing and inconsistent.
This commit fixes the issue by making ANALYZE always use the foreign
table owner's user mapping, regardless of the restore_stats setting.
Also this commit adds a regression test covering both restore_stats
enabled and disabled cases.
---
contrib/postgres_fdw/expected/postgres_fdw.out | 11 +++++++++++
contrib/postgres_fdw/postgres_fdw.c | 6 +++---
contrib/postgres_fdw/sql/postgres_fdw.sql | 12 ++++++++++++
3 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index e90289e4ab1..e195003eae0 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -12917,6 +12917,16 @@ CREATE FOREIGN TABLE simport_fview (c1 int, c2 text)
ALTER FOREIGN TABLE simport_fview OPTIONS (ADD restore_stats 'true');
ANALYZE simport_fview; -- should fail
WARNING: could not import statistics for foreign table "public.simport_fview" --- remote table "public.simport_view" is of relkind "v" which cannot have statistics
+-- Ensure ANALYZE uses the table owner's user mapping
+CREATE ROLE regress_simport_maintain NOSUPERUSER;
+GRANT MAINTAIN ON TABLE simport_ftable TO regress_simport_maintain;
+SET ROLE regress_simport_maintain;
+ANALYZE simport_ftable; -- should work
+RESET ROLE;
+ALTER FOREIGN TABLE simport_ftable OPTIONS (SET restore_stats 'false');
+SET ROLE regress_simport_maintain;
+ANALYZE simport_ftable; -- should work
+RESET ROLE;
-- This tests build_remattrmap()'s deparsing of column names that include
-- single quotes or backslashes
CREATE TABLE dtest_table ("col'quote" int, "col\backslash" int);
@@ -12932,6 +12942,7 @@ DROP FOREIGN TABLE simport_ftable;
DROP FOREIGN TABLE simport_fview;
DROP VIEW simport_view;
DROP TABLE simport_table;
+DROP ROLE regress_simport_maintain;
DROP FOREIGN TABLE dtest_ftable;
DROP TABLE dtest_table;
-- ===================================================================
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 85be46eb2a2..4e50ecbfba5 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -5720,10 +5720,10 @@ fetch_remote_statistics(Relation relation,
}
/*
- * Get connection to the foreign server. Connection manager will
- * establish new connection if necessary.
+ * Get the connection to use. We do the remote access as the table's
+ * owner, even if the ANALYZE was started by some other user.
*/
- user = GetUserMapping(GetUserId(), table->serverid);
+ user = GetUserMapping(relation->rd_rel->relowner, table->serverid);
conn = GetConnection(user, false, NULL);
remstats->server_version_num = server_version_num = PQserverVersion(conn);
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index dfc58beb0d2..80fbfe9892d 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -4573,6 +4573,17 @@ ALTER FOREIGN TABLE simport_fview OPTIONS (ADD restore_stats 'true');
ANALYZE simport_fview; -- should fail
+-- Ensure ANALYZE uses the table owner's user mapping
+CREATE ROLE regress_simport_maintain NOSUPERUSER;
+GRANT MAINTAIN ON TABLE simport_ftable TO regress_simport_maintain;
+SET ROLE regress_simport_maintain;
+ANALYZE simport_ftable; -- should work
+RESET ROLE;
+ALTER FOREIGN TABLE simport_ftable OPTIONS (SET restore_stats 'false');
+SET ROLE regress_simport_maintain;
+ANALYZE simport_ftable; -- should work
+RESET ROLE;
+
-- This tests build_remattrmap()'s deparsing of column names that include
-- single quotes or backslashes
CREATE TABLE dtest_table ("col'quote" int, "col\backslash" int);
@@ -4589,6 +4600,7 @@ DROP FOREIGN TABLE simport_ftable;
DROP FOREIGN TABLE simport_fview;
DROP VIEW simport_view;
DROP TABLE simport_table;
+DROP ROLE regress_simport_maintain;
DROP FOREIGN TABLE dtest_ftable;
DROP TABLE dtest_table;
--
2.53.0