summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/events.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-08-23 15:40:09 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-08-23 15:40:09 -0400
commit28bfc3d5dfdaae57a94f660959aaaeb83a5e2132 (patch)
tree43d42adce27ce2d606e8f1fae4849b722f0d8bd3 /lib/sqlalchemy/events.py
parent16d66d35644eaa6609fdc5c8f805314f7cf4d0fc (diff)
downloadsqlalchemy-28bfc3d5dfdaae57a94f660959aaaeb83a5e2132.tar.gz
- [feature] The before_cursor_execute event
fires off for so-called "_cursor_execute" events, which are usually special-case executions of primary-key bound sequences and default-generation SQL phrases that invoke separately when RETURNING is not used with INSERT. [ticket:2459]
Diffstat (limited to 'lib/sqlalchemy/events.py')
-rw-r--r--lib/sqlalchemy/events.py229
1 files changed, 209 insertions, 20 deletions
diff --git a/lib/sqlalchemy/events.py b/lib/sqlalchemy/events.py
index 10717ee50..61392ea62 100644
--- a/lib/sqlalchemy/events.py
+++ b/lib/sqlalchemy/events.py
@@ -341,18 +341,56 @@ class ConnectionEvents(event.Events):
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`,
- such as an :class:`.Engine`, e.g.::
+ An event listener can be associated with any :class:`.Connectable`
+ class or instance, such as an :class:`.Engine`, e.g.::
from sqlalchemy import event, create_engine
- def before_execute(conn, clauseelement, multiparams, params):
- log.info("Received statement: %s" % clauseelement)
+ 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_execute", before_execute)
+ event.listen(engine, "before_cursor_execute", before_cursor_execute)
- Some events allow modifiers to the :func:`.event.listen` function.
+ or with a specific :class:`.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)
+
+ 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:`.ConnectionEvents` can be established on any
+ combination of :class:`.Engine`, :class:`.Connection`, as well
+ as instances of each of those classes. Events across all
+ four scopes will fire off for a given instance of
+ :class:`.Connection`. However, for performance reasons, the
+ :class:`.Connection` object determines at instantiation time
+ whether or not its parent :class:`.Engine` has event listeners
+ established. Event listeners added to the :class:`.Engine`
+ class or to an instance of :class:`.Engine` *after* the instantiation
+ of a dependent :class:`.Connection` instance will usually
+ *not* be available on that :class:`.Connection` instance. The newly
+ added listeners will instead take effect for :class:`.Connection`
+ instances created subsequent to those event listeners being
+ established on the parent :class:`.Engine` class or instance.
:param retval=False: Applies to the :meth:`.before_execute` and
:meth:`.before_cursor_execute` events only. When True, the
@@ -400,18 +438,107 @@ class ConnectionEvents(event.Events):
event.Events._listen(target, identifier, fn)
def before_execute(self, conn, clauseelement, multiparams, params):
- """Intercept high level execute() events."""
+ """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, conn, clauseelement, multiparams, params):
+ # do something with clauseelement, multiparams, params
+ return clauseelement, multiparams, params
+
+ :param conn: :class:`.Connection` object
+ :param clauseelement: SQL expression construct, :class:`.Compiled`
+ instance, or string statement passed to :meth:`.Connection.execute`.
+ :param multiparams: Multiple parameter sets, a list of dictionaries.
+ :param params: Single parameter set, a single dictionary.
+
+ See also:
+
+ :meth:`.before_cursor_execute`
+
+ """
def after_execute(self, conn, clauseelement, multiparams, params, result):
- """Intercept high level execute() events."""
+ """Intercept high level execute() events after execute.
+
+
+ :param conn: :class:`.Connection` object
+ :param clauseelement: SQL expression construct, :class:`.Compiled`
+ instance, or string statement passed to :meth:`.Connection.execute`.
+ :param multiparams: Multiple parameter sets, a list of dictionaries.
+ :param params: Single parameter set, a single dictionary.
+ :param result: :class:`.ResultProxy` generated by the execution.
+
+ """
def before_cursor_execute(self, conn, cursor, statement,
parameters, context, executemany):
- """Intercept low-level cursor execute() events."""
+ """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:`.ConnectionEvents`.
+
+ :param conn: :class:`.Connection` object
+ :param cursor: DBAPI cursor object
+ :param statement: string SQL statement
+ :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.
+
+ See also:
+
+ :meth:`.before_execute`
+
+ :meth:`.after_cursor_execute`
+
+ """
def after_cursor_execute(self, conn, cursor, statement,
parameters, context, executemany):
- """Intercept low-level cursor execute() events."""
+ """Intercept low-level cursor execute() events after execution.
+
+ :param conn: :class:`.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:`.ResultProxy`.
+ :param statement: string SQL statement
+ :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 dbapi_error(self, conn, cursor, statement, parameters,
context, exception):
@@ -439,37 +566,99 @@ class ConnectionEvents(event.Events):
exception is then wrapped in a SQLAlchemy DBAPI exception
wrapper and re-thrown.
+ :param conn: :class:`.Connection` object
+ :param cursor: DBAPI cursor object
+ :param statement: string SQL statement
+ :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 exception: The **unwrapped** exception emitted directly from the
+ DBAPI. The class here is specific to the DBAPI module in use.
+
.. versionadded:: 0.7.7
"""
def begin(self, conn):
- """Intercept begin() events."""
+ """Intercept begin() events.
+
+ :param conn: :class:`.Connection` object
+
+ """
def rollback(self, conn):
- """Intercept rollback() events."""
+ """Intercept rollback() events.
+
+ :param conn: :class:`.Connection` object
+
+ """
def commit(self, conn):
- """Intercept commit() events."""
+ """Intercept commit() events.
+
+ :param conn: :class:`.Connection` object
+ """
def savepoint(self, conn, name=None):
- """Intercept savepoint() events."""
+ """Intercept savepoint() events.
+
+ :param conn: :class:`.Connection` object
+ :param name: specified name used for the savepoint.
+
+ """
def rollback_savepoint(self, conn, name, context):
- """Intercept rollback_savepoint() events."""
+ """Intercept rollback_savepoint() events.
+
+ :param conn: :class:`.Connection` object
+ :param name: specified name used for the savepoint.
+ :param context: :class:`.ExecutionContext` in use. May be ``None``.
+
+ """
def release_savepoint(self, conn, name, context):
- """Intercept release_savepoint() events."""
+ """Intercept release_savepoint() events.
+
+ :param conn: :class:`.Connection` object
+ :param name: specified name used for the savepoint.
+ :param context: :class:`.ExecutionContext` in use. May be ``None``.
+
+ """
def begin_twophase(self, conn, xid):
- """Intercept begin_twophase() events."""
+ """Intercept begin_twophase() events.
+
+ :param conn: :class:`.Connection` object
+ :param xid: two-phase XID identifier
+
+ """
def prepare_twophase(self, conn, xid):
- """Intercept prepare_twophase() events."""
+ """Intercept prepare_twophase() events.
+
+ :param conn: :class:`.Connection` object
+ :param xid: two-phase XID identifier
+ """
def rollback_twophase(self, conn, xid, is_prepared):
- """Intercept rollback_twophase() events."""
+ """Intercept rollback_twophase() events.
+
+ :param conn: :class:`.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."""
+ """Intercept commit_twophase() events.
+
+ :param conn: :class:`.Connection` object
+ :param xid: two-phase XID identifier
+ :param is_prepared: boolean, indicates if
+ :meth:`.TwoPhaseTransaction.prepare` was called.
+
+ """