base.py 122 KB

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