From: Daniele Varrazzo Date: Fri, 12 Feb 2021 02:21:35 +0000 (+0100) Subject: Set up row maker and loaders only once in a server-side cursor lifetime X-Git-Tag: 3.0.dev0~106^2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=88ac162dfa1d5fa8116c023ff06f057e8885136b;p=thirdparty%2Fpsycopg.git Set up row maker and loaders only once in a server-side cursor lifetime It wasn't happening once per movement, as I was fearing, but it was happening exactly twice: once on DECLARE, once on describe_portal(). We actually don't care about the DECLARE result: it was being set on the cursor only to detect errors, so now that's done manually. --- diff --git a/psycopg3/psycopg3/server_cursor.py b/psycopg3/psycopg3/server_cursor.py index f1386047f..851839ec7 100644 --- a/psycopg3/psycopg3/server_cursor.py +++ b/psycopg3/psycopg3/server_cursor.py @@ -61,11 +61,12 @@ class ServerCursorHelper(Generic[ConnectionType]): yield from cur._start_query(query) pgq = cur._convert_query(query, params) - cur._execute_send(pgq) + cur._execute_send(pgq, no_pqexec=True) results = yield from execute(conn.pgconn) - cur._execute_results(results) + if results[-1].status != pq.ExecStatus.COMMAND_OK: + cur._raise_from_results(results) - # The above result is an COMMAND_OK. Get the cursor result shape + # The above result only returned COMMAND_OK. Get the cursor shape yield from self._describe_gen(cur) def _describe_gen(self, cur: BaseCursor[ConnectionType]) -> PQGen[None]: diff --git a/tests/test_server_cursor.py b/tests/test_server_cursor.py index 6e908a407..a4e6c0124 100644 --- a/tests/test_server_cursor.py +++ b/tests/test_server_cursor.py @@ -151,13 +151,23 @@ def test_nextset(conn): def test_row_factory(conn): + n = 0 + def my_row_factory(cur): - return lambda values: [-v for v in values] + nonlocal n + n += 1 + return lambda values: [n] + [-v for v in values] cur = conn.cursor("foo", row_factory=my_row_factory) - cur.execute("select generate_series(1, 3)") - r = cur.fetchall() - assert r == [[-1], [-2], [-3]] + cur.execute("select generate_series(1, 3)", scrollable=True) + rows = cur.fetchall() + cur.scroll(0, "absolute") + while 1: + row = cur.fetchone() + if not row: + break + rows.append(row) + assert rows == [[1, -1], [1, -2], [1, -3]] * 2 def test_rownumber(conn): diff --git a/tests/test_server_cursor_async.py b/tests/test_server_cursor_async.py index 5625cd885..191d3dd7f 100644 --- a/tests/test_server_cursor_async.py +++ b/tests/test_server_cursor_async.py @@ -153,13 +153,23 @@ async def test_nextset(aconn): async def test_row_factory(aconn): + n = 0 + def my_row_factory(cur): - return lambda values: [-v for v in values] + nonlocal n + n += 1 + return lambda values: [n] + [-v for v in values] cur = aconn.cursor("foo", row_factory=my_row_factory) - await cur.execute("select generate_series(1, 3)") - r = await cur.fetchall() - assert r == [[-1], [-2], [-3]] + await cur.execute("select generate_series(1, 3)", scrollable=True) + rows = await cur.fetchall() + await cur.scroll(0, "absolute") + while 1: + row = await cur.fetchone() + if not row: + break + rows.append(row) + assert rows == [[1, -1], [1, -2], [1, -3]] * 2 async def test_rownumber(aconn):