]> granicus.if.org Git - postgresql/commitdiff
Fix dblink and tablefunc to not return with the wrong CurrentMemoryContext.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Nov 2008 23:23:52 +0000 (23:23 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Nov 2008 23:23:52 +0000 (23:23 +0000)
Per buildfarm results.

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

index 498e852a98d82fd1069337c0fda0709abe942864..9a5303f3866a769a6ccbd4663bb622e968a940a3 100644 (file)
@@ -8,7 +8,7 @@
  * Darko Prenosil <Darko.Prenosil@finteh.hr>
  * Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
  *
- * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.75 2008/09/22 13:55:13 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.76 2008/11/30 23:23:52 tgl Exp $
  * Copyright (c) 2001-2008, PostgreSQL Global Development Group
  * ALL RIGHTS RESERVED;
  *
@@ -213,7 +213,6 @@ dblink_connect(PG_FUNCTION_ARGS)
        char       *connstr = NULL;
        char       *connname = NULL;
        char       *msg;
-       MemoryContext oldcontext;
        PGconn     *conn = NULL;
        remoteConn *rconn = NULL;
 
@@ -227,17 +226,14 @@ dblink_connect(PG_FUNCTION_ARGS)
        else if (PG_NARGS() == 1)
                connstr = text_to_cstring(PG_GETARG_TEXT_PP(0));
 
-       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-
        if (connname)
-               rconn = (remoteConn *) palloc(sizeof(remoteConn));
+               rconn = (remoteConn *) MemoryContextAlloc(TopMemoryContext,
+                                                                                                 sizeof(remoteConn));
 
        /* check password in connection string if not superuser */
        dblink_connstr_check(connstr);
        conn = PQconnectdb(connstr);
 
-       MemoryContextSwitchTo(oldcontext);
-
        if (PQstatus(conn) == CONNECTION_BAD)
        {
                msg = pstrdup(PQerrorMessage(conn));
@@ -562,10 +558,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 &&
@@ -607,9 +603,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,
@@ -617,14 +610,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;
@@ -815,7 +819,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 ||
@@ -825,6 +832,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
                                dblink_res_error(conname, res, "could not execute query", fail);
                                if (freeconn)
                                        PQfinish(conn);
+                               MemoryContextSwitchTo(oldcontext);
                                SRF_RETURN_DONE(funcctx);
                        }
 
@@ -894,6 +902,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
                        {
                                if (res)
                                        PQclear(res);
+                               MemoryContextSwitchTo(oldcontext);
                                SRF_RETURN_DONE(funcctx);
                        }
 
@@ -1261,8 +1270,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 1f4a6dd9dddb531e380085b2aafdd2288558509d..28b7a64f439de3438bdedf80abfaabd5543527a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/tablefunc/tablefunc.c,v 1.55 2008/10/29 00:00:38 tgl Exp $ 
+ * $PostgreSQL: pgsql/contrib/tablefunc/tablefunc.c,v 1.56 2008/11/30 23:23:52 tgl Exp $ 
  *
  *
  * tablefunc
@@ -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