diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 4e29ee9407..226e737e2d 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -8,7 +8,7 @@ * Darko Prenosil * Shridhar Daithankar * - * $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))); +} diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out index 170d69c286..f2eb6aa5e2 100644 --- a/contrib/dblink/expected/dblink.out +++ b/contrib/dblink/expected/dblink.out @@ -125,9 +125,8 @@ WHERE t.a > 7; -- open a cursor with bad SQL and fail_on_error set to false SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foobar',false); -NOTICE: sql error -DETAIL: ERROR: relation "foobar" does not exist - +NOTICE: relation "foobar" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not open cursor. dblink_open ------------- ERROR @@ -194,9 +193,8 @@ FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]); -- intentionally botch a fetch SELECT * FROM dblink_fetch('rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]); -NOTICE: sql error -DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist - +NOTICE: cursor "rmt_foobar_cursor" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not fetch from cursor. a | b | c ---+---+--- (0 rows) @@ -210,9 +208,8 @@ SELECT dblink_exec('ABORT'); -- close the wrong cursor SELECT dblink_close('rmt_foobar_cursor',false); -NOTICE: sql error -DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist - +NOTICE: cursor "rmt_foobar_cursor" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not close cursor. dblink_close -------------- ERROR @@ -221,15 +218,13 @@ DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist -- should generate 'cursor "rmt_foo_cursor" not found' error SELECT * FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]); -ERROR: sql error -DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist - +ERROR: cursor "rmt_foo_cursor" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not fetch from cursor. -- this time, 'cursor "rmt_foo_cursor" not found' as a notice SELECT * FROM dblink_fetch('rmt_foo_cursor',4,false) AS t(a int, b text, c text[]); -NOTICE: sql error -DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist - +NOTICE: cursor "rmt_foo_cursor" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not fetch from cursor. a | b | c ---+---+--- (0 rows) @@ -291,9 +286,8 @@ FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[]); -- bad remote select SELECT * FROM dblink('SELECT * FROM foobar',false) AS t(a int, b text, c text[]); -NOTICE: sql error -DETAIL: ERROR: relation "foobar" does not exist - +NOTICE: relation "foobar" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not execute query. a | b | c ---+---+--- (0 rows) @@ -316,9 +310,8 @@ WHERE a = 11; -- botch a change to some other data SELECT dblink_exec('UPDATE foobar SET f3[2] = ''b99'' WHERE f1 = 11',false); -NOTICE: sql error -DETAIL: ERROR: relation "foobar" does not exist - +NOTICE: relation "foobar" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not execute command. dblink_exec ------------- ERROR @@ -378,9 +371,8 @@ WHERE t.a > 7; SELECT * FROM dblink('myconn','SELECT * FROM foobar',false) AS t(a int, b text, c text[]) WHERE t.a > 7; -NOTICE: sql error -DETAIL: ERROR: relation "foobar" does not exist - +NOTICE: relation "foobar" does not exist +CONTEXT: Error occurred on dblink connection named "unnamed": could not execute query. a | b | c ---+---+--- (0 rows) @@ -416,9 +408,8 @@ SELECT dblink_disconnect('myconn2'); -- open a cursor incorrectly SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foobar',false); -NOTICE: sql error -DETAIL: ERROR: relation "foobar" does not exist - +NOTICE: relation "foobar" does not exist +CONTEXT: Error occurred on dblink connection named "myconn": could not open cursor. dblink_open ------------- ERROR @@ -503,9 +494,8 @@ SELECT dblink_close('myconn','rmt_foo_cursor'); -- this should fail because there is no open transaction SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo'); -ERROR: sql error -DETAIL: ERROR: DECLARE CURSOR can only be used in transaction blocks - +ERROR: DECLARE CURSOR can only be used in transaction blocks +CONTEXT: Error occurred on dblink connection named "unnamed": could not execute command. -- reset remote transaction state SELECT dblink_exec('myconn','ABORT'); dblink_exec @@ -554,9 +544,8 @@ FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]); -- fetch some data incorrectly SELECT * FROM dblink_fetch('myconn','rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]); -NOTICE: sql error -DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist - +NOTICE: cursor "rmt_foobar_cursor" does not exist +CONTEXT: Error occurred on dblink connection named "myconn": could not fetch from cursor. a | b | c ---+---+--- (0 rows) @@ -571,9 +560,8 @@ SELECT dblink_exec('myconn','ABORT'); -- should generate 'cursor "rmt_foo_cursor" not found' error SELECT * FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]); -ERROR: sql error -DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist - +ERROR: cursor "rmt_foo_cursor" does not exist +CONTEXT: Error occurred on dblink connection named "myconn": could not fetch from cursor. -- close the named persistent connection SELECT dblink_disconnect('myconn'); dblink_disconnect