- The hostaddr and host parameters are used appropriately to ensure that
- name and reverse name queries are not made. See the documentation of
- these parameters in for details.
+ The hostaddr parameter must be used appropriately
+ to prevent DNS queries from being made. See the documentation of
+ this parameter in for details.
- You ensure that the socket is in the appropriate state
+ You must ensure that the socket is in the appropriate state
before calling PQconnectPoll, as described below.
- Note: use of PQconnectStartParams is analogous to
- PQconnectStart shown below.
+ To begin a nonblocking connection request,
+ call PQconnectStart
+ or PQconnectStartParams. If the result is null,
+ then
libpq has been unable to allocate a
+ new PGconn structure. Otherwise, a
+ valid PGconn pointer is returned (though not
+ yet representing a valid connection to the database). Next
+ call PQstatus(conn). If the result
+ is CONNECTION_BAD, the connection attempt has already
+ failed, typically because of invalid connection parameters.
- To begin a nonblocking connection request, call conn = PQconnectStart("connection_info_string").
- If
conn is null, then
libpq has been unable to allocate a new
PGconn
- structure. Otherwise, a valid PGconn pointer is returned (though not yet
- representing a valid connection to the database). On return from
- PQconnectStart, call status = PQstatus(conn). If status equals
- CONNECTION_BAD, PQconnectStart has failed.
-
-
- If PQconnectStart succeeds, the next stage is to poll
-
libpq so that it can proceed with the connection sequence.
+ If PQconnectStart
+ or PQconnectStartParams succeeds, the next stage
+ is to poll
libpq so that it can proceed with
+ the connection sequence.
Use PQsocket(conn) to obtain the descriptor of the
socket underlying the database connection.
+ (Caution: do not assume that the socket remains the same
+ across PQconnectPoll calls.)
Loop thus: If PQconnectPoll(conn) last returned
PGRES_POLLING_READING, wait until the socket is ready to
read (as indicated by select(), poll(), or
Conversely, if PQconnectPoll(conn) last returned
PGRES_POLLING_WRITING, wait until the socket is ready
to write, then call PQconnectPoll(conn) again.
- If you have yet to call
- PQconnectPoll, i.e., just after the call to
- PQconnectStart, behave as if it last returned
+ On the first iteration, i.e. if you have yet to call
+ PQconnectPoll, behave as if it last returned
PGRES_POLLING_WRITING. Continue this loop until
PQconnectPoll(conn) returns
PGRES_POLLING_FAILED, indicating the connection procedure
- Note that if PQconnectStart returns a non-null pointer, you must call
- PQfinish when you are finished with it, in order to dispose of
- the structure and any associated memory blocks. This must be done even if
- the connection attempt fails or is abandoned.
+ Note that when PQconnectStart
+ or PQconnectStartParams returns a non-null
+ pointer, you must call PQfinish when you are
+ finished with it, in order to dispose of the structure and any
+ associated memory blocks. This must be done even if the connection
+ attempt fails or is abandoned.
It is possible to specify multiple hosts to connect to, so that they are
tried in the given order. In the Keyword/Value format, the host,
hostaddr, and port options accept a comma-separated
- list of values. The same number of elements must be given in each option, such
+ list of values. The same number of elements must be given in each
+ option that is specified, such
that e.g. the first hostaddr corresponds to the first host name,
the second hostaddr corresponds to the second host name, and so
forth. As an exception, if only one port is specified, it
In the connection URI format, you can list multiple host:port pairs
- separated by commas, in the host component of the URI. In either
- format, a single host name can also translate to multiple network addresses. A
- common example of this is a host that has both an IPv4 and an IPv6 address.
+ separated by commas, in the host component of the URI.
+
+
+ In either format, a single host name can translate to multiple network
+ addresses. A common example of this is a host that has both an IPv4 and
+ an IPv6 address.
Name of host to connect to.
host name
If a host name begins with a slash, it specifies Unix-domain
communication rather than TCP/IP communication; the value is the
- name of the directory in which the socket file is stored. If
- multiple host names are specified, each will be tried in turn in
- the order given. The default behavior when host is
+ name of the directory in which the socket file is stored.
+ The default behavior when host is
not specified, or is empty, is to connect to a Unix-domain
socket
Unix domain socket in
/tmp (or whatever socket directory was specified
- If host is specified without hostaddr,
- a host name lookup occurs.
+ If host is specified
+ without hostaddr, a host name lookup occurs.
+ (When using PQconnectPoll, the lookup occurs
+ when PQconnectPoll first considers this host
+ name, and it may cause PQconnectPoll to block
+ for a significant amount of time.)
static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
static void freePGconn(PGconn *conn);
static void closePGconn(PGconn *conn);
-static void release_all_addrinfo(PGconn *conn);
+static void release_conn_addrinfo(PGconn *conn);
static void sendTerminateConn(PGconn *conn);
static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
static PQconninfoOption *parse_connection_string(const char *conninfo,
static int
connectDBStart(PGconn *conn)
{
- char portstr[MAXPGPATH];
- int ret;
- int i;
-
if (!conn)
return 0;
*/
resetPQExpBuffer(&conn->errorMessage);
- /*
- * Look up socket addresses for each possible host using
- * pg_getaddrinfo_all.
- */
- for (i = 0; i < conn->nconnhost; ++i)
- {
- pg_conn_host *ch = &conn->connhost[i];
- struct addrinfo hint;
- int thisport;
-
- /* Initialize hint structure */
- MemSet(&hint, 0, sizeof(hint));
- hint.ai_socktype = SOCK_STREAM;
- hint.ai_family = AF_UNSPEC;
-
- /* Figure out the port number we're going to use. */
- if (ch->port == NULL || ch->port[0] == '\0')
- thisport = DEF_PGPORT;
- else
- {
- thisport = atoi(ch->port);
- if (thisport < 1 || thisport > 65535)
- {
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("invalid port number: \"%s\"\n"),
- ch->port);
- conn->options_valid = false;
- goto connect_errReturn;
- }
- }
- snprintf(portstr, sizeof(portstr), "%d", thisport);
-
- /* Use pg_getaddrinfo_all() to resolve the address */
- ret = 1;
- switch (ch->type)
- {
- case CHT_HOST_NAME:
- ret = pg_getaddrinfo_all(ch->host, portstr, &hint, &ch->addrlist);
- if (ret || !ch->addrlist)
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not translate host name \"%s\" to address: %s\n"),
- ch->host, gai_strerror(ret));
- break;
-
- case CHT_HOST_ADDRESS:
- hint.ai_flags = AI_NUMERICHOST;
- ret = pg_getaddrinfo_all(ch->hostaddr, portstr, &hint, &ch->addrlist);
- if (ret || !ch->addrlist)
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not parse network address \"%s\": %s\n"),
- ch->hostaddr, gai_strerror(ret));
- break;
-
- case CHT_UNIX_SOCKET:
-#ifdef HAVE_UNIX_SOCKETS
- hint.ai_family = AF_UNIX;
- UNIXSOCK_PATH(portstr, thisport, ch->host);
- if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN)
- {
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("Unix-domain socket path \"%s\" is too long (maximum %d bytes)\n"),
- portstr,
- (int) (UNIXSOCK_PATH_BUFLEN - 1));
- conn->options_valid = false;
- goto connect_errReturn;
- }
-
- /*
- * NULL hostname tells pg_getaddrinfo_all to parse the service
- * name as a Unix-domain socket path.
- */
- ret = pg_getaddrinfo_all(NULL, portstr, &hint, &ch->addrlist);
- if (ret || !ch->addrlist)
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"),
- portstr, gai_strerror(ret));
- break;
-#else
- Assert(false);
- conn->options_valid = false;
- goto connect_errReturn;
-#endif
- }
- if (ret || !ch->addrlist)
- {
- if (ch->addrlist)
- {
- pg_freeaddrinfo_all(hint.ai_family, ch->addrlist);
- ch->addrlist = NULL;
- }
- conn->options_valid = false;
- goto connect_errReturn;
- }
- }
-
/*
* Set up to try to connect to the first host. (Setting whichhost = -1 is
* a bit of a cheat, but PQconnectPoll will advance it to 0 before
/* Time to advance to next connhost[] entry? */
if (conn->try_next_host)
{
+ pg_conn_host *ch;
+ struct addrinfo hint;
+ int thisport;
+ int ret;
+ char portstr[MAXPGPATH];
+
if (conn->whichhost + 1 >= conn->nconnhost)
{
/*
goto error_return;
}
conn->whichhost++;
- conn->addr_cur = conn->connhost[conn->whichhost].addrlist;
- /* If no addresses for this host, just try the next one */
- if (conn->addr_cur == NULL)
- goto keep_going;
+
+ /* Drop any address info for previous host */
+ release_conn_addrinfo(conn);
+
+ /*
+ * Look up info for the new host. On failure, log the problem in
+ * conn->errorMessage, then loop around to try the next host. (Note
+ * we don't clear try_next_host until we've succeeded.)
+ */
+ ch = &conn->connhost[conn->whichhost];
+
+ /* Initialize hint structure */
+ MemSet(&hint, 0, sizeof(hint));
+ hint.ai_socktype = SOCK_STREAM;
+ conn->addrlist_family = hint.ai_family = AF_UNSPEC;
+
+ /* Figure out the port number we're going to use. */
+ if (ch->port == NULL || ch->port[0] == '\0')
+ thisport = DEF_PGPORT;
+ else
+ {
+ thisport = atoi(ch->port);
+ if (thisport < 1 || thisport > 65535)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("invalid port number: \"%s\"\n"),
+ ch->port);
+ goto keep_going;
+ }
+ }
+ snprintf(portstr, sizeof(portstr), "%d", thisport);
+
+ /* Use pg_getaddrinfo_all() to resolve the address */
+ switch (ch->type)
+ {
+ case CHT_HOST_NAME:
+ ret = pg_getaddrinfo_all(ch->host, portstr, &hint,
+ &conn->addrlist);
+ if (ret || !conn->addrlist)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not translate host name \"%s\" to address: %s\n"),
+ ch->host, gai_strerror(ret));
+ goto keep_going;
+ }
+ break;
+
+ case CHT_HOST_ADDRESS:
+ hint.ai_flags = AI_NUMERICHOST;
+ ret = pg_getaddrinfo_all(ch->hostaddr, portstr, &hint,
+ &conn->addrlist);
+ if (ret || !conn->addrlist)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not parse network address \"%s\": %s\n"),
+ ch->hostaddr, gai_strerror(ret));
+ goto keep_going;
+ }
+ break;
+
+ case CHT_UNIX_SOCKET:
+#ifdef HAVE_UNIX_SOCKETS
+ conn->addrlist_family = hint.ai_family = AF_UNIX;
+ UNIXSOCK_PATH(portstr, thisport, ch->host);
+ if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("Unix-domain socket path \"%s\" is too long (maximum %d bytes)\n"),
+ portstr,
+ (int) (UNIXSOCK_PATH_BUFLEN - 1));
+ goto keep_going;
+ }
+
+ /*
+ * NULL hostname tells pg_getaddrinfo_all to parse the service
+ * name as a Unix-domain socket path.
+ */
+ ret = pg_getaddrinfo_all(NULL, portstr, &hint,
+ &conn->addrlist);
+ if (ret || !conn->addrlist)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"),
+ portstr, gai_strerror(ret));
+ goto keep_going;
+ }
+#else
+ Assert(false);
+#endif
+ break;
+ }
+
+ /* OK, scan this addrlist for a working server address */
+ conn->addr_cur = conn->addrlist;
reset_connection_state_machine = true;
conn->try_next_host = false;
}
return PGRES_POLLING_READING;
}
- /* We can release the address lists now. */
- release_all_addrinfo(conn);
+ /* We can release the address list now. */
+ release_conn_addrinfo(conn);
/* We are open for business! */
conn->status = CONNECTION_OK;
return PGRES_POLLING_READING;
}
- /* We can release the address lists now. */
- release_all_addrinfo(conn);
+ /* We can release the address list now. */
+ release_conn_addrinfo(conn);
/* We are open for business! */
conn->status = CONNECTION_OK;
goto keep_going;
}
+ /* We can release the address list now. */
+ release_conn_addrinfo(conn);
+
/* We are open for business! */
conn->status = CONNECTION_OK;
return PGRES_POLLING_OK;
PQclear(res);
termPQExpBuffer(&savedMessage);
- /* We can release the address lists now. */
- release_all_addrinfo(conn);
-
/*
* Finish reading any remaining messages before being
* considered as ready.
}
/*
- * release_all_addrinfo
- * - free addrinfo of all hostconn elements.
+ * release_conn_addrinfo
+ * - Free any addrinfo list in the PGconn.
*/
-
static void
-release_all_addrinfo(PGconn *conn)
+release_conn_addrinfo(PGconn *conn)
{
- if (conn->connhost != NULL)
+ if (conn->addrlist)
{
- int i;
-
- for (i = 0; i < conn->nconnhost; ++i)
- {
- int family = AF_UNSPEC;
-
-#ifdef HAVE_UNIX_SOCKETS
- if (conn->connhost[i].type == CHT_UNIX_SOCKET)
- family = AF_UNIX;
-#endif
-
- pg_freeaddrinfo_all(family,
- conn->connhost[i].addrlist);
- conn->connhost[i].addrlist = NULL;
- }
+ pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
+ conn->addrlist = NULL;
+ conn->addr_cur = NULL; /* for safety */
}
- conn->addr_cur = NULL;
}
/*
conn->xactStatus = PQTRANS_IDLE;
pqClearAsyncResult(conn); /* deallocate result */
resetPQExpBuffer(&conn->errorMessage);
- release_all_addrinfo(conn);
+ release_conn_addrinfo(conn);
/* Reset all state obtained from server, too */
pqDropServerData(conn);