psycopg2.py 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. # dialects/postgresql/psycopg2.py
  2. # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
  3. # <see AUTHORS file>
  4. #
  5. # This module is part of SQLAlchemy and is released under
  6. # the MIT License: https://www.opensource.org/licenses/mit-license.php
  7. r"""
  8. .. dialect:: postgresql+psycopg2
  9. :name: psycopg2
  10. :dbapi: psycopg2
  11. :connectstring: postgresql+psycopg2://user:password@host:port/dbname[?key=value&key=value...]
  12. :url: https://pypi.org/project/psycopg2/
  13. psycopg2 Connect Arguments
  14. --------------------------
  15. Keyword arguments that are specific to the SQLAlchemy psycopg2 dialect
  16. may be passed to :func:`_sa.create_engine()`, and include the following:
  17. * ``isolation_level``: This option, available for all PostgreSQL dialects,
  18. includes the ``AUTOCOMMIT`` isolation level when using the psycopg2
  19. dialect. This option sets the **default** isolation level for the
  20. connection that is set immediately upon connection to the database before
  21. the connection is pooled. This option is generally superseded by the more
  22. modern :paramref:`_engine.Connection.execution_options.isolation_level`
  23. execution option, detailed at :ref:`dbapi_autocommit`.
  24. .. seealso::
  25. :ref:`psycopg2_isolation_level`
  26. :ref:`dbapi_autocommit`
  27. * ``client_encoding``: sets the client encoding in a libpq-agnostic way,
  28. using psycopg2's ``set_client_encoding()`` method.
  29. .. seealso::
  30. :ref:`psycopg2_unicode`
  31. * ``use_native_unicode``: Under Python 2 only, this can be set to False to
  32. disable the use of psycopg2's native Unicode support.
  33. .. seealso::
  34. :ref:`psycopg2_disable_native_unicode`
  35. * ``executemany_mode``, ``executemany_batch_page_size``,
  36. ``executemany_values_page_size``: Allows use of psycopg2
  37. extensions for optimizing "executemany"-style queries. See the referenced
  38. section below for details.
  39. .. seealso::
  40. :ref:`psycopg2_executemany_mode`
  41. .. tip::
  42. The above keyword arguments are **dialect** keyword arguments, meaning
  43. that they are passed as explicit keyword arguments to :func:`_sa.create_engine()`::
  44. engine = create_engine(
  45. "postgresql+psycopg2://scott:tiger@localhost/test",
  46. isolation_level="SERIALIZABLE",
  47. )
  48. These should not be confused with **DBAPI** connect arguments, which
  49. are passed as part of the :paramref:`_sa.create_engine.connect_args`
  50. dictionary and/or are passed in the URL query string, as detailed in
  51. the section :ref:`custom_dbapi_args`.
  52. .. _psycopg2_ssl:
  53. SSL Connections
  54. ---------------
  55. The psycopg2 module has a connection argument named ``sslmode`` for
  56. controlling its behavior regarding secure (SSL) connections. The default is
  57. ``sslmode=prefer``; it will attempt an SSL connection and if that fails it
  58. will fall back to an unencrypted connection. ``sslmode=require`` may be used
  59. to ensure that only secure connections are established. Consult the
  60. psycopg2 / libpq documentation for further options that are available.
  61. Note that ``sslmode`` is specific to psycopg2 so it is included in the
  62. connection URI::
  63. engine = sa.create_engine(
  64. "postgresql+psycopg2://scott:tiger@192.168.0.199:5432/test?sslmode=require"
  65. )
  66. Unix Domain Connections
  67. ------------------------
  68. psycopg2 supports connecting via Unix domain connections. When the ``host``
  69. portion of the URL is omitted, SQLAlchemy passes ``None`` to psycopg2,
  70. which specifies Unix-domain communication rather than TCP/IP communication::
  71. create_engine("postgresql+psycopg2://user:password@/dbname")
  72. By default, the socket file used is to connect to a Unix-domain socket
  73. in ``/tmp``, or whatever socket directory was specified when PostgreSQL
  74. was built. This value can be overridden by passing a pathname to psycopg2,
  75. using ``host`` as an additional keyword argument::
  76. create_engine("postgresql+psycopg2://user:password@/dbname?host=/var/lib/postgresql")
  77. .. seealso::
  78. `PQconnectdbParams \
  79. <https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS>`_
  80. .. _psycopg2_multi_host:
  81. Specifying multiple fallback hosts
  82. -----------------------------------
  83. psycopg2 supports multiple connection points in the connection string.
  84. When the ``host`` parameter is used multiple times in the query section of
  85. the URL, SQLAlchemy will create a single string of the host and port
  86. information provided to make the connections. Tokens may consist of
  87. ``host::port`` or just ``host``; in the latter case, the default port
  88. is selected by libpq. In the example below, three host connections
  89. are specified, for ``HostA::PortA``, ``HostB`` connecting to the default port,
  90. and ``HostC::PortC``::
  91. create_engine(
  92. "postgresql+psycopg2://user:password@/dbname?host=HostA:PortA&host=HostB&host=HostC:PortC"
  93. )
  94. As an alternative, libpq query string format also may be used; this specifies
  95. ``host`` and ``port`` as single query string arguments with comma-separated
  96. lists - the default port can be chosen by indicating an empty value
  97. in the comma separated list::
  98. create_engine(
  99. "postgresql+psycopg2://user:password@/dbname?host=HostA,HostB,HostC&port=PortA,,PortC"
  100. )
  101. With either URL style, connections to each host is attempted based on a
  102. configurable strategy, which may be configured using the libpq
  103. ``target_session_attrs`` parameter. Per libpq this defaults to ``any``
  104. which indicates a connection to each host is then attempted until a connection is successful.
  105. Other strategies include ``primary``, ``prefer-standby``, etc. The complete
  106. list is documented by PostgreSQL at
  107. `libpq connection strings <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING>`_.
  108. For example, to indicate two hosts using the ``primary`` strategy::
  109. create_engine(
  110. "postgresql+psycopg2://user:password@/dbname?host=HostA:PortA&host=HostB&host=HostC:PortC&target_session_attrs=primary"
  111. )
  112. .. versionchanged:: 1.4.40 Port specification in psycopg2 multiple host format
  113. is repaired, previously ports were not correctly interpreted in this context.
  114. libpq comma-separated format is also now supported.
  115. .. versionadded:: 1.3.20 Support for multiple hosts in PostgreSQL connection
  116. string.
  117. .. seealso::
  118. `libpq connection strings <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING>`_ - please refer
  119. to this section in the libpq documentation for complete background on multiple host support.
  120. Empty DSN Connections / Environment Variable Connections
  121. ---------------------------------------------------------
  122. The psycopg2 DBAPI can connect to PostgreSQL by passing an empty DSN to the
  123. libpq client library, which by default indicates to connect to a localhost
  124. PostgreSQL database that is open for "trust" connections. This behavior can be
  125. further tailored using a particular set of environment variables which are
  126. prefixed with ``PG_...``, which are consumed by ``libpq`` to take the place of
  127. any or all elements of the connection string.
  128. For this form, the URL can be passed without any elements other than the
  129. initial scheme::
  130. engine = create_engine('postgresql+psycopg2://')
  131. In the above form, a blank "dsn" string is passed to the ``psycopg2.connect()``
  132. function which in turn represents an empty DSN passed to libpq.
  133. .. versionadded:: 1.3.2 support for parameter-less connections with psycopg2.
  134. .. seealso::
  135. `Environment Variables\
  136. <https://www.postgresql.org/docs/current/libpq-envars.html>`_ -
  137. PostgreSQL documentation on how to use ``PG_...``
  138. environment variables for connections.
  139. .. _psycopg2_execution_options:
  140. Per-Statement/Connection Execution Options
  141. -------------------------------------------
  142. The following DBAPI-specific options are respected when used with
  143. :meth:`_engine.Connection.execution_options`,
  144. :meth:`.Executable.execution_options`,
  145. :meth:`_query.Query.execution_options`,
  146. in addition to those not specific to DBAPIs:
  147. * ``isolation_level`` - Set the transaction isolation level for the lifespan
  148. of a :class:`_engine.Connection` (can only be set on a connection,
  149. not a statement
  150. or query). See :ref:`psycopg2_isolation_level`.
  151. * ``stream_results`` - Enable or disable usage of psycopg2 server side
  152. cursors - this feature makes use of "named" cursors in combination with
  153. special result handling methods so that result rows are not fully buffered.
  154. Defaults to False, meaning cursors are buffered by default.
  155. * ``max_row_buffer`` - when using ``stream_results``, an integer value that
  156. specifies the maximum number of rows to buffer at a time. This is
  157. interpreted by the :class:`.BufferedRowCursorResult`, and if omitted the
  158. buffer will grow to ultimately store 1000 rows at a time.
  159. .. versionchanged:: 1.4 The ``max_row_buffer`` size can now be greater than
  160. 1000, and the buffer will grow to that size.
  161. .. _psycopg2_batch_mode:
  162. .. _psycopg2_executemany_mode:
  163. Psycopg2 Fast Execution Helpers
  164. -------------------------------
  165. Modern versions of psycopg2 include a feature known as
  166. `Fast Execution Helpers \
  167. <https://www.psycopg.org/docs/extras.html#fast-execution-helpers>`_, which
  168. have been shown in benchmarking to improve psycopg2's executemany()
  169. performance, primarily with INSERT statements, by multiple orders of magnitude.
  170. SQLAlchemy internally makes use of these extensions for ``executemany()`` style
  171. calls, which correspond to lists of parameters being passed to
  172. :meth:`_engine.Connection.execute` as detailed in :ref:`multiple parameter
  173. sets <tutorial_multiple_parameters>`. The ORM also uses this mode internally whenever
  174. possible.
  175. The two available extensions on the psycopg2 side are the ``execute_values()``
  176. and ``execute_batch()`` functions. The psycopg2 dialect defaults to using the
  177. ``execute_values()`` extension for all qualifying INSERT statements.
  178. .. versionchanged:: 1.4 The psycopg2 dialect now defaults to a new mode
  179. ``"values_only"`` for ``executemany_mode``, which allows an order of
  180. magnitude performance improvement for INSERT statements, but does not
  181. include "batch" mode for UPDATE and DELETE statements which removes the
  182. ability of ``cursor.rowcount`` to function correctly.
  183. The use of these extensions is controlled by the ``executemany_mode`` flag
  184. which may be passed to :func:`_sa.create_engine`::
  185. engine = create_engine(
  186. "postgresql+psycopg2://scott:tiger@host/dbname",
  187. executemany_mode='values_plus_batch')
  188. Possible options for ``executemany_mode`` include:
  189. * ``values_only`` - this is the default value. the psycopg2 execute_values()
  190. extension is used for qualifying INSERT statements, which rewrites the INSERT
  191. to include multiple VALUES clauses so that many parameter sets can be
  192. inserted with one statement.
  193. .. versionadded:: 1.4 Added ``"values_only"`` setting for ``executemany_mode``
  194. which is also now the default.
  195. * ``None`` - No psycopg2 extensions are not used, and the usual
  196. ``cursor.executemany()`` method is used when invoking statements with
  197. multiple parameter sets.
  198. * ``'batch'`` - Uses ``psycopg2.extras.execute_batch`` for all qualifying
  199. INSERT, UPDATE and DELETE statements, so that multiple copies
  200. of a SQL query, each one corresponding to a parameter set passed to
  201. ``executemany()``, are joined into a single SQL string separated by a
  202. semicolon. When using this mode, the :attr:`_engine.CursorResult.rowcount`
  203. attribute will not contain a value for executemany-style executions.
  204. * ``'values_plus_batch'``- ``execute_values`` is used for qualifying INSERT
  205. statements, ``execute_batch`` is used for UPDATE and DELETE.
  206. When using this mode, the :attr:`_engine.CursorResult.rowcount`
  207. attribute will not contain a value for executemany-style executions against
  208. UPDATE and DELETE statements.
  209. By "qualifying statements", we mean that the statement being executed
  210. must be a Core :func:`_expression.insert`, :func:`_expression.update`
  211. or :func:`_expression.delete` construct, and not a plain textual SQL
  212. string or one constructed using :func:`_expression.text`. When using the
  213. ORM, all insert/update/delete statements used by the ORM flush process
  214. are qualifying.
  215. The "page size" for the "values" and "batch" strategies can be affected
  216. by using the ``executemany_batch_page_size`` and
  217. ``executemany_values_page_size`` engine parameters. These
  218. control how many parameter sets
  219. should be represented in each execution. The "values" page size defaults
  220. to 1000, which is different that psycopg2's default. The "batch" page
  221. size defaults to 100. These can be affected by passing new values to
  222. :func:`_engine.create_engine`::
  223. engine = create_engine(
  224. "postgresql+psycopg2://scott:tiger@host/dbname",
  225. executemany_mode='values',
  226. executemany_values_page_size=10000, executemany_batch_page_size=500)
  227. .. versionchanged:: 1.4
  228. The default for ``executemany_values_page_size`` is now 1000, up from
  229. 100.
  230. .. seealso::
  231. :ref:`tutorial_multiple_parameters` - General information on using the
  232. :class:`_engine.Connection`
  233. object to execute statements in such a way as to make
  234. use of the DBAPI ``.executemany()`` method.
  235. .. _psycopg2_unicode:
  236. Unicode with Psycopg2
  237. ----------------------
  238. The psycopg2 DBAPI driver supports Unicode data transparently. Under Python 2
  239. only, the SQLAlchemy psycopg2 dialect will enable the
  240. ``psycopg2.extensions.UNICODE`` extension by default to ensure Unicode is
  241. handled properly; under Python 3, this is psycopg2's default behavior.
  242. The client character encoding can be controlled for the psycopg2 dialect
  243. in the following ways:
  244. * For PostgreSQL 9.1 and above, the ``client_encoding`` parameter may be
  245. passed in the database URL; this parameter is consumed by the underlying
  246. ``libpq`` PostgreSQL client library::
  247. engine = create_engine("postgresql+psycopg2://user:pass@host/dbname?client_encoding=utf8")
  248. Alternatively, the above ``client_encoding`` value may be passed using
  249. :paramref:`_sa.create_engine.connect_args` for programmatic establishment with
  250. ``libpq``::
  251. engine = create_engine(
  252. "postgresql+psycopg2://user:pass@host/dbname",
  253. connect_args={'client_encoding': 'utf8'}
  254. )
  255. * For all PostgreSQL versions, psycopg2 supports a client-side encoding
  256. value that will be passed to database connections when they are first
  257. established. The SQLAlchemy psycopg2 dialect supports this using the
  258. ``client_encoding`` parameter passed to :func:`_sa.create_engine`::
  259. engine = create_engine(
  260. "postgresql+psycopg2://user:pass@host/dbname",
  261. client_encoding="utf8"
  262. )
  263. .. tip:: The above ``client_encoding`` parameter admittedly is very similar
  264. in appearance to usage of the parameter within the
  265. :paramref:`_sa.create_engine.connect_args` dictionary; the difference
  266. above is that the parameter is consumed by psycopg2 and is
  267. passed to the database connection using ``SET client_encoding TO
  268. 'utf8'``; in the previously mentioned style, the parameter is instead
  269. passed through psycopg2 and consumed by the ``libpq`` library.
  270. * A common way to set up client encoding with PostgreSQL databases is to
  271. ensure it is configured within the server-side postgresql.conf file;
  272. this is the recommended way to set encoding for a server that is
  273. consistently of one encoding in all databases::
  274. # postgresql.conf file
  275. # client_encoding = sql_ascii # actually, defaults to database
  276. # encoding
  277. client_encoding = utf8
  278. .. _psycopg2_disable_native_unicode:
  279. Disabling Native Unicode
  280. ^^^^^^^^^^^^^^^^^^^^^^^^
  281. Under Python 2 only, SQLAlchemy can also be instructed to skip the usage of the
  282. psycopg2 ``UNICODE`` extension and to instead utilize its own unicode
  283. encode/decode services, which are normally reserved only for those DBAPIs that
  284. don't fully support unicode directly. Passing ``use_native_unicode=False`` to
  285. :func:`_sa.create_engine` will disable usage of ``psycopg2.extensions.
  286. UNICODE``. SQLAlchemy will instead encode data itself into Python bytestrings
  287. on the way in and coerce from bytes on the way back, using the value of the
  288. :func:`_sa.create_engine` ``encoding`` parameter, which defaults to ``utf-8``.
  289. SQLAlchemy's own unicode encode/decode functionality is steadily becoming
  290. obsolete as most DBAPIs now support unicode fully.
  291. Transactions
  292. ------------
  293. The psycopg2 dialect fully supports SAVEPOINT and two-phase commit operations.
  294. .. _psycopg2_isolation_level:
  295. Psycopg2 Transaction Isolation Level
  296. -------------------------------------
  297. As discussed in :ref:`postgresql_isolation_level`,
  298. all PostgreSQL dialects support setting of transaction isolation level
  299. both via the ``isolation_level`` parameter passed to :func:`_sa.create_engine`
  300. ,
  301. as well as the ``isolation_level`` argument used by
  302. :meth:`_engine.Connection.execution_options`. When using the psycopg2 dialect
  303. , these
  304. options make use of psycopg2's ``set_isolation_level()`` connection method,
  305. rather than emitting a PostgreSQL directive; this is because psycopg2's
  306. API-level setting is always emitted at the start of each transaction in any
  307. case.
  308. The psycopg2 dialect supports these constants for isolation level:
  309. * ``READ COMMITTED``
  310. * ``READ UNCOMMITTED``
  311. * ``REPEATABLE READ``
  312. * ``SERIALIZABLE``
  313. * ``AUTOCOMMIT``
  314. .. seealso::
  315. :ref:`postgresql_isolation_level`
  316. :ref:`pg8000_isolation_level`
  317. NOTICE logging
  318. ---------------
  319. The psycopg2 dialect will log PostgreSQL NOTICE messages
  320. via the ``sqlalchemy.dialects.postgresql`` logger. When this logger
  321. is set to the ``logging.INFO`` level, notice messages will be logged::
  322. import logging
  323. logging.getLogger('sqlalchemy.dialects.postgresql').setLevel(logging.INFO)
  324. Above, it is assumed that logging is configured externally. If this is not
  325. the case, configuration such as ``logging.basicConfig()`` must be utilized::
  326. import logging
  327. logging.basicConfig() # log messages to stdout
  328. logging.getLogger('sqlalchemy.dialects.postgresql').setLevel(logging.INFO)
  329. .. seealso::
  330. `Logging HOWTO <https://docs.python.org/3/howto/logging.html>`_ - on the python.org website
  331. .. _psycopg2_hstore:
  332. HSTORE type
  333. ------------
  334. The ``psycopg2`` DBAPI includes an extension to natively handle marshalling of
  335. the HSTORE type. The SQLAlchemy psycopg2 dialect will enable this extension
  336. by default when psycopg2 version 2.4 or greater is used, and
  337. it is detected that the target database has the HSTORE type set up for use.
  338. In other words, when the dialect makes the first
  339. connection, a sequence like the following is performed:
  340. 1. Request the available HSTORE oids using
  341. ``psycopg2.extras.HstoreAdapter.get_oids()``.
  342. If this function returns a list of HSTORE identifiers, we then determine
  343. that the ``HSTORE`` extension is present.
  344. This function is **skipped** if the version of psycopg2 installed is
  345. less than version 2.4.
  346. 2. If the ``use_native_hstore`` flag is at its default of ``True``, and
  347. we've detected that ``HSTORE`` oids are available, the
  348. ``psycopg2.extensions.register_hstore()`` extension is invoked for all
  349. connections.
  350. The ``register_hstore()`` extension has the effect of **all Python
  351. dictionaries being accepted as parameters regardless of the type of target
  352. column in SQL**. The dictionaries are converted by this extension into a
  353. textual HSTORE expression. If this behavior is not desired, disable the
  354. use of the hstore extension by setting ``use_native_hstore`` to ``False`` as
  355. follows::
  356. engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test",
  357. use_native_hstore=False)
  358. The ``HSTORE`` type is **still supported** when the
  359. ``psycopg2.extensions.register_hstore()`` extension is not used. It merely
  360. means that the coercion between Python dictionaries and the HSTORE
  361. string format, on both the parameter side and the result side, will take
  362. place within SQLAlchemy's own marshalling logic, and not that of ``psycopg2``
  363. which may be more performant.
  364. """ # noqa
  365. from __future__ import absolute_import
  366. import decimal
  367. import logging
  368. import re
  369. from uuid import UUID as _python_UUID
  370. from .array import ARRAY as PGARRAY
  371. from .base import _ColonCast
  372. from .base import _DECIMAL_TYPES
  373. from .base import _FLOAT_TYPES
  374. from .base import _INT_TYPES
  375. from .base import ENUM
  376. from .base import PGCompiler
  377. from .base import PGDialect
  378. from .base import PGExecutionContext
  379. from .base import PGIdentifierPreparer
  380. from .base import UUID
  381. from .hstore import HSTORE
  382. from .json import JSON
  383. from .json import JSONB
  384. from ... import exc
  385. from ... import processors
  386. from ... import types as sqltypes
  387. from ... import util
  388. from ...engine import cursor as _cursor
  389. from ...util import collections_abc
  390. logger = logging.getLogger("sqlalchemy.dialects.postgresql")
  391. class _PGNumeric(sqltypes.Numeric):
  392. def bind_processor(self, dialect):
  393. return None
  394. def result_processor(self, dialect, coltype):
  395. if self.asdecimal:
  396. if coltype in _FLOAT_TYPES:
  397. return processors.to_decimal_processor_factory(
  398. decimal.Decimal, self._effective_decimal_return_scale
  399. )
  400. elif coltype in _DECIMAL_TYPES or coltype in _INT_TYPES:
  401. # pg8000 returns Decimal natively for 1700
  402. return None
  403. else:
  404. raise exc.InvalidRequestError(
  405. "Unknown PG numeric type: %d" % coltype
  406. )
  407. else:
  408. if coltype in _FLOAT_TYPES:
  409. # pg8000 returns float natively for 701
  410. return None
  411. elif coltype in _DECIMAL_TYPES or coltype in _INT_TYPES:
  412. return processors.to_float
  413. else:
  414. raise exc.InvalidRequestError(
  415. "Unknown PG numeric type: %d" % coltype
  416. )
  417. class _PGEnum(ENUM):
  418. def result_processor(self, dialect, coltype):
  419. if util.py2k and self._expect_unicode is True:
  420. # for py2k, if the enum type needs unicode data (which is set up as
  421. # part of the Enum() constructor based on values passed as py2k
  422. # unicode objects) we have to use our own converters since
  423. # psycopg2's don't work, a rare exception to the "modern DBAPIs
  424. # support unicode everywhere" theme of deprecating
  425. # convert_unicode=True. Use the special "force_nocheck" directive
  426. # which forces unicode conversion to happen on the Python side
  427. # without an isinstance() check. in py3k psycopg2 does the right
  428. # thing automatically.
  429. self._expect_unicode = "force_nocheck"
  430. return super(_PGEnum, self).result_processor(dialect, coltype)
  431. class _PGHStore(HSTORE):
  432. def bind_processor(self, dialect):
  433. if dialect._has_native_hstore:
  434. return None
  435. else:
  436. return super(_PGHStore, self).bind_processor(dialect)
  437. def result_processor(self, dialect, coltype):
  438. if dialect._has_native_hstore:
  439. return None
  440. else:
  441. return super(_PGHStore, self).result_processor(dialect, coltype)
  442. class _PGARRAY(PGARRAY):
  443. def bind_expression(self, bindvalue):
  444. return _ColonCast(bindvalue, self)
  445. class _PGJSON(JSON):
  446. def result_processor(self, dialect, coltype):
  447. return None
  448. class _PGJSONB(JSONB):
  449. def result_processor(self, dialect, coltype):
  450. return None
  451. class _PGUUID(UUID):
  452. def bind_processor(self, dialect):
  453. if not self.as_uuid and dialect.use_native_uuid:
  454. def process(value):
  455. if value is not None:
  456. value = _python_UUID(value)
  457. return value
  458. return process
  459. def result_processor(self, dialect, coltype):
  460. if not self.as_uuid and dialect.use_native_uuid:
  461. def process(value):
  462. if value is not None:
  463. value = str(value)
  464. return value
  465. return process
  466. _server_side_id = util.counter()
  467. class PGExecutionContext_psycopg2(PGExecutionContext):
  468. _psycopg2_fetched_rows = None
  469. def create_server_side_cursor(self):
  470. # use server-side cursors:
  471. # https://lists.initd.org/pipermail/psycopg/2007-January/005251.html
  472. ident = "c_%s_%s" % (hex(id(self))[2:], hex(_server_side_id())[2:])
  473. return self._dbapi_connection.cursor(ident)
  474. def post_exec(self):
  475. if (
  476. self._psycopg2_fetched_rows
  477. and self.compiled
  478. and self.compiled.returning
  479. ):
  480. # psycopg2 execute_values will provide for a real cursor where
  481. # cursor.description works correctly. however, it executes the
  482. # INSERT statement multiple times for multiple pages of rows, so
  483. # while this cursor also supports calling .fetchall() directly, in
  484. # order to get the list of all rows inserted across multiple pages,
  485. # we have to retrieve the aggregated list from the execute_values()
  486. # function directly.
  487. strat_cls = _cursor.FullyBufferedCursorFetchStrategy
  488. self.cursor_fetch_strategy = strat_cls(
  489. self.cursor, initial_buffer=self._psycopg2_fetched_rows
  490. )
  491. self._log_notices(self.cursor)
  492. def _log_notices(self, cursor):
  493. # check also that notices is an iterable, after it's already
  494. # established that we will be iterating through it. This is to get
  495. # around test suites such as SQLAlchemy's using a Mock object for
  496. # cursor
  497. if not cursor.connection.notices or not isinstance(
  498. cursor.connection.notices, collections_abc.Iterable
  499. ):
  500. return
  501. for notice in cursor.connection.notices:
  502. # NOTICE messages have a
  503. # newline character at the end
  504. logger.info(notice.rstrip())
  505. cursor.connection.notices[:] = []
  506. class PGCompiler_psycopg2(PGCompiler):
  507. pass
  508. class PGIdentifierPreparer_psycopg2(PGIdentifierPreparer):
  509. pass
  510. EXECUTEMANY_PLAIN = util.symbol("executemany_plain", canonical=0)
  511. EXECUTEMANY_BATCH = util.symbol("executemany_batch", canonical=1)
  512. EXECUTEMANY_VALUES = util.symbol("executemany_values", canonical=2)
  513. EXECUTEMANY_VALUES_PLUS_BATCH = util.symbol(
  514. "executemany_values_plus_batch",
  515. canonical=EXECUTEMANY_BATCH | EXECUTEMANY_VALUES,
  516. )
  517. class PGDialect_psycopg2(PGDialect):
  518. driver = "psycopg2"
  519. supports_statement_cache = True
  520. if util.py2k:
  521. # turn off supports_unicode_statements for Python 2. psycopg2 supports
  522. # unicode statements in Py2K. But! it does not support unicode *bound
  523. # parameter names* because it uses the Python "%" operator to
  524. # interpolate these into the string, and this fails. So for Py2K, we
  525. # have to use full-on encoding for statements and parameters before
  526. # passing to cursor.execute().
  527. supports_unicode_statements = False
  528. supports_server_side_cursors = True
  529. default_paramstyle = "pyformat"
  530. # set to true based on psycopg2 version
  531. supports_sane_multi_rowcount = False
  532. execution_ctx_cls = PGExecutionContext_psycopg2
  533. statement_compiler = PGCompiler_psycopg2
  534. preparer = PGIdentifierPreparer_psycopg2
  535. psycopg2_version = (0, 0)
  536. _has_native_hstore = True
  537. engine_config_types = PGDialect.engine_config_types.union(
  538. {"use_native_unicode": util.asbool}
  539. )
  540. colspecs = util.update_copy(
  541. PGDialect.colspecs,
  542. {
  543. sqltypes.Numeric: _PGNumeric,
  544. ENUM: _PGEnum, # needs force_unicode
  545. sqltypes.Enum: _PGEnum, # needs force_unicode
  546. HSTORE: _PGHStore,
  547. JSON: _PGJSON,
  548. sqltypes.JSON: _PGJSON,
  549. JSONB: _PGJSONB,
  550. UUID: _PGUUID,
  551. sqltypes.ARRAY: _PGARRAY,
  552. },
  553. )
  554. def __init__(
  555. self,
  556. use_native_unicode=True,
  557. client_encoding=None,
  558. use_native_hstore=True,
  559. use_native_uuid=True,
  560. executemany_mode="values_only",
  561. executemany_batch_page_size=100,
  562. executemany_values_page_size=1000,
  563. **kwargs
  564. ):
  565. PGDialect.__init__(self, **kwargs)
  566. self.use_native_unicode = use_native_unicode
  567. if not use_native_unicode and not util.py2k:
  568. raise exc.ArgumentError(
  569. "psycopg2 native_unicode mode is required under Python 3"
  570. )
  571. if not use_native_hstore:
  572. self._has_native_hstore = False
  573. self.use_native_hstore = use_native_hstore
  574. self.use_native_uuid = use_native_uuid
  575. self.supports_unicode_binds = use_native_unicode
  576. self.client_encoding = client_encoding
  577. # Parse executemany_mode argument, allowing it to be only one of the
  578. # symbol names
  579. self.executemany_mode = util.symbol.parse_user_argument(
  580. executemany_mode,
  581. {
  582. EXECUTEMANY_PLAIN: [None],
  583. EXECUTEMANY_BATCH: ["batch"],
  584. EXECUTEMANY_VALUES: ["values_only"],
  585. EXECUTEMANY_VALUES_PLUS_BATCH: ["values_plus_batch", "values"],
  586. },
  587. "executemany_mode",
  588. )
  589. if self.executemany_mode & EXECUTEMANY_VALUES:
  590. self.insert_executemany_returning = True
  591. self.executemany_batch_page_size = executemany_batch_page_size
  592. self.executemany_values_page_size = executemany_values_page_size
  593. if self.dbapi and hasattr(self.dbapi, "__version__"):
  594. m = re.match(r"(\d+)\.(\d+)(?:\.(\d+))?", self.dbapi.__version__)
  595. if m:
  596. self.psycopg2_version = tuple(
  597. int(x) for x in m.group(1, 2, 3) if x is not None
  598. )
  599. if self.psycopg2_version < (2, 7):
  600. raise ImportError(
  601. "psycopg2 version 2.7 or higher is required."
  602. )
  603. def initialize(self, connection):
  604. super(PGDialect_psycopg2, self).initialize(connection)
  605. self._has_native_hstore = (
  606. self.use_native_hstore
  607. and self._hstore_oids(connection.connection) is not None
  608. )
  609. # PGDialect.initialize() checks server version for <= 8.2 and sets
  610. # this flag to False if so
  611. if not self.full_returning:
  612. self.insert_executemany_returning = False
  613. self.executemany_mode = EXECUTEMANY_PLAIN
  614. self.supports_sane_multi_rowcount = not (
  615. self.executemany_mode & EXECUTEMANY_BATCH
  616. )
  617. @classmethod
  618. def dbapi(cls):
  619. import psycopg2
  620. return psycopg2
  621. @classmethod
  622. def _psycopg2_extensions(cls):
  623. from psycopg2 import extensions
  624. return extensions
  625. @classmethod
  626. def _psycopg2_extras(cls):
  627. from psycopg2 import extras
  628. return extras
  629. @util.memoized_property
  630. def _isolation_lookup(self):
  631. extensions = self._psycopg2_extensions()
  632. return {
  633. "AUTOCOMMIT": extensions.ISOLATION_LEVEL_AUTOCOMMIT,
  634. "READ COMMITTED": extensions.ISOLATION_LEVEL_READ_COMMITTED,
  635. "READ UNCOMMITTED": extensions.ISOLATION_LEVEL_READ_UNCOMMITTED,
  636. "REPEATABLE READ": extensions.ISOLATION_LEVEL_REPEATABLE_READ,
  637. "SERIALIZABLE": extensions.ISOLATION_LEVEL_SERIALIZABLE,
  638. }
  639. def set_isolation_level(self, connection, level):
  640. try:
  641. level = self._isolation_lookup[level.replace("_", " ")]
  642. except KeyError as err:
  643. util.raise_(
  644. exc.ArgumentError(
  645. "Invalid value '%s' for isolation_level. "
  646. "Valid isolation levels for %s are %s"
  647. % (level, self.name, ", ".join(self._isolation_lookup))
  648. ),
  649. replace_context=err,
  650. )
  651. connection.set_isolation_level(level)
  652. def set_readonly(self, connection, value):
  653. connection.readonly = value
  654. def get_readonly(self, connection):
  655. return connection.readonly
  656. def set_deferrable(self, connection, value):
  657. connection.deferrable = value
  658. def get_deferrable(self, connection):
  659. return connection.deferrable
  660. def do_ping(self, dbapi_connection):
  661. cursor = None
  662. before_autocommit = dbapi_connection.autocommit
  663. try:
  664. if not before_autocommit:
  665. dbapi_connection.autocommit = True
  666. cursor = dbapi_connection.cursor()
  667. try:
  668. cursor.execute(self._dialect_specific_select_one)
  669. finally:
  670. cursor.close()
  671. if not before_autocommit and not dbapi_connection.closed:
  672. dbapi_connection.autocommit = before_autocommit
  673. except self.dbapi.Error as err:
  674. if self.is_disconnect(err, dbapi_connection, cursor):
  675. return False
  676. else:
  677. raise
  678. else:
  679. return True
  680. def on_connect(self):
  681. extras = self._psycopg2_extras()
  682. extensions = self._psycopg2_extensions()
  683. fns = []
  684. if self.client_encoding is not None:
  685. def on_connect(conn):
  686. conn.set_client_encoding(self.client_encoding)
  687. fns.append(on_connect)
  688. if self.isolation_level is not None:
  689. def on_connect(conn):
  690. self.set_isolation_level(conn, self.isolation_level)
  691. fns.append(on_connect)
  692. if self.dbapi and self.use_native_uuid:
  693. def on_connect(conn):
  694. extras.register_uuid(None, conn)
  695. fns.append(on_connect)
  696. if util.py2k and self.dbapi and self.use_native_unicode:
  697. def on_connect(conn):
  698. extensions.register_type(extensions.UNICODE, conn)
  699. extensions.register_type(extensions.UNICODEARRAY, conn)
  700. fns.append(on_connect)
  701. if self.dbapi and self.use_native_hstore:
  702. def on_connect(conn):
  703. hstore_oids = self._hstore_oids(conn)
  704. if hstore_oids is not None:
  705. oid, array_oid = hstore_oids
  706. kw = {"oid": oid}
  707. if util.py2k:
  708. kw["unicode"] = True
  709. kw["array_oid"] = array_oid
  710. extras.register_hstore(conn, **kw)
  711. fns.append(on_connect)
  712. if self.dbapi and self._json_deserializer:
  713. def on_connect(conn):
  714. extras.register_default_json(
  715. conn, loads=self._json_deserializer
  716. )
  717. extras.register_default_jsonb(
  718. conn, loads=self._json_deserializer
  719. )
  720. fns.append(on_connect)
  721. if fns:
  722. def on_connect(conn):
  723. for fn in fns:
  724. fn(conn)
  725. return on_connect
  726. else:
  727. return None
  728. def do_executemany(self, cursor, statement, parameters, context=None):
  729. if (
  730. self.executemany_mode & EXECUTEMANY_VALUES
  731. and context
  732. and context.isinsert
  733. and context.compiled._is_safe_for_fast_insert_values_helper
  734. ):
  735. executemany_values = (
  736. "(%s)" % context.compiled.insert_single_values_expr
  737. )
  738. if not self.supports_unicode_statements:
  739. executemany_values = executemany_values.encode(self.encoding)
  740. # guard for statement that was altered via event hook or similar
  741. if executemany_values not in statement:
  742. executemany_values = None
  743. else:
  744. executemany_values = None
  745. if executemany_values:
  746. statement = statement.replace(executemany_values, "%s")
  747. if self.executemany_values_page_size:
  748. kwargs = {"page_size": self.executemany_values_page_size}
  749. else:
  750. kwargs = {}
  751. xtras = self._psycopg2_extras()
  752. context._psycopg2_fetched_rows = xtras.execute_values(
  753. cursor,
  754. statement,
  755. parameters,
  756. template=executemany_values,
  757. fetch=bool(context.compiled.returning),
  758. **kwargs
  759. )
  760. elif self.executemany_mode & EXECUTEMANY_BATCH:
  761. if self.executemany_batch_page_size:
  762. kwargs = {"page_size": self.executemany_batch_page_size}
  763. else:
  764. kwargs = {}
  765. self._psycopg2_extras().execute_batch(
  766. cursor, statement, parameters, **kwargs
  767. )
  768. else:
  769. cursor.executemany(statement, parameters)
  770. @util.memoized_instancemethod
  771. def _hstore_oids(self, conn):
  772. extras = self._psycopg2_extras()
  773. if hasattr(conn, "dbapi_connection"):
  774. conn = conn.dbapi_connection
  775. oids = extras.HstoreAdapter.get_oids(conn)
  776. if oids is not None and oids[0]:
  777. return oids[0:2]
  778. else:
  779. return None
  780. def create_connect_args(self, url):
  781. opts = url.translate_connect_args(username="user")
  782. is_multihost = False
  783. if "host" in url.query:
  784. is_multihost = isinstance(url.query["host"], (list, tuple))
  785. if opts or url.query:
  786. if not opts:
  787. opts = {}
  788. if "port" in opts:
  789. opts["port"] = int(opts["port"])
  790. opts.update(url.query)
  791. if is_multihost:
  792. hosts, ports = zip(
  793. *[
  794. token.split(":") if ":" in token else (token, "")
  795. for token in url.query["host"]
  796. ]
  797. )
  798. opts["host"] = ",".join(hosts)
  799. if "port" in opts:
  800. raise exc.ArgumentError(
  801. "Can't mix 'multihost' formats together; use "
  802. '"host=h1,h2,h3&port=p1,p2,p3" or '
  803. '"host=h1:p1&host=h2:p2&host=h3:p3" separately'
  804. )
  805. opts["port"] = ",".join(ports)
  806. return ([], opts)
  807. else:
  808. # no connection arguments whatsoever; psycopg2.connect()
  809. # requires that "dsn" be present as a blank string.
  810. return ([""], opts)
  811. def is_disconnect(self, e, connection, cursor):
  812. if isinstance(e, self.dbapi.Error):
  813. # check the "closed" flag. this might not be
  814. # present on old psycopg2 versions. Also,
  815. # this flag doesn't actually help in a lot of disconnect
  816. # situations, so don't rely on it.
  817. if getattr(connection, "closed", False):
  818. return True
  819. # checks based on strings. in the case that .closed
  820. # didn't cut it, fall back onto these.
  821. str_e = str(e).partition("\n")[0]
  822. for msg in [
  823. # these error messages from libpq: interfaces/libpq/fe-misc.c
  824. # and interfaces/libpq/fe-secure.c.
  825. "terminating connection",
  826. "closed the connection",
  827. "connection not open",
  828. "could not receive data from server",
  829. "could not send data to server",
  830. # psycopg2 client errors, psycopg2/connection.h,
  831. # psycopg2/cursor.h
  832. "connection already closed",
  833. "cursor already closed",
  834. # not sure where this path is originally from, it may
  835. # be obsolete. It really says "losed", not "closed".
  836. "losed the connection unexpectedly",
  837. # these can occur in newer SSL
  838. "connection has been closed unexpectedly",
  839. "SSL error: decryption failed or bad record mac",
  840. "SSL SYSCALL error: Bad file descriptor",
  841. "SSL SYSCALL error: EOF detected",
  842. "SSL SYSCALL error: Operation timed out",
  843. "SSL SYSCALL error: Bad address",
  844. ]:
  845. idx = str_e.find(msg)
  846. if idx >= 0 and '"' not in str_e[:idx]:
  847. return True
  848. return False
  849. dialect = PGDialect_psycopg2