Initial commit (Clean history)
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
psycopg libpq wrapper
|
||||
|
||||
This package exposes the libpq functionalities as Python objects and functions.
|
||||
|
||||
The real implementation (the binding to the C library) is
|
||||
implementation-dependant but all the implementations share the same interface.
|
||||
"""
|
||||
|
||||
# Copyright (C) 2020 The Psycopg Team
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import logging
|
||||
from collections.abc import Callable
|
||||
|
||||
from . import abc
|
||||
from .misc import ConninfoOption, PGnotify, PGresAttDesc, error_message, version_pretty
|
||||
from ._enums import ConnStatus, DiagnosticField, ExecStatus, Format, Ping
|
||||
from ._enums import PipelineStatus, PollingStatus, Trace, TransactionStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__impl__: str
|
||||
"""The currently loaded implementation of the `!psycopg.pq` package.
|
||||
|
||||
Possible values include ``python``, ``c``, ``binary``.
|
||||
"""
|
||||
|
||||
__build_version__: int
|
||||
"""The libpq version the C package was built with.
|
||||
|
||||
A number in the same format of `~psycopg.ConnectionInfo.server_version`
|
||||
representing the libpq used to build the speedup module (``c``, ``binary``) if
|
||||
available.
|
||||
|
||||
Certain features might not be available if the built version is too old.
|
||||
"""
|
||||
|
||||
version: Callable[[], int]
|
||||
PGconn: type[abc.PGconn]
|
||||
PGresult: type[abc.PGresult]
|
||||
Conninfo: type[abc.Conninfo]
|
||||
Escaping: type[abc.Escaping]
|
||||
PGcancel: type[abc.PGcancel]
|
||||
PGcancelConn: type[abc.PGcancelConn]
|
||||
|
||||
|
||||
def import_from_libpq() -> None:
|
||||
"""
|
||||
Import pq objects implementation from the best libpq wrapper available.
|
||||
|
||||
If an implementation is requested try to import only it, otherwise
|
||||
try to import the best implementation available.
|
||||
"""
|
||||
# import these names into the module on success as side effect
|
||||
global __impl__, version, __build_version__
|
||||
global PGconn, PGresult, Conninfo, Escaping, PGcancel, PGcancelConn
|
||||
|
||||
impl = os.environ.get("PSYCOPG_IMPL", "").lower()
|
||||
module = None
|
||||
attempts: list[str] = []
|
||||
|
||||
def handle_error(name: str, e: Exception) -> None:
|
||||
if not impl:
|
||||
msg = f"couldn't import psycopg '{name}' implementation: {e}"
|
||||
attempts.append(msg)
|
||||
else:
|
||||
msg = f"couldn't import requested psycopg '{name}' implementation: {e}"
|
||||
raise ImportError(msg) from e
|
||||
|
||||
# The best implementation: fast but requires the system libpq installed
|
||||
if not impl or impl == "c":
|
||||
try:
|
||||
from psycopg_c import pq as module # type: ignore
|
||||
except Exception as e:
|
||||
handle_error("c", e)
|
||||
|
||||
# Second best implementation: fast and stand-alone
|
||||
if not module and (not impl or impl == "binary"):
|
||||
try:
|
||||
from psycopg_binary import pq as module # type: ignore
|
||||
except Exception as e:
|
||||
handle_error("binary", e)
|
||||
|
||||
# Pure Python implementation, slow and requires the system libpq installed.
|
||||
if not module and (not impl or impl == "python"):
|
||||
try:
|
||||
from . import pq_ctypes as module # type: ignore[assignment]
|
||||
except Exception as e:
|
||||
handle_error("python", e)
|
||||
|
||||
if module:
|
||||
__impl__ = module.__impl__
|
||||
version = module.version
|
||||
PGconn = module.PGconn
|
||||
PGresult = module.PGresult
|
||||
Conninfo = module.Conninfo
|
||||
Escaping = module.Escaping
|
||||
PGcancel = module.PGcancel
|
||||
PGcancelConn = module.PGcancelConn
|
||||
__build_version__ = module.__build_version__
|
||||
elif impl:
|
||||
raise ImportError(f"requested psycopg implementation '{impl}' unknown")
|
||||
else:
|
||||
sattempts = "\n".join(f"- {attempt}" for attempt in attempts)
|
||||
raise ImportError(
|
||||
f"""\
|
||||
no pq wrapper available.
|
||||
Attempts made:
|
||||
{sattempts}"""
|
||||
)
|
||||
|
||||
|
||||
import_from_libpq()
|
||||
|
||||
__all__ = (
|
||||
"ConnStatus",
|
||||
"PipelineStatus",
|
||||
"PollingStatus",
|
||||
"TransactionStatus",
|
||||
"ExecStatus",
|
||||
"Ping",
|
||||
"DiagnosticField",
|
||||
"Format",
|
||||
"Trace",
|
||||
"PGconn",
|
||||
"PGnotify",
|
||||
"Conninfo",
|
||||
"PGresAttDesc",
|
||||
"error_message",
|
||||
"ConninfoOption",
|
||||
"version",
|
||||
"version_pretty",
|
||||
)
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
libpq debugging tools
|
||||
|
||||
These functionalities are exposed here for convenience, but are not part of
|
||||
the public interface and are subject to change at any moment.
|
||||
|
||||
Suggested usage::
|
||||
|
||||
import logging
|
||||
import psycopg
|
||||
from psycopg import pq
|
||||
from psycopg.pq._debug import PGconnDebug
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||
logger = logging.getLogger("psycopg.debug")
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
assert pq.__impl__ == "python"
|
||||
pq.PGconn = PGconnDebug
|
||||
|
||||
with psycopg.connect("") as conn:
|
||||
conn.pgconn.trace(2)
|
||||
conn.pgconn.set_trace_flags(
|
||||
pq.Trace.SUPPRESS_TIMESTAMPS | pq.Trace.REGRESS_MODE)
|
||||
...
|
||||
|
||||
"""
|
||||
|
||||
# Copyright (C) 2022 The Psycopg Team
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
from typing import Any
|
||||
from functools import wraps
|
||||
from collections.abc import Callable
|
||||
|
||||
from . import PGconn, abc
|
||||
from .misc import connection_summary
|
||||
from .._compat import Self, TypeVar
|
||||
|
||||
Func = TypeVar("Func", bound=Callable[..., Any])
|
||||
|
||||
logger = logging.getLogger("psycopg.debug")
|
||||
|
||||
|
||||
class PGconnDebug:
|
||||
"""Wrapper for a PQconn logging all its access."""
|
||||
|
||||
_pgconn: abc.PGconn
|
||||
|
||||
def __init__(self, pgconn: abc.PGconn):
|
||||
super().__setattr__("_pgconn", pgconn)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}"
|
||||
info = connection_summary(self._pgconn)
|
||||
return f"<{cls} {info} at 0x{id(self):x}>"
|
||||
|
||||
def __getattr__(self, attr: str) -> Any:
|
||||
if callable(value := getattr(self._pgconn, attr)):
|
||||
return debugging(value)
|
||||
else:
|
||||
logger.info("PGconn.%s -> %s", attr, value)
|
||||
return value
|
||||
|
||||
def __setattr__(self, attr: str, value: Any) -> None:
|
||||
setattr(self._pgconn, attr, value)
|
||||
logger.info("PGconn.%s <- %s", attr, value)
|
||||
|
||||
@classmethod
|
||||
def connect(cls, conninfo: bytes) -> Self:
|
||||
return cls(debugging(PGconn.connect)(conninfo))
|
||||
|
||||
@classmethod
|
||||
def connect_start(cls, conninfo: bytes) -> Self:
|
||||
return cls(debugging(PGconn.connect_start)(conninfo))
|
||||
|
||||
@classmethod
|
||||
def ping(self, conninfo: bytes) -> int:
|
||||
return debugging(PGconn.ping)(conninfo)
|
||||
|
||||
|
||||
def debugging(f: Func) -> Func:
|
||||
"""Wrap a function in order to log its arguments and return value on call."""
|
||||
|
||||
@wraps(f)
|
||||
def debugging_(*args: Any, **kwargs: Any) -> Any:
|
||||
reprs = []
|
||||
for arg in args:
|
||||
reprs.append(f"{arg!r}")
|
||||
for k, v in kwargs.items():
|
||||
reprs.append(f"{k}={v!r}")
|
||||
|
||||
logger.info("PGconn.%s(%s)", f.__name__, ", ".join(reprs))
|
||||
try:
|
||||
rv = f(*args, **kwargs)
|
||||
except Exception as ex:
|
||||
logger.info(" <- %r", ex)
|
||||
raise
|
||||
else:
|
||||
# Display the return value only if the function is declared to return
|
||||
# something else than None.
|
||||
ra = inspect.signature(f).return_annotation
|
||||
if ra is not None or rv is not None:
|
||||
logger.info(" <- %r", rv)
|
||||
return rv
|
||||
|
||||
return debugging_ # type: ignore
|
||||
@@ -0,0 +1,259 @@
|
||||
"""
|
||||
libpq enum definitions for psycopg
|
||||
"""
|
||||
|
||||
# Copyright (C) 2020 The Psycopg Team
|
||||
|
||||
from enum import IntEnum, IntFlag, auto
|
||||
|
||||
# Check in src/interfaces/libpq/libpq-fe.h for updates.
|
||||
|
||||
|
||||
class ConnStatus(IntEnum):
|
||||
"""
|
||||
Current status of the connection.
|
||||
"""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
OK = 0
|
||||
"""The connection is in a working state."""
|
||||
BAD = auto()
|
||||
"""The connection is closed."""
|
||||
|
||||
STARTED = auto()
|
||||
MADE = auto()
|
||||
AWAITING_RESPONSE = auto()
|
||||
AUTH_OK = auto()
|
||||
SETENV = auto()
|
||||
SSL_STARTUP = auto()
|
||||
NEEDED = auto()
|
||||
CHECK_WRITABLE = auto()
|
||||
CONSUME = auto()
|
||||
GSS_STARTUP = auto()
|
||||
CHECK_TARGET = auto()
|
||||
CHECK_STANDBY = auto()
|
||||
ALLOCATED = auto() # Only for cancel connections.
|
||||
AUTHENTICATING = auto()
|
||||
|
||||
|
||||
class PollingStatus(IntEnum):
|
||||
"""
|
||||
The status of the socket during a connection.
|
||||
|
||||
If ``READING`` or ``WRITING`` you may select before polling again.
|
||||
"""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
FAILED = 0
|
||||
"""Connection attempt failed."""
|
||||
READING = auto()
|
||||
"""Will have to wait before reading new data."""
|
||||
WRITING = auto()
|
||||
"""Will have to wait before writing new data."""
|
||||
OK = auto()
|
||||
"""Connection completed."""
|
||||
|
||||
ACTIVE = auto()
|
||||
|
||||
|
||||
class ExecStatus(IntEnum):
|
||||
"""
|
||||
The status of a command.
|
||||
"""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
EMPTY_QUERY = 0
|
||||
"""The string sent to the server was empty."""
|
||||
|
||||
COMMAND_OK = auto()
|
||||
"""Successful completion of a command returning no data."""
|
||||
|
||||
TUPLES_OK = auto()
|
||||
"""
|
||||
Successful completion of a command returning data (such as a SELECT or SHOW).
|
||||
"""
|
||||
|
||||
COPY_OUT = auto()
|
||||
"""Copy Out (from server) data transfer started."""
|
||||
|
||||
COPY_IN = auto()
|
||||
"""Copy In (to server) data transfer started."""
|
||||
|
||||
BAD_RESPONSE = auto()
|
||||
"""The server's response was not understood."""
|
||||
|
||||
NONFATAL_ERROR = auto()
|
||||
"""A nonfatal error (a notice or warning) occurred."""
|
||||
|
||||
FATAL_ERROR = auto()
|
||||
"""A fatal error occurred."""
|
||||
|
||||
COPY_BOTH = auto()
|
||||
"""
|
||||
Copy In/Out (to and from server) data transfer started.
|
||||
|
||||
This feature is currently used only for streaming replication, so this
|
||||
status should not occur in ordinary applications.
|
||||
"""
|
||||
|
||||
SINGLE_TUPLE = auto()
|
||||
"""
|
||||
The PGresult contains a single result tuple from the current command.
|
||||
|
||||
This status occurs only when single-row mode has been selected for the
|
||||
query.
|
||||
"""
|
||||
|
||||
PIPELINE_SYNC = auto()
|
||||
"""
|
||||
The PGresult represents a synchronization point in pipeline mode,
|
||||
requested by PQpipelineSync.
|
||||
|
||||
This status occurs only when pipeline mode has been selected.
|
||||
"""
|
||||
|
||||
PIPELINE_ABORTED = auto()
|
||||
"""
|
||||
The PGresult represents a pipeline that has received an error from the server.
|
||||
|
||||
PQgetResult must be called repeatedly, and each time it will return this
|
||||
status code until the end of the current pipeline, at which point it will
|
||||
return PGRES_PIPELINE_SYNC and normal processing can resume.
|
||||
"""
|
||||
TUPLES_CHUNK = auto()
|
||||
"""The PGresult contains several result tuples from the current command.
|
||||
|
||||
This status occurs only when chunked mode has been selected for the query.
|
||||
"""
|
||||
|
||||
|
||||
class TransactionStatus(IntEnum):
|
||||
"""
|
||||
The transaction status of a connection.
|
||||
"""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
IDLE = 0
|
||||
"""Connection ready, no transaction active."""
|
||||
|
||||
ACTIVE = auto()
|
||||
"""A command is in progress."""
|
||||
|
||||
INTRANS = auto()
|
||||
"""Connection idle in an open transaction."""
|
||||
|
||||
INERROR = auto()
|
||||
"""An error happened in the current transaction."""
|
||||
|
||||
UNKNOWN = auto()
|
||||
"""Unknown connection state, broken connection."""
|
||||
|
||||
|
||||
class Ping(IntEnum):
|
||||
"""Response from a ping attempt."""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
OK = 0
|
||||
"""
|
||||
The server is running and appears to be accepting connections.
|
||||
"""
|
||||
|
||||
REJECT = auto()
|
||||
"""
|
||||
The server is running but is in a state that disallows connections.
|
||||
"""
|
||||
|
||||
NO_RESPONSE = auto()
|
||||
"""
|
||||
The server could not be contacted.
|
||||
"""
|
||||
|
||||
NO_ATTEMPT = auto()
|
||||
"""
|
||||
No attempt was made to contact the server.
|
||||
"""
|
||||
|
||||
|
||||
class PipelineStatus(IntEnum):
|
||||
"""Pipeline mode status of the libpq connection."""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
OFF = 0
|
||||
"""
|
||||
The libpq connection is *not* in pipeline mode.
|
||||
"""
|
||||
ON = auto()
|
||||
"""
|
||||
The libpq connection is in pipeline mode.
|
||||
"""
|
||||
ABORTED = auto()
|
||||
"""
|
||||
The libpq connection is in pipeline mode and an error occurred while
|
||||
processing the current pipeline. The aborted flag is cleared when
|
||||
PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
|
||||
"""
|
||||
|
||||
|
||||
class DiagnosticField(IntEnum):
|
||||
"""
|
||||
Fields in an error report.
|
||||
"""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
# from src/include/postgres_ext.h
|
||||
|
||||
SEVERITY = ord("S")
|
||||
SEVERITY_NONLOCALIZED = ord("V")
|
||||
SQLSTATE = ord("C")
|
||||
MESSAGE_PRIMARY = ord("M")
|
||||
MESSAGE_DETAIL = ord("D")
|
||||
MESSAGE_HINT = ord("H")
|
||||
STATEMENT_POSITION = ord("P")
|
||||
INTERNAL_POSITION = ord("p")
|
||||
INTERNAL_QUERY = ord("q")
|
||||
CONTEXT = ord("W")
|
||||
SCHEMA_NAME = ord("s")
|
||||
TABLE_NAME = ord("t")
|
||||
COLUMN_NAME = ord("c")
|
||||
DATATYPE_NAME = ord("d")
|
||||
CONSTRAINT_NAME = ord("n")
|
||||
SOURCE_FILE = ord("F")
|
||||
SOURCE_LINE = ord("L")
|
||||
SOURCE_FUNCTION = ord("R")
|
||||
|
||||
|
||||
class Format(IntEnum):
|
||||
"""
|
||||
Enum representing the format of a query argument or return value.
|
||||
|
||||
These values are only the ones managed by the libpq. `~psycopg` may also
|
||||
support automatically-chosen values: see `psycopg.adapt.PyFormat`.
|
||||
"""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
TEXT = 0
|
||||
"""Text parameter."""
|
||||
BINARY = 1
|
||||
"""Binary parameter."""
|
||||
|
||||
|
||||
class Trace(IntFlag):
|
||||
"""
|
||||
Enum to control tracing of the client/server communication.
|
||||
"""
|
||||
|
||||
__module__ = "psycopg.pq"
|
||||
|
||||
SUPPRESS_TIMESTAMPS = 1
|
||||
"""Do not include timestamps in messages."""
|
||||
|
||||
REGRESS_MODE = 2
|
||||
"""Redact some fields, e.g. OIDs, from messages."""
|
||||
@@ -0,0 +1,844 @@
|
||||
"""
|
||||
libpq access using ctypes
|
||||
"""
|
||||
|
||||
# Copyright (C) 2020 The Psycopg Team
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
from ctypes import CFUNCTYPE, POINTER, Structure, c_char, c_char_p, c_int, c_size_t
|
||||
from ctypes import c_ubyte, c_uint, c_void_p
|
||||
from typing import Any, NoReturn
|
||||
|
||||
from .misc import find_libpq_full_path, version_pretty
|
||||
from ..errors import NotSupportedError
|
||||
|
||||
if not (libname := find_libpq_full_path()):
|
||||
raise ImportError("libpq library not found")
|
||||
|
||||
pq = ctypes.cdll.LoadLibrary(libname)
|
||||
|
||||
|
||||
class FILE(Structure):
|
||||
pass
|
||||
|
||||
|
||||
FILE_ptr = POINTER(FILE)
|
||||
|
||||
if sys.platform == "linux":
|
||||
if not (libcname := ctypes.util.find_library("c")):
|
||||
# Likely this is a system using musl libc, see the following bug:
|
||||
# https://github.com/python/cpython/issues/65821
|
||||
libcname = "libc.so"
|
||||
libc = ctypes.cdll.LoadLibrary(libcname)
|
||||
|
||||
fdopen = libc.fdopen
|
||||
fdopen.argtypes = (c_int, c_char_p)
|
||||
fdopen.restype = FILE_ptr
|
||||
|
||||
|
||||
def not_supported_before(fname: str, pgversion: int) -> Any:
|
||||
def not_supported(*args: Any, **kwargs: Any) -> NoReturn:
|
||||
raise NotSupportedError(
|
||||
f"{fname} requires libpq from PostgreSQL {version_pretty(pgversion)} on"
|
||||
f" the client; version {version_pretty(libpq_version)} available instead"
|
||||
)
|
||||
|
||||
return not_supported
|
||||
|
||||
|
||||
# Get the libpq version to define what functions are available.
|
||||
|
||||
PQlibVersion = pq.PQlibVersion
|
||||
PQlibVersion.argtypes = []
|
||||
PQlibVersion.restype = c_int
|
||||
|
||||
libpq_version = PQlibVersion()
|
||||
|
||||
|
||||
# libpq data types
|
||||
|
||||
|
||||
Oid = c_uint
|
||||
|
||||
|
||||
class PGconn_struct(Structure):
|
||||
_fields_ = []
|
||||
|
||||
|
||||
class PGresult_struct(Structure):
|
||||
_fields_ = []
|
||||
|
||||
|
||||
class PQconninfoOption_struct(Structure):
|
||||
_fields_ = [
|
||||
("keyword", c_char_p),
|
||||
("envvar", c_char_p),
|
||||
("compiled", c_char_p),
|
||||
("val", c_char_p),
|
||||
("label", c_char_p),
|
||||
("dispchar", c_char_p),
|
||||
("dispsize", c_int),
|
||||
]
|
||||
|
||||
|
||||
class PGnotify_struct(Structure):
|
||||
_fields_ = [
|
||||
("relname", c_char_p),
|
||||
("be_pid", c_int),
|
||||
("extra", c_char_p),
|
||||
]
|
||||
|
||||
|
||||
class PGcancelConn_struct(Structure):
|
||||
_fields_ = []
|
||||
|
||||
|
||||
class PGcancel_struct(Structure):
|
||||
_fields_ = []
|
||||
|
||||
|
||||
class PGresAttDesc_struct(Structure):
|
||||
_fields_ = [
|
||||
("name", c_char_p),
|
||||
("tableid", Oid),
|
||||
("columnid", c_int),
|
||||
("format", c_int),
|
||||
("typid", Oid),
|
||||
("typlen", c_int),
|
||||
("atttypmod", c_int),
|
||||
]
|
||||
|
||||
|
||||
PGconn_ptr = POINTER(PGconn_struct)
|
||||
PGresult_ptr = POINTER(PGresult_struct)
|
||||
PQconninfoOption_ptr = POINTER(PQconninfoOption_struct)
|
||||
PGnotify_ptr = POINTER(PGnotify_struct)
|
||||
PGcancelConn_ptr = POINTER(PGcancelConn_struct)
|
||||
PGcancel_ptr = POINTER(PGcancel_struct)
|
||||
PGresAttDesc_ptr = POINTER(PGresAttDesc_struct)
|
||||
|
||||
|
||||
# Function definitions as explained in PostgreSQL 12 documentation
|
||||
|
||||
# 33.1. Database Connection Control Functions
|
||||
|
||||
# PQconnectdbParams: doesn't seem useful, won't wrap for now
|
||||
|
||||
PQconnectdb = pq.PQconnectdb
|
||||
PQconnectdb.argtypes = [c_char_p]
|
||||
PQconnectdb.restype = PGconn_ptr
|
||||
|
||||
# PQsetdbLogin: not useful
|
||||
# PQsetdb: not useful
|
||||
|
||||
# PQconnectStartParams: not useful
|
||||
|
||||
PQconnectStart = pq.PQconnectStart
|
||||
PQconnectStart.argtypes = [c_char_p]
|
||||
PQconnectStart.restype = PGconn_ptr
|
||||
|
||||
PQconnectPoll = pq.PQconnectPoll
|
||||
PQconnectPoll.argtypes = [PGconn_ptr]
|
||||
PQconnectPoll.restype = c_int
|
||||
|
||||
PQconndefaults = pq.PQconndefaults
|
||||
PQconndefaults.argtypes = []
|
||||
PQconndefaults.restype = PQconninfoOption_ptr
|
||||
|
||||
PQconninfoFree = pq.PQconninfoFree
|
||||
PQconninfoFree.argtypes = [PQconninfoOption_ptr]
|
||||
PQconninfoFree.restype = None
|
||||
|
||||
PQconninfo = pq.PQconninfo
|
||||
PQconninfo.argtypes = [PGconn_ptr]
|
||||
PQconninfo.restype = PQconninfoOption_ptr
|
||||
|
||||
PQconninfoParse = pq.PQconninfoParse
|
||||
PQconninfoParse.argtypes = [c_char_p, POINTER(c_char_p)]
|
||||
PQconninfoParse.restype = PQconninfoOption_ptr
|
||||
|
||||
PQfinish = pq.PQfinish
|
||||
PQfinish.argtypes = [PGconn_ptr]
|
||||
PQfinish.restype = None
|
||||
|
||||
PQreset = pq.PQreset
|
||||
PQreset.argtypes = [PGconn_ptr]
|
||||
PQreset.restype = None
|
||||
|
||||
PQresetStart = pq.PQresetStart
|
||||
PQresetStart.argtypes = [PGconn_ptr]
|
||||
PQresetStart.restype = c_int
|
||||
|
||||
PQresetPoll = pq.PQresetPoll
|
||||
PQresetPoll.argtypes = [PGconn_ptr]
|
||||
PQresetPoll.restype = c_int
|
||||
|
||||
PQping = pq.PQping
|
||||
PQping.argtypes = [c_char_p]
|
||||
PQping.restype = c_int
|
||||
|
||||
|
||||
# 33.2. Connection Status Functions
|
||||
|
||||
PQdb = pq.PQdb
|
||||
PQdb.argtypes = [PGconn_ptr]
|
||||
PQdb.restype = c_char_p
|
||||
|
||||
PQuser = pq.PQuser
|
||||
PQuser.argtypes = [PGconn_ptr]
|
||||
PQuser.restype = c_char_p
|
||||
|
||||
PQpass = pq.PQpass
|
||||
PQpass.argtypes = [PGconn_ptr]
|
||||
PQpass.restype = c_char_p
|
||||
|
||||
PQhost = pq.PQhost
|
||||
PQhost.argtypes = [PGconn_ptr]
|
||||
PQhost.restype = c_char_p
|
||||
|
||||
|
||||
if libpq_version >= 120000:
|
||||
PQhostaddr = pq.PQhostaddr
|
||||
PQhostaddr.argtypes = [PGconn_ptr]
|
||||
PQhostaddr.restype = c_char_p
|
||||
else:
|
||||
PQhostaddr = not_supported_before("PQhostaddr", 120000)
|
||||
|
||||
PQport = pq.PQport
|
||||
PQport.argtypes = [PGconn_ptr]
|
||||
PQport.restype = c_char_p
|
||||
|
||||
PQtty = pq.PQtty
|
||||
PQtty.argtypes = [PGconn_ptr]
|
||||
PQtty.restype = c_char_p
|
||||
|
||||
PQoptions = pq.PQoptions
|
||||
PQoptions.argtypes = [PGconn_ptr]
|
||||
PQoptions.restype = c_char_p
|
||||
|
||||
PQstatus = pq.PQstatus
|
||||
PQstatus.argtypes = [PGconn_ptr]
|
||||
PQstatus.restype = c_int
|
||||
|
||||
PQtransactionStatus = pq.PQtransactionStatus
|
||||
PQtransactionStatus.argtypes = [PGconn_ptr]
|
||||
PQtransactionStatus.restype = c_int
|
||||
|
||||
PQparameterStatus = pq.PQparameterStatus
|
||||
PQparameterStatus.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQparameterStatus.restype = c_char_p
|
||||
|
||||
PQprotocolVersion = pq.PQprotocolVersion
|
||||
PQprotocolVersion.argtypes = [PGconn_ptr]
|
||||
PQprotocolVersion.restype = c_int
|
||||
|
||||
if libpq_version >= 180000:
|
||||
PQfullProtocolVersion = pq.PQfullProtocolVersion
|
||||
PQfullProtocolVersion.argtypes = [PGconn_ptr]
|
||||
PQfullProtocolVersion.restype = c_int
|
||||
else:
|
||||
PQfullProtocolVersion = not_supported_before("PQfullProtocolVersion", 180000)
|
||||
|
||||
PQserverVersion = pq.PQserverVersion
|
||||
PQserverVersion.argtypes = [PGconn_ptr]
|
||||
PQserverVersion.restype = c_int
|
||||
|
||||
PQerrorMessage = pq.PQerrorMessage
|
||||
PQerrorMessage.argtypes = [PGconn_ptr]
|
||||
PQerrorMessage.restype = c_char_p
|
||||
|
||||
PQsocket = pq.PQsocket
|
||||
PQsocket.argtypes = [PGconn_ptr]
|
||||
PQsocket.restype = c_int
|
||||
|
||||
PQbackendPID = pq.PQbackendPID
|
||||
PQbackendPID.argtypes = [PGconn_ptr]
|
||||
PQbackendPID.restype = c_int
|
||||
|
||||
PQconnectionNeedsPassword = pq.PQconnectionNeedsPassword
|
||||
PQconnectionNeedsPassword.argtypes = [PGconn_ptr]
|
||||
PQconnectionNeedsPassword.restype = c_int
|
||||
|
||||
PQconnectionUsedPassword = pq.PQconnectionUsedPassword
|
||||
PQconnectionUsedPassword.argtypes = [PGconn_ptr]
|
||||
PQconnectionUsedPassword.restype = c_int
|
||||
|
||||
if libpq_version >= 160000:
|
||||
PQconnectionUsedGSSAPI = pq.PQconnectionUsedGSSAPI
|
||||
PQconnectionUsedGSSAPI.argtypes = [PGconn_ptr]
|
||||
PQconnectionUsedGSSAPI.restype = c_int
|
||||
else:
|
||||
PQconnectionUsedGSSAPI = not_supported_before("PQconnectionUsedGSSAPI", 160000)
|
||||
|
||||
PQsslInUse = pq.PQsslInUse
|
||||
PQsslInUse.argtypes = [PGconn_ptr]
|
||||
PQsslInUse.restype = c_int
|
||||
|
||||
# TODO: PQsslAttribute, PQsslAttributeNames, PQsslStruct, PQgetssl
|
||||
|
||||
|
||||
# 33.3. Command Execution Functions
|
||||
|
||||
PQexec = pq.PQexec
|
||||
PQexec.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQexec.restype = PGresult_ptr
|
||||
|
||||
PQexecParams = pq.PQexecParams
|
||||
PQexecParams.argtypes = [
|
||||
PGconn_ptr,
|
||||
c_char_p,
|
||||
c_int,
|
||||
POINTER(Oid),
|
||||
POINTER(c_char_p),
|
||||
POINTER(c_int),
|
||||
POINTER(c_int),
|
||||
c_int,
|
||||
]
|
||||
PQexecParams.restype = PGresult_ptr
|
||||
|
||||
PQprepare = pq.PQprepare
|
||||
PQprepare.argtypes = [PGconn_ptr, c_char_p, c_char_p, c_int, POINTER(Oid)]
|
||||
PQprepare.restype = PGresult_ptr
|
||||
|
||||
PQexecPrepared = pq.PQexecPrepared
|
||||
PQexecPrepared.argtypes = [
|
||||
PGconn_ptr,
|
||||
c_char_p,
|
||||
c_int,
|
||||
POINTER(c_char_p),
|
||||
POINTER(c_int),
|
||||
POINTER(c_int),
|
||||
c_int,
|
||||
]
|
||||
PQexecPrepared.restype = PGresult_ptr
|
||||
|
||||
PQdescribePrepared = pq.PQdescribePrepared
|
||||
PQdescribePrepared.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQdescribePrepared.restype = PGresult_ptr
|
||||
|
||||
PQdescribePortal = pq.PQdescribePortal
|
||||
PQdescribePortal.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQdescribePortal.restype = PGresult_ptr
|
||||
|
||||
if libpq_version >= 170000:
|
||||
PQclosePrepared = pq.PQclosePrepared
|
||||
PQclosePrepared.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQclosePrepared.restype = PGresult_ptr
|
||||
|
||||
PQclosePortal = pq.PQclosePortal
|
||||
PQclosePortal.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQclosePortal.restype = PGresult_ptr
|
||||
|
||||
else:
|
||||
PQclosePrepared = not_supported_before("PQclosePrepared", 170000)
|
||||
PQclosePortal = not_supported_before("PQclosePortal", 170000)
|
||||
|
||||
PQresultStatus = pq.PQresultStatus
|
||||
PQresultStatus.argtypes = [PGresult_ptr]
|
||||
PQresultStatus.restype = c_int
|
||||
|
||||
# PQresStatus: not needed, we have pretty enums
|
||||
|
||||
PQresultErrorMessage = pq.PQresultErrorMessage
|
||||
PQresultErrorMessage.argtypes = [PGresult_ptr]
|
||||
PQresultErrorMessage.restype = c_char_p
|
||||
|
||||
# TODO: PQresultVerboseErrorMessage
|
||||
|
||||
PQresultErrorField = pq.PQresultErrorField
|
||||
PQresultErrorField.argtypes = [PGresult_ptr, c_int]
|
||||
PQresultErrorField.restype = c_char_p
|
||||
|
||||
PQclear = pq.PQclear
|
||||
PQclear.argtypes = [PGresult_ptr]
|
||||
PQclear.restype = None
|
||||
|
||||
|
||||
# 33.3.2. Retrieving Query Result Information
|
||||
|
||||
PQntuples = pq.PQntuples
|
||||
PQntuples.argtypes = [PGresult_ptr]
|
||||
PQntuples.restype = c_int
|
||||
|
||||
PQnfields = pq.PQnfields
|
||||
PQnfields.argtypes = [PGresult_ptr]
|
||||
PQnfields.restype = c_int
|
||||
|
||||
PQfname = pq.PQfname
|
||||
PQfname.argtypes = [PGresult_ptr, c_int]
|
||||
PQfname.restype = c_char_p
|
||||
|
||||
# PQfnumber: useless and hard to use
|
||||
|
||||
PQftable = pq.PQftable
|
||||
PQftable.argtypes = [PGresult_ptr, c_int]
|
||||
PQftable.restype = Oid
|
||||
|
||||
PQftablecol = pq.PQftablecol
|
||||
PQftablecol.argtypes = [PGresult_ptr, c_int]
|
||||
PQftablecol.restype = c_int
|
||||
|
||||
PQfformat = pq.PQfformat
|
||||
PQfformat.argtypes = [PGresult_ptr, c_int]
|
||||
PQfformat.restype = c_int
|
||||
|
||||
PQftype = pq.PQftype
|
||||
PQftype.argtypes = [PGresult_ptr, c_int]
|
||||
PQftype.restype = Oid
|
||||
|
||||
PQfmod = pq.PQfmod
|
||||
PQfmod.argtypes = [PGresult_ptr, c_int]
|
||||
PQfmod.restype = c_int
|
||||
|
||||
PQfsize = pq.PQfsize
|
||||
PQfsize.argtypes = [PGresult_ptr, c_int]
|
||||
PQfsize.restype = c_int
|
||||
|
||||
PQbinaryTuples = pq.PQbinaryTuples
|
||||
PQbinaryTuples.argtypes = [PGresult_ptr]
|
||||
PQbinaryTuples.restype = c_int
|
||||
|
||||
PQgetvalue = pq.PQgetvalue
|
||||
PQgetvalue.argtypes = [PGresult_ptr, c_int, c_int]
|
||||
PQgetvalue.restype = POINTER(c_char) # not a null-terminated string
|
||||
|
||||
PQgetisnull = pq.PQgetisnull
|
||||
PQgetisnull.argtypes = [PGresult_ptr, c_int, c_int]
|
||||
PQgetisnull.restype = c_int
|
||||
|
||||
PQgetlength = pq.PQgetlength
|
||||
PQgetlength.argtypes = [PGresult_ptr, c_int, c_int]
|
||||
PQgetlength.restype = c_int
|
||||
|
||||
PQnparams = pq.PQnparams
|
||||
PQnparams.argtypes = [PGresult_ptr]
|
||||
PQnparams.restype = c_int
|
||||
|
||||
PQparamtype = pq.PQparamtype
|
||||
PQparamtype.argtypes = [PGresult_ptr, c_int]
|
||||
PQparamtype.restype = Oid
|
||||
|
||||
# PQprint: pretty useless
|
||||
|
||||
# 33.3.3. Retrieving Other Result Information
|
||||
|
||||
PQcmdStatus = pq.PQcmdStatus
|
||||
PQcmdStatus.argtypes = [PGresult_ptr]
|
||||
PQcmdStatus.restype = c_char_p
|
||||
|
||||
PQcmdTuples = pq.PQcmdTuples
|
||||
PQcmdTuples.argtypes = [PGresult_ptr]
|
||||
PQcmdTuples.restype = c_char_p
|
||||
|
||||
PQoidValue = pq.PQoidValue
|
||||
PQoidValue.argtypes = [PGresult_ptr]
|
||||
PQoidValue.restype = Oid
|
||||
|
||||
|
||||
# 33.3.4. Escaping Strings for Inclusion in SQL Commands
|
||||
|
||||
PQescapeLiteral = pq.PQescapeLiteral
|
||||
PQescapeLiteral.argtypes = [PGconn_ptr, c_char_p, c_size_t]
|
||||
PQescapeLiteral.restype = POINTER(c_char)
|
||||
|
||||
PQescapeIdentifier = pq.PQescapeIdentifier
|
||||
PQescapeIdentifier.argtypes = [PGconn_ptr, c_char_p, c_size_t]
|
||||
PQescapeIdentifier.restype = POINTER(c_char)
|
||||
|
||||
PQescapeStringConn = pq.PQescapeStringConn
|
||||
# TODO: raises "wrong type" error
|
||||
# PQescapeStringConn.argtypes = [
|
||||
# PGconn_ptr, c_char_p, c_char_p, c_size_t, POINTER(c_int)
|
||||
# ]
|
||||
PQescapeStringConn.restype = c_size_t
|
||||
|
||||
PQescapeString = pq.PQescapeString
|
||||
# TODO: raises "wrong type" error
|
||||
# PQescapeString.argtypes = [c_char_p, c_char_p, c_size_t]
|
||||
PQescapeString.restype = c_size_t
|
||||
|
||||
PQescapeByteaConn = pq.PQescapeByteaConn
|
||||
PQescapeByteaConn.argtypes = [
|
||||
PGconn_ptr,
|
||||
POINTER(c_char), # actually POINTER(c_ubyte) but this is easier
|
||||
c_size_t,
|
||||
POINTER(c_size_t),
|
||||
]
|
||||
PQescapeByteaConn.restype = POINTER(c_ubyte)
|
||||
|
||||
PQescapeBytea = pq.PQescapeBytea
|
||||
PQescapeBytea.argtypes = [
|
||||
POINTER(c_char), # actually POINTER(c_ubyte) but this is easier
|
||||
c_size_t,
|
||||
POINTER(c_size_t),
|
||||
]
|
||||
PQescapeBytea.restype = POINTER(c_ubyte)
|
||||
|
||||
|
||||
PQunescapeBytea = pq.PQunescapeBytea
|
||||
PQunescapeBytea.argtypes = [
|
||||
POINTER(c_char), # actually POINTER(c_ubyte) but this is easier
|
||||
POINTER(c_size_t),
|
||||
]
|
||||
PQunescapeBytea.restype = POINTER(c_ubyte)
|
||||
|
||||
|
||||
# 33.4. Asynchronous Command Processing
|
||||
|
||||
PQsendQuery = pq.PQsendQuery
|
||||
PQsendQuery.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQsendQuery.restype = c_int
|
||||
|
||||
PQsendQueryParams = pq.PQsendQueryParams
|
||||
PQsendQueryParams.argtypes = [
|
||||
PGconn_ptr,
|
||||
c_char_p,
|
||||
c_int,
|
||||
POINTER(Oid),
|
||||
POINTER(c_char_p),
|
||||
POINTER(c_int),
|
||||
POINTER(c_int),
|
||||
c_int,
|
||||
]
|
||||
PQsendQueryParams.restype = c_int
|
||||
|
||||
PQsendPrepare = pq.PQsendPrepare
|
||||
PQsendPrepare.argtypes = [PGconn_ptr, c_char_p, c_char_p, c_int, POINTER(Oid)]
|
||||
PQsendPrepare.restype = c_int
|
||||
|
||||
PQsendQueryPrepared = pq.PQsendQueryPrepared
|
||||
PQsendQueryPrepared.argtypes = [
|
||||
PGconn_ptr,
|
||||
c_char_p,
|
||||
c_int,
|
||||
POINTER(c_char_p),
|
||||
POINTER(c_int),
|
||||
POINTER(c_int),
|
||||
c_int,
|
||||
]
|
||||
PQsendQueryPrepared.restype = c_int
|
||||
|
||||
PQsendDescribePrepared = pq.PQsendDescribePrepared
|
||||
PQsendDescribePrepared.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQsendDescribePrepared.restype = c_int
|
||||
|
||||
PQsendDescribePortal = pq.PQsendDescribePortal
|
||||
PQsendDescribePortal.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQsendDescribePortal.restype = c_int
|
||||
|
||||
if libpq_version >= 170000:
|
||||
PQsendClosePrepared = pq.PQsendClosePrepared
|
||||
PQsendClosePrepared.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQsendClosePrepared.restype = c_int
|
||||
|
||||
PQsendClosePortal = pq.PQsendClosePortal
|
||||
PQsendClosePortal.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQsendClosePortal.restype = c_int
|
||||
|
||||
else:
|
||||
PQsendClosePrepared = not_supported_before("PQsendClosePrepared", 170000)
|
||||
PQsendClosePortal = not_supported_before("PQsendClosePortal", 170000)
|
||||
|
||||
PQgetResult = pq.PQgetResult
|
||||
PQgetResult.argtypes = [PGconn_ptr]
|
||||
PQgetResult.restype = PGresult_ptr
|
||||
|
||||
PQconsumeInput = pq.PQconsumeInput
|
||||
PQconsumeInput.argtypes = [PGconn_ptr]
|
||||
PQconsumeInput.restype = c_int
|
||||
|
||||
PQisBusy = pq.PQisBusy
|
||||
PQisBusy.argtypes = [PGconn_ptr]
|
||||
PQisBusy.restype = c_int
|
||||
|
||||
PQsetnonblocking = pq.PQsetnonblocking
|
||||
PQsetnonblocking.argtypes = [PGconn_ptr, c_int]
|
||||
PQsetnonblocking.restype = c_int
|
||||
|
||||
PQisnonblocking = pq.PQisnonblocking
|
||||
PQisnonblocking.argtypes = [PGconn_ptr]
|
||||
PQisnonblocking.restype = c_int
|
||||
|
||||
PQflush = pq.PQflush
|
||||
PQflush.argtypes = [PGconn_ptr]
|
||||
PQflush.restype = c_int
|
||||
|
||||
|
||||
# 32.6. Retrieving Query Results in Chunks
|
||||
PQsetSingleRowMode = pq.PQsetSingleRowMode
|
||||
PQsetSingleRowMode.argtypes = [PGconn_ptr]
|
||||
PQsetSingleRowMode.restype = c_int
|
||||
|
||||
if libpq_version >= 170000:
|
||||
PQsetChunkedRowsMode = pq.PQsetChunkedRowsMode
|
||||
PQsetChunkedRowsMode.argtypes = [PGconn_ptr, c_int]
|
||||
PQsetChunkedRowsMode.restype = c_int
|
||||
else:
|
||||
PQsetChunkedRowsMode = not_supported_before("PQsetChunkedRowsMode", 170000)
|
||||
|
||||
# 33.6. Canceling Queries in Progress
|
||||
|
||||
if libpq_version >= 170000:
|
||||
PQcancelCreate = pq.PQcancelCreate
|
||||
PQcancelCreate.argtypes = [PGconn_ptr]
|
||||
PQcancelCreate.restype = PGcancelConn_ptr
|
||||
|
||||
PQcancelStart = pq.PQcancelStart
|
||||
PQcancelStart.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelStart.restype = c_int
|
||||
|
||||
PQcancelBlocking = pq.PQcancelBlocking
|
||||
PQcancelBlocking.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelBlocking.restype = c_int
|
||||
|
||||
PQcancelPoll = pq.PQcancelPoll
|
||||
PQcancelPoll.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelPoll.restype = c_int
|
||||
|
||||
PQcancelStatus = pq.PQcancelStatus
|
||||
PQcancelStatus.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelStatus.restype = c_int
|
||||
|
||||
PQcancelSocket = pq.PQcancelSocket
|
||||
PQcancelSocket.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelSocket.restype = c_int
|
||||
|
||||
PQcancelErrorMessage = pq.PQcancelErrorMessage
|
||||
PQcancelErrorMessage.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelErrorMessage.restype = c_char_p
|
||||
|
||||
PQcancelReset = pq.PQcancelReset
|
||||
PQcancelReset.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelReset.restype = None
|
||||
|
||||
PQcancelFinish = pq.PQcancelFinish
|
||||
PQcancelFinish.argtypes = [PGcancelConn_ptr]
|
||||
PQcancelFinish.restype = None
|
||||
|
||||
else:
|
||||
PQcancelCreate = not_supported_before("PQcancelCreate", 170000)
|
||||
PQcancelStart = not_supported_before("PQcancelStart", 170000)
|
||||
PQcancelBlocking = not_supported_before("PQcancelBlocking", 170000)
|
||||
PQcancelPoll = not_supported_before("PQcancelPoll", 170000)
|
||||
PQcancelStatus = not_supported_before("PQcancelStatus", 170000)
|
||||
PQcancelSocket = not_supported_before("PQcancelSocket", 170000)
|
||||
PQcancelErrorMessage = not_supported_before("PQcancelErrorMessage", 170000)
|
||||
PQcancelReset = not_supported_before("PQcancelReset", 170000)
|
||||
PQcancelFinish = not_supported_before("PQcancelFinish", 170000)
|
||||
|
||||
|
||||
PQgetCancel = pq.PQgetCancel
|
||||
PQgetCancel.argtypes = [PGconn_ptr]
|
||||
PQgetCancel.restype = PGcancel_ptr
|
||||
|
||||
PQfreeCancel = pq.PQfreeCancel
|
||||
PQfreeCancel.argtypes = [PGcancel_ptr]
|
||||
PQfreeCancel.restype = None
|
||||
|
||||
PQcancel = pq.PQcancel
|
||||
# TODO: raises "wrong type" error
|
||||
# PQcancel.argtypes = [PGcancel_ptr, POINTER(c_char), c_int]
|
||||
PQcancel.restype = c_int
|
||||
|
||||
|
||||
# 33.8. Asynchronous Notification
|
||||
|
||||
PQnotifies = pq.PQnotifies
|
||||
PQnotifies.argtypes = [PGconn_ptr]
|
||||
PQnotifies.restype = PGnotify_ptr
|
||||
|
||||
|
||||
# 33.9. Functions Associated with the COPY Command
|
||||
|
||||
PQputCopyData = pq.PQputCopyData
|
||||
PQputCopyData.argtypes = [PGconn_ptr, c_char_p, c_int]
|
||||
PQputCopyData.restype = c_int
|
||||
|
||||
PQputCopyEnd = pq.PQputCopyEnd
|
||||
PQputCopyEnd.argtypes = [PGconn_ptr, c_char_p]
|
||||
PQputCopyEnd.restype = c_int
|
||||
|
||||
PQgetCopyData = pq.PQgetCopyData
|
||||
PQgetCopyData.argtypes = [PGconn_ptr, POINTER(c_char_p), c_int]
|
||||
PQgetCopyData.restype = c_int
|
||||
|
||||
|
||||
# 33.10. Control Functions
|
||||
|
||||
PQtrace = pq.PQtrace
|
||||
PQtrace.argtypes = [PGconn_ptr, FILE_ptr]
|
||||
PQtrace.restype = None
|
||||
|
||||
if libpq_version >= 140000:
|
||||
PQsetTraceFlags = pq.PQsetTraceFlags
|
||||
PQsetTraceFlags.argtypes = [PGconn_ptr, c_int]
|
||||
PQsetTraceFlags.restype = None
|
||||
else:
|
||||
PQsetTraceFlags = not_supported_before("PQsetTraceFlags", 140000)
|
||||
|
||||
PQuntrace = pq.PQuntrace
|
||||
PQuntrace.argtypes = [PGconn_ptr]
|
||||
PQuntrace.restype = None
|
||||
|
||||
# 33.11. Miscellaneous Functions
|
||||
|
||||
PQfreemem = pq.PQfreemem
|
||||
PQfreemem.argtypes = [c_void_p]
|
||||
PQfreemem.restype = None
|
||||
|
||||
if libpq_version >= 100000:
|
||||
PQencryptPasswordConn = pq.PQencryptPasswordConn
|
||||
PQencryptPasswordConn.argtypes = [PGconn_ptr, c_char_p, c_char_p, c_char_p]
|
||||
PQencryptPasswordConn.restype = POINTER(c_char)
|
||||
else:
|
||||
PQencryptPasswordConn = not_supported_before("PQencryptPasswordConn", 100000)
|
||||
|
||||
if libpq_version >= 170000:
|
||||
PQchangePassword = pq.PQchangePassword
|
||||
PQchangePassword.argtypes = [PGconn_ptr, c_char_p, c_char_p]
|
||||
PQchangePassword.restype = PGresult_ptr
|
||||
else:
|
||||
PQchangePassword = not_supported_before("PQchangePassword", 170000)
|
||||
|
||||
PQmakeEmptyPGresult = pq.PQmakeEmptyPGresult
|
||||
PQmakeEmptyPGresult.argtypes = [PGconn_ptr, c_int]
|
||||
PQmakeEmptyPGresult.restype = PGresult_ptr
|
||||
|
||||
PQsetResultAttrs = pq.PQsetResultAttrs
|
||||
PQsetResultAttrs.argtypes = [PGresult_ptr, c_int, PGresAttDesc_ptr]
|
||||
PQsetResultAttrs.restype = c_int
|
||||
|
||||
|
||||
# 33.12. Notice Processing
|
||||
|
||||
PQnoticeReceiver = CFUNCTYPE(None, c_void_p, PGresult_ptr)
|
||||
|
||||
PQsetNoticeReceiver = pq.PQsetNoticeReceiver
|
||||
PQsetNoticeReceiver.argtypes = [PGconn_ptr, PQnoticeReceiver, c_void_p]
|
||||
PQsetNoticeReceiver.restype = PQnoticeReceiver
|
||||
|
||||
# 34.5 Pipeline Mode
|
||||
|
||||
if libpq_version >= 140000:
|
||||
PQpipelineStatus = pq.PQpipelineStatus
|
||||
PQpipelineStatus.argtypes = [PGconn_ptr]
|
||||
PQpipelineStatus.restype = c_int
|
||||
|
||||
PQenterPipelineMode = pq.PQenterPipelineMode
|
||||
PQenterPipelineMode.argtypes = [PGconn_ptr]
|
||||
PQenterPipelineMode.restype = c_int
|
||||
|
||||
PQexitPipelineMode = pq.PQexitPipelineMode
|
||||
PQexitPipelineMode.argtypes = [PGconn_ptr]
|
||||
PQexitPipelineMode.restype = c_int
|
||||
|
||||
PQpipelineSync = pq.PQpipelineSync
|
||||
PQpipelineSync.argtypes = [PGconn_ptr]
|
||||
PQpipelineSync.restype = c_int
|
||||
|
||||
PQsendFlushRequest = pq.PQsendFlushRequest
|
||||
PQsendFlushRequest.argtypes = [PGconn_ptr]
|
||||
PQsendFlushRequest.restype = c_int
|
||||
|
||||
else:
|
||||
PQpipelineStatus = not_supported_before("PQpipelineStatus", 140000)
|
||||
PQenterPipelineMode = not_supported_before("PQenterPipelineMode", 140000)
|
||||
PQexitPipelineMode = not_supported_before("PQexitPipelineMode", 140000)
|
||||
PQpipelineSync = not_supported_before("PQpipelineSync", 140000)
|
||||
PQsendFlushRequest = not_supported_before("PQsendFlushRequest", 140000)
|
||||
|
||||
|
||||
# 33.18. SSL Support
|
||||
|
||||
PQinitOpenSSL = pq.PQinitOpenSSL
|
||||
PQinitOpenSSL.argtypes = [c_int, c_int]
|
||||
PQinitOpenSSL.restype = None
|
||||
|
||||
|
||||
def generate_stub() -> None:
|
||||
import re
|
||||
from ctypes import _CFuncPtr # type: ignore[attr-defined]
|
||||
|
||||
def type2str(fname: str, narg: int | None, t: Any) -> str:
|
||||
if t is None:
|
||||
return "None"
|
||||
elif t is c_void_p:
|
||||
return "Any"
|
||||
elif t is c_int or t is c_uint or t is c_size_t:
|
||||
return "int"
|
||||
elif t is c_char_p or t.__name__ == "LP_c_char":
|
||||
if narg is not None:
|
||||
return "bytes"
|
||||
else:
|
||||
return "bytes | None"
|
||||
|
||||
elif t.__name__ in (
|
||||
"LP_PGconn_struct",
|
||||
"LP_PGresult_struct",
|
||||
"LP_PGcancelConn_struct",
|
||||
"LP_PGcancel_struct",
|
||||
):
|
||||
if narg is not None:
|
||||
return f"{t.__name__[3:]} | None"
|
||||
else:
|
||||
return str(t.__name__[3:])
|
||||
|
||||
elif t.__name__ in ("LP_PQconninfoOption_struct",):
|
||||
return f"Sequence[{t.__name__[3:]}]"
|
||||
|
||||
elif t.__name__ in (
|
||||
"LP_c_ubyte",
|
||||
"LP_c_char_p",
|
||||
"LP_c_int",
|
||||
"LP_c_uint",
|
||||
"LP_c_ulong",
|
||||
"LP_FILE",
|
||||
):
|
||||
return f"_Pointer[{t.__name__[3:]}]"
|
||||
|
||||
else:
|
||||
assert False, f"can't deal with {t} in {fname}"
|
||||
|
||||
fn = __file__ + "i"
|
||||
with open(fn) as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
istart, iend = (
|
||||
i
|
||||
for i, line in enumerate(lines)
|
||||
if re.match(r"\s*#\s*autogenerated:\s+(start|end)", line)
|
||||
)
|
||||
|
||||
known = {
|
||||
line[4:].split("(", 1)[0] for line in lines[:istart] if line.startswith("def ")
|
||||
}
|
||||
|
||||
signatures = []
|
||||
|
||||
for name, obj in globals().items():
|
||||
if name in known:
|
||||
continue
|
||||
if not isinstance(obj, _CFuncPtr):
|
||||
continue
|
||||
|
||||
params = []
|
||||
for i, t in enumerate(obj.argtypes):
|
||||
params.append(f"arg{i + 1}: {type2str(name, i, t)}")
|
||||
|
||||
resname = type2str(name, None, obj.restype)
|
||||
|
||||
signatures.append(f"def {name}({', '.join(params)}) -> {resname}: ...")
|
||||
|
||||
lines[istart + 1 : iend] = signatures
|
||||
|
||||
with open(fn, "w") as f:
|
||||
f.write("\n".join(lines))
|
||||
f.write("\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_stub()
|
||||
@@ -0,0 +1,229 @@
|
||||
"""
|
||||
types stub for ctypes functions
|
||||
"""
|
||||
|
||||
# Copyright (C) 2020 The Psycopg Team
|
||||
|
||||
from ctypes import Array, _Pointer, c_char, c_char_p, c_int, c_ubyte, c_uint, c_ulong
|
||||
from ctypes import pointer
|
||||
from typing import Any, Callable, Sequence
|
||||
|
||||
class FILE: ...
|
||||
|
||||
def fdopen(fd: int, mode: bytes) -> _Pointer[FILE]: ... # type: ignore[type-var]
|
||||
|
||||
Oid = c_uint
|
||||
|
||||
class PGconn_struct: ...
|
||||
class PGresult_struct: ...
|
||||
class PGcancelConn_struct: ...
|
||||
class PGcancel_struct: ...
|
||||
|
||||
class PQconninfoOption_struct:
|
||||
keyword: bytes
|
||||
envvar: bytes
|
||||
compiled: bytes
|
||||
val: bytes
|
||||
label: bytes
|
||||
dispchar: bytes
|
||||
dispsize: int
|
||||
|
||||
class PGnotify_struct:
|
||||
be_pid: int
|
||||
relname: bytes
|
||||
extra: bytes
|
||||
|
||||
class PGresAttDesc_struct:
|
||||
name: bytes
|
||||
tableid: int
|
||||
columnid: int
|
||||
format: int
|
||||
typid: int
|
||||
typlen: int
|
||||
atttypmod: int
|
||||
|
||||
def PQhostaddr(arg1: PGconn_struct | None) -> bytes: ...
|
||||
def PQerrorMessage(arg1: PGconn_struct | None) -> bytes: ...
|
||||
def PQresultErrorMessage(arg1: PGresult_struct | None) -> bytes: ...
|
||||
def PQexecPrepared(
|
||||
arg1: PGconn_struct | None,
|
||||
arg2: bytes,
|
||||
arg3: int,
|
||||
arg4: Array[c_char_p] | None,
|
||||
arg5: Array[c_int] | None,
|
||||
arg6: Array[c_int] | None,
|
||||
arg7: int,
|
||||
) -> PGresult_struct: ...
|
||||
def PQprepare(
|
||||
arg1: PGconn_struct | None,
|
||||
arg2: bytes,
|
||||
arg3: bytes,
|
||||
arg4: int,
|
||||
arg5: Array[c_uint] | None,
|
||||
) -> PGresult_struct: ...
|
||||
def PQgetvalue(
|
||||
arg1: PGresult_struct | None, arg2: int, arg3: int
|
||||
) -> _Pointer[c_char]: ...
|
||||
def PQcmdTuples(arg1: PGresult_struct | None) -> bytes: ...
|
||||
def PQescapeStringConn(
|
||||
arg1: PGconn_struct | None,
|
||||
arg2: c_char_p,
|
||||
arg3: bytes,
|
||||
arg4: int,
|
||||
arg5: _Pointer[c_int],
|
||||
) -> int: ...
|
||||
def PQescapeString(arg1: c_char_p, arg2: bytes, arg3: int) -> int: ...
|
||||
def PQsendPrepare(
|
||||
arg1: PGconn_struct | None,
|
||||
arg2: bytes,
|
||||
arg3: bytes,
|
||||
arg4: int,
|
||||
arg5: Array[c_uint] | None,
|
||||
) -> int: ...
|
||||
def PQsendQueryPrepared(
|
||||
arg1: PGconn_struct | None,
|
||||
arg2: bytes,
|
||||
arg3: int,
|
||||
arg4: Array[c_char_p] | None,
|
||||
arg5: Array[c_int] | None,
|
||||
arg6: Array[c_int] | None,
|
||||
arg7: int,
|
||||
) -> int: ...
|
||||
def PQcancelCreate(arg1: PGconn_struct | None) -> PGcancelConn_struct: ...
|
||||
def PQcancelBlocking(arg1: PGcancelConn_struct | None) -> int: ...
|
||||
def PQcancelStart(arg1: PGcancelConn_struct | None) -> int: ...
|
||||
def PQcancelPoll(arg1: PGcancelConn_struct | None) -> int: ...
|
||||
def PQcancelStatus(arg1: PGcancelConn_struct | None) -> int: ...
|
||||
def PQcancelSocket(arg1: PGcancelConn_struct | None) -> int: ...
|
||||
def PQcancelErrorMessage(arg1: PGcancelConn_struct | None) -> bytes: ...
|
||||
def PQcancelReset(arg1: PGcancelConn_struct | None) -> None: ...
|
||||
def PQcancelFinish(arg1: PGcancelConn_struct | None) -> None: ...
|
||||
def PQcancel(arg1: PGcancel_struct | None, arg2: c_char_p, arg3: int) -> int: ...
|
||||
def PQsetNoticeReceiver(
|
||||
arg1: PGconn_struct, arg2: Callable[[Any], PGresult_struct], arg3: Any
|
||||
) -> Callable[[Any], PGresult_struct]: ...
|
||||
|
||||
# TODO: Ignoring type as getting an error on mypy/ctypes:
|
||||
# Type argument "psycopg.pq._pq_ctypes.PGnotify_struct" of "pointer" must be
|
||||
# a subtype of "ctypes._CData"
|
||||
def PQnotifies(
|
||||
arg1: PGconn_struct | None,
|
||||
) -> _Pointer[PGnotify_struct] | None: ... # type: ignore
|
||||
def PQputCopyEnd(arg1: PGconn_struct | None, arg2: bytes | None) -> int: ...
|
||||
|
||||
# Arg 2 is a _Pointer, reported as _CArgObject by mypy
|
||||
def PQgetCopyData(arg1: PGconn_struct | None, arg2: Any, arg3: int) -> int: ...
|
||||
def PQsetResultAttrs(
|
||||
arg1: PGresult_struct | None,
|
||||
arg2: int,
|
||||
arg3: Array[PGresAttDesc_struct], # type: ignore
|
||||
) -> int: ...
|
||||
def PQtrace(
|
||||
arg1: PGconn_struct | None,
|
||||
arg2: _Pointer[FILE], # type: ignore[type-var]
|
||||
) -> None: ...
|
||||
def PQsetTraceFlags(arg1: PGconn_struct | None, arg2: int) -> None: ...
|
||||
def PQencryptPasswordConn(
|
||||
arg1: PGconn_struct | None,
|
||||
arg2: bytes,
|
||||
arg3: bytes,
|
||||
arg4: bytes | None,
|
||||
) -> bytes: ...
|
||||
def PQpipelineStatus(pgconn: PGconn_struct | None) -> int: ...
|
||||
def PQenterPipelineMode(pgconn: PGconn_struct | None) -> int: ...
|
||||
def PQexitPipelineMode(pgconn: PGconn_struct | None) -> int: ...
|
||||
def PQpipelineSync(pgconn: PGconn_struct | None) -> int: ...
|
||||
def PQsendFlushRequest(pgconn: PGconn_struct | None) -> int: ...
|
||||
|
||||
# Autogenerated section.
|
||||
# In order to refresh, run:
|
||||
# python -m psycopg.pq._pq_ctypes
|
||||
|
||||
# fmt: off
|
||||
# autogenerated: start
|
||||
def PQlibVersion() -> int: ...
|
||||
def PQconnectdb(arg1: bytes) -> PGconn_struct: ...
|
||||
def PQconnectStart(arg1: bytes) -> PGconn_struct: ...
|
||||
def PQconnectPoll(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQconndefaults() -> Sequence[PQconninfoOption_struct]: ...
|
||||
def PQconninfoFree(arg1: Sequence[PQconninfoOption_struct]) -> None: ...
|
||||
def PQconninfo(arg1: PGconn_struct | None) -> Sequence[PQconninfoOption_struct]: ...
|
||||
def PQconninfoParse(arg1: bytes, arg2: _Pointer[c_char_p]) -> Sequence[PQconninfoOption_struct]: ...
|
||||
def PQfinish(arg1: PGconn_struct | None) -> None: ...
|
||||
def PQreset(arg1: PGconn_struct | None) -> None: ...
|
||||
def PQresetStart(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQresetPoll(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQping(arg1: bytes) -> int: ...
|
||||
def PQdb(arg1: PGconn_struct | None) -> bytes | None: ...
|
||||
def PQuser(arg1: PGconn_struct | None) -> bytes | None: ...
|
||||
def PQpass(arg1: PGconn_struct | None) -> bytes | None: ...
|
||||
def PQhost(arg1: PGconn_struct | None) -> bytes | None: ...
|
||||
def PQport(arg1: PGconn_struct | None) -> bytes | None: ...
|
||||
def PQtty(arg1: PGconn_struct | None) -> bytes | None: ...
|
||||
def PQoptions(arg1: PGconn_struct | None) -> bytes | None: ...
|
||||
def PQstatus(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQtransactionStatus(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQparameterStatus(arg1: PGconn_struct | None, arg2: bytes) -> bytes | None: ...
|
||||
def PQprotocolVersion(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQfullProtocolVersion(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQserverVersion(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQsocket(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQbackendPID(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQconnectionNeedsPassword(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQconnectionUsedPassword(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQconnectionUsedGSSAPI(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQsslInUse(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQexec(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
|
||||
def PQexecParams(arg1: PGconn_struct | None, arg2: bytes, arg3: int, arg4: _Pointer[c_uint], arg5: _Pointer[c_char_p], arg6: _Pointer[c_int], arg7: _Pointer[c_int], arg8: int) -> PGresult_struct: ...
|
||||
def PQdescribePrepared(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
|
||||
def PQdescribePortal(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
|
||||
def PQclosePrepared(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
|
||||
def PQclosePortal(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
|
||||
def PQresultStatus(arg1: PGresult_struct | None) -> int: ...
|
||||
def PQresultErrorField(arg1: PGresult_struct | None, arg2: int) -> bytes | None: ...
|
||||
def PQclear(arg1: PGresult_struct | None) -> None: ...
|
||||
def PQntuples(arg1: PGresult_struct | None) -> int: ...
|
||||
def PQnfields(arg1: PGresult_struct | None) -> int: ...
|
||||
def PQfname(arg1: PGresult_struct | None, arg2: int) -> bytes | None: ...
|
||||
def PQftable(arg1: PGresult_struct | None, arg2: int) -> int: ...
|
||||
def PQftablecol(arg1: PGresult_struct | None, arg2: int) -> int: ...
|
||||
def PQfformat(arg1: PGresult_struct | None, arg2: int) -> int: ...
|
||||
def PQftype(arg1: PGresult_struct | None, arg2: int) -> int: ...
|
||||
def PQfmod(arg1: PGresult_struct | None, arg2: int) -> int: ...
|
||||
def PQfsize(arg1: PGresult_struct | None, arg2: int) -> int: ...
|
||||
def PQbinaryTuples(arg1: PGresult_struct | None) -> int: ...
|
||||
def PQgetisnull(arg1: PGresult_struct | None, arg2: int, arg3: int) -> int: ...
|
||||
def PQgetlength(arg1: PGresult_struct | None, arg2: int, arg3: int) -> int: ...
|
||||
def PQnparams(arg1: PGresult_struct | None) -> int: ...
|
||||
def PQparamtype(arg1: PGresult_struct | None, arg2: int) -> int: ...
|
||||
def PQcmdStatus(arg1: PGresult_struct | None) -> bytes | None: ...
|
||||
def PQoidValue(arg1: PGresult_struct | None) -> int: ...
|
||||
def PQescapeLiteral(arg1: PGconn_struct | None, arg2: bytes, arg3: int) -> bytes | None: ...
|
||||
def PQescapeIdentifier(arg1: PGconn_struct | None, arg2: bytes, arg3: int) -> bytes | None: ...
|
||||
def PQescapeByteaConn(arg1: PGconn_struct | None, arg2: bytes, arg3: int, arg4: _Pointer[c_ulong]) -> _Pointer[c_ubyte]: ...
|
||||
def PQescapeBytea(arg1: bytes, arg2: int, arg3: _Pointer[c_ulong]) -> _Pointer[c_ubyte]: ...
|
||||
def PQunescapeBytea(arg1: bytes, arg2: _Pointer[c_ulong]) -> _Pointer[c_ubyte]: ...
|
||||
def PQsendQuery(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
|
||||
def PQsendQueryParams(arg1: PGconn_struct | None, arg2: bytes, arg3: int, arg4: _Pointer[c_uint], arg5: _Pointer[c_char_p], arg6: _Pointer[c_int], arg7: _Pointer[c_int], arg8: int) -> int: ...
|
||||
def PQsendDescribePrepared(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
|
||||
def PQsendDescribePortal(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
|
||||
def PQsendClosePrepared(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
|
||||
def PQsendClosePortal(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
|
||||
def PQgetResult(arg1: PGconn_struct | None) -> PGresult_struct: ...
|
||||
def PQconsumeInput(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQisBusy(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQsetnonblocking(arg1: PGconn_struct | None, arg2: int) -> int: ...
|
||||
def PQisnonblocking(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQflush(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQsetSingleRowMode(arg1: PGconn_struct | None) -> int: ...
|
||||
def PQsetChunkedRowsMode(arg1: PGconn_struct | None, arg2: int) -> int: ...
|
||||
def PQgetCancel(arg1: PGconn_struct | None) -> PGcancel_struct: ...
|
||||
def PQfreeCancel(arg1: PGcancel_struct | None) -> None: ...
|
||||
def PQputCopyData(arg1: PGconn_struct | None, arg2: bytes, arg3: int) -> int: ...
|
||||
def PQuntrace(arg1: PGconn_struct | None) -> None: ...
|
||||
def PQfreemem(arg1: Any) -> None: ...
|
||||
def PQchangePassword(arg1: PGconn_struct | None, arg2: bytes, arg3: bytes) -> PGresult_struct: ...
|
||||
def PQmakeEmptyPGresult(arg1: PGconn_struct | None, arg2: int) -> PGresult_struct: ...
|
||||
def PQinitOpenSSL(arg1: int, arg2: int) -> None: ...
|
||||
# autogenerated: end
|
||||
# fmt: on
|
||||
@@ -0,0 +1,345 @@
|
||||
"""
|
||||
Protocol objects to represent objects exposed by different pq implementations.
|
||||
"""
|
||||
|
||||
# Copyright (C) 2020 The Psycopg Team
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Protocol, TypeAlias, Union
|
||||
from collections.abc import Callable, Sequence
|
||||
|
||||
from ._enums import Format, Trace
|
||||
from .._compat import Self
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .misc import ConninfoOption, PGnotify, PGresAttDesc
|
||||
|
||||
# An object implementing the buffer protocol (ish)
|
||||
Buffer: TypeAlias = Union[bytes, bytearray, memoryview]
|
||||
|
||||
|
||||
class PGconn(Protocol):
|
||||
notice_handler: Callable[[PGresult], None] | None
|
||||
notify_handler: Callable[[PGnotify], None] | None
|
||||
|
||||
@classmethod
|
||||
def connect(cls, conninfo: bytes) -> Self: ...
|
||||
|
||||
@classmethod
|
||||
def connect_start(cls, conninfo: bytes) -> Self: ...
|
||||
|
||||
def connect_poll(self) -> int: ...
|
||||
|
||||
def finish(self) -> None: ...
|
||||
|
||||
@property
|
||||
def info(self) -> list[ConninfoOption]: ...
|
||||
|
||||
def reset(self) -> None: ...
|
||||
|
||||
def reset_start(self) -> None: ...
|
||||
|
||||
def reset_poll(self) -> int: ...
|
||||
|
||||
@classmethod
|
||||
def ping(self, conninfo: bytes) -> int: ...
|
||||
|
||||
@property
|
||||
def db(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def user(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def password(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def host(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def hostaddr(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def port(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def tty(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def options(self) -> bytes: ...
|
||||
|
||||
@property
|
||||
def status(self) -> int: ...
|
||||
|
||||
@property
|
||||
def transaction_status(self) -> int: ...
|
||||
|
||||
def parameter_status(self, name: bytes) -> bytes | None: ...
|
||||
|
||||
@property
|
||||
def error_message(self) -> bytes: ...
|
||||
|
||||
def get_error_message(self, encoding: str = ...) -> str: ...
|
||||
|
||||
@property
|
||||
def _encoding(self) -> str: ...
|
||||
|
||||
@property
|
||||
def protocol_version(self) -> int: ...
|
||||
|
||||
@property
|
||||
def full_protocol_version(self) -> int: ...
|
||||
|
||||
@property
|
||||
def server_version(self) -> int: ...
|
||||
|
||||
@property
|
||||
def socket(self) -> int: ...
|
||||
|
||||
@property
|
||||
def backend_pid(self) -> int: ...
|
||||
|
||||
@property
|
||||
def needs_password(self) -> bool: ...
|
||||
|
||||
@property
|
||||
def used_password(self) -> bool: ...
|
||||
|
||||
@property
|
||||
def used_gssapi(self) -> bool: ...
|
||||
|
||||
@property
|
||||
def ssl_in_use(self) -> bool: ...
|
||||
|
||||
def exec_(self, command: bytes) -> PGresult: ...
|
||||
|
||||
def send_query(self, command: bytes) -> None: ...
|
||||
|
||||
def exec_params(
|
||||
self,
|
||||
command: bytes,
|
||||
param_values: Sequence[Buffer | None] | None,
|
||||
param_types: Sequence[int] | None = None,
|
||||
param_formats: Sequence[int] | None = None,
|
||||
result_format: int = Format.TEXT,
|
||||
) -> PGresult: ...
|
||||
|
||||
def send_query_params(
|
||||
self,
|
||||
command: bytes,
|
||||
param_values: Sequence[Buffer | None] | None,
|
||||
param_types: Sequence[int] | None = None,
|
||||
param_formats: Sequence[int] | None = None,
|
||||
result_format: int = Format.TEXT,
|
||||
) -> None: ...
|
||||
|
||||
def send_prepare(
|
||||
self,
|
||||
name: bytes,
|
||||
command: bytes,
|
||||
param_types: Sequence[int] | None = None,
|
||||
) -> None: ...
|
||||
|
||||
def send_query_prepared(
|
||||
self,
|
||||
name: bytes,
|
||||
param_values: Sequence[Buffer | None] | None,
|
||||
param_formats: Sequence[int] | None = None,
|
||||
result_format: int = Format.TEXT,
|
||||
) -> None: ...
|
||||
|
||||
def prepare(
|
||||
self,
|
||||
name: bytes,
|
||||
command: bytes,
|
||||
param_types: Sequence[int] | None = None,
|
||||
) -> PGresult: ...
|
||||
|
||||
def exec_prepared(
|
||||
self,
|
||||
name: bytes,
|
||||
param_values: Sequence[Buffer] | None,
|
||||
param_formats: Sequence[int] | None = None,
|
||||
result_format: int = 0,
|
||||
) -> PGresult: ...
|
||||
|
||||
def describe_prepared(self, name: bytes) -> PGresult: ...
|
||||
|
||||
def send_describe_prepared(self, name: bytes) -> None: ...
|
||||
|
||||
def describe_portal(self, name: bytes) -> PGresult: ...
|
||||
|
||||
def send_describe_portal(self, name: bytes) -> None: ...
|
||||
|
||||
def close_prepared(self, name: bytes) -> PGresult: ...
|
||||
|
||||
def send_close_prepared(self, name: bytes) -> None: ...
|
||||
|
||||
def close_portal(self, name: bytes) -> PGresult: ...
|
||||
|
||||
def send_close_portal(self, name: bytes) -> None: ...
|
||||
|
||||
def get_result(self) -> PGresult | None: ...
|
||||
|
||||
def consume_input(self) -> None: ...
|
||||
|
||||
def is_busy(self) -> int: ...
|
||||
|
||||
@property
|
||||
def nonblocking(self) -> int: ...
|
||||
|
||||
@nonblocking.setter
|
||||
def nonblocking(self, arg: int) -> None: ...
|
||||
|
||||
def flush(self) -> int: ...
|
||||
|
||||
def set_single_row_mode(self) -> None: ...
|
||||
|
||||
def set_chunked_rows_mode(self, size: int) -> None: ...
|
||||
|
||||
def cancel_conn(self) -> PGcancelConn: ...
|
||||
|
||||
def get_cancel(self) -> PGcancel: ...
|
||||
|
||||
def notifies(self) -> PGnotify | None: ...
|
||||
|
||||
def put_copy_data(self, buffer: Buffer) -> int: ...
|
||||
|
||||
def put_copy_end(self, error: bytes | None = None) -> int: ...
|
||||
|
||||
def get_copy_data(self, async_: int) -> tuple[int, memoryview]: ...
|
||||
|
||||
def trace(self, fileno: int) -> None: ...
|
||||
|
||||
def set_trace_flags(self, flags: Trace) -> None: ...
|
||||
|
||||
def untrace(self) -> None: ...
|
||||
|
||||
def encrypt_password(
|
||||
self, passwd: bytes, user: bytes, algorithm: bytes | None = None
|
||||
) -> bytes: ...
|
||||
|
||||
def change_password(self, user: bytes, passwd: bytes) -> None: ...
|
||||
|
||||
def make_empty_result(self, exec_status: int) -> PGresult: ...
|
||||
|
||||
@property
|
||||
def pipeline_status(self) -> int: ...
|
||||
|
||||
def enter_pipeline_mode(self) -> None: ...
|
||||
|
||||
def exit_pipeline_mode(self) -> None: ...
|
||||
|
||||
def pipeline_sync(self) -> None: ...
|
||||
|
||||
def send_flush_request(self) -> None: ...
|
||||
|
||||
|
||||
class PGresult(Protocol):
|
||||
def clear(self) -> None: ...
|
||||
|
||||
@property
|
||||
def status(self) -> int: ...
|
||||
|
||||
@property
|
||||
def error_message(self) -> bytes: ...
|
||||
|
||||
def get_error_message(self, encoding: str = ...) -> str: ...
|
||||
|
||||
def error_field(self, fieldcode: int) -> bytes | None: ...
|
||||
|
||||
@property
|
||||
def ntuples(self) -> int: ...
|
||||
|
||||
@property
|
||||
def nfields(self) -> int: ...
|
||||
|
||||
def fname(self, column_number: int) -> bytes | None: ...
|
||||
|
||||
def ftable(self, column_number: int) -> int: ...
|
||||
|
||||
def ftablecol(self, column_number: int) -> int: ...
|
||||
|
||||
def fformat(self, column_number: int) -> int: ...
|
||||
|
||||
def ftype(self, column_number: int) -> int: ...
|
||||
|
||||
def fmod(self, column_number: int) -> int: ...
|
||||
|
||||
def fsize(self, column_number: int) -> int: ...
|
||||
|
||||
@property
|
||||
def binary_tuples(self) -> int: ...
|
||||
|
||||
def get_value(self, row_number: int, column_number: int) -> bytes | None: ...
|
||||
|
||||
@property
|
||||
def nparams(self) -> int: ...
|
||||
|
||||
def param_type(self, param_number: int) -> int: ...
|
||||
|
||||
@property
|
||||
def command_status(self) -> bytes | None: ...
|
||||
|
||||
@property
|
||||
def command_tuples(self) -> int | None: ...
|
||||
|
||||
@property
|
||||
def oid_value(self) -> int: ...
|
||||
|
||||
def set_attributes(self, descriptions: list[PGresAttDesc]) -> None: ...
|
||||
|
||||
|
||||
class PGcancelConn(Protocol):
|
||||
def start(self) -> None: ...
|
||||
|
||||
def blocking(self) -> None: ...
|
||||
|
||||
def poll(self) -> int: ...
|
||||
|
||||
@property
|
||||
def status(self) -> int: ...
|
||||
|
||||
@property
|
||||
def socket(self) -> int: ...
|
||||
|
||||
@property
|
||||
def error_message(self) -> bytes: ...
|
||||
|
||||
def get_error_message(self, encoding: str = ...) -> str: ...
|
||||
|
||||
def reset(self) -> None: ...
|
||||
|
||||
def finish(self) -> None: ...
|
||||
|
||||
|
||||
class PGcancel(Protocol):
|
||||
def free(self) -> None: ...
|
||||
|
||||
def cancel(self) -> None: ...
|
||||
|
||||
|
||||
class Conninfo(Protocol):
|
||||
@classmethod
|
||||
def get_defaults(cls) -> list[ConninfoOption]: ...
|
||||
|
||||
@classmethod
|
||||
def parse(cls, conninfo: bytes) -> list[ConninfoOption]: ...
|
||||
|
||||
@classmethod
|
||||
def _options_from_array(cls, opts: Sequence[Any]) -> list[ConninfoOption]: ...
|
||||
|
||||
|
||||
class Escaping(Protocol):
|
||||
def __init__(self, conn: PGconn | None = None): ...
|
||||
|
||||
def escape_literal(self, data: Buffer) -> bytes: ...
|
||||
|
||||
def escape_identifier(self, data: Buffer) -> bytes: ...
|
||||
|
||||
def escape_string(self, data: Buffer) -> bytes: ...
|
||||
|
||||
def escape_bytea(self, data: Buffer) -> bytes: ...
|
||||
|
||||
def unescape_bytea(self, data: Buffer) -> bytes: ...
|
||||
@@ -0,0 +1,198 @@
|
||||
"""
|
||||
Various functionalities to make easier to work with the libpq.
|
||||
"""
|
||||
|
||||
# Copyright (C) 2020 The Psycopg Team
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import logging
|
||||
import ctypes.util
|
||||
from typing import NamedTuple
|
||||
from pathlib import Path
|
||||
from functools import cache
|
||||
|
||||
from . import abc
|
||||
from ._enums import ConnStatus, PipelineStatus, TransactionStatus
|
||||
|
||||
logger = logging.getLogger("psycopg.pq")
|
||||
|
||||
OK = ConnStatus.OK
|
||||
|
||||
|
||||
class PGnotify(NamedTuple):
|
||||
relname: bytes
|
||||
be_pid: int
|
||||
extra: bytes
|
||||
|
||||
|
||||
class ConninfoOption(NamedTuple):
|
||||
keyword: bytes
|
||||
envvar: bytes | None
|
||||
compiled: bytes | None
|
||||
val: bytes | None
|
||||
label: bytes
|
||||
dispchar: bytes
|
||||
dispsize: int
|
||||
|
||||
|
||||
class PGresAttDesc(NamedTuple):
|
||||
name: bytes
|
||||
tableid: int
|
||||
columnid: int
|
||||
format: int
|
||||
typid: int
|
||||
typlen: int
|
||||
atttypmod: int
|
||||
|
||||
|
||||
@cache
|
||||
def find_libpq_full_path() -> str | None:
|
||||
if sys.platform == "win32":
|
||||
if (libname := ctypes.util.find_library("libpq.dll")) is None:
|
||||
return None
|
||||
libname = str(Path(libname).resolve())
|
||||
elif sys.platform == "darwin":
|
||||
libname = ctypes.util.find_library("libpq.dylib")
|
||||
# (hopefully) temporary hack: libpq not in a standard place
|
||||
# https://github.com/orgs/Homebrew/discussions/3595
|
||||
# If pg_config is available and agrees, let's use its indications.
|
||||
if not libname:
|
||||
try:
|
||||
import subprocess as sp
|
||||
|
||||
libdir = sp.check_output(["pg_config", "--libdir"]).strip().decode()
|
||||
if not os.path.exists(libname := os.path.join(libdir, "libpq.dylib")):
|
||||
libname = None
|
||||
except Exception as ex:
|
||||
logger.debug("couldn't use pg_config to find libpq: %s", ex)
|
||||
|
||||
else:
|
||||
libname = ctypes.util.find_library("pq")
|
||||
|
||||
return libname
|
||||
|
||||
|
||||
def error_message(
|
||||
obj: abc.PGconn | abc.PGresult | abc.PGcancelConn, encoding: str = ""
|
||||
) -> str:
|
||||
"""
|
||||
Return an error message from a `PGconn`, `PGresult`, `PGcancelConn`.
|
||||
|
||||
The return value is a `!str` (unlike pq data which is usually `!bytes`):
|
||||
use the connection encoding if available, otherwise the `!encoding`
|
||||
parameter as a fallback for decoding. Don't raise exceptions on decoding
|
||||
errors.
|
||||
"""
|
||||
# Note: this function is exposed by the pq module and was documented, therefore
|
||||
# we are not going to remove it, but we don't use it internally.
|
||||
|
||||
# Don't pass the encoding if not specified, because different classes have
|
||||
# different defaults (conn has its own encoding. others default to utf8).
|
||||
return obj.get_error_message(encoding) if encoding else obj.get_error_message()
|
||||
|
||||
|
||||
# Possible prefixes to strip for error messages, in the known localizations.
|
||||
# This regular expression is generated from PostgreSQL sources using the
|
||||
# `tools/update_error_prefixes.py` script
|
||||
PREFIXES = re.compile(
|
||||
# autogenerated: start
|
||||
r"""
|
||||
^ (?:
|
||||
DEBUG | INFO | HINWEIS | WARNUNG | FEHLER | LOG | FATAL | PANIK # de
|
||||
| DEBUG | INFO | NOTICE | WARNING | ERROR | LOG | FATAL | PANIC # en
|
||||
| DEBUG | INFO | NOTICE | WARNING | ERROR | LOG | FATAL | PANIC # es
|
||||
| DEBUG | INFO | NOTICE | ATTENTION | ERREUR | LOG | FATAL | PANIC # fr
|
||||
| DEBUG | INFO | NOTICE | PERINGATAN | ERROR | LOG | FATAL | PANIK # id
|
||||
| DEBUG | INFO | NOTIFICA | ATTENZIONE | ERRORE | LOG | FATALE | PANICO # it
|
||||
| DEBUG | INFO | NOTICE | WARNING | ERROR | LOG | FATAL | PANIC # ja
|
||||
| 디버그 | 정보 | 알림 | 경고 | 오류 | 로그 | 치명적오류 | 손상 # ko
|
||||
| DEBUG | INFORMACJA | UWAGA | OSTRZEŻENIE | BŁĄD | DZIENNIK | KATASTROFALNY | PANIKA # pl
|
||||
| DEPURAÇÃO | INFO | NOTA | AVISO | ERRO | LOG | FATAL | PÂNICO # pt_BR
|
||||
| ОТЛАДКА | ИНФОРМАЦИЯ | ЗАМЕЧАНИЕ | ПРЕДУПРЕЖДЕНИЕ | ОШИБКА | СООБЩЕНИЕ | ВАЖНО | ПАНИКА # ru
|
||||
| DEBUG | INFO | NOTIS | VARNING | FEL | LOGG | FATALT | PANIK # sv
|
||||
| DEBUG | BİLGİ | NOT | UYARI | HATA | LOG | ÖLÜMCÜL\ \(FATAL\) | KRİTİK # tr
|
||||
| НАЛАГОДЖЕННЯ | ІНФОРМАЦІЯ | ПОВІДОМЛЕННЯ | ПОПЕРЕДЖЕННЯ | ПОМИЛКА | ЗАПИСУВАННЯ | ФАТАЛЬНО | ПАНІКА # uk
|
||||
| 调试 | 信息 | 注意 | 警告 | 错误 | 日志 | 致命错误 | 比致命错误还过分的错误 # zh_CN
|
||||
) : \s+
|
||||
""", # noqa: E501
|
||||
# autogenerated: end
|
||||
re.VERBOSE | re.MULTILINE,
|
||||
)
|
||||
|
||||
|
||||
def strip_severity(msg: str) -> str:
|
||||
"""Strip severity and whitespaces from error message."""
|
||||
if m := PREFIXES.match(msg):
|
||||
msg = msg[m.span()[1] :]
|
||||
|
||||
return msg.strip()
|
||||
|
||||
|
||||
def _clean_error_message(msg: bytes, encoding: str) -> str:
|
||||
if smsg := msg.decode(encoding, "replace"):
|
||||
return strip_severity(smsg)
|
||||
else:
|
||||
return "no error details available"
|
||||
|
||||
|
||||
def connection_summary(pgconn: abc.PGconn) -> str:
|
||||
"""
|
||||
Return summary information on a connection.
|
||||
|
||||
Useful for __repr__
|
||||
"""
|
||||
parts = []
|
||||
if pgconn.status == OK:
|
||||
# Put together the [STATUS]
|
||||
status: str = TransactionStatus(pgconn.transaction_status).name
|
||||
if pgconn.pipeline_status:
|
||||
status += f", pipeline={PipelineStatus(pgconn.pipeline_status).name}"
|
||||
|
||||
# Put together the (CONNECTION)
|
||||
if not pgconn.host.startswith(b"/"):
|
||||
parts.append(("host", pgconn.host.decode()))
|
||||
if (port := pgconn.port.decode() or get_compiled_port()) != "5432":
|
||||
parts.append(("port", port))
|
||||
if pgconn.user != pgconn.db:
|
||||
parts.append(("user", pgconn.user.decode()))
|
||||
parts.append(("database", pgconn.db.decode()))
|
||||
|
||||
else:
|
||||
try:
|
||||
status = ConnStatus(pgconn.status).name
|
||||
except ValueError:
|
||||
# It might happen if a new status on connection appears
|
||||
# before upgrading the ConnStatus enum.
|
||||
status = f"status={pgconn.status} (unkndown)"
|
||||
|
||||
if sparts := " ".join("%s=%s" % part for part in parts):
|
||||
sparts = f" ({sparts})"
|
||||
return f"[{status}]{sparts}"
|
||||
|
||||
|
||||
def version_pretty(version: int) -> str:
|
||||
"""
|
||||
Return a pretty representation of a PostgreSQL version
|
||||
|
||||
For instance: 140002 -> 14.2, 90610 -> 9.6.10
|
||||
"""
|
||||
version, patch = divmod(version, 100)
|
||||
major, minor = divmod(version, 100)
|
||||
if major >= 10 and minor == 0:
|
||||
return f"{major}.{patch}"
|
||||
else:
|
||||
return f"{major}.{minor}.{patch}"
|
||||
|
||||
|
||||
@cache
|
||||
def get_compiled_port() -> str:
|
||||
"""Return the default port compiled with the libpq."""
|
||||
|
||||
from psycopg._conninfo_utils import get_param_def
|
||||
|
||||
info = get_param_def("port")
|
||||
return info.compiled if info and info.compiled else ""
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user