Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/base.py: 24%

1027 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1# engine/base.py 

2# Copyright (C) 2005-2022 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 

7from __future__ import with_statement 

8 

9import contextlib 

10import sys 

11 

12from .interfaces import Connectable 

13from .interfaces import ExceptionContext 

14from .util import _distill_params 

15from .util import _distill_params_20 

16from .util import TransactionalContext 

17from .. import exc 

18from .. import inspection 

19from .. import log 

20from .. import util 

21from ..sql import compiler 

22from ..sql import util as sql_util 

23 

24 

25"""Defines :class:`_engine.Connection` and :class:`_engine.Engine`. 

26 

27""" 

28 

29_EMPTY_EXECUTION_OPTS = util.immutabledict() 

30 

31 

32class Connection(Connectable): 

33 """Provides high-level functionality for a wrapped DB-API connection. 

34 

35 **This is the SQLAlchemy 1.x.x version** of the :class:`_engine.Connection` 

36 class. For the :term:`2.0 style` version, which features some API 

37 differences, see :class:`_future.Connection`. 

38 

39 The :class:`_engine.Connection` object is procured by calling 

40 the :meth:`_engine.Engine.connect` method of the :class:`_engine.Engine` 

41 object, and provides services for execution of SQL statements as well 

42 as transaction control. 

43 

44 The Connection object is **not** thread-safe. While a Connection can be 

45 shared among threads using properly synchronized access, it is still 

46 possible that the underlying DBAPI connection may not support shared 

47 access between threads. Check the DBAPI documentation for details. 

48 

49 The Connection object represents a single DBAPI connection checked out 

50 from the connection pool. In this state, the connection pool has no affect 

51 upon the connection, including its expiration or timeout state. For the 

52 connection pool to properly manage connections, connections should be 

53 returned to the connection pool (i.e. ``connection.close()``) whenever the 

54 connection is not in use. 

55 

56 .. index:: 

57 single: thread safety; Connection 

58 

59 """ 

60 

61 _is_future = False 

62 _sqla_logger_namespace = "sqlalchemy.engine.Connection" 

63 

64 # used by sqlalchemy.engine.util.TransactionalContext 

65 _trans_context_manager = None 

66 

67 def __init__( 

68 self, 

69 engine, 

70 connection=None, 

71 close_with_result=False, 

72 _branch_from=None, 

73 _execution_options=None, 

74 _dispatch=None, 

75 _has_events=None, 

76 _allow_revalidate=True, 

77 ): 

78 """Construct a new Connection.""" 

79 self.engine = engine 

80 self.dialect = engine.dialect 

81 self.__branch_from = _branch_from 

82 

83 if _branch_from: 

84 # branching is always "from" the root connection 

85 assert _branch_from.__branch_from is None 

86 self._dbapi_connection = connection 

87 self._execution_options = _execution_options 

88 self._echo = _branch_from._echo 

89 self.should_close_with_result = False 

90 self.dispatch = _dispatch 

91 self._has_events = _branch_from._has_events 

92 else: 

93 self._dbapi_connection = ( 

94 connection 

95 if connection is not None 

96 else engine.raw_connection() 

97 ) 

98 

99 self._transaction = self._nested_transaction = None 

100 self.__savepoint_seq = 0 

101 self.__in_begin = False 

102 self.should_close_with_result = close_with_result 

103 

104 self.__can_reconnect = _allow_revalidate 

105 self._echo = self.engine._should_log_info() 

106 

107 if _has_events is None: 

108 # if _has_events is sent explicitly as False, 

109 # then don't join the dispatch of the engine; we don't 

110 # want to handle any of the engine's events in that case. 

111 self.dispatch = self.dispatch._join(engine.dispatch) 

112 self._has_events = _has_events or ( 

113 _has_events is None and engine._has_events 

114 ) 

115 

116 assert not _execution_options 

117 self._execution_options = engine._execution_options 

118 

119 if self._has_events or self.engine._has_events: 

120 self.dispatch.engine_connect(self, _branch_from is not None) 

121 

122 @util.memoized_property 

123 def _message_formatter(self): 

124 if "logging_token" in self._execution_options: 

125 token = self._execution_options["logging_token"] 

126 return lambda msg: "[%s] %s" % (token, msg) 

127 else: 

128 return None 

129 

130 def _log_info(self, message, *arg, **kw): 

131 fmt = self._message_formatter 

132 

133 if fmt: 

134 message = fmt(message) 

135 

136 if log.STACKLEVEL: 

137 kw["stacklevel"] = 1 + log.STACKLEVEL_OFFSET 

138 

139 self.engine.logger.info(message, *arg, **kw) 

140 

141 def _log_debug(self, message, *arg, **kw): 

142 fmt = self._message_formatter 

143 

144 if fmt: 

145 message = fmt(message) 

146 

147 if log.STACKLEVEL: 

148 kw["stacklevel"] = 1 + log.STACKLEVEL_OFFSET 

149 

150 self.engine.logger.debug(message, *arg, **kw) 

151 

152 @property 

153 def _schema_translate_map(self): 

154 return self._execution_options.get("schema_translate_map", None) 

155 

156 def schema_for_object(self, obj): 

157 """Return the schema name for the given schema item taking into 

158 account current schema translate map. 

159 

160 """ 

161 

162 name = obj.schema 

163 schema_translate_map = self._execution_options.get( 

164 "schema_translate_map", None 

165 ) 

166 

167 if ( 

168 schema_translate_map 

169 and name in schema_translate_map 

170 and obj._use_schema_map 

171 ): 

172 return schema_translate_map[name] 

173 else: 

174 return name 

175 

176 def _branch(self): 

177 """Return a new Connection which references this Connection's 

178 engine and connection; but does not have close_with_result enabled, 

179 and also whose close() method does nothing. 

180 

181 .. deprecated:: 1.4 the "branching" concept will be removed in 

182 SQLAlchemy 2.0 as well as the "Connection.connect()" method which 

183 is the only consumer for this. 

184 

185 The Core uses this very sparingly, only in the case of 

186 custom SQL default functions that are to be INSERTed as the 

187 primary key of a row where we need to get the value back, so we have 

188 to invoke it distinctly - this is a very uncommon case. 

189 

190 Userland code accesses _branch() when the connect() 

191 method is called. The branched connection 

192 acts as much as possible like the parent, except that it stays 

193 connected when a close() event occurs. 

194 

195 """ 

196 return self.engine._connection_cls( 

197 self.engine, 

198 self._dbapi_connection, 

199 _branch_from=self.__branch_from if self.__branch_from else self, 

200 _execution_options=self._execution_options, 

201 _has_events=self._has_events, 

202 _dispatch=self.dispatch, 

203 ) 

204 

205 def _generate_for_options(self): 

206 """define connection method chaining behavior for execution_options""" 

207 

208 if self._is_future: 

209 return self 

210 else: 

211 c = self.__class__.__new__(self.__class__) 

212 c.__dict__ = self.__dict__.copy() 

213 return c 

214 

215 def __enter__(self): 

216 return self 

217 

218 def __exit__(self, type_, value, traceback): 

219 self.close() 

220 

221 def execution_options(self, **opt): 

222 r""" Set non-SQL options for the connection which take effect 

223 during execution. 

224 

225 For a "future" style connection, this method returns this same 

226 :class:`_future.Connection` object with the new options added. 

227 

228 For a legacy connection, this method returns a copy of this 

229 :class:`_engine.Connection` which references the same underlying DBAPI 

230 connection, but also defines the given execution options which will 

231 take effect for a call to 

232 :meth:`execute`. As the new :class:`_engine.Connection` references the 

233 same underlying resource, it's usually a good idea to ensure that 

234 the copies will be discarded immediately, which is implicit if used 

235 as in:: 

236 

237 result = connection.execution_options(stream_results=True).\ 

238 execute(stmt) 

239 

240 Note that any key/value can be passed to 

241 :meth:`_engine.Connection.execution_options`, 

242 and it will be stored in the 

243 ``_execution_options`` dictionary of the :class:`_engine.Connection`. 

244 It 

245 is suitable for usage by end-user schemes to communicate with 

246 event listeners, for example. 

247 

248 The keywords that are currently recognized by SQLAlchemy itself 

249 include all those listed under :meth:`.Executable.execution_options`, 

250 as well as others that are specific to :class:`_engine.Connection`. 

251 

252 :param autocommit: Available on: Connection, statement. 

253 When True, a COMMIT will be invoked after execution 

254 when executed in 'autocommit' mode, i.e. when an explicit 

255 transaction is not begun on the connection. Note that this 

256 is **library level, not DBAPI level autocommit**. The DBAPI 

257 connection will remain in a real transaction unless the 

258 "AUTOCOMMIT" isolation level is used. 

259 

260 .. deprecated:: 1.4 The "autocommit" execution option is deprecated 

261 and will be removed in SQLAlchemy 2.0. See 

262 :ref:`migration_20_autocommit` for discussion. 

263 

264 :param compiled_cache: Available on: Connection. 

265 A dictionary where :class:`.Compiled` objects 

266 will be cached when the :class:`_engine.Connection` 

267 compiles a clause 

268 expression into a :class:`.Compiled` object. This dictionary will 

269 supersede the statement cache that may be configured on the 

270 :class:`_engine.Engine` itself. If set to None, caching 

271 is disabled, even if the engine has a configured cache size. 

272 

273 Note that the ORM makes use of its own "compiled" caches for 

274 some operations, including flush operations. The caching 

275 used by the ORM internally supersedes a cache dictionary 

276 specified here. 

277 

278 :param logging_token: Available on: :class:`_engine.Connection`, 

279 :class:`_engine.Engine`. 

280 

281 Adds the specified string token surrounded by brackets in log 

282 messages logged by the connection, i.e. the logging that's enabled 

283 either via the :paramref:`_sa.create_engine.echo` flag or via the 

284 ``logging.getLogger("sqlalchemy.engine")`` logger. This allows a 

285 per-connection or per-sub-engine token to be available which is 

286 useful for debugging concurrent connection scenarios. 

287 

288 .. versionadded:: 1.4.0b2 

289 

290 .. seealso:: 

291 

292 :ref:`dbengine_logging_tokens` - usage example 

293 

294 :paramref:`_sa.create_engine.logging_name` - adds a name to the 

295 name used by the Python logger object itself. 

296 

297 :param isolation_level: Available on: :class:`_engine.Connection`. 

298 

299 Set the transaction isolation level for the lifespan of this 

300 :class:`_engine.Connection` object. 

301 Valid values include those string 

302 values accepted by the :paramref:`_sa.create_engine.isolation_level` 

303 parameter passed to :func:`_sa.create_engine`. These levels are 

304 semi-database specific; see individual dialect documentation for 

305 valid levels. 

306 

307 The isolation level option applies the isolation level by emitting 

308 statements on the DBAPI connection, and **necessarily affects the 

309 original Connection object overall**, not just the copy that is 

310 returned by the call to :meth:`_engine.Connection.execution_options` 

311 method. The isolation level will remain at the given setting until 

312 the DBAPI connection itself is returned to the connection pool, i.e. 

313 the :meth:`_engine.Connection.close` method on the original 

314 :class:`_engine.Connection` is called, 

315 where an event handler will emit 

316 additional statements on the DBAPI connection in order to revert the 

317 isolation level change. 

318 

319 .. warning:: The ``isolation_level`` execution option should 

320 **not** be used when a transaction is already established, that 

321 is, the :meth:`_engine.Connection.begin` 

322 method or similar has been 

323 called. A database cannot change the isolation level on a 

324 transaction in progress, and different DBAPIs and/or 

325 SQLAlchemy dialects may implicitly roll back or commit 

326 the transaction, or not affect the connection at all. 

327 

328 .. note:: The ``isolation_level`` execution option is implicitly 

329 reset if the :class:`_engine.Connection` is invalidated, e.g. via 

330 the :meth:`_engine.Connection.invalidate` method, or if a 

331 disconnection error occurs. The new connection produced after 

332 the invalidation will not have the isolation level re-applied 

333 to it automatically. 

334 

335 .. seealso:: 

336 

337 :paramref:`_sa.create_engine.isolation_level` 

338 - set per :class:`_engine.Engine` isolation level 

339 

340 :meth:`_engine.Connection.get_isolation_level` 

341 - view current level 

342 

343 :ref:`SQLite Transaction Isolation <sqlite_isolation_level>` 

344 

345 :ref:`PostgreSQL Transaction Isolation <postgresql_isolation_level>` 

346 

347 :ref:`MySQL Transaction Isolation <mysql_isolation_level>` 

348 

349 :ref:`SQL Server Transaction Isolation <mssql_isolation_level>` 

350 

351 :ref:`session_transaction_isolation` - for the ORM 

352 

353 :param no_parameters: When ``True``, if the final parameter 

354 list or dictionary is totally empty, will invoke the 

355 statement on the cursor as ``cursor.execute(statement)``, 

356 not passing the parameter collection at all. 

357 Some DBAPIs such as psycopg2 and mysql-python consider 

358 percent signs as significant only when parameters are 

359 present; this option allows code to generate SQL 

360 containing percent signs (and possibly other characters) 

361 that is neutral regarding whether it's executed by the DBAPI 

362 or piped into a script that's later invoked by 

363 command line tools. 

364 

365 :param stream_results: Available on: Connection, statement. 

366 Indicate to the dialect that results should be 

367 "streamed" and not pre-buffered, if possible. For backends 

368 such as PostgreSQL, MySQL and MariaDB, this indicates the use of 

369 a "server side cursor" as opposed to a client side cursor. 

370 Other backends such as that of Oracle may already use server 

371 side cursors by default. 

372 

373 The usage of 

374 :paramref:`_engine.Connection.execution_options.stream_results` is 

375 usually combined with setting a fixed number of rows to to be fetched 

376 in batches, to allow for efficient iteration of database rows while 

377 at the same time not loading all result rows into memory at once; 

378 this can be configured on a :class:`_engine.Result` object using the 

379 :meth:`_engine.Result.yield_per` method, after execution has 

380 returned a new :class:`_engine.Result`. If 

381 :meth:`_engine.Result.yield_per` is not used, 

382 the :paramref:`_engine.Connection.execution_options.stream_results` 

383 mode of operation will instead use a dynamically sized buffer 

384 which buffers sets of rows at a time, growing on each batch 

385 based on a fixed growth size up until a limit which may 

386 be configured using the 

387 :paramref:`_engine.Connection.execution_options.max_row_buffer` 

388 parameter. 

389 

390 When using the ORM to fetch ORM mapped objects from a result, 

391 :meth:`_engine.Result.yield_per` should always be used with 

392 :paramref:`_engine.Connection.execution_options.stream_results`, 

393 so that the ORM does not fetch all rows into new ORM objects at once. 

394 

395 For typical use, the 

396 :paramref:`_engine.Connection.execution_options.yield_per` execution 

397 option should be preferred, which sets up both 

398 :paramref:`_engine.Connection.execution_options.stream_results` and 

399 :meth:`_engine.Result.yield_per` at once. This option is supported 

400 both at a core level by :class:`_engine.Connection` as well as by the 

401 ORM :class:`_engine.Session`; the latter is described at 

402 :ref:`orm_queryguide_yield_per`. 

403 

404 .. seealso:: 

405 

406 :ref:`engine_stream_results` - background on 

407 :paramref:`_engine.Connection.execution_options.stream_results` 

408 

409 :paramref:`_engine.Connection.execution_options.max_row_buffer` 

410 

411 :paramref:`_engine.Connection.execution_options.yield_per` 

412 

413 :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel` 

414 describing the ORM version of ``yield_per`` 

415 

416 :param max_row_buffer: Available on: :class:`_engine.Connection`, 

417 :class:`_sql.Executable`. Sets a maximum 

418 buffer size to use when the 

419 :paramref:`_engine.Connection.execution_options.stream_results` 

420 execution option is used on a backend that supports server side 

421 cursors. The default value if not specified is 1000. 

422 

423 .. seealso:: 

424 

425 :paramref:`_engine.Connection.execution_options.stream_results` 

426 

427 :ref:`engine_stream_results` 

428 

429 

430 :param yield_per: Available on: :class:`_engine.Connection`, 

431 :class:`_sql.Executable`. Integer value applied which will 

432 set the :paramref:`_engine.Connection.execution_options.stream_results` 

433 execution option and invoke :meth:`_engine.Result.yield_per` 

434 automatically at once. Allows equivalent functionality as 

435 is present when using this parameter with the ORM. 

436 

437 .. versionadded:: 1.4.40 

438 

439 .. seealso:: 

440 

441 :ref:`engine_stream_results` - background and examples 

442 on using server side cursors with Core. 

443 

444 :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel` 

445 describing the ORM version of ``yield_per`` 

446 

447 :param schema_translate_map: Available on: :class:`_engine.Connection`, 

448 :class:`_engine.Engine`, :class:`_sql.Executable`. 

449 

450 :param schema_translate_map: Available on: Connection, Engine. 

451 A dictionary mapping schema names to schema names, that will be 

452 applied to the :paramref:`_schema.Table.schema` element of each 

453 :class:`_schema.Table` 

454 encountered when SQL or DDL expression elements 

455 are compiled into strings; the resulting schema name will be 

456 converted based on presence in the map of the original name. 

457 

458 .. versionadded:: 1.1 

459 

460 .. seealso:: 

461 

462 :ref:`schema_translating` 

463 

464 .. seealso:: 

465 

466 :meth:`_engine.Engine.execution_options` 

467 

468 :meth:`.Executable.execution_options` 

469 

470 :meth:`_engine.Connection.get_execution_options` 

471 

472 

473 """ # noqa 

