From: Daniele Varrazzo Date: Thu, 12 May 2022 21:47:46 +0000 (+0200) Subject: fix: don't forbid all PQexec queries in client-side cursors X-Git-Tag: 3.1~99^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=70a3e00c676c8f57d747ce9b4c0629fcd5d3e613;p=thirdparty%2Fpsycopg.git fix: don't forbid all PQexec queries in client-side cursors We can still use PQexecParams with an empty list of parameters. This has advantages, such as the possibility of implementing stream(), and less faffing with differences between Cursor and ClientCursor. --- diff --git a/psycopg/psycopg/client_cursor.py b/psycopg/psycopg/client_cursor.py index 851b1cec6..a61d10234 100644 --- a/psycopg/psycopg/client_cursor.py +++ b/psycopg/psycopg/client_cursor.py @@ -49,20 +49,23 @@ class ClientCursorMixin(BaseCursor[ConnectionType, Row]): "client-side cursors don't support binary results" ) - if no_pqexec: - raise e.NotSupportedError( - "PQexec operations not supported by client-side cursors" - ) - self._query = query - # if we don't have to, let's use exec_ as it can run more than - # one query in one go - if self._conn._pipeline: - self._conn._pipeline.command_queue.append( - partial(self._pgconn.send_query, query.query) - ) + if no_pqexec: + if self._conn._pipeline: + self._conn._pipeline.command_queue.append( + partial(self._pgconn.send_query_params, None) + ) + else: + self._pgconn.send_query_params(query.query, None) else: - self._pgconn.send_query(query.query) + # if we don't have to, let's use exec_ as it can run more than + # one query in one go + if self._conn._pipeline: + self._conn._pipeline.command_queue.append( + partial(self._pgconn.send_query, query.query) + ) + else: + self._pgconn.send_query(query.query) def _convert_query( self, query: Query, params: Optional[Params] = None @@ -76,9 +79,6 @@ class ClientCursorMixin(BaseCursor[ConnectionType, Row]): ) -> Tuple[Prepare, bytes]: return (Prepare.NO, b"") - def _is_pipeline_supported(self) -> bool: - return False - class ClientCursor(ClientCursorMixin["Connection[Row]", Row], Cursor[Row]): pass diff --git a/psycopg/psycopg/cursor.py b/psycopg/psycopg/cursor.py index 12db07a3f..26d161143 100644 --- a/psycopg/psycopg/cursor.py +++ b/psycopg/psycopg/cursor.py @@ -726,7 +726,7 @@ class Cursor(BaseCursor["Connection[Any]", Row]): Execute the same command with a sequence of input data. """ try: - if self._is_pipeline_supported(): + if Pipeline.is_supported(): # If there is already a pipeline, ride it, in order to avoid # sending unnecessary Sync. with self._conn.lock: @@ -749,9 +749,6 @@ class Cursor(BaseCursor["Connection[Any]", Row]): except e.Error as ex: raise ex.with_traceback(None) - def _is_pipeline_supported(self) -> bool: - return Pipeline.is_supported() - def stream( self, query: Query, diff --git a/tests/test_client_cursor.py b/tests/test_client_cursor.py index dc5b22edb..c2db78750 100644 --- a/tests/test_client_cursor.py +++ b/tests/test_client_cursor.py @@ -583,12 +583,14 @@ def test_query_params_executemany(conn): def test_stream(conn): cur = conn.cursor() - with pytest.raises(psycopg.NotSupportedError): - for rec in cur.stream( - "select i, '2021-01-01'::date + i from generate_series(1, %s) as i", - [2], - ): - pass + recs = [] + for rec in cur.stream( + "select i, '2021-01-01'::date + i from generate_series(1, %s) as i", + [2], + ): + recs.append(rec) + + assert recs == [(1, dt.date(2021, 1, 2)), (2, dt.date(2021, 1, 3))] class TestColumn: diff --git a/tests/test_client_cursor_async.py b/tests/test_client_cursor_async.py index f4d7dc8bb..af8307ac9 100644 --- a/tests/test_client_cursor_async.py +++ b/tests/test_client_cursor_async.py @@ -577,12 +577,14 @@ async def test_query_params_executemany(aconn): async def test_stream(aconn): cur = aconn.cursor() - with pytest.raises(psycopg.NotSupportedError): - async for rec in cur.stream( - "select i, '2021-01-01'::date + i from generate_series(1, %s) as i", - [2], - ): - pass + recs = [] + async for rec in cur.stream( + "select i, '2021-01-01'::date + i from generate_series(1, %s) as i", + [2], + ): + recs.append(rec) + + assert recs == [(1, dt.date(2021, 1, 2)), (2, dt.date(2021, 1, 3))] async def test_str(aconn):