Index: contrib/dblink/dblink.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/contrib/dblink/dblink.c,v retrieving revision 1.29 diff -c -r1.29 dblink.c *** contrib/dblink/dblink.c 28 Nov 2003 05:03:01 -0000 1.29 --- contrib/dblink/dblink.c 13 Feb 2004 18:23:49 -0000 *************** *** 82,88 **** 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 */ --- 82,87 ---- *************** *** 395,400 **** --- 394,400 ---- StringInfo str = makeStringInfo(); char *curname = NULL; int howmany = 0; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; if (PG_NARGS() == 3) { *************** *** 457,463 **** if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); else if (functyptype == 'p' && functypeid == RECORDOID) ! tupdesc = pgresultGetTupleDesc(res); else /* shouldn't happen */ elog(ERROR, "return type must be a row type"); --- 457,472 ---- if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); else if (functyptype == 'p' && functypeid == RECORDOID) ! { ! if (!rsinfo) ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("returning setof record is not " \ ! "allowed in this context"))); ! ! /* get the requested return tuple description */ ! tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); ! } else /* shouldn't happen */ elog(ERROR, "return type must be a row type"); *************** *** 550,555 **** --- 559,565 ---- 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,626 **** if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); else if (functyptype == 'p' && functypeid == RECORDOID) ! tupdesc = pgresultGetTupleDesc(res); else /* shouldn't happen */ elog(ERROR, "return type must be a row type"); --- 630,645 ---- if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); else if (functyptype == 'p' && functypeid == RECORDOID) ! { ! if (!rsinfo) ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("returning setof record is not " \ ! "allowed in this context"))); ! ! /* get the requested return tuple description */ ! tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); ! } else /* shouldn't happen */ elog(ERROR, "return type must be a row type"); *************** *** 1801,1863 **** relation_close(rel, AccessShareLock); 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; } /* --- 1820,1825 ----