474 c = self._generate_for_options() 

475 c._execution_options = c._execution_options.union(opt) 

476 if self._has_events or self.engine._has_events: 

477 self.dispatch.set_connection_execution_options(c, opt) 

478 self.dialect.set_connection_execution_options(c, opt) 

479 return c 

480 

481 def get_execution_options(self): 

482 """Get the non-SQL options which will take effect during execution. 

483 

484 .. versionadded:: 1.3 

485 

486 .. seealso:: 

487 

488 :meth:`_engine.Connection.execution_options` 

489 """ 

490 return self._execution_options 

491 

492 @property 

493 def closed(self): 

494 """Return True if this connection is closed.""" 

495 

496 # note this is independent for a "branched" connection vs. 

497 # the base 

498 

499 return self._dbapi_connection is None and not self.__can_reconnect 

500 

501 @property 

502 def invalidated(self): 

503 """Return True if this connection was invalidated.""" 

504 

505 # prior to 1.4, "invalid" was stored as a state independent of 

506 # "closed", meaning an invalidated connection could be "closed", 

507 # the _dbapi_connection would be None and closed=True, yet the 

508 # "invalid" flag would stay True. This meant that there were 

509 # three separate states (open/valid, closed/valid, closed/invalid) 

510 # when there is really no reason for that; a connection that's 

511 # "closed" does not need to be "invalid". So the state is now 

512 # represented by the two facts alone. 

513 

514 if self.__branch_from: 

515 return self.__branch_from.invalidated 

516 

517 return self._dbapi_connection is None and not self.closed 

518 

519 @property 

520 def connection(self): 

521 """The underlying DB-API connection managed by this Connection. 

522 

523 This is a SQLAlchemy connection-pool proxied connection 

524 which then has the attribute 

525 :attr:`_pool._ConnectionFairy.dbapi_connection` that refers to the 

526 actual driver connection. 

527 

528 .. seealso:: 

529 

530 

531 :ref:`dbapi_connections` 

532 

533 """ 

534 

535 if self._dbapi_connection is None: 

536 try: 

537 return self._revalidate_connection() 

538 except (exc.PendingRollbackError, exc.ResourceClosedError): 

539 raise 

540 except BaseException as e: 

541 self._handle_dbapi_exception(e, None, None, None, None) 

542 else: 

543 return self._dbapi_connection 

544 

545 def get_isolation_level(self): 

546 """Return the current isolation level assigned to this 

547 :class:`_engine.Connection`. 

548 

549 This will typically be the default isolation level as determined 

550 by the dialect, unless if the 

551 :paramref:`.Connection.execution_options.isolation_level` 

552 feature has been used to alter the isolation level on a 

553 per-:class:`_engine.Connection` basis. 

554 

555 This attribute will typically perform a live SQL operation in order 

556 to procure the current isolation level, so the value returned is the 

557 actual level on the underlying DBAPI connection regardless of how 

558 this state was set. Compare to the 

559 :attr:`_engine.Connection.default_isolation_level` accessor 

560 which returns the dialect-level setting without performing a SQL 

561 query. 

562 

563 .. versionadded:: 0.9.9 

564 

565 .. seealso:: 

566 

567 :attr:`_engine.Connection.default_isolation_level` 

568 - view default level 

569 

570 :paramref:`_sa.create_engine.isolation_level` 

571 - set per :class:`_engine.Engine` isolation level 

572 

573 :paramref:`.Connection.execution_options.isolation_level` 

574 - set per :class:`_engine.Connection` isolation level 

575 

576 """ 

577 try: 

578 return self.dialect.get_isolation_level(self.connection) 

579 except BaseException as e: 

580 self._handle_dbapi_exception(e, None, None, None, None) 

581 

582 @property 

583 def default_isolation_level(self): 

584 """The default isolation level assigned to this 

585 :class:`_engine.Connection`. 

586 

587 This is the isolation level setting that the 

588 :class:`_engine.Connection` 

589 has when first procured via the :meth:`_engine.Engine.connect` method. 

590 This level stays in place until the 

591 :paramref:`.Connection.execution_options.isolation_level` is used 

592 to change the setting on a per-:class:`_engine.Connection` basis. 

593 

594 Unlike :meth:`_engine.Connection.get_isolation_level`, 

595 this attribute is set 

596 ahead of time from the first connection procured by the dialect, 

597 so SQL query is not invoked when this accessor is called. 

598 

599 .. versionadded:: 0.9.9 

600 

601 .. seealso:: 

602 

603 :meth:`_engine.Connection.get_isolation_level` 

604 - view current level 

605 

606 :paramref:`_sa.create_engine.isolation_level` 

607 - set per :class:`_engine.Engine` isolation level 

608 

609 :paramref:`.Connection.execution_options.isolation_level` 

610 - set per :class:`_engine.Connection` isolation level 

611 

612 """ 

613 return self.dialect.default_isolation_level 

614 

615 def _invalid_transaction(self): 

616 if self.invalidated: 

617 raise exc.PendingRollbackError( 

618 "Can't reconnect until invalid %stransaction is rolled " 

619 "back." 

620 % ( 

621 "savepoint " 

622 if self._nested_transaction is not None 

623 else "" 

624 ), 

625 code="8s2b", 

626 ) 

627 else: 

628 assert not self._is_future 

629 raise exc.PendingRollbackError( 

630 "This connection is on an inactive %stransaction. " 

631 "Please rollback() fully before proceeding." 

632 % ( 

633 "savepoint " 

634 if self._nested_transaction is not None 

635 else "" 

636 ), 

637 code="8s2a", 

638 ) 

639 

640 def _revalidate_connection(self): 

641 if self.__branch_from: 

642 return self.__branch_from._revalidate_connection() 

643 if self.__can_reconnect and self.invalidated: 

644 if self._transaction is not None: 

645 self._invalid_transaction() 

646 self._dbapi_connection = self.engine.raw_connection( 

647 _connection=self 

648 ) 

649 return self._dbapi_connection 

650 raise exc.ResourceClosedError("This Connection is closed") 

651 

652 @property 

653 def _still_open_and_dbapi_connection_is_valid(self): 

654 return self._dbapi_connection is not None and getattr( 

655 self._dbapi_connection, "is_valid", False 

656 ) 

657 

658 @property 

659 def info(self): 

660 """Info dictionary associated with the underlying DBAPI connection 

661 referred to by this :class:`_engine.Connection`, allowing user-defined 

662 data to be associated with the connection. 

663 

664 The data here will follow along with the DBAPI connection including 

665 after it is returned to the connection pool and used again 

666 in subsequent instances of :class:`_engine.Connection`. 

667 

668 """ 

669 

670 return self.connection.info 

671 

672 @util.deprecated_20(":meth:`.Connection.connect`") 

673 def connect(self, close_with_result=False): 

674 """Returns a branched version of this :class:`_engine.Connection`. 

675 

676 The :meth:`_engine.Connection.close` method on the returned 

677 :class:`_engine.Connection` can be called and this 

678 :class:`_engine.Connection` will remain open. 

679 

680 This method provides usage symmetry with 

681 :meth:`_engine.Engine.connect`, including for usage 

682 with context managers. 

683 

684 """ 

685 

686 return self._branch() 

687 

688 def invalidate(self, exception=None): 

689 """Invalidate the underlying DBAPI connection associated with 

690 this :class:`_engine.Connection`. 

691 

692 An attempt will be made to close the underlying DBAPI connection 

693 immediately; however if this operation fails, the error is logged 

694 but not raised. The connection is then discarded whether or not 

695 close() succeeded. 

696 

697 Upon the next use (where "use" typically means using the 

698 :meth:`_engine.Connection.execute` method or similar), 

699 this :class:`_engine.Connection` will attempt to 

700 procure a new DBAPI connection using the services of the 

701 :class:`_pool.Pool` as a source of connectivity (e.g. 

702 a "reconnection"). 

703 

704 If a transaction was in progress (e.g. the 

705 :meth:`_engine.Connection.begin` method has been called) when 

706 :meth:`_engine.Connection.invalidate` method is called, at the DBAPI 

707 level all state associated with this transaction is lost, as 

708 the DBAPI connection is closed. The :class:`_engine.Connection` 

709 will not allow a reconnection to proceed until the 

710 :class:`.Transaction` object is ended, by calling the 

711 :meth:`.Transaction.rollback` method; until that point, any attempt at 

712 continuing to use the :class:`_engine.Connection` will raise an 

713 :class:`~sqlalchemy.exc.InvalidRequestError`. 

714 This is to prevent applications from accidentally 

715 continuing an ongoing transactional operations despite the 

716 fact that the transaction has been lost due to an 

717 invalidation. 

718 

719 The :meth:`_engine.Connection.invalidate` method, 

720 just like auto-invalidation, 

721 will at the connection pool level invoke the 

722 :meth:`_events.PoolEvents.invalidate` event. 

723 

724 :param exception: an optional ``Exception`` instance that's the 

725 reason for the invalidation. is passed along to event handlers 

726 and logging functions. 

727 

728 .. seealso:: 

729 

730 :ref:`pool_connection_invalidation` 

731 

732 """ 

733 

734 if self.__branch_from: 

735 return self.__branch_from.invalidate(exception=exception) 

736 

737 if self.invalidated: 

738 return 

739 

740 if self.closed: 

741 raise exc.ResourceClosedError("This Connection is closed") 

742 

743 if self._still_open_and_dbapi_connection_is_valid: 

744 self._dbapi_connection.invalidate(exception) 

745 self._dbapi_connection = None 

746 

747 def detach(self): 

748 """Detach the underlying DB-API connection from its connection pool. 

749 

750 E.g.:: 

751 

752 with engine.connect() as conn: 

753 conn.detach() 

754 conn.execute(text("SET search_path TO schema1, schema2")) 

755 

756 # work with connection 

757 

758 # connection is fully closed (since we used "with:", can 

759 # also call .close()) 

760 

761 This :class:`_engine.Connection` instance will remain usable. 

762 When closed 

763 (or exited from a context manager context as above), 

764 the DB-API connection will be literally closed and not 

765 returned to its originating pool. 

766 

767 This method can be used to insulate the rest of an application 

768 from a modified state on a connection (such as a transaction 

769 isolation level or similar). 

770 

771 """ 

772 

773 self._dbapi_connection.detach() 

774 

775 def _autobegin(self): 

776 self.begin() 

777 

778 def begin(self): 

779 """Begin a transaction and return a transaction handle. 

780 

781 The returned object is an instance of :class:`.Transaction`. 

782 This object represents the "scope" of the transaction, 

783 which completes when either the :meth:`.Transaction.rollback` 

784 or :meth:`.Transaction.commit` method is called. 

785 

786 .. tip:: 

787 

788 The :meth:`_engine.Connection.begin` method is invoked when using 

789 the :meth:`_engine.Engine.begin` context manager method as well. 

790 All documentation that refers to behaviors specific to the 

791 :meth:`_engine.Connection.begin` method also apply to use of the 

792 :meth:`_engine.Engine.begin` method. 

793 

794 Legacy use: nested calls to :meth:`.begin` on the same 

795 :class:`_engine.Connection` will return new :class:`.Transaction` 

796 objects that represent an emulated transaction within the scope of the 

797 enclosing transaction, that is:: 

798 

799 trans = conn.begin() # outermost transaction 

800 trans2 = conn.begin() # "nested" 

801 trans2.commit() # does nothing 

802 trans.commit() # actually commits 

803 

804 Calls to :meth:`.Transaction.commit` only have an effect 

805 when invoked via the outermost :class:`.Transaction` object, though the 

806 :meth:`.Transaction.rollback` method of any of the 

807 :class:`.Transaction` objects will roll back the 

808 transaction. 

809 

810 .. tip:: 

811 

812 The above "nesting" behavior is a legacy behavior specific to 

813 :term:`1.x style` use and will be removed in SQLAlchemy 2.0. For 

814 notes on :term:`2.0 style` use, see 

815 :meth:`_future.Connection.begin`. 

816 

817 

818 .. seealso:: 

819 

820 :meth:`_engine.Connection.begin_nested` - use a SAVEPOINT 

821 

822 :meth:`_engine.Connection.begin_twophase` - 

823 use a two phase /XID transaction 

824 

825 :meth:`_engine.Engine.begin` - context manager available from 

826 :class:`_engine.Engine` 

827 

828 """ 

829 if self._is_future: 

830 assert not self.__branch_from 

831 elif self.__branch_from: 

832 return self.__branch_from.begin() 

833 

834 if self.__in_begin: 

835 # for dialects that emit SQL within the process of 

836 # dialect.do_begin() or dialect.do_begin_twophase(), this 

837 # flag prevents "autobegin" from being emitted within that 

838 # process, while allowing self._transaction to remain at None 

839 # until it's complete. 

840 return 

841 elif self._transaction is None: 

842 self._transaction = RootTransaction(self) 

843 return self._transaction 

844 else: 

845 if self._is_future: 

846 raise exc.InvalidRequestError( 

847 "This connection has already initialized a SQLAlchemy " 

848 "Transaction() object via begin() or autobegin; can't " 

849 "call begin() here unless rollback() or commit() " 

850 "is called first." 

851 ) 

852 else: 

853 return MarkerTransaction(self) 

854 

855 def begin_nested(self): 

