--- dblink.c-741 2003-11-28 05:03:48.000000000 +0000 +++ dblink.c 2004-02-10 16:31:11.305534520 +0000 @@ -82,7 +82,7 @@ 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 TupleDesc pgresultGetTupleDesc(PGresult *res, const bool use_oid_map); static char *generate_relation_name(Oid relid); /* Global */ @@ -457,7 +457,7 @@ if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); else if (functyptype == 'p' && functypeid == RECORDOID) - tupdesc = pgresultGetTupleDesc(res); + tupdesc = pgresultGetTupleDesc(res, true); else /* shouldn't happen */ elog(ERROR, "return type must be a row type"); @@ -550,6 +550,7 @@ char *sql = NULL; char *conname = NULL; remoteConn *rcon = NULL; + bool use_oid_map = true; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); @@ -559,20 +560,25 @@ * calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - if (PG_NARGS() == 2) - { + + switch (PG_NARGS()) { + case 3: + if (!PG_ARGISNULL(2)) + use_oid_map = PG_GETARG_BOOL(2); + case 2: DBLINK_GET_CONN; sql = GET_STR(PG_GETARG_TEXT_P(1)); - } - else if (PG_NARGS() == 1) - { + break; + + case 1: conn = persistent_conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); - } - else + break; + + default: /* shouldn't happen */ elog(ERROR, "wrong number of arguments"); + } if (!conn) DBLINK_CONN_NOT_AVAIL; @@ -620,7 +626,7 @@ if (functyptype == 'c') tupdesc = TypeGetTupleDesc(functypeid, NIL); else if (functyptype == 'p' && functypeid == RECORDOID) - tupdesc = pgresultGetTupleDesc(res); + tupdesc = pgresultGetTupleDesc(res, use_oid_map); else /* shouldn't happen */ elog(ERROR, "return type must be a row type"); @@ -1802,7 +1808,7 @@ } static TupleDesc -pgresultGetTupleDesc(PGresult *res) +pgresultGetTupleDesc(PGresult *res, const bool use_oid_map) { int natts; AttrNumber attnum; @@ -1813,6 +1819,14 @@ bool attisset; Oid atttypid; int i; + + void *plan = NULL; + Oid arg[2] = {NAMEOID,OIDOID}; + int ret = 0; + Datum values[2]; + Datum local_oid; + char *typname; + bool isnull; /* * allocate a new tuple descriptor @@ -1824,6 +1838,28 @@ desc = CreateTemplateTupleDesc(natts, false); + if (use_oid_map) { + /* + * Connect to SPI manager + */ + if ((ret = SPI_connect()) < 0) + /* internal error */ + elog(ERROR, "SPI_connect failure - returned %d", ret); + + /* + * Create query plan for mapping remote oid to local oid + */ + plan = SPI_prepare("SELECT local_oid, typname FROM dblink_oid_map WHERE db_id = $1 AND remote_oid = $2", 2, arg); + if (plan == NULL) + /* internal error */ + elog(ERROR, "SPI_prepare returned %d", SPI_result); + + /* + * TODO: Determine unique id of remote database (instead of "test") + */ + values[0] = PointerGetDatum("test"); + } + attnum = 0; for (i = 0; i < natts; i++) @@ -1839,6 +1875,33 @@ atttypid = PQftype(res, i); atttypmod = PQfmod(res, i); + if (use_oid_map) { + values[1] = ObjectIdGetDatum(atttypid); + + if ((ret = SPI_execp(plan, values, NULL, 1)) < 0) + elog(ERROR, "SPI_execp returned %d", ret); + + if (SPI_processed < 1) + ereport(ERROR, + (errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH), + errmsg("unknown remote datatype"), + errdetail("Remote datatype oid \"%d\" is not in oid map", + atttypid))); + + local_oid = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull); + + if (isnull) { + typname = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2); + ereport(ERROR, + (errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH), + errmsg("unknown local datatype"), + errdetail("Remote datatype \"%s\" is not mapped " \ + "to a local datatype", (char *) DatumGetPointer(typname)))); + } + + atttypid = DatumGetObjectId(local_oid); + } + if (PQfsize(res, i) != get_typlen(atttypid)) ereport(ERROR, (errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH), @@ -1855,6 +1918,10 @@ atttypmod, attdim, attisset); } + if (use_oid_map) { + SPI_finish(); + } + return desc; }