>From 4a26e88bed0d6f6e7e51b39c6d0f9caf4dc3fbea Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Mon, 2 Feb 2015 16:05:22 +0900
Subject: [PATCH] Make fetch_size settable per foreign server and foreign table

postgres_fdw fetches tuples by the fixed fetch size, but the suitable
size varies widely by the configuration. This patch enables users to
set it as an foreign server option or an foreign table option
'fetch_size'.
---
 contrib/postgres_fdw/option.c       |  6 ++++++
 contrib/postgres_fdw/postgres_fdw.c | 37 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c
index 7547ec2..2a3ab7d 100644
--- a/contrib/postgres_fdw/option.c
+++ b/contrib/postgres_fdw/option.c
@@ -153,6 +153,12 @@ InitPgFdwOptions(void)
 		/* updatable is available on both server and table */
 		{"updatable", ForeignServerRelationId, false},
 		{"updatable", ForeignTableRelationId, false},
+		/*
+		 * fetch_size is available on both server and table, the table setting
+		 * overrides the server setting.
+		 */
+		{"fetch_size", ForeignServerRelationId, false},
+		{"fetch_size", ForeignTableRelationId, false},
 		{NULL, InvalidOid, false}
 	};
 
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index d76e739..ac5e416 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -134,6 +134,7 @@ typedef struct PgFdwScanState
 	/* extracted fdw_private data */
 	char	   *query;			/* text of SELECT command */
 	List	   *retrieved_attrs;	/* list of retrieved attribute numbers */
+	int			fetch_size;		/* number of tuples per fetch */
 
 	/* for remote query execution */
 	PGconn	   *conn;			/* connection for the scan */
@@ -871,6 +872,22 @@ postgresGetForeignPlan(PlannerInfo *root,
 							fdw_private);
 }
 
+static DefElem*
+get_option(List *options, char *optname)
+{
+	ListCell *lc;
+
+	foreach(lc, options)
+	{
+		DefElem	*def = (DefElem *) lfirst(lc);
+
+		if (strcmp(def->defname, optname) == 0)
+			return def;
+	}
+	return NULL;
+}
+
+
 /*
  * postgresBeginForeignScan
  *		Initiate an executor scan of a foreign PostgreSQL table.
@@ -889,6 +906,7 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags)
 	int			numParams;
 	int			i;
 	ListCell   *lc;
+	DefElem	   *def;
 
 	/*
 	 * Do nothing in EXPLAIN (no ANALYZE) case.  node->fdw_state stays NULL.
@@ -915,6 +933,23 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags)
 	server = GetForeignServer(table->serverid);
 	user = GetUserMapping(userid, server->serverid);
 
+	/* Reading table options */
+	fsstate->fetch_size = -1;
+
+	def = get_option(table->options, "fetch_size");
+	if (!def)
+		def = get_option(server->options, "fetch_size");
+
+	if (def)
+	{
+		fsstate->fetch_size = strtod(defGetString(def), NULL);
+		if (fsstate->fetch_size < 0)
+			elog(ERROR, "invalid fetch size for foreign table \"%s\"",
+				 get_rel_name(table->relid));
+	}
+	else
+		fsstate->fetch_size = 100;
+
 	/*
 	 * Get connection to the foreign server.  Connection manager will
 	 * establish new connection if necessary.
@@ -2031,7 +2066,7 @@ fetch_more_data(ForeignScanState *node)
 		int			i;
 
 		/* The fetch size is arbitrary, but shouldn't be enormous. */
-		fetch_size = 100;
+		fetch_size = fsstate->fetch_size;
 
 		snprintf(sql, sizeof(sql), "FETCH %d FROM c%u",
 				 fetch_size, fsstate->cursor_number);
-- 
2.1.0.GIT

