mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-30 19:00:29 +08:00
Make dblink try harder to form useful error messages
When libpq encounters a connection-level error, e.g. runs out of memory while forming a result, there will be no error associated with PGresult, but a message will be placed into PGconn's error buffer. postgres_fdw takes care to use the PGconn error message when PGresult does not have one, but dblink has been negligent in that regard. Modify dblink to mirror what postgres_fdw has been doing. Back-patch to all supported branches. Author: Joe Conway Reviewed-By: Tom Lane Discussion: https://postgr.es/m/02fa2d90-2efd-00bc-fefc-c23c00eb671e%40joeconway.com
This commit is contained in:
parent
3ee8067284
commit
2f802d95b4
@ -113,7 +113,8 @@ static Relation get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclM
|
|||||||
static char *generate_relation_name(Relation rel);
|
static char *generate_relation_name(Relation rel);
|
||||||
static void dblink_connstr_check(const char *connstr);
|
static void dblink_connstr_check(const char *connstr);
|
||||||
static void dblink_security_check(PGconn *conn, remoteConn *rconn);
|
static void dblink_security_check(PGconn *conn, remoteConn *rconn);
|
||||||
static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail);
|
static void dblink_res_error(PGconn *conn, const char *conname, PGresult *res,
|
||||||
|
const char *dblink_context_msg, bool fail);
|
||||||
static char *get_connect_string(const char *servername);
|
static char *get_connect_string(const char *servername);
|
||||||
static char *escape_param_str(const char *from);
|
static char *escape_param_str(const char *from);
|
||||||
static void validate_pkattnums(Relation rel,
|
static void validate_pkattnums(Relation rel,
|
||||||
@ -428,7 +429,7 @@ dblink_open(PG_FUNCTION_ARGS)
|
|||||||
res = PQexec(conn, buf.data);
|
res = PQexec(conn, buf.data);
|
||||||
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
{
|
{
|
||||||
dblink_res_error(conname, res, "could not open cursor", fail);
|
dblink_res_error(conn, conname, res, "could not open cursor", fail);
|
||||||
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +498,7 @@ dblink_close(PG_FUNCTION_ARGS)
|
|||||||
res = PQexec(conn, buf.data);
|
res = PQexec(conn, buf.data);
|
||||||
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
{
|
{
|
||||||
dblink_res_error(conname, res, "could not close cursor", fail);
|
dblink_res_error(conn, conname, res, "could not close cursor", fail);
|
||||||
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,7 +601,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||||
PQresultStatus(res) != PGRES_TUPLES_OK))
|
PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||||
{
|
{
|
||||||
dblink_res_error(conname, res, "could not fetch from cursor", fail);
|
dblink_res_error(conn, conname, res,
|
||||||
|
"could not fetch from cursor", fail);
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
}
|
}
|
||||||
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||||
@ -751,8 +753,8 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
|
|||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK &&
|
if (PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||||
PQresultStatus(res) != PGRES_TUPLES_OK)
|
PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
dblink_res_error(conname, res, "could not execute query",
|
dblink_res_error(conn, conname, res,
|
||||||
fail);
|
"could not execute query", fail);
|
||||||
/* if fail isn't set, we'll return an empty query result */
|
/* if fail isn't set, we'll return an empty query result */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -997,7 +999,8 @@ materializeQueryResult(FunctionCallInfo fcinfo,
|
|||||||
PGresult *res1 = res;
|
PGresult *res1 = res;
|
||||||
|
|
||||||
res = NULL;
|
res = NULL;
|
||||||
dblink_res_error(conname, res1, "could not execute query", fail);
|
dblink_res_error(conn, conname, res1,
|
||||||
|
"could not execute query", fail);
|
||||||
/* if fail isn't set, we'll return an empty query result */
|
/* if fail isn't set, we'll return an empty query result */
|
||||||
}
|
}
|
||||||
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||||
@ -1432,7 +1435,8 @@ dblink_exec(PG_FUNCTION_ARGS)
|
|||||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||||
PQresultStatus(res) != PGRES_TUPLES_OK))
|
PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||||
{
|
{
|
||||||
dblink_res_error(conname, res, "could not execute command", fail);
|
dblink_res_error(conn, conname, res,
|
||||||
|
"could not execute command", fail);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* and save a copy of the command status string to return as our
|
* and save a copy of the command status string to return as our
|
||||||
@ -2663,7 +2667,8 @@ dblink_connstr_check(const char *connstr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail)
|
dblink_res_error(PGconn *conn, const char *conname, PGresult *res,
|
||||||
|
const char *dblink_context_msg, bool fail)
|
||||||
{
|
{
|
||||||
int level;
|
int level;
|
||||||
char *pg_diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
|
char *pg_diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
|
||||||
@ -2697,6 +2702,14 @@ dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_
|
|||||||
xpstrdup(message_hint, pg_diag_message_hint);
|
xpstrdup(message_hint, pg_diag_message_hint);
|
||||||
xpstrdup(message_context, pg_diag_context);
|
xpstrdup(message_context, pg_diag_context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we don't get a message from the PGresult, try the PGconn. This
|
||||||
|
* is needed because for connection-level failures, PQexec may just
|
||||||
|
* return NULL, not a PGresult at all.
|
||||||
|
*/
|
||||||
|
if (message_primary == NULL)
|
||||||
|
message_primary = PQerrorMessage(conn);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user