1# engine/interfaces.py
2# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7
8"""Define core interfaces used by the engine system."""
9
10from .. import util
11from ..sql.compiler import Compiled # noqa
12from ..sql.compiler import TypeCompiler # noqa
13from ..util.concurrency import await_only
14
15
16class Dialect(object):
17 """Define the behavior of a specific database and DB-API combination.
18
19 Any aspect of metadata definition, SQL query generation,
20 execution, result-set handling, or anything else which varies
21 between databases is defined under the general category of the
22 Dialect. The Dialect acts as a factory for other
23 database-specific object implementations including
24 ExecutionContext, Compiled, DefaultGenerator, and TypeEngine.
25
26 .. note:: Third party dialects should not subclass :class:`.Dialect`
27 directly. Instead, subclass :class:`.default.DefaultDialect` or
28 descendant class.
29
30 All dialects include the following attributes. There are many other
31 attributes that may be supported as well:
32
33 ``name``
34 identifying name for the dialect from a DBAPI-neutral point of view
35 (i.e. 'sqlite')
36
37 ``driver``
38 identifying name for the dialect's DBAPI
39
40 ``positional``
41 True if the paramstyle for this Dialect is positional.
42
43 ``paramstyle``
44 the paramstyle to be used (some DB-APIs support multiple
45 paramstyles).
46
47 ``encoding``
48 type of encoding to use for unicode, usually defaults to
49 'utf-8'.
50
51 ``statement_compiler``
52 a :class:`.Compiled` class used to compile SQL statements
53
54 ``ddl_compiler``
55 a :class:`.Compiled` class used to compile DDL statements
56
57 ``server_version_info``
58 a tuple containing a version number for the DB backend in use.
59 This value is only available for supporting dialects, and is
60 typically populated during the initial connection to the database.
61
62 ``default_schema_name``
63 the name of the default schema. This value is only available for
64 supporting dialects, and is typically populated during the
65 initial connection to the database.
66
67 ``execution_ctx_cls``
68 a :class:`.ExecutionContext` class used to handle statement execution
69
70 ``execute_sequence_format``
71 either the 'tuple' or 'list' type, depending on what cursor.execute()
72 accepts for the second argument (they vary).
73
74 ``preparer``
75 a :class:`~sqlalchemy.sql.compiler.IdentifierPreparer` class used to
76 quote identifiers.
77
78 ``supports_alter``
79 ``True`` if the database supports ``ALTER TABLE`` - used only for
80 generating foreign key constraints in certain circumstances
81
82 ``max_identifier_length``
83 The maximum length of identifier names.
84
85 ``supports_sane_rowcount``
86 Indicate whether the dialect properly implements rowcount for
87 ``UPDATE`` and ``DELETE`` statements.
88
89 ``supports_sane_multi_rowcount``
90 Indicate whether the dialect properly implements rowcount for
91 ``UPDATE`` and ``DELETE`` statements when executed via
92 executemany.
93
94 ``preexecute_autoincrement_sequences``
95 True if 'implicit' primary key functions must be executed separately
96 in order to get their value. This is currently oriented towards
97 PostgreSQL.
98
99 ``implicit_returning``
100 use RETURNING or equivalent during INSERT execution in order to load
101 newly generated primary keys and other column defaults in one execution,
102 which are then available via inserted_primary_key.
103 If an insert statement has returning() specified explicitly,
104 the "implicit" functionality is not used and inserted_primary_key
105 will not be available.
106
107 ``colspecs``
108 A dictionary of TypeEngine classes from sqlalchemy.types mapped
109 to subclasses that are specific to the dialect class. This
110 dictionary is class-level only and is not accessed from the
111 dialect instance itself.
112
113 ``supports_default_values``
114 Indicates if the construct ``INSERT INTO tablename DEFAULT
115 VALUES`` is supported
116
117 ``supports_sequences``
118 Indicates if the dialect supports CREATE SEQUENCE or similar.
119
120 ``sequences_optional``
121 If True, indicates if the "optional" flag on the Sequence() construct
122 should signal to not generate a CREATE SEQUENCE. Applies only to
123 dialects that support sequences. Currently used only to allow PostgreSQL
124 SERIAL to be used on a column that specifies Sequence() for usage on
125 other backends.
126
127 ``supports_native_enum``
128 Indicates if the dialect supports a native ENUM construct.
129 This will prevent types.Enum from generating a CHECK
130 constraint when that type is used.
131
132 ``supports_native_boolean``
133 Indicates if the dialect supports a native boolean construct.
134 This will prevent types.Boolean from generating a CHECK
135 constraint when that type is used.
136
137 ``dbapi_exception_translation_map``
138 A dictionary of names that will contain as values the names of
139 pep-249 exceptions ("IntegrityError", "OperationalError", etc)
140 keyed to alternate class names, to support the case where a
141 DBAPI has exception classes that aren't named as they are
142 referred to (e.g. IntegrityError = MyException). In the vast
143 majority of cases this dictionary is empty.
144
145 .. versionadded:: 1.0.5
146
147 """
148
149 _has_events = False
150
151 supports_statement_cache = True
152 """indicates if this dialect supports caching.
153
154 All dialects that are compatible with statement caching should set this
155 flag to True directly on each dialect class and subclass that supports
156 it. SQLAlchemy tests that this flag is locally present on each dialect
157 subclass before it will use statement caching. This is to provide
158 safety for legacy or new dialects that are not yet fully tested to be
159 compliant with SQL statement caching.
160
161 .. versionadded:: 1.4.5
162
163 .. seealso::
164
165 :ref:`engine_thirdparty_caching`
166
167 """
168
169 def create_connect_args(self, url):
170 """Build DB-API compatible connection arguments.
171
172 Given a :class:`.URL` object, returns a tuple
173 consisting of a ``(*args, **kwargs)`` suitable to send directly
174 to the dbapi's connect function. The arguments are sent to the
175 :meth:`.Dialect.connect` method which then runs the DBAPI-level
176 ``connect()`` function.
177
178 The method typically makes use of the
179 :meth:`.URL.translate_connect_args`
180 method in order to generate a dictionary of options.
181
182 The default implementation is::
183
184 def create_connect_args(self, url):
185 opts = url.translate_connect_args()
186 opts.update(url.query)
187 return [[], opts]
188
189 :param url: a :class:`.URL` object
190
191 :return: a tuple of ``(*args, **kwargs)`` which will be passed to the
192 :meth:`.Dialect.connect` method.
193
194 .. seealso::
195
196 :meth:`.URL.translate_connect_args`
197
198 """
199
200 raise NotImplementedError()
201
202 @classmethod
203 def type_descriptor(cls, typeobj):
204 """Transform a generic type to a dialect-specific type.
205
206 Dialect classes will usually use the
207 :func:`_types.adapt_type` function in the types module to
208 accomplish this.
209
210 The returned result is cached *per dialect class* so can
211 contain no dialect-instance state.
212
213 """
214
215 raise NotImplementedError()
216
217 def initialize(self, connection):
218 """Called during strategized creation of the dialect with a
219 connection.
220
221 Allows dialects to configure options based on server version info or
222 other properties.
223
224 The connection passed here is a SQLAlchemy Connection object,
225 with full capabilities.
226
227 The initialize() method of the base dialect should be called via
228 super().
229
230 .. note:: as of SQLAlchemy 1.4, this method is called **before**
231 any :meth:`_engine.Dialect.on_connect` hooks are called.
232
233 """
234
235 pass
236
237 def get_columns(self, connection, table_name, schema=None, **kw):
238 """Return information about columns in `table_name`.
239
240 Given a :class:`_engine.Connection`, a string
241 `table_name`, and an optional string `schema`, return column
242 information as a list of dictionaries with these keys:
243
244 name
245 the column's name
246
247 type
248 [sqlalchemy.types#TypeEngine]
249
250 nullable
251 boolean
252
253 default
254 the column's default value
255
256 autoincrement
257 boolean
258
259 sequence
260 a dictionary of the form
261 {'name' : str, 'start' :int, 'increment': int, 'minvalue': int,
262 'maxvalue': int, 'nominvalue': bool, 'nomaxvalue': bool,
263 'cycle': bool, 'cache': int, 'order': bool}
264
265 Additional column attributes may be present.
266 """
267
268 raise NotImplementedError()
269
270 def get_pk_constraint(self, connection, table_name, schema=None, **kw):
271 """Return information about the primary key constraint on
272 table_name`.
273
274 Given a :class:`_engine.Connection`, a string
275 `table_name`, and an optional string `schema`, return primary
276 key information as a dictionary with these keys:
277
278 constrained_columns
279 a list of column names that make up the primary key
280
281 name
282 optional name of the primary key constraint.
283
284 """
285 raise NotImplementedError()
286
287 def get_foreign_keys(self, connection, table_name, schema=None, **kw):
288 """Return information about foreign_keys in `table_name`.
289
290 Given a :class:`_engine.Connection`, a string
291 `table_name`, and an optional string `schema`, return foreign
292 key information as a list of dicts with these keys:
293
294 name
295 the constraint's name
296
297 constrained_columns
298 a list of column names that make up the foreign key
299
300 referred_schema
301 the name of the referred schema
302
303 referred_table
304 the name of the referred table
305
306 referred_columns
307 a list of column names in the referred table that correspond to
308 constrained_columns
309 """
310
311 raise NotImplementedError()
312
313 def get_table_names(self, connection, schema=None, **kw):
314 """Return a list of table names for `schema`."""
315
316 raise NotImplementedError()
317
318 def get_temp_table_names(self, connection, schema=None, **kw):
319 """Return a list of temporary table names on the given connection,
320 if supported by the underlying backend.
321
322 """
323
324 raise NotImplementedError()
325
326 def get_view_names(self, connection, schema=None, **kw):
327 """Return a list of all view names available in the database.
328
329 :param schema: schema name to query, if not the default schema.
330 """
331
332 raise NotImplementedError()
333
334 def get_sequence_names(self, connection, schema=None, **kw):
335 """Return a list of all sequence names available in the database.
336
337 :param schema: schema name to query, if not the default schema.
338
339 .. versionadded:: 1.4
340 """
341
342 raise NotImplementedError()
343
344 def get_temp_view_names(self, connection, schema=None, **kw):
345 """Return a list of temporary view names on the given connection,
346 if supported by the underlying backend.
347
348 """
349
350 raise NotImplementedError()
351
352 def get_view_definition(self, connection, view_name, schema=None, **kw):
353 """Return view definition.
354
355 Given a :class:`_engine.Connection`, a string
356 `view_name`, and an optional string `schema`, return the view
357 definition.
358 """
359
360 raise NotImplementedError()
361
362 def get_indexes(self, connection, table_name, schema=None, **kw):
363 """Return information about indexes in `table_name`.
364
365 Given a :class:`_engine.Connection`, a string
366 `table_name` and an optional string `schema`, return index
367 information as a list of dictionaries with these keys:
368
369 name
370 the index's name
371
372 column_names
373 list of column names in order
374
375 unique
376 boolean
377 """
378
379 raise NotImplementedError()
380
381 def get_unique_constraints(
382 self, connection, table_name, schema=None, **kw
383 ):
384 r"""Return information about unique constraints in `table_name`.
385
386 Given a string `table_name` and an optional string `schema`, return
387 unique constraint information as a list of dicts with these keys:
388
389 name
390 the unique constraint's name
391
392 column_names
393 list of column names in order
394
395 \**kw
396 other options passed to the dialect's get_unique_constraints()
397 method.
398
399 .. versionadded:: 0.9.0
400
401 """
402
403 raise NotImplementedError()
404
405 def get_check_constraints(self, connection, table_name, schema=None, **kw):
406 r"""Return information about check constraints in `table_name`.
407
408 Given a string `table_name` and an optional string `schema`, return
409 check constraint information as a list of dicts with these keys:
410
411 * ``name`` -
412 the check constraint's name
413
414 * ``sqltext`` -
415 the check constraint's SQL expression
416
417 * ``**kw`` -
418 other options passed to the dialect's get_check_constraints()
419 method.
420
421 .. versionadded:: 1.1.0
422
423 """
424
425 raise NotImplementedError()
426
427 def get_table_comment(self, connection, table_name, schema=None, **kw):
428 r"""Return the "comment" for the table identified by `table_name`.
429
430 Given a string `table_name` and an optional string `schema`, return
431 table comment information as a dictionary with this key:
432
433 text
434 text of the comment
435
436 Raises ``NotImplementedError`` for dialects that don't support
437 comments.
438
439 .. versionadded:: 1.2
440
441 """
442
443 raise NotImplementedError()
444
445 def normalize_name(self, name):
446 """convert the given name to lowercase if it is detected as
447 case insensitive.
448
449 This method is only used if the dialect defines
450 requires_name_normalize=True.
451
452 """
453 raise NotImplementedError()
454
455 def denormalize_name(self, name):
456 """convert the given name to a case insensitive identifier
457 for the backend if it is an all-lowercase name.
458
459 This method is only used if the dialect defines
460 requires_name_normalize=True.
461
462 """
463 raise NotImplementedError()
464
465 def has_table(self, connection, table_name, schema=None, **kw):
466 """For internal dialect use, check the existence of a particular table
467 in the database.
468
469 Given a :class:`_engine.Connection` object, a string table_name and
470 optional schema name, return True if the given table exists in the
471 database, False otherwise.
472
473 This method serves as the underlying implementation of the
474 public facing :meth:`.Inspector.has_table` method, and is also used
475 internally to implement the "checkfirst" behavior for methods like
476 :meth:`_schema.Table.create` and :meth:`_schema.MetaData.create_all`.
477
478 .. note:: This method is used internally by SQLAlchemy, and is
479 published so that third-party dialects may provide an
480 implementation. It is **not** the public API for checking for table
481 presence. Please use the :meth:`.Inspector.has_table` method.
482 Alternatively, for legacy cross-compatibility, the
483 :meth:`_engine.Engine.has_table` method may be used.
484
485 """
486
487 raise NotImplementedError()
488
489 def has_index(self, connection, table_name, index_name, schema=None):
490 """Check the existence of a particular index name in the database.
491
492 Given a :class:`_engine.Connection` object, a string
493 `table_name` and string index name, return True if an index of the
494 given name on the given table exists, false otherwise.
495
496 The :class:`.DefaultDialect` implements this in terms of the
497 :meth:`.Dialect.has_table` and :meth:`.Dialect.get_indexes` methods,
498 however dialects can implement a more performant version.
499
500
501 .. versionadded:: 1.4
502
503 """
504
505 raise NotImplementedError()
506
507 def has_sequence(self, connection, sequence_name, schema=None, **kw):
508 """Check the existence of a particular sequence in the database.
509
510 Given a :class:`_engine.Connection` object and a string
511 `sequence_name`, return True if the given sequence exists in
512 the database, False otherwise.
513 """
514
515 raise NotImplementedError()
516
517 def _get_server_version_info(self, connection):
518 """Retrieve the server version info from the given connection.
519
520 This is used by the default implementation to populate the
521 "server_version_info" attribute and is called exactly
522 once upon first connect.
523
524 """
525
526 raise NotImplementedError()
527
528 def _get_default_schema_name(self, connection):
529 """Return the string name of the currently selected schema from
530 the given connection.
531
532 This is used by the default implementation to populate the
533 "default_schema_name" attribute and is called exactly
534 once upon first connect.
535
536 """
537
538 raise NotImplementedError()
539
540 def do_begin(self, dbapi_connection):
541 """Provide an implementation of ``connection.begin()``, given a
542 DB-API connection.
543
544 The DBAPI has no dedicated "begin" method and it is expected
545 that transactions are implicit. This hook is provided for those
546 DBAPIs that might need additional help in this area.
547
548 Note that :meth:`.Dialect.do_begin` is not called unless a
549 :class:`.Transaction` object is in use. The
550 :meth:`.Dialect.do_autocommit`
551 hook is provided for DBAPIs that need some extra commands emitted
552 after a commit in order to enter the next transaction, when the
553 SQLAlchemy :class:`_engine.Connection`
554 is used in its default "autocommit"
555 mode.
556
557 :param dbapi_connection: a DBAPI connection, typically
558 proxied within a :class:`.ConnectionFairy`.
559
560 """
561
562 raise NotImplementedError()
563
564 def do_rollback(self, dbapi_connection):
565 """Provide an implementation of ``connection.rollback()``, given
566 a DB-API connection.
567
568 :param dbapi_connection: a DBAPI connection, typically
569 proxied within a :class:`.ConnectionFairy`.
570
571 """
572
573 raise NotImplementedError()
574
575 def do_commit(self, dbapi_connection):
576 """Provide an implementation of ``connection.commit()``, given a
577 DB-API connection.
578
579 :param dbapi_connection: a DBAPI connection, typically
580 proxied within a :class:`.ConnectionFairy`.
581
582 """
583
584 raise NotImplementedError()
585
586 def do_terminate(self, dbapi_connection):
587 """Provide an implementation of ``connection.close()`` that tries as
588 much as possible to not block, given a DBAPI
589 connection.
590
591 In the vast majority of cases this just calls .close(), however
592 for some asyncio dialects may call upon different API features.
593
594 This hook is called by the :class:`_pool.Pool`
595 when a connection is being recycled or has been invalidated.
596
597 .. versionadded:: 1.4.41
598
599 """
600
601 raise NotImplementedError()
602
603 def do_close(self, dbapi_connection):
604 """Provide an implementation of ``connection.close()``, given a DBAPI
605 connection.
606
607 This hook is called by the :class:`_pool.Pool`
608 when a connection has been
609 detached from the pool, or is being returned beyond the normal
610 capacity of the pool.
611
612 """
613
614 raise NotImplementedError()
615
616 def do_set_input_sizes(self, cursor, list_of_tuples, context):
617 """invoke the cursor.setinputsizes() method with appropriate arguments
618
619 This hook is called if the dialect.use_inputsizes flag is set to True.
620 Parameter data is passed in a list of tuples (paramname, dbtype,
621 sqltype), where ``paramname`` is the key of the parameter in the
622 statement, ``dbtype`` is the DBAPI datatype and ``sqltype`` is the
623 SQLAlchemy type. The order of tuples is in the correct parameter order.
624
625 .. versionadded:: 1.4
626
627
628 """
629 raise NotImplementedError()
630
631 def create_xid(self):
632 """Create a two-phase transaction ID.
633
634 This id will be passed to do_begin_twophase(),
635 do_rollback_twophase(), do_commit_twophase(). Its format is
636 unspecified.
637 """
638
639 raise NotImplementedError()
640
641 def do_savepoint(self, connection, name):
642 """Create a savepoint with the given name.
643
644 :param connection: a :class:`_engine.Connection`.
645 :param name: savepoint name.
646
647 """
648
649 raise NotImplementedError()
650
651 def do_rollback_to_savepoint(self, connection, name):
652 """Rollback a connection to the named savepoint.
653
654 :param connection: a :class:`_engine.Connection`.
655 :param name: savepoint name.
656
657 """
658
659 raise NotImplementedError()
660
661 def do_release_savepoint(self, connection, name):
662 """Release the named savepoint on a connection.
663
664 :param connection: a :class:`_engine.Connection`.
665 :param name: savepoint name.
666 """
667
668 raise NotImplementedError()
669
670 def do_begin_twophase(self, connection, xid):
671 """Begin a two phase transaction on the given connection.
672
673 :param connection: a :class:`_engine.Connection`.
674 :param xid: xid
675
676 """
677
678 raise NotImplementedError()
679
680 def do_prepare_twophase(self, connection, xid):
681 """Prepare a two phase transaction on the given connection.
682
683 :param connection: a :class:`_engine.Connection`.
684 :param xid: xid
685
686 """
687
688 raise NotImplementedError()
689
690 def do_rollback_twophase(
691 self, connection, xid, is_prepared=True, recover=False
692 ):
693 """Rollback a two phase transaction on the given connection.
694
695 :param connection: a :class:`_engine.Connection`.
696 :param xid: xid
697 :param is_prepared: whether or not
698 :meth:`.TwoPhaseTransaction.prepare` was called.
699 :param recover: if the recover flag was passed.
700
701 """
702
703 raise NotImplementedError()
704
705 def do_commit_twophase(
706 self, connection, xid, is_prepared=True, recover=False
707 ):
708 """Commit a two phase transaction on the given connection.
709
710
711 :param connection: a :class:`_engine.Connection`.
712 :param xid: xid
713 :param is_prepared: whether or not
714 :meth:`.TwoPhaseTransaction.prepare` was called.
715 :param recover: if the recover flag was passed.
716
717 """
718
719 raise NotImplementedError()
720
721 def do_recover_twophase(self, connection):
722 """Recover list of uncommitted prepared two phase transaction
723 identifiers on the given connection.
724
725 :param connection: a :class:`_engine.Connection`.
726
727 """
728
729 raise NotImplementedError()
730
731 def do_executemany(self, cursor, statement, parameters, context=None):
732 """Provide an implementation of ``cursor.executemany(statement,
733 parameters)``."""
734
735 raise NotImplementedError()
736
737 def do_execute(self, cursor, statement, parameters, context=None):
738 """Provide an implementation of ``cursor.execute(statement,
739 parameters)``."""
740
741 raise NotImplementedError()
742
743 def do_execute_no_params(
744 self, cursor, statement, parameters, context=None
745 ):
746 """Provide an implementation of ``cursor.execute(statement)``.
747
748 The parameter collection should not be sent.
749
750 """
751
752 raise NotImplementedError()
753
754 def is_disconnect(self, e, connection, cursor):
755 """Return True if the given DB-API error indicates an invalid
756 connection"""
757
758 raise NotImplementedError()
759
760 def connect(self, *cargs, **cparams):
761 r"""Establish a connection using this dialect's DBAPI.
762
763 The default implementation of this method is::
764
765 def connect(self, *cargs, **cparams):
766 return self.dbapi.connect(*cargs, **cparams)
767
768 The ``*cargs, **cparams`` parameters are generated directly
769 from this dialect's :meth:`.Dialect.create_connect_args` method.
770
771 This method may be used for dialects that need to perform programmatic
772 per-connection steps when a new connection is procured from the
773 DBAPI.
774
775
776 :param \*cargs: positional parameters returned from the
777 :meth:`.Dialect.create_connect_args` method
778
779 :param \*\*cparams: keyword parameters returned from the
780 :meth:`.Dialect.create_connect_args` method.
781
782 :return: a DBAPI connection, typically from the :pep:`249` module
783 level ``.connect()`` function.
784
785 .. seealso::
786
787 :meth:`.Dialect.create_connect_args`
788
789 :meth:`.Dialect.on_connect`
790
791 """
792
793 def on_connect_url(self, url):
794 """return a callable which sets up a newly created DBAPI connection.
795
796 This method is a new hook that supersedes the
797 :meth:`_engine.Dialect.on_connect` method when implemented by a
798 dialect. When not implemented by a dialect, it invokes the
799 :meth:`_engine.Dialect.on_connect` method directly to maintain
800 compatibility with existing dialects. There is no deprecation
801 for :meth:`_engine.Dialect.on_connect` expected.
802
803 The callable should accept a single argument "conn" which is the
804 DBAPI connection itself. The inner callable has no
805 return value.
806
807 E.g.::
808
809 class MyDialect(default.DefaultDialect):
810 # ...
811
812 def on_connect_url(self, url):
813 def do_on_connect(connection):
814 connection.execute("SET SPECIAL FLAGS etc")
815
816 return do_on_connect
817
818 This is used to set dialect-wide per-connection options such as
819 isolation modes, Unicode modes, etc.
820
821 This method differs from :meth:`_engine.Dialect.on_connect` in that
822 it is passed the :class:`_engine.URL` object that's relevant to the
823 connect args. Normally the only way to get this is from the
824 :meth:`_engine.Dialect.on_connect` hook is to look on the
825 :class:`_engine.Engine` itself, however this URL object may have been
826 replaced by plugins.
827
828 .. note::
829
830 The default implementation of
831 :meth:`_engine.Dialect.on_connect_url` is to invoke the
832 :meth:`_engine.Dialect.on_connect` method. Therefore if a dialect
833 implements this method, the :meth:`_engine.Dialect.on_connect`
834 method **will not be called** unless the overriding dialect calls
835 it directly from here.
836
837 .. versionadded:: 1.4.3 added :meth:`_engine.Dialect.on_connect_url`
838 which normally calls into :meth:`_engine.Dialect.on_connect`.
839
840 :param url: a :class:`_engine.URL` object representing the
841 :class:`_engine.URL` that was passed to the
842 :meth:`_engine.Dialect.create_connect_args` method.
843
844 :return: a callable that accepts a single DBAPI connection as an
845 argument, or None.
846
847 .. seealso::
848
849 :meth:`_engine.Dialect.on_connect`
850
851 """
852 return self.on_connect()
853
854 def on_connect(self):
855 """return a callable which sets up a newly created DBAPI connection.
856
857 The callable should accept a single argument "conn" which is the
858 DBAPI connection itself. The inner callable has no
859 return value.
860
861 E.g.::
862
863 class MyDialect(default.DefaultDialect):
864 # ...
865
866 def on_connect(self):
867 def do_on_connect(connection):
868 connection.execute("SET SPECIAL FLAGS etc")
869
870 return do_on_connect
871
872 This is used to set dialect-wide per-connection options such as
873 isolation modes, Unicode modes, etc.
874
875 The "do_on_connect" callable is invoked by using the
876 :meth:`_events.PoolEvents.connect` event
877 hook, then unwrapping the DBAPI connection and passing it into the
878 callable.
879
880 .. versionchanged:: 1.4 the on_connect hook is no longer called twice
881 for the first connection of a dialect. The on_connect hook is still
882 called before the :meth:`_engine.Dialect.initialize` method however.
883
884 .. versionchanged:: 1.4.3 the on_connect hook is invoked from a new
885 method on_connect_url that passes the URL that was used to create
886 the connect args. Dialects can implement on_connect_url instead
887 of on_connect if they need the URL object that was used for the
888 connection in order to get additional context.
889
890 If None is returned, no event listener is generated.
891
892 :return: a callable that accepts a single DBAPI connection as an
893 argument, or None.
894
895 .. seealso::
896
897 :meth:`.Dialect.connect` - allows the DBAPI ``connect()`` sequence
898 itself to be controlled.
899
900 :meth:`.Dialect.on_connect_url` - supersedes
901 :meth:`.Dialect.on_connect` to also receive the
902 :class:`_engine.URL` object in context.
903
904 """
905 return None
906
907 def reset_isolation_level(self, dbapi_conn):
908 """Given a DBAPI connection, revert its isolation to the default.
909
910 Note that this is a dialect-level method which is used as part
911 of the implementation of the :class:`_engine.Connection` and
912 :class:`_engine.Engine`
913 isolation level facilities; these APIs should be preferred for
914 most typical use cases.
915
916 .. seealso::
917
918 :meth:`_engine.Connection.get_isolation_level`
919 - view current level
920
921 :attr:`_engine.Connection.default_isolation_level`
922 - view default level
923
924 :paramref:`.Connection.execution_options.isolation_level` -
925 set per :class:`_engine.Connection` isolation level
926
927 :paramref:`_sa.create_engine.isolation_level` -
928 set per :class:`_engine.Engine` isolation level
929
930 """
931
932 raise NotImplementedError()
933
934 def set_isolation_level(self, dbapi_conn, level):
935 """Given a DBAPI connection, set its isolation level.
936
937 Note that this is a dialect-level method which is used as part
938 of the implementation of the :class:`_engine.Connection` and
939 :class:`_engine.Engine`
940 isolation level facilities; these APIs should be preferred for
941 most typical use cases.
942
943 .. seealso::
944
945 :meth:`_engine.Connection.get_isolation_level`
946 - view current level
947
948 :attr:`_engine.Connection.default_isolation_level`
949 - view default level
950
951 :paramref:`.Connection.execution_options.isolation_level` -
952 set per :class:`_engine.Connection` isolation level
953
954 :paramref:`_sa.create_engine.isolation_level` -
955 set per :class:`_engine.Engine` isolation level
956
957 """
958
959 raise NotImplementedError()
960
961 def get_isolation_level(self, dbapi_conn):
962 """Given a DBAPI connection, return its isolation level.
963
964 When working with a :class:`_engine.Connection` object,
965 the corresponding
966 DBAPI connection may be procured using the
967 :attr:`_engine.Connection.connection` accessor.
968
969 Note that this is a dialect-level method which is used as part
970 of the implementation of the :class:`_engine.Connection` and
971 :class:`_engine.Engine` isolation level facilities;
972 these APIs should be preferred for most typical use cases.
973
974
975 .. seealso::
976
977 :meth:`_engine.Connection.get_isolation_level`
978 - view current level
979
980 :attr:`_engine.Connection.default_isolation_level`
981 - view default level
982
983 :paramref:`.Connection.execution_options.isolation_level` -
984 set per :class:`_engine.Connection` isolation level
985
986 :paramref:`_sa.create_engine.isolation_level` -
987 set per :class:`_engine.Engine` isolation level
988
989
990 """
991
992 raise NotImplementedError()
993
994 def get_default_isolation_level(self, dbapi_conn):
995 """Given a DBAPI connection, return its isolation level, or
996 a default isolation level if one cannot be retrieved.
997
998 This method may only raise NotImplementedError and
999 **must not raise any other exception**, as it is used implicitly upon
1000 first connect.
1001
1002 The method **must return a value** for a dialect that supports
1003 isolation level settings, as this level is what will be reverted
1004 towards when a per-connection isolation level change is made.
1005
1006 The method defaults to using the :meth:`.Dialect.get_isolation_level`
1007 method unless overridden by a dialect.
1008
1009 .. versionadded:: 1.3.22
1010
1011 """
1012 raise NotImplementedError()
1013
1014 @classmethod
1015 def get_dialect_cls(cls, url):
1016 """Given a URL, return the :class:`.Dialect` that will be used.
1017
1018 This is a hook that allows an external plugin to provide functionality
1019 around an existing dialect, by allowing the plugin to be loaded
1020 from the url based on an entrypoint, and then the plugin returns
1021 the actual dialect to be used.
1022
1023 By default this just returns the cls.
1024
1025 .. versionadded:: 1.0.3
1026
1027 """
1028 return cls
1029
1030 @classmethod
1031 def load_provisioning(cls):
1032 """set up the provision.py module for this dialect.
1033
1034 For dialects that include a provision.py module that sets up
1035 provisioning followers, this method should initiate that process.
1036
1037 A typical implementation would be::
1038
1039 @classmethod
1040 def load_provisioning(cls):
1041 __import__("mydialect.provision")
1042
1043 The default method assumes a module named ``provision.py`` inside
1044 the owning package of the current dialect, based on the ``__module__``
1045 attribute::
1046
1047 @classmethod
1048 def load_provisioning(cls):
1049 package = ".".join(cls.__module__.split(".")[0:-1])
1050 try:
1051 __import__(package + ".provision")
1052 except ImportError:
1053 pass
1054
1055 .. versionadded:: 1.3.14
1056
1057 """
1058
1059 @classmethod
1060 def engine_created(cls, engine):
1061 """A convenience hook called before returning the final
1062 :class:`_engine.Engine`.
1063
1064 If the dialect returned a different class from the
1065 :meth:`.get_dialect_cls`
1066 method, then the hook is called on both classes, first on
1067 the dialect class returned by the :meth:`.get_dialect_cls` method and
1068 then on the class on which the method was called.
1069
1070 The hook should be used by dialects and/or wrappers to apply special
1071 events to the engine or its components. In particular, it allows
1072 a dialect-wrapping class to apply dialect-level events.
1073
1074 .. versionadded:: 1.0.3
1075
1076 """
1077
1078 def get_driver_connection(self, connection):
1079 """Returns the connection object as returned by the external driver
1080 package.
1081
1082 For normal dialects that use a DBAPI compliant driver this call
1083 will just return the ``connection`` passed as argument.
1084 For dialects that instead adapt a non DBAPI compliant driver, like
1085 when adapting an asyncio driver, this call will return the
1086 connection-like object as returned by the driver.
1087
1088 .. versionadded:: 1.4.24
1089
1090 """
1091 raise NotImplementedError()
1092
1093
1094class CreateEnginePlugin(object):
1095 """A set of hooks intended to augment the construction of an
1096 :class:`_engine.Engine` object based on entrypoint names in a URL.
1097
1098 The purpose of :class:`_engine.CreateEnginePlugin` is to allow third-party
1099 systems to apply engine, pool and dialect level event listeners without
1100 the need for the target application to be modified; instead, the plugin
1101 names can be added to the database URL. Target applications for
1102 :class:`_engine.CreateEnginePlugin` include:
1103
1104 * connection and SQL performance tools, e.g. which use events to track
1105 number of checkouts and/or time spent with statements
1106
1107 * connectivity plugins such as proxies
1108
1109 A rudimentary :class:`_engine.CreateEnginePlugin` that attaches a logger
1110 to an :class:`_engine.Engine` object might look like::
1111
1112
1113 import logging
1114
1115 from sqlalchemy.engine import CreateEnginePlugin
1116 from sqlalchemy import event
1117
1118 class LogCursorEventsPlugin(CreateEnginePlugin):
1119 def __init__(self, url, kwargs):
1120 # consume the parameter "log_cursor_logging_name" from the
1121 # URL query
1122 logging_name = url.query.get("log_cursor_logging_name", "log_cursor")
1123
1124 self.log = logging.getLogger(logging_name)
1125
1126 def update_url(self, url):
1127 "update the URL to one that no longer includes our parameters"
1128 return url.difference_update_query(["log_cursor_logging_name"])
1129
1130 def engine_created(self, engine):
1131 "attach an event listener after the new Engine is constructed"
1132 event.listen(engine, "before_cursor_execute", self._log_event)
1133
1134
1135 def _log_event(
1136 self,
1137 conn,
1138 cursor,
1139 statement,
1140 parameters,
1141 context,
1142 executemany):
1143
1144 self.log.info("Plugin logged cursor event: %s", statement)
1145
1146
1147
1148 Plugins are registered using entry points in a similar way as that
1149 of dialects::
1150
1151 entry_points={
1152 'sqlalchemy.plugins': [
1153 'log_cursor_plugin = myapp.plugins:LogCursorEventsPlugin'
1154 ]
1155
1156 A plugin that uses the above names would be invoked from a database
1157 URL as in::
1158
1159 from sqlalchemy import create_engine
1160
1161 engine = create_engine(
1162 "mysql+pymysql://scott:tiger@localhost/test?"
1163 "plugin=log_cursor_plugin&log_cursor_logging_name=mylogger"
1164 )
1165
1166 The ``plugin`` URL parameter supports multiple instances, so that a URL
1167 may specify multiple plugins; they are loaded in the order stated
1168 in the URL::
1169
1170 engine = create_engine(
1171 "mysql+pymysql://scott:tiger@localhost/test?"
1172 "plugin=plugin_one&plugin=plugin_twp&plugin=plugin_three")
1173
1174 The plugin names may also be passed directly to :func:`_sa.create_engine`
1175 using the :paramref:`_sa.create_engine.plugins` argument::
1176
1177 engine = create_engine(
1178 "mysql+pymysql://scott:tiger@localhost/test",
1179 plugins=["myplugin"])
1180
1181 .. versionadded:: 1.2.3 plugin names can also be specified
1182 to :func:`_sa.create_engine` as a list
1183
1184 A plugin may consume plugin-specific arguments from the
1185 :class:`_engine.URL` object as well as the ``kwargs`` dictionary, which is
1186 the dictionary of arguments passed to the :func:`_sa.create_engine`
1187 call. "Consuming" these arguments includes that they must be removed
1188 when the plugin initializes, so that the arguments are not passed along
1189 to the :class:`_engine.Dialect` constructor, where they will raise an
1190 :class:`_exc.ArgumentError` because they are not known by the dialect.
1191
1192 As of version 1.4 of SQLAlchemy, arguments should continue to be consumed
1193 from the ``kwargs`` dictionary directly, by removing the values with a
1194 method such as ``dict.pop``. Arguments from the :class:`_engine.URL` object
1195 should be consumed by implementing the
1196 :meth:`_engine.CreateEnginePlugin.update_url` method, returning a new copy
1197 of the :class:`_engine.URL` with plugin-specific parameters removed::
1198
1199 class MyPlugin(CreateEnginePlugin):
1200 def __init__(self, url, kwargs):
1201 self.my_argument_one = url.query['my_argument_one']
1202 self.my_argument_two = url.query['my_argument_two']
1203 self.my_argument_three = kwargs.pop('my_argument_three', None)
1204
1205 def update_url(self, url):
1206 return url.difference_update_query(
1207 ["my_argument_one", "my_argument_two"]
1208 )
1209
1210 Arguments like those illustrated above would be consumed from a
1211 :func:`_sa.create_engine` call such as::
1212
1213 from sqlalchemy import create_engine
1214
1215 engine = create_engine(
1216 "mysql+pymysql://scott:tiger@localhost/test?"
1217 "plugin=myplugin&my_argument_one=foo&my_argument_two=bar",
1218 my_argument_three='bat'
1219 )
1220
1221 .. versionchanged:: 1.4
1222
1223 The :class:`_engine.URL` object is now immutable; a
1224 :class:`_engine.CreateEnginePlugin` that needs to alter the
1225 :class:`_engine.URL` should implement the newly added
1226 :meth:`_engine.CreateEnginePlugin.update_url` method, which
1227 is invoked after the plugin is constructed.
1228
1229 For migration, construct the plugin in the following way, checking
1230 for the existence of the :meth:`_engine.CreateEnginePlugin.update_url`
1231 method to detect which version is running::
1232
1233 class MyPlugin(CreateEnginePlugin):
1234 def __init__(self, url, kwargs):
1235 if hasattr(CreateEnginePlugin, "update_url"):
1236 # detect the 1.4 API
1237 self.my_argument_one = url.query['my_argument_one']
1238 self.my_argument_two = url.query['my_argument_two']
1239 else:
1240 # detect the 1.3 and earlier API - mutate the
1241 # URL directly
1242 self.my_argument_one = url.query.pop('my_argument_one')
1243 self.my_argument_two = url.query.pop('my_argument_two')
1244
1245 self.my_argument_three = kwargs.pop('my_argument_three', None)
1246
1247 def update_url(self, url):
1248 # this method is only called in the 1.4 version
1249 return url.difference_update_query(
1250 ["my_argument_one", "my_argument_two"]
1251 )
1252
1253 .. seealso::
1254
1255 :ref:`change_5526` - overview of the :class:`_engine.URL` change which
1256 also includes notes regarding :class:`_engine.CreateEnginePlugin`.
1257
1258
1259 When the engine creation process completes and produces the
1260 :class:`_engine.Engine` object, it is again passed to the plugin via the
1261 :meth:`_engine.CreateEnginePlugin.engine_created` hook. In this hook, additional
1262 changes can be made to the engine, most typically involving setup of
1263 events (e.g. those defined in :ref:`core_event_toplevel`).
1264
1265 .. versionadded:: 1.1
1266
1267 """ # noqa: E501
1268
1269 def __init__(self, url, kwargs):
1270 """Construct a new :class:`.CreateEnginePlugin`.
1271
1272 The plugin object is instantiated individually for each call
1273 to :func:`_sa.create_engine`. A single :class:`_engine.
1274 Engine` will be
1275 passed to the :meth:`.CreateEnginePlugin.engine_created` method
1276 corresponding to this URL.
1277
1278 :param url: the :class:`_engine.URL` object. The plugin may inspect
1279 the :class:`_engine.URL` for arguments. Arguments used by the
1280 plugin should be removed, by returning an updated :class:`_engine.URL`
1281 from the :meth:`_engine.CreateEnginePlugin.update_url` method.
1282
1283 .. versionchanged:: 1.4
1284
1285 The :class:`_engine.URL` object is now immutable, so a
1286 :class:`_engine.CreateEnginePlugin` that needs to alter the
1287 :class:`_engine.URL` object should implement the
1288 :meth:`_engine.CreateEnginePlugin.update_url` method.
1289
1290 :param kwargs: The keyword arguments passed to
1291 :func:`_sa.create_engine`.
1292
1293 """
1294 self.url = url
1295
1296 def update_url(self, url):
1297 """Update the :class:`_engine.URL`.
1298
1299 A new :class:`_engine.URL` should be returned. This method is
1300 typically used to consume configuration arguments from the
1301 :class:`_engine.URL` which must be removed, as they will not be
1302 recognized by the dialect. The
1303 :meth:`_engine.URL.difference_update_query` method is available
1304 to remove these arguments. See the docstring at
1305 :class:`_engine.CreateEnginePlugin` for an example.
1306
1307
1308 .. versionadded:: 1.4
1309
1310 """
1311
1312 def handle_dialect_kwargs(self, dialect_cls, dialect_args):
1313 """parse and modify dialect kwargs"""
1314
1315 def handle_pool_kwargs(self, pool_cls, pool_args):
1316 """parse and modify pool kwargs"""
1317
1318 def engine_created(self, engine):
1319 """Receive the :class:`_engine.Engine`
1320 object when it is fully constructed.
1321
1322 The plugin may make additional changes to the engine, such as
1323 registering engine or connection pool events.
1324
1325 """
1326
1327
1328class ExecutionContext(object):
1329 """A messenger object for a Dialect that corresponds to a single
1330 execution.
1331
1332 ExecutionContext should have these data members:
1333
1334 connection
1335 Connection object which can be freely used by default value
1336 generators to execute SQL. This Connection should reference the
1337 same underlying connection/transactional resources of
1338 root_connection.
1339
1340 root_connection
1341 Connection object which is the source of this ExecutionContext. This
1342 Connection may have close_with_result=True set, in which case it can
1343 only be used once.
1344
1345 dialect
1346 dialect which created this ExecutionContext.
1347
1348 cursor
1349 DB-API cursor procured from the connection,
1350
1351 compiled
1352 if passed to constructor, sqlalchemy.engine.base.Compiled object
1353 being executed,
1354
1355 statement
1356 string version of the statement to be executed. Is either
1357 passed to the constructor, or must be created from the
1358 sql.Compiled object by the time pre_exec() has completed.
1359
1360 parameters
1361 bind parameters passed to the execute() method. For compiled
1362 statements, this is a dictionary or list of dictionaries. For
1363 textual statements, it should be in a format suitable for the
1364 dialect's paramstyle (i.e. dict or list of dicts for non
1365 positional, list or list of lists/tuples for positional).
1366
1367 isinsert
1368 True if the statement is an INSERT.
1369
1370 isupdate
1371 True if the statement is an UPDATE.
1372
1373 should_autocommit
1374 True if the statement is a "committable" statement.
1375
1376 prefetch_cols
1377 a list of Column objects for which a client-side default
1378 was fired off. Applies to inserts and updates.
1379
1380 postfetch_cols
1381 a list of Column objects for which a server-side default or
1382 inline SQL expression value was fired off. Applies to inserts
1383 and updates.
1384 """
1385
1386 def create_cursor(self):
1387 """Return a new cursor generated from this ExecutionContext's
1388 connection.
1389
1390 Some dialects may wish to change the behavior of
1391 connection.cursor(), such as postgresql which may return a PG
1392 "server side" cursor.
1393 """
1394
1395 raise NotImplementedError()
1396
1397 def pre_exec(self):
1398 """Called before an execution of a compiled statement.
1399
1400 If a compiled statement was passed to this ExecutionContext,
1401 the `statement` and `parameters` datamembers must be
1402 initialized after this statement is complete.
1403 """
1404
1405 raise NotImplementedError()
1406
1407 def get_out_parameter_values(self, out_param_names):
1408 """Return a sequence of OUT parameter values from a cursor.
1409
1410 For dialects that support OUT parameters, this method will be called
1411 when there is a :class:`.SQLCompiler` object which has the
1412 :attr:`.SQLCompiler.has_out_parameters` flag set. This flag in turn
1413 will be set to True if the statement itself has :class:`.BindParameter`
1414 objects that have the ``.isoutparam`` flag set which are consumed by
1415 the :meth:`.SQLCompiler.visit_bindparam` method. If the dialect
1416 compiler produces :class:`.BindParameter` objects with ``.isoutparam``
1417 set which are not handled by :meth:`.SQLCompiler.visit_bindparam`, it
1418 should set this flag explicitly.
1419
1420 The list of names that were rendered for each bound parameter
1421 is passed to the method. The method should then return a sequence of
1422 values corresponding to the list of parameter objects. Unlike in
1423 previous SQLAlchemy versions, the values can be the **raw values** from
1424 the DBAPI; the execution context will apply the appropriate type
1425 handler based on what's present in self.compiled.binds and update the
1426 values. The processed dictionary will then be made available via the
1427 ``.out_parameters`` collection on the result object. Note that
1428 SQLAlchemy 1.4 has multiple kinds of result object as part of the 2.0
1429 transition.
1430
1431 .. versionadded:: 1.4 - added
1432 :meth:`.ExecutionContext.get_out_parameter_values`, which is invoked
1433 automatically by the :class:`.DefaultExecutionContext` when there
1434 are :class:`.BindParameter` objects with the ``.isoutparam`` flag
1435 set. This replaces the practice of setting out parameters within
1436 the now-removed ``get_result_proxy()`` method.
1437
1438 """
1439 raise NotImplementedError()
1440
1441 def post_exec(self):
1442 """Called after the execution of a compiled statement.
1443
1444 If a compiled statement was passed to this ExecutionContext,
1445 the `last_insert_ids`, `last_inserted_params`, etc.
1446 datamembers should be available after this method completes.
1447 """
1448
1449 raise NotImplementedError()
1450
1451 def handle_dbapi_exception(self, e):
1452 """Receive a DBAPI exception which occurred upon execute, result
1453 fetch, etc."""
1454
1455 raise NotImplementedError()
1456
1457 def should_autocommit_text(self, statement):
1458 """Parse the given textual statement and return True if it refers to
1459 a "committable" statement"""
1460
1461 raise NotImplementedError()
1462
1463 def lastrow_has_defaults(self):
1464 """Return True if the last INSERT or UPDATE row contained
1465 inlined or database-side defaults.
1466 """
1467
1468 raise NotImplementedError()
1469
1470 def get_rowcount(self):
1471 """Return the DBAPI ``cursor.rowcount`` value, or in some
1472 cases an interpreted value.
1473
1474 See :attr:`_engine.CursorResult.rowcount` for details on this.
1475
1476 """
1477
1478 raise NotImplementedError()
1479
1480
1481@util.deprecated_20_cls(
1482 ":class:`.Connectable`",
1483 alternative=(
1484 "The :class:`_engine.Engine` will be the only Core "
1485 "object that features a .connect() method, and the "
1486 ":class:`_engine.Connection` will be the only object that features "
1487 "an .execute() method."
1488 ),
1489 constructor=None,
1490)
1491class Connectable(object):
1492 """Interface for an object which supports execution of SQL constructs.
1493
1494 The two implementations of :class:`.Connectable` are
1495 :class:`_engine.Connection` and :class:`_engine.Engine`.
1496
1497 Connectable must also implement the 'dialect' member which references a
1498 :class:`.Dialect` instance.
1499
1500 """
1501
1502 def connect(self, **kwargs):
1503 """Return a :class:`_engine.Connection` object.
1504
1505 Depending on context, this may be ``self`` if this object
1506 is already an instance of :class:`_engine.Connection`, or a newly
1507 procured :class:`_engine.Connection` if this object is an instance
1508 of :class:`_engine.Engine`.
1509
1510 """
1511
1512 engine = None
1513 """The :class:`_engine.Engine` instance referred to by this
1514 :class:`.Connectable`.
1515
1516 May be ``self`` if this is already an :class:`_engine.Engine`.
1517
1518 """
1519
1520 def execute(self, object_, *multiparams, **params):
1521 """Executes the given construct and returns a
1522 :class:`_engine.CursorResult`.
1523 """
1524 raise NotImplementedError()
1525
1526 def scalar(self, object_, *multiparams, **params):
1527 """Executes and returns the first column of the first row.
1528
1529 The underlying cursor is closed after execution.
1530 """
1531 raise NotImplementedError()
1532
1533 def _run_visitor(self, visitorcallable, element, **kwargs):
1534 raise NotImplementedError()
1535
1536 def _execute_clauseelement(self, elem, multiparams=None, params=None):
1537 raise NotImplementedError()
1538
1539
1540class ExceptionContext(object):
1541 """Encapsulate information about an error condition in progress.
1542
1543 This object exists solely to be passed to the
1544 :meth:`_events.ConnectionEvents.handle_error` event,
1545 supporting an interface that
1546 can be extended without backwards-incompatibility.
1547
1548 .. versionadded:: 0.9.7
1549
1550 """
1551
1552 connection = None
1553 """The :class:`_engine.Connection` in use during the exception.
1554
1555 This member is present, except in the case of a failure when
1556 first connecting.
1557
1558 .. seealso::
1559
1560 :attr:`.ExceptionContext.engine`
1561
1562
1563 """
1564
1565 engine = None
1566 """The :class:`_engine.Engine` in use during the exception.
1567
1568 This member should always be present, even in the case of a failure
1569 when first connecting.
1570
1571 .. versionadded:: 1.0.0
1572
1573 """
1574
1575 cursor = None
1576 """The DBAPI cursor object.
1577
1578 May be None.
1579
1580 """
1581
1582 statement = None
1583 """String SQL statement that was emitted directly to the DBAPI.
1584
1585 May be None.
1586
1587 """
1588
1589 parameters = None
1590 """Parameter collection that was emitted directly to the DBAPI.
1591
1592 May be None.
1593
1594 """
1595
1596 original_exception = None
1597 """The exception object which was caught.
1598
1599 This member is always present.
1600
1601 """
1602
1603 sqlalchemy_exception = None
1604 """The :class:`sqlalchemy.exc.StatementError` which wraps the original,
1605 and will be raised if exception handling is not circumvented by the event.
1606
1607 May be None, as not all exception types are wrapped by SQLAlchemy.
1608 For DBAPI-level exceptions that subclass the dbapi's Error class, this
1609 field will always be present.
1610
1611 """
1612
1613 chained_exception = None
1614 """The exception that was returned by the previous handler in the
1615 exception chain, if any.
1616
1617 If present, this exception will be the one ultimately raised by
1618 SQLAlchemy unless a subsequent handler replaces it.
1619
1620 May be None.
1621
1622 """
1623
1624 execution_context = None
1625 """The :class:`.ExecutionContext` corresponding to the execution
1626 operation in progress.
1627
1628 This is present for statement execution operations, but not for
1629 operations such as transaction begin/end. It also is not present when
1630 the exception was raised before the :class:`.ExecutionContext`
1631 could be constructed.
1632
1633 Note that the :attr:`.ExceptionContext.statement` and
1634 :attr:`.ExceptionContext.parameters` members may represent a
1635 different value than that of the :class:`.ExecutionContext`,
1636 potentially in the case where a
1637 :meth:`_events.ConnectionEvents.before_cursor_execute` event or similar
1638 modified the statement/parameters to be sent.
1639
1640 May be None.
1641
1642 """
1643
1644 is_disconnect = None
1645 """Represent whether the exception as occurred represents a "disconnect"
1646 condition.
1647
1648 This flag will always be True or False within the scope of the
1649 :meth:`_events.ConnectionEvents.handle_error` handler.
1650
1651 SQLAlchemy will defer to this flag in order to determine whether or not
1652 the connection should be invalidated subsequently. That is, by
1653 assigning to this flag, a "disconnect" event which then results in
1654 a connection and pool invalidation can be invoked or prevented by
1655 changing this flag.
1656
1657
1658 .. note:: The pool "pre_ping" handler enabled using the
1659 :paramref:`_sa.create_engine.pool_pre_ping` parameter does **not**
1660 consult this event before deciding if the "ping" returned false,
1661 as opposed to receiving an unhandled error. For this use case, the
1662 :ref:`legacy recipe based on engine_connect() may be used
1663 <pool_disconnects_pessimistic_custom>`. A future API allow more
1664 comprehensive customization of the "disconnect" detection mechanism
1665 across all functions.
1666
1667 """
1668
1669 invalidate_pool_on_disconnect = True
1670 """Represent whether all connections in the pool should be invalidated
1671 when a "disconnect" condition is in effect.
1672
1673 Setting this flag to False within the scope of the
1674 :meth:`_events.ConnectionEvents.handle_error`
1675 event will have the effect such
1676 that the full collection of connections in the pool will not be
1677 invalidated during a disconnect; only the current connection that is the
1678 subject of the error will actually be invalidated.
1679
1680 The purpose of this flag is for custom disconnect-handling schemes where
1681 the invalidation of other connections in the pool is to be performed
1682 based on other conditions, or even on a per-connection basis.
1683
1684 .. versionadded:: 1.0.3
1685
1686 """
1687
1688
1689class AdaptedConnection(object):
1690 """Interface of an adapted connection object to support the DBAPI protocol.
1691
1692 Used by asyncio dialects to provide a sync-style pep-249 facade on top
1693 of the asyncio connection/cursor API provided by the driver.
1694
1695 .. versionadded:: 1.4.24
1696
1697 """
1698
1699 __slots__ = ("_connection",)
1700
1701 @property
1702 def driver_connection(self):
1703 """The connection object as returned by the driver after a connect."""
1704 return self._connection
1705
1706 def run_async(self, fn):
1707 """Run the awaitable returned by the given function, which is passed
1708 the raw asyncio driver connection.
1709
1710 This is used to invoke awaitable-only methods on the driver connection
1711 within the context of a "synchronous" method, like a connection
1712 pool event handler.
1713
1714 E.g.::
1715
1716 engine = create_async_engine(...)
1717
1718 @event.listens_for(engine.sync_engine, "connect")
1719 def register_custom_types(dbapi_connection, ...):
1720 dbapi_connection.run_async(
1721 lambda connection: connection.set_type_codec(
1722 'MyCustomType', encoder, decoder, ...
1723 )
1724 )
1725
1726 .. versionadded:: 1.4.30
1727
1728 .. seealso::
1729
1730 :ref:`asyncio_events_run_async`
1731
1732 """
1733 return await_only(fn(self._connection))
1734
1735 def __repr__(self):
1736 return "<AdaptedConnection %s>" % self._connection