mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
When an ERROR happens on a dblink remote connection, take
pains to pass the ERROR message components locally, including using the passed SQLSTATE. Also wrap the passed info in an appropriate CONTEXT message. Addresses complaint by Henry Combrinck. Joe Conway, with much good advice from Tom Lane.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
* Darko Prenosil <Darko.Prenosil@finteh.hr>
|
||||
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.73 2008/04/04 17:02:56 momjian Exp $
|
||||
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.74 2008/07/03 03:56:57 joe Exp $
|
||||
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
|
||||
* ALL RIGHTS RESERVED;
|
||||
*
|
||||
@ -94,6 +94,7 @@ static HeapTuple get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 p
|
||||
static Oid get_relid_from_relname(text *relname_text);
|
||||
static char *generate_relation_name(Oid relid);
|
||||
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);
|
||||
|
||||
/* Global */
|
||||
static remoteConn *pconn = NULL;
|
||||
@ -125,6 +126,14 @@ typedef struct remoteConnHashEnt
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define xpstrdup(var_c, var_) \
|
||||
do { \
|
||||
if (var_ != NULL) \
|
||||
var_c = pstrdup(var_); \
|
||||
else \
|
||||
var_c = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define DBLINK_RES_INTERNALERROR(p2) \
|
||||
do { \
|
||||
msg = pstrdup(PQerrorMessage(conn)); \
|
||||
@ -133,28 +142,6 @@ typedef struct remoteConnHashEnt
|
||||
elog(ERROR, "%s: %s", p2, msg); \
|
||||
} while (0)
|
||||
|
||||
#define DBLINK_RES_ERROR(p2) \
|
||||
do { \
|
||||
msg = pstrdup(PQerrorMessage(conn)); \
|
||||
if (res) \
|
||||
PQclear(res); \
|
||||
ereport(ERROR, \
|
||||
(errcode(ERRCODE_SYNTAX_ERROR), \
|
||||
errmsg("%s", p2), \
|
||||
errdetail("%s", msg))); \
|
||||
} while (0)
|
||||
|
||||
#define DBLINK_RES_ERROR_AS_NOTICE(p2) \
|
||||
do { \
|
||||
msg = pstrdup(PQerrorMessage(conn)); \
|
||||
if (res) \
|
||||
PQclear(res); \
|
||||
ereport(NOTICE, \
|
||||
(errcode(ERRCODE_SYNTAX_ERROR), \
|
||||
errmsg("%s", p2), \
|
||||
errdetail("%s", msg))); \
|
||||
} while (0)
|
||||
|
||||
#define DBLINK_CONN_NOT_AVAIL \
|
||||
do { \
|
||||
if(conname) \
|
||||
@ -396,13 +383,8 @@ dblink_open(PG_FUNCTION_ARGS)
|
||||
res = PQexec(conn, buf.data);
|
||||
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
if (fail)
|
||||
DBLINK_RES_ERROR("sql error");
|
||||
else
|
||||
{
|
||||
DBLINK_RES_ERROR_AS_NOTICE("sql error");
|
||||
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
||||
}
|
||||
dblink_res_error(conname, res, "could not open cursor", fail);
|
||||
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -470,13 +452,8 @@ dblink_close(PG_FUNCTION_ARGS)
|
||||
res = PQexec(conn, buf.data);
|
||||
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
if (fail)
|
||||
DBLINK_RES_ERROR("sql error");
|
||||
else
|
||||
{
|
||||
DBLINK_RES_ERROR_AS_NOTICE("sql error");
|
||||
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
||||
}
|
||||
dblink_res_error(conname, res, "could not close cursor", fail);
|
||||
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -513,7 +490,6 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
||||
int call_cntr;
|
||||
int max_calls;
|
||||
AttInMetadata *attinmeta;
|
||||
char *msg;
|
||||
PGresult *res = NULL;
|
||||
MemoryContext oldcontext;
|
||||
char *conname = NULL;
|
||||
@ -590,13 +566,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||
PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||
{
|
||||
if (fail)
|
||||
DBLINK_RES_ERROR("sql error");
|
||||
else
|
||||
{
|
||||
DBLINK_RES_ERROR_AS_NOTICE("sql error");
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
dblink_res_error(conname, res, "could not fetch from cursor", fail);
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
@ -846,15 +817,10 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
|
||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||
PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||
{
|
||||
if (fail)
|
||||
DBLINK_RES_ERROR("sql error");
|
||||
else
|
||||
{
|
||||
DBLINK_RES_ERROR_AS_NOTICE("sql error");
|
||||
if (freeconn)
|
||||
PQfinish(conn);
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
dblink_res_error(conname, res, "could not execute query", fail);
|
||||
if (freeconn)
|
||||
PQfinish(conn);
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
||||
if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
@ -1180,10 +1146,7 @@ dblink_exec(PG_FUNCTION_ARGS)
|
||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||
PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||
{
|
||||
if (fail)
|
||||
DBLINK_RES_ERROR("sql error");
|
||||
else
|
||||
DBLINK_RES_ERROR_AS_NOTICE("sql error");
|
||||
dblink_res_error(conname, res, "could not execute command", fail);
|
||||
|
||||
/* need a tuple descriptor representing one TEXT column */
|
||||
tupdesc = CreateTemplateTupleDesc(1, false);
|
||||
@ -1195,7 +1158,6 @@ dblink_exec(PG_FUNCTION_ARGS)
|
||||
* result tuple
|
||||
*/
|
||||
sql_cmd_status = cstring_to_text("ERROR");
|
||||
|
||||
}
|
||||
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
@ -2288,3 +2250,54 @@ dblink_security_check(PGconn *conn, remoteConn *rconn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail)
|
||||
{
|
||||
int level;
|
||||
char *pg_diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
|
||||
char *pg_diag_message_primary = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
|
||||
char *pg_diag_message_detail = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
|
||||
char *pg_diag_message_hint = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
|
||||
char *pg_diag_context = PQresultErrorField(res, PG_DIAG_CONTEXT);
|
||||
int sqlstate;
|
||||
char *message_primary;
|
||||
char *message_detail;
|
||||
char *message_hint;
|
||||
char *message_context;
|
||||
const char *dblink_context_conname = "unnamed";
|
||||
|
||||
if (fail)
|
||||
level = ERROR;
|
||||
else
|
||||
level = NOTICE;
|
||||
|
||||
if (pg_diag_sqlstate)
|
||||
sqlstate = MAKE_SQLSTATE(pg_diag_sqlstate[0],
|
||||
pg_diag_sqlstate[1],
|
||||
pg_diag_sqlstate[2],
|
||||
pg_diag_sqlstate[3],
|
||||
pg_diag_sqlstate[4]);
|
||||
else
|
||||
sqlstate = ERRCODE_CONNECTION_FAILURE;
|
||||
|
||||
xpstrdup(message_primary, pg_diag_message_primary);
|
||||
xpstrdup(message_detail, pg_diag_message_detail);
|
||||
xpstrdup(message_hint, pg_diag_message_hint);
|
||||
xpstrdup(message_context, pg_diag_context);
|
||||
|
||||
if (res)
|
||||
PQclear(res);
|
||||
|
||||
if (conname)
|
||||
dblink_context_conname = conname;
|
||||
|
||||
ereport(level,
|
||||
(errcode(sqlstate),
|
||||
message_primary ? errmsg("%s", message_primary) : errmsg("unknown error"),
|
||||
message_detail ? errdetail("%s", message_detail) : 0,
|
||||
message_hint ? errhint("%s", message_hint) : 0,
|
||||
message_context ? errcontext("%s", message_context) : 0,
|
||||
errcontext("Error occurred on dblink connection named \"%s\": %s.",
|
||||
dblink_context_conname, dblink_context_msg)));
|
||||
}
|
||||
|
Reference in New Issue
Block a user