Fix dblink and tablefunc to not return with the wrong CurrentMemoryContext.
authorTom Lane <[email protected]>
Sun, 30 Nov 2008 23:24:08 +0000 (23:24 +0000)
committerTom Lane <[email protected]>
Sun, 30 Nov 2008 23:24:08 +0000 (23:24 +0000)
Per buildfarm results.

contrib/dblink/dblink.c
contrib/tablefunc/tablefunc.c

index b95795a2b1ef476f5e66583182c1b7e5f4ea6865..9cd3a27004d16ab0c4227a5334c9b8719bc1d313 100644 (file)
@@ -8,7 +8,7 @@
  * Darko Prenosil <[email protected]>
  * Shridhar Daithankar <[email protected]>
  *
- * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.60.2.2 2008/01/03 21:28:18 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.60.2.3 2008/11/30 23:24:08 tgl Exp $
  * Copyright (c) 2001-2006, PostgreSQL Global Development Group
  * ALL RIGHTS RESERVED;
  *
@@ -224,7 +224,6 @@ dblink_connect(PG_FUNCTION_ARGS)
    char       *connstr = NULL;
    char       *connname = NULL;
    char       *msg;
-   MemoryContext oldcontext;
    PGconn     *conn = NULL;
    remoteConn *rconn = NULL;
 
@@ -238,17 +237,14 @@ dblink_connect(PG_FUNCTION_ARGS)
    else if (PG_NARGS() == 1)
        connstr = GET_STR(PG_GETARG_TEXT_P(0));
 
-   oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-
    if (connname)
-       rconn = (remoteConn *) palloc(sizeof(remoteConn));
+       rconn = (remoteConn *) MemoryContextAlloc(TopMemoryContext,
+                                                 sizeof(remoteConn));
 
    /* check password used if not superuser */
    dblink_security_check(conn, rconn, connstr);
    conn = PQconnectdb(connstr);
 
-   MemoryContextSwitchTo(oldcontext);
-
    if (PQstatus(conn) == CONNECTION_BAD)
    {
        msg = pstrdup(PQerrorMessage(conn));
@@ -581,10 +577,10 @@ dblink_fetch(PG_FUNCTION_ARGS)
        funcctx = SRF_FIRSTCALL_INIT();
 
        /*
-        * switch to memory context appropriate for multiple function calls
+        * Try to execute the query.  Note that since libpq uses malloc,
+        * the PGresult will be long-lived even though we are still in
+        * a short-lived memory context.
         */
-       oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
        res = PQexec(conn, buf.data);
        if (!res ||
            (PQresultStatus(res) != PGRES_COMMAND_OK &&
@@ -631,9 +627,6 @@ dblink_fetch(PG_FUNCTION_ARGS)
                break;
        }
 
-       /* make sure we have a persistent copy of the tupdesc */
-       tupdesc = CreateTupleDescCopy(tupdesc);
-
        /* check result and tuple descriptor have the same number of columns */
        if (PQnfields(res) != tupdesc->natts)
            ereport(ERROR,
@@ -641,14 +634,25 @@ dblink_fetch(PG_FUNCTION_ARGS)
                     errmsg("remote query result rowtype does not match "
                            "the specified FROM clause rowtype")));
 
-       /* fast track when no results */
+       /*
+        * fast track when no results.  We could exit earlier, but then
+        * we'd not report error if the result tuple type is wrong.
+        */
        if (funcctx->max_calls < 1)
        {
-           if (res)
-               PQclear(res);
+           PQclear(res);
            SRF_RETURN_DONE(funcctx);
        }
 
+       /*
+        * switch to memory context appropriate for multiple function calls,
+        * so we can make long-lived copy of tupdesc etc
+        */
+       oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+       /* make sure we have a persistent copy of the tupdesc */
+       tupdesc = CreateTupleDescCopy(tupdesc);
+
        /* store needed metadata for subsequent calls */
        attinmeta = TupleDescGetAttInMetadata(tupdesc);
        funcctx->attinmeta = attinmeta;
@@ -839,7 +843,10 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
                res = PQgetResult(conn);
                /* NULL means we're all done with the async results */
                if (!res)
+               {
+                   MemoryContextSwitchTo(oldcontext);
                    SRF_RETURN_DONE(funcctx);
+               }
            }
 
            if (!res ||
@@ -853,6 +860,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
                    DBLINK_RES_ERROR_AS_NOTICE("sql error");
                    if (freeconn)
                        PQfinish(conn);
+                   MemoryContextSwitchTo(oldcontext);
                    SRF_RETURN_DONE(funcctx);
                }
            }
@@ -923,6 +931,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
            {
                if (res)
                    PQclear(res);
+               MemoryContextSwitchTo(oldcontext);
                SRF_RETURN_DONE(funcctx);
            }
 
@@ -1294,8 +1303,11 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
            funcctx->user_fctx = results;
        }
        else
+       {
            /* fast track when no results */
+           MemoryContextSwitchTo(oldcontext);
            SRF_RETURN_DONE(funcctx);
+       }
 
        MemoryContextSwitchTo(oldcontext);
    }
index 0be013b90841c34611d83c46d7f4e4cee0832692..26886b2af9dd328eade3052d1001bb6c90f06125 100644 (file)
@@ -381,11 +381,6 @@ crosstab(PG_FUNCTION_ARGS)
        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();
 
-       /*
-        * switch to memory context appropriate for multiple function calls
-        */
-       oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
        /* Connect to SPI manager */
        if ((ret = SPI_connect()) < 0)
            /* internal error */
@@ -426,9 +421,6 @@ crosstab(PG_FUNCTION_ARGS)
            SRF_RETURN_DONE(funcctx);
        }
 
-       /* SPI switches context on us, so reset it */
-       MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
        /* get a tuple descriptor for our result type */
        switch (get_call_result_type(fcinfo, NULL, &tupdesc))
        {
@@ -448,9 +440,6 @@ crosstab(PG_FUNCTION_ARGS)
                break;
        }
 
-       /* make sure we have a persistent copy of the tupdesc */
-       tupdesc = CreateTupleDescCopy(tupdesc);
-
        /*
         * Check that return tupdesc is compatible with the data we got from
         * SPI, at least based on number and type of attributes
@@ -461,6 +450,14 @@ crosstab(PG_FUNCTION_ARGS)
                     errmsg("return and sql tuple descriptions are " \
                            "incompatible")));
 
+       /*
+        * switch to memory context appropriate for multiple function calls
+        */
+       oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+       /* make sure we have a persistent copy of the tupdesc */
+       tupdesc = CreateTupleDescCopy(tupdesc);
+
        /*
         * Generate attribute metadata needed later to produce tuples from raw
         * C strings