Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c0241b9

Browse files
committed
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.
1 parent 0a8f6b7 commit c0241b9

File tree

2 files changed

+95
-94
lines changed

2 files changed

+95
-94
lines changed

contrib/dblink/dblink.c

Lines changed: 71 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Darko Prenosil <Darko.Prenosil@finteh.hr>
99
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
1010
*
11-
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.73 2008/04/04 17:02:56 momjian Exp $
11+
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.74 2008/07/03 03:56:57 joe Exp $
1212
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
1313
* ALL RIGHTS RESERVED;
1414
*
@@ -94,6 +94,7 @@ static HeapTuple get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 p
9494
static Oid get_relid_from_relname(text *relname_text);
9595
static char *generate_relation_name(Oid relid);
9696
static void dblink_security_check(PGconn *conn, remoteConn *rconn);
97+
static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail);
9798

9899
/* Global */
99100
static remoteConn *pconn = NULL;
@@ -125,34 +126,20 @@ typedef struct remoteConnHashEnt
125126
} \
126127
} while (0)
127128

128-
#define DBLINK_RES_INTERNALERROR(p2) \
129-
do { \
130-
msg = pstrdup(PQerrorMessage(conn)); \
131-
if (res) \
132-
PQclear(res); \
133-
elog(ERROR, "%s: %s", p2, msg); \
134-
} while (0)
135-
136-
#define DBLINK_RES_ERROR(p2) \
129+
#define xpstrdup(var_c, var_) \
137130
do { \
138-
msg = pstrdup(PQerrorMessage(conn)); \
139-
if (res) \
140-
PQclear(res); \
141-
ereport(ERROR, \
142-
(errcode(ERRCODE_SYNTAX_ERROR), \
143-
errmsg("%s", p2), \
144-
errdetail("%s", msg))); \
131+
if (var_ != NULL) \
132+
var_c = pstrdup(var_); \
133+
else \
134+
var_c = NULL; \
145135
} while (0)
146136

147-
#define DBLINK_RES_ERROR_AS_NOTICE(p2) \
137+
#define DBLINK_RES_INTERNALERROR(p2) \
148138
do { \
149139
msg = pstrdup(PQerrorMessage(conn)); \
150140
if (res) \
151141
PQclear(res); \
152-
ereport(NOTICE, \
153-
(errcode(ERRCODE_SYNTAX_ERROR), \
154-
errmsg("%s", p2), \
155-
errdetail("%s", msg))); \
142+
elog(ERROR, "%s: %s", p2, msg); \
156143
} while (0)
157144

158145
#define DBLINK_CONN_NOT_AVAIL \
@@ -396,13 +383,8 @@ dblink_open(PG_FUNCTION_ARGS)
396383
res = PQexec(conn, buf.data);
397384
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
398385
{
399-
if (fail)
400-
DBLINK_RES_ERROR("sql error");
401-
else
402-
{
403-
DBLINK_RES_ERROR_AS_NOTICE("sql error");
404-
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
405-
}
386+
dblink_res_error(conname, res, "could not open cursor", fail);
387+
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
406388
}
407389

408390
PQclear(res);
@@ -470,13 +452,8 @@ dblink_close(PG_FUNCTION_ARGS)
470452
res = PQexec(conn, buf.data);
471453
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
472454
{
473-
if (fail)
474-
DBLINK_RES_ERROR("sql error");
475-
else
476-
{
477-
DBLINK_RES_ERROR_AS_NOTICE("sql error");
478-
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
479-
}
455+
dblink_res_error(conname, res, "could not close cursor", fail);
456+
PG_RETURN_TEXT_P(cstring_to_text("ERROR"));
480457
}
481458

482459
PQclear(res);
@@ -513,7 +490,6 @@ dblink_fetch(PG_FUNCTION_ARGS)
513490
int call_cntr;
514491
int max_calls;
515492
AttInMetadata *attinmeta;
516-
char *msg;
517493
PGresult *res = NULL;
518494
MemoryContext oldcontext;
519495
char *conname = NULL;
@@ -590,13 +566,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
590566
(PQresultStatus(res) != PGRES_COMMAND_OK &&
591567
PQresultStatus(res) != PGRES_TUPLES_OK))
592568
{
593-
if (fail)
594-
DBLINK_RES_ERROR("sql error");
595-
else
596-
{
597-
DBLINK_RES_ERROR_AS_NOTICE("sql error");
598-
SRF_RETURN_DONE(funcctx);
599-
}
569+
dblink_res_error(conname, res, "could not fetch from cursor", fail);
570+
SRF_RETURN_DONE(funcctx);
600571
}
601572
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
602573
{
@@ -846,15 +817,10 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
846817
(PQresultStatus(res) != PGRES_COMMAND_OK &&
847818
PQresultStatus(res) != PGRES_TUPLES_OK))
848819
{
849-
if (fail)
850-
DBLINK_RES_ERROR("sql error");
851-
else
852-
{
853-
DBLINK_RES_ERROR_AS_NOTICE("sql error");
854-
if (freeconn)
855-
PQfinish(conn);
856-
SRF_RETURN_DONE(funcctx);
857-
}
820+
dblink_res_error(conname, res, "could not execute query", fail);
821+
if (freeconn)
822+
PQfinish(conn);
823+
SRF_RETURN_DONE(funcctx);
858824
}
859825