856 """Begin a nested transaction (i.e. SAVEPOINT) and return a 

857 transaction handle, assuming an outer transaction is already 

858 established. 

859 

860 Nested transactions require SAVEPOINT support in the 

861 underlying database. Any transaction in the hierarchy may 

862 ``commit`` and ``rollback``, however the outermost transaction 

863 still controls the overall ``commit`` or ``rollback`` of the 

864 transaction of a whole. 

865 

866 The legacy form of :meth:`_engine.Connection.begin_nested` method has 

867 alternate behaviors based on whether or not the 

868 :meth:`_engine.Connection.begin` method was called previously. If 

869 :meth:`_engine.Connection.begin` was not called, then this method will 

870 behave the same as the :meth:`_engine.Connection.begin` method and 

871 return a :class:`.RootTransaction` object that begins and commits a 

872 real transaction - **no savepoint is invoked**. If 

873 :meth:`_engine.Connection.begin` **has** been called, and a 

874 :class:`.RootTransaction` is already established, then this method 

875 returns an instance of :class:`.NestedTransaction` which will invoke 

876 and manage the scope of a SAVEPOINT. 

877 

878 .. tip:: 

879 

880 The above mentioned behavior of 

881 :meth:`_engine.Connection.begin_nested` is a legacy behavior 

882 specific to :term:`1.x style` use. In :term:`2.0 style` use, the 

883 :meth:`_future.Connection.begin_nested` method instead autobegins 

884 the outer transaction that can be committed using 

885 "commit-as-you-go" style; see 

886 :meth:`_future.Connection.begin_nested` for migration details. 

887 

888 .. versionchanged:: 1.4.13 The behavior of 

889 :meth:`_engine.Connection.begin_nested` 

890 as returning a :class:`.RootTransaction` if 

891 :meth:`_engine.Connection.begin` were not called has been restored 

892 as was the case in 1.3.x versions; in previous 1.4.x versions, an 

893 outer transaction would be "autobegun" but would not be committed. 

894 

895 

896 .. seealso:: 

897 

898 :meth:`_engine.Connection.begin` 

899 

900 :ref:`session_begin_nested` - ORM support for SAVEPOINT 

901 

902 """ 

903 if self._is_future: 

904 assert not self.__branch_from 

905 elif self.__branch_from: 

906 return self.__branch_from.begin_nested() 

907 

908 if self._transaction is None: 

909 if not self._is_future: 

910 util.warn_deprecated_20( 

911 "Calling Connection.begin_nested() in 2.0 style use will " 

912 "return a NestedTransaction (SAVEPOINT) in all cases, " 

913 "that will not commit the outer transaction. For code " 

914 "that is cross-compatible between 1.x and 2.0 style use, " 

915 "ensure Connection.begin() is called before calling " 

916 "Connection.begin_nested()." 

917 ) 

918 return self.begin() 

919 else: 

920 self._autobegin() 

921 

922 return NestedTransaction(self) 

923 

924 def begin_twophase(self, xid=None): 

925 """Begin a two-phase or XA transaction and return a transaction 

926 handle. 

927 

928 The returned object is an instance of :class:`.TwoPhaseTransaction`, 

929 which in addition to the methods provided by 

930 :class:`.Transaction`, also provides a 

931 :meth:`~.TwoPhaseTransaction.prepare` method. 

932 

933 :param xid: the two phase transaction id. If not supplied, a 

934 random id will be generated. 

935 

936 .. seealso:: 

937 

938 :meth:`_engine.Connection.begin` 

939 

940 :meth:`_engine.Connection.begin_twophase` 

941 

942 """ 

943 

944 if self.__branch_from: 

945 return self.__branch_from.begin_twophase(xid=xid) 

946 

947 if self._transaction is not None: 

948 raise exc.InvalidRequestError( 

949 "Cannot start a two phase transaction when a transaction " 

950 "is already in progress." 

951 ) 

952 if xid is None: 

953 xid = self.engine.dialect.create_xid() 

954 return TwoPhaseTransaction(self, xid) 

955 

956 def recover_twophase(self): 

957 return self.engine.dialect.do_recover_twophase(self) 

958 

959 def rollback_prepared(self, xid, recover=False): 

960 self.engine.dialect.do_rollback_twophase(self, xid, recover=recover) 

961 

962 def commit_prepared(self, xid, recover=False): 

963 self.engine.dialect.do_commit_twophase(self, xid, recover=recover) 

964 

965 def in_transaction(self): 

966 """Return True if a transaction is in progress.""" 

967 if self.__branch_from is not None: 

968 return self.__branch_from.in_transaction() 

969 

970 return self._transaction is not None and self._transaction.is_active 

971 

972 def in_nested_transaction(self): 

973 """Return True if a transaction is in progress.""" 

974 if self.__branch_from is not None: 

975 return self.__branch_from.in_nested_transaction() 

976 

977 return ( 

978 self._nested_transaction is not None 

979 and self._nested_transaction.is_active 

980 ) 

981 

982 def _is_autocommit_isolation(self): 

983 opt_iso = self._execution_options.get("isolation_level", None) 

984 return bool( 

985 opt_iso == "AUTOCOMMIT" 

986 or ( 

987 opt_iso is None 

988 and getattr(self.engine.dialect, "isolation_level", None) 

989 == "AUTOCOMMIT" 

990 ) 

991 ) 

992 

993 def get_transaction(self): 

994 """Return the current root transaction in progress, if any. 

995 

996 .. versionadded:: 1.4 

997 

998 """ 

999 

1000 if self.__branch_from is not None: 

1001 return self.__branch_from.get_transaction() 

1002 

1003 return self._transaction 

1004 

1005 def get_nested_transaction(self): 

1006 """Return the current nested transaction in progress, if any. 

1007 

1008 .. versionadded:: 1.4 

1009 

1010 """ 

1011 if self.__branch_from is not None: 

1012 

1013 return self.__branch_from.get_nested_transaction() 

1014 

1015 return self._nested_transaction 

1016 

1017 def _begin_impl(self, transaction): 

1018 assert not self.__branch_from 

1019 

1020 if self._echo: 

1021 if self._is_autocommit_isolation(): 

1022 self._log_info( 

1023 "BEGIN (implicit; DBAPI should not BEGIN due to " 

1024 "autocommit mode)" 

1025 ) 

1026 else: 

1027 self._log_info("BEGIN (implicit)") 

1028 

1029 self.__in_begin = True 

1030 

1031 if self._has_events or self.engine._has_events: 

1032 self.dispatch.begin(self) 

1033 

1034 try: 

1035 self.engine.dialect.do_begin(self.connection) 

1036 except BaseException as e: 

1037 self._handle_dbapi_exception(e, None, None, None, None) 

1038 finally: 

1039 self.__in_begin = False 

1040 

1041 def _rollback_impl(self): 

1042 assert not self.__branch_from 

1043 

1044 if self._has_events or self.engine._has_events: 

1045 self.dispatch.rollback(self) 

1046 

1047 if self._still_open_and_dbapi_connection_is_valid: 

1048 if self._echo: 

1049 if self._is_autocommit_isolation(): 

1050 self._log_info( 

1051 "ROLLBACK using DBAPI connection.rollback(), " 

1052 "DBAPI should ignore due to autocommit mode" 

1053 ) 

1054 else: 

1055 self._log_info("ROLLBACK") 

1056 try: 

1057 self.engine.dialect.do_rollback(self.connection) 

1058 except BaseException as e: 

1059 self._handle_dbapi_exception(e, None, None, None, None) 

1060 

1061 def _commit_impl(self, autocommit=False): 

1062 assert not self.__branch_from 

1063 

1064 # AUTOCOMMIT isolation-level is a dialect-specific concept, however 

1065 # if a connection has this set as the isolation level, we can skip 

1066 # the "autocommit" warning as the operation will do "autocommit" 

1067 # in any case 

1068 if autocommit and not self._is_autocommit_isolation(): 

1069 util.warn_deprecated_20( 

1070 "The current statement is being autocommitted using " 

1071 "implicit autocommit, which will be removed in " 

1072 "SQLAlchemy 2.0. " 

1073 "Use the .begin() method of Engine or Connection in order to " 

1074 "use an explicit transaction for DML and DDL statements." 

1075 ) 

1076 

1077 if self._has_events or self.engine._has_events: 

1078 self.dispatch.commit(self) 

1079 

1080 if self._echo: 

1081 if self._is_autocommit_isolation(): 

1082 self._log_info( 

1083 "COMMIT using DBAPI connection.commit(), " 

1084 "DBAPI should ignore due to autocommit mode" 

1085 ) 

1086 else: 

1087 self._log_info("COMMIT") 

1088 try: 

1089 self.engine.dialect.do_commit(self.connection) 

1090 except BaseException as e: 

1091 self._handle_dbapi_exception(e, None, None, None, None) 

1092 

1093 def _savepoint_impl(self, name=None): 

1094 assert not self.__branch_from 

1095 

1096 if self._has_events or self.engine._has_events: 

1097 self.dispatch.savepoint(self, name) 

1098 

1099 if name is None: 

1100 self.__savepoint_seq += 1 

1101 name = "sa_savepoint_%s" % self.__savepoint_seq 

1102 if self._still_open_and_dbapi_connection_is_valid: 

1103 self.engine.dialect.do_savepoint(self, name) 

1104 return name 

1105 

1106 def _rollback_to_savepoint_impl(self, name): 

1107 assert not self.__branch_from 

1108 

1109 if self._has_events or self.engine._has_events: 

1110 self.dispatch.rollback_savepoint(self, name, None) 

1111 

1112 if self._still_open_and_dbapi_connection_is_valid: 

1113 self.engine.dialect.do_rollback_to_savepoint(self, name) 

1114 

1115 def _release_savepoint_impl(self, name): 

1116 assert not self.__branch_from 

1117 

1118 if self._has_events or self.engine._has_events: 

1119 self.dispatch.release_savepoint(self, name, None) 

1120 

1121 if self._still_open_and_dbapi_connection_is_valid: 

1122 self.engine.dialect.do_release_savepoint(self, name) 

1123 

1124 def _begin_twophase_impl(self, transaction): 

1125 assert not self.__branch_from 

1126 

1127 if self._echo: 

1128 self._log_info("BEGIN TWOPHASE (implicit)") 

1129 if self._has_events or self.engine._has_events: 

1130 self.dispatch.begin_twophase(self, transaction.xid) 

1131 

1132 if self._still_open_and_dbapi_connection_is_valid: 

1133 self.__in_begin = True 

1134 try: 

1135 self.engine.dialect.do_begin_twophase(self, transaction.xid) 

1136 except BaseException as e: 

1137 self._handle_dbapi_exception(e, None, None, None, None) 

1138 finally: 

1139 self.__in_begin = False 

1140 

1141 def _prepare_twophase_impl(self, xid): 

1142 assert not self.__branch_from 

1143 

1144 if self._has_events or self.engine._has_events: 

1145 self.dispatch.prepare_twophase(self, xid) 

1146 

1147 if self._still_open_and_dbapi_connection_is_valid: 

1148 assert isinstance(self._transaction, TwoPhaseTransaction) 

1149 try: 

1150 self.engine.dialect.do_prepare_twophase(self, xid) 

1151 except BaseException as e: 

1152 self._handle_dbapi_exception(e, None, None, None, None) 

1153 

1154 def _rollback_twophase_impl(self, xid, is_prepared): 

1155 assert not self.__branch_from 

1156 

1157 if self._has_events or self.engine._has_events: 

1158 self.dispatch.rollback_twophase(self, xid, is_prepared) 

1159 

1160 if self._still_open_and_dbapi_connection_is_valid: 

1161 assert isinstance(self._transaction, TwoPhaseTransaction) 

1162 try: 

1163 self.engine.dialect.do_rollback_twophase( 

1164 self, xid, is_prepared 

1165 ) 

1166 except BaseException as e: 

1167 self._handle_dbapi_exception(e, None, None, None, None) 

1168 

1169 def _commit_twophase_impl(self, xid, is_prepared): 

1170 assert not self.__branch_from 

1171 

1172 if self._has_events or self.engine._has_events: 

1173 self.dispatch.commit_twophase(self, xid, is_prepared) 

1174 

1175 if self._still_open_and_dbapi_connection_is_valid: 

1176 assert isinstance(self._transaction, TwoPhaseTransaction) 

1177 try: 

1178 self.engine.dialect.do_commit_twophase(self, xid, is_prepared) 

1179 except BaseException as e: 

1180 self._handle_dbapi_exception(e, None, None, None, None) 

1181 

1182 def _autorollback(self): 

1183 if self.__branch_from: 

1184 self.__branch_from._autorollback() 

1185 

1186 if not self.in_transaction(): 

1187 self._rollback_impl() 

1188 

1189 def _warn_for_legacy_exec_format(self): 

1190 util.warn_deprecated_20( 

1191 "The connection.execute() method in " 

1192 "SQLAlchemy 2.0 will accept parameters as a single " 

1193 "dictionary or a " 

1194 "single sequence of dictionaries only. " 

1195 "Parameters passed as keyword arguments, tuples or positionally " 

1196 "oriented dictionaries and/or tuples " 

1197 "will no longer be accepted." 

1198 ) 

1199 

1200 def close(self): 

1201 """Close this :class:`_engine.Connection`. 

1202 

1203 This results in a release of the underlying database 

1204 resources, that is, the DBAPI connection referenced 

1205 internally. The DBAPI connection is typically restored 

1206 back to the connection-holding :class:`_pool.Pool` referenced 

1207 by the :class:`_engine.Engine` that produced this 

1208 :class:`_engine.Connection`. Any transactional state present on 

1209 the DBAPI connection is also unconditionally released via 

1210 the DBAPI connection's ``rollback()`` method, regardless 

1211 of any :class:`.Transaction` object that may be 

1212 outstanding with regards to this :class:`_engine.Connection`. 

1213 

1214 After :meth:`_engine.Connection.close` is called, the 

1215 :class:`_engine.Connection` is permanently in a closed state, 

1216 and will allow no further operations. 

1217 

1218 """ 

1219 

1220 if self.__branch_from: 

1221 assert not self._is_future 

1222 util.warn_deprecated_20( 

1223 "The .close() method on a so-called 'branched' connection is " 

1224 "deprecated as of 1.4, as are 'branched' connections overall, " 

1225 "and will be removed in a future release. If this is a " 

1226 "default-handling function, don't close the connection." 

1227 ) 

1228 self._dbapi_connection = None 

1229 self.__can_reconnect = False 

1230 return 

1231 

1232 if self._transaction: 

1233 self._transaction.close() 

1234 skip_reset = True 

1235 else: 

1236 skip_reset = False 

1237 

1238 if self._dbapi_connection is not None: 

1239 conn = self._dbapi_connection 

1240 

1241 # as we just closed the transaction, close the connection 

1242 # pool connection without doing an additional reset 

1243 if skip_reset: 

1244 conn._close_special(transaction_reset=True) 

1245 else: 

1246 conn.close() 

1247 

1248 # There is a slight chance that conn.close() may have 

1249 # triggered an invalidation here in which case 

1250 # _dbapi_connection would already be None, however usually 

1251 # it will be non-None here and in a "closed" state. 

1252 self._dbapi_connection = None 

1253 self.__can_reconnect = False 

1254 

1255 def scalar(self, object_, *multiparams, **params): 

1256 """Executes and returns the first column of the first row. 

1257 

1258 The underlying result/cursor is closed after execution. 

1259 

1260 """ 

1261 

1262 return self.execute(object_, *multiparams, **params).scalar() 

1263 

1264 def scalars(self, object_, *multiparams, **params): 

1265 """Executes and returns a scalar result set, which yields scalar values 

1266 from the first column of each row. 

1267 

1268 This method is equivalent to calling :meth:`_engine.Connection.execute` 

1269 to receive a :class:`_result.Result` object, then invoking the 

1270 :meth:`_result.Result.scalars` method to produce a 

1271 :class:`_result.ScalarResult` instance. 

1272 

1273 :return: a :class:`_result.ScalarResult` 

1274 

1275 .. versionadded:: 1.4.24 

1276 

1277 """ 

1278 

1279 return self.execute(object_, *multiparams, **params).scalars() 

1280 

1281 def execute(self, statement, *multiparams, **params): 

1282 r"""Executes a SQL statement construct and returns a 

1283 :class:`_engine.CursorResult`. 

1284 

1285 :param statement: The statement to be executed. May be 

1286 one of: 

1287 

1288 * a plain string (deprecated) 

1289 * any :class:`_expression.ClauseElement` construct that is also 

1290 a subclass of :class:`.Executable`, such as a 

1291 :func:`_expression.select` construct 

1292 * a :class:`.FunctionElement`, such as that generated 

1293 by :data:`.func`, will be automatically wrapped in 

1294 a SELECT statement, which is then executed. 

1295 * a :class:`.DDLElement` object 

1296 * a :class:`.DefaultGenerator` object 

1297 * a :class:`.Compiled` object 

1298 

1299 .. deprecated:: 2.0 passing a string to 

1300 :meth:`_engine.Connection.execute` is 

1301 deprecated and will be removed in version 2.0. Use the 

1302 :func:`_expression.text` construct with 

1303 :meth:`_engine.Connection.execute`, or the 

1304 :meth:`_engine.Connection.exec_driver_sql` 

1305 method to invoke a driver-level 

1306 SQL string. 

1307 

1308 :param \*multiparams/\**params: represent bound parameter 

1309 values to be used in the execution. Typically, 

1310 the format is either a collection of one or more 

1311 dictionaries passed to \*multiparams:: 

1312 

1313 conn.execute( 

1314 table.insert(), 

1315 {"id":1, "value":"v1"}, 

1316 {"id":2, "value":"v2"} 

1317 ) 

1318 

1319 ...or individual key/values interpreted by \**params:: 

1320 

1321 conn.execute( 

1322 table.insert(), id=1, value="v1" 

1323 ) 

1324 

1325 In the case that a plain SQL string is passed, and the underlying 

1326 DBAPI accepts positional bind parameters, a collection of tuples 

1327 or individual values in \*multiparams may be passed:: 

1328 

1329 conn.execute( 

1330 "INSERT INTO table (id, value) VALUES (?, ?)", 

1331 (1, "v1"), (2, "v2") 

1332 ) 

1333 

1334 conn.execute( 

1335 "INSERT INTO table (id, value) VALUES (?, ?)", 

1336 1, "v1" 

1337 ) 

1338 

1339 Note above, the usage of a question mark "?" or other 

1340 symbol is contingent upon the "paramstyle" accepted by the DBAPI 

1341 in use, which may be any of "qmark", "named", "pyformat", "format", 

1342 "numeric". See `pep-249 

1343 <https://www.python.org/dev/peps/pep-0249/>`_ for details on 

1344 paramstyle. 

1345 

1346 To execute a textual SQL statement which uses bound parameters in a 

1347 DBAPI-agnostic way, use the :func:`_expression.text` construct. 

1348 

1349 .. deprecated:: 2.0 use of tuple or scalar positional parameters 

1350 is deprecated. All params should be dicts or sequences of dicts. 

1351 Use :meth:`.exec_driver_sql` to execute a plain string with 

1352 tuple or scalar positional parameters. 

1353 

1354 """ 

1355 

1356 if isinstance(statement, util.string_types): 

1357 util.warn_deprecated_20( 

1358 "Passing a string to Connection.execute() is " 

1359 "deprecated and will be removed in version 2.0. Use the " 

1360 "text() construct, " 

1361 "or the Connection.exec_driver_sql() method to invoke a " 

1362 "driver-level SQL string." 

1363 ) 

1364 

1365 return self._exec_driver_sql( 

1366 statement, 

1367 multiparams, 

1368 params, 

1369 _EMPTY_EXECUTION_OPTS, 

1370 future=False, 

1371 ) 

1372 

1373 try: 

1374 meth = statement._execute_on_connection 

1375 except AttributeError as err: 

1376 util.raise_( 

1377 exc.ObjectNotExecutableError(statement), replace_context=err 

1378 ) 

1379 else: 

1380 return meth(self, multiparams, params, _EMPTY_EXECUTION_OPTS) 

1381 

1382 def _execute_function(self, func, multiparams, params, execution_options): 

1383 """Execute a sql.FunctionElement object.""" 

1384 

1385 return self._execute_clauseelement( 

1386 func.select(), multiparams, params, execution_options 

1387 ) 

1388 

1389 def _execute_default( 

1390 self, 

1391 default, 

1392 multiparams, 

1393 params, 

1394 # migrate is calling this directly :( 

1395 execution_options=_EMPTY_EXECUTION_OPTS, 

1396 ): 

1397 """Execute a schema.ColumnDefault object.""" 

1398 

1399 execution_options = self._execution_options.merge_with( 

1400 execution_options 

1401 ) 

1402 

1403 distilled_parameters = _distill_params(self, multiparams, params) 

1404 

1405 if self._has_events or self.engine._has_events: 

1406 ( 

1407 default, 

1408 distilled_params, 

1409 event_multiparams, 

1410 event_params, 

1411 ) = self._invoke_before_exec_event( 

1412 default, distilled_parameters, execution_options 

1413 ) 

1414 

1415 try: 

1416 conn = self._dbapi_connection 

1417 if conn is None: 

1418 conn = self._revalidate_connection() 

1419 

1420 dialect = self.dialect 

1421 ctx = dialect.execution_ctx_cls._init_default( 

1422 dialect, self, conn, execution_options 

1423 ) 

1424 except (exc.PendingRollbackError, exc.ResourceClosedError): 

1425 raise 

1426 except BaseException as e: 

1427 self._handle_dbapi_exception(e, None, None, None, None) 

1428 

1429 ret = ctx._exec_default(None, default, None) 

1430 if self.should_close_with_result: 

1431 self.close() 

1432 

1433 if self._has_events or self.engine._has_events: 

1434 self.dispatch.after_execute( 

1435 self, 

1436 default, 

1437 event_multiparams, 

1438 event_params, 

1439 execution_options, 

1440 ret, 

1441 ) 

1442 

1443 return ret 

1444 

1445 def _execute_ddl(self, ddl, multiparams, params, execution_options): 

1446 """Execute a schema.DDL object.""" 

1447 

1448 execution_options = ddl._execution_options.merge_with( 

1449 self._execution_options, execution_options 

1450 ) 

1451 

1452 distilled_parameters = _distill_params(self, multiparams, params) 

1453 

1454 if self._has_events or self.engine._has_events: 

1455 ( 

1456 ddl, 

1457 distilled_params, 

1458 event_multiparams, 

1459 event_params, 

1460 ) = self._invoke_before_exec_event( 

1461 ddl, distilled_parameters, execution_options 

1462 ) 

1463 

1464 exec_opts = self._execution_options.merge_with(execution_options) 

1465 schema_translate_map = exec_opts.get("schema_translate_map", None) 

1466 

1467 dialect = self.dialect 

1468 

1469 compiled = ddl.compile( 

1470 dialect=dialect, schema_translate_map=schema_translate_map 

1471 ) 

1472 ret = self._execute_context( 

1473 dialect, 

1474 dialect.execution_ctx_cls._init_ddl, 

1475 compiled, 

1476 None, 

1477 execution_options, 

1478 compiled, 

1479 ) 

1480 if self._has_events or self.engine._has_events: 

1481 self.dispatch.after_execute( 

1482 self, 

1483 ddl, 

1484 event_multiparams, 

1485 event_params, 

1486 execution_options, 

1487 ret, 

1488 ) 

1489 return ret 

1490 

1491 def _invoke_before_exec_event( 

1492 self, elem, distilled_params, execution_options 

1493 ): 

1494 

1495 if len(distilled_params) == 1: 

1496 event_multiparams, event_params = [], distilled_params[0] 

1497 else: 

1498 event_multiparams, event_params = distilled_params, {} 

1499 

1500 for fn in self.dispatch.before_execute: 

1501 elem, event_multiparams, event_params = fn( 

1502 self, 

1503 elem, 

1504 event_multiparams, 

1505 event_params, 

1506 execution_options, 

1507 ) 

1508 

1509 if event_multiparams: 

1510 distilled_params = list(event_multiparams) 

1511 if event_params: 

1512 raise exc.InvalidRequestError( 

1513 "Event handler can't return non-empty multiparams " 

1514 "and params at the same time" 

1515 ) 

1516 elif event_params: 

1517 distilled_params = [event_params] 

1518 else: 

1519 distilled_params = [] 

1520 

1521 return elem, distilled_params, event_multiparams, event_params 

1522 

1523 def _execute_clauseelement( 

1524 self, elem, multiparams, params, execution_options 

1525 ): 

1526 """Execute a sql.ClauseElement object.""" 

1527 

1528 execution_options = elem._execution_options.merge_with( 

1529 self._execution_options, execution_options 

1530 ) 

1531 

1532 distilled_params = _distill_params(self, multiparams, params) 

1533 

1534 has_events = self._has_events or self.engine._has_events 

1535 if has_events: 

1536 ( 

1537 elem, 

1538 distilled_params, 

1539 event_multiparams, 

1540 event_params, 

1541 ) = self._invoke_before_exec_event( 

1542 elem, distilled_params, execution_options 

1543 ) 

1544 

1545 if distilled_params: 

1546 # ensure we don't retain a link to the view object for keys() 

1547 # which links to the values, which we don't want to cache 

1548 keys = sorted(distilled_params[0]) 

1549 for_executemany = len(distilled_params) > 1 

1550 else: 

1551 keys = [] 

1552 for_executemany = False 

1553 

1554 dialect = self.dialect 

1555 

1556 schema_translate_map = execution_options.get( 

1557 "schema_translate_map", None 

1558 ) 

1559 

1560 compiled_cache = execution_options.get( 

1561 "compiled_cache", self.engine._compiled_cache 

1562 ) 

1563 

1564 compiled_sql, extracted_params, cache_hit = elem._compile_w_cache( 

1565 dialect=dialect, 

1566 compiled_cache=compiled_cache, 

1567 column_keys=keys, 

1568 for_executemany=for_executemany, 

1569 schema_translate_map=schema_translate_map, 

1570 linting=self.dialect.compiler_linting | compiler.WARN_LINTING, 

1571 ) 

1572 ret = self._execute_context( 

1573 dialect, 

1574 dialect.execution_ctx_cls._init_compiled, 

1575 compiled_sql, 

1576 distilled_params, 

1577 execution_options, 

1578 compiled_sql, 

1579 distilled_params, 

1580 elem, 

1581 extracted_params, 

1582 cache_hit=cache_hit, 

1583 ) 

1584 if has_events: 

1585 self.dispatch.after_execute( 

1586 self, 

1587 elem, 

1588 event_multiparams, 

1589 event_params, 

1590 execution_options, 

1591 ret, 

1592 ) 

1593 return ret 

1594 

1595 def _execute_compiled( 

1596 self, 

1597 compiled, 

1598 multiparams, 

1599 params, 

1600 execution_options=_EMPTY_EXECUTION_OPTS, 

1601 ): 

1602 """Execute a sql.Compiled object. 

1603 

1604 TODO: why do we have this? likely deprecate or remove 

1605 

1606 """ 

1607 

1608 execution_options = compiled.execution_options.merge_with( 

1609 self._execution_options, execution_options 

1610 ) 

1611 distilled_parameters = _distill_params(self, multiparams, params) 

1612 

1613 if self._has_events or self.engine._has_events: 

1614 ( 

1615 compiled, 

1616 distilled_params, 

1617 event_multiparams, 

1618 event_params, 

1619 ) = self._invoke_before_exec_event( 

1620 compiled, distilled_parameters, execution_options 

1621 ) 

1622 

1623 dialect = self.dialect 

1624 

1625 ret = self._execute_context( 

1626 dialect, 

1627 dialect.execution_ctx_cls._init_compiled, 

1628 compiled, 

1629 distilled_parameters, 

1630 execution_options, 

1631 compiled, 

1632 distilled_parameters, 

1633 None, 

1634 None, 

1635 ) 

1636 if self._has_events or self.engine._has_events: 

1637 self.dispatch.after_execute( 

1638 self, 

1639 compiled, 

1640 event_multiparams, 

1641 event_params, 

1642 execution_options, 

1643 ret, 

1644 ) 

1645 return ret 

1646 

1647 def _exec_driver_sql( 

1648 self, statement, multiparams, params, execution_options, future 

1649 ): 

1650 

1651 execution_options = self._execution_options.merge_with( 

1652 execution_options 

1653 ) 

1654 

1655 distilled_parameters = _distill_params(self, multiparams, params) 

1656 

1657 if not future: 

1658 if self._has_events or self.engine._has_events: 

1659 ( 

1660 statement, 

1661 distilled_params, 

1662 event_multiparams, 

1663 event_params, 

1664 ) = self._invoke_before_exec_event( 

1665 statement, distilled_parameters, execution_options 

1666 ) 

1667 

1668 dialect = self.dialect 

1669 ret = self._execute_context( 

1670 dialect, 

1671 dialect.execution_ctx_cls._init_statement, 

1672 statement, 

1673 distilled_parameters, 

1674 execution_options, 

1675 statement, 

1676 distilled_parameters, 

1677 ) 

1678 

1679 if not future: 

1680 if self._has_events or self.engine._has_events: 

1681 self.dispatch.after_execute( 

1682 self, 

1683 statement, 

1684 event_multiparams, 

1685 event_params, 

1686 execution_options, 

1687 ret, 

1688 ) 

1689 return ret 

1690 

1691 def _execute_20( 

1692 self, 

1693 statement, 

1694 parameters=None, 

1695 execution_options=_EMPTY_EXECUTION_OPTS, 

1696 ): 

1697 args_10style, kwargs_10style = _distill_params_20(parameters) 

1698 try: 

1699 meth = statement._execute_on_connection 

1700 except AttributeError as err: 

1701 util.raise_( 

1702 exc.ObjectNotExecutableError(statement), replace_context=err 

1703 ) 

1704 else: 

1705 return meth(self, args_10style, kwargs_10style, execution_options) 

1706 

1707 def exec_driver_sql( 

1708 self, statement, parameters=None, execution_options=None 

1709 ): 

1710 r"""Executes a SQL statement construct and returns a 

1711 :class:`_engine.CursorResult`. 

1712 

1713 :param statement: The statement str to be executed. Bound parameters 

1714 must use the underlying DBAPI's paramstyle, such as "qmark", 

1715 "pyformat", "format", etc. 

1716 

1717 :param parameters: represent bound parameter values to be used in the 

1718 execution. The format is one of: a dictionary of named parameters, 

1719 a tuple of positional parameters, or a list containing either 

1720 dictionaries or tuples for multiple-execute support. 

1721 

1722 E.g. multiple dictionaries:: 

1723 

1724 

1725 conn.exec_driver_sql( 

1726 "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)", 

1727 [{"id":1, "value":"v1"}, {"id":2, "value":"v2"}] 

1728 ) 

1729 

1730 Single dictionary:: 

1731 

1732 conn.exec_driver_sql( 

1733 "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)", 

1734 dict(id=1, value="v1") 

1735 ) 

1736 

1737 Single tuple:: 

1738 

1739 conn.exec_driver_sql( 

1740 "INSERT INTO table (id, value) VALUES (?, ?)", 

1741 (1, 'v1') 

1742 ) 

1743 

1744 .. note:: The :meth:`_engine.Connection.exec_driver_sql` method does 

1745 not participate in the 

1746 :meth:`_events.ConnectionEvents.before_execute` and 

1747 :meth:`_events.ConnectionEvents.after_execute` events. To 

1748 intercept calls to :meth:`_engine.Connection.exec_driver_sql`, use 

1749 :meth:`_events.ConnectionEvents.before_cursor_execute` and 

1750 :meth:`_events.ConnectionEvents.after_cursor_execute`. 

1751 

1752 .. seealso:: 

1753 

1754 :pep:`249` 

1755 

1756 """ 

1757 

1758 args_10style, kwargs_10style = _distill_params_20(parameters) 

1759 

1760 return self._exec_driver_sql( 

1761 statement, 

1762 args_10style, 

1763 kwargs_10style, 

1764 execution_options, 

1765 future=True, 

1766 ) 

1767 

1768 def _execute_context( 

1769 self, 

1770 dialect, 

1771 constructor, 

1772 statement, 

1773 parameters, 

1774 execution_options, 

1775 *args, 

1776 **kw 

1777 ): 

1778 """Create an :class:`.ExecutionContext` and execute, returning 

1779 a :class:`_engine.CursorResult`.""" 

1780 

1781 branched = self 

1782 if self.__branch_from: 

1783 # if this is a "branched" connection, do everything in terms 

1784 # of the "root" connection, *except* for .close(), which is 

1785 # the only feature that branching provides 

1786 self = self.__branch_from 

1787 

1788 if execution_options: 

1789 yp = execution_options.get("yield_per", None) 

1790 if yp: 

1791 execution_options = execution_options.union( 

1792 {"stream_results": True, "max_row_buffer": yp} 

1793 ) 

1794 

1795 try: 

1796 conn = self._dbapi_connection 

1797 if conn is None: 

1798 conn = self._revalidate_connection() 

1799 

1800 context = constructor( 

1801 dialect, self, conn, execution_options, *args, **kw 

1802 ) 

1803 except (exc.PendingRollbackError, exc.ResourceClosedError): 

1804 raise 

1805 except BaseException as e: 

1806 self._handle_dbapi_exception( 

1807 e, util.text_type(statement), parameters, None, None 

1808 ) 

1809 

1810 if ( 

1811 self._transaction 

1812 and not self._transaction.is_active 

1813 or ( 

1814 self._nested_transaction 

1815 and not self._nested_transaction.is_active 

1816 ) 

1817 ): 

1818 self._invalid_transaction() 

1819 

1820 elif self._trans_context_manager: 

1821 TransactionalContext._trans_ctx_check(self) 

1822 

1823 if self._is_future and self._transaction is None: 

1824 self._autobegin() 

1825 

1826 context.pre_exec() 

1827 

1828 if dialect.use_setinputsizes: 

1829 context._set_input_sizes() 

1830 

1831 cursor, statement, parameters = ( 

1832 context.cursor, 

1833 context.statement, 

1834 context.parameters, 

1835 ) 

1836 

1837 if not context.executemany: 

1838 parameters = parameters[0] 

1839 

1840 if self._has_events or self.engine._has_events: 

1841 for fn in self.dispatch.before_cursor_execute: 

1842 statement, parameters = fn( 

1843 self, 

1844 cursor, 

1845 statement, 

1846 parameters, 

1847 context, 

1848 context.executemany, 

1849 ) 

1850 

1851 if self._echo: 

1852 

1853 self._log_info(statement) 

1854 

1855 stats = context._get_cache_stats() 

1856 

1857 if not self.engine.hide_parameters: 

1858 self._log_info( 

1859 "[%s] %r", 

1860 stats, 

1861 sql_util._repr_params( 

1862 parameters, batches=10, ismulti=context.executemany 

1863 ), 

1864 ) 

1865 else: 

1866 self._log_info( 

1867 "[%s] [SQL parameters hidden due to hide_parameters=True]" 

1868 % (stats,) 

1869 ) 

1870 

1871 evt_handled = False 

1872 try: 

1873 if context.executemany: 

1874 if self.dialect._has_events: 

1875 for fn in self.dialect.dispatch.do_executemany: 

1876 if fn(cursor, statement, parameters, context): 

1877 evt_handled = True 

1878 break 

1879 if not evt_handled: 

1880 self.dialect.do_executemany( 

1881 cursor, statement, parameters, context 

1882 ) 

1883 elif not parameters and context.no_parameters: 

1884 if self.dialect._has_events: 

1885 for fn in self.dialect.dispatch.do_execute_no_params: 

1886 if fn(cursor, statement, context): 

1887 evt_handled = True 

1888 break 

1889 if not evt_handled: 

1890 self.dialect.do_execute_no_params( 

1891 cursor, statement, context 

1892 ) 

1893 else: 

1894 if self.dialect._has_events: 

1895 for fn in self.dialect.dispatch.do_execute: 

1896 if fn(cursor, statement, parameters, context): 

1897 evt_handled = True 

1898 break 

1899 if not evt_handled: 

1900 self.dialect.do_execute( 

1901 cursor, statement, parameters, context 

1902 ) 

1903 

1904 if self._has_events or self.engine._has_events: 

1905 self.dispatch.after_cursor_execute( 

1906 self, 

1907 cursor, 

1908 statement, 

1909 parameters, 

1910 context, 

1911 context.executemany, 

1912 ) 

1913 

1914 context.post_exec() 

1915 

1916 result = context._setup_result_proxy() 

1917 

1918 if not self._is_future: 

1919 should_close_with_result = branched.should_close_with_result 

1920 

1921 if not result._soft_closed and should_close_with_result: 

1922 result._autoclose_connection = True 

1923 

1924 if ( 

1925 # usually we're in a transaction so avoid relatively 

1926 # expensive / legacy should_autocommit call 

1927 self._transaction is None 

1928 and context.should_autocommit 

1929 ): 

1930 self._commit_impl(autocommit=True) 

1931 

1932 # for "connectionless" execution, we have to close this 

1933 # Connection after the statement is complete. 

1934 # legacy stuff. 

1935 if should_close_with_result and context._soft_closed: 

1936 assert not self._is_future 

1937 

1938 # CursorResult already exhausted rows / has no rows. 

1939 # close us now 

1940 branched.close() 

1941 

1942 except BaseException as e: 

1943 self._handle_dbapi_exception( 

1944 e, statement, parameters, cursor, context 

1945 ) 

1946 

1947 return result 

1948 

1949 def _cursor_execute(self, cursor, statement, parameters, context=None): 

1950 """Execute a statement + params on the given cursor. 

1951 

1952 Adds appropriate logging and exception handling. 

1953 

1954 This method is used by DefaultDialect for special-case 

1955 executions, such as for sequences and column defaults. 

1956 The path of statement execution in the majority of cases 

1957 terminates at _execute_context(). 

1958 

1959 """ 

1960 if self._has_events or self.engine._has_events: 

1961 for fn in self.dispatch.before_cursor_execute: 

1962 statement, parameters = fn( 

1963 self, cursor, statement, parameters, context, False 

1964 ) 

1965 

1966 if self._echo: 

1967 self._log_info(statement) 

1968 self._log_info("[raw sql] %r", parameters) 

1969 try: 

1970 for fn in ( 

1971 () 

1972 if not self.dialect._has_events 

1973 else self.dialect.dispatch.do_execute 

1974 ): 

1975 if fn(cursor, statement, parameters, context): 

1976 break 

1977 else: 

1978 self.dialect.do_execute(cursor, statement, parameters, context) 

1979 except BaseException as e: 

1980 self._handle_dbapi_exception( 

1981 e, statement, parameters, cursor, context 

1982 ) 

1983 

1984 if self._has_events or self.engine._has_events: 

1985 self.dispatch.after_cursor_execute( 

1986 self, cursor, statement, parameters, context, False 

1987 ) 

1988 

1989 def _safe_close_cursor(self, cursor): 

1990 """Close the given cursor, catching exceptions 

1991 and turning into log warnings. 

1992 

1993 """ 

1994 try: 

1995 cursor.close() 

1996 except Exception: 

1997 # log the error through the connection pool's logger. 

1998 self.engine.pool.logger.error( 

1999 "Error closing cursor", exc_info=True 

2000 ) 

2001 

2002 _reentrant_error = False 

2003 _is_disconnect = False 

2004 

2005 def _handle_dbapi_exception( 

2006 self, e, statement, parameters, cursor, context 

2007 ): 

2008 exc_info = sys.exc_info() 

2009 

2010 is_exit_exception = util.is_exit_exception(e) 

2011 

2012 if not self._is_disconnect: 

2013 self._is_disconnect = ( 

2014 isinstance(e, self.dialect.dbapi.Error) 

2015 and not self.closed 

2016 and self.dialect.is_disconnect( 

2017 e, 

2018 self._dbapi_connection if not self.invalidated else None, 

2019 cursor, 

2020 ) 

2021 ) or (is_exit_exception and not self.closed) 

2022 

2023 invalidate_pool_on_disconnect = not is_exit_exception 

2024 

2025 if self._reentrant_error: 

2026 util.raise_( 

2027 exc.DBAPIError.instance( 

2028 statement, 

2029 parameters, 

2030 e, 

2031 self.dialect.dbapi.Error, 

2032 hide_parameters=self.engine.hide_parameters, 

2033 dialect=self.dialect, 

2034 ismulti=context.executemany 

2035 if context is not None 

2036 else None, 

2037 ), 

2038 with_traceback=exc_info[2], 

2039 from_=e, 

2040 ) 

2041 self._reentrant_error = True 

2042 try: 

2043 # non-DBAPI error - if we already got a context, 

2044 # or there's no string statement, don't wrap it 

2045 should_wrap = isinstance(e, self.dialect.dbapi.Error) or ( 

2046 statement is not None 

2047 and context is None 

2048 and not is_exit_exception 

2049 ) 

2050 

2051 if should_wrap: 

2052 sqlalchemy_exception = exc.DBAPIError.instance( 

2053 statement, 

2054 parameters, 

2055 e, 

2056 self.dialect.dbapi.Error, 

2057 hide_parameters=self.engine.hide_parameters, 

2058 connection_invalidated=self._is_disconnect, 

2059 dialect=self.dialect, 

2060 ismulti=context.executemany 

2061 if context is not None 

2062 else None, 

2063 ) 

2064 else: 

2065 sqlalchemy_exception = None 

2066 

2067 newraise = None 

2068 

2069 if ( 

2070 self._has_events or self.engine._has_events 

2071 ) and not self._execution_options.get( 

2072 "skip_user_error_events", False 

2073 ): 

2074 ctx = ExceptionContextImpl( 

2075 e, 

2076 sqlalchemy_exception, 

2077 self.engine, 

2078 self, 

2079 cursor, 

2080 statement, 

2081 parameters, 

2082 context, 

2083 self._is_disconnect, 

2084 invalidate_pool_on_disconnect, 

2085 ) 

2086 

2087 for fn in self.dispatch.handle_error: 

2088 try: 

2089 # handler returns an exception; 

2090 # call next handler in a chain 

2091 per_fn = fn(ctx) 

2092 if per_fn is not None: 

2093 ctx.chained_exception = newraise = per_fn 

2094 except Exception as _raised: 

2095 # handler raises an exception - stop processing 

2096 newraise = _raised 

2097 break 

2098 

2099 if self._is_disconnect != ctx.is_disconnect: 

2100 self._is_disconnect = ctx.is_disconnect 

2101 if sqlalchemy_exception: 

2102 sqlalchemy_exception.connection_invalidated = ( 

2103 ctx.is_disconnect 

2104 ) 

2105 

2106 # set up potentially user-defined value for 

2107 # invalidate pool. 

2108 invalidate_pool_on_disconnect = ( 

2109 ctx.invalidate_pool_on_disconnect 

2110 ) 

2111 

2112 if should_wrap and context: 

2113 context.handle_dbapi_exception(e) 

2114 

2115 if not self._is_disconnect: 

2116 if cursor: 

2117 self._safe_close_cursor(cursor) 

2118 with util.safe_reraise(warn_only=True): 

2119 self._autorollback() 

2120 

2121 if newraise: 

2122 util.raise_(newraise, with_traceback=exc_info[2], from_=e) 

2123 elif should_wrap: 

2124 util.raise_( 

2125 sqlalchemy_exception, with_traceback=exc_info[2], from_=e 

2126 ) 

2127 else: 

2128 util.raise_(exc_info[1], with_traceback=exc_info[2]) 

2129 

2130 finally: 

2131 del self._reentrant_error 

2132 if self._is_disconnect: 

2133 del self._is_disconnect 

2134 if not self.invalidated: 

2135 dbapi_conn_wrapper = self._dbapi_connection 

2136 if invalidate_pool_on_disconnect: 

2137 self.engine.pool._invalidate(dbapi_conn_wrapper, e) 

2138 self.invalidate(e) 

2139 if self.should_close_with_result: 

2140 assert not self._is_future 

2141 self.close() 

2142 

2143 @classmethod 

2144 def _handle_dbapi_exception_noconnection(cls, e, dialect, engine): 

2145 exc_info = sys.exc_info() 

2146 

2147 is_disconnect = dialect.is_disconnect(e, None, None) 

2148 

2149 should_wrap = isinstance(e, dialect.dbapi.Error) 

2150 

2151 if should_wrap: 

2152 sqlalchemy_exception = exc.DBAPIError.instance( 

2153 None, 

2154 None, 

2155 e, 

2156 dialect.dbapi.Error, 

2157 hide_parameters=engine.hide_parameters, 

2158 connection_invalidated=is_disconnect, 

2159 ) 

2160 else: 

2161 sqlalchemy_exception = None 

2162 

2163 newraise = None 

2164 

2165 if engine._has_events: 

2166 ctx = ExceptionContextImpl( 

2167 e, 

2168 sqlalchemy_exception, 

2169 engine, 

2170 None, 

2171 None, 

2172 None, 

2173 None, 

2174 None, 

2175 is_disconnect, 

2176 True, 

2177 ) 

2178 for fn in engine.dispatch.handle_error: 

2179 try: 

2180 # handler returns an exception; 

2181 # call next handler in a chain 

2182 per_fn = fn(ctx) 

2183 if per_fn is not None: 

2184 ctx.chained_exception = newraise = per_fn 

2185 except Exception as _raised: 

2186 # handler raises an exception - stop processing 

2187 newraise = _raised 

2188 break 

2189 

2190 if sqlalchemy_exception and is_disconnect != ctx.is_disconnect: 

2191 sqlalchemy_exception.connection_invalidated = ( 

2192 is_disconnect 

2193 ) = ctx.is_disconnect 

2194 

2195 if newraise: 

2196 util.raise_(newraise, with_traceback=exc_info[2], from_=e) 

2197 elif should_wrap: 

2198 util.raise_( 

2199 sqlalchemy_exception, with_traceback=exc_info[2], from_=e 

2200 ) 

2201 else: 

2202 util.raise_(exc_info[1], with_traceback=exc_info[2]) 

2203 

2204 def _run_ddl_visitor(self, visitorcallable, element, **kwargs): 

2205 """run a DDL visitor. 

2206 

2207 This method is only here so that the MockConnection can change the 

2208 options given to the visitor so that "checkfirst" is skipped. 

2209 

2210 """ 

2211 visitorcallable(self.dialect, self, **kwargs).traverse_single(element) 

2212 

2213 @util.deprecated( 

2214 "1.4", 

2215 "The :meth:`_engine.Connection.transaction` " 

2216 "method is deprecated and will be " 

2217 "removed in a future release. Use the :meth:`_engine.Engine.begin` " 

2218 "context manager instead.", 

2219 ) 

2220 def transaction(self, callable_, *args, **kwargs): 

2221 r"""Execute the given function within a transaction boundary. 

2222 

2223 The function is passed this :class:`_engine.Connection` 

2224 as the first argument, followed by the given \*args and \**kwargs, 

2225 e.g.:: 

2226 

2227 def do_something(conn, x, y): 

2228 conn.execute(text("some statement"), {'x':x, 'y':y}) 

2229 

2230 conn.transaction(do_something, 5, 10) 

2231 

2232 The operations inside the function are all invoked within the 

2233 context of a single :class:`.Transaction`. 

2234 Upon success, the transaction is committed. If an 

2235 exception is raised, the transaction is rolled back 

2236 before propagating the exception. 

2237 

2238 .. note:: 

2239 

2240 The :meth:`.transaction` method is superseded by 

2241 the usage of the Python ``with:`` statement, which can 

2242 be used with :meth:`_engine.Connection.begin`:: 

2243 

2244 with conn.begin(): 

2245 conn.execute(text("some statement"), {'x':5, 'y':10}) 

2246 

2247 As well as with :meth:`_engine.Engine.begin`:: 

2248 

2249 with engine.begin() as conn: 

2250 conn.execute(text("some statement"), {'x':5, 'y':10}) 

2251 

2252 .. seealso:: 

2253 

2254 :meth:`_engine.Engine.begin` - engine-level transactional 

2255 context 

2256 

2257 :meth:`_engine.Engine.transaction` - engine-level version of 

2258 :meth:`_engine.Connection.transaction` 

2259 

2260 """ 

2261 

2262 kwargs["_sa_skip_warning"] = True 

2263 trans = self.begin() 

2264 try: 

2265 ret = self.run_callable(callable_, *args, **kwargs) 

2266 trans.commit() 

2267 return ret 

2268 except: 

2269 with util.safe_reraise(): 

2270 trans.rollback() 

2271 

2272 @util.deprecated( 

2273 "1.4", 

2274 "The :meth:`_engine.Connection.run_callable` " 

2275 "method is deprecated and will " 

2276 "be removed in a future release. Invoke the callable function " 

2277 "directly, passing the Connection.", 

2278 ) 

2279 def run_callable(self, callable_, *args, **kwargs): 

2280 r"""Given a callable object or function, execute it, passing 

2281 a :class:`_engine.Connection` as the first argument. 

2282 

2283 The given \*args and \**kwargs are passed subsequent 

2284 to the :class:`_engine.Connection` argument. 

2285 

2286 This function, along with :meth:`_engine.Engine.run_callable`, 

2287 allows a function to be run with a :class:`_engine.Connection` 

2288 or :class:`_engine.Engine` object without the need to know 

2289 which one is being dealt with. 

2290 

2291 """ 

2292 return callable_(self, *args, **kwargs) 

2293 

2294 

2295class ExceptionContextImpl(ExceptionContext): 

2296 """Implement the :class:`.ExceptionContext` interface.""" 

2297 

2298 def __init__( 

2299 self, 

2300 exception, 

2301 sqlalchemy_exception, 

2302 engine, 

2303 connection, 

2304 cursor, 

2305 statement, 

2306 parameters, 

2307 context, 

2308 is_disconnect, 

2309 invalidate_pool_on_disconnect, 

2310 ): 

2311 self.engine = engine 

2312 self.connection = connection 

2313 self.sqlalchemy_exception = sqlalchemy_exception 

2314 self.original_exception = exception 

2315 self.execution_context = context 

2316 self.statement = statement 

2317 self.parameters = parameters 

2318 self.is_disconnect = is_disconnect 

2319 self.invalidate_pool_on_disconnect = invalidate_pool_on_disconnect 

2320 

2321 

2322class Transaction(TransactionalContext): 

2323 """Represent a database transaction in progress. 

2324 

2325 The :class:`.Transaction` object is procured by 

2326 calling the :meth:`_engine.Connection.begin` method of 

2327 :class:`_engine.Connection`:: 

2328 

2329 from sqlalchemy import create_engine 

2330 engine = create_engine("postgresql://scott:tiger@localhost/test") 

2331 connection = engine.connect() 

2332 trans = connection.begin() 

2333 connection.execute(text("insert into x (a, b) values (1, 2)")) 

2334 trans.commit() 

2335 

2336 The object provides :meth:`.rollback` and :meth:`.commit` 

2337 methods in order to control transaction boundaries. It 

2338 also implements a context manager interface so that 

2339 the Python ``with`` statement can be used with the 

2340 :meth:`_engine.Connection.begin` method:: 

2341 

2342 with connection.begin(): 

2343 connection.execute(text("insert into x (a, b) values (1, 2)")) 

2344 

2345 The Transaction object is **not** threadsafe. 

2346 

2347 .. seealso:: 

2348 

2349 :meth:`_engine.Connection.begin` 

2350 

2351 :meth:`_engine.Connection.begin_twophase` 

2352 

2353 :meth:`_engine.Connection.begin_nested` 

2354 

2355 .. index:: 

2356 single: thread safety; Transaction 

2357 """ 

2358 

2359 __slots__ = () 

2360 

2361 _is_root = False 

2362 

2363 def __init__(self, connection): 

2364 raise NotImplementedError() 

2365 

2366 def _do_deactivate(self): 

2367 """do whatever steps are necessary to set this transaction as 

2368 "deactive", however leave this transaction object in place as far 

2369 as the connection's state. 

2370 

2371 for a "real" transaction this should roll back the transaction 

2372 and ensure this transaction is no longer a reset agent. 

2373 

2374 this is used for nesting of marker transactions where the marker 

2375 can set the "real" transaction as rolled back, however it stays 

2376 in place. 

2377 

2378 for 2.0 we hope to remove this nesting feature. 

2379 

2380 """ 

2381 raise NotImplementedError() 

2382 

2383 @property 

2384 def _deactivated_from_connection(self): 

2385 """True if this transaction is totally deactivated from the connection 

2386 and therefore can no longer affect its state. 

2387 

2388 """ 

2389 raise NotImplementedError() 

2390 

2391 def _do_close(self): 

2392 raise NotImplementedError() 

2393 

2394 def _do_rollback(self): 

2395 raise NotImplementedError() 

2396 

2397 def _do_commit(self): 

2398 raise NotImplementedError() 

2399 

2400 @property 

2401 def is_valid(self): 

2402 return self.is_active and not self.connection.invalidated 

2403 

2404 def close(self): 

2405 """Close this :class:`.Transaction`. 

2406 

2407 If this transaction is the base transaction in a begin/commit 

2408 nesting, the transaction will rollback(). Otherwise, the 

2409 method returns. 

2410 

2411 This is used to cancel a Transaction without affecting the scope of 

2412 an enclosing transaction. 

2413 

2414 """ 

2415 try: 

2416 self._do_close() 

2417 finally: 

2418 assert not self.is_active 

2419 

2420 def rollback(self): 

2421 """Roll back this :class:`.Transaction`. 

2422 

2423 The implementation of this may vary based on the type of transaction in 

2424 use: 

2425 

2426 * For a simple database transaction (e.g. :class:`.RootTransaction`), 

2427 it corresponds to a ROLLBACK. 

2428 

2429 * For a :class:`.NestedTransaction`, it corresponds to a 

2430 "ROLLBACK TO SAVEPOINT" operation. 

2431 

2432 * For a :class:`.TwoPhaseTransaction`, DBAPI-specific methods for two 

2433 phase transactions may be used. 

2434 

2435 

2436 """ 

2437 try: 

2438 self._do_rollback() 

2439 finally: 

2440 assert not self.is_active 

2441 

2442 def commit(self): 

2443 """Commit this :class:`.Transaction`. 

2444 

2445 The implementation of this may vary based on the type of transaction in 

2446 use: 

2447 

2448 * For a simple database transaction (e.g. :class:`.RootTransaction`), 

2449 it corresponds to a COMMIT. 

2450 

2451 * For a :class:`.NestedTransaction`, it corresponds to a 

2452 "RELEASE SAVEPOINT" operation. 

2453 

2454 * For a :class:`.TwoPhaseTransaction`, DBAPI-specific methods for two 

2455 phase transactions may be used. 

2456 

2457 """ 

2458 try: 

2459 self._do_commit() 

2460 finally: 

2461 assert not self.is_active 

2462 

2463 def _get_subject(self): 

2464 return self.connection 

2465 

2466 def _transaction_is_active(self): 

2467 return self.is_active 

2468 

2469 def _transaction_is_closed(self): 

2470 return not self._deactivated_from_connection 

2471 

2472 def _rollback_can_be_called(self): 

2473 # for RootTransaction / NestedTransaction, it's safe to call 

2474 # rollback() even if the transaction is deactive and no warnings 

2475 # will be emitted. tested in 

2476 # test_transaction.py -> test_no_rollback_in_deactive(?:_savepoint)? 

2477 return True 

2478 

2479 

2480class MarkerTransaction(Transaction): 

2481 """A 'marker' transaction that is used for nested begin() calls. 

2482 

2483 .. deprecated:: 1.4 future connection for 2.0 won't support this pattern. 

2484 

2485 """ 

2486 

2487 __slots__ = ("connection", "_is_active", "_transaction") 

2488 

2489 def __init__(self, connection): 

2490 assert connection._transaction is not None 

2491 if not connection._transaction.is_active: 

2492 raise exc.InvalidRequestError( 

2493 "the current transaction on this connection is inactive. " 

2494 "Please issue a rollback first." 

2495 ) 

2496 

2497 assert not connection._is_future 

2498 util.warn_deprecated_20( 

2499 "Calling .begin() when a transaction is already begun, creating " 

2500 "a 'sub' transaction, is deprecated " 

2501 "and will be removed in 2.0. See the documentation section " 

2502 "'Migrating from the nesting pattern' for background on how " 

2503 "to migrate from this pattern." 

2504 ) 

2505 

2506 self.connection = connection 

2507 

2508 if connection._trans_context_manager: 

2509 TransactionalContext._trans_ctx_check(connection) 

2510 

2511 if connection._nested_transaction is not None: 

2512 self._transaction = connection._nested_transaction 

2513 else: 

2514 self._transaction = connection._transaction 

2515 self._is_active = True 

2516 

2517 @property 

2518 def _deactivated_from_connection(self): 

2519 return not self.is_active 

2520 

2521 @property 

2522 def is_active(self): 

2523 return self._is_active and self._transaction.is_active 

2524 

2525 def _deactivate(self): 

2526 self._is_active = False 

2527 

2528 def _do_close(self): 

2529 # does not actually roll back the root 

2530 self._deactivate() 

2531 

2532 def _do_rollback(self): 

2533 # does roll back the root 

2534 if self._is_active: 

2535 try: 

2536 self._transaction._do_deactivate() 

2537 finally: 

2538 self._deactivate() 

2539 

2540 def _do_commit(self): 

2541 self._deactivate() 

2542 

2543 

2544class RootTransaction(Transaction): 

2545 """Represent the "root" transaction on a :class:`_engine.Connection`. 

2546 

2547 This corresponds to the current "BEGIN/COMMIT/ROLLBACK" that's occurring 

2548 for the :class:`_engine.Connection`. The :class:`_engine.RootTransaction` 

2549 is created by calling upon the :meth:`_engine.Connection.begin` method, and 

2550 remains associated with the :class:`_engine.Connection` throughout its 

2551 active span. The current :class:`_engine.RootTransaction` in use is 

2552 accessible via the :attr:`_engine.Connection.get_transaction` method of 

2553 :class:`_engine.Connection`. 

2554 

2555 In :term:`2.0 style` use, the :class:`_future.Connection` also employs 

2556 "autobegin" behavior that will create a new 

2557 :class:`_engine.RootTransaction` whenever a connection in a 

2558 non-transactional state is used to emit commands on the DBAPI connection. 

2559 The scope of the :class:`_engine.RootTransaction` in 2.0 style 

2560 use can be controlled using the :meth:`_future.Connection.commit` and 

2561 :meth:`_future.Connection.rollback` methods. 

2562 

2563 

2564 """ 

2565 

2566 _is_root = True 

2567 

2568 __slots__ = ("connection", "is_active") 

2569 

2570 def __init__(self, connection): 

2571 assert connection._transaction is None 

2572 if connection._trans_context_manager: 

2573 TransactionalContext._trans_ctx_check(connection) 

2574 self.connection = connection 

2575 self._connection_begin_impl() 

2576 connection._transaction = self 

2577 

2578 self.is_active = True 

2579 

2580 def _deactivate_from_connection(self): 

2581 if self.is_active: 

2582 assert self.connection._transaction is self 

2583 self.is_active = False 

2584 

2585 elif self.connection._transaction is not self: 

2586 util.warn("transaction already deassociated from connection") 

2587 

2588 @property 

2589 def _deactivated_from_connection(self): 

2590 return self.connection._transaction is not self 

2591 

2592 def _do_deactivate(self): 

2593 # called from a MarkerTransaction to cancel this root transaction. 

2594 # the transaction stays in place as connection._transaction, but 

2595 # is no longer active and is no longer the reset agent for the 

2596 # pooled connection. the connection won't support a new begin() 

2597 # until this transaction is explicitly closed, rolled back, 

2598 # or committed. 

2599 

2600 assert self.connection._transaction is self 

2601 

2602 if self.is_active: 

2603 self._connection_rollback_impl() 

2604 

2605 # handle case where a savepoint was created inside of a marker 

2606 # transaction that refers to a root. nested has to be cancelled 

2607 # also. 

2608 if self.connection._nested_transaction: 

2609 self.connection._nested_transaction._cancel() 

2610 

2611 self._deactivate_from_connection() 

2612 

2613 def _connection_begin_impl(self): 

2614 self.connection._begin_impl(self) 

2615 

2616 def _connection_rollback_impl(self): 

2617 self.connection._rollback_impl() 

2618 

2619 def _connection_commit_impl(self): 

2620 self.connection._commit_impl() 

2621 

2622 def _close_impl(self, try_deactivate=False): 

2623 try: 

2624 if self.is_active: 

2625 self._connection_rollback_impl() 

2626 

2627 if self.connection._nested_transaction: 

2628 self.connection._nested_transaction._cancel() 

2629 finally: 

2630 if self.is_active or try_deactivate: 

2631 self._deactivate_from_connection() 

2632 if self.connection._transaction is self: 

2633 self.connection._transaction = None 

2634 

2635 assert not self.is_active 

2636 assert self.connection._transaction is not self 

2637 

2638 def _do_close(self): 

2639 self._close_impl() 

2640 

2641 def _do_rollback(self): 

2642 self._close_impl(try_deactivate=True) 

2643 

2644 def _do_commit(self): 

2645 if self.is_active: 

2646 assert self.connection._transaction is self 

2647 

2648 try: 

2649 self._connection_commit_impl() 

2650 finally: 

2651 # whether or not commit succeeds, cancel any 

2652 # nested transactions, make this transaction "inactive" 

2653 # and remove it as a reset agent 

2654 if self.connection._nested_transaction: 

2655 self.connection._nested_transaction._cancel() 

2656 

2657 self._deactivate_from_connection() 

2658 

2659 # ...however only remove as the connection's current transaction 

2660 # if commit succeeded. otherwise it stays on so that a rollback 

2661 # needs to occur. 

2662 self.connection._transaction = None 

2663 else: 

2664 if self.connection._transaction is self: 

2665 self.connection._invalid_transaction() 

2666 else: 

2667 raise exc.InvalidRequestError("This transaction is inactive") 

2668 

2669 assert not self.is_active 

2670 assert self.connection._transaction is not self 

2671 

2672 

2673class NestedTransaction(Transaction): 

2674 """Represent a 'nested', or SAVEPOINT transaction. 

2675 

2676 The :class:`.NestedTransaction` object is created by calling the 

2677 :meth:`_engine.Connection.begin_nested` method of 

2678 :class:`_engine.Connection`. 

2679 

2680 When using :class:`.NestedTransaction`, the semantics of "begin" / 

2681 "commit" / "rollback" are as follows: 

2682 

2683 * the "begin" operation corresponds to the "BEGIN SAVEPOINT" command, where 

2684 the savepoint is given an explicit name that is part of the state 

2685 of this object. 

2686 

2687 * The :meth:`.NestedTransaction.commit` method corresponds to a 

2688 "RELEASE SAVEPOINT" operation, using the savepoint identifier associated 

2689 with this :class:`.NestedTransaction`. 

2690 

2691 * The :meth:`.NestedTransaction.rollback` method corresponds to a 

2692 "ROLLBACK TO SAVEPOINT" operation, using the savepoint identifier 

2693 associated with this :class:`.NestedTransaction`. 

2694 

2695 The rationale for mimicking the semantics of an outer transaction in 

2696 terms of savepoints so that code may deal with a "savepoint" transaction 

2697 and an "outer" transaction in an agnostic way. 

2698 

2699 .. seealso:: 

2700 

2701 :ref:`session_begin_nested` - ORM version of the SAVEPOINT API. 

2702 

2703 """ 

2704 

2705 __slots__ = ("connection", "is_active", "_savepoint", "_previous_nested") 

2706 

2707 def __init__(self, connection): 

2708 assert connection._transaction is not None 

2709 if connection._trans_context_manager: 

2710 TransactionalContext._trans_ctx_check(connection) 

2711 self.connection = connection 

2712 self._savepoint = self.connection._savepoint_impl() 

2713 self.is_active = True 

2714 self._previous_nested = connection._nested_transaction 

2715 connection._nested_transaction = self 

2716 

2717 def _deactivate_from_connection(self, warn=True): 

2718 if self.connection._nested_transaction is self: 

2719 self.connection._nested_transaction = self._previous_nested 

2720 elif warn: 

2721 util.warn( 

2722 "nested transaction already deassociated from connection" 

2723 ) 

2724 

2725 @property 

2726 def _deactivated_from_connection(self): 

2727 return self.connection._nested_transaction is not self 

2728 

2729 def _cancel(self): 

2730 # called by RootTransaction when the outer transaction is 

2731 # committed, rolled back, or closed to cancel all savepoints 

2732 # without any action being taken 

2733 self.is_active = False 

2734 self._deactivate_from_connection() 

2735 if self._previous_nested: 

2736 self._previous_nested._cancel() 

2737 

2738 def _close_impl(self, deactivate_from_connection, warn_already_deactive): 

2739 try: 

2740 if self.is_active and self.connection._transaction.is_active: 

2741 self.connection._rollback_to_savepoint_impl(self._savepoint) 

2742 finally: 

2743 self.is_active = False 

2744 

2745 if deactivate_from_connection: 

2746 self._deactivate_from_connection(warn=warn_already_deactive) 

2747 

2748 assert not self.is_active 

2749 if deactivate_from_connection: 

2750 assert self.connection._nested_transaction is not self 

2751 

2752 def _do_deactivate(self): 

2753 self._close_impl(False, False) 

2754 

2755 def _do_close(self): 

2756 self._close_impl(True, False) 

2757 

2758 def _do_rollback(self): 

2759 self._close_impl(True, True) 

2760 

2761 def _do_commit(self): 

2762 if self.is_active: 

2763 try: 

2764 self.connection._release_savepoint_impl(self._savepoint) 

2765 finally: 

2766 # nested trans becomes inactive on failed release 

2767 # unconditionally. this prevents it from trying to 

2768 # emit SQL when it rolls back. 

2769 self.is_active = False 

2770 

2771 # but only de-associate from connection if it succeeded 

2772 self._deactivate_from_connection() 

2773 else: 

2774 if self.connection._nested_transaction is self: 

2775 self.connection._invalid_transaction() 

2776 else: 

2777 raise exc.InvalidRequestError( 

2778 "This nested transaction is inactive" 

2779 ) 

2780 

2781 

2782class TwoPhaseTransaction(RootTransaction): 

2783 """Represent a two-phase transaction. 

2784 

2785 A new :class:`.TwoPhaseTransaction` object may be procured 

2786 using the :meth:`_engine.Connection.begin_twophase` method. 

2787 

2788 The interface is the same as that of :class:`.Transaction` 

2789 with the addition of the :meth:`prepare` method. 

2790 

2791 """ 

2792 

2793 __slots__ = ("connection", "is_active", "xid", "_is_prepared") 

2794 

2795 def __init__(self, connection, xid): 

2796 self._is_prepared = False 

2797 self.xid = xid 

2798 super(TwoPhaseTransaction, self).__init__(connection) 

2799 

2800 def prepare(self): 

2801 """Prepare this :class:`.TwoPhaseTransaction`. 

2802 

2803 After a PREPARE, the transaction can be committed. 

2804 

2805 """ 

2806 if not self.is_active: 

2807 raise exc.InvalidRequestError("This transaction is inactive") 

2808 self.connection._prepare_twophase_impl(self.xid) 

2809 self._is_prepared = True 

2810 

2811 def _connection_begin_impl(self): 

2812 self.connection._begin_twophase_impl(self) 

2813 

2814 def _connection_rollback_impl(self): 

2815 self.connection._rollback_twophase_impl(self.xid, self._is_prepared) 

2816 

2817 def _connection_commit_impl(self): 

2818 self.connection._commit_twophase_impl(self.xid, self._is_prepared) 

2819 

2820 

2821class Engine(Connectable, log.Identified): 

2822 """ 

2823 Connects a :class:`~sqlalchemy.pool.Pool` and 

2824 :class:`~sqlalchemy.engine.interfaces.Dialect` together to provide a 

2825 source of database connectivity and behavior. 

2826 

2827 This is the **SQLAlchemy 1.x version** of :class:`_engine.Engine`. For 

2828 the :term:`2.0 style` version, which includes some API differences, 

2829 see :class:`_future.Engine`. 

2830 

2831 An :class:`_engine.Engine` object is instantiated publicly using the 

2832 :func:`~sqlalchemy.create_engine` function. 

2833 

2834 .. seealso:: 

2835 

2836 :doc:`/core/engines` 

2837 

2838 :ref:`connections_toplevel` 

2839 

2840 """ 

2841 

2842 _execution_options = _EMPTY_EXECUTION_OPTS 

2843 _has_events = False 

2844 _connection_cls = Connection 

2845 _sqla_logger_namespace = "sqlalchemy.engine.Engine" 

2846 _is_future = False 

2847 

2848 _schema_translate_map = None 

2849 

2850 def __init__( 

2851 self, 

2852 pool, 

2853 dialect, 

2854 url, 

2855 logging_name=None, 

2856 echo=None, 

2857 query_cache_size=500, 

2858 execution_options=None, 

2859 hide_parameters=False, 

2860 ): 

2861 self.pool = pool 

2862 self.url = url 

2863 self.dialect = dialect 

2864 if logging_name: 

2865 self.logging_name = logging_name 

2866 self.echo = echo 

2867 self.hide_parameters = hide_parameters 

2868 if query_cache_size != 0: 

2869 self._compiled_cache = util.LRUCache( 

2870 query_cache_size, size_alert=self._lru_size_alert 

2871 ) 

2872 else: 

2873 self._compiled_cache = None 

2874 log.instance_logger(self, echoflag=echo) 

2875 if execution_options: 

2876 self.update_execution_options(**execution_options) 

2877 

2878 def _lru_size_alert(self, cache): 

2879 if self._should_log_info: 

2880 self.logger.info( 

2881 "Compiled cache size pruning from %d items to %d. " 

2882 "Increase cache size to reduce the frequency of pruning.", 

2883 len(cache), 

2884 cache.capacity, 

2885 ) 

2886 

2887 @property 

2888 def engine(self): 

2889 return self 

2890 

2891 def clear_compiled_cache(self): 

2892 """Clear the compiled cache associated with the dialect. 

2893 

2894 This applies **only** to the built-in cache that is established 

2895 via the :paramref:`_engine.create_engine.query_cache_size` parameter. 

2896 It will not impact any dictionary caches that were passed via the 

2897 :paramref:`.Connection.execution_options.query_cache` parameter. 

2898 

2899 .. versionadded:: 1.4 

2900 

2901 """ 

2902 if self._compiled_cache: 

2903 self._compiled_cache.clear() 

2904 

2905 def update_execution_options(self, **opt): 

2906 r"""Update the default execution_options dictionary 

2907 of this :class:`_engine.Engine`. 

2908 

2909 The given keys/values in \**opt are added to the 

2910 default execution options that will be used for 

2911 all connections. The initial contents of this dictionary 

2912 can be sent via the ``execution_options`` parameter 

2913 to :func:`_sa.create_engine`. 

2914 

2915 .. seealso:: 

2916 

2917 :meth:`_engine.Connection.execution_options` 

2918 

2919 :meth:`_engine.Engine.execution_options` 

2920 

2921 """ 

2922 self._execution_options = self._execution_options.union(opt) 

2923 self.dispatch.set_engine_execution_options(self, opt) 

2924 self.dialect.set_engine_execution_options(self, opt) 

2925 

2926 def execution_options(self, **opt): 

2927 """Return a new :class:`_engine.Engine` that will provide 

2928 :class:`_engine.Connection` objects with the given execution options. 

2929 

2930 The returned :class:`_engine.Engine` remains related to the original 

2931 :class:`_engine.Engine` in that it shares the same connection pool and 

2932 other state: 

2933 

2934 * The :class:`_pool.Pool` used by the new :class:`_engine.Engine` 

2935 is the 

2936 same instance. The :meth:`_engine.Engine.dispose` 

2937 method will replace 

2938 the connection pool instance for the parent engine as well 

2939 as this one. 

2940 * Event listeners are "cascaded" - meaning, the new 

2941 :class:`_engine.Engine` 

2942 inherits the events of the parent, and new events can be associated 

2943 with the new :class:`_engine.Engine` individually. 

2944 * The logging configuration and logging_name is copied from the parent 

2945 :class:`_engine.Engine`. 

2946 

2947 The intent of the :meth:`_engine.Engine.execution_options` method is 

2948 to implement "sharding" schemes where multiple :class:`_engine.Engine` 

2949 objects refer to the same connection pool, but are differentiated 

2950 by options that would be consumed by a custom event:: 

2951 

2952 primary_engine = create_engine("mysql://") 

2953 shard1 = primary_engine.execution_options(shard_id="shard1") 

2954 shard2 = primary_engine.execution_options(shard_id="shard2") 

2955 

2956 Above, the ``shard1`` engine serves as a factory for 

2957 :class:`_engine.Connection` 

2958 objects that will contain the execution option 

2959 ``shard_id=shard1``, and ``shard2`` will produce 

2960 :class:`_engine.Connection` 

2961 objects that contain the execution option ``shard_id=shard2``. 

2962 

2963 An event handler can consume the above execution option to perform 

2964 a schema switch or other operation, given a connection. Below 

2965 we emit a MySQL ``use`` statement to switch databases, at the same 

2966 time keeping track of which database we've established using the 

2967 :attr:`_engine.Connection.info` dictionary, 

2968 which gives us a persistent 

2969 storage space that follows the DBAPI connection:: 

2970 

2971 from sqlalchemy import event 

2972 from sqlalchemy.engine import Engine 

2973 

2974 shards = {"default": "base", shard_1: "db1", "shard_2": "db2"} 

2975 

2976 @event.listens_for(Engine, "before_cursor_execute") 

2977 def _switch_shard(conn, cursor, stmt, 

2978 params, context, executemany): 

2979 shard_id = conn._execution_options.get('shard_id', "default") 

2980 current_shard = conn.info.get("current_shard", None) 

2981 

2982 if current_shard != shard_id: 

2983 cursor.execute("use %s" % shards[shard_id]) 

2984 conn.info["current_shard"] = shard_id 

2985 

2986 .. seealso:: 

2987 

2988 :meth:`_engine.Connection.execution_options` 

2989 - update execution options 

2990 on a :class:`_engine.Connection` object. 

2991 

2992 :meth:`_engine.Engine.update_execution_options` 

2993 - update the execution 

2994 options for a given :class:`_engine.Engine` in place. 

2995 

2996 :meth:`_engine.Engine.get_execution_options` 

2997 

2998 

2999 """ 

3000 return self._option_cls(self, opt) 

3001 

3002 def get_execution_options(self): 

3003 """Get the non-SQL options which will take effect during execution. 

3004 

3005 .. versionadded: 1.3 

3006 

3007 .. seealso:: 

3008 

3009 :meth:`_engine.Engine.execution_options` 

3010 """ 

3011 return self._execution_options 

3012 

3013 @property 

3014 def name(self): 

3015 """String name of the :class:`~sqlalchemy.engine.interfaces.Dialect` 

3016 in use by this :class:`Engine`.""" 

3017 

3018 return self.dialect.name 

3019 

3020 @property 

3021 def driver(self): 

3022 """Driver name of the :class:`~sqlalchemy.engine.interfaces.Dialect` 

3023 in use by this :class:`Engine`.""" 

3024 

3025 return self.dialect.driver 

3026 

3027 echo = log.echo_property() 

3028 

3029 def __repr__(self): 

3030 return "Engine(%r)" % (self.url,) 

3031 

3032 def dispose(self, close=True): 

3033 """Dispose of the connection pool used by this 

3034 :class:`_engine.Engine`. 

3035 

3036 A new connection pool is created immediately after the old one has been 

3037 disposed. The previous connection pool is disposed either actively, by 

3038 closing out all currently checked-in connections in that pool, or 

3039 passively, by losing references to it but otherwise not closing any 

3040 connections. The latter strategy is more appropriate for an initializer 

3041 in a forked Python process. 

3042 

3043 :param close: if left at its default of ``True``, has the 

3044 effect of fully closing all **currently checked in** 

3045 database connections. Connections that are still checked out 

3046 will **not** be closed, however they will no longer be associated 

3047 with this :class:`_engine.Engine`, 

3048 so when they are closed individually, eventually the 

3049 :class:`_pool.Pool` which they are associated with will 

3050 be garbage collected and they will be closed out fully, if 

3051 not already closed on checkin. 

3052 

3053 If set to ``False``, the previous connection pool is de-referenced, 

3054 and otherwise not touched in any way. 

3055 

3056 .. versionadded:: 1.4.33 Added the :paramref:`.Engine.dispose.close` 

3057 parameter to allow the replacement of a connection pool in a child 

3058 process without interfering with the connections used by the parent 

3059 process. 

3060 

3061 

3062 .. seealso:: 

3063 

3064 :ref:`engine_disposal` 

3065 

3066 :ref:`pooling_multiprocessing` 

3067 

3068 """ 

3069 if close: 

3070 self.pool.dispose() 

3071 self.pool = self.pool.recreate() 

3072 self.dispatch.engine_disposed(self) 

3073 

3074 def _execute_default( 

3075 self, default, multiparams=(), params=util.EMPTY_DICT 

3076 ): 

3077 with self.connect() as conn: 

3078 return conn._execute_default(default, multiparams, params) 

3079 

3080 @contextlib.contextmanager 

3081 def _optional_conn_ctx_manager(self, connection=None): 

3082 if connection is None: 

3083 with self.connect() as conn: 

3084 yield conn 

3085 else: 

3086 yield connection 

3087 

3088 class _trans_ctx(object): 

3089 def __init__(self, conn, transaction, close_with_result): 

3090 self.conn = conn 

3091 self.transaction = transaction 

3092 self.close_with_result = close_with_result 

3093 

3094 def __enter__(self): 

3095 self.transaction.__enter__() 

3096 return self.conn 

3097 

3098 def __exit__(self, type_, value, traceback): 

3099 try: 

3100 self.transaction.__exit__(type_, value, traceback) 

3101 finally: 

3102 if not self.close_with_result: 

3103 self.conn.close() 

3104 

3105 def begin(self, close_with_result=False): 

3106 """Return a context manager delivering a :class:`_engine.Connection` 

3107 with a :class:`.Transaction` established. 

3108 

3109 E.g.:: 

3110 

3111 with engine.begin() as conn: 

3112 conn.execute( 

3113 text("insert into table (x, y, z) values (1, 2, 3)") 

3114 ) 

3115 conn.execute(text("my_special_procedure(5)")) 

3116 

3117 Upon successful operation, the :class:`.Transaction` 

3118 is committed. If an error is raised, the :class:`.Transaction` 

3119 is rolled back. 

3120 

3121 Legacy use only: the ``close_with_result`` flag is normally ``False``, 

3122 and indicates that the :class:`_engine.Connection` will be closed when 

3123 the operation is complete. When set to ``True``, it indicates the 

3124 :class:`_engine.Connection` is in "single use" mode, where the 

3125 :class:`_engine.CursorResult` returned by the first call to 

3126 :meth:`_engine.Connection.execute` will close the 

3127 :class:`_engine.Connection` when that :class:`_engine.CursorResult` has 

3128 exhausted all result rows. 

3129 

3130 .. seealso:: 

3131 

3132 :meth:`_engine.Engine.connect` - procure a 

3133 :class:`_engine.Connection` from 

3134 an :class:`_engine.Engine`. 

3135 

3136 :meth:`_engine.Connection.begin` - start a :class:`.Transaction` 

3137 for a particular :class:`_engine.Connection`. 

3138 

3139 """ 

3140 if self._connection_cls._is_future: 

3141 conn = self.connect() 

3142 else: 

3143 conn = self.connect(close_with_result=close_with_result) 

3144 try: 

3145 trans = conn.begin() 

3146 except: 

3147 with util.safe_reraise(): 

3148 conn.close() 

3149 return Engine._trans_ctx(conn, trans, close_with_result) 

3150 

3151 @util.deprecated( 

3152 "1.4", 

3153 "The :meth:`_engine.Engine.transaction` " 

3154 "method is deprecated and will be " 

3155 "removed in a future release. Use the :meth:`_engine.Engine.begin` " 

3156 "context " 

3157 "manager instead.", 

3158 ) 

3159 def transaction(self, callable_, *args, **kwargs): 

3160 r"""Execute the given function within a transaction boundary. 

3161 

3162 The function is passed a :class:`_engine.Connection` newly procured 

3163 from :meth:`_engine.Engine.connect` as the first argument, 

3164 followed by the given \*args and \**kwargs. 

3165 

3166 e.g.:: 

3167 

3168 def do_something(conn, x, y): 

3169 conn.execute(text("some statement"), {'x':x, 'y':y}) 

3170 

3171 engine.transaction(do_something, 5, 10) 

3172 

3173 The operations inside the function are all invoked within the 

3174 context of a single :class:`.Transaction`. 

3175 Upon success, the transaction is committed. If an 

3176 exception is raised, the transaction is rolled back 

3177 before propagating the exception. 

3178 

3179 .. note:: 

3180 

3181 The :meth:`.transaction` method is superseded by 

3182 the usage of the Python ``with:`` statement, which can 

3183 be used with :meth:`_engine.Engine.begin`:: 

3184 

3185 with engine.begin() as conn: 

3186 conn.execute(text("some statement"), {'x':5, 'y':10}) 

3187 

3188 .. seealso:: 

3189 

3190 :meth:`_engine.Engine.begin` - engine-level transactional 

3191 context 

3192 

3193 :meth:`_engine.Connection.transaction` 

3194 - connection-level version of 

3195 :meth:`_engine.Engine.transaction` 

3196 

3197 """ 

3198 kwargs["_sa_skip_warning"] = True 

3199 with self.connect() as conn: 

3200 return conn.transaction(callable_, *args, **kwargs) 

3201 

3202 @util.deprecated( 

3203 "1.4", 

3204 "The :meth:`_engine.Engine.run_callable` " 

3205 "method is deprecated and will be " 

3206 "removed in a future release. Use the :meth:`_engine.Engine.begin` " 

3207 "context manager instead.", 

3208 ) 

3209 def run_callable(self, callable_, *args, **kwargs): 

3210 r"""Given a callable object or function, execute it, passing 

3211 a :class:`_engine.Connection` as the first argument. 

3212 

3213 The given \*args and \**kwargs are passed subsequent 

3214 to the :class:`_engine.Connection` argument. 

3215 

3216 This function, along with :meth:`_engine.Connection.run_callable`, 

3217 allows a function to be run with a :class:`_engine.Connection` 

3218 or :class:`_engine.Engine` object without the need to know 

3219 which one is being dealt with. 

3220 

3221 """ 

3222 kwargs["_sa_skip_warning"] = True 

3223 with self.connect() as conn: 

3224 return conn.run_callable(callable_, *args, **kwargs) 

3225 

3226 def _run_ddl_visitor(self, visitorcallable, element, **kwargs): 

3227 with self.begin() as conn: 

3228 conn._run_ddl_visitor(visitorcallable, element, **kwargs) 

3229 

3230 @util.deprecated_20( 

3231 ":meth:`_engine.Engine.execute`", 

3232 alternative="All statement execution in SQLAlchemy 2.0 is performed " 

3233 "by the :meth:`_engine.Connection.execute` method of " 

3234 ":class:`_engine.Connection`, " 

3235 "or in the ORM by the :meth:`.Session.execute` method of " 

3236 ":class:`.Session`.", 

3237 ) 

3238 def execute(self, statement, *multiparams, **params): 

3239 """Executes the given construct and returns a 

3240 :class:`_engine.CursorResult`. 

3241 

3242 The arguments are the same as those used by 

3243 :meth:`_engine.Connection.execute`. 

3244 

3245 Here, a :class:`_engine.Connection` is acquired using the 

3246 :meth:`_engine.Engine.connect` method, and the statement executed 

3247 with that connection. The returned :class:`_engine.CursorResult` 

3248 is flagged 

3249 such that when the :class:`_engine.CursorResult` is exhausted and its 

3250 underlying cursor is closed, the :class:`_engine.Connection` 

3251 created here 

3252 will also be closed, which allows its associated DBAPI connection 

3253 resource to be returned to the connection pool. 

3254 

3255 """ 

3256 connection = self.connect(close_with_result=True) 

3257 return connection.execute(statement, *multiparams, **params) 

3258 

3259 @util.deprecated_20( 

3260 ":meth:`_engine.Engine.scalar`", 

3261 alternative="All statement execution in SQLAlchemy 2.0 is performed " 

3262 "by the :meth:`_engine.Connection.execute` method of " 

3263 ":class:`_engine.Connection`, " 

3264 "or in the ORM by the :meth:`.Session.execute` method of " 

3265 ":class:`.Session`; the :meth:`_future.Result.scalar` " 

3266 "method can then be " 

3267 "used to return a scalar result.", 

3268 ) 

3269 def scalar(self, statement, *multiparams, **params): 

3270 """Executes and returns the first column of the first row. 

3271 

3272 The underlying result/cursor is closed after execution. 

3273 """ 

3274 return self.execute(statement, *multiparams, **params).scalar() 

3275 

3276 def _execute_clauseelement( 

3277 self, 

3278 elem, 

3279 multiparams=None, 

3280 params=None, 

3281 execution_options=_EMPTY_EXECUTION_OPTS, 

3282 ): 

3283 connection = self.connect(close_with_result=True) 

3284 return connection._execute_clauseelement( 

3285 elem, multiparams, params, execution_options 

3286 ) 

3287 

3288 def _execute_compiled( 

3289 self, 

3290 compiled, 

3291 multiparams, 

3292 params, 

3293 execution_options=_EMPTY_EXECUTION_OPTS, 

3294 ): 

3295 connection = self.connect(close_with_result=True) 

3296 return connection._execute_compiled( 

3297 compiled, multiparams, params, execution_options 

3298 ) 

3299 

3300 def connect(self, close_with_result=False): 

3301 """Return a new :class:`_engine.Connection` object. 

3302 

3303 The :class:`_engine.Connection` object is a facade that uses a DBAPI 

3304 connection internally in order to communicate with the database. This 

3305 connection is procured from the connection-holding :class:`_pool.Pool` 

3306 referenced by this :class:`_engine.Engine`. When the 

3307 :meth:`_engine.Connection.close` method of the 

3308 :class:`_engine.Connection` object 

3309 is called, the underlying DBAPI connection is then returned to the 

3310 connection pool, where it may be used again in a subsequent call to 

3311 :meth:`_engine.Engine.connect`. 

3312 

3313 """ 

3314 

3315 return self._connection_cls(self, close_with_result=close_with_result) 

3316 

3317 @util.deprecated( 

3318 "1.4", 

3319 "The :meth:`_engine.Engine.table_names` " 

3320 "method is deprecated and will be " 

3321 "removed in a future release. Please refer to " 

3322 ":meth:`_reflection.Inspector.get_table_names`.", 

3323 ) 

3324 def table_names(self, schema=None, connection=None): 

3325 """Return a list of all table names available in the database. 

3326 

3327 :param schema: Optional, retrieve names from a non-default schema. 

3328 

3329 :param connection: Optional, use a specified connection. 

3330 """ 

3331 with self._optional_conn_ctx_manager(connection) as conn: 

3332 insp = inspection.inspect(conn) 

3333 return insp.get_table_names(schema) 

3334 

3335 @util.deprecated( 

3336 "1.4", 

3337 "The :meth:`_engine.Engine.has_table` " 

3338 "method is deprecated and will be " 

3339 "removed in a future release. Please refer to " 

3340 ":meth:`_reflection.Inspector.has_table`.", 

3341 ) 

3342 def has_table(self, table_name, schema=None): 

3343 """Return True if the given backend has a table of the given name. 

3344 

3345 .. seealso:: 

3346 

3347 :ref:`metadata_reflection_inspector` - detailed schema inspection 

3348 using the :class:`_reflection.Inspector` interface. 

3349 

3350 :class:`.quoted_name` - used to pass quoting information along 

3351 with a schema identifier. 

3352 

3353 """ 

3354 with self._optional_conn_ctx_manager(None) as conn: 

3355 insp = inspection.inspect(conn) 

3356 return insp.has_table(table_name, schema=schema) 

3357 

3358 def _wrap_pool_connect(self, fn, connection): 

3359 dialect = self.dialect 

3360 try: 

3361 return fn() 

3362 except dialect.dbapi.Error as e: 

3363 if connection is None: 

3364 Connection._handle_dbapi_exception_noconnection( 

3365 e, dialect, self 

3366 ) 

3367 else: 

3368 util.raise_( 

3369 sys.exc_info()[1], with_traceback=sys.exc_info()[2] 

3370 ) 

3371 

3372 def raw_connection(self, _connection=None): 

3373 """Return a "raw" DBAPI connection from the connection pool. 

3374 

3375 The returned object is a proxied version of the DBAPI 

3376 connection object used by the underlying driver in use. 

3377 The object will have all the same behavior as the real DBAPI 

3378 connection, except that its ``close()`` method will result in the 

3379 connection being returned to the pool, rather than being closed 

3380 for real. 

3381 

3382 This method provides direct DBAPI connection access for 

3383 special situations when the API provided by 

3384 :class:`_engine.Connection` 

3385 is not needed. When a :class:`_engine.Connection` object is already 

3386 present, the DBAPI connection is available using 

3387 the :attr:`_engine.Connection.connection` accessor. 

3388 

3389 .. seealso:: 

3390 

3391 :ref:`dbapi_connections` 

3392 

3393 """ 

3394 return self._wrap_pool_connect(self.pool.connect, _connection) 

3395 

3396 

3397class OptionEngineMixin(object): 

3398 _sa_propagate_class_events = False 

3399 

3400 def __init__(self, proxied, execution_options): 

3401 self._proxied = proxied 

3402 self.url = proxied.url 

3403 self.dialect = proxied.dialect 

3404 self.logging_name = proxied.logging_name 

3405 self.echo = proxied.echo 

3406 self._compiled_cache = proxied._compiled_cache 

3407 self.hide_parameters = proxied.hide_parameters 

3408 log.instance_logger(self, echoflag=self.echo) 

3409 

3410 # note: this will propagate events that are assigned to the parent 

3411 # engine after this OptionEngine is created. Since we share 

3412 # the events of the parent we also disallow class-level events 

3413 # to apply to the OptionEngine class directly. 

3414 # 

3415 # the other way this can work would be to transfer existing 

3416 # events only, using: 

3417 # self.dispatch._update(proxied.dispatch) 

3418 # 

3419 # that might be more appropriate however it would be a behavioral 

3420 # change for logic that assigns events to the parent engine and 

3421 # would like it to take effect for the already-created sub-engine. 

3422 self.dispatch = self.dispatch._join(proxied.dispatch) 

3423 

3424 self._execution_options = proxied._execution_options 

3425 self.update_execution_options(**execution_options) 

3426 

3427 def _get_pool(self): 

3428 return self._proxied.pool 

3429 

3430 def _set_pool(self, pool): 

3431 self._proxied.pool = pool 

3432 

3433 pool = property(_get_pool, _set_pool) 

3434 

3435 def _get_has_events(self): 

3436 return self._proxied._has_events or self.__dict__.get( 

3437 "_has_events", False 

3438 ) 

3439 

3440 def _set_has_events(self, value): 

3441 self.__dict__["_has_events"] = value 

3442 

3443 _has_events = property(_get_has_events, _set_has_events) 

3444 

3445 

3446class OptionEngine(OptionEngineMixin, Engine): 

3447 pass 

3448 

3449 

3450Engine._option_cls = OptionEngine