diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index bba0d2adc3c2fd15e94882cd349efd3abf8a00cc..e8ad94ba841532ca20bd441167e0b2d7df973ade 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -53,6 +53,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
@@ -86,7 +87,8 @@ typedef struct storeInfo
  */
 static Datum dblink_record_internal(FunctionCallInfo fcinfo, bool is_async);
 static void prepTuplestoreResult(FunctionCallInfo fcinfo);
-static void materializeResult(FunctionCallInfo fcinfo, PGresult *res);
+static void materializeResult(FunctionCallInfo fcinfo, PGconn *conn,
+				  PGresult *res);
 static void materializeQueryResult(FunctionCallInfo fcinfo,
 					   PGconn *conn,
 					   const char *conname,
@@ -118,6 +120,8 @@ static void validate_pkattnums(Relation rel,
 				   int **pkattnums, int *pknumatts);
 static bool is_valid_dblink_option(const PQconninfoOption *options,
 					   const char *option, Oid context);
+static int	applyRemoteGucs(PGconn *conn);
+static void restoreLocalGucs(int nestlevel);
 
 /* Global */
 static remoteConn *pconn = NULL;
@@ -605,7 +609,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
 				 errmsg("cursor \"%s\" does not exist", curname)));
 	}
 
-	materializeResult(fcinfo, res);
+	materializeResult(fcinfo, conn, res);
 	return (Datum) 0;
 }
 
@@ -750,7 +754,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
 				}
 				else
 				{
-					materializeResult(fcinfo, res);
+					materializeResult(fcinfo, conn, res);
 				}
 			}
 		}
@@ -806,7 +810,7 @@ prepTuplestoreResult(FunctionCallInfo fcinfo)
  * The PGresult will be released in this function.
  */
 static void
