From: Daniele Varrazzo Date: Wed, 10 Feb 2021 17:50:03 +0000 (+0100) Subject: Make sue ServerCursor.execute() can be used more than once X-Git-Tag: 3.0.dev0~115^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e38d1460f6f8f87ecfb789c6053100c5881afd64;p=thirdparty%2Fpsycopg.git Make sue ServerCursor.execute() can be used more than once --- diff --git a/psycopg3/psycopg3/server_cursor.py b/psycopg3/psycopg3/server_cursor.py index 289485edc..e0e66e999 100644 --- a/psycopg3/psycopg3/server_cursor.py +++ b/psycopg3/psycopg3/server_cursor.py @@ -53,6 +53,12 @@ class ServerCursorHelper(Generic[ConnectionType]): ) -> PQGen[None]: """Generator implementing `ServerCursor.execute()`.""" conn = cur._conn + + # If the cursor is being reused, the previous one must be closed. + if self.described: + yield from self._close_gen(cur) + self.described = False + yield from cur._start_query(query) pgq = cur._convert_query(query, params) cur._execute_send(pgq) diff --git a/tests/test_server_cursor.py b/tests/test_server_cursor.py index ff9c2559b..78d456507 100644 --- a/tests/test_server_cursor.py +++ b/tests/test_server_cursor.py @@ -94,6 +94,20 @@ def test_warn_close(conn, recwarn): assert ".close()" in str(recwarn.pop(ResourceWarning).message) +def test_execute_reuse(conn): + with conn.cursor("foo") as cur: + cur.execute("select generate_series(1, %s) as foo", (3,)) + assert cur.fetchone() == (1,) + + cur.execute( + "select %s::text as bar, %s::text as baz", ("hello", "world") + ) + assert cur.fetchone() == ("hello", "world") + assert cur.description[0].name == "bar" + assert cur.description[0].type_code == cur.adapters.types["text"].oid + assert cur.description[1].name == "baz" + + def test_executemany(conn): cur = conn.cursor("foo") with pytest.raises(e.NotSupportedError): diff --git a/tests/test_server_cursor_async.py b/tests/test_server_cursor_async.py index 685c55928..4a3465535 100644 --- a/tests/test_server_cursor_async.py +++ b/tests/test_server_cursor_async.py @@ -96,6 +96,20 @@ async def test_warn_close(aconn, recwarn): assert ".close()" in str(recwarn.pop(ResourceWarning).message) +async def test_execute_reuse(aconn): + async with aconn.cursor("foo") as cur: + await cur.execute("select generate_series(1, %s) as foo", (3,)) + assert await cur.fetchone() == (1,) + + await cur.execute( + "select %s::text as bar, %s::text as baz", ("hello", "world") + ) + assert await cur.fetchone() == ("hello", "world") + assert cur.description[0].name == "bar" + assert cur.description[0].type_code == cur.adapters.types["text"].oid + assert cur.description[1].name == "baz" + + async def test_executemany(aconn): cur = aconn.cursor("foo") with pytest.raises(e.NotSupportedError):