When the remote query result has a different number of columns
authorJoe Conway <mail@joeconway.com>
Tue, 3 Jan 2006 23:48:04 +0000 (23:48 +0000)
committerJoe Conway <mail@joeconway.com>
Tue, 3 Jan 2006 23:48:04 +0000 (23:48 +0000)
than the local query specifies (e.g. in the FROM clause),
throw an ERROR (instead of crashing). Fix for bug #2129 reported
by Akio Iwaasa.

contrib/dblink/dblink.c
contrib/dblink/doc/cursor

index 3fea501b60cf75d6f6f34ecefee6206cf4e13597..dbaebc8855234763f6e93011f13cf21dc0ef7fce 100644 (file)
@@ -446,10 +446,6 @@ dblink_fetch(PG_FUNCTION_ARGS)
                /* got results, keep track of them */
                funcctx->user_fctx = res;
 
-               /* fast track when no results */
-               if (funcctx->max_calls < 1)
-                       SRF_RETURN_DONE(funcctx);
-
                /* check typtype to see if we have a predetermined return type */
                functypeid = get_func_rettype(funcid);
                functyptype = get_typtype(functypeid);
@@ -474,6 +470,22 @@ dblink_fetch(PG_FUNCTION_ARGS)
                /* store needed metadata for subsequent calls */
                slot = TupleDescGetSlot(tupdesc);
                funcctx->slot = slot;
+
+               /* check result and tuple descriptor have the same number of columns */
+               if (PQnfields(res) != tupdesc->natts)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                               errmsg("remote query result rowtype does not match "
+                                               "the specified FROM clause rowtype")));
+
+               /* fast track when no results */
+               if (funcctx->max_calls < 1)
+               {
+                       if (res)
+                               PQclear(res);
+                       SRF_RETURN_DONE(funcctx);
+               }
+
                attinmeta = TupleDescGetAttInMetadata(tupdesc);
                funcctx->attinmeta = attinmeta;
 
@@ -617,10 +629,6 @@ dblink_record(PG_FUNCTION_ARGS)
                if (freeconn && PG_NARGS() == 2)
                        PQfinish(conn);
 
-               /* fast track when no results */
-               if (funcctx->max_calls < 1)
-                       SRF_RETURN_DONE(funcctx);
-
                /* check typtype to see if we have a predetermined return type */
                functypeid = get_func_rettype(funcid);
                functyptype = get_typtype(functypeid);
@@ -648,6 +656,22 @@ dblink_record(PG_FUNCTION_ARGS)
                /* store needed metadata for subsequent calls */
                slot = TupleDescGetSlot(tupdesc);
                funcctx->slot = slot;
+
+               /* check result and tuple descriptor have the same number of columns */
+               if (PQnfields(res) != tupdesc->natts)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                               errmsg("remote query result rowtype does not match "
+                                               "the specified FROM clause rowtype")));
+
+               /* fast track when no results */
+               if (funcctx->max_calls < 1)
+               {
+                       if (res)
+                               PQclear(res);
+                       SRF_RETURN_DONE(funcctx);
+               }
+
                attinmeta = TupleDescGetAttInMetadata(tupdesc);
                funcctx->attinmeta = attinmeta;
 
index 7c9cc3cde25554b1bd0c7438a2d8ec5961475225..bf591a4d6e5159ed443f2833fe2ccdd84b2964e3 100644 (file)
@@ -79,6 +79,13 @@ Outputs
 
   Returns setof record
 
+Note
+
+  On a mismatch between the number of return fields as specified in the FROM
+  clause, and the actual number of fields returned by the remote cursor, an
+  ERROR will be thrown. In this event, the remote cursor is still advanced
+  by as many rows as it would have been if the ERROR had not occurred.
+
 Example usage
 
 test=# select dblink_connect('dbname=template1');