From: Shigeru Hanada Date: Tue, 9 Nov 2010 06:18:20 +0000 (+0900) Subject: Use BeginScan instead of the first Itereate call to execute remote X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=1a63c5ddc16792c2e070a89aee5b83ddf46ea842;p=users%2Fhanada%2Fpostgres.git Use BeginScan instead of the first Itereate call to execute remote query in postgresql_fdw. --- diff --git a/contrib/postgresql_fdw/postgresql_fdw.c b/contrib/postgresql_fdw/postgresql_fdw.c index f327a298f1..e9716d47b2 100644 --- a/contrib/postgresql_fdw/postgresql_fdw.c +++ b/contrib/postgresql_fdw/postgresql_fdw.c @@ -500,121 +500,115 @@ pgOpen(ForeignScanState *scanstate) */ static void pgBeginScan(ForeignScanState *scanstate) -{ -} - -/* - * return tuples one by one. - * - execute SQL statement which was deparsed in pgOpen() - * - * The all of result are fetched at once when pgIterate() is called first after - * pgOpen() or pgReOpen(). - * pgIterate() takes out a tuple from tupstore with tupslot and returns it. - */ -static void -pgIterate(ForeignScanState *scanstate) { pgFdwReply *reply = (pgFdwReply *) scanstate->reply; - TupleTableSlot *slot = scanstate->ss.ss_ScanTupleSlot; - - /* - * Execute query with current parameters. - */ - if (reply->tupstore == NULL) + PGconn *conn = (PGconn *) scanstate->conn; + PGresult *res; + ParamListInfo info = scanstate->ss.ps.state->es_param_list_info; + int numParams = info ? info->numParams : 0; + Oid *types = NULL; + const char **values = NULL; + + /* construct parameter array in text format */ + /* TODO: omit unused parameter */ + if (numParams > 0) { - PGconn *conn = (PGconn *) scanstate->conn; - PGresult *res; - ParamListInfo info = scanstate->ss.ps.state->es_param_list_info; - int numParams = info ? info->numParams : 0; - Oid *types = NULL; - const char **values = NULL; - - /* construct parameter array in text format */ - /* TODO: omit unused parameter */ - if (numParams > 0) - { - int i; + int i; - types = palloc0(sizeof(Oid) * numParams); - values = palloc0(sizeof(char *) * numParams); - for (i = 0; i < numParams; i++) + types = palloc0(sizeof(Oid) * numParams); + values = palloc0(sizeof(char *) * numParams); + for (i = 0; i < numParams; i++) + { + types[i] = info->params[i].ptype; + if (info->params[i].isnull) + values[i] = NULL; + else { - types[i] = info->params[i].ptype; - if (info->params[i].isnull) - values[i] = NULL; - else - { - Oid out_func_oid; - bool isvarlena; - FmgrInfo func; - - /* TODO: cache FmgrInfo to use it again after pgReOpen() */ - /* TODO: send parameters in binary format rather than text */ - getTypeOutputInfo(types[i], &out_func_oid, &isvarlena); - fmgr_info(out_func_oid, &func); - values[i] = - OutputFunctionCall(&func, info->params[i].value); - } + Oid out_func_oid; + bool isvarlena; + FmgrInfo func; + + /* TODO: cache FmgrInfo to use it again after pgReOpen() */ + /* TODO: send parameters in binary format rather than text */ + getTypeOutputInfo(types[i], &out_func_oid, &isvarlena); + fmgr_info(out_func_oid, &func); + values[i] = + OutputFunctionCall(&func, info->params[i].value); } } + } - /* - * Execute query with the parameters. - * TODO: support internal parameters(PARAM_EXTERN) - * TODO: support cursor mode for huge result sets. - */ - res = PQexecParams(conn, reply->sql, - numParams, types, values, NULL, NULL, 0); - if (numParams > 0) - { - int i; - pfree(types); - for (i = 0; i < numParams; i++) - pfree((char *) values[i]); - pfree(values); - } + /* + * Execute query with the parameters. + * TODO: support internal parameters(PARAM_EXTERN) + * TODO: support cursor mode for huge result sets. + */ + res = PQexecParams(conn, reply->sql, + numParams, types, values, NULL, NULL, 0); + if (numParams > 0) + { + int i; + pfree(types); + for (i = 0; i < numParams; i++) + pfree((char *) values[i]); + pfree(values); + } - /* - * If the query has failed and the connection became invalid, we need to - * remove the connection from cache. This clean-up might make next - * query on the same server successful. - */ - if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) - { - char *msg; + /* + * If the query has failed and the connection became invalid, we need to + * remove the connection from cache. This clean-up might make next + * query on the same server successful. + */ + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) + { + char *msg; - PQclear(res); - msg = pstrdup(PQerrorMessage(conn)); - if (PQstatus(conn) != CONNECTION_OK) - { - conn = UnregisterConnection(scanstate->server->servername); - PQfinish(conn); - } - - ereport(ERROR, ( - errmsg("could not execute foreign query"), - errdetail("%s", msg), errhint("%s", reply->sql))); + PQclear(res); + msg = pstrdup(PQerrorMessage(conn)); + if (PQstatus(conn) != CONNECTION_OK) + { + conn = UnregisterConnection(scanstate->server->servername); + PQfinish(conn); } - /* Note: use PG_TRY to ensure freeing PGresult. */ - PG_TRY(); - { - TupleDesc tupdesc = ExecGetScanType((ScanState *) scanstate); + ereport(ERROR, ( + errmsg("could not execute foreign query"), + errdetail("%s", msg), errhint("%s", reply->sql))); + } - /* create tuplestore to store results */ - reply->tupstore = tuplestore_begin_heap(true, false, work_mem); + /* Note: use PG_TRY to ensure freeing PGresult. */ + PG_TRY(); + { + TupleDesc tupdesc = ExecGetScanType((ScanState *) scanstate); - storeResult(reply->tupstore, false, tupdesc, res); + /* create tuplestore to store results */ + reply->tupstore = tuplestore_begin_heap(true, false, work_mem); - PQclear(res); - } - PG_CATCH(); - { - PQclear(res); - PG_RE_THROW(); - } - PG_END_TRY(); + storeResult(reply->tupstore, false, tupdesc, res); + + PQclear(res); } + PG_CATCH(); + { + PQclear(res); + PG_RE_THROW(); + } + PG_END_TRY(); +} + +/* + * return tuples one by one. + * - execute SQL statement which was deparsed in pgOpen() + * + * The all of result are fetched at once when pgIterate() is called first after + * pgOpen() or pgReOpen(). + * pgIterate() takes out a tuple from tupstore with tupslot and returns it. + */ +static void +pgIterate(ForeignScanState *scanstate) +{ + pgFdwReply *reply = (pgFdwReply *) scanstate->reply; + TupleTableSlot *slot = scanstate->ss.ss_ScanTupleSlot; /* store the next tuple into the slot from the tuplestore */ if (tuplestore_gettupleslot(reply->tupstore, true, false, slot))