123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829 |
- # sqlalchemy/engine/events.py
- # Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
- # <see AUTHORS file>
- #
- # This module is part of SQLAlchemy and is released under
- # the MIT License: https://www.opensource.org/licenses/mit-license.php
- from .base import Engine
- from .interfaces import Connectable
- from .interfaces import Dialect
- from .. import event
- from .. import exc
- class ConnectionEvents(event.Events):
- """Available events for :class:`.Connectable`, which includes
- :class:`_engine.Connection` and :class:`_engine.Engine`.
- The methods here define the name of an event as well as the names of
- members that are passed to listener functions.
- An event listener can be associated with any :class:`.Connectable`
- class or instance, such as an :class:`_engine.Engine`, e.g.::
- from sqlalchemy import event, create_engine
- def before_cursor_execute(conn, cursor, statement, parameters, context,
- executemany):
- log.info("Received statement: %s", statement)
- engine = create_engine('postgresql://scott:tiger@localhost/test')
- event.listen(engine, "before_cursor_execute", before_cursor_execute)
- or with a specific :class:`_engine.Connection`::
- with engine.begin() as conn:
- @event.listens_for(conn, 'before_cursor_execute')
- def before_cursor_execute(conn, cursor, statement, parameters,
- context, executemany):
- log.info("Received statement: %s", statement)
- When the methods are called with a `statement` parameter, such as in
- :meth:`.after_cursor_execute` or :meth:`.before_cursor_execute`,
- the statement is the exact SQL string that was prepared for transmission
- to the DBAPI ``cursor`` in the connection's :class:`.Dialect`.
- The :meth:`.before_execute` and :meth:`.before_cursor_execute`
- events can also be established with the ``retval=True`` flag, which
- allows modification of the statement and parameters to be sent
- to the database. The :meth:`.before_cursor_execute` event is
- particularly useful here to add ad-hoc string transformations, such
- as comments, to all executions::
- from sqlalchemy.engine import Engine
- from sqlalchemy import event
- @event.listens_for(Engine, "before_cursor_execute", retval=True)
- def comment_sql_calls(conn, cursor, statement, parameters,
- context, executemany):
- statement = statement + " -- some comment"
- return statement, parameters
- .. note:: :class:`_events.ConnectionEvents` can be established on any
- combination of :class:`_engine.Engine`, :class:`_engine.Connection`,
- as well
- as instances of each of those classes. Events across all
- four scopes will fire off for a given instance of
- :class:`_engine.Connection`. However, for performance reasons, the
- :class:`_engine.Connection` object determines at instantiation time
- whether or not its parent :class:`_engine.Engine` has event listeners
- established. Event listeners added to the :class:`_engine.Engine`
- class or to an instance of :class:`_engine.Engine`
- *after* the instantiation
- of a dependent :class:`_engine.Connection` instance will usually
- *not* be available on that :class:`_engine.Connection` instance.
- The newly
- added listeners will instead take effect for
- :class:`_engine.Connection`
- instances created subsequent to those event listeners being
- established on the parent :class:`_engine.Engine` class or instance.
- :param retval=False: Applies to the :meth:`.before_execute` and
- :meth:`.before_cursor_execute` events only. When True, the
- user-defined event function must have a return value, which
- is a tuple of parameters that replace the given statement
- and parameters. See those methods for a description of
- specific return arguments.
- """
- _target_class_doc = "SomeEngine"
- _dispatch_target = Connectable
- @classmethod
- def _listen(cls, event_key, retval=False):
- target, identifier, fn = (
- event_key.dispatch_target,
- event_key.identifier,
- event_key._listen_fn,
- )
- target._has_events = True
- if not retval:
- if identifier == "before_execute":
- orig_fn = fn
- def wrap_before_execute(
- conn, clauseelement, multiparams, params, execution_options
- ):
- orig_fn(
- conn,
- clauseelement,
- multiparams,
- params,
- execution_options,
- )
- return clauseelement, multiparams, params
- fn = wrap_before_execute
- elif identifier == "before_cursor_execute":
- orig_fn = fn
- def wrap_before_cursor_execute(
- conn, cursor, statement, parameters, context, executemany
- ):
- orig_fn(
- conn,
- cursor,
- statement,
- parameters,
- context,
- executemany,
- )
- return statement, parameters
- fn = wrap_before_cursor_execute
- elif retval and identifier not in (
- "before_execute",
- "before_cursor_execute",
- "handle_error",
- ):
- raise exc.ArgumentError(
- "Only the 'before_execute', "
- "'before_cursor_execute' and 'handle_error' engine "
- "event listeners accept the 'retval=True' "
- "argument."
- )
- event_key.with_wrapper(fn).base_listen()
- @event._legacy_signature(
- "1.4",
- ["conn", "clauseelement", "multiparams", "params"],
- lambda conn, clauseelement, multiparams, params, execution_options: (
- conn,
- clauseelement,
- multiparams,
- params,
- ),
- )
- def before_execute(
- self, conn, clauseelement, multiparams, params, execution_options
- ):
- """Intercept high level execute() events, receiving uncompiled
- SQL constructs and other objects prior to rendering into SQL.
- This event is good for debugging SQL compilation issues as well
- as early manipulation of the parameters being sent to the database,
- as the parameter lists will be in a consistent format here.
- This event can be optionally established with the ``retval=True``
- flag. The ``clauseelement``, ``multiparams``, and ``params``
- arguments should be returned as a three-tuple in this case::
- @event.listens_for(Engine, "before_execute", retval=True)
- def before_execute(conn, clauseelement, multiparams, params):
- # do something with clauseelement, multiparams, params
- return clauseelement, multiparams, params
- :param conn: :class:`_engine.Connection` object
- :param clauseelement: SQL expression construct, :class:`.Compiled`
- instance, or string statement passed to
- :meth:`_engine.Connection.execute`.
- :param multiparams: Multiple parameter sets, a list of dictionaries.
- :param params: Single parameter set, a single dictionary.
- :param execution_options: dictionary of execution
- options passed along with the statement, if any. This is a merge
- of all options that will be used, including those of the statement,
- the connection, and those passed in to the method itself for
- the 2.0 style of execution.
- .. versionadded: 1.4
- .. seealso::
- :meth:`.before_cursor_execute`
- """
- @event._legacy_signature(
- "1.4",
- ["conn", "clauseelement", "multiparams", "params", "result"],
- lambda conn, clauseelement, multiparams, params, execution_options, result: ( # noqa
- conn,
- clauseelement,
- multiparams,
- params,
- result,
- ),
- )
- def after_execute(
- self,
- conn,
- clauseelement,
- multiparams,
- params,
- execution_options,
- result,
- ):
- """Intercept high level execute() events after execute.
- :param conn: :class:`_engine.Connection` object
- :param clauseelement: SQL expression construct, :class:`.Compiled`
- instance, or string statement passed to
- :meth:`_engine.Connection.execute`.
- :param multiparams: Multiple parameter sets, a list of dictionaries.
- :param params: Single parameter set, a single dictionary.
- :param execution_options: dictionary of execution
- options passed along with the statement, if any. This is a merge
- of all options that will be used, including those of the statement,
- the connection, and those passed in to the method itself for
- the 2.0 style of execution.
- .. versionadded: 1.4
- :param result: :class:`_engine.CursorResult` generated by the
- execution.
- """
- def before_cursor_execute(
- self, conn, cursor, statement, parameters, context, executemany
- ):
- """Intercept low-level cursor execute() events before execution,
- receiving the string SQL statement and DBAPI-specific parameter list to
- be invoked against a cursor.
- This event is a good choice for logging as well as late modifications
- to the SQL string. It's less ideal for parameter modifications except
- for those which are specific to a target backend.
- This event can be optionally established with the ``retval=True``
- flag. The ``statement`` and ``parameters`` arguments should be
- returned as a two-tuple in this case::
- @event.listens_for(Engine, "before_cursor_execute", retval=True)
- def before_cursor_execute(conn, cursor, statement,
- parameters, context, executemany):
- # do something with statement, parameters
- return statement, parameters
- See the example at :class:`_events.ConnectionEvents`.
- :param conn: :class:`_engine.Connection` object
- :param cursor: DBAPI cursor object
- :param statement: string SQL statement, as to be passed to the DBAPI
- :param parameters: Dictionary, tuple, or list of parameters being
- passed to the ``execute()`` or ``executemany()`` method of the
- DBAPI ``cursor``. In some cases may be ``None``.
- :param context: :class:`.ExecutionContext` object in use. May
- be ``None``.
- :param executemany: boolean, if ``True``, this is an ``executemany()``
- call, if ``False``, this is an ``execute()`` call.
- .. seealso::
- :meth:`.before_execute`
- :meth:`.after_cursor_execute`
- """
- def after_cursor_execute(
- self, conn, cursor, statement, parameters, context, executemany
- ):
- """Intercept low-level cursor execute() events after execution.
- :param conn: :class:`_engine.Connection` object
- :param cursor: DBAPI cursor object. Will have results pending
- if the statement was a SELECT, but these should not be consumed
- as they will be needed by the :class:`_engine.CursorResult`.
- :param statement: string SQL statement, as passed to the DBAPI
- :param parameters: Dictionary, tuple, or list of parameters being
- passed to the ``execute()`` or ``executemany()`` method of the
- DBAPI ``cursor``. In some cases may be ``None``.
- :param context: :class:`.ExecutionContext` object in use. May
- be ``None``.
- :param executemany: boolean, if ``True``, this is an ``executemany()``
- call, if ``False``, this is an ``execute()`` call.
- """
- def handle_error(self, exception_context):
- r"""Intercept all exceptions processed by the
- :class:`_engine.Connection`.
- This includes all exceptions emitted by the DBAPI as well as
- within SQLAlchemy's statement invocation process, including
- encoding errors and other statement validation errors. Other areas
- in which the event is invoked include transaction begin and end,
- result row fetching, cursor creation.
- Note that :meth:`.handle_error` may support new kinds of exceptions
- and new calling scenarios at *any time*. Code which uses this
- event must expect new calling patterns to be present in minor
- releases.
- To support the wide variety of members that correspond to an exception,
- as well as to allow extensibility of the event without backwards
- incompatibility, the sole argument received is an instance of
- :class:`.ExceptionContext`. This object contains data members
- representing detail about the exception.
- Use cases supported by this hook include:
- * read-only, low-level exception handling for logging and
- debugging purposes
- * exception re-writing
- * Establishing or disabling whether a connection or the owning
- connection pool is invalidated or expired in response to a
- specific exception [1]_.
- The hook is called while the cursor from the failed operation
- (if any) is still open and accessible. Special cleanup operations
- can be called on this cursor; SQLAlchemy will attempt to close
- this cursor subsequent to this hook being invoked. If the connection
- is in "autocommit" mode, the transaction also remains open within
- the scope of this hook; the rollback of the per-statement transaction
- also occurs after the hook is called.
- .. note::
- .. [1] The pool "pre_ping" handler enabled using the
- :paramref:`_sa.create_engine.pool_pre_ping` parameter does
- **not** consult this event before deciding if the "ping"
- returned false, as opposed to receiving an unhandled error.
- For this use case, the :ref:`legacy recipe based on
- engine_connect() may be used
- <pool_disconnects_pessimistic_custom>`. A future API allow
- more comprehensive customization of the "disconnect"
- detection mechanism across all functions.
- A handler function has two options for replacing
- the SQLAlchemy-constructed exception into one that is user
- defined. It can either raise this new exception directly, in
- which case all further event listeners are bypassed and the
- exception will be raised, after appropriate cleanup as taken
- place::
- @event.listens_for(Engine, "handle_error")
- def handle_exception(context):
- if isinstance(context.original_exception,
- psycopg2.OperationalError) and \
- "failed" in str(context.original_exception):
- raise MySpecialException("failed operation")
- .. warning:: Because the
- :meth:`_events.ConnectionEvents.handle_error`
- event specifically provides for exceptions to be re-thrown as
- the ultimate exception raised by the failed statement,
- **stack traces will be misleading** if the user-defined event
- handler itself fails and throws an unexpected exception;
- the stack trace may not illustrate the actual code line that
- failed! It is advised to code carefully here and use
- logging and/or inline debugging if unexpected exceptions are
- occurring.
- Alternatively, a "chained" style of event handling can be
- used, by configuring the handler with the ``retval=True``
- modifier and returning the new exception instance from the
- function. In this case, event handling will continue onto the
- next handler. The "chained" exception is available using
- :attr:`.ExceptionContext.chained_exception`::
- @event.listens_for(Engine, "handle_error", retval=True)
- def handle_exception(context):
- if context.chained_exception is not None and \
- "special" in context.chained_exception.message:
- return MySpecialException("failed",
- cause=context.chained_exception)
- Handlers that return ``None`` may be used within the chain; when
- a handler returns ``None``, the previous exception instance,
- if any, is maintained as the current exception that is passed onto the
- next handler.
- When a custom exception is raised or returned, SQLAlchemy raises
- this new exception as-is, it is not wrapped by any SQLAlchemy
- object. If the exception is not a subclass of
- :class:`sqlalchemy.exc.StatementError`,
- certain features may not be available; currently this includes
- the ORM's feature of adding a detail hint about "autoflush" to
- exceptions raised within the autoflush process.
- :param context: an :class:`.ExceptionContext` object. See this
- class for details on all available members.
- .. versionadded:: 0.9.7 Added the
- :meth:`_events.ConnectionEvents.handle_error` hook.
- .. versionchanged:: 1.1 The :meth:`.handle_error` event will now
- receive all exceptions that inherit from ``BaseException``,
- including ``SystemExit`` and ``KeyboardInterrupt``. The setting for
- :attr:`.ExceptionContext.is_disconnect` is ``True`` in this case and
- the default for
- :attr:`.ExceptionContext.invalidate_pool_on_disconnect` is
- ``False``.
- .. versionchanged:: 1.0.0 The :meth:`.handle_error` event is now
- invoked when an :class:`_engine.Engine` fails during the initial
- call to :meth:`_engine.Engine.connect`, as well as when a
- :class:`_engine.Connection` object encounters an error during a
- reconnect operation.
- .. versionchanged:: 1.0.0 The :meth:`.handle_error` event is
- not fired off when a dialect makes use of the
- ``skip_user_error_events`` execution option. This is used
- by dialects which intend to catch SQLAlchemy-specific exceptions
- within specific operations, such as when the MySQL dialect detects
- a table not present within the ``has_table()`` dialect method.
- Prior to 1.0.0, code which implements :meth:`.handle_error` needs
- to ensure that exceptions thrown in these scenarios are re-raised
- without modification.
- """
- def engine_connect(self, conn, branch):
- """Intercept the creation of a new :class:`_engine.Connection`.
- This event is called typically as the direct result of calling
- the :meth:`_engine.Engine.connect` method.
- It differs from the :meth:`_events.PoolEvents.connect` method, which
- refers to the actual connection to a database at the DBAPI level;
- a DBAPI connection may be pooled and reused for many operations.
- In contrast, this event refers only to the production of a higher level
- :class:`_engine.Connection` wrapper around such a DBAPI connection.
- It also differs from the :meth:`_events.PoolEvents.checkout` event
- in that it is specific to the :class:`_engine.Connection` object,
- not the
- DBAPI connection that :meth:`_events.PoolEvents.checkout` deals with,
- although
- this DBAPI connection is available here via the
- :attr:`_engine.Connection.connection` attribute.
- But note there can in fact
- be multiple :meth:`_events.PoolEvents.checkout`
- events within the lifespan
- of a single :class:`_engine.Connection` object, if that
- :class:`_engine.Connection`
- is invalidated and re-established. There can also be multiple
- :class:`_engine.Connection`
- objects generated for the same already-checked-out
- DBAPI connection, in the case that a "branch" of a
- :class:`_engine.Connection`
- is produced.
- :param conn: :class:`_engine.Connection` object.
- :param branch: if True, this is a "branch" of an existing
- :class:`_engine.Connection`. A branch is generated within the course
- of a statement execution to invoke supplemental statements, most
- typically to pre-execute a SELECT of a default value for the purposes
- of an INSERT statement.
- .. seealso::
- :meth:`_events.PoolEvents.checkout`
- the lower-level pool checkout event
- for an individual DBAPI connection
- """
- def set_connection_execution_options(self, conn, opts):
- """Intercept when the :meth:`_engine.Connection.execution_options`
- method is called.
- This method is called after the new :class:`_engine.Connection`
- has been
- produced, with the newly updated execution options collection, but
- before the :class:`.Dialect` has acted upon any of those new options.
- Note that this method is not called when a new
- :class:`_engine.Connection`
- is produced which is inheriting execution options from its parent
- :class:`_engine.Engine`; to intercept this condition, use the
- :meth:`_events.ConnectionEvents.engine_connect` event.
- :param conn: The newly copied :class:`_engine.Connection` object
- :param opts: dictionary of options that were passed to the
- :meth:`_engine.Connection.execution_options` method.
- .. versionadded:: 0.9.0
- .. seealso::
- :meth:`_events.ConnectionEvents.set_engine_execution_options`
- - event
- which is called when :meth:`_engine.Engine.execution_options`
- is called.
- """
- def set_engine_execution_options(self, engine, opts):
- """Intercept when the :meth:`_engine.Engine.execution_options`
- method is called.
- The :meth:`_engine.Engine.execution_options` method produces a shallow
- copy of the :class:`_engine.Engine` which stores the new options.
- That new
- :class:`_engine.Engine` is passed here.
- A particular application of this
- method is to add a :meth:`_events.ConnectionEvents.engine_connect`
- event
- handler to the given :class:`_engine.Engine`
- which will perform some per-
- :class:`_engine.Connection` task specific to these execution options.
- :param conn: The newly copied :class:`_engine.Engine` object
- :param opts: dictionary of options that were passed to the
- :meth:`_engine.Connection.execution_options` method.
- .. versionadded:: 0.9.0
- .. seealso::
- :meth:`_events.ConnectionEvents.set_connection_execution_options`
- - event
- which is called when :meth:`_engine.Connection.execution_options`
- is
- called.
- """
- def engine_disposed(self, engine):
- """Intercept when the :meth:`_engine.Engine.dispose` method is called.
- The :meth:`_engine.Engine.dispose` method instructs the engine to
- "dispose" of it's connection pool (e.g. :class:`_pool.Pool`), and
- replaces it with a new one. Disposing of the old pool has the
- effect that existing checked-in connections are closed. The new
- pool does not establish any new connections until it is first used.
- This event can be used to indicate that resources related to the
- :class:`_engine.Engine` should also be cleaned up,
- keeping in mind that the
- :class:`_engine.Engine`
- can still be used for new requests in which case
- it re-acquires connection resources.
- .. versionadded:: 1.0.5
- """
- def begin(self, conn):
- """Intercept begin() events.
- :param conn: :class:`_engine.Connection` object
- """
- def rollback(self, conn):
- """Intercept rollback() events, as initiated by a
- :class:`.Transaction`.
- Note that the :class:`_pool.Pool` also "auto-rolls back"
- a DBAPI connection upon checkin, if the ``reset_on_return``
- flag is set to its default value of ``'rollback'``.
- To intercept this
- rollback, use the :meth:`_events.PoolEvents.reset` hook.
- :param conn: :class:`_engine.Connection` object
- .. seealso::
- :meth:`_events.PoolEvents.reset`
- """
- def commit(self, conn):
- """Intercept commit() events, as initiated by a
- :class:`.Transaction`.
- Note that the :class:`_pool.Pool` may also "auto-commit"
- a DBAPI connection upon checkin, if the ``reset_on_return``
- flag is set to the value ``'commit'``. To intercept this
- commit, use the :meth:`_events.PoolEvents.reset` hook.
- :param conn: :class:`_engine.Connection` object
- """
- def savepoint(self, conn, name):
- """Intercept savepoint() events.
- :param conn: :class:`_engine.Connection` object
- :param name: specified name used for the savepoint.
- """
- def rollback_savepoint(self, conn, name, context):
- """Intercept rollback_savepoint() events.
- :param conn: :class:`_engine.Connection` object
- :param name: specified name used for the savepoint.
- :param context: not used
- """
- # TODO: deprecate "context"
- def release_savepoint(self, conn, name, context):
- """Intercept release_savepoint() events.
- :param conn: :class:`_engine.Connection` object
- :param name: specified name used for the savepoint.
- :param context: not used
- """
- # TODO: deprecate "context"
- def begin_twophase(self, conn, xid):
- """Intercept begin_twophase() events.
- :param conn: :class:`_engine.Connection` object
- :param xid: two-phase XID identifier
- """
- def prepare_twophase(self, conn, xid):
- """Intercept prepare_twophase() events.
- :param conn: :class:`_engine.Connection` object
- :param xid: two-phase XID identifier
- """
- def rollback_twophase(self, conn, xid, is_prepared):
- """Intercept rollback_twophase() events.
- :param conn: :class:`_engine.Connection` object
- :param xid: two-phase XID identifier
- :param is_prepared: boolean, indicates if
- :meth:`.TwoPhaseTransaction.prepare` was called.
- """
- def commit_twophase(self, conn, xid, is_prepared):
- """Intercept commit_twophase() events.
- :param conn: :class:`_engine.Connection` object
- :param xid: two-phase XID identifier
- :param is_prepared: boolean, indicates if
- :meth:`.TwoPhaseTransaction.prepare` was called.
- """
- class DialectEvents(event.Events):
- """event interface for execution-replacement functions.
- These events allow direct instrumentation and replacement
- of key dialect functions which interact with the DBAPI.
- .. note::
- :class:`.DialectEvents` hooks should be considered **semi-public**
- and experimental.
- These hooks are not for general use and are only for those situations
- where intricate re-statement of DBAPI mechanics must be injected onto
- an existing dialect. For general-use statement-interception events,
- please use the :class:`_events.ConnectionEvents` interface.
- .. seealso::
- :meth:`_events.ConnectionEvents.before_cursor_execute`
- :meth:`_events.ConnectionEvents.before_execute`
- :meth:`_events.ConnectionEvents.after_cursor_execute`
- :meth:`_events.ConnectionEvents.after_execute`
- .. versionadded:: 0.9.4
- """
- _target_class_doc = "SomeEngine"
- _dispatch_target = Dialect
- @classmethod
- def _listen(cls, event_key, retval=False):
- target = event_key.dispatch_target
- target._has_events = True
- event_key.base_listen()
- @classmethod
- def _accept_with(cls, target):
- if isinstance(target, type):
- if issubclass(target, Engine):
- return Dialect
- elif issubclass(target, Dialect):
- return target
- elif isinstance(target, Engine):
- return target.dialect
- else:
- return target
- def do_connect(self, dialect, conn_rec, cargs, cparams):
- """Receive connection arguments before a connection is made.
- This event is useful in that it allows the handler to manipulate the
- cargs and/or cparams collections that control how the DBAPI
- ``connect()`` function will be called. ``cargs`` will always be a
- Python list that can be mutated in-place, and ``cparams`` a Python
- dictionary that may also be mutated::
- e = create_engine("postgresql+psycopg2://user@host/dbname")
- @event.listens_for(e, 'do_connect')
- def receive_do_connect(dialect, conn_rec, cargs, cparams):
- cparams["password"] = "some_password"
- The event hook may also be used to override the call to ``connect()``
- entirely, by returning a non-``None`` DBAPI connection object::
- e = create_engine("postgresql+psycopg2://user@host/dbname")
- @event.listens_for(e, 'do_connect')
- def receive_do_connect(dialect, conn_rec, cargs, cparams):
- return psycopg2.connect(*cargs, **cparams)
- .. versionadded:: 1.0.3
- .. seealso::
- :ref:`custom_dbapi_args`
- """
- def do_executemany(self, cursor, statement, parameters, context):
- """Receive a cursor to have executemany() called.
- Return the value True to halt further events from invoking,
- and to indicate that the cursor execution has already taken
- place within the event handler.
- """
- def do_execute_no_params(self, cursor, statement, context):
- """Receive a cursor to have execute() with no parameters called.
- Return the value True to halt further events from invoking,
- and to indicate that the cursor execution has already taken
- place within the event handler.
- """
- def do_execute(self, cursor, statement, parameters, context):
- """Receive a cursor to have execute() called.
- Return the value True to halt further events from invoking,
- and to indicate that the cursor execution has already taken
- place within the event handler.
- """
- def do_setinputsizes(
- self, inputsizes, cursor, statement, parameters, context
- ):
- """Receive the setinputsizes dictionary for possible modification.
- This event is emitted in the case where the dialect makes use of the
- DBAPI ``cursor.setinputsizes()`` method which passes information about
- parameter binding for a particular statement. The given
- ``inputsizes`` dictionary will contain :class:`.BindParameter` objects
- as keys, linked to DBAPI-specific type objects as values; for
- parameters that are not bound, they are added to the dictionary with
- ``None`` as the value, which means the parameter will not be included
- in the ultimate setinputsizes call. The event may be used to inspect
- and/or log the datatypes that are being bound, as well as to modify the
- dictionary in place. Parameters can be added, modified, or removed
- from this dictionary. Callers will typically want to inspect the
- :attr:`.BindParameter.type` attribute of the given bind objects in
- order to make decisions about the DBAPI object.
- After the event, the ``inputsizes`` dictionary is converted into
- an appropriate datastructure to be passed to ``cursor.setinputsizes``;
- either a list for a positional bound parameter execution style,
- or a dictionary of string parameter keys to DBAPI type objects for
- a named bound parameter execution style.
- The setinputsizes hook overall is only used for dialects which include
- the flag ``use_setinputsizes=True``. Dialects which use this
- include cx_Oracle, pg8000, asyncpg, and pyodbc dialects.
- .. note::
- For use with pyodbc, the ``use_setinputsizes`` flag
- must be passed to the dialect, e.g.::
- create_engine("mssql+pyodbc://...", use_setinputsizes=True)
- .. seealso::
- :ref:`mssql_pyodbc_setinputsizes`
- .. versionadded:: 1.2.9
- .. seealso::
- :ref:`cx_oracle_setinputsizes`
- """
- pass
|