diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index aada47565e..4ecca8eff8 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