From: Shigeru Hanada Date: Thu, 11 Nov 2010 05:44:04 +0000 (+0900) Subject: Refactor postgresql_fdw. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=e15c9eea243fb68ff8968abee237bd2683047036;p=users%2Fhanada%2Fpostgres.git Refactor postgresql_fdw. Simplify GetConnection() in fsconnection.c with merging related functions. --- diff --git a/contrib/postgresql_fdw/fsconnection.c b/contrib/postgresql_fdw/fsconnection.c index a9d5732c4b..f56b30eafd 100644 --- a/contrib/postgresql_fdw/fsconnection.c +++ b/contrib/postgresql_fdw/fsconnection.c @@ -24,8 +24,7 @@ #include "fsconnection.h" static void check_conn_params(const char **keywords, const char **values); -static PGconn *get_cached_connection(const char *name); -static void register_connection(PGconn *conn, const char *conname); +static PGconn *connect_pg_server(ForeignServer *server, UserMapping *user); static void cleanup_connection(ResourceReleasePhase phase, bool isCommit, bool isTopLevel, @@ -56,62 +55,79 @@ static HTAB *FSConnectionHash; PGconn * GetConnection(ForeignServer *server, UserMapping *user) { - PGconn *conn; - const char **all_keywords; - const char **all_values; - const char **keywords; - const char **values; - int n; - int i, j; + const char *conname = server->servername; + bool found; + ConnCacheEntry *entry; + PGconn *conn = NULL; - /* First of all, lookup connection cache by name */ - conn = get_cached_connection(server->servername); - if (conn != NULL) - return conn; + /* initialize connection cache if it isn't */ + if (FSConnectionHash == NULL) + { + HASHCTL ctl; - /* - * Construct connection params from generic options of ForeignServer and - * UserMapping. Generic options might not be a one of connection options. - */ - n = list_length(server->options) + list_length(user->options) + 1; - all_keywords = (const char **) palloc(sizeof(char *) * n); - all_values = (const char **) palloc(sizeof(char *) * n); - keywords = (const char **) palloc(sizeof(char *) * n); - values = (const char **) palloc(sizeof(char *) * n); - n = 0; - n += flatten_generic_options(server->options, - all_keywords + n, all_values + n); - n += flatten_generic_options(user->options, - all_keywords + n, all_values + n); - all_keywords[n] = all_values[n] = NULL; + elog(DEBUG1, "%s() cache not initialized(%s)", __FUNCTION__, conname); - for (i = 0, j = 0; all_keywords[i]; i++) + /* hash key is the name of the connection */ + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = NAMEDATALEN; + ctl.entrysize = sizeof(ConnCacheEntry); + /* allocate FSConnectionHash in the cache context */ + ctl.hcxt = CacheMemoryContext; + FSConnectionHash = hash_create("Foreign Connections", 32, + &ctl, + HASH_ELEM | HASH_CONTEXT); + } + + /* Is there any cached and valid connection with such name? */ + entry = hash_search(FSConnectionHash, conname, HASH_ENTER, &found); + if (found) { - /* Use only libpq connection options. */ - if (!is_libpq_connection_option(all_keywords[i])) - continue; - keywords[j] = all_keywords[i]; - values[j] = all_values[i]; - j++; + if (entry->conn != NULL) + { + entry->refs++; + elog(DEBUG1, "%s() ref %d for %s", __FUNCTION__, + entry->refs, entry->name); + return entry->conn; + } + + /* + * Connection cache entry was found but connection in it is invalid. + * We reuse entry to store newly established connection later. + */ } - keywords[j] = values[j] = NULL; - pfree(all_keywords); - pfree(all_values); - /* verify connection parameters and do connect */ - check_conn_params(keywords, values); - conn = PQconnectdbParams(keywords, values, 0); - if (!conn || PQstatus(conn) != CONNECTION_OK) - ereport(ERROR, - (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), - errmsg("could not connect to server \"%s\"", - server->servername), - errdetail("%s", PQerrorMessage(conn)))); - pfree(keywords); - pfree(values); + /* + * Here we have to establish new connection. + * Use PG_TRY block to ensure closing connection on error. + */ + PG_TRY(); + { + /* Connect to the foreign PostgreSQL server */ + conn = connect_pg_server(server, user); - /* register the connection into connection cache. */ - register_connection(conn, server->servername); + /* + * Initialize the cache entry to keep new connection. + * Note: entry->name has been initialized in hash_search(HASH_ENTER). + */ + entry->refs = 1; + entry->conn = conn; + elog(DEBUG1, "%s() ref %d for %s", __FUNCTION__, + entry->refs, entry->name); + + /* + * Use ResourceOner to clean the connection up on error including + * user interrupt. + */ + RegisterResourceReleaseCallback(cleanup_connection, entry); + elog(DEBUG1, "%s() register %p(%s)", __FUNCTION__, entry, entry->name); + } + PG_CATCH(); + { + PQfinish(conn); + entry->conn = NULL; + PG_RE_THROW(); + } + PG_END_TRY(); return conn; } @@ -144,109 +160,59 @@ check_conn_params(const char **keywords, const char **values) errdetail("Non-superusers must provide a password in the connection string."))); } -/* Find a connection from the cache by name. */ static PGconn * -get_cached_connection(const char *conname) +connect_pg_server(ForeignServer *server, UserMapping *user) { - ConnCacheEntry *entry; - - AssertArg(conname != NULL); - AssertArg(strlen(conname) < NAMEDATALEN); - - /* Is the connection cache has been initialized? */ - if (FSConnectionHash == NULL) - { - elog(DEBUG1, "%s() cache not initialized(%s)", __FUNCTION__, conname); - return NULL; - } - - /* Is there any cached connection with such name? */ - entry = (ConnCacheEntry *) hash_search(FSConnectionHash, - conname, - HASH_FIND, - NULL); - if (entry == NULL) - { - elog(DEBUG1, "%s() \"%s\" isn't cached", __FUNCTION__, conname); - return NULL; - } - - /* Is the cached connection valid? */ - if (entry->conn == NULL) - { - elog(DEBUG1, "%s() \"%s\" has been closed", __FUNCTION__, conname); - return NULL; - } + const char *conname = server->servername; + PGconn *conn; + const char **all_keywords; + const char **all_values; + const char **keywords; + const char **values; + int n; + int i, j; /* - * Now the appropriate connection has been found, return it with - * incrementing reference count. + * Construct connection params from generic options of ForeignServer and + * UserMapping. Generic options might not be a one of connection options. */ - entry->refs++; - elog(DEBUG1, "%s() ref %d for %s", __FUNCTION__, entry->refs, entry->name); - - return entry->conn; -} - -/* - * Regsiter a named PGconn into connection cache. - */ -static void -register_connection(PGconn *conn, const char *conname) -{ - bool found; - ConnCacheEntry *entry; - - AssertArg(conn != NULL); - AssertArg(conname != NULL); - AssertArg(strlen(conname) < NAMEDATALEN); - - /* Use PG_TRY block to ensure closing connection on error. */ - PG_TRY(); - { - /* initialize connection cache */ - if (FSConnectionHash == NULL) - { - HASHCTL ctl; - - /* hash key is the name of the connection */ - MemSet(&ctl, 0, sizeof(ctl)); - ctl.keysize = NAMEDATALEN; - ctl.entrysize = sizeof(ConnCacheEntry); - /* allocate FSConnectionHash in the cache context */ - ctl.hcxt = CacheMemoryContext; - FSConnectionHash = hash_create("Foreign Connections", 32, - &ctl, - HASH_ELEM | HASH_CONTEXT); - } - - /* - * Search from cache first. When an apporopriate connection was found in - * the connection cache, use it. - */ - entry = (ConnCacheEntry *) hash_search(FSConnectionHash, - conname, - HASH_ENTER, - &found); - if (found) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("connection \"%s\" already exists", conname))); - - entry->refs = 1; - entry->conn = conn; + n = list_length(server->options) + list_length(user->options) + 1; + all_keywords = (const char **) palloc(sizeof(char *) * n); + all_values = (const char **) palloc(sizeof(char *) * n); + keywords = (const char **) palloc(sizeof(char *) * n); + values = (const char **) palloc(sizeof(char *) * n); + n = 0; + n += flatten_generic_options(server->options, + all_keywords + n, all_values + n); + n += flatten_generic_options(user->options, + all_keywords + n, all_values + n); + all_keywords[n] = all_values[n] = NULL; - /* Use ResourceOner to cleanup on error, including user interrupt. */ - RegisterResourceReleaseCallback(cleanup_connection, entry); - elog(DEBUG1, "%s() register %p(%s)", __FUNCTION__, entry, entry->name); - } - PG_CATCH(); + for (i = 0, j = 0; all_keywords[i]; i++) { - PQfinish(conn); - PG_RE_THROW(); + /* Use only libpq connection options. */ + if (!is_libpq_connection_option(all_keywords[i])) + continue; + keywords[j] = all_keywords[i]; + values[j] = all_values[i]; + j++; } - PG_END_TRY(); + keywords[j] = values[j] = NULL; + pfree(all_keywords); + pfree(all_values); + /* verify connection parameters and do connect */ + check_conn_params(keywords, values); + conn = PQconnectdbParams(keywords, values, 0); + if (!conn || PQstatus(conn) != CONNECTION_OK) + ereport(ERROR, + (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), + errmsg("could not connect to server \"%s\"", conname), + errdetail("%s", PQerrorMessage(conn)))); + pfree(keywords); + pfree(values); + + return conn; } /* @@ -325,5 +291,6 @@ cleanup_connection(ResourceReleasePhase phase, PQfinish(entry->conn); entry->conn = NULL; //UnregisterResourceReleaseCallback(cleanup_connection, entry); + hash_search(FSConnectionHash, entry->name, HASH_REMOVE, NULL); } }