-materializeResult(FunctionCallInfo fcinfo, PGresult *res)
+materializeResult(FunctionCallInfo fcinfo, PGconn *conn, PGresult *res)
 {
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 
@@ -816,7 +820,7 @@ materializeResult(FunctionCallInfo fcinfo, PGresult *res)
 	PG_TRY();
 	{
 		TupleDesc	tupdesc;
-		bool		is_sql_cmd = false;
+		bool		is_sql_cmd;
 		int			ntuples;
 		int			nfields;
 
@@ -877,6 +881,7 @@ materializeResult(FunctionCallInfo fcinfo, PGresult *res)
 		if (ntuples > 0)
 		{
 			AttInMetadata *attinmeta;
+			int			nestlevel = -1;
 			Tuplestorestate *tupstore;
 			MemoryContext oldcontext;
 			int			row;
@@ -884,6 +889,10 @@ materializeResult(FunctionCallInfo fcinfo, PGresult *res)
 
 			attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
+			/* Set GUCs to ensure we read GUC-sensitive data types correctly */
+			if (!is_sql_cmd)
+				nestlevel = applyRemoteGucs(conn);
+
 			oldcontext = MemoryContextSwitchTo(
 									rsinfo->econtext->ecxt_per_query_memory);
 			tupstore = tuplestore_begin_heap(true, false, work_mem);
@@ -920,6 +929,9 @@ materializeResult(FunctionCallInfo fcinfo, PGresult *res)
 				tuplestore_puttuple(tupstore, tuple);
 			}
 
+			/* clean up GUC settings, if we changed any */
+			restoreLocalGucs(nestlevel);
+
 			/* clean up and return the tuplestore */
 			tuplestore_donestoring(tupstore);
 		}
@@ -1053,6 +1065,7 @@ static PGresult *
 storeQueryResult(storeInfo *sinfo, PGconn *conn, const char *sql)
 {
 	bool		first = true;
+	int			nestlevel = -1;
 	PGresult   *res;
 
 	if (!PQsendQuery(conn, sql))
@@ -1072,6 +1085,15 @@ storeQueryResult(storeInfo *sinfo, PGconn *conn, const char *sql)
 		if (PQresultStatus(sinfo->cur_res) == PGRES_SINGLE_TUPLE)
 		{
 			/* got one row from possibly-bigger resultset */
+
+			/*
+			 * Set GUCs to ensure we read GUC-sensitive data types correctly.
+			 * We shouldn't do this until we have a row in hand, to ensure
+			 * libpq has seen any earlier ParameterStatus protocol messages.
+			 */
+			if (first && nestlevel < 0)
+				nestlevel = applyRemoteGucs(conn);
+
 			storeRow(sinfo, sinfo->cur_res, first);
 
 			PQclear(sinfo->cur_res);
@@ -1092,6 +1114,9 @@ storeQueryResult(storeInfo *sinfo, PGconn *conn, const char *sql)
 		}
 	}
 
+	/* clean up GUC settings, if we changed any */
+	restoreLocalGucs(nestlevel);
+
 	/* return last_res */
 	res = sinfo->last_res;
 	sinfo->last_res = NULL;
@@ -2898,3 +2923,73 @@ is_valid_dblink_option(const PQconninfoOption *options, const char *option,
 
 	return true;
 }
+
+/*
+ * Copy the remote session's values of GUCs that affect datatype I/O
+ * and apply them locally in a new GUC nesting level.  Returns the new
+ * nestlevel (which is needed by restoreLocalGucs to undo the settings),
+ * or -1 if no new nestlevel was needed.
+ *
+ * We use the equivalent of a function SET option to allow the settings to
+ * persist only until the caller calls restoreLocalGucs.  If an error is
+ * thrown in between, guc.c will take care of undoing the settings.
+ */
+static int
+applyRemoteGucs(PGconn *conn)
+{
+	static const char *const GUCsAffectingIO[] = {
+		"DateStyle",
+		"IntervalStyle"
+	};
+
+	int			nestlevel = -1;
+	int			i;
+
+	for (i = 0; i < lengthof(GUCsAffectingIO); i++)
+	{
+		const char *gucName = GUCsAffectingIO[i];
+		const char *remoteVal = PQparameterStatus(conn, gucName);
+		const char *localVal;
+
+		/*
+		 * If the remote server is pre-8.4, it won't have IntervalStyle, but
+		 * that's okay because its output format won't be ambiguous.  So just
+		 * skip the GUC if we don't get a value for it.  (We might eventually
+		 * need more complicated logic with remote-version checks here.)
+		 */
+		if (remoteVal == NULL)
+			continue;
+
+		/*
+		 * Avoid GUC-setting overhead if the remote and local GUCs already
+		 * have the same value.
+		 */
+		localVal = GetConfigOption(gucName, false, false);
+		Assert(localVal != NULL);
+
+		if (strcmp(remoteVal, localVal) == 0)
+			continue;
+
+		/* Create new GUC nest level if we didn't already */
+		if (nestlevel < 0)
+			nestlevel = NewGUCNestLevel();
+
+		/* Apply the option (this will throw error on failure) */
+		(void) set_config_option(gucName, remoteVal,
+								 PGC_USERSET, PGC_S_SESSION,
+								 GUC_ACTION_SAVE, true, 0);
+	}
+
+	return nestlevel;
+}
+
+/*
+ * Restore local GUCs after they have been overlaid with remote settings.
+ */
+static void
+restoreLocalGucs(int nestlevel)
+{
+	/* Do nothing if no new nestlevel was created */
+	if (nestlevel > 0)
+		AtEOXact_GUC(true, nestlevel);
+}
diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out
index 78b4a99606a96145dc6112c2746d1429bb094f1e..f237c43d3d42121956f144b449202929cc1fb097 100644
--- a/contrib/dblink/expected/dblink.out
+++ b/contrib/dblink/expected/dblink.out
@@ -913,3 +913,179 @@ SELECT dblink_build_sql_delete('test_dropped', '1', 1,
  DELETE FROM test_dropped WHERE id = '2'
 (1 row)
 
+-- test local mimicry of remote GUC values that affect datatype I/O
+SET datestyle = ISO, MDY;
+SET intervalstyle = postgres;
+SET timezone = UTC;
+SELECT dblink_connect('myconn','dbname=contrib_regression');
+ dblink_connect 
+----------------
+ OK
+(1 row)
+
+SELECT dblink_exec('myconn', 'SET datestyle = GERMAN, DMY;');
+ dblink_exec 
+-------------
+ SET
+(1 row)
+
+-- single row synchronous case
+SELECT *
+FROM dblink('myconn',
+    'SELECT * FROM (VALUES (''12.03.2013 00:00:00+00'')) t')
+  AS t(a timestamptz);
+           a            
+------------------------
+ 2013-03-12 00:00:00+00
+(1 row)
+
+-- multi-row synchronous case
+SELECT *
+FROM dblink('myconn',
+    'SELECT * FROM
+     (VALUES (''12.03.2013 00:00:00+00''),
+             (''12.03.2013 00:00:00+00'')) t')
+  AS t(a timestamptz);
+           a            
+------------------------
+ 2013-03-12 00:00:00+00
+ 2013-03-12 00:00:00+00
+(2 rows)
+
+-- single-row asynchronous case
+SELECT *
+FROM dblink_send_query('myconn',
+    'SELECT * FROM
+     (VALUES (''12.03.2013 00:00:00+00'')) t');
+ dblink_send_query 
+-------------------
+                 1
+(1 row)
+
+CREATE TEMPORARY TABLE result AS
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz))
+UNION ALL
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz));
+SELECT * FROM result;
+           t            
+------------------------
+ 2013-03-12 00:00:00+00
+(1 row)
+
+DROP TABLE result;
+-- multi-row asynchronous case
+SELECT *
+FROM dblink_send_query('myconn',
+    'SELECT * FROM
+     (VALUES (''12.03.2013 00:00:00+00''),
+             (''12.03.2013 00:00:00+00'')) t');
+ dblink_send_query 
+-------------------
+                 1
+(1 row)
+
+CREATE TEMPORARY TABLE result AS
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz))
+UNION ALL
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz))
+UNION ALL
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz));
+SELECT * FROM result;
+           t            
+------------------------
+ 2013-03-12 00:00:00+00
+ 2013-03-12 00:00:00+00
+(2 rows)
+
+DROP TABLE result;
+-- Try an ambiguous interval
+SELECT dblink_exec('myconn', 'SET intervalstyle = sql_standard;');
+ dblink_exec 
+-------------
+ SET
+(1 row)
+
+SELECT *
+FROM dblink('myconn',
+    'SELECT * FROM (VALUES (''-1 2:03:04'')) i')
+  AS i(i interval);
+         i         
+-------------------
+ -1 days -02:03:04
+(1 row)
+
+-- Try swapping to another format to ensure the GUCs are tracked
+-- properly through a change.
+CREATE TEMPORARY TABLE result (t timestamptz);
+SELECT dblink_exec('myconn', 'SET datestyle = ISO, MDY;');
+ dblink_exec 
+-------------
+ SET
+(1 row)
+
+INSERT INTO result
+  SELECT *
+  FROM dblink('myconn',
+              'SELECT * FROM (VALUES (''03.12.2013 00:00:00+00'')) t')
+    AS t(a timestamptz);
+SELECT dblink_exec('myconn', 'SET datestyle = GERMAN, DMY;');
+ dblink_exec 
+-------------
+ SET
+(1 row)
+
+INSERT INTO result
+  SELECT *
+  FROM dblink('myconn',
+              'SELECT * FROM (VALUES (''12.03.2013 00:00:00+00'')) t')
+    AS t(a timestamptz);
+SELECT * FROM result;
+           t            
+------------------------
+ 2013-03-12 00:00:00+00
+ 2013-03-12 00:00:00+00
+(2 rows)
+
+DROP TABLE result;
+-- Check error throwing in dblink_fetch
+SELECT dblink_open('myconn','error_cursor',
+       'SELECT * FROM (VALUES (''1''), (''not an int'')) AS t(text);');
+ dblink_open 
+-------------
+ OK
+(1 row)
+
+SELECT *
+FROM dblink_fetch('myconn','error_cursor', 1) AS t(i int);
+ i 
+---
+ 1
+(1 row)
+
+SELECT *
+FROM dblink_fetch('myconn','error_cursor', 1) AS t(i int);
+ERROR:  invalid input syntax for integer: "not an int"
+-- Make sure that the local settings have retained their values in spite
+-- of shenanigans on the connection.
+SHOW datestyle;
+ DateStyle 
+-----------
+ ISO, MDY
+(1 row)
+
+SHOW intervalstyle;
+ IntervalStyle 
+---------------
+ postgres
+(1 row)
+
+-- Clean up GUC-setting tests
+SELECT dblink_disconnect('myconn');
+ dblink_disconnect 
+-------------------
+ OK
+(1 row)
+
+RESET datestyle;
+RESET intervalstyle;
+RESET timezone;
diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql
index 4f72ccf1d8e37271e29985bb57e2a6c50365ba15..2a107601c5565a75153fe47ebd4f05c1c93d7bfa 100644
--- a/contrib/dblink/sql/dblink.sql
+++ b/contrib/dblink/sql/dblink.sql
@@ -426,3 +426,99 @@ SELECT dblink_build_sql_update('test_dropped', '1', 1,
 
 SELECT dblink_build_sql_delete('test_dropped', '1', 1,
                                ARRAY['2'::TEXT]);
+
+-- test local mimicry of remote GUC values that affect datatype I/O
+SET datestyle = ISO, MDY;
+SET intervalstyle = postgres;
+SET timezone = UTC;
+SELECT dblink_connect('myconn','dbname=contrib_regression');
+SELECT dblink_exec('myconn', 'SET datestyle = GERMAN, DMY;');
+
+-- single row synchronous case
+SELECT *
+FROM dblink('myconn',
+    'SELECT * FROM (VALUES (''12.03.2013 00:00:00+00'')) t')
+  AS t(a timestamptz);
+
+-- multi-row synchronous case
+SELECT *
+FROM dblink('myconn',
+    'SELECT * FROM
+     (VALUES (''12.03.2013 00:00:00+00''),
+             (''12.03.2013 00:00:00+00'')) t')
+  AS t(a timestamptz);
+
+-- single-row asynchronous case
+SELECT *
+FROM dblink_send_query('myconn',
+    'SELECT * FROM
+     (VALUES (''12.03.2013 00:00:00+00'')) t');
+CREATE TEMPORARY TABLE result AS
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz))
+UNION ALL
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz));
+SELECT * FROM result;
+DROP TABLE result;
+
+-- multi-row asynchronous case
+SELECT *
+FROM dblink_send_query('myconn',
+    'SELECT * FROM
+     (VALUES (''12.03.2013 00:00:00+00''),
+             (''12.03.2013 00:00:00+00'')) t');
+CREATE TEMPORARY TABLE result AS
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz))
+UNION ALL
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz))
+UNION ALL
+(SELECT * from dblink_get_result('myconn') as t(t timestamptz));
+SELECT * FROM result;
+DROP TABLE result;
+
+-- Try an ambiguous interval
+SELECT dblink_exec('myconn', 'SET intervalstyle = sql_standard;');
+SELECT *
+FROM dblink('myconn',
+    'SELECT * FROM (VALUES (''-1 2:03:04'')) i')
+  AS i(i interval);
+
+-- Try swapping to another format to ensure the GUCs are tracked
+-- properly through a change.
+CREATE TEMPORARY TABLE result (t timestamptz);
+
+SELECT dblink_exec('myconn', 'SET datestyle = ISO, MDY;');
+INSERT INTO result
+  SELECT *
+  FROM dblink('myconn',
+              'SELECT * FROM (VALUES (''03.12.2013 00:00:00+00'')) t')
+    AS t(a timestamptz);
+
+SELECT dblink_exec('myconn', 'SET datestyle = GERMAN, DMY;');
+INSERT INTO result
+  SELECT *
+  FROM dblink('myconn',
+              'SELECT * FROM (VALUES (''12.03.2013 00:00:00+00'')) t')
+    AS t(a timestamptz);
+
+SELECT * FROM result;
+
+DROP TABLE result;
+
+-- Check error throwing in dblink_fetch
+SELECT dblink_open('myconn','error_cursor',
+       'SELECT * FROM (VALUES (''1''), (''not an int'')) AS t(text);');
+SELECT *
+FROM dblink_fetch('myconn','error_cursor', 1) AS t(i int);
+SELECT *
+FROM dblink_fetch('myconn','error_cursor', 1) AS t(i int);
+
+-- Make sure that the local settings have retained their values in spite
+-- of shenanigans on the connection.
+SHOW datestyle;
+SHOW intervalstyle;
+
+-- Clean up GUC-setting tests
+SELECT dblink_disconnect('myconn');
+RESET datestyle;
+RESET intervalstyle;
+RESET timezone;