You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3301 lines
115KB

  1. # engine/base.py
  2. # Copyright (C) 2005-2021 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: http://www.opensource.org/licenses/mit-license.php
  7. from __future__ import with_statement
  8. import contextlib
  9. import sys
  10. from .interfaces import Connectable
  11. from .interfaces import ExceptionContext
  12. from .util import _distill_params
  13. from .util import _distill_params_20
  14. from .util import TransactionalContext
  15. from .. import exc
  16. from .. import inspection
  17. from .. import log
  18. from .. import util
  19. from ..sql import compiler
  20. from ..sql import util as sql_util
  21. """Defines :class:`_engine.Connection` and :class:`_engine.Engine`.
  22. """
  23. _EMPTY_EXECUTION_OPTS = util.immutabledict()
  24. class Connection(Connectable):
  25. """Provides high-level functionality for a wrapped DB-API connection.
  26. **This is the SQLAlchemy 1.x.x version** of the :class:`_engine.Connection`
  27. class. For the :term:`2.0 style` version, which features some API
  28. differences, see :class:`_future.Connection`.
  29. The :class:`_engine.Connection` object is procured by calling
  30. the :meth:`_engine.Engine.connect` method of the :class:`_engine.Engine`
  31. object, and provides services for execution of SQL statements as well
  32. as transaction control.
  33. The Connection object is **not** thread-safe. While a Connection can be
  34. shared among threads using properly synchronized access, it is still
  35. possible that the underlying DBAPI connection may not support shared
  36. access between threads. Check the DBAPI documentation for details.
  37. The Connection object represents a single DBAPI connection checked out
  38. from the connection pool. In this state, the connection pool has no affect
  39. upon the connection, including its expiration or timeout state. For the
  40. connection pool to properly manage connections, connections should be
  41. returned to the connection pool (i.e. ``connection.close()``) whenever the
  42. connection is not in use.
  43. .. index::
  44. single: thread safety; Connection
  45. """
  46. _is_future = False
  47. _sqla_logger_namespace = "sqlalchemy.engine.Connection"
  48. # used by sqlalchemy.engine.util.TransactionalContext
  49. _trans_context_manager = None
  50. def __init__(
  51. self,
  52. engine,
  53. connection=None,
  54. close_with_result=False,
  55. _branch_from=None,
  56. _execution_options=None,
  57. _dispatch=None,
  58. _has_events=None,
  59. _allow_revalidate=True,
  60. ):
  61. """Construct a new Connection."""
  62. self.engine = engine
  63. self.dialect = engine.dialect
  64. self.__branch_from = _branch_from
  65. if _branch_from:
  66. # branching is always "from" the root connection
  67. assert _branch_from.__branch_from is None
  68. self._dbapi_connection = connection
  69. self._execution_options = _execution_options
  70. self._echo = _branch_from._echo
  71. self.should_close_with_result = False
  72. self.dispatch = _dispatch
  73. self._has_events = _branch_from._has_events
  74. else:
  75. self._dbapi_connection = (
  76. connection
  77. if connection is not None
  78. else engine.raw_connection()
  79. )
  80. self._transaction = self._nested_transaction = None
  81. self.__savepoint_seq = 0
  82. self.__in_begin = False
  83. self.should_close_with_result = close_with_result
  84. self.__can_reconnect = _allow_revalidate
  85. self._echo = self.engine._should_log_info()
  86. if _has_events is None:
  87. # if _has_events is sent explicitly as False,
  88. # then don't join the dispatch of the engine; we don't
  89. # want to handle any of the engine's events in that case.
  90. self.dispatch = self.dispatch._join(engine.dispatch)
  91. self._has_events = _has_events or (
  92. _has_events is None and engine._has_events
  93. )
  94. assert not _execution_options
  95. self._execution_options = engine._execution_options
  96. if self._has_events or self.engine._has_events:
  97. self.dispatch.engine_connect(self, _branch_from is not None)
  98. @util.memoized_property
  99. def _message_formatter(self):
  100. if "logging_token" in self._execution_options:
  101. token = self._execution_options["logging_token"]
  102. return lambda msg: "[%s] %s" % (token, msg)
  103. else:
  104. return None
  105. def _log_info(self, message, *arg, **kw):
  106. fmt = self._message_formatter
  107. if fmt:
  108. message = fmt(message)
  109. self.engine.logger.info(message, *arg, **kw)
  110. def _log_debug(self, message, *arg, **kw):
  111. fmt = self._message_formatter
  112. if fmt:
  113. message = fmt(message)
  114. self.engine.logger.debug(message, *arg, **kw)
  115. @property
  116. def _schema_translate_map(self):
  117. return self._execution_options.get("schema_translate_map", None)
  118. def schema_for_object(self, obj):
  119. """Return the schema name for the given schema item taking into
  120. account current schema translate map.
  121. """
  122. name = obj.schema
  123. schema_translate_map = self._execution_options.get(
  124. "schema_translate_map", None
  125. )
  126. if (
  127. schema_translate_map
  128. and name in schema_translate_map
  129. and obj._use_schema_map
  130. ):
  131. return schema_translate_map[name]
  132. else:
  133. return name
  134. def _branch(self):
  135. """Return a new Connection which references this Connection's
  136. engine and connection; but does not have close_with_result enabled,
  137. and also whose close() method does nothing.
  138. .. deprecated:: 1.4 the "branching" concept will be removed in
  139. SQLAlchemy 2.0 as well as the "Connection.connect()" method which
  140. is the only consumer for this.
  141. The Core uses this very sparingly, only in the case of
  142. custom SQL default functions that are to be INSERTed as the
  143. primary key of a row where we need to get the value back, so we have
  144. to invoke it distinctly - this is a very uncommon case.
  145. Userland code accesses _branch() when the connect()
  146. method is called. The branched connection
  147. acts as much as possible like the parent, except that it stays
  148. connected when a close() event occurs.
  149. """
  150. return self.engine._connection_cls(
  151. self.engine,
  152. self._dbapi_connection,
  153. _branch_from=self.__branch_from if self.__branch_from else self,
  154. _execution_options=self._execution_options,
  155. _has_events=self._has_events,
  156. _dispatch=self.dispatch,
  157. )
  158. def _generate_for_options(self):
  159. """define connection method chaining behavior for execution_options"""
  160. if self._is_future:
  161. return self
  162. else:
  163. c = self.__class__.__new__(self.__class__)
  164. c.__dict__ = self.__dict__.copy()
  165. return c
  166. def __enter__(self):
  167. return self
  168. def __exit__(self, type_, value, traceback):
  169. self.close()
  170. def execution_options(self, **opt):
  171. r""" Set non-SQL options for the connection which take effect
  172. during execution.
  173. For a "future" style connection, this method returns this same
  174. :class:`_future.Connection` object with the new options added.
  175. For a legacy connection, this method returns a copy of this
  176. :class:`_engine.Connection` which references the same underlying DBAPI
  177. connection, but also defines the given execution options which will
  178. take effect for a call to
  179. :meth:`execute`. As the new :class:`_engine.Connection` references the
  180. same underlying resource, it's usually a good idea to ensure that
  181. the copies will be discarded immediately, which is implicit if used
  182. as in::
  183. result = connection.execution_options(stream_results=True).\
  184. execute(stmt)
  185. Note that any key/value can be passed to
  186. :meth:`_engine.Connection.execution_options`,
  187. and it will be stored in the
  188. ``_execution_options`` dictionary of the :class:`_engine.Connection`.
  189. It
  190. is suitable for usage by end-user schemes to communicate with
  191. event listeners, for example.
  192. The keywords that are currently recognized by SQLAlchemy itself
  193. include all those listed under :meth:`.Executable.execution_options`,
  194. as well as others that are specific to :class:`_engine.Connection`.
  195. :param autocommit: Available on: Connection, statement.
  196. When True, a COMMIT will be invoked after execution
  197. when executed in 'autocommit' mode, i.e. when an explicit
  198. transaction is not begun on the connection. Note that this
  199. is **library level, not DBAPI level autocommit**. The DBAPI
  200. connection will remain in a real transaction unless the
  201. "AUTOCOMMIT" isolation level is used.
  202. .. deprecated:: 1.4 The "autocommit" execution option is deprecated
  203. and will be removed in SQLAlchemy 2.0. See
  204. :ref:`migration_20_autocommit` for discussion.
  205. :param compiled_cache: Available on: Connection.
  206. A dictionary where :class:`.Compiled` objects
  207. will be cached when the :class:`_engine.Connection`
  208. compiles a clause
  209. expression into a :class:`.Compiled` object. This dictionary will
  210. supersede the statement cache that may be configured on the
  211. :class:`_engine.Engine` itself. If set to None, caching
  212. is disabled, even if the engine has a configured cache size.
  213. Note that the ORM makes use of its own "compiled" caches for
  214. some operations, including flush operations. The caching
  215. used by the ORM internally supersedes a cache dictionary
  216. specified here.
  217. :param logging_token: Available on: :class:`_engine.Connection`,
  218. :class:`_engine.Engine`.
  219. Adds the specified string token surrounded by brackets in log
  220. messages logged by the connection, i.e. the logging that's enabled
  221. either via the :paramref:`_sa.create_engine.echo` flag or via the
  222. ``logging.getLogger("sqlalchemy.engine")`` logger. This allows a
  223. per-connection or per-sub-engine token to be available which is
  224. useful for debugging concurrent connection scenarios.
  225. .. versionadded:: 1.4.0b2
  226. .. seealso::
  227. :ref:`dbengine_logging_tokens` - usage example
  228. :paramref:`_sa.create_engine.logging_name` - adds a name to the
  229. name used by the Python logger object itself.
  230. :param isolation_level: Available on: :class:`_engine.Connection`.
  231. Set the transaction isolation level for the lifespan of this
  232. :class:`_engine.Connection` object.
  233. Valid values include those string
  234. values accepted by the :paramref:`_sa.create_engine.isolation_level`
  235. parameter passed to :func:`_sa.create_engine`. These levels are
  236. semi-database specific; see individual dialect documentation for
  237. valid levels.
  238. The isolation level option applies the isolation level by emitting
  239. statements on the DBAPI connection, and **necessarily affects the
  240. original Connection object overall**, not just the copy that is
  241. returned by the call to :meth:`_engine.Connection.execution_options`
  242. method. The isolation level will remain at the given setting until
  243. the DBAPI connection itself is returned to the connection pool, i.e.
  244. the :meth:`_engine.Connection.close` method on the original
  245. :class:`_engine.Connection` is called,
  246. where an event handler will emit
  247. additional statements on the DBAPI connection in order to revert the
  248. isolation level change.
  249. .. warning:: The ``isolation_level`` execution option should
  250. **not** be used when a transaction is already established, that
  251. is, the :meth:`_engine.Connection.begin`
  252. method or similar has been
  253. called. A database cannot change the isolation level on a
  254. transaction in progress, and different DBAPIs and/or
  255. SQLAlchemy dialects may implicitly roll back or commit
  256. the transaction, or not affect the connection at all.
  257. .. note:: The ``isolation_level`` execution option is implicitly
  258. reset if the :class:`_engine.Connection` is invalidated, e.g. via
  259. the :meth:`_engine.Connection.invalidate` method, or if a
  260. disconnection error occurs. The new connection produced after
  261. the invalidation will not have the isolation level re-applied
  262. to it automatically.
  263. .. seealso::
  264. :paramref:`_sa.create_engine.isolation_level`
  265. - set per :class:`_engine.Engine` isolation level
  266. :meth:`_engine.Connection.get_isolation_level`
  267. - view current level
  268. :ref:`SQLite Transaction Isolation <sqlite_isolation_level>`
  269. :ref:`PostgreSQL Transaction Isolation <postgresql_isolation_level>`
  270. :ref:`MySQL Transaction Isolation <mysql_isolation_level>`
  271. :ref:`SQL Server Transaction Isolation <mssql_isolation_level>`
  272. :ref:`session_transaction_isolation` - for the ORM
  273. :param no_parameters: When ``True``, if the final parameter
  274. list or dictionary is totally empty, will invoke the
  275. statement on the cursor as ``cursor.execute(statement)``,
  276. not passing the parameter collection at all.
  277. Some DBAPIs such as psycopg2 and mysql-python consider
  278. percent signs as significant only when parameters are
  279. present; this option allows code to generate SQL
  280. containing percent signs (and possibly other characters)
  281. that is neutral regarding whether it's executed by the DBAPI
  282. or piped into a script that's later invoked by
  283. command line tools.
  284. :param stream_results: Available on: Connection, statement.
  285. Indicate to the dialect that results should be
  286. "streamed" and not pre-buffered, if possible. This is a limitation
  287. of many DBAPIs. The flag is currently understood within a subset
  288. of dialects within the PostgreSQL and MySQL categories, and
  289. may be supported by other third party dialects as well.
  290. .. seealso::
  291. :ref:`engine_stream_results`
  292. :param schema_translate_map: Available on: Connection, Engine.
  293. A dictionary mapping schema names to schema names, that will be
  294. applied to the :paramref:`_schema.Table.schema` element of each
  295. :class:`_schema.Table`
  296. encountered when SQL or DDL expression elements
  297. are compiled into strings; the resulting schema name will be
  298. converted based on presence in the map of the original name.
  299. .. versionadded:: 1.1
  300. .. seealso::
  301. :ref:`schema_translating`
  302. .. seealso::
  303. :meth:`_engine.Engine.execution_options`
  304. :meth:`.Executable.execution_options`
  305. :meth:`_engine.Connection.get_execution_options`
  306. """ # noqa
  307. c = self._generate_for_options()
  308. c._execution_options = c._execution_options.union(opt)
  309. if self._has_events or self.engine._has_events:
  310. self.dispatch.set_connection_execution_options(c, opt)
  311. self.dialect.set_connection_execution_options(c, opt)
  312. return c
  313. def get_execution_options(self):
  314. """Get the non-SQL options which will take effect during execution.
  315. .. versionadded:: 1.3
  316. .. seealso::
  317. :meth:`_engine.Connection.execution_options`
  318. """
  319. return self._execution_options
  320. @property
  321. def closed(self):
  322. """Return True if this connection is closed."""
  323. # note this is independent for a "branched" connection vs.
  324. # the base
  325. return self._dbapi_connection is None and not self.__can_reconnect
  326. @property
  327. def invalidated(self):
  328. """Return True if this connection was invalidated."""
  329. # prior to 1.4, "invalid" was stored as a state independent of
  330. # "closed", meaning an invalidated connection could be "closed",
  331. # the _dbapi_connection would be None and closed=True, yet the
  332. # "invalid" flag would stay True. This meant that there were
  333. # three separate states (open/valid, closed/valid, closed/invalid)
  334. # when there is really no reason for that; a connection that's
  335. # "closed" does not need to be "invalid". So the state is now
  336. # represented by the two facts alone.
  337. if self.__branch_from:
  338. return self.__branch_from.invalidated
  339. return self._dbapi_connection is None and not self.closed
  340. @property
  341. def connection(self):
  342. """The underlying DB-API connection managed by this Connection.
  343. .. seealso::
  344. :ref:`dbapi_connections`
  345. """
  346. if self._dbapi_connection is None:
  347. try:
  348. return self._revalidate_connection()
  349. except (exc.PendingRollbackError, exc.ResourceClosedError):
  350. raise
  351. except BaseException as e:
  352. self._handle_dbapi_exception(e, None, None, None, None)
  353. else:
  354. return self._dbapi_connection
  355. def get_isolation_level(self):
  356. """Return the current isolation level assigned to this
  357. :class:`_engine.Connection`.
  358. This will typically be the default isolation level as determined
  359. by the dialect, unless if the
  360. :paramref:`.Connection.execution_options.isolation_level`
  361. feature has been used to alter the isolation level on a
  362. per-:class:`_engine.Connection` basis.
  363. This attribute will typically perform a live SQL operation in order
  364. to procure the current isolation level, so the value returned is the
  365. actual level on the underlying DBAPI connection regardless of how
  366. this state was set. Compare to the
  367. :attr:`_engine.Connection.default_isolation_level` accessor
  368. which returns the dialect-level setting without performing a SQL
  369. query.
  370. .. versionadded:: 0.9.9
  371. .. seealso::
  372. :attr:`_engine.Connection.default_isolation_level`
  373. - view default level
  374. :paramref:`_sa.create_engine.isolation_level`
  375. - set per :class:`_engine.Engine` isolation level
  376. :paramref:`.Connection.execution_options.isolation_level`
  377. - set per :class:`_engine.Connection` isolation level
  378. """
  379. try:
  380. return self.dialect.get_isolation_level(self.connection)
  381. except BaseException as e:
  382. self._handle_dbapi_exception(e, None, None, None, None)
  383. @property
  384. def default_isolation_level(self):
  385. """The default isolation level assigned to this
  386. :class:`_engine.Connection`.
  387. This is the isolation level setting that the
  388. :class:`_engine.Connection`
  389. has when first procured via the :meth:`_engine.Engine.connect` method.
  390. This level stays in place until the
  391. :paramref:`.Connection.execution_options.isolation_level` is used
  392. to change the setting on a per-:class:`_engine.Connection` basis.
  393. Unlike :meth:`_engine.Connection.get_isolation_level`,
  394. this attribute is set
  395. ahead of time from the first connection procured by the dialect,
  396. so SQL query is not invoked when this accessor is called.
  397. .. versionadded:: 0.9.9
  398. .. seealso::
  399. :meth:`_engine.Connection.get_isolation_level`
  400. - view current level
  401. :paramref:`_sa.create_engine.isolation_level`
  402. - set per :class:`_engine.Engine` isolation level
  403. :paramref:`.Connection.execution_options.isolation_level`
  404. - set per :class:`_engine.Connection` isolation level
  405. """
  406. return self.dialect.default_isolation_level
  407. def _invalid_transaction(self):
  408. if self.invalidated:
  409. raise exc.PendingRollbackError(
  410. "Can't reconnect until invalid %stransaction is rolled "
  411. "back."
  412. % (
  413. "savepoint "
  414. if self._nested_transaction is not None
  415. else ""
  416. ),
  417. code="8s2b",
  418. )
  419. else:
  420. assert not self._is_future
  421. raise exc.PendingRollbackError(
  422. "This connection is on an inactive %stransaction. "
  423. "Please rollback() fully before proceeding."
  424. % (
  425. "savepoint "
  426. if self._nested_transaction is not None
  427. else ""
  428. ),
  429. code="8s2a",
  430. )
  431. def _revalidate_connection(self):
  432. if self.__branch_from:
  433. return self.__branch_from._revalidate_connection()
  434. if self.__can_reconnect and self.invalidated:
  435. if self._transaction is not None:
  436. self._invalid_transaction()
  437. self._dbapi_connection = self.engine.raw_connection(
  438. _connection=self
  439. )
  440. return self._dbapi_connection
  441. raise exc.ResourceClosedError("This Connection is closed")
  442. @property
  443. def _still_open_and_dbapi_connection_is_valid(self):
  444. return self._dbapi_connection is not None and getattr(
  445. self._dbapi_connection, "is_valid", False
  446. )
  447. @property
  448. def info(self):
  449. """Info dictionary associated with the underlying DBAPI connection
  450. referred to by this :class:`_engine.Connection`, allowing user-defined
  451. data to be associated with the connection.
  452. The data here will follow along with the DBAPI connection including
  453. after it is returned to the connection pool and used again
  454. in subsequent instances of :class:`_engine.Connection`.
  455. """
  456. return self.connection.info
  457. @util.deprecated_20(":meth:`.Connection.connect`")
  458. def connect(self, close_with_result=False):
  459. """Returns a branched version of this :class:`_engine.Connection`.
  460. The :meth:`_engine.Connection.close` method on the returned
  461. :class:`_engine.Connection` can be called and this
  462. :class:`_engine.Connection` will remain open.
  463. This method provides usage symmetry with
  464. :meth:`_engine.Engine.connect`, including for usage
  465. with context managers.
  466. """
  467. return self._branch()
  468. def invalidate(self, exception=None):
  469. """Invalidate the underlying DBAPI connection associated with
  470. this :class:`_engine.Connection`.
  471. An attempt will be made to close the underlying DBAPI connection
  472. immediately; however if this operation fails, the error is logged
  473. but not raised. The connection is then discarded whether or not
  474. close() succeeded.
  475. Upon the next use (where "use" typically means using the
  476. :meth:`_engine.Connection.execute` method or similar),
  477. this :class:`_engine.Connection` will attempt to
  478. procure a new DBAPI connection using the services of the
  479. :class:`_pool.Pool` as a source of connectivity (e.g.
  480. a "reconnection").
  481. If a transaction was in progress (e.g. the
  482. :meth:`_engine.Connection.begin` method has been called) when
  483. :meth:`_engine.Connection.invalidate` method is called, at the DBAPI
  484. level all state associated with this transaction is lost, as
  485. the DBAPI connection is closed. The :class:`_engine.Connection`
  486. will not allow a reconnection to proceed until the
  487. :class:`.Transaction` object is ended, by calling the
  488. :meth:`.Transaction.rollback` method; until that point, any attempt at
  489. continuing to use the :class:`_engine.Connection` will raise an
  490. :class:`~sqlalchemy.exc.InvalidRequestError`.
  491. This is to prevent applications from accidentally
  492. continuing an ongoing transactional operations despite the
  493. fact that the transaction has been lost due to an
  494. invalidation.
  495. The :meth:`_engine.Connection.invalidate` method,
  496. just like auto-invalidation,
  497. will at the connection pool level invoke the
  498. :meth:`_events.PoolEvents.invalidate` event.
  499. :param exception: an optional ``Exception`` instance that's the
  500. reason for the invalidation. is passed along to event handlers
  501. and logging functions.
  502. .. seealso::
  503. :ref:`pool_connection_invalidation`
  504. """
  505. if self.__branch_from:
  506. return self.__branch_from.invalidate(exception=exception)
  507. if self.invalidated:
  508. return
  509. if self.closed:
  510. raise exc.ResourceClosedError("This Connection is closed")
  511. if self._still_open_and_dbapi_connection_is_valid:
  512. self._dbapi_connection.invalidate(exception)
  513. self._dbapi_connection = None
  514. def detach(self):
  515. """Detach the underlying DB-API connection from its connection pool.
  516. E.g.::
  517. with engine.connect() as conn:
  518. conn.detach()
  519. conn.execute(text("SET search_path TO schema1, schema2"))
  520. # work with connection
  521. # connection is fully closed (since we used "with:", can
  522. # also call .close())
  523. This :class:`_engine.Connection` instance will remain usable.
  524. When closed
  525. (or exited from a context manager context as above),
  526. the DB-API connection will be literally closed and not
  527. returned to its originating pool.
  528. This method can be used to insulate the rest of an application
  529. from a modified state on a connection (such as a transaction
  530. isolation level or similar).
  531. """
  532. self._dbapi_connection.detach()
  533. def _autobegin(self):
  534. self.begin()
  535. def begin(self):
  536. """Begin a transaction and return a transaction handle.
  537. The returned object is an instance of :class:`.Transaction`.
  538. This object represents the "scope" of the transaction,
  539. which completes when either the :meth:`.Transaction.rollback`
  540. or :meth:`.Transaction.commit` method is called.
  541. .. tip::
  542. The :meth:`_engine.Connection.begin` method is invoked when using
  543. the :meth:`_engine.Engine.begin` context manager method as well.
  544. All documentation that refers to behaviors specific to the
  545. :meth:`_engine.Connection.begin` method also apply to use of the
  546. :meth:`_engine.Engine.begin` method.
  547. Legacy use: nested calls to :meth:`.begin` on the same
  548. :class:`_engine.Connection` will return new :class:`.Transaction`
  549. objects that represent an emulated transaction within the scope of the
  550. enclosing transaction, that is::
  551. trans = conn.begin() # outermost transaction
  552. trans2 = conn.begin() # "nested"
  553. trans2.commit() # does nothing
  554. trans.commit() # actually commits
  555. Calls to :meth:`.Transaction.commit` only have an effect
  556. when invoked via the outermost :class:`.Transaction` object, though the
  557. :meth:`.Transaction.rollback` method of any of the
  558. :class:`.Transaction` objects will roll back the
  559. transaction.
  560. .. tip::
  561. The above "nesting" behavior is a legacy behavior specific to
  562. :term:`1.x style` use and will be removed in SQLAlchemy 2.0. For
  563. notes on :term:`2.0 style` use, see
  564. :meth:`_future.Connection.begin`.
  565. .. seealso::
  566. :meth:`_engine.Connection.begin_nested` - use a SAVEPOINT
  567. :meth:`_engine.Connection.begin_twophase` -
  568. use a two phase /XID transaction
  569. :meth:`_engine.Engine.begin` - context manager available from
  570. :class:`_engine.Engine`
  571. """
  572. if self._is_future:
  573. assert not self.__branch_from
  574. elif self.__branch_from:
  575. return self.__branch_from.begin()
  576. if self.__in_begin:
  577. # for dialects that emit SQL within the process of
  578. # dialect.do_begin() or dialect.do_begin_twophase(), this
  579. # flag prevents "autobegin" from being emitted within that
  580. # process, while allowing self._transaction to remain at None
  581. # until it's complete.
  582. return
  583. elif self._transaction is None:
  584. self._transaction = RootTransaction(self)
  585. return self._transaction
  586. else:
  587. if self._is_future:
  588. raise exc.InvalidRequestError(
  589. "a transaction is already begun for this connection"
  590. )
  591. else:
  592. return MarkerTransaction(self)
  593. def begin_nested(self):
  594. """Begin a nested transaction (i.e. SAVEPOINT) and return a
  595. transaction handle, assuming an outer transaction is already
  596. established.
  597. Nested transactions require SAVEPOINT support in the
  598. underlying database. Any transaction in the hierarchy may
  599. ``commit`` and ``rollback``, however the outermost transaction
  600. still controls the overall ``commit`` or ``rollback`` of the
  601. transaction of a whole.
  602. The legacy form of :meth:`_engine.Connection.begin_nested` method has
  603. alternate behaviors based on whether or not the
  604. :meth:`_engine.Connection.begin` method was called previously. If
  605. :meth:`_engine.Connection.begin` was not called, then this method will
  606. behave the same as the :meth:`_engine.Connection.begin` method and
  607. return a :class:`.RootTransaction` object that begins and commits a
  608. real transaction - **no savepoint is invoked**. If
  609. :meth:`_engine.Connection.begin` **has** been called, and a
  610. :class:`.RootTransaction` is already established, then this method
  611. returns an instance of :class:`.NestedTransaction` which will invoke
  612. and manage the scope of a SAVEPOINT.
  613. .. tip::
  614. The above mentioned behavior of
  615. :meth:`_engine.Connection.begin_nested` is a legacy behavior
  616. specific to :term:`1.x style` use. In :term:`2.0 style` use, the
  617. :meth:`_future.Connection.begin_nested` method instead autobegins
  618. the outer transaction that can be committed using
  619. "commit-as-you-go" style; see
  620. :meth:`_future.Connection.begin_nested` for migration details.
  621. .. versionchanged:: 1.4.13 The behavior of
  622. :meth:`_engine.Connection.begin_nested`
  623. as returning a :class:`.RootTransaction` if
  624. :meth:`_engine.Connection.begin` were not called has been restored
  625. as was the case in 1.3.x versions; in previous 1.4.x versions, an
  626. outer transaction would be "autobegun" but would not be committed.
  627. .. seealso::
  628. :meth:`_engine.Connection.begin`
  629. :meth:`_engine.Connection.begin_twophase`
  630. """
  631. if self._is_future:
  632. assert not self.__branch_from
  633. elif self.__branch_from:
  634. return self.__branch_from.begin_nested()
  635. if self._transaction is None:
  636. if not self._is_future:
  637. util.warn_deprecated_20(
  638. "Calling Connection.begin_nested() in 2.0 style use will "
  639. "return a NestedTransaction (SAVEPOINT) in all cases, "
  640. "that will not commit the outer transaction. For code "
  641. "that is cross-compatible between 1.x and 2.0 style use, "
  642. "ensure Connection.begin() is called before calling "
  643. "Connection.begin_nested()."
  644. )
  645. return self.begin()
  646. else:
  647. self._autobegin()
  648. return NestedTransaction(self)
  649. def begin_twophase(self, xid=None):
  650. """Begin a two-phase or XA transaction and return a transaction
  651. handle.
  652. The returned object is an instance of :class:`.TwoPhaseTransaction`,
  653. which in addition to the methods provided by
  654. :class:`.Transaction`, also provides a
  655. :meth:`~.TwoPhaseTransaction.prepare` method.
  656. :param xid: the two phase transaction id. If not supplied, a
  657. random id will be generated.
  658. .. seealso::
  659. :meth:`_engine.Connection.begin`
  660. :meth:`_engine.Connection.begin_twophase`
  661. """
  662. if self.__branch_from:
  663. return self.__branch_from.begin_twophase(xid=xid)
  664. if self._transaction is not None:
  665. raise exc.InvalidRequestError(
  666. "Cannot start a two phase transaction when a transaction "
  667. "is already in progress."
  668. )
  669. if xid is None:
  670. xid = self.engine.dialect.create_xid()
  671. return TwoPhaseTransaction(self, xid)
  672. def recover_twophase(self):
  673. return self.engine.dialect.do_recover_twophase(self)
  674. def rollback_prepared(self, xid, recover=False):
  675. self.engine.dialect.do_rollback_twophase(self, xid, recover=recover)
  676. def commit_prepared(self, xid, recover=False):
  677. self.engine.dialect.do_commit_twophase(self, xid, recover=recover)
  678. def in_transaction(self):
  679. """Return True if a transaction is in progress."""
  680. if self.__branch_from is not None:
  681. return self.__branch_from.in_transaction()
  682. return self._transaction is not None and self._transaction.is_active
  683. def in_nested_transaction(self):
  684. """Return True if a transaction is in progress."""
  685. if self.__branch_from is not None:
  686. return self.__branch_from.in_nested_transaction()
  687. return (
  688. self._nested_transaction is not None
  689. and self._nested_transaction.is_active
  690. )
  691. def _is_autocommit(self):
  692. return (
  693. self._execution_options.get("isolation_level", None)
  694. == "AUTOCOMMIT"
  695. )
  696. def get_transaction(self):
  697. """Return the current root transaction in progress, if any.
  698. .. versionadded:: 1.4
  699. """
  700. if self.__branch_from is not None:
  701. return self.__branch_from.get_transaction()
  702. return self._transaction
  703. def get_nested_transaction(self):
  704. """Return the current nested transaction in progress, if any.
  705. .. versionadded:: 1.4
  706. """
  707. if self.__branch_from is not None:
  708. return self.__branch_from.get_nested_transaction()
  709. return self._nested_transaction
  710. def _begin_impl(self, transaction):
  711. assert not self.__branch_from
  712. if self._echo:
  713. self._log_info("BEGIN (implicit)")
  714. self.__in_begin = True
  715. if self._has_events or self.engine._has_events:
  716. self.dispatch.begin(self)
  717. try:
  718. self.engine.dialect.do_begin(self.connection)
  719. except BaseException as e:
  720. self._handle_dbapi_exception(e, None, None, None, None)
  721. finally:
  722. self.__in_begin = False
  723. def _rollback_impl(self):
  724. assert not self.__branch_from
  725. if self._has_events or self.engine._has_events:
  726. self.dispatch.rollback(self)
  727. if self._still_open_and_dbapi_connection_is_valid:
  728. if self._echo:
  729. if self._is_autocommit():
  730. self._log_info(
  731. "ROLLBACK using DBAPI connection.rollback(), "
  732. "DBAPI should ignore due to autocommit mode"
  733. )
  734. else:
  735. self._log_info("ROLLBACK")
  736. try:
  737. self.engine.dialect.do_rollback(self.connection)
  738. except BaseException as e:
  739. self._handle_dbapi_exception(e, None, None, None, None)
  740. def _commit_impl(self, autocommit=False):
  741. assert not self.__branch_from
  742. # AUTOCOMMIT isolation-level is a dialect-specific concept, however
  743. # if a connection has this set as the isolation level, we can skip
  744. # the "autocommit" warning as the operation will do "autocommit"
  745. # in any case
  746. if autocommit and not self._is_autocommit():
  747. util.warn_deprecated_20(
  748. "The current statement is being autocommitted using "
  749. "implicit autocommit, which will be removed in "
  750. "SQLAlchemy 2.0. "
  751. "Use the .begin() method of Engine or Connection in order to "
  752. "use an explicit transaction for DML and DDL statements."
  753. )
  754. if self._has_events or self.engine._has_events:
  755. self.dispatch.commit(self)
  756. if self._echo:
  757. if self._is_autocommit():
  758. self._log_info(
  759. "COMMIT using DBAPI connection.commit(), "
  760. "DBAPI should ignore due to autocommit mode"
  761. )
  762. else:
  763. self._log_info("COMMIT")
  764. try:
  765. self.engine.dialect.do_commit(self.connection)
  766. except BaseException as e:
  767. self._handle_dbapi_exception(e, None, None, None, None)
  768. def _savepoint_impl(self, name=None):
  769. assert not self.__branch_from
  770. if self._has_events or self.engine._has_events:
  771. self.dispatch.savepoint(self, name)
  772. if name is None:
  773. self.__savepoint_seq += 1
  774. name = "sa_savepoint_%s" % self.__savepoint_seq
  775. if self._still_open_and_dbapi_connection_is_valid:
  776. self.engine.dialect.do_savepoint(self, name)
  777. return name
  778. def _rollback_to_savepoint_impl(self, name):
  779. assert not self.__branch_from
  780. if self._has_events or self.engine._has_events:
  781. self.dispatch.rollback_savepoint(self, name, None)
  782. if self._still_open_and_dbapi_connection_is_valid:
  783. self.engine.dialect.do_rollback_to_savepoint(self, name)
  784. def _release_savepoint_impl(self, name):
  785. assert not self.__branch_from
  786. if self._has_events or self.engine._has_events:
  787. self.dispatch.release_savepoint(self, name, None)
  788. if self._still_open_and_dbapi_connection_is_valid:
  789. self.engine.dialect.do_release_savepoint(self, name)
  790. def _begin_twophase_impl(self, transaction):
  791. assert not self.__branch_from
  792. if self._echo:
  793. self._log_info("BEGIN TWOPHASE (implicit)")
  794. if self._has_events or self.engine._has_events:
  795. self.dispatch.begin_twophase(self, transaction.xid)
  796. if self._still_open_and_dbapi_connection_is_valid:
  797. self.__in_begin = True
  798. try:
  799. self.engine.dialect.do_begin_twophase(self, transaction.xid)
  800. except BaseException as e:
  801. self._handle_dbapi_exception(e, None, None, None, None)
  802. finally:
  803. self.__in_begin = False
  804. def _prepare_twophase_impl(self, xid):
  805. assert not self.__branch_from
  806. if self._has_events or self.engine._has_events:
  807. self.dispatch.prepare_twophase(self, xid)
  808. if self._still_open_and_dbapi_connection_is_valid:
  809. assert isinstance(self._transaction, TwoPhaseTransaction)
  810. try:
  811. self.engine.dialect.do_prepare_twophase(self, xid)
  812. except BaseException as e:
  813. self._handle_dbapi_exception(e, None, None, None, None)
  814. def _rollback_twophase_impl(self, xid, is_prepared):
  815. assert not self.__branch_from
  816. if self._has_events or self.engine._has_events:
  817. self.dispatch.rollback_twophase(self, xid, is_prepared)
  818. if self._still_open_and_dbapi_connection_is_valid:
  819. assert isinstance(self._transaction, TwoPhaseTransaction)
  820. try:
  821. self.engine.dialect.do_rollback_twophase(
  822. self, xid, is_prepared
  823. )
  824. except BaseException as e:
  825. self._handle_dbapi_exception(e, None, None, None, None)
  826. def _commit_twophase_impl(self, xid, is_prepared):
  827. assert not self.__branch_from
  828. if self._has_events or self.engine._has_events:
  829. self.dispatch.commit_twophase(self, xid, is_prepared)
  830. if self._still_open_and_dbapi_connection_is_valid:
  831. assert isinstance(self._transaction, TwoPhaseTransaction)
  832. try:
  833. self.engine.dialect.do_commit_twophase(self, xid, is_prepared)
  834. except BaseException as e:
  835. self._handle_dbapi_exception(e, None, None, None, None)
  836. def _autorollback(self):
  837. if self.__branch_from:
  838. self.__branch_from._autorollback()
  839. if not self.in_transaction():
  840. self._rollback_impl()
  841. def _warn_for_legacy_exec_format(self):
  842. util.warn_deprecated_20(
  843. "The connection.execute() method in "
  844. "SQLAlchemy 2.0 will accept parameters as a single "
  845. "dictionary or a "
  846. "single sequence of dictionaries only. "
  847. "Parameters passed as keyword arguments, tuples or positionally "
  848. "oriented dictionaries and/or tuples "
  849. "will no longer be accepted."
  850. )
  851. def close(self):
  852. """Close this :class:`_engine.Connection`.
  853. This results in a release of the underlying database
  854. resources, that is, the DBAPI connection referenced
  855. internally. The DBAPI connection is typically restored
  856. back to the connection-holding :class:`_pool.Pool` referenced
  857. by the :class:`_engine.Engine` that produced this
  858. :class:`_engine.Connection`. Any transactional state present on
  859. the DBAPI connection is also unconditionally released via
  860. the DBAPI connection's ``rollback()`` method, regardless
  861. of any :class:`.Transaction` object that may be
  862. outstanding with regards to this :class:`_engine.Connection`.
  863. After :meth:`_engine.Connection.close` is called, the
  864. :class:`_engine.Connection` is permanently in a closed state,
  865. and will allow no further operations.
  866. """
  867. if self.__branch_from:
  868. assert not self._is_future
  869. util.warn_deprecated_20(
  870. "The .close() method on a so-called 'branched' connection is "
  871. "deprecated as of 1.4, as are 'branched' connections overall, "
  872. "and will be removed in a future release. If this is a "
  873. "default-handling function, don't close the connection."
  874. )
  875. self._dbapi_connection = None
  876. self.__can_reconnect = False
  877. return
  878. if self._transaction:
  879. self._transaction.close()
  880. skip_reset = True
  881. else:
  882. skip_reset = False
  883. if self._dbapi_connection is not None:
  884. conn = self._dbapi_connection
  885. # as we just closed the transaction, close the connection
  886. # pool connection without doing an additional reset
  887. if skip_reset:
  888. conn._close_no_reset()
  889. else:
  890. conn.close()
  891. # There is a slight chance that conn.close() may have
  892. # triggered an invalidation here in which case
  893. # _dbapi_connection would already be None, however usually
  894. # it will be non-None here and in a "closed" state.
  895. self._dbapi_connection = None
  896. self.__can_reconnect = False
  897. def scalar(self, object_, *multiparams, **params):
  898. """Executes and returns the first column of the first row.
  899. The underlying result/cursor is closed after execution.
  900. """
  901. return self.execute(object_, *multiparams, **params).scalar()
  902. def execute(self, statement, *multiparams, **params):
  903. r"""Executes a SQL statement construct and returns a
  904. :class:`_engine.CursorResult`.
  905. :param statement: The statement to be executed. May be
  906. one of:
  907. * a plain string (deprecated)
  908. * any :class:`_expression.ClauseElement` construct that is also
  909. a subclass of :class:`.Executable`, such as a
  910. :func:`_expression.select` construct
  911. * a :class:`.FunctionElement`, such as that generated
  912. by :data:`.func`, will be automatically wrapped in
  913. a SELECT statement, which is then executed.
  914. * a :class:`.DDLElement` object
  915. * a :class:`.DefaultGenerator` object
  916. * a :class:`.Compiled` object
  917. .. deprecated:: 2.0 passing a string to
  918. :meth:`_engine.Connection.execute` is
  919. deprecated and will be removed in version 2.0. Use the
  920. :func:`_expression.text` construct with
  921. :meth:`_engine.Connection.execute`, or the
  922. :meth:`_engine.Connection.exec_driver_sql`
  923. method to invoke a driver-level
  924. SQL string.
  925. :param \*multiparams/\**params: represent bound parameter
  926. values to be used in the execution. Typically,
  927. the format is either a collection of one or more
  928. dictionaries passed to \*multiparams::
  929. conn.execute(
  930. table.insert(),
  931. {"id":1, "value":"v1"},
  932. {"id":2, "value":"v2"}
  933. )
  934. ...or individual key/values interpreted by \**params::
  935. conn.execute(
  936. table.insert(), id=1, value="v1"
  937. )
  938. In the case that a plain SQL string is passed, and the underlying
  939. DBAPI accepts positional bind parameters, a collection of tuples
  940. or individual values in \*multiparams may be passed::
  941. conn.execute(
  942. "INSERT INTO table (id, value) VALUES (?, ?)",
  943. (1, "v1"), (2, "v2")
  944. )
  945. conn.execute(
  946. "INSERT INTO table (id, value) VALUES (?, ?)",
  947. 1, "v1"
  948. )
  949. Note above, the usage of a question mark "?" or other
  950. symbol is contingent upon the "paramstyle" accepted by the DBAPI
  951. in use, which may be any of "qmark", "named", "pyformat", "format",
  952. "numeric". See `pep-249 <http://www.python.org/dev/peps/pep-0249/>`_
  953. for details on paramstyle.
  954. To execute a textual SQL statement which uses bound parameters in a
  955. DBAPI-agnostic way, use the :func:`_expression.text` construct.
  956. .. deprecated:: 2.0 use of tuple or scalar positional parameters
  957. is deprecated. All params should be dicts or sequences of dicts.
  958. Use :meth:`.exec_driver_sql` to execute a plain string with
  959. tuple or scalar positional parameters.
  960. """
  961. if isinstance(statement, util.string_types):
  962. util.warn_deprecated_20(
  963. "Passing a string to Connection.execute() is "
  964. "deprecated and will be removed in version 2.0. Use the "
  965. "text() construct, "
  966. "or the Connection.exec_driver_sql() method to invoke a "
  967. "driver-level SQL string."
  968. )
  969. return self._exec_driver_sql(
  970. statement,
  971. multiparams,
  972. params,
  973. _EMPTY_EXECUTION_OPTS,
  974. future=False,
  975. )
  976. try:
  977. meth = statement._execute_on_connection
  978. except AttributeError as err:
  979. util.raise_(
  980. exc.ObjectNotExecutableError(statement), replace_context=err
  981. )
  982. else:
  983. return meth(self, multiparams, params, _EMPTY_EXECUTION_OPTS)
  984. def _execute_function(self, func, multiparams, params, execution_options):
  985. """Execute a sql.FunctionElement object."""
  986. return self._execute_clauseelement(
  987. func.select(), multiparams, params, execution_options
  988. )
  989. def _execute_default(
  990. self,
  991. default,
  992. multiparams,
  993. params,
  994. # migrate is calling this directly :(
  995. execution_options=_EMPTY_EXECUTION_OPTS,
  996. ):
  997. """Execute a schema.ColumnDefault object."""
  998. execution_options = self._execution_options.merge_with(
  999. execution_options
  1000. )
  1001. distilled_parameters = _distill_params(self, multiparams, params)
  1002. if self._has_events or self.engine._has_events:
  1003. (
  1004. distilled_params,
  1005. event_multiparams,
  1006. event_params,
  1007. ) = self._invoke_before_exec_event(
  1008. default, distilled_parameters, execution_options
  1009. )
  1010. try:
  1011. conn = self._dbapi_connection
  1012. if conn is None:
  1013. conn = self._revalidate_connection()
  1014. dialect = self.dialect
  1015. ctx = dialect.execution_ctx_cls._init_default(
  1016. dialect, self, conn, execution_options
  1017. )
  1018. except (exc.PendingRollbackError, exc.ResourceClosedError):
  1019. raise
  1020. except BaseException as e:
  1021. self._handle_dbapi_exception(e, None, None, None, None)
  1022. ret = ctx._exec_default(None, default, None)
  1023. if self.should_close_with_result:
  1024. self.close()
  1025. if self._has_events or self.engine._has_events:
  1026. self.dispatch.after_execute(
  1027. self,
  1028. default,
  1029. event_multiparams,
  1030. event_params,
  1031. execution_options,
  1032. ret,
  1033. )
  1034. return ret
  1035. def _execute_ddl(self, ddl, multiparams, params, execution_options):
  1036. """Execute a schema.DDL object."""
  1037. execution_options = ddl._execution_options.merge_with(
  1038. self._execution_options, execution_options
  1039. )
  1040. distilled_parameters = _distill_params(self, multiparams, params)
  1041. if self._has_events or self.engine._has_events:
  1042. (
  1043. distilled_params,
  1044. event_multiparams,
  1045. event_params,
  1046. ) = self._invoke_before_exec_event(
  1047. ddl, distilled_parameters, execution_options
  1048. )
  1049. exec_opts = self._execution_options.merge_with(execution_options)
  1050. schema_translate_map = exec_opts.get("schema_translate_map", None)
  1051. dialect = self.dialect
  1052. compiled = ddl.compile(
  1053. dialect=dialect, schema_translate_map=schema_translate_map
  1054. )
  1055. ret = self._execute_context(
  1056. dialect,
  1057. dialect.execution_ctx_cls._init_ddl,
  1058. compiled,
  1059. None,
  1060. execution_options,
  1061. compiled,
  1062. )
  1063. if self._has_events or self.engine._has_events:
  1064. self.dispatch.after_execute(
  1065. self,
  1066. ddl,
  1067. event_multiparams,
  1068. event_params,
  1069. execution_options,
  1070. ret,
  1071. )
  1072. return ret
  1073. def _invoke_before_exec_event(
  1074. self, elem, distilled_params, execution_options
  1075. ):
  1076. if len(distilled_params) == 1:
  1077. event_multiparams, event_params = [], distilled_params[0]
  1078. else:
  1079. event_multiparams, event_params = distilled_params, {}
  1080. for fn in self.dispatch.before_execute:
  1081. elem, event_multiparams, event_params = fn(
  1082. self,
  1083. elem,
  1084. event_multiparams,
  1085. event_params,
  1086. execution_options,
  1087. )
  1088. if event_multiparams:
  1089. distilled_params = list(event_multiparams)
  1090. if event_params:
  1091. raise exc.InvalidRequestError(
  1092. "Event handler can't return non-empty multiparams "
  1093. "and params at the same time"
  1094. )
  1095. elif event_params:
  1096. distilled_params = [event_params]
  1097. else:
  1098. distilled_params = []
  1099. return distilled_params, event_multiparams, event_params
  1100. def _execute_clauseelement(
  1101. self, elem, multiparams, params, execution_options
  1102. ):
  1103. """Execute a sql.ClauseElement object."""
  1104. execution_options = elem._execution_options.merge_with(
  1105. self._execution_options, execution_options
  1106. )
  1107. distilled_params = _distill_params(self, multiparams, params)
  1108. has_events = self._has_events or self.engine._has_events
  1109. if has_events:
  1110. (
  1111. distilled_params,
  1112. event_multiparams,
  1113. event_params,
  1114. ) = self._invoke_before_exec_event(
  1115. elem, distilled_params, execution_options
  1116. )
  1117. if distilled_params:
  1118. # ensure we don't retain a link to the view object for keys()
  1119. # which links to the values, which we don't want to cache
  1120. keys = sorted(distilled_params[0])
  1121. for_executemany = len(distilled_params) > 1
  1122. else:
  1123. keys = []
  1124. for_executemany = False
  1125. dialect = self.dialect
  1126. schema_translate_map = execution_options.get(
  1127. "schema_translate_map", None
  1128. )
  1129. compiled_cache = execution_options.get(
  1130. "compiled_cache", self.engine._compiled_cache
  1131. )
  1132. compiled_sql, extracted_params, cache_hit = elem._compile_w_cache(
  1133. dialect=dialect,
  1134. compiled_cache=compiled_cache,
  1135. column_keys=keys,
  1136. for_executemany=for_executemany,
  1137. schema_translate_map=schema_translate_map,
  1138. linting=self.dialect.compiler_linting | compiler.WARN_LINTING,
  1139. )
  1140. ret = self._execute_context(
  1141. dialect,
  1142. dialect.execution_ctx_cls._init_compiled,
  1143. compiled_sql,
  1144. distilled_params,
  1145. execution_options,
  1146. compiled_sql,
  1147. distilled_params,
  1148. elem,
  1149. extracted_params,
  1150. cache_hit=cache_hit,
  1151. )
  1152. if has_events:
  1153. self.dispatch.after_execute(
  1154. self,
  1155. elem,
  1156. event_multiparams,
  1157. event_params,
  1158. execution_options,
  1159. ret,
  1160. )
  1161. return ret
  1162. def _execute_compiled(
  1163. self,
  1164. compiled,
  1165. multiparams,
  1166. params,
  1167. execution_options=_EMPTY_EXECUTION_OPTS,
  1168. ):
  1169. """Execute a sql.Compiled object.
  1170. TODO: why do we have this? likely deprecate or remove
  1171. """
  1172. execution_options = compiled.execution_options.merge_with(
  1173. self._execution_options, execution_options
  1174. )
  1175. distilled_parameters = _distill_params(self, multiparams, params)
  1176. if self._has_events or self.engine._has_events:
  1177. (
  1178. distilled_params,
  1179. event_multiparams,
  1180. event_params,
  1181. ) = self._invoke_before_exec_event(
  1182. compiled, distilled_parameters, execution_options
  1183. )
  1184. dialect = self.dialect
  1185. ret = self._execute_context(
  1186. dialect,
  1187. dialect.execution_ctx_cls._init_compiled,
  1188. compiled,
  1189. distilled_parameters,
  1190. execution_options,
  1191. compiled,
  1192. distilled_parameters,
  1193. None,
  1194. None,
  1195. )
  1196. if self._has_events or self.engine._has_events:
  1197. self.dispatch.after_execute(
  1198. self,
  1199. compiled,
  1200. event_multiparams,
  1201. event_params,
  1202. execution_options,
  1203. ret,
  1204. )
  1205. return ret
  1206. def _exec_driver_sql(
  1207. self, statement, multiparams, params, execution_options, future
  1208. ):
  1209. execution_options = self._execution_options.merge_with(
  1210. execution_options
  1211. )
  1212. distilled_parameters = _distill_params(self, multiparams, params)
  1213. if not future:
  1214. if self._has_events or self.engine._has_events:
  1215. (
  1216. distilled_params,
  1217. event_multiparams,
  1218. event_params,
  1219. ) = self._invoke_before_exec_event(
  1220. statement, distilled_parameters, execution_options
  1221. )
  1222. dialect = self.dialect
  1223. ret = self._execute_context(
  1224. dialect,
  1225. dialect.execution_ctx_cls._init_statement,
  1226. statement,
  1227. distilled_parameters,
  1228. execution_options,
  1229. statement,
  1230. distilled_parameters,
  1231. )
  1232. if not future:
  1233. if self._has_events or self.engine._has_events:
  1234. self.dispatch.after_execute(
  1235. self,
  1236. statement,
  1237. event_multiparams,
  1238. event_params,
  1239. execution_options,
  1240. ret,
  1241. )
  1242. return ret
  1243. def _execute_20(
  1244. self,
  1245. statement,
  1246. parameters=None,
  1247. execution_options=_EMPTY_EXECUTION_OPTS,
  1248. ):
  1249. args_10style, kwargs_10style = _distill_params_20(parameters)
  1250. try:
  1251. meth = statement._execute_on_connection
  1252. except AttributeError as err:
  1253. util.raise_(
  1254. exc.ObjectNotExecutableError(statement), replace_context=err
  1255. )
  1256. else:
  1257. return meth(self, args_10style, kwargs_10style, execution_options)
  1258. def exec_driver_sql(
  1259. self, statement, parameters=None, execution_options=None
  1260. ):
  1261. r"""Executes a SQL statement construct and returns a
  1262. :class:`_engine.CursorResult`.
  1263. :param statement: The statement str to be executed. Bound parameters
  1264. must use the underlying DBAPI's paramstyle, such as "qmark",
  1265. "pyformat", "format", etc.
  1266. :param parameters: represent bound parameter values to be used in the
  1267. execution. The format is one of: a dictionary of named parameters,
  1268. a tuple of positional parameters, or a list containing either
  1269. dictionaries or tuples for multiple-execute support.
  1270. E.g. multiple dictionaries::
  1271. conn.exec_driver_sql(
  1272. "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)",
  1273. [{"id":1, "value":"v1"}, {"id":2, "value":"v2"}]
  1274. )
  1275. Single dictionary::
  1276. conn.exec_driver_sql(
  1277. "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)",
  1278. dict(id=1, value="v1")
  1279. )
  1280. Single tuple::
  1281. conn.exec_driver_sql(
  1282. "INSERT INTO table (id, value) VALUES (?, ?)",
  1283. (1, 'v1')
  1284. )
  1285. .. note:: The :meth:`_engine.Connection.exec_driver_sql` method does
  1286. not participate in the
  1287. :meth:`_events.ConnectionEvents.before_execute` and
  1288. :meth:`_events.ConnectionEvents.after_execute` events. To
  1289. intercept calls to :meth:`_engine.Connection.exec_driver_sql`, use
  1290. :meth:`_events.ConnectionEvents.before_cursor_execute` and
  1291. :meth:`_events.ConnectionEvents.after_cursor_execute`.
  1292. .. seealso::
  1293. :pep:`249`
  1294. """
  1295. args_10style, kwargs_10style = _distill_params_20(parameters)
  1296. return self._exec_driver_sql(
  1297. statement,
  1298. args_10style,
  1299. kwargs_10style,
  1300. execution_options,
  1301. future=True,
  1302. )
  1303. def _execute_context(
  1304. self,
  1305. dialect,
  1306. constructor,
  1307. statement,
  1308. parameters,
  1309. execution_options,
  1310. *args,
  1311. **kw
  1312. ):
  1313. """Create an :class:`.ExecutionContext` and execute, returning
  1314. a :class:`_engine.CursorResult`."""
  1315. branched = self
  1316. if self.__branch_from:
  1317. # if this is a "branched" connection, do everything in terms
  1318. # of the "root" connection, *except* for .close(), which is
  1319. # the only feature that branching provides
  1320. self = self.__branch_from
  1321. try:
  1322. conn = self._dbapi_connection
  1323. if conn is None:
  1324. conn = self._revalidate_connection()
  1325. context = constructor(
  1326. dialect, self, conn, execution_options, *args, **kw
  1327. )
  1328. except (exc.PendingRollbackError, exc.ResourceClosedError):
  1329. raise
  1330. except BaseException as e:
  1331. self._handle_dbapi_exception(
  1332. e, util.text_type(statement), parameters, None, None
  1333. )
  1334. if (
  1335. self._transaction
  1336. and not self._transaction.is_active
  1337. or (
  1338. self._nested_transaction
  1339. and not self._nested_transaction.is_active
  1340. )
  1341. ):
  1342. self._invalid_transaction()
  1343. elif self._trans_context_manager:
  1344. TransactionalContext._trans_ctx_check(self)
  1345. if self._is_future and self._transaction is None:
  1346. self._autobegin()
  1347. context.pre_exec()
  1348. if dialect.use_setinputsizes:
  1349. context._set_input_sizes()
  1350. cursor, statement, parameters = (
  1351. context.cursor,
  1352. context.statement,
  1353. context.parameters,
  1354. )
  1355. if not context.executemany:
  1356. parameters = parameters[0]
  1357. if self._has_events or self.engine._has_events:
  1358. for fn in self.dispatch.before_cursor_execute:
  1359. statement, parameters = fn(
  1360. self,
  1361. cursor,
  1362. statement,
  1363. parameters,
  1364. context,
  1365. context.executemany,
  1366. )
  1367. if self._echo:
  1368. self._log_info(statement)
  1369. stats = context._get_cache_stats()
  1370. if not self.engine.hide_parameters:
  1371. self._log_info(
  1372. "[%s] %r",
  1373. stats,
  1374. sql_util._repr_params(
  1375. parameters, batches=10, ismulti=context.executemany
  1376. ),
  1377. )
  1378. else:
  1379. self._log_info(
  1380. "[%s] [SQL parameters hidden due to hide_parameters=True]"
  1381. % (stats,)
  1382. )
  1383. evt_handled = False
  1384. try:
  1385. if context.executemany:
  1386. if self.dialect._has_events:
  1387. for fn in self.dialect.dispatch.do_executemany:
  1388. if fn(cursor, statement, parameters, context):
  1389. evt_handled = True
  1390. break
  1391. if not evt_handled:
  1392. self.dialect.do_executemany(
  1393. cursor, statement, parameters, context
  1394. )
  1395. elif not parameters and context.no_parameters:
  1396. if self.dialect._has_events:
  1397. for fn in self.dialect.dispatch.do_execute_no_params:
  1398. if fn(cursor, statement, context):
  1399. evt_handled = True
  1400. break
  1401. if not evt_handled:
  1402. self.dialect.do_execute_no_params(
  1403. cursor, statement, context
  1404. )
  1405. else:
  1406. if self.dialect._has_events:
  1407. for fn in self.dialect.dispatch.do_execute:
  1408. if fn(cursor, statement, parameters, context):
  1409. evt_handled = True
  1410. break
  1411. if not evt_handled:
  1412. self.dialect.do_execute(
  1413. cursor, statement, parameters, context
  1414. )
  1415. if self._has_events or self.engine._has_events:
  1416. self.dispatch.after_cursor_execute(
  1417. self,
  1418. cursor,
  1419. statement,
  1420. parameters,
  1421. context,
  1422. context.executemany,
  1423. )
  1424. context.post_exec()
  1425. result = context._setup_result_proxy()
  1426. if not self._is_future:
  1427. should_close_with_result = branched.should_close_with_result
  1428. if not result._soft_closed and should_close_with_result:
  1429. result._autoclose_connection = True
  1430. if (
  1431. # usually we're in a transaction so avoid relatively
  1432. # expensive / legacy should_autocommit call
  1433. self._transaction is None
  1434. and context.should_autocommit
  1435. ):
  1436. self._commit_impl(autocommit=True)
  1437. # for "connectionless" execution, we have to close this
  1438. # Connection after the statement is complete.
  1439. # legacy stuff.
  1440. if should_close_with_result and context._soft_closed:
  1441. assert not self._is_future
  1442. # CursorResult already exhausted rows / has no rows.
  1443. # close us now
  1444. branched.close()
  1445. except BaseException as e:
  1446. self._handle_dbapi_exception(
  1447. e, statement, parameters, cursor, context
  1448. )
  1449. return result
  1450. def _cursor_execute(self, cursor, statement, parameters, context=None):
  1451. """Execute a statement + params on the given cursor.
  1452. Adds appropriate logging and exception handling.
  1453. This method is used by DefaultDialect for special-case
  1454. executions, such as for sequences and column defaults.
  1455. The path of statement execution in the majority of cases
  1456. terminates at _execute_context().
  1457. """
  1458. if self._has_events or self.engine._has_events:
  1459. for fn in self.dispatch.before_cursor_execute:
  1460. statement, parameters = fn(
  1461. self, cursor, statement, parameters, context, False
  1462. )
  1463. if self._echo:
  1464. self._log_info(statement)
  1465. self._log_info("[raw sql] %r", parameters)
  1466. try:
  1467. for fn in (
  1468. ()
  1469. if not self.dialect._has_events
  1470. else self.dialect.dispatch.do_execute
  1471. ):
  1472. if fn(cursor, statement, parameters, context):
  1473. break
  1474. else:
  1475. self.dialect.do_execute(cursor, statement, parameters, context)
  1476. except BaseException as e:
  1477. self._handle_dbapi_exception(
  1478. e, statement, parameters, cursor, context
  1479. )
  1480. if self._has_events or self.engine._has_events:
  1481. self.dispatch.after_cursor_execute(
  1482. self, cursor, statement, parameters, context, False
  1483. )
  1484. def _safe_close_cursor(self, cursor):
  1485. """Close the given cursor, catching exceptions
  1486. and turning into log warnings.
  1487. """
  1488. try:
  1489. cursor.close()
  1490. except Exception:
  1491. # log the error through the connection pool's logger.
  1492. self.engine.pool.logger.error(
  1493. "Error closing cursor", exc_info=True
  1494. )
  1495. _reentrant_error = False
  1496. _is_disconnect = False
  1497. def _handle_dbapi_exception(
  1498. self, e, statement, parameters, cursor, context
  1499. ):
  1500. exc_info = sys.exc_info()
  1501. is_exit_exception = util.is_exit_exception(e)
  1502. if not self._is_disconnect:
  1503. self._is_disconnect = (
  1504. isinstance(e, self.dialect.dbapi.Error)
  1505. and not self.closed
  1506. and self.dialect.is_disconnect(
  1507. e,
  1508. self._dbapi_connection if not self.invalidated else None,
  1509. cursor,
  1510. )
  1511. ) or (is_exit_exception and not self.closed)
  1512. invalidate_pool_on_disconnect = not is_exit_exception
  1513. if self._reentrant_error:
  1514. util.raise_(
  1515. exc.DBAPIError.instance(
  1516. statement,
  1517. parameters,
  1518. e,
  1519. self.dialect.dbapi.Error,
  1520. hide_parameters=self.engine.hide_parameters,
  1521. dialect=self.dialect,
  1522. ismulti=context.executemany
  1523. if context is not None
  1524. else None,
  1525. ),
  1526. with_traceback=exc_info[2],
  1527. from_=e,
  1528. )
  1529. self._reentrant_error = True
  1530. try:
  1531. # non-DBAPI error - if we already got a context,
  1532. # or there's no string statement, don't wrap it
  1533. should_wrap = isinstance(e, self.dialect.dbapi.Error) or (
  1534. statement is not None
  1535. and context is None
  1536. and not is_exit_exception
  1537. )
  1538. if should_wrap:
  1539. sqlalchemy_exception = exc.DBAPIError.instance(
  1540. statement,
  1541. parameters,
  1542. e,
  1543. self.dialect.dbapi.Error,
  1544. hide_parameters=self.engine.hide_parameters,
  1545. connection_invalidated=self._is_disconnect,
  1546. dialect=self.dialect,
  1547. ismulti=context.executemany
  1548. if context is not None
  1549. else None,
  1550. )
  1551. else:
  1552. sqlalchemy_exception = None
  1553. newraise = None
  1554. if (
  1555. self._has_events or self.engine._has_events
  1556. ) and not self._execution_options.get(
  1557. "skip_user_error_events", False
  1558. ):
  1559. ctx = ExceptionContextImpl(
  1560. e,
  1561. sqlalchemy_exception,
  1562. self.engine,
  1563. self,
  1564. cursor,
  1565. statement,
  1566. parameters,
  1567. context,
  1568. self._is_disconnect,
  1569. invalidate_pool_on_disconnect,
  1570. )
  1571. for fn in self.dispatch.handle_error:
  1572. try:
  1573. # handler returns an exception;
  1574. # call next handler in a chain
  1575. per_fn = fn(ctx)
  1576. if per_fn is not None:
  1577. ctx.chained_exception = newraise = per_fn
  1578. except Exception as _raised:
  1579. # handler raises an exception - stop processing
  1580. newraise = _raised
  1581. break
  1582. if self._is_disconnect != ctx.is_disconnect:
  1583. self._is_disconnect = ctx.is_disconnect
  1584. if sqlalchemy_exception:
  1585. sqlalchemy_exception.connection_invalidated = (
  1586. ctx.is_disconnect
  1587. )
  1588. # set up potentially user-defined value for
  1589. # invalidate pool.
  1590. invalidate_pool_on_disconnect = (
  1591. ctx.invalidate_pool_on_disconnect
  1592. )
  1593. if should_wrap and context:
  1594. context.handle_dbapi_exception(e)
  1595. if not self._is_disconnect:
  1596. if cursor:
  1597. self._safe_close_cursor(cursor)
  1598. with util.safe_reraise(warn_only=True):
  1599. self._autorollback()
  1600. if newraise:
  1601. util.raise_(newraise, with_traceback=exc_info[2], from_=e)
  1602. elif should_wrap:
  1603. util.raise_(
  1604. sqlalchemy_exception, with_traceback=exc_info[2], from_=e
  1605. )
  1606. else:
  1607. util.raise_(exc_info[1], with_traceback=exc_info[2])
  1608. finally:
  1609. del self._reentrant_error
  1610. if self._is_disconnect:
  1611. del self._is_disconnect
  1612. if not self.invalidated:
  1613. dbapi_conn_wrapper = self._dbapi_connection
  1614. if invalidate_pool_on_disconnect:
  1615. self.engine.pool._invalidate(dbapi_conn_wrapper, e)
  1616. self.invalidate(e)
  1617. if self.should_close_with_result:
  1618. assert not self._is_future
  1619. self.close()
  1620. @classmethod
  1621. def _handle_dbapi_exception_noconnection(cls, e, dialect, engine):
  1622. exc_info = sys.exc_info()
  1623. is_disconnect = dialect.is_disconnect(e, None, None)
  1624. should_wrap = isinstance(e, dialect.dbapi.Error)
  1625. if should_wrap:
  1626. sqlalchemy_exception = exc.DBAPIError.instance(
  1627. None,
  1628. None,
  1629. e,
  1630. dialect.dbapi.Error,
  1631. hide_parameters=engine.hide_parameters,
  1632. connection_invalidated=is_disconnect,
  1633. )
  1634. else:
  1635. sqlalchemy_exception = None
  1636. newraise = None
  1637. if engine._has_events:
  1638. ctx = ExceptionContextImpl(
  1639. e,
  1640. sqlalchemy_exception,
  1641. engine,
  1642. None,
  1643. None,
  1644. None,
  1645. None,
  1646. None,
  1647. is_disconnect,
  1648. True,
  1649. )
  1650. for fn in engine.dispatch.handle_error:
  1651. try:
  1652. # handler returns an exception;
  1653. # call next handler in a chain
  1654. per_fn = fn(ctx)
  1655. if per_fn is not None:
  1656. ctx.chained_exception = newraise = per_fn
  1657. except Exception as _raised:
  1658. # handler raises an exception - stop processing
  1659. newraise = _raised
  1660. break
  1661. if sqlalchemy_exception and is_disconnect != ctx.is_disconnect:
  1662. sqlalchemy_exception.connection_invalidated = (
  1663. is_disconnect
  1664. ) = ctx.is_disconnect
  1665. if newraise:
  1666. util.raise_(newraise, with_traceback=exc_info[2], from_=e)
  1667. elif should_wrap:
  1668. util.raise_(
  1669. sqlalchemy_exception, with_traceback=exc_info[2], from_=e
  1670. )
  1671. else:
  1672. util.raise_(exc_info[1], with_traceback=exc_info[2])
  1673. def _run_ddl_visitor(self, visitorcallable, element, **kwargs):
  1674. """run a DDL visitor.
  1675. This method is only here so that the MockConnection can change the
  1676. options given to the visitor so that "checkfirst" is skipped.
  1677. """
  1678. visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
  1679. @util.deprecated(
  1680. "1.4",
  1681. "The :meth:`_engine.Connection.transaction` "
  1682. "method is deprecated and will be "
  1683. "removed in a future release. Use the :meth:`_engine.Engine.begin` "
  1684. "context manager instead.",
  1685. )
  1686. def transaction(self, callable_, *args, **kwargs):
  1687. r"""Execute the given function within a transaction boundary.
  1688. The function is passed this :class:`_engine.Connection`
  1689. as the first argument, followed by the given \*args and \**kwargs,
  1690. e.g.::
  1691. def do_something(conn, x, y):
  1692. conn.execute(text("some statement"), {'x':x, 'y':y})
  1693. conn.transaction(do_something, 5, 10)
  1694. The operations inside the function are all invoked within the
  1695. context of a single :class:`.Transaction`.
  1696. Upon success, the transaction is committed. If an
  1697. exception is raised, the transaction is rolled back
  1698. before propagating the exception.
  1699. .. note::
  1700. The :meth:`.transaction` method is superseded by
  1701. the usage of the Python ``with:`` statement, which can
  1702. be used with :meth:`_engine.Connection.begin`::
  1703. with conn.begin():
  1704. conn.execute(text("some statement"), {'x':5, 'y':10})
  1705. As well as with :meth:`_engine.Engine.begin`::
  1706. with engine.begin() as conn:
  1707. conn.execute(text("some statement"), {'x':5, 'y':10})
  1708. .. seealso::
  1709. :meth:`_engine.Engine.begin` - engine-level transactional
  1710. context
  1711. :meth:`_engine.Engine.transaction` - engine-level version of
  1712. :meth:`_engine.Connection.transaction`
  1713. """
  1714. kwargs["_sa_skip_warning"] = True
  1715. trans = self.begin()
  1716. try:
  1717. ret = self.run_callable(callable_, *args, **kwargs)
  1718. trans.commit()
  1719. return ret
  1720. except:
  1721. with util.safe_reraise():
  1722. trans.rollback()
  1723. @util.deprecated(
  1724. "1.4",
  1725. "The :meth:`_engine.Connection.run_callable` "
  1726. "method is deprecated and will "
  1727. "be removed in a future release. Invoke the callable function "
  1728. "directly, passing the Connection.",
  1729. )
  1730. def run_callable(self, callable_, *args, **kwargs):
  1731. r"""Given a callable object or function, execute it, passing
  1732. a :class:`_engine.Connection` as the first argument.
  1733. The given \*args and \**kwargs are passed subsequent
  1734. to the :class:`_engine.Connection` argument.
  1735. This function, along with :meth:`_engine.Engine.run_callable`,
  1736. allows a function to be run with a :class:`_engine.Connection`
  1737. or :class:`_engine.Engine` object without the need to know
  1738. which one is being dealt with.
  1739. """
  1740. return callable_(self, *args, **kwargs)
  1741. class ExceptionContextImpl(ExceptionContext):
  1742. """Implement the :class:`.ExceptionContext` interface."""
  1743. def __init__(
  1744. self,
  1745. exception,
  1746. sqlalchemy_exception,
  1747. engine,
  1748. connection,
  1749. cursor,
  1750. statement,
  1751. parameters,
  1752. context,
  1753. is_disconnect,
  1754. invalidate_pool_on_disconnect,
  1755. ):
  1756. self.engine = engine
  1757. self.connection = connection
  1758. self.sqlalchemy_exception = sqlalchemy_exception
  1759. self.original_exception = exception
  1760. self.execution_context = context
  1761. self.statement = statement
  1762. self.parameters = parameters
  1763. self.is_disconnect = is_disconnect
  1764. self.invalidate_pool_on_disconnect = invalidate_pool_on_disconnect
  1765. class Transaction(TransactionalContext):
  1766. """Represent a database transaction in progress.
  1767. The :class:`.Transaction` object is procured by
  1768. calling the :meth:`_engine.Connection.begin` method of
  1769. :class:`_engine.Connection`::
  1770. from sqlalchemy import create_engine
  1771. engine = create_engine("postgresql://scott:tiger@localhost/test")
  1772. connection = engine.connect()
  1773. trans = connection.begin()
  1774. connection.execute(text("insert into x (a, b) values (1, 2)"))
  1775. trans.commit()
  1776. The object provides :meth:`.rollback` and :meth:`.commit`
  1777. methods in order to control transaction boundaries. It
  1778. also implements a context manager interface so that
  1779. the Python ``with`` statement can be used with the
  1780. :meth:`_engine.Connection.begin` method::
  1781. with connection.begin():
  1782. connection.execute(text("insert into x (a, b) values (1, 2)"))
  1783. The Transaction object is **not** threadsafe.
  1784. .. seealso::
  1785. :meth:`_engine.Connection.begin`
  1786. :meth:`_engine.Connection.begin_twophase`
  1787. :meth:`_engine.Connection.begin_nested`
  1788. .. index::
  1789. single: thread safety; Transaction
  1790. """
  1791. __slots__ = ()
  1792. _is_root = False
  1793. def __init__(self, connection):
  1794. raise NotImplementedError()
  1795. def _do_deactivate(self):
  1796. """do whatever steps are necessary to set this transaction as
  1797. "deactive", however leave this transaction object in place as far
  1798. as the connection's state.
  1799. for a "real" transaction this should roll back the transaction
  1800. and ensure this transaction is no longer a reset agent.
  1801. this is used for nesting of marker transactions where the marker
  1802. can set the "real" transaction as rolled back, however it stays
  1803. in place.
  1804. for 2.0 we hope to remove this nesting feature.
  1805. """
  1806. raise NotImplementedError()
  1807. @property
  1808. def _deactivated_from_connection(self):
  1809. """True if this transaction is totally deactivated from the connection
  1810. and therefore can no longer affect its state.
  1811. """
  1812. raise NotImplementedError()
  1813. def _do_close(self):
  1814. raise NotImplementedError()
  1815. def _do_rollback(self):
  1816. raise NotImplementedError()
  1817. def _do_commit(self):
  1818. raise NotImplementedError()
  1819. @property
  1820. def is_valid(self):
  1821. return self.is_active and not self.connection.invalidated
  1822. def close(self):
  1823. """Close this :class:`.Transaction`.
  1824. If this transaction is the base transaction in a begin/commit
  1825. nesting, the transaction will rollback(). Otherwise, the
  1826. method returns.
  1827. This is used to cancel a Transaction without affecting the scope of
  1828. an enclosing transaction.
  1829. """
  1830. try:
  1831. self._do_close()
  1832. finally:
  1833. assert not self.is_active
  1834. def rollback(self):
  1835. """Roll back this :class:`.Transaction`.
  1836. The implementation of this may vary based on the type of transaction in
  1837. use:
  1838. * For a simple database transaction (e.g. :class:`.RootTransaction`),
  1839. it corresponds to a ROLLBACK.
  1840. * For a :class:`.NestedTransaction`, it corresponds to a
  1841. "ROLLBACK TO SAVEPOINT" operation.
  1842. * For a :class:`.TwoPhaseTransaction`, DBAPI-specific methods for two
  1843. phase transactions may be used.
  1844. """
  1845. try:
  1846. self._do_rollback()
  1847. finally:
  1848. assert not self.is_active
  1849. def commit(self):
  1850. """Commit this :class:`.Transaction`.
  1851. The implementation of this may vary based on the type of transaction in
  1852. use:
  1853. * For a simple database transaction (e.g. :class:`.RootTransaction`),
  1854. it corresponds to a COMMIT.
  1855. * For a :class:`.NestedTransaction`, it corresponds to a
  1856. "RELEASE SAVEPOINT" operation.
  1857. * For a :class:`.TwoPhaseTransaction`, DBAPI-specific methods for two
  1858. phase transactions may be used.
  1859. """
  1860. try:
  1861. self._do_commit()
  1862. finally:
  1863. assert not self.is_active
  1864. def _get_subject(self):
  1865. return self.connection
  1866. def _transaction_is_active(self):
  1867. return self.is_active
  1868. def _transaction_is_closed(self):
  1869. return not self._deactivated_from_connection
  1870. class MarkerTransaction(Transaction):
  1871. """A 'marker' transaction that is used for nested begin() calls.
  1872. .. deprecated:: 1.4 future connection for 2.0 won't support this pattern.
  1873. """
  1874. __slots__ = ("connection", "_is_active", "_transaction")
  1875. def __init__(self, connection):
  1876. assert connection._transaction is not None
  1877. if not connection._transaction.is_active:
  1878. raise exc.InvalidRequestError(
  1879. "the current transaction on this connection is inactive. "
  1880. "Please issue a rollback first."
  1881. )
  1882. assert not connection._is_future
  1883. util.warn_deprecated_20(
  1884. "Calling .begin() when a transaction is already begun, creating "
  1885. "a 'sub' transaction, is deprecated "
  1886. "and will be removed in 2.0. See the documentation section "
  1887. "'Migrating from the nesting pattern' for background on how "
  1888. "to migrate from this pattern."
  1889. )
  1890. self.connection = connection
  1891. if connection._trans_context_manager:
  1892. TransactionalContext._trans_ctx_check(connection)
  1893. if connection._nested_transaction is not None:
  1894. self._transaction = connection._nested_transaction
  1895. else:
  1896. self._transaction = connection._transaction
  1897. self._is_active = True
  1898. @property
  1899. def _deactivated_from_connection(self):
  1900. return not self.is_active
  1901. @property
  1902. def is_active(self):
  1903. return self._is_active and self._transaction.is_active
  1904. def _deactivate(self):
  1905. self._is_active = False
  1906. def _do_close(self):
  1907. # does not actually roll back the root
  1908. self._deactivate()
  1909. def _do_rollback(self):
  1910. # does roll back the root
  1911. if self._is_active:
  1912. try:
  1913. self._transaction._do_deactivate()
  1914. finally:
  1915. self._deactivate()
  1916. def _do_commit(self):
  1917. self._deactivate()
  1918. class RootTransaction(Transaction):
  1919. """Represent the "root" transaction on a :class:`_engine.Connection`.
  1920. This corresponds to the current "BEGIN/COMMIT/ROLLBACK" that's occurring
  1921. for the :class:`_engine.Connection`. The :class:`_engine.RootTransaction`
  1922. is created by calling upon the :meth:`_engine.Connection.begin` method, and
  1923. remains associated with the :class:`_engine.Connection` throughout its
  1924. active span. The current :class:`_engine.RootTransaction` in use is
  1925. accessible via the :attr:`_engine.Connection.get_transaction` method of
  1926. :class:`_engine.Connection`.
  1927. In :term:`2.0 style` use, the :class:`_future.Connection` also employs
  1928. "autobegin" behavior that will create a new
  1929. :class:`_engine.RootTransaction` whenever a connection in a
  1930. non-transactional state is used to emit commands on the DBAPI connection.
  1931. The scope of the :class:`_engine.RootTransaction` in 2.0 style
  1932. use can be controlled using the :meth:`_future.Connection.commit` and
  1933. :meth:`_future.Connection.rollback` methods.
  1934. """
  1935. _is_root = True
  1936. __slots__ = ("connection", "is_active")
  1937. def __init__(self, connection):
  1938. assert connection._transaction is None
  1939. if connection._trans_context_manager:
  1940. TransactionalContext._trans_ctx_check(connection)
  1941. self.connection = connection
  1942. self._connection_begin_impl()
  1943. connection._transaction = self
  1944. self.is_active = True
  1945. def _deactivate_from_connection(self):
  1946. if self.is_active:
  1947. assert self.connection._transaction is self
  1948. self.is_active = False
  1949. elif self.connection._transaction is not self:
  1950. util.warn("transaction already deassociated from connection")
  1951. @property
  1952. def _deactivated_from_connection(self):
  1953. return self.connection._transaction is not self
  1954. def _do_deactivate(self):
  1955. # called from a MarkerTransaction to cancel this root transaction.
  1956. # the transaction stays in place as connection._transaction, but
  1957. # is no longer active and is no longer the reset agent for the
  1958. # pooled connection. the connection won't support a new begin()
  1959. # until this transaction is explicitly closed, rolled back,
  1960. # or committed.
  1961. assert self.connection._transaction is self
  1962. if self.is_active:
  1963. self._connection_rollback_impl()
  1964. # handle case where a savepoint was created inside of a marker
  1965. # transaction that refers to a root. nested has to be cancelled
  1966. # also.
  1967. if self.connection._nested_transaction:
  1968. self.connection._nested_transaction._cancel()
  1969. self._deactivate_from_connection()
  1970. def _connection_begin_impl(self):
  1971. self.connection._begin_impl(self)
  1972. def _connection_rollback_impl(self):
  1973. self.connection._rollback_impl()
  1974. def _connection_commit_impl(self):
  1975. self.connection._commit_impl()
  1976. def _close_impl(self, try_deactivate=False):
  1977. try:
  1978. if self.is_active:
  1979. self._connection_rollback_impl()
  1980. if self.connection._nested_transaction:
  1981. self.connection._nested_transaction._cancel()
  1982. finally:
  1983. if self.is_active or try_deactivate:
  1984. self._deactivate_from_connection()
  1985. if self.connection._transaction is self:
  1986. self.connection._transaction = None
  1987. assert not self.is_active
  1988. assert self.connection._transaction is not self
  1989. def _do_close(self):
  1990. self._close_impl()
  1991. def _do_rollback(self):
  1992. self._close_impl(try_deactivate=True)
  1993. def _do_commit(self):
  1994. if self.is_active:
  1995. assert self.connection._transaction is self
  1996. try:
  1997. self._connection_commit_impl()
  1998. finally:
  1999. # whether or not commit succeeds, cancel any
  2000. # nested transactions, make this transaction "inactive"
  2001. # and remove it as a reset agent
  2002. if self.connection._nested_transaction:
  2003. self.connection._nested_transaction._cancel()
  2004. self._deactivate_from_connection()
  2005. # ...however only remove as the connection's current transaction
  2006. # if commit succeeded. otherwise it stays on so that a rollback
  2007. # needs to occur.
  2008. self.connection._transaction = None
  2009. else:
  2010. if self.connection._transaction is self:
  2011. self.connection._invalid_transaction()
  2012. else:
  2013. raise exc.InvalidRequestError("This transaction is inactive")
  2014. assert not self.is_active
  2015. assert self.connection._transaction is not self
  2016. class NestedTransaction(Transaction):
  2017. """Represent a 'nested', or SAVEPOINT transaction.
  2018. The :class:`.NestedTransaction` object is created by calling the
  2019. :meth:`_engine.Connection.begin_nested` method of
  2020. :class:`_engine.Connection`.
  2021. When using :class:`.NestedTransaction`, the semantics of "begin" /
  2022. "commit" / "rollback" are as follows:
  2023. * the "begin" operation corresponds to the "BEGIN SAVEPOINT" command, where
  2024. the savepoint is given an explicit name that is part of the state
  2025. of this object.
  2026. * The :meth:`.NestedTransaction.commit` method corresponds to a
  2027. "RELEASE SAVEPOINT" operation, using the savepoint identifier associated
  2028. with this :class:`.NestedTransaction`.
  2029. * The :meth:`.NestedTransaction.rollback` method corresponds to a
  2030. "ROLLBACK TO SAVEPOINT" operation, using the savepoint identifier
  2031. associated with this :class:`.NestedTransaction`.
  2032. The rationale for mimicking the semantics of an outer transaction in
  2033. terms of savepoints so that code may deal with a "savepoint" transaction
  2034. and an "outer" transaction in an agnostic way.
  2035. .. seealso::
  2036. :ref:`session_begin_nested` - ORM version of the SAVEPOINT API.
  2037. """
  2038. __slots__ = ("connection", "is_active", "_savepoint", "_previous_nested")
  2039. def __init__(self, connection):
  2040. assert connection._transaction is not None
  2041. if connection._trans_context_manager:
  2042. TransactionalContext._trans_ctx_check(connection)
  2043. self.connection = connection
  2044. self._savepoint = self.connection._savepoint_impl()
  2045. self.is_active = True
  2046. self._previous_nested = connection._nested_transaction
  2047. connection._nested_transaction = self
  2048. def _deactivate_from_connection(self, warn=True):
  2049. if self.connection._nested_transaction is self:
  2050. self.connection._nested_transaction = self._previous_nested
  2051. elif warn:
  2052. util.warn(
  2053. "nested transaction already deassociated from connection"
  2054. )
  2055. @property
  2056. def _deactivated_from_connection(self):
  2057. return self.connection._nested_transaction is not self
  2058. def _cancel(self):
  2059. # called by RootTransaction when the outer transaction is
  2060. # committed, rolled back, or closed to cancel all savepoints
  2061. # without any action being taken
  2062. self.is_active = False
  2063. self._deactivate_from_connection()
  2064. if self._previous_nested:
  2065. self._previous_nested._cancel()
  2066. def _close_impl(self, deactivate_from_connection, warn_already_deactive):
  2067. try:
  2068. if self.is_active and self.connection._transaction.is_active:
  2069. self.connection._rollback_to_savepoint_impl(self._savepoint)
  2070. finally:
  2071. self.is_active = False
  2072. if deactivate_from_connection:
  2073. self._deactivate_from_connection(warn=warn_already_deactive)
  2074. assert not self.is_active
  2075. if deactivate_from_connection:
  2076. assert self.connection._nested_transaction is not self
  2077. def _do_deactivate(self):
  2078. self._close_impl(False, False)
  2079. def _do_close(self):
  2080. self._close_impl(True, False)
  2081. def _do_rollback(self):
  2082. self._close_impl(True, True)
  2083. def _do_commit(self):
  2084. if self.is_active:
  2085. try:
  2086. self.connection._release_savepoint_impl(self._savepoint)
  2087. finally:
  2088. # nested trans becomes inactive on failed release
  2089. # unconditionally. this prevents it from trying to
  2090. # emit SQL when it rolls back.
  2091. self.is_active = False
  2092. # but only de-associate from connection if it succeeded
  2093. self._deactivate_from_connection()
  2094. else:
  2095. if self.connection._nested_transaction is self:
  2096. self.connection._invalid_transaction()
  2097. else:
  2098. raise exc.InvalidRequestError(
  2099. "This nested transaction is inactive"
  2100. )
  2101. class TwoPhaseTransaction(RootTransaction):
  2102. """Represent a two-phase transaction.
  2103. A new :class:`.TwoPhaseTransaction` object may be procured
  2104. using the :meth:`_engine.Connection.begin_twophase` method.
  2105. The interface is the same as that of :class:`.Transaction`
  2106. with the addition of the :meth:`prepare` method.
  2107. """
  2108. __slots__ = ("connection", "is_active", "xid", "_is_prepared")
  2109. def __init__(self, connection, xid):
  2110. self._is_prepared = False
  2111. self.xid = xid
  2112. super(TwoPhaseTransaction, self).__init__(connection)
  2113. def prepare(self):
  2114. """Prepare this :class:`.TwoPhaseTransaction`.
  2115. After a PREPARE, the transaction can be committed.
  2116. """
  2117. if not self.is_active:
  2118. raise exc.InvalidRequestError("This transaction is inactive")
  2119. self.connection._prepare_twophase_impl(self.xid)
  2120. self._is_prepared = True
  2121. def _connection_begin_impl(self):
  2122. self.connection._begin_twophase_impl(self)
  2123. def _connection_rollback_impl(self):
  2124. self.connection._rollback_twophase_impl(self.xid, self._is_prepared)
  2125. def _connection_commit_impl(self):
  2126. self.connection._commit_twophase_impl(self.xid, self._is_prepared)
  2127. class Engine(Connectable, log.Identified):
  2128. """
  2129. Connects a :class:`~sqlalchemy.pool.Pool` and
  2130. :class:`~sqlalchemy.engine.interfaces.Dialect` together to provide a
  2131. source of database connectivity and behavior.
  2132. This is the **SQLAlchemy 1.x version** of :class:`_engine.Engine`. For
  2133. the :term:`2.0 style` version, which includes some API differences,
  2134. see :class:`_future.Engine`.
  2135. An :class:`_engine.Engine` object is instantiated publicly using the
  2136. :func:`~sqlalchemy.create_engine` function.
  2137. .. seealso::
  2138. :doc:`/core/engines`
  2139. :ref:`connections_toplevel`
  2140. """
  2141. _execution_options = _EMPTY_EXECUTION_OPTS
  2142. _has_events = False
  2143. _connection_cls = Connection
  2144. _sqla_logger_namespace = "sqlalchemy.engine.Engine"
  2145. _is_future = False
  2146. _schema_translate_map = None
  2147. def __init__(
  2148. self,
  2149. pool,
  2150. dialect,
  2151. url,
  2152. logging_name=None,
  2153. echo=None,
  2154. query_cache_size=500,
  2155. execution_options=None,
  2156. hide_parameters=False,
  2157. ):
  2158. self.pool = pool
  2159. self.url = url
  2160. self.dialect = dialect
  2161. if logging_name:
  2162. self.logging_name = logging_name
  2163. self.echo = echo
  2164. self.hide_parameters = hide_parameters
  2165. if query_cache_size != 0:
  2166. self._compiled_cache = util.LRUCache(
  2167. query_cache_size, size_alert=self._lru_size_alert
  2168. )
  2169. else:
  2170. self._compiled_cache = None
  2171. log.instance_logger(self, echoflag=echo)
  2172. if execution_options:
  2173. self.update_execution_options(**execution_options)
  2174. def _lru_size_alert(self, cache):
  2175. if self._should_log_info:
  2176. self.logger.info(
  2177. "Compiled cache size pruning from %d items to %d. "
  2178. "Increase cache size to reduce the frequency of pruning.",
  2179. len(cache),
  2180. cache.capacity,
  2181. )
  2182. @property
  2183. def engine(self):
  2184. return self
  2185. def clear_compiled_cache(self):
  2186. """Clear the compiled cache associated with the dialect.
  2187. This applies **only** to the built-in cache that is established
  2188. via the :paramref:`_engine.create_engine.query_cache_size` parameter.
  2189. It will not impact any dictionary caches that were passed via the
  2190. :paramref:`.Connection.execution_options.query_cache` parameter.
  2191. .. versionadded:: 1.4
  2192. """
  2193. if self._compiled_cache:
  2194. self._compiled_cache.clear()
  2195. def update_execution_options(self, **opt):
  2196. r"""Update the default execution_options dictionary
  2197. of this :class:`_engine.Engine`.
  2198. The given keys/values in \**opt are added to the
  2199. default execution options that will be used for
  2200. all connections. The initial contents of this dictionary
  2201. can be sent via the ``execution_options`` parameter
  2202. to :func:`_sa.create_engine`.
  2203. .. seealso::
  2204. :meth:`_engine.Connection.execution_options`
  2205. :meth:`_engine.Engine.execution_options`
  2206. """
  2207. self._execution_options = self._execution_options.union(opt)
  2208. self.dispatch.set_engine_execution_options(self, opt)
  2209. self.dialect.set_engine_execution_options(self, opt)
  2210. def execution_options(self, **opt):
  2211. """Return a new :class:`_engine.Engine` that will provide
  2212. :class:`_engine.Connection` objects with the given execution options.
  2213. The returned :class:`_engine.Engine` remains related to the original
  2214. :class:`_engine.Engine` in that it shares the same connection pool and
  2215. other state:
  2216. * The :class:`_pool.Pool` used by the new :class:`_engine.Engine`
  2217. is the
  2218. same instance. The :meth:`_engine.Engine.dispose`
  2219. method will replace
  2220. the connection pool instance for the parent engine as well
  2221. as this one.
  2222. * Event listeners are "cascaded" - meaning, the new
  2223. :class:`_engine.Engine`
  2224. inherits the events of the parent, and new events can be associated
  2225. with the new :class:`_engine.Engine` individually.
  2226. * The logging configuration and logging_name is copied from the parent
  2227. :class:`_engine.Engine`.
  2228. The intent of the :meth:`_engine.Engine.execution_options` method is
  2229. to implement "sharding" schemes where multiple :class:`_engine.Engine`
  2230. objects refer to the same connection pool, but are differentiated
  2231. by options that would be consumed by a custom event::
  2232. primary_engine = create_engine("mysql://")
  2233. shard1 = primary_engine.execution_options(shard_id="shard1")
  2234. shard2 = primary_engine.execution_options(shard_id="shard2")
  2235. Above, the ``shard1`` engine serves as a factory for
  2236. :class:`_engine.Connection`
  2237. objects that will contain the execution option
  2238. ``shard_id=shard1``, and ``shard2`` will produce
  2239. :class:`_engine.Connection`
  2240. objects that contain the execution option ``shard_id=shard2``.
  2241. An event handler can consume the above execution option to perform
  2242. a schema switch or other operation, given a connection. Below
  2243. we emit a MySQL ``use`` statement to switch databases, at the same
  2244. time keeping track of which database we've established using the
  2245. :attr:`_engine.Connection.info` dictionary,
  2246. which gives us a persistent
  2247. storage space that follows the DBAPI connection::
  2248. from sqlalchemy import event
  2249. from sqlalchemy.engine import Engine
  2250. shards = {"default": "base", shard_1: "db1", "shard_2": "db2"}
  2251. @event.listens_for(Engine, "before_cursor_execute")
  2252. def _switch_shard(conn, cursor, stmt,
  2253. params, context, executemany):
  2254. shard_id = conn._execution_options.get('shard_id', "default")
  2255. current_shard = conn.info.get("current_shard", None)
  2256. if current_shard != shard_id:
  2257. cursor.execute("use %s" % shards[shard_id])
  2258. conn.info["current_shard"] = shard_id
  2259. .. seealso::
  2260. :meth:`_engine.Connection.execution_options`
  2261. - update execution options
  2262. on a :class:`_engine.Connection` object.
  2263. :meth:`_engine.Engine.update_execution_options`
  2264. - update the execution
  2265. options for a given :class:`_engine.Engine` in place.
  2266. :meth:`_engine.Engine.get_execution_options`
  2267. """
  2268. return self._option_cls(self, opt)
  2269. def get_execution_options(self):
  2270. """Get the non-SQL options which will take effect during execution.
  2271. .. versionadded: 1.3
  2272. .. seealso::
  2273. :meth:`_engine.Engine.execution_options`
  2274. """
  2275. return self._execution_options
  2276. @property
  2277. def name(self):
  2278. """String name of the :class:`~sqlalchemy.engine.interfaces.Dialect`
  2279. in use by this :class:`Engine`."""
  2280. return self.dialect.name
  2281. @property
  2282. def driver(self):
  2283. """Driver name of the :class:`~sqlalchemy.engine.interfaces.Dialect`
  2284. in use by this :class:`Engine`."""
  2285. return self.dialect.driver
  2286. echo = log.echo_property()
  2287. def __repr__(self):
  2288. return "Engine(%r)" % (self.url,)
  2289. def dispose(self):
  2290. """Dispose of the connection pool used by this
  2291. :class:`_engine.Engine`.
  2292. This has the effect of fully closing all **currently checked in**
  2293. database connections. Connections that are still checked out
  2294. will **not** be closed, however they will no longer be associated
  2295. with this :class:`_engine.Engine`,
  2296. so when they are closed individually,
  2297. eventually the :class:`_pool.Pool` which they are associated with will
  2298. be garbage collected and they will be closed out fully, if
  2299. not already closed on checkin.
  2300. A new connection pool is created immediately after the old one has
  2301. been disposed. This new pool, like all SQLAlchemy connection pools,
  2302. does not make any actual connections to the database until one is
  2303. first requested, so as long as the :class:`_engine.Engine`
  2304. isn't used again,
  2305. no new connections will be made.
  2306. .. seealso::
  2307. :ref:`engine_disposal`
  2308. """
  2309. self.pool.dispose()
  2310. self.pool = self.pool.recreate()
  2311. self.dispatch.engine_disposed(self)
  2312. def _execute_default(
  2313. self, default, multiparams=(), params=util.EMPTY_DICT
  2314. ):
  2315. with self.connect() as conn:
  2316. return conn._execute_default(default, multiparams, params)
  2317. @contextlib.contextmanager
  2318. def _optional_conn_ctx_manager(self, connection=None):
  2319. if connection is None:
  2320. with self.connect() as conn:
  2321. yield conn
  2322. else:
  2323. yield connection
  2324. class _trans_ctx(object):
  2325. def __init__(self, conn, transaction, close_with_result):
  2326. self.conn = conn
  2327. self.transaction = transaction
  2328. self.close_with_result = close_with_result
  2329. def __enter__(self):
  2330. self.transaction.__enter__()
  2331. return self.conn
  2332. def __exit__(self, type_, value, traceback):
  2333. try:
  2334. self.transaction.__exit__(type_, value, traceback)
  2335. finally:
  2336. if not self.close_with_result:
  2337. self.conn.close()
  2338. def begin(self, close_with_result=False):
  2339. """Return a context manager delivering a :class:`_engine.Connection`
  2340. with a :class:`.Transaction` established.
  2341. E.g.::
  2342. with engine.begin() as conn:
  2343. conn.execute(
  2344. text("insert into table (x, y, z) values (1, 2, 3)")
  2345. )
  2346. conn.execute(text("my_special_procedure(5)"))
  2347. Upon successful operation, the :class:`.Transaction`
  2348. is committed. If an error is raised, the :class:`.Transaction`
  2349. is rolled back.
  2350. Legacy use only: the ``close_with_result`` flag is normally ``False``,
  2351. and indicates that the :class:`_engine.Connection` will be closed when
  2352. the operation is complete. When set to ``True``, it indicates the
  2353. :class:`_engine.Connection` is in "single use" mode, where the
  2354. :class:`_engine.CursorResult` returned by the first call to
  2355. :meth:`_engine.Connection.execute` will close the
  2356. :class:`_engine.Connection` when that :class:`_engine.CursorResult` has
  2357. exhausted all result rows.
  2358. .. seealso::
  2359. :meth:`_engine.Engine.connect` - procure a
  2360. :class:`_engine.Connection` from
  2361. an :class:`_engine.Engine`.
  2362. :meth:`_engine.Connection.begin` - start a :class:`.Transaction`
  2363. for a particular :class:`_engine.Connection`.
  2364. """
  2365. if self._connection_cls._is_future:
  2366. conn = self.connect()
  2367. else:
  2368. conn = self.connect(close_with_result=close_with_result)
  2369. try:
  2370. trans = conn.begin()
  2371. except:
  2372. with util.safe_reraise():
  2373. conn.close()
  2374. return Engine._trans_ctx(conn, trans, close_with_result)
  2375. @util.deprecated(
  2376. "1.4",
  2377. "The :meth:`_engine.Engine.transaction` "
  2378. "method is deprecated and will be "
  2379. "removed in a future release. Use the :meth:`_engine.Engine.begin` "
  2380. "context "
  2381. "manager instead.",
  2382. )
  2383. def transaction(self, callable_, *args, **kwargs):
  2384. r"""Execute the given function within a transaction boundary.
  2385. The function is passed a :class:`_engine.Connection` newly procured
  2386. from :meth:`_engine.Engine.connect` as the first argument,
  2387. followed by the given \*args and \**kwargs.
  2388. e.g.::
  2389. def do_something(conn, x, y):
  2390. conn.execute(text("some statement"), {'x':x, 'y':y})
  2391. engine.transaction(do_something, 5, 10)
  2392. The operations inside the function are all invoked within the
  2393. context of a single :class:`.Transaction`.
  2394. Upon success, the transaction is committed. If an
  2395. exception is raised, the transaction is rolled back
  2396. before propagating the exception.
  2397. .. note::
  2398. The :meth:`.transaction` method is superseded by
  2399. the usage of the Python ``with:`` statement, which can
  2400. be used with :meth:`_engine.Engine.begin`::
  2401. with engine.begin() as conn:
  2402. conn.execute(text("some statement"), {'x':5, 'y':10})
  2403. .. seealso::
  2404. :meth:`_engine.Engine.begin` - engine-level transactional
  2405. context
  2406. :meth:`_engine.Connection.transaction`
  2407. - connection-level version of
  2408. :meth:`_engine.Engine.transaction`
  2409. """
  2410. kwargs["_sa_skip_warning"] = True
  2411. with self.connect() as conn:
  2412. return conn.transaction(callable_, *args, **kwargs)
  2413. @util.deprecated(
  2414. "1.4",
  2415. "The :meth:`_engine.Engine.run_callable` "
  2416. "method is deprecated and will be "
  2417. "removed in a future release. Use the :meth:`_engine.Engine.begin` "
  2418. "context manager instead.",
  2419. )
  2420. def run_callable(self, callable_, *args, **kwargs):
  2421. r"""Given a callable object or function, execute it, passing
  2422. a :class:`_engine.Connection` as the first argument.
  2423. The given \*args and \**kwargs are passed subsequent
  2424. to the :class:`_engine.Connection` argument.
  2425. This function, along with :meth:`_engine.Connection.run_callable`,
  2426. allows a function to be run with a :class:`_engine.Connection`
  2427. or :class:`_engine.Engine` object without the need to know
  2428. which one is being dealt with.
  2429. """
  2430. kwargs["_sa_skip_warning"] = True
  2431. with self.connect() as conn:
  2432. return conn.run_callable(callable_, *args, **kwargs)
  2433. def _run_ddl_visitor(self, visitorcallable, element, **kwargs):
  2434. with self.begin() as conn:
  2435. conn._run_ddl_visitor(visitorcallable, element, **kwargs)
  2436. @util.deprecated_20(
  2437. ":meth:`_engine.Engine.execute`",
  2438. alternative="All statement execution in SQLAlchemy 2.0 is performed "
  2439. "by the :meth:`_engine.Connection.execute` method of "
  2440. ":class:`_engine.Connection`, "
  2441. "or in the ORM by the :meth:`.Session.execute` method of "
  2442. ":class:`.Session`.",
  2443. )
  2444. def execute(self, statement, *multiparams, **params):
  2445. """Executes the given construct and returns a
  2446. :class:`_engine.CursorResult`.
  2447. The arguments are the same as those used by
  2448. :meth:`_engine.Connection.execute`.
  2449. Here, a :class:`_engine.Connection` is acquired using the
  2450. :meth:`_engine.Engine.connect` method, and the statement executed
  2451. with that connection. The returned :class:`_engine.CursorResult`
  2452. is flagged
  2453. such that when the :class:`_engine.CursorResult` is exhausted and its
  2454. underlying cursor is closed, the :class:`_engine.Connection`
  2455. created here
  2456. will also be closed, which allows its associated DBAPI connection
  2457. resource to be returned to the connection pool.
  2458. """
  2459. connection = self.connect(close_with_result=True)
  2460. return connection.execute(statement, *multiparams, **params)
  2461. @util.deprecated_20(
  2462. ":meth:`_engine.Engine.scalar`",
  2463. alternative="All statement execution in SQLAlchemy 2.0 is performed "
  2464. "by the :meth:`_engine.Connection.execute` method of "
  2465. ":class:`_engine.Connection`, "
  2466. "or in the ORM by the :meth:`.Session.execute` method of "
  2467. ":class:`.Session`; the :meth:`_future.Result.scalar` "
  2468. "method can then be "
  2469. "used to return a scalar result.",
  2470. )
  2471. def scalar(self, statement, *multiparams, **params):
  2472. """Executes and returns the first column of the first row.
  2473. The underlying result/cursor is closed after execution.
  2474. """
  2475. return self.execute(statement, *multiparams, **params).scalar()
  2476. def _execute_clauseelement(
  2477. self,
  2478. elem,
  2479. multiparams=None,
  2480. params=None,
  2481. execution_options=_EMPTY_EXECUTION_OPTS,
  2482. ):
  2483. connection = self.connect(close_with_result=True)
  2484. return connection._execute_clauseelement(
  2485. elem, multiparams, params, execution_options
  2486. )
  2487. def _execute_compiled(
  2488. self,
  2489. compiled,
  2490. multiparams,
  2491. params,
  2492. execution_options=_EMPTY_EXECUTION_OPTS,
  2493. ):
  2494. connection = self.connect(close_with_result=True)
  2495. return connection._execute_compiled(
  2496. compiled, multiparams, params, execution_options
  2497. )
  2498. def connect(self, close_with_result=False):
  2499. """Return a new :class:`_engine.Connection` object.
  2500. The :class:`_engine.Connection` object is a facade that uses a DBAPI
  2501. connection internally in order to communicate with the database. This
  2502. connection is procured from the connection-holding :class:`_pool.Pool`
  2503. referenced by this :class:`_engine.Engine`. When the
  2504. :meth:`_engine.Connection.close` method of the
  2505. :class:`_engine.Connection` object
  2506. is called, the underlying DBAPI connection is then returned to the
  2507. connection pool, where it may be used again in a subsequent call to
  2508. :meth:`_engine.Engine.connect`.
  2509. """
  2510. return self._connection_cls(self, close_with_result=close_with_result)
  2511. @util.deprecated(
  2512. "1.4",
  2513. "The :meth:`_engine.Engine.table_names` "
  2514. "method is deprecated and will be "
  2515. "removed in a future release. Please refer to "
  2516. ":meth:`_reflection.Inspector.get_table_names`.",
  2517. )
  2518. def table_names(self, schema=None, connection=None):
  2519. """Return a list of all table names available in the database.
  2520. :param schema: Optional, retrieve names from a non-default schema.
  2521. :param connection: Optional, use a specified connection.
  2522. """
  2523. with self._optional_conn_ctx_manager(connection) as conn:
  2524. insp = inspection.inspect(conn)
  2525. return insp.get_table_names(schema)
  2526. @util.deprecated(
  2527. "1.4",
  2528. "The :meth:`_engine.Engine.has_table` "
  2529. "method is deprecated and will be "
  2530. "removed in a future release. Please refer to "
  2531. ":meth:`_reflection.Inspector.has_table`.",
  2532. )
  2533. def has_table(self, table_name, schema=None):
  2534. """Return True if the given backend has a table of the given name.
  2535. .. seealso::
  2536. :ref:`metadata_reflection_inspector` - detailed schema inspection
  2537. using the :class:`_reflection.Inspector` interface.
  2538. :class:`.quoted_name` - used to pass quoting information along
  2539. with a schema identifier.
  2540. """
  2541. with self._optional_conn_ctx_manager(None) as conn:
  2542. insp = inspection.inspect(conn)
  2543. return insp.has_table(table_name, schema=schema)
  2544. def _wrap_pool_connect(self, fn, connection):
  2545. dialect = self.dialect
  2546. try:
  2547. return fn()
  2548. except dialect.dbapi.Error as e:
  2549. if connection is None:
  2550. Connection._handle_dbapi_exception_noconnection(
  2551. e, dialect, self
  2552. )
  2553. else:
  2554. util.raise_(
  2555. sys.exc_info()[1], with_traceback=sys.exc_info()[2]
  2556. )
  2557. def raw_connection(self, _connection=None):
  2558. """Return a "raw" DBAPI connection from the connection pool.
  2559. The returned object is a proxied version of the DBAPI
  2560. connection object used by the underlying driver in use.
  2561. The object will have all the same behavior as the real DBAPI
  2562. connection, except that its ``close()`` method will result in the
  2563. connection being returned to the pool, rather than being closed
  2564. for real.
  2565. This method provides direct DBAPI connection access for
  2566. special situations when the API provided by
  2567. :class:`_engine.Connection`
  2568. is not needed. When a :class:`_engine.Connection` object is already
  2569. present, the DBAPI connection is available using
  2570. the :attr:`_engine.Connection.connection` accessor.
  2571. .. seealso::
  2572. :ref:`dbapi_connections`
  2573. """
  2574. return self._wrap_pool_connect(self.pool.connect, _connection)
  2575. class OptionEngineMixin(object):
  2576. _sa_propagate_class_events = False
  2577. def __init__(self, proxied, execution_options):
  2578. self._proxied = proxied
  2579. self.url = proxied.url
  2580. self.dialect = proxied.dialect
  2581. self.logging_name = proxied.logging_name
  2582. self.echo = proxied.echo
  2583. self._compiled_cache = proxied._compiled_cache
  2584. self.hide_parameters = proxied.hide_parameters
  2585. log.instance_logger(self, echoflag=self.echo)
  2586. # note: this will propagate events that are assigned to the parent
  2587. # engine after this OptionEngine is created. Since we share
  2588. # the events of the parent we also disallow class-level events
  2589. # to apply to the OptionEngine class directly.
  2590. #
  2591. # the other way this can work would be to transfer existing
  2592. # events only, using:
  2593. # self.dispatch._update(proxied.dispatch)
  2594. #
  2595. # that might be more appropriate however it would be a behavioral
  2596. # change for logic that assigns events to the parent engine and
  2597. # would like it to take effect for the already-created sub-engine.
  2598. self.dispatch = self.dispatch._join(proxied.dispatch)
  2599. self._execution_options = proxied._execution_options
  2600. self.update_execution_options(**execution_options)
  2601. def _get_pool(self):
  2602. return self._proxied.pool
  2603. def _set_pool(self, pool):
  2604. self._proxied.pool = pool
  2605. pool = property(_get_pool, _set_pool)
  2606. def _get_has_events(self):
  2607. return self._proxied._has_events or self.__dict__.get(
  2608. "_has_events", False
  2609. )
  2610. def _set_has_events(self, value):
  2611. self.__dict__["_has_events"] = value
  2612. _has_events = property(_get_has_events, _set_has_events)
  2613. class OptionEngine(OptionEngineMixin, Engine):
  2614. pass
  2615. Engine._option_cls = OptionEngine