diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index e09d6f16f69..9c92ee51760 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -8,7 +8,7 @@ * Darko Prenosil * Shridhar Daithankar * - * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.69 2008/01/14 02:49:47 tgl Exp $ + * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.69.2.1 2008/11/30 23:24:01 tgl Exp $ * Copyright (c) 2001-2008, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * @@ -226,7 +226,6 @@ dblink_connect(PG_FUNCTION_ARGS) char *connstr = NULL; char *connname = NULL; char *msg; - MemoryContext oldcontext; PGconn *conn = NULL; remoteConn *rconn = NULL; @@ -240,13 +239,11 @@ 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)); - conn = PQconnectdb(connstr); + rconn = (remoteConn *) MemoryContextAlloc(TopMemoryContext, + sizeof(remoteConn)); - MemoryContextSwitchTo(oldcontext); + conn = PQconnectdb(connstr); if (PQstatus(conn) == CONNECTION_BAD) { @@ -583,10 +580,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 && @@ -633,9 +630,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, @@ -643,14 +637,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; @@ -841,7 +846,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 || @@ -855,6 +863,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); } } @@ -925,6 +934,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get) { if (res) PQclear(res); + MemoryContextSwitchTo(oldcontext); SRF_RETURN_DONE(funcctx); } @@ -1296,8 +1306,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); } diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index bfac89e4146..9c9d0aa7a29 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -378,11 +378,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 */ @@ -423,9 +418,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)) { @@ -445,9 +437,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 @@ -458,6 +447,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