From b01f59bffcbfb989912d601b1fd6841347b1dd10 Mon Sep 17 00:00:00 2001
From: Rafia Sabih <rafia.sabih@cybertec.at>
Date: Fri, 19 Jun 2026 14:26:58 +0200
Subject: [PATCH 1/1] Emit debug message for batch_size reduced

    In case batch_size is reduced to keep the parameter within
    limits of libpq, emit a debug message.
    Also emit a warning message when batch_size is set to a value
    over the limit.
---
 .../postgres_fdw/expected/postgres_fdw.out    | 24 +++++++++++++++++++
 contrib/postgres_fdw/postgres_fdw.c           | 13 ++++++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     | 24 +++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index e90289e4ab1..3abd2f4b01c 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -11509,6 +11509,30 @@ DROP TRIGGER ftable_rowcount_trigger ON ltable;
 DROP TABLE ltable;
 DROP TABLE parent;
 DROP FUNCTION ftable_rowcount_trigf;
+-- Verify that DEBUG1 is emitted when batch_size is reduced to stay within
+-- the libpq 65535-parameter limit.
+SET client_min_messages = DEBUG1;
+CREATE TABLE batch_table ( x int, y int );
+CREATE FOREIGN TABLE ftable ( x int, y int )
+	SERVER loopback
+	OPTIONS (table_name 'batch_table', batch_size '33000');
+INSERT INTO ftable(x) VALUES (1);
+DEBUG:  postgres_fdw: batch_size reduced from 33000 to 32767 to stay within the libpq 65535-parameter limit
+RESET client_min_messages;
+-- Clean up
+DROP FOREIGN TABLE ftable;
+DROP TABLE batch_table;
+-- Verify that a WARNING is emitted when batch_size is set to or above the
+-- libpq 65535-parameter limit.
+CREATE TABLE batch_warn_table ( x int );
+CREATE FOREIGN TABLE ftable_warn ( x int )
+  SERVER loopback
+  OPTIONS (table_name 'batch_warn_table', batch_size '65536');
+INSERT INTO ftable_warn VALUES (1);
+WARNING:  postgres_fdw: batch_size 65536 is at or above the libpq 65535-parameter limit; the effective per-batch ceiling is limit / number_of_columns and may be lower
+-- Clean up
+DROP FOREIGN TABLE ftable_warn;
+DROP TABLE batch_warn_table;
 -- ===================================================================
 -- test asynchronous execution
 -- ===================================================================
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 6dbae583ecc..6567c60d610 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2304,7 +2304,15 @@ postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo)
 	 * don't exceed this limit by using the maximum batch_size possible.
 	 */
 	if (fmstate && fmstate->p_nums > 0)
+	{
+		int			configured = batch_size;
+
 		batch_size = Min(batch_size, PQ_QUERY_PARAM_MAX_LIMIT / fmstate->p_nums);
+		if (batch_size < configured)
+			elog(DEBUG1, "postgres_fdw: batch_size reduced from %d to %d "
+				 "to stay within the libpq %d-parameter limit",
+				 configured, batch_size, PQ_QUERY_PARAM_MAX_LIMIT);
+	}
 
 	return batch_size;
 }
@@ -8829,6 +8837,11 @@ get_batch_size_option(Relation rel)
 		if (strcmp(def->defname, "batch_size") == 0)
 		{
 			(void) parse_int(defGetString(def), &batch_size, 0, NULL);
+			if (batch_size > PQ_QUERY_PARAM_MAX_LIMIT)
+				elog(WARNING, "postgres_fdw: batch_size %d is at or above the libpq "
+					 "%d-parameter limit; the effective per-batch ceiling is "
+					 "limit / number_of_columns and may be lower",
+					 batch_size, PQ_QUERY_PARAM_MAX_LIMIT);
 			break;
 		}
 	}
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index dfc58beb0d2..9d05fab7c1c 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3934,6 +3934,30 @@ DROP TABLE ltable;
 DROP TABLE parent;
 DROP FUNCTION ftable_rowcount_trigf;
 
+-- Verify that DEBUG1 is emitted when batch_size is reduced to stay within
+-- the libpq 65535-parameter limit.
+SET client_min_messages = DEBUG1;
+CREATE TABLE batch_table ( x int, y int );
+CREATE FOREIGN TABLE ftable ( x int, y int )
+	SERVER loopback
+	OPTIONS (table_name 'batch_table', batch_size '33000');
+INSERT INTO ftable(x) VALUES (1);
+RESET client_min_messages;
+-- Clean up
+DROP FOREIGN TABLE ftable;
+DROP TABLE batch_table;
+
+-- Verify that a WARNING is emitted when batch_size is set to or above the
+-- libpq 65535-parameter limit.
+CREATE TABLE batch_warn_table ( x int );
+CREATE FOREIGN TABLE ftable_warn ( x int )
+  SERVER loopback
+  OPTIONS (table_name 'batch_warn_table', batch_size '65536');
+INSERT INTO ftable_warn VALUES (1);
+-- Clean up
+DROP FOREIGN TABLE ftable_warn;
+DROP TABLE batch_warn_table;
+
 -- ===================================================================
 -- test asynchronous execution
 -- ===================================================================
-- 
2.39.5 (Apple Git-154)