860826
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -1180,10 +1146,7 @@ dblink_exec(PG_FUNCTION_ARGS)
11801146
(PQresultStatus(res) != PGRES_COMMAND_OK &&
11811147
PQresultStatus(res) != PGRES_TUPLES_OK))
11821148
{
1183-
if (fail)
1184-
DBLINK_RES_ERROR("sql error");
1185-
else
1186-
DBLINK_RES_ERROR_AS_NOTICE("sql error");
1149+
dblink_res_error(conname, res, "could not execute command", fail);
11871150

11881151
/* need a tuple descriptor representing one TEXT column */
11891152
tupdesc = CreateTemplateTupleDesc(1, false);
@@ -1195,7 +1158,6 @@ dblink_exec(PG_FUNCTION_ARGS)
11951158
* result tuple
11961159
*/
11971160
sql_cmd_status = cstring_to_text("ERROR");
1198-
11991161
}
12001162
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
12011163
{
@@ -2288,3 +2250,54 @@ dblink_security_check(PGconn *conn, remoteConn *rconn)
22882250
}
22892251
}
22902252
}
2253+
2254+
static void
2255+
dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail)
2256+
{
2257+
int level;
2258+
char *pg_diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
2259+
char *pg_diag_message_primary = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
2260+
char *pg_diag_message_detail = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
2261+
char *pg_diag_message_hint = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
2262+
char *pg_diag_context = PQresultErrorField(res, PG_DIAG_CONTEXT);
2263+
int sqlstate;
2264+
char *message_primary;
2265+
char *message_detail;
2266+
char *message_hint;
2267+
char *message_context;
2268+
const char *dblink_context_conname = "unnamed";
2269+
2270+
if (fail)
2271+
level = ERROR;
2272+
else
2273+
level = NOTICE;
2274+
2275+
if (pg_diag_sqlstate)
2276+
sqlstate = MAKE_SQLSTATE(pg_diag_sqlstate[0],
2277+
pg_diag_sqlstate[1],
2278+
pg_diag_sqlstate[2],
2279+
pg_diag_sqlstate[3],
2280+
pg_diag_sqlstate[4]);
2281+
else
2282+
sqlstate = ERRCODE_CONNECTION_FAILURE;
2283+
2284+
xpstrdup(message_primary, pg_diag_message_primary);
2285+
xpstrdup(message_detail, pg_diag_message_detail);
2286+
xpstrdup(message_hint, pg_diag_message_hint);
2287+
xpstrdup(message_context, pg_diag_context);
2288+
2289+
if (res)
2290+
PQclear(res);
2291+
2292+
if (conname)
2293+
dblink_context_conname = conname;
2294+
2295+
ereport(level,
2296+
(errcode(sqlstate),
2297+
message_primary ? errmsg("%s", message_primary) : errmsg("unknown error"),
2298+
message_detail ? errdetail("%s", message_detail) : 0,
2299+
message_hint ? errhint("%s", message_hint) : 0,
2300+
message_context ? errcontext("%s", message_context) : 0,
2301+
errcontext("Error occurred on dblink connection named \"%s\": %s.",
2302+
dblink_context_conname, dblink_context_msg)));
2303+
}

contrib/dblink/expected/dblink.out

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,8 @@ WHERE t.a > 7;
125125

