Add error detail when adding a data node fails

When `add_data_node` fails, it often gives an opaque error that it
couldn't connect to the data node. This change adds the libpq
connection error as a detailed message in the error.
This commit is contained in:
Erik Nordström 2020-12-17 09:51:11 +01:00 committed by Erik Nordström
parent 15e1edb76f
commit eede24bcf2
3 changed files with 51 additions and 19 deletions

View File

@ -552,16 +552,27 @@ connect_for_bootstrapping(const char *node_name, const char *const host, int32 p
const char *username, const char *password) const char *username, const char *password)
{ {
TSConnection *conn = NULL; TSConnection *conn = NULL;
char *err = NULL;
int i; int i;
for (i = 0; i < lengthof(bootstrap_databases); i++) for (i = 0; i < lengthof(bootstrap_databases); i++)
{ {
List *node_options = List *node_options =
create_data_node_options(host, port, bootstrap_databases[i], username, password); create_data_node_options(host, port, bootstrap_databases[i], username, password);
conn = remote_connection_open_with_options_nothrow(node_name, node_options); conn = remote_connection_open_with_options_nothrow(node_name, node_options, &err);
if (conn) if (conn)
return conn; return conn;
} }
return conn;
ereport(ERROR,
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
errmsg("could not connect to \"%s\"", node_name),
err == NULL ? 0 : errdetail("%s", err)));
pg_unreachable();
return NULL;
} }
/* /*
@ -726,12 +737,7 @@ data_node_add_internal(PG_FUNCTION_ARGS, bool set_distid)
{ {
TSConnection *conn = TSConnection *conn =
connect_for_bootstrapping(node_name, host, port, username, password); connect_for_bootstrapping(node_name, host, port, username, password);
Assert(NULL != conn);
if (NULL == conn)
ereport(ERROR,
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
errmsg("could not connect to \"%s\"", node_name)));
data_node_validate_extension_availability(conn); data_node_validate_extension_availability(conn);
database_created = data_node_bootstrap_database(conn, &database); database_created = data_node_bootstrap_database(conn, &database);
remote_connection_close(conn); remote_connection_close(conn);

View File

@ -1132,6 +1132,23 @@ set_ssl_options(const char *user_name, const char **keywords, const char **value
*option_start = option_pos; *option_start = option_pos;
} }
/*
* Finish the connection and, optionally, save the connection error.
*/
static void
finish_connection(PGconn *conn, char **errmsg)
{
if (NULL != errmsg)
{
if (NULL == conn)
*errmsg = "invalid connection";
else
*errmsg = pchomp(PQerrorMessage(conn));
}
PQfinish(conn);
}
/* /*
* This will only open a connection to a specific node, but not do anything * This will only open a connection to a specific node, but not do anything
* else. In particular, it will not perform any validation nor configure the * else. In particular, it will not perform any validation nor configure the
@ -1140,7 +1157,8 @@ set_ssl_options(const char *user_name, const char **keywords, const char **value
* function. * function.
*/ */
TSConnection * TSConnection *
remote_connection_open_with_options_nothrow(const char *node_name, List *connection_options) remote_connection_open_with_options_nothrow(const char *node_name, List *connection_options,
char **errmsg)
{ {
PGconn *volatile pg_conn = NULL; PGconn *volatile pg_conn = NULL;
const char *user_name = NULL; const char *user_name = NULL;
@ -1150,6 +1168,9 @@ remote_connection_open_with_options_nothrow(const char *node_name, List *connect
int option_count; int option_count;
int option_pos; int option_pos;
if (NULL != errmsg)
*errmsg = NULL;
/* /*
* Construct connection params from generic options of ForeignServer * Construct connection params from generic options of ForeignServer
* and user. (Some of them might not be libpq options, in * and user. (Some of them might not be libpq options, in
@ -1204,7 +1225,7 @@ remote_connection_open_with_options_nothrow(const char *node_name, List *connect
if (PQstatus(pg_conn) == CONNECTION_BAD) if (PQstatus(pg_conn) == CONNECTION_BAD)
{ {
PQfinish(pg_conn); finish_connection(pg_conn, errmsg);
pg_conn = NULL; pg_conn = NULL;
} }
@ -1221,7 +1242,7 @@ remote_connection_open_with_options_nothrow(const char *node_name, List *connect
case PGRES_POLLING_FAILED: case PGRES_POLLING_FAILED:
/* connection attempt failed */ /* connection attempt failed */
stop_waiting = true; stop_waiting = true;
PQfinish(pg_conn); finish_connection(pg_conn, errmsg);
pg_conn = NULL; pg_conn = NULL;
break; break;
case PGRES_POLLING_OK: case PGRES_POLLING_OK:
@ -1256,7 +1277,7 @@ remote_connection_open_with_options_nothrow(const char *node_name, List *connect
PG_CATCH(); PG_CATCH();
{ {
if (NULL != pg_conn) if (NULL != pg_conn)
PQfinish(pg_conn); finish_connection(pg_conn, errmsg);
PG_RE_THROW(); PG_RE_THROW();
} }
@ -1271,14 +1292,14 @@ remote_connection_open_with_options_nothrow(const char *node_name, List *connect
if (PQstatus(pg_conn) != CONNECTION_OK) if (PQstatus(pg_conn) != CONNECTION_OK)
{ {
PQfinish(pg_conn); finish_connection(pg_conn, errmsg);
return NULL; return NULL;
} }
ts_conn = remote_connection_create(pg_conn, false, node_name); ts_conn = remote_connection_create(pg_conn, false, node_name);
if (NULL == ts_conn) if (NULL == ts_conn)
PQfinish(pg_conn); finish_connection(pg_conn, errmsg);
return ts_conn; return ts_conn;
} }
@ -1297,12 +1318,15 @@ TSConnection *
remote_connection_open_with_options(const char *node_name, List *connection_options, remote_connection_open_with_options(const char *node_name, List *connection_options,
bool set_dist_id) bool set_dist_id)
{ {
TSConnection *conn = remote_connection_open_with_options_nothrow(node_name, connection_options); char *err = NULL;
TSConnection *conn =
remote_connection_open_with_options_nothrow(node_name, connection_options, &err);
if (NULL == conn) if (NULL == conn)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
errmsg("could not connect to \"%s\"", node_name))); errmsg("could not connect to \"%s\"", node_name),
err == NULL ? 0 : errdetail_internal("%s", err)));
/* /*
* Use PG_TRY block to ensure closing connection on error. * Use PG_TRY block to ensure closing connection on error.
@ -1477,11 +1501,12 @@ remote_connection_open_nothrow(Oid server_id, Oid user_id, char **errmsg)
} }
connection_options = add_userinfo_to_server_options(server, user_id); connection_options = add_userinfo_to_server_options(server, user_id);
conn = remote_connection_open_with_options_nothrow(server->servername, connection_options); conn =
remote_connection_open_with_options_nothrow(server->servername, connection_options, errmsg);
if (NULL == conn) if (NULL == conn)
{ {
if (NULL != errmsg) if (NULL != errmsg && NULL == *errmsg)
*errmsg = "internal connection error"; *errmsg = "internal connection error";
return NULL; return NULL;
} }

View File

@ -39,7 +39,8 @@ extern TSConnection *remote_connection_open_with_options(const char *node_name,
List *connection_options, List *connection_options,
bool set_dist_id); bool set_dist_id);
extern TSConnection *remote_connection_open_with_options_nothrow(const char *node_name, extern TSConnection *remote_connection_open_with_options_nothrow(const char *node_name,
List *connection_options); List *connection_options,
char **errmsg);
extern TSConnection *remote_connection_open_by_id(TSConnectionId id); extern TSConnection *remote_connection_open_by_id(TSConnectionId id);
extern TSConnection *remote_connection_open(Oid server_id, Oid user_id); extern TSConnection *remote_connection_open(Oid server_id, Oid user_id);
extern TSConnection *remote_connection_open_nothrow(Oid server_id, Oid user_id, char **errmsg); extern TSConnection *remote_connection_open_nothrow(Oid server_id, Oid user_id, char **errmsg);