diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index aada47565e2a08572d4edc9bbc5c43e61f6c16bc..4ecca8eff8be1fc418370a8cd2edea45bb228896 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -82,7 +82,6 @@ static char *quote_ident_cstr(char *rawstr);
 static int16 get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key);
 static HeapTuple get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals);
 static Oid	get_relid_from_relname(text *relname_text);
-static TupleDesc pgresultGetTupleDesc(PGresult *res);
 static char *generate_relation_name(Oid relid);
 
 /* Global */
@@ -395,6 +394,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
 		StringInfo	str = makeStringInfo();
 		char	   *curname = NULL;
 		int			howmany = 0;
+		ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 
 		if (PG_NARGS() == 3)
 		{
@@ -457,7 +457,16 @@ dblink_fetch(PG_FUNCTION_ARGS)
 		if (functyptype == 'c')
 			tupdesc = TypeGetTupleDesc(functypeid, NIL);
 		else if (functyptype == 'p' && functypeid == RECORDOID)
-			tupdesc = pgresultGetTupleDesc(res);
+		{
+			if (!rsinfo || !IsA(rsinfo, ReturnSetInfo))
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("function returning record called in context "
+								"that cannot accept type record")));
+
+			/* get the requested return tuple description */
+			tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+		}
 		else
 			/* shouldn't happen */
 			elog(ERROR, "return type must be a row type");
@@ -550,6 +559,7 @@ dblink_record(PG_FUNCTION_ARGS)
 		char	   *sql = NULL;
 		char	   *conname = NULL;
 		remoteConn *rcon = NULL;
+		ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 
 		/* create a function context for cross-call persistence */
 		funcctx = SRF_FIRSTCALL_INIT();
@@ -620,7 +630,16 @@ dblink_record(PG_FUNCTION_ARGS)
 			if (functyptype == 'c')
 				tupdesc = TypeGetTupleDesc(functypeid, NIL);
 			else if (functyptype == 'p' && functypeid == RECORDOID)
-				tupdesc = pgresultGetTupleDesc(res);
+			{
+				if (!rsinfo || !IsA(rsinfo, ReturnSetInfo))
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("function returning record called in context "
+									"that cannot accept type record")));
+
+				/* get the requested return tuple description */
+				tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+			}
 			else
 				/* shouldn't happen */
 				elog(ERROR, "return type must be a row type");
@@ -1803,63 +1822,6 @@ get_relid_from_relname(text *relname_text)
 	return relid;
 }
 
-static TupleDesc
-pgresultGetTupleDesc(PGresult *res)
-{
-	int			natts;
-	AttrNumber	attnum;
-	TupleDesc	desc;
-	char	   *attname;
-	int32		atttypmod;
-	int			attdim;
-	bool		attisset;
-	Oid			atttypid;
-	int			i;
-
-	/*
-	 * allocate a new tuple descriptor
-	 */
-	natts = PQnfields(res);
-	if (natts < 1)
-		/* shouldn't happen */
-		elog(ERROR, "cannot create a description for empty results");
-
-	desc = CreateTemplateTupleDesc(natts, false);
-
-	attnum = 0;
-
-	for (i = 0; i < natts; i++)
-	{
-		/*
-		 * for each field, get the name and type information from the
-		 * query result and have TupleDescInitEntry fill in the attribute
-		 * information we need.
-		 */
-		attnum++;
-
-		attname = PQfname(res, i);
-		atttypid = PQftype(res, i);
-		atttypmod = PQfmod(res, i);
-
-		if (PQfsize(res, i) != get_typlen(atttypid))
-			ereport(ERROR,
-					(errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH),
-					 errmsg("field size mismatch"),
-				errdetail("Size of remote field \"%s\" does not match " \
-						  "size of local type \"%s\".", attname,
-						  format_type_with_typemod(atttypid,
-												   atttypmod))));
-
-		attdim = 0;
-		attisset = false;
-
-		TupleDescInitEntry(desc, attnum, attname, atttypid,
-						   atttypmod, attdim, attisset);
-	}
-
-	return desc;
-}
-
 /*
  * generate_relation_name - copied from ruleutils.c
  *		Compute the name to display for a relation specified by OID