Tom Lane wrote:
Lines 509-512 of contrib/dblink/expected/dblink.out read:

-- 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

The error message is not consistent with what the comment claims.
Looking at the test case in total, I think the code is responding

Actually the comment was correct, but there was a bug which caused the automatically opened transaction to not get closed.

I was really expecting a "DECLARE CURSOR may only be used in transaction blocks" error there, but didn't notice that I was actually getting a different error message :-(.

The bug can be reproduced by using dblink_open to automatically open a transaction, and then using dblink_exec to manually ABORT it:

-- open a test connection
SELECT dblink_connect('myconn','dbname=contrib_regression');
 dblink_connect
----------------
 OK
(1 row)

-- open a cursor incorrectly; this bumps up the refcount
contrib_regression=# SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foobar',false);
NOTICE:  sql error
DETAIL:  ERROR:  relation "foobar" does not exist

 dblink_open
-------------
 ERROR
(1 row)

-- manually abort remote transaction; does not maintain refcount
SELECT dblink_exec('myconn','ABORT');
 dblink_exec
-------------
 ROLLBACK
(1 row)

-- test automatic transaction; this bumps up the refcount
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
 dblink_open
-------------
 OK
(1 row)

-- this should commit the automatically opened transaction
-- but it doesn't because the refcount is wrong
SELECT dblink_close('myconn','rmt_foo_cursor');
 dblink_close
--------------
 OK
(1 row)

-- this should fail because there is no open transaction
-- but it doesn't because dblink_close did not commit
SELECT dblink_exec('myconn','DECLARE xact_test2 CURSOR FOR SELECT * FROM foo');
  dblink_exec
----------------
 DECLARE CURSOR
(1 row)

I think the attached patch does the trick in a minimally invasive way. If there are no objections I'll commit to head and 8.1 stable branches. The problem doesn't exist before 8.1.

BTW, I was led to notice this while examining the current buildfarm
failure report from osprey,
http://www.pgbuildfarm.org/cgi-bin/show_log.pl?nm=osprey&dt=2006-06-17%2004:00:16
It looks to me like the diffs are consistent with the idea that the test
is using a copy of dblink that predates this patch ... do you agree?
If so, anyone have an idea how that could happen?  I thought we'd fixed
all the rpath problems, and anyway osprey wasn't failing like this
before today.

I haven't really looked at the buildfarm before -- I might be blind, but I couldn't figure out how to see the regression.diff file.

Joe


? .deps
? .regression.diffs.swp
? current.diff
? dblink.sql
? libdblink.so.0.0
? results
Index: dblink.c
===================================================================
RCS file: /cvsroot/pgsql/contrib/dblink/dblink.c,v
retrieving revision 1.55
diff -c -r1.55 dblink.c
*** dblink.c	30 May 2006 22:12:12 -0000	1.55
--- dblink.c	20 Jun 2006 16:28:01 -0000
***************
*** 361,366 ****
--- 361,373 ----
  			DBLINK_RES_INTERNALERROR("begin error");
  		PQclear(res);
  		rconn->newXactForCursor = TRUE;
+ 		/*
+ 		 * Since transaction state was IDLE, we force cursor count to
+ 		 * initially be 0. This is needed as a previous ABORT might
+ 		 * have wiped out our transaction without maintaining the
+ 		 * cursor count for us.
+ 		 */
+ 		rconn->openCursorCount = 0;
  	}
  
  	/* if we started a transaction, increment cursor count */
Index: expected/dblink.out
===================================================================
RCS file: /cvsroot/pgsql/contrib/dblink/expected/dblink.out,v
retrieving revision 1.16
diff -c -r1.16 dblink.out
*** expected/dblink.out	18 Oct 2005 02:55:49 -0000	1.16
--- expected/dblink.out	20 Jun 2006 16:28:01 -0000
***************
*** 509,515 ****
  -- 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');
--- 509,515 ----
  -- 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 may only be used in transaction blocks
  
  -- reset remote transaction state
  SELECT dblink_exec('myconn','ABORT');
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to