123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- """psycopg extensions to the DBAPI-2.0
- This module holds all the extensions to the DBAPI-2.0 provided by psycopg.
- - `connection` -- the new-type inheritable connection class
- - `cursor` -- the new-type inheritable cursor class
- - `lobject` -- the new-type inheritable large object class
- - `adapt()` -- exposes the PEP-246_ compatible adapting mechanism used
- by psycopg to adapt Python types to PostgreSQL ones
- .. _PEP-246: https://www.python.org/dev/peps/pep-0246/
- """
- # psycopg/extensions.py - DBAPI-2.0 extensions specific to psycopg
- #
- # Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
- # Copyright (C) 2020-2021 The Psycopg Team
- #
- # psycopg2 is free software: you can redistribute it and/or modify it
- # under the terms of the GNU Lesser General Public License as published
- # by the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # In addition, as a special exception, the copyright holders give
- # permission to link this program with the OpenSSL library (or with
- # modified versions of OpenSSL that use the same license as OpenSSL),
- # and distribute linked combinations including the two.
- #
- # You must obey the GNU Lesser General Public License in all respects for
- # all of the code used other than OpenSSL.
- #
- # psycopg2 is distributed in the hope that it will be useful, but WITHOUT
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- # License for more details.
- import re as _re
- from psycopg2._psycopg import ( # noqa
- BINARYARRAY, BOOLEAN, BOOLEANARRAY, BYTES, BYTESARRAY, DATE, DATEARRAY,
- DATETIMEARRAY, DECIMAL, DECIMALARRAY, FLOAT, FLOATARRAY, INTEGER,
- INTEGERARRAY, INTERVAL, INTERVALARRAY, LONGINTEGER, LONGINTEGERARRAY,
- ROWIDARRAY, STRINGARRAY, TIME, TIMEARRAY, UNICODE, UNICODEARRAY,
- AsIs, Binary, Boolean, Float, Int, QuotedString, )
- from psycopg2._psycopg import ( # noqa
- PYDATE, PYDATETIME, PYDATETIMETZ, PYINTERVAL, PYTIME, PYDATEARRAY,
- PYDATETIMEARRAY, PYDATETIMETZARRAY, PYINTERVALARRAY, PYTIMEARRAY,
- DateFromPy, TimeFromPy, TimestampFromPy, IntervalFromPy, )
- from psycopg2._psycopg import ( # noqa
- adapt, adapters, encodings, connection, cursor,
- lobject, Xid, libpq_version, parse_dsn, quote_ident,
- string_types, binary_types, new_type, new_array_type, register_type,
- ISQLQuote, Notify, Diagnostics, Column, ConnectionInfo,
- QueryCanceledError, TransactionRollbackError,
- set_wait_callback, get_wait_callback, encrypt_password, )
- """Isolation level values."""
- ISOLATION_LEVEL_AUTOCOMMIT = 0
- ISOLATION_LEVEL_READ_UNCOMMITTED = 4
- ISOLATION_LEVEL_READ_COMMITTED = 1
- ISOLATION_LEVEL_REPEATABLE_READ = 2
- ISOLATION_LEVEL_SERIALIZABLE = 3
- ISOLATION_LEVEL_DEFAULT = None
- """psycopg connection status values."""
- STATUS_SETUP = 0
- STATUS_READY = 1
- STATUS_BEGIN = 2
- STATUS_SYNC = 3 # currently unused
- STATUS_ASYNC = 4 # currently unused
- STATUS_PREPARED = 5
- # This is a useful mnemonic to check if the connection is in a transaction
- STATUS_IN_TRANSACTION = STATUS_BEGIN
- """psycopg asynchronous connection polling values"""
- POLL_OK = 0
- POLL_READ = 1
- POLL_WRITE = 2
- POLL_ERROR = 3
- """Backend transaction status values."""
- TRANSACTION_STATUS_IDLE = 0
- TRANSACTION_STATUS_ACTIVE = 1
- TRANSACTION_STATUS_INTRANS = 2
- TRANSACTION_STATUS_INERROR = 3
- TRANSACTION_STATUS_UNKNOWN = 4
- def register_adapter(typ, callable):
- """Register 'callable' as an ISQLQuote adapter for type 'typ'."""
- adapters[(typ, ISQLQuote)] = callable
- # The SQL_IN class is the official adapter for tuples starting from 2.0.6.
- class SQL_IN:
- """Adapt any iterable to an SQL quotable object."""
- def __init__(self, seq):
- self._seq = seq
- self._conn = None
- def prepare(self, conn):
- self._conn = conn
- def getquoted(self):
- # this is the important line: note how every object in the
- # list is adapted and then how getquoted() is called on it
- pobjs = [adapt(o) for o in self._seq]
- if self._conn is not None:
- for obj in pobjs:
- if hasattr(obj, 'prepare'):
- obj.prepare(self._conn)
- qobjs = [o.getquoted() for o in pobjs]
- return b'(' + b', '.join(qobjs) + b')'
- def __str__(self):
- return str(self.getquoted())
- class NoneAdapter:
- """Adapt None to NULL.
- This adapter is not used normally as a fast path in mogrify uses NULL,
- but it makes easier to adapt composite types.
- """
- def __init__(self, obj):
- pass
- def getquoted(self, _null=b"NULL"):
- return _null
- def make_dsn(dsn=None, **kwargs):
- """Convert a set of keywords into a connection strings."""
- if dsn is None and not kwargs:
- return ''
- # If no kwarg is specified don't mung the dsn, but verify it
- if not kwargs:
- parse_dsn(dsn)
- return dsn
- # Override the dsn with the parameters
- if 'database' in kwargs:
- if 'dbname' in kwargs:
- raise TypeError(
- "you can't specify both 'database' and 'dbname' arguments")
- kwargs['dbname'] = kwargs.pop('database')
- # Drop the None arguments
- kwargs = {k: v for (k, v) in kwargs.items() if v is not None}
- if dsn is not None:
- tmp = parse_dsn(dsn)
- tmp.update(kwargs)
- kwargs = tmp
- dsn = " ".join(["{}={}".format(k, _param_escape(str(v)))
- for (k, v) in kwargs.items()])
- # verify that the returned dsn is valid
- parse_dsn(dsn)
- return dsn
- def _param_escape(s,
- re_escape=_re.compile(r"([\\'])"),
- re_space=_re.compile(r'\s')):
- """
- Apply the escaping rule required by PQconnectdb
- """
- if not s:
- return "''"
- s = re_escape.sub(r'\\\1', s)
- if re_space.search(s):
- s = "'" + s + "'"
- return s
- # Create default json typecasters for PostgreSQL 9.2 oids
- from psycopg2._json import register_default_json, register_default_jsonb # noqa
- try:
- JSON, JSONARRAY = register_default_json()
- JSONB, JSONBARRAY = register_default_jsonb()
- except ImportError:
- pass
- del register_default_json, register_default_jsonb
- # Create default Range typecasters
- from psycopg2. _range import Range # noqa
- del Range
- # Add the "cleaned" version of the encodings to the key.
- # When the encoding is set its name is cleaned up from - and _ and turned
- # uppercase, so an encoding not respecting these rules wouldn't be found in the
- # encodings keys and would raise an exception with the unicode typecaster
- for k, v in list(encodings.items()):
- k = k.replace('_', '').replace('-', '').upper()
- encodings[k] = v
- del k, v
|