dialect shares most of its behavior with the ``psycopg2`` dialect.
Further documentation is available there.
+Using a different Cursor class
+------------------------------
+
+One of the differences between ``psycopg`` and the older ``psycopg2``
+is how bound parameters are handled: ``psycopg2`` would bind them
+client side, while ``psycopg`` by default will bind them server side.
+
+It's possible to configure ``psycopg`` to do client side binding by
+specifying the ``cursor_factory`` to be ``ClientCursor`` when creating
+the engine::
+
+ from psycopg import ClientCursor
+
+ client_side_engine = create_engine(
+ "postgresql+psycopg://...",
+ connect_args={"cursor_factory": ClientCursor},
+ )
+
+Similarly when using an async engine the ``AsyncClientCursor`` can be
+specified::
+
+ from psycopg import AsyncClientCursor
+
+ client_side_engine = create_async_engine(
+ "postgresql+psycopg://...",
+ connect_args={"cursor_factory": AsyncClientCursor},
+ )
+
+.. seealso::
+
+ `Client-side-binding cursors <https://www.psycopg.org/psycopg3/docs/advanced/cursors.html#client-side-binding-cursors>`_
+
""" # noqa
from __future__ import annotations
conn.exec_driver_sql("SELECT note('another note')")
finally:
trans.rollback()
+ conn.close()
finally:
log.removeHandler(buf)
log.setLevel(lev)
def test_async_version(self):
e = create_engine("postgresql+psycopg_async://")
is_true(isinstance(e.dialect, psycopg_dialect.PGDialectAsync_psycopg))
+
+ @testing.skip_if(lambda c: c.db.dialect.is_async)
+ def test_client_side_cursor(self, testing_engine):
+ from psycopg import ClientCursor
+
+ engine = testing_engine(
+ options={"connect_args": {"cursor_factory": ClientCursor}}
+ )
+
+ with engine.connect() as c:
+ res = c.execute(select(1, 2, 3)).one()
+ eq_(res, (1, 2, 3))
+ with c.connection.driver_connection.cursor() as cursor:
+ is_true(isinstance(cursor, ClientCursor))
+
+ @config.async_test
+ @testing.skip_if(lambda c: not c.db.dialect.is_async)
+ async def test_async_client_side_cursor(self, testing_engine):
+ from psycopg import AsyncClientCursor
+
+ engine = testing_engine(
+ options={"connect_args": {"cursor_factory": AsyncClientCursor}},
+ asyncio=True,
+ )
+
+ async with engine.connect() as c:
+ res = (await c.execute(select(1, 2, 3))).one()
+ eq_(res, (1, 2, 3))
+ async with (
+ await c.get_raw_connection()
+ ).driver_connection.cursor() as cursor:
+ is_true(isinstance(cursor, AsyncClientCursor))
+
+ await engine.dispose()