Re: dblink - custom datatypes NOW work :) - Mailing list pgsql-hackers

From Joe Conway
Subject Re: dblink - custom datatypes NOW work :)
Date
Msg-id 402D09BE.2030907@joeconway.com
Whole thread Raw
In response to dblink - custom datatypes NOW work :)  (Mark Gibson <gibsonm@cromwell.co.uk>)
Responses Re: dblink - custom datatypes NOW work :)  (Mark Gibson <gibsonm@cromwell.co.uk>)
List pgsql-hackers
Mark Gibson wrote:
>    I've found the problem, although I'm still a bit confused by it.

I hate to do this to you now, but after some thought I think I have a
better approach -- I'd be interested in opinions on that assessment.

The attached eliminates pgresultGetTupleDesc() entirely and instead
depends on the TupleDesc passed as rsinfo->expectedDesc from the
executor. What this means is that the string representation of the
remote value (from the "out" function on the remote side, as provided by
libpq) will get fed into the "in" function corresponding to the local
type you assign in your SQL statement. Assuming the types on the two
sides are the same (or at least compatible), it should work well.

Please give this a try and let me know what you think.

Joe

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 ----

pgsql-hackers by date:

Previous
From: markw@osdl.org
Date:
Subject: Re: Proposed Query Planner TODO items
Next
From: Joseph Tate
Date:
Subject: pg_restore problems and suggested resolution