Re: [HACKERS] Patching dblink.c to avoid warning about - Mailing list pgsql-patches
From | Joe Conway |
---|---|
Subject | Re: [HACKERS] Patching dblink.c to avoid warning about |
Date | |
Msg-id | 4351B747.20701@joeconway.com Whole thread Raw |
In response to | Re: [HACKERS] Patching dblink.c to avoid warning about open (Bruce Momjian <pgman@candle.pha.pa.us>) |
Responses |
Re: [HACKERS] Patching dblink.c to avoid warning about open transaction
|
List | pgsql-patches |
Bruce Momjian wrote: > No problem -- thanks. I have slimmed down the patch by applying the > cosmetic parts to CVS. Use the URL above to get the newest versions of > the dblink.c and regression changes. > Here is my counter-proposal to Bruce's dblink patch. Any comments? Is it too late to apply this for 8.1? I tend to agree with calling this a bugfix. Thanks, Joe Index: dblink.c =================================================================== RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.c,v retrieving revision 1.47 diff -c -r1.47 dblink.c *** dblink.c 15 Oct 2005 02:49:04 -0000 1.47 --- dblink.c 16 Oct 2005 02:04:13 -0000 *************** *** 60,68 **** typedef struct remoteConn { ! PGconn *conn; /* Hold the remote connection */ ! int autoXactCursors;/* Indicates the number of open cursors, ! * non-zero means we opened the xact ourselves */ } remoteConn; /* --- 60,68 ---- typedef struct remoteConn { ! PGconn *conn; /* Hold the remote connection */ ! int openCursorCount; /* The number of open cursors */ ! bool newXactForCursor; /* Opened a transaction for a cursor */ } remoteConn; /* *************** *** 84,93 **** static char *generate_relation_name(Oid relid); /* Global */ ! List *res_id = NIL; ! int res_id_index = 0; ! PGconn *persistent_conn = NULL; ! static HTAB *remoteConnHash = NULL; /* * Following is list that holds multiple remote connections. --- 84,91 ---- static char *generate_relation_name(Oid relid); /* Global */ ! static remoteConn *pconn = NULL; ! static HTAB *remoteConnHash = NULL; /* * Following is list that holds multiple remote connections. *************** *** 184,189 **** --- 182,197 ---- } \ } while (0) + #define DBLINK_INIT \ + do { \ + if (!pconn) \ + { \ + pconn = (remoteConn *) MemoryContextAlloc(TopMemoryContext, sizeof(remoteConn)); \ + pconn->conn = NULL; \ + pconn->openCursorCount = 0; \ + pconn->newXactForCursor = FALSE; \ + } \ + } while (0) /* * Create a persistent connection to another database *************** *** 199,204 **** --- 207,214 ---- PGconn *conn = NULL; remoteConn *rconn = NULL; + DBLINK_INIT; + if (PG_NARGS() == 2) { connstr = GET_STR(PG_GETARG_TEXT_P(1)); *************** *** 234,240 **** createNewConnection(connname, rconn); } else ! persistent_conn = conn; PG_RETURN_TEXT_P(GET_TEXT("OK")); } --- 244,250 ---- createNewConnection(connname, rconn); } else ! pconn->conn = conn; PG_RETURN_TEXT_P(GET_TEXT("OK")); } *************** *** 250,255 **** --- 260,267 ---- remoteConn *rconn = NULL; PGconn *conn = NULL; + DBLINK_INIT; + if (PG_NARGS() == 1) { conname = GET_STR(PG_GETARG_TEXT_P(0)); *************** *** 258,264 **** conn = rconn->conn; } else ! conn = persistent_conn; if (!conn) DBLINK_CONN_NOT_AVAIL; --- 270,276 ---- conn = rconn->conn; } else ! conn = pconn->conn; if (!conn) DBLINK_CONN_NOT_AVAIL; *************** *** 270,276 **** pfree(rconn); } else ! persistent_conn = NULL; PG_RETURN_TEXT_P(GET_TEXT("OK")); } --- 282,288 ---- pfree(rconn); } else ! pconn->conn = NULL; PG_RETURN_TEXT_P(GET_TEXT("OK")); } *************** *** 285,290 **** --- 297,304 ---- char *msg; PGresult *res = NULL; PGconn *conn = NULL; + int *openCursorCount = NULL; + bool *newXactForCursor = NULL; char *curname = NULL; char *sql = NULL; char *conname = NULL; *************** *** 292,303 **** remoteConn *rconn = NULL; bool fail = true; /* default to backward compatible behavior */ if (PG_NARGS() == 2) { /* text,text */ curname = GET_STR(PG_GETARG_TEXT_P(0)); sql = GET_STR(PG_GETARG_TEXT_P(1)); ! conn = persistent_conn; } else if (PG_NARGS() == 3) { --- 306,321 ---- remoteConn *rconn = NULL; bool fail = true; /* default to backward compatible behavior */ + DBLINK_INIT; + if (PG_NARGS() == 2) { /* text,text */ curname = GET_STR(PG_GETARG_TEXT_P(0)); sql = GET_STR(PG_GETARG_TEXT_P(1)); ! conn = pconn->conn; ! openCursorCount = &pconn->openCursorCount; ! newXactForCursor = &pconn->newXactForCursor; } else if (PG_NARGS() == 3) { *************** *** 307,313 **** curname = GET_STR(PG_GETARG_TEXT_P(0)); sql = GET_STR(PG_GETARG_TEXT_P(1)); fail = PG_GETARG_BOOL(2); ! conn = persistent_conn; } else { --- 325,333 ---- curname = GET_STR(PG_GETARG_TEXT_P(0)); sql = GET_STR(PG_GETARG_TEXT_P(1)); fail = PG_GETARG_BOOL(2); ! conn = pconn->conn; ! openCursorCount = &pconn->openCursorCount; ! newXactForCursor = &pconn->newXactForCursor; } else { *************** *** 316,322 **** --- 336,346 ---- sql = GET_STR(PG_GETARG_TEXT_P(2)); rconn = getConnectionByName(conname); if (rconn) + { conn = rconn->conn; + openCursorCount = &rconn->openCursorCount; + newXactForCursor = &rconn->newXactForCursor; + } } } else if (PG_NARGS() == 4) *************** *** 328,344 **** fail = PG_GETARG_BOOL(3); rconn = getConnectionByName(conname); if (rconn) conn = rconn->conn; } if (!conn) DBLINK_CONN_NOT_AVAIL; ! res = PQexec(conn, "BEGIN"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) ! DBLINK_RES_INTERNALERROR("begin error"); ! PQclear(res); appendStringInfo(str, "DECLARE %s CURSOR FOR %s", curname, sql); res = PQexec(conn, str->data); --- 352,380 ---- fail = PG_GETARG_BOOL(3); rconn = getConnectionByName(conname); if (rconn) + { conn = rconn->conn; + openCursorCount = &rconn->openCursorCount; + newXactForCursor = &rconn->newXactForCursor; + } } if (!conn) DBLINK_CONN_NOT_AVAIL; ! /* If we are not in a transaction, start one */ ! if (PQtransactionStatus(conn) == PQTRANS_IDLE) ! { ! res = PQexec(conn, "BEGIN"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) ! DBLINK_RES_INTERNALERROR("begin error"); ! PQclear(res); ! *newXactForCursor = TRUE; ! } ! /* if we started a transaction, increment cursor count */ ! if (*newXactForCursor) ! (*openCursorCount)++; appendStringInfo(str, "DECLARE %s CURSOR FOR %s", curname, sql); res = PQexec(conn, str->data); *************** *** 365,370 **** --- 401,408 ---- dblink_close(PG_FUNCTION_ARGS) { PGconn *conn = NULL; + int *openCursorCount = NULL; + bool *newXactForCursor = NULL; PGresult *res = NULL; char *curname = NULL; char *conname = NULL; *************** *** 373,383 **** remoteConn *rconn = NULL; bool fail = true; /* default to backward compatible behavior */ if (PG_NARGS() == 1) { /* text */ curname = GET_STR(PG_GETARG_TEXT_P(0)); ! conn = persistent_conn; } else if (PG_NARGS() == 2) { --- 411,425 ---- remoteConn *rconn = NULL; bool fail = true; /* default to backward compatible behavior */ + DBLINK_INIT; + if (PG_NARGS() == 1) { /* text */ curname = GET_STR(PG_GETARG_TEXT_P(0)); ! conn = pconn->conn; ! openCursorCount = &pconn->openCursorCount; ! newXactForCursor = &pconn->newXactForCursor; } else if (PG_NARGS() == 2) { *************** *** 386,392 **** { curname = GET_STR(PG_GETARG_TEXT_P(0)); fail = PG_GETARG_BOOL(1); ! conn = persistent_conn; } else { --- 428,436 ---- { curname = GET_STR(PG_GETARG_TEXT_P(0)); fail = PG_GETARG_BOOL(1); ! conn = pconn->conn; ! openCursorCount = &pconn->openCursorCount; ! newXactForCursor = &pconn->newXactForCursor; } else { *************** *** 394,400 **** --- 438,448 ---- curname = GET_STR(PG_GETARG_TEXT_P(1)); rconn = getConnectionByName(conname); if (rconn) + { conn = rconn->conn; + openCursorCount = &rconn->openCursorCount; + newXactForCursor = &rconn->newXactForCursor; + } } } if (PG_NARGS() == 3) *************** *** 405,411 **** --- 453,463 ---- fail = PG_GETARG_BOOL(2); rconn = getConnectionByName(conname); if (rconn) + { conn = rconn->conn; + openCursorCount = &rconn->openCursorCount; + newXactForCursor = &rconn->newXactForCursor; + } } if (!conn) *************** *** 428,439 **** PQclear(res); ! /* commit the transaction */ ! res = PQexec(conn, "COMMIT"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) ! DBLINK_RES_INTERNALERROR("commit error"); ! PQclear(res); PG_RETURN_TEXT_P(GET_TEXT("OK")); } --- 480,501 ---- PQclear(res); ! /* if we started a transaction, decrement cursor count */ ! if (*newXactForCursor) ! { ! (*openCursorCount)--; ! /* if count is zero, commit the transaction */ ! if (*openCursorCount == 0) ! { ! *newXactForCursor = FALSE; ! ! res = PQexec(conn, "COMMIT"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) ! DBLINK_RES_INTERNALERROR("commit error"); ! PQclear(res); ! } ! } PG_RETURN_TEXT_P(GET_TEXT("OK")); } *************** *** 456,461 **** --- 518,525 ---- char *conname = NULL; remoteConn *rconn = NULL; + DBLINK_INIT; + /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { *************** *** 485,491 **** curname = GET_STR(PG_GETARG_TEXT_P(0)); howmany = PG_GETARG_INT32(1); fail = PG_GETARG_BOOL(2); ! conn = persistent_conn; } else { --- 549,555 ---- curname = GET_STR(PG_GETARG_TEXT_P(0)); howmany = PG_GETARG_INT32(1); fail = PG_GETARG_BOOL(2); ! conn = pconn->conn; } else { *************** *** 503,509 **** /* text,int */ curname = GET_STR(PG_GETARG_TEXT_P(0)); howmany = PG_GETARG_INT32(1); ! conn = persistent_conn; } if (!conn) --- 567,573 ---- /* text,int */ curname = GET_STR(PG_GETARG_TEXT_P(0)); howmany = PG_GETARG_INT32(1); ! conn = pconn->conn; } if (!conn) *************** *** 648,653 **** --- 712,719 ---- MemoryContext oldcontext; bool freeconn = false; + DBLINK_INIT; + /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { *************** *** 678,684 **** /* text,text or text,bool */ if (get_fn_expr_argtype(fcinfo->flinfo, 1) == BOOLOID) { ! conn = persistent_conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); fail = PG_GETARG_BOOL(1); } --- 744,750 ---- /* text,text or text,bool */ if (get_fn_expr_argtype(fcinfo->flinfo, 1) == BOOLOID) { ! conn = pconn->conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); fail = PG_GETARG_BOOL(1); } *************** *** 691,697 **** else if (PG_NARGS() == 1) { /* text */ ! conn = persistent_conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); } else --- 757,763 ---- else if (PG_NARGS() == 1) { /* text */ ! conn = pconn->conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); } else *************** *** 857,862 **** --- 923,930 ---- bool freeconn = false; bool fail = true; /* default to backward compatible behavior */ + DBLINK_INIT; + if (PG_NARGS() == 3) { /* must be text,text,bool */ *************** *** 869,875 **** /* might be text,text or text,bool */ if (get_fn_expr_argtype(fcinfo->flinfo, 1) == BOOLOID) { ! conn = persistent_conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); fail = PG_GETARG_BOOL(1); } --- 937,943 ---- /* might be text,text or text,bool */ if (get_fn_expr_argtype(fcinfo->flinfo, 1) == BOOLOID) { ! conn = pconn->conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); fail = PG_GETARG_BOOL(1); } *************** *** 882,888 **** else if (PG_NARGS() == 1) { /* must be single text argument */ ! conn = persistent_conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); } else --- 950,956 ---- else if (PG_NARGS() == 1) { /* must be single text argument */ ! conn = pconn->conn; sql = GET_STR(PG_GETARG_TEXT_P(0)); } else Index: expected/dblink.out =================================================================== RCS file: /opt/src/cvs/pgsql/contrib/dblink/expected/dblink.out,v retrieving revision 1.15 diff -c -r1.15 dblink.out *** expected/dblink.out 8 Oct 2005 16:10:38 -0000 1.15 --- expected/dblink.out 16 Oct 2005 02:05:28 -0000 *************** *** 436,441 **** --- 436,523 ---- ROLLBACK (1 row) + -- test opening cursor in a transaction + SELECT dblink_exec('myconn','BEGIN'); + dblink_exec + ------------- + BEGIN + (1 row) + + -- an open transaction will prevent dblink_open() from opening its own + SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo'); + dblink_open + ------------- + OK + (1 row) + + -- this should not commit the transaction because the client opened it + SELECT dblink_close('myconn','rmt_foo_cursor'); + dblink_close + -------------- + OK + (1 row) + + -- this should succeed because we have an open transaction + SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo'); + dblink_exec + ---------------- + DECLARE CURSOR + (1 row) + + -- commit remote transaction + SELECT dblink_exec('myconn','COMMIT'); + dblink_exec + ------------- + COMMIT + (1 row) + + -- test automatic transactions for multiple cursor opens + SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo'); + dblink_open + ------------- + OK + (1 row) + + -- the second cursor + SELECT dblink_open('myconn','rmt_foo_cursor2','SELECT * FROM foo'); + dblink_open + ------------- + OK + (1 row) + + -- this should not commit the transaction + SELECT dblink_close('myconn','rmt_foo_cursor2'); + dblink_close + -------------- + OK + (1 row) + + -- this should succeed because we have an open transaction + SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo'); + dblink_exec + ---------------- + DECLARE CURSOR + (1 row) + + -- this should commit the transaction + SELECT dblink_close('myconn','rmt_foo_cursor'); + dblink_close + -------------- + OK + (1 row) + + -- 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: cursor "xact_test" already exists + + -- reset remote transaction state + SELECT dblink_exec('myconn','ABORT'); + dblink_exec + ------------- + ROLLBACK + (1 row) + -- open a cursor SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo'); dblink_open Index: sql/dblink.sql =================================================================== RCS file: /opt/src/cvs/pgsql/contrib/dblink/sql/dblink.sql,v retrieving revision 1.14 diff -c -r1.14 dblink.sql *** sql/dblink.sql 8 Oct 2005 16:10:38 -0000 1.14 --- sql/dblink.sql 16 Oct 2005 01:59:11 -0000 *************** *** 217,222 **** --- 217,258 ---- -- reset remote transaction state SELECT dblink_exec('myconn','ABORT'); + -- test opening cursor in a transaction + SELECT dblink_exec('myconn','BEGIN'); + + -- an open transaction will prevent dblink_open() from opening its own + SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo'); + + -- this should not commit the transaction because the client opened it + SELECT dblink_close('myconn','rmt_foo_cursor'); + + -- this should succeed because we have an open transaction + SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo'); + + -- commit remote transaction + SELECT dblink_exec('myconn','COMMIT'); + + -- test automatic transactions for multiple cursor opens + SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo'); + + -- the second cursor + SELECT dblink_open('myconn','rmt_foo_cursor2','SELECT * FROM foo'); + + -- this should not commit the transaction + SELECT dblink_close('myconn','rmt_foo_cursor2'); + + -- this should succeed because we have an open transaction + SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo'); + + -- this should commit the transaction + 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'); + + -- reset remote transaction state + SELECT dblink_exec('myconn','ABORT'); + -- open a cursor SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
pgsql-patches by date: