2005-10-18 09:42:00 +04:00
|
|
|
"""psycopg extensions to the DBAPI-2.0
|
2005-01-20 08:49:40 +03:00
|
|
|
|
2005-10-18 09:42:00 +04:00
|
|
|
This module holds all the extensions to the DBAPI-2.0 provided by psycopg.
|
2005-01-20 08:49:40 +03:00
|
|
|
|
2005-11-26 10:47:48 +03:00
|
|
|
- `connection` -- the new-type inheritable connection class
|
|
|
|
- `cursor` -- the new-type inheritable cursor class
|
2006-09-02 09:33:03 +04:00
|
|
|
- `lobject` -- the new-type inheritable large object class
|
2006-01-05 19:56:40 +03:00
|
|
|
- `adapt()` -- exposes the PEP-246_ compatible adapting mechanism used
|
2005-11-26 10:47:48 +03:00
|
|
|
by psycopg to adapt Python types to PostgreSQL ones
|
2016-03-03 07:33:59 +03:00
|
|
|
|
2018-09-23 04:54:55 +03:00
|
|
|
.. _PEP-246: https://www.python.org/dev/peps/pep-0246/
|
2005-01-20 08:49:40 +03:00
|
|
|
"""
|
2004-10-19 07:17:12 +04:00
|
|
|
# psycopg/extensions.py - DBAPI-2.0 extensions specific to psycopg
|
|
|
|
#
|
2019-02-17 04:34:52 +03:00
|
|
|
# Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
|
2021-06-15 02:37:22 +03:00
|
|
|
# Copyright (C) 2020-2021 The Psycopg Team
|
2004-10-19 07:17:12 +04:00
|
|
|
#
|
2010-02-13 01:34:53 +03:00
|
|
|
# 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.
|
2004-10-19 07:17:12 +04:00
|
|
|
#
|
2010-02-13 01:34:53 +03:00
|
|
|
# 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.
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2016-03-03 07:33:59 +03:00
|
|
|
import re as _re
|
|
|
|
|
2016-10-11 02:10:53 +03:00
|
|
|
from psycopg2._psycopg import ( # noqa
|
2019-01-18 18:47:01 +03:00
|
|
|
BINARYARRAY, BOOLEAN, BOOLEANARRAY, BYTES, BYTESARRAY, DATE, DATEARRAY,
|
|
|
|
DATETIMEARRAY, DECIMAL, DECIMALARRAY, FLOAT, FLOATARRAY, INTEGER,
|
|
|
|
INTEGERARRAY, INTERVAL, INTERVALARRAY, LONGINTEGER, LONGINTEGERARRAY,
|
|
|
|
ROWIDARRAY, STRINGARRAY, TIME, TIMEARRAY, UNICODE, UNICODEARRAY,
|
2016-10-11 02:10:53 +03:00
|
|
|
AsIs, Binary, Boolean, Float, Int, QuotedString, )
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2019-03-14 04:21:16 +03:00
|
|
|
from psycopg2._psycopg import ( # noqa
|
|
|
|
PYDATE, PYDATETIME, PYDATETIMETZ, PYINTERVAL, PYTIME, PYDATEARRAY,
|
|
|
|
PYDATETIMEARRAY, PYDATETIMETZARRAY, PYINTERVALARRAY, PYTIMEARRAY,
|
|
|
|
DateFromPy, TimeFromPy, TimestampFromPy, IntervalFromPy, )
|
2004-10-19 07:17:12 +04:00
|
|
|
|
2016-10-11 02:10:53 +03:00
|
|
|
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,
|
2018-10-12 01:55:36 +03:00
|
|
|
ISQLQuote, Notify, Diagnostics, Column, ConnectionInfo,
|
2016-10-11 02:10:53 +03:00
|
|
|
QueryCanceledError, TransactionRollbackError,
|
2017-09-14 21:12:37 +03:00
|
|
|
set_wait_callback, get_wait_callback, encrypt_password, )
|
2005-01-20 08:49:40 +03:00
|
|
|
|
2010-04-02 04:56:38 +04:00
|
|
|
|
2005-10-08 07:04:40 +04:00
|
|
|
"""Isolation level values."""
|
2016-10-11 02:10:53 +03:00
|
|
|
ISOLATION_LEVEL_AUTOCOMMIT = 0
|
|
|
|
ISOLATION_LEVEL_READ_UNCOMMITTED = 4
|
|
|
|
ISOLATION_LEVEL_READ_COMMITTED = 1
|
|
|
|
ISOLATION_LEVEL_REPEATABLE_READ = 2
|
|
|
|
ISOLATION_LEVEL_SERIALIZABLE = 3
|
2017-02-16 05:07:05 +03:00
|
|
|
ISOLATION_LEVEL_DEFAULT = None
|
2016-10-11 02:10:53 +03:00
|
|
|
|
2011-12-15 15:22:52 +04:00
|
|
|
|
2007-04-26 02:42:36 +04:00
|
|
|
"""psycopg connection status values."""
|
2016-10-11 02:10:53 +03:00
|
|
|
STATUS_SETUP = 0
|
|
|
|
STATUS_READY = 1
|
|
|
|
STATUS_BEGIN = 2
|
|
|
|
STATUS_SYNC = 3 # currently unused
|
|
|
|
STATUS_ASYNC = 4 # currently unused
|
2010-10-09 01:03:06 +04:00
|
|
|
STATUS_PREPARED = 5
|
2006-09-01 12:20:11 +04:00
|
|
|
|
2013-04-26 12:21:56 +04:00
|
|
|
# This is a useful mnemonic to check if the connection is in a transaction
|
2006-09-01 12:20:11 +04:00
|
|
|
STATUS_IN_TRANSACTION = STATUS_BEGIN
|
|
|
|
|
2016-10-11 02:10:53 +03:00
|
|
|
|
2010-04-05 18:52:25 +04:00
|
|
|
"""psycopg asynchronous connection polling values"""
|
2016-10-11 02:10:53 +03:00
|
|
|
POLL_OK = 0
|
|
|
|
POLL_READ = 1
|
2010-04-05 13:30:03 +04:00
|
|
|
POLL_WRITE = 2
|
2010-04-02 04:56:38 +04:00
|
|
|
POLL_ERROR = 3
|
2010-04-05 13:30:03 +04:00
|
|
|
|
2016-10-11 02:10:53 +03:00
|
|
|
|
2007-04-26 02:42:36 +04:00
|
|
|
"""Backend transaction status values."""
|
2016-10-11 02:10:53 +03:00
|
|
|
TRANSACTION_STATUS_IDLE = 0
|
|
|
|
TRANSACTION_STATUS_ACTIVE = 1
|
2007-04-26 02:42:36 +04:00
|
|
|
TRANSACTION_STATUS_INTRANS = 2
|
|
|
|
TRANSACTION_STATUS_INERROR = 3
|
|
|
|
TRANSACTION_STATUS_UNKNOWN = 4
|
2005-01-20 08:49:40 +03:00
|
|
|
|
2010-12-29 05:43:19 +03:00
|
|
|
|
2005-01-20 08:49:40 +03:00
|
|
|
def register_adapter(typ, callable):
|
|
|
|
"""Register 'callable' as an ISQLQuote adapter for type 'typ'."""
|
|
|
|
adapters[(typ, ISQLQuote)] = callable
|
2006-01-12 21:36:57 +03:00
|
|
|
|
2007-01-16 13:58:05 +03:00
|
|
|
|
|
|
|
# The SQL_IN class is the official adapter for tuples starting from 2.0.6.
|
2020-11-17 22:37:42 +03:00
|
|
|
class SQL_IN:
|
2007-01-16 13:58:05 +03:00
|
|
|
"""Adapt any iterable to an SQL quotable object."""
|
|
|
|
def __init__(self, seq):
|
|
|
|
self._seq = seq
|
2012-09-24 19:55:01 +04:00
|
|
|
self._conn = None
|
2007-01-16 13:58:05 +03:00
|
|
|
|
|
|
|
def prepare(self, conn):
|
|
|
|
self._conn = conn
|
2012-09-24 19:55:01 +04:00
|
|
|
|
2007-01-16 13:58:05 +03:00
|
|
|
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]
|
2012-09-24 19:55:01 +04:00
|
|
|
if self._conn is not None:
|
|
|
|
for obj in pobjs:
|
|
|
|
if hasattr(obj, 'prepare'):
|
|
|
|
obj.prepare(self._conn)
|
2011-01-01 18:53:11 +03:00
|
|
|
qobjs = [o.getquoted() for o in pobjs]
|
2016-08-15 03:55:57 +03:00
|
|
|
return b'(' + b', '.join(qobjs) + b')'
|
2007-01-16 13:58:05 +03:00
|
|
|
|
2011-01-01 18:53:11 +03:00
|
|
|
def __str__(self):
|
|
|
|
return str(self.getquoted())
|
2007-01-16 13:58:05 +03:00
|
|
|
|
|
|
|
|
2020-11-17 22:37:42 +03:00
|
|
|
class NoneAdapter:
|
2010-12-31 21:21:44 +03:00
|
|
|
"""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
|
|
|
|
|
2016-08-15 03:55:57 +03:00
|
|
|
def getquoted(self, _null=b"NULL"):
|
2011-01-01 18:53:11 +03:00
|
|
|
return _null
|
2010-12-31 21:21:44 +03:00
|
|
|
|
|
|
|
|
2016-03-03 07:33:59 +03:00
|
|
|
def make_dsn(dsn=None, **kwargs):
|
|
|
|
"""Convert a set of keywords into a connection strings."""
|
2016-03-03 18:07:38 +03:00
|
|
|
if dsn is None and not kwargs:
|
2016-03-03 19:58:24 +03:00
|
|
|
return ''
|
2016-03-03 18:07:38 +03:00
|
|
|
|
2016-03-03 19:52:53 +03:00
|
|
|
# If no kwarg is specified don't mung the dsn, but verify it
|
2016-03-03 18:07:38 +03:00
|
|
|
if not kwargs:
|
2016-03-03 19:52:53 +03:00
|
|
|
parse_dsn(dsn)
|
2016-03-03 18:07:38 +03:00
|
|
|
return dsn
|
|
|
|
|
2016-03-03 07:33:59 +03:00
|
|
|
# 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')
|
|
|
|
|
2017-03-01 23:12:13 +03:00
|
|
|
# Drop the None arguments
|
2017-12-11 05:35:41 +03:00
|
|
|
kwargs = {k: v for (k, v) in kwargs.items() if v is not None}
|
2017-03-01 23:12:13 +03:00
|
|
|
|
2016-03-03 07:33:59 +03:00
|
|
|
if dsn is not None:
|
|
|
|
tmp = parse_dsn(dsn)
|
|
|
|
tmp.update(kwargs)
|
|
|
|
kwargs = tmp
|
|
|
|
|
2020-11-17 22:37:42 +03:00
|
|
|
dsn = " ".join(["{}={}".format(k, _param_escape(str(v)))
|
2017-12-11 05:35:41 +03:00
|
|
|
for (k, v) in kwargs.items()])
|
2016-03-03 19:52:53 +03:00
|
|
|
|
|
|
|
# verify that the returned dsn is valid
|
|
|
|
parse_dsn(dsn)
|
|
|
|
|
2016-03-03 07:33:59 +03:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2012-09-19 07:26:35 +04:00
|
|
|
# Create default json typecasters for PostgreSQL 9.2 oids
|
2016-10-11 02:10:53 +03:00
|
|
|
from psycopg2._json import register_default_json, register_default_jsonb # noqa
|
2012-09-19 07:26:35 +04:00
|
|
|
|
|
|
|
try:
|
2012-09-19 18:49:00 +04:00
|
|
|
JSON, JSONARRAY = register_default_json()
|
2014-08-13 03:54:49 +04:00
|
|
|
JSONB, JSONBARRAY = register_default_jsonb()
|
2012-09-19 07:26:35 +04:00
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
|
2014-08-13 03:54:49 +04:00
|
|
|
del register_default_json, register_default_jsonb
|
2012-09-19 07:26:35 +04:00
|
|
|
|
|
|
|
|
2013-04-07 05:37:55 +04:00
|
|
|
# Create default Range typecasters
|
2016-10-11 02:10:53 +03:00
|
|
|
from psycopg2. _range import Range # noqa
|
2013-04-07 05:37:55 +04:00
|
|
|
del Range
|
|
|
|
|
2014-08-13 03:54:49 +04:00
|
|
|
|
2010-12-14 05:21:49 +03:00
|
|
|
# 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
|
2017-12-11 05:35:41 +03:00
|
|
|
for k, v in list(encodings.items()):
|
2010-12-14 05:21:49 +03:00
|
|
|
k = k.replace('_', '').replace('-', '').upper()
|
|
|
|
encodings[k] = v
|
|
|
|
|
2011-09-22 17:34:14 +04:00
|
|
|
del k, v
|