96 lines
2.7 KiB
Python
96 lines
2.7 KiB
Python
|
"""
|
||
|
psycopg client-side binding cursors
|
||
|
"""
|
||
|
|
||
|
# Copyright (C) 2022 The Psycopg Team
|
||
|
|
||
|
from typing import Optional, Tuple, TYPE_CHECKING
|
||
|
from functools import partial
|
||
|
|
||
|
from ._queries import PostgresQuery, PostgresClientQuery
|
||
|
|
||
|
from . import pq
|
||
|
from . import adapt
|
||
|
from . import errors as e
|
||
|
from .abc import ConnectionType, Query, Params
|
||
|
from .rows import Row
|
||
|
from .cursor import BaseCursor, Cursor
|
||
|
from ._preparing import Prepare
|
||
|
from .cursor_async import AsyncCursor
|
||
|
|
||
|
if TYPE_CHECKING:
|
||
|
from typing import Any # noqa: F401
|
||
|
from .connection import Connection # noqa: F401
|
||
|
from .connection_async import AsyncConnection # noqa: F401
|
||
|
|
||
|
TEXT = pq.Format.TEXT
|
||
|
BINARY = pq.Format.BINARY
|
||
|
|
||
|
|
||
|
class ClientCursorMixin(BaseCursor[ConnectionType, Row]):
|
||
|
def mogrify(self, query: Query, params: Optional[Params] = None) -> str:
|
||
|
"""
|
||
|
Return the query and parameters merged.
|
||
|
|
||
|
Parameters are adapted and merged to the query the same way that
|
||
|
`!execute()` would do.
|
||
|
|
||
|
"""
|
||
|
self._tx = adapt.Transformer(self)
|
||
|
pgq = self._convert_query(query, params)
|
||
|
return pgq.query.decode(self._tx.encoding)
|
||
|
|
||
|
def _execute_send(
|
||
|
self,
|
||
|
query: PostgresQuery,
|
||
|
*,
|
||
|
force_extended: bool = False,
|
||
|
binary: Optional[bool] = None,
|
||
|
) -> None:
|
||
|
if binary is None:
|
||
|
fmt = self.format
|
||
|
else:
|
||
|
fmt = BINARY if binary else TEXT
|
||
|
|
||
|
if fmt == BINARY:
|
||
|
raise e.NotSupportedError(
|
||
|
"client-side cursors don't support binary results"
|
||
|
)
|
||
|
|
||
|
self._query = query
|
||
|
|
||
|
if self._conn._pipeline:
|
||
|
# In pipeline mode always use PQsendQueryParams - see #314
|
||
|
# Multiple statements in the same query are not allowed anyway.
|
||
|
self._conn._pipeline.command_queue.append(
|
||
|
partial(self._pgconn.send_query_params, query.query, None)
|
||
|
)
|
||
|
elif force_extended:
|
||
|
self._pgconn.send_query_params(query.query, None)
|
||
|
else:
|
||
|
# If we can, let's use simple query protocol,
|
||
|
# as it can execute more than one statement in a single query.
|
||
|
self._pgconn.send_query(query.query)
|
||
|
|
||
|
def _convert_query(
|
||
|
self, query: Query, params: Optional[Params] = None
|
||
|
) -> PostgresQuery:
|
||
|
pgq = PostgresClientQuery(self._tx)
|
||
|
pgq.convert(query, params)
|
||
|
return pgq
|
||
|
|
||
|
def _get_prepared(
|
||
|
self, pgq: PostgresQuery, prepare: Optional[bool] = None
|
||
|
) -> Tuple[Prepare, bytes]:
|
||
|
return (Prepare.NO, b"")
|
||
|
|
||
|
|
||
|
class ClientCursor(ClientCursorMixin["Connection[Any]", Row], Cursor[Row]):
|
||
|
__module__ = "psycopg"
|
||
|
|
||
|
|
||
|
class AsyncClientCursor(
|
||
|
ClientCursorMixin["AsyncConnection[Any]", Row], AsyncCursor[Row]
|
||
|
):
|
||
|
__module__ = "psycopg"
|