126126
-- open a cursor with bad SQL and fail_on_error set to false
127127
SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foobar',false);
128-
NOTICE: sql error
129-
DETAIL: ERROR: relation "foobar" does not exist
130-
128+
NOTICE: relation "foobar" does not exist
129+
CONTEXT: Error occurred on dblink connection named "unnamed": could not open cursor.
131130
dblink_open
132131
-------------
133132
ERROR
@@ -194,9 +193,8 @@ FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
194193
-- intentionally botch a fetch
195194
SELECT *
196195
FROM dblink_fetch('rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
197-
NOTICE: sql error
198-
DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist
199-
196+
NOTICE: cursor "rmt_foobar_cursor" does not exist
197+
CONTEXT: Error occurred on dblink connection named "unnamed": could not fetch from cursor.
200198
a | b | c
201199
---+---+---
202200
(0 rows)
@@ -210,9 +208,8 @@ SELECT dblink_exec('ABORT');
210208

211209
-- close the wrong cursor
212210
SELECT dblink_close('rmt_foobar_cursor',false);
213-
NOTICE: sql error
214-
DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist
215-
211+
NOTICE: cursor "rmt_foobar_cursor" does not exist
212+
CONTEXT: Error occurred on dblink connection named "unnamed": could not close cursor.
216213
dblink_close
217214
--------------
218215
ERROR
@@ -221,15 +218,13 @@ DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist
221218
-- should generate 'cursor "rmt_foo_cursor" not found' error
222219
SELECT *
223220
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
224-
ERROR: sql error
225-
DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist
226-
221+
ERROR: cursor "rmt_foo_cursor" does not exist
222+
CONTEXT: Error occurred on dblink connection named "unnamed": could not fetch from cursor.
227223
-- this time, 'cursor "rmt_foo_cursor" not found' as a notice
228224
SELECT *
229225
FROM dblink_fetch('rmt_foo_cursor',4,false) AS t(a int, b text, c text[]);
230-
NOTICE: sql error
231-
DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist
232-
226+
NOTICE: cursor "rmt_foo_cursor" does not exist
227+
CONTEXT: Error occurred on dblink connection named "unnamed": could not fetch from cursor.
233228
a | b | c
234229
---+---+---
235230
(0 rows)
@@ -291,9 +286,8 @@ FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[]);
291286
-- bad remote select
292287
SELECT *
293288
FROM dblink('SELECT * FROM foobar',false) AS t(a int, b text, c text[]);
294-
NOTICE: sql error
295-
DETAIL: ERROR: relation "foobar" does not exist
296-
289+
NOTICE: relation "foobar" does not exist
290+
CONTEXT: Error occurred on dblink connection named "unnamed": could not execute query.
297291
a | b | c
298292
---+---+---
299293
(0 rows)
@@ -316,9 +310,8 @@ WHERE a = 11;
316310

317311
-- botch a change to some other data
318312
SELECT dblink_exec('UPDATE foobar SET f3[2] = ''b99'' WHERE f1 = 11',false);
319-
NOTICE: sql error
320-
DETAIL: ERROR: relation "foobar" does not exist
321-
313+
NOTICE: relation "foobar" does not exist
314+
CONTEXT: Error occurred on dblink connection named "unnamed": could not execute command.
322315
dblink_exec
323316
-------------
324317
ERROR
@@ -378,9 +371,8 @@ WHERE t.a > 7;
378371
SELECT *
379372
FROM dblink('myconn','SELECT * FROM foobar',false) AS t(a int, b text, c text[])
380373
WHERE t.a > 7;
381-
NOTICE: sql error
382-
DETAIL: ERROR: relation "foobar" does not exist
383-
374+
NOTICE: relation "foobar" does not exist
375+
CONTEXT: Error occurred on dblink connection named "unnamed": could not execute query.
384376
a | b | c
385377
---+---+---
386378
(0 rows)
@@ -416,9 +408,8 @@ SELECT dblink_disconnect('myconn2');
416408

417409
-- open a cursor incorrectly
418410
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foobar',false);
419-
NOTICE: sql error
420-
DETAIL: ERROR: relation "foobar" does not exist
421-
411+
NOTICE: relation "foobar" does not exist
412+
CONTEXT: Error occurred on dblink connection named "myconn": could not open cursor.
422413
dblink_open
423414
-------------
424415
ERROR
@@ -503,9 +494,8 @@ SELECT dblink_close('myconn','rmt_foo_cursor');
503494

504495
-- this should fail because there is no open transaction
505496
SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo');
506-
ERROR: sql error
507-
DETAIL: ERROR: DECLARE CURSOR can only be used in transaction blocks
508-
497+
ERROR: DECLARE CURSOR can only be used in transaction blocks
498+
CONTEXT: Error occurred on dblink connection named "unnamed": could not execute command.
509499
-- reset remote transaction state
510500
SELECT dblink_exec('myconn','ABORT');
511501
dblink_exec
@@ -554,9 +544,8 @@ FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
554544
-- fetch some data incorrectly
555545
SELECT *
556546
FROM dblink_fetch('myconn','rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
557-
NOTICE: sql error
558-
DETAIL: ERROR: cursor "rmt_foobar_cursor" does not exist
559-
547+
NOTICE: cursor "rmt_foobar_cursor" does not exist
548+
CONTEXT: Error occurred on dblink connection named "myconn": could not fetch from cursor.
560549
a | b | c
561550
---+---+---
562551
(0 rows)
@@ -571,9 +560,8 @@ SELECT dblink_exec('myconn','ABORT');
571560
-- should generate 'cursor "rmt_foo_cursor" not found' error
572561
SELECT *
573562
FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
574-
ERROR: sql error
575-
DETAIL: ERROR: cursor "rmt_foo_cursor" does not exist
576-
563+
ERROR: cursor "rmt_foo_cursor" does not exist
564+
CONTEXT: Error occurred on dblink connection named "myconn": could not fetch from cursor.
577565
-- close the named persistent connection
578566
SELECT dblink_disconnect('myconn');
579567
dblink_disconnect

0 commit comments

Comments
 (0)