cur.pgresult = res
return cur._tx.load_rows(0, res.ntuples)
+ def _scroll_gen(self, value: int, mode: str) -> PQGen[None]:
+ if mode not in ("relative", "absolute"):
+ raise ValueError(
+ f"bad mode: {mode}. It should be 'relative' or 'absolute'"
+ )
+ query = sql.SQL("move{} {} from {}").format(
+ sql.SQL(" absolute" if mode == "absolute" else ""),
+ sql.Literal(value),
+ sql.Identifier(self.name),
+ )
+ cur = self._cur
+ yield from cur._conn._exec_command(query)
+
def _make_declare_statement(
self, query: Query, scrollable: bool, hold: bool
) -> sql.Composable:
if len(recs) < self.itersize:
break
+ def scroll(self, value: int, mode: str = "relative") -> None:
+ with self._conn.lock:
+ self._conn.wait(self._helper._scroll_gen(value, mode))
+ # Postgres doesn't have a reliable way to report a cursor out of bound
+ if mode == "relative":
+ self._pos += value
+ else:
+ self._pos = value
+
class AsyncNamedCursor(BaseCursor["AsyncConnection"]):
__module__ = "psycopg3"
yield rec
if len(recs) < self.itersize:
break
+
+ async def scroll(self, value: int, mode: str = "relative") -> None:
+ async with self._conn.lock:
+ await self._conn.wait(self._helper._scroll_gen(value, mode))
+import pytest
+
+
def test_funny_name(conn):
cur = conn.cursor("1-2-3")
cur.execute("select generate_series(1, 3) as bar")
assert len(cmds) == 2
for cmd in cmds:
assert ("fetch forward 2") in cmd.lower()
+
+
+def test_scroll(conn):
+ cur = conn.cursor("tmp")
+ with pytest.raises(conn.ProgrammingError):
+ cur.scroll(0)
+
+ cur.execute("select generate_series(0,9)")
+ cur.scroll(2)
+ assert cur.fetchone() == (2,)
+ cur.scroll(2)
+ assert cur.fetchone() == (5,)
+ cur.scroll(2, mode="relative")
+ assert cur.fetchone() == (8,)
+ cur.scroll(9, mode="absolute")
+ assert cur.fetchone() == (9,)
+
+ with pytest.raises(ValueError):
+ cur.scroll(9, mode="wat")
assert len(cmds) == 2
for cmd in cmds:
assert ("fetch forward 2") in cmd.lower()
+
+
+async def test_scroll(aconn):
+ cur = await aconn.cursor("tmp")
+ with pytest.raises(aconn.ProgrammingError):
+ await cur.scroll(0)
+
+ await cur.execute("select generate_series(0,9)")
+ await cur.scroll(2)
+ assert await cur.fetchone() == (2,)
+ await cur.scroll(2)
+ assert await cur.fetchone() == (5,)
+ await cur.scroll(2, mode="relative")
+ assert await cur.fetchone() == (8,)
+ await cur.scroll(9, mode="absolute")
+ assert await cur.fetchone() == (9,)
+
+ with pytest.raises(ValueError):
+ await cur.scroll(9, mode="wat")