1 | # interfaces.py |
---|
2 | # Copyright (C) 2007 Jason Kirtland jek@discorporate.us |
---|
3 | # |
---|
4 | # This module is part of SQLAlchemy and is released under |
---|
5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php |
---|
6 | |
---|
7 | """Interfaces and abstract types.""" |
---|
8 | |
---|
9 | |
---|
10 | class PoolListener(object): |
---|
11 | """Hooks into the lifecycle of connections in a ``Pool``. |
---|
12 | |
---|
13 | Usage:: |
---|
14 | |
---|
15 | class MyListener(PoolListener): |
---|
16 | def connect(self, dbapi_con, con_record): |
---|
17 | '''perform connect operations''' |
---|
18 | # etc. |
---|
19 | |
---|
20 | # create a new pool with a listener |
---|
21 | p = QueuePool(..., listeners=[MyListener()]) |
---|
22 | |
---|
23 | # add a listener after the fact |
---|
24 | p.add_listener(MyListener()) |
---|
25 | |
---|
26 | # usage with create_engine() |
---|
27 | e = create_engine("url://", listeners=[MyListener()]) |
---|
28 | |
---|
29 | All of the standard connection :class:`~sqlalchemy.pool.Pool` types can |
---|
30 | accept event listeners for key connection lifecycle events: |
---|
31 | creation, pool check-out and check-in. There are no events fired |
---|
32 | when a connection closes. |
---|
33 | |
---|
34 | For any given DB-API connection, there will be one ``connect`` |
---|
35 | event, `n` number of ``checkout`` events, and either `n` or `n - 1` |
---|
36 | ``checkin`` events. (If a ``Connection`` is detached from its |
---|
37 | pool via the ``detach()`` method, it won't be checked back in.) |
---|
38 | |
---|
39 | These are low-level events for low-level objects: raw Python |
---|
40 | DB-API connections, without the conveniences of the SQLAlchemy |
---|
41 | ``Connection`` wrapper, ``Dialect`` services or ``ClauseElement`` |
---|
42 | execution. If you execute SQL through the connection, explicitly |
---|
43 | closing all cursors and other resources is recommended. |
---|
44 | |
---|
45 | Events also receive a ``_ConnectionRecord``, a long-lived internal |
---|
46 | ``Pool`` object that basically represents a "slot" in the |
---|
47 | connection pool. ``_ConnectionRecord`` objects have one public |
---|
48 | attribute of note: ``info``, a dictionary whose contents are |
---|
49 | scoped to the lifetime of the DB-API connection managed by the |
---|
50 | record. You can use this shared storage area however you like. |
---|
51 | |
---|
52 | There is no need to subclass ``PoolListener`` to handle events. |
---|
53 | Any class that implements one or more of these methods can be used |
---|
54 | as a pool listener. The ``Pool`` will inspect the methods |
---|
55 | provided by a listener object and add the listener to one or more |
---|
56 | internal event queues based on its capabilities. In terms of |
---|
57 | efficiency and function call overhead, you're much better off only |
---|
58 | providing implementations for the hooks you'll be using. |
---|
59 | |
---|
60 | """ |
---|
61 | |
---|
62 | def connect(self, dbapi_con, con_record): |
---|
63 | """Called once for each new DB-API connection or Pool's ``creator()``. |
---|
64 | |
---|
65 | dbapi_con |
---|
66 | A newly connected raw DB-API connection (not a SQLAlchemy |
---|
67 | ``Connection`` wrapper). |
---|
68 | |
---|
69 | con_record |
---|
70 | The ``_ConnectionRecord`` that persistently manages the connection |
---|
71 | |
---|
72 | """ |
---|
73 | |
---|
74 | def checkout(self, dbapi_con, con_record, con_proxy): |
---|
75 | """Called when a connection is retrieved from the Pool. |
---|
76 | |
---|
77 | dbapi_con |
---|
78 | A raw DB-API connection |
---|
79 | |
---|
80 | con_record |
---|
81 | The ``_ConnectionRecord`` that persistently manages the connection |
---|
82 | |
---|
83 | con_proxy |
---|
84 | The ``_ConnectionFairy`` which manages the connection for the span of |
---|
85 | the current checkout. |
---|
86 | |
---|
87 | If you raise an ``exc.DisconnectionError``, the current |
---|
88 | connection will be disposed and a fresh connection retrieved. |
---|
89 | Processing of all checkout listeners will abort and restart |
---|
90 | using the new connection. |
---|
91 | """ |
---|
92 | |
---|
93 | def checkin(self, dbapi_con, con_record): |
---|
94 | """Called when a connection returns to the pool. |
---|
95 | |
---|
96 | Note that the connection may be closed, and may be None if the |
---|
97 | connection has been invalidated. ``checkin`` will not be called |
---|
98 | for detached connections. (They do not return to the pool.) |
---|
99 | |
---|
100 | dbapi_con |
---|
101 | A raw DB-API connection |
---|
102 | |
---|
103 | con_record |
---|
104 | The ``_ConnectionRecord`` that persistently manages the connection |
---|
105 | |
---|
106 | """ |
---|
107 | |
---|
108 | class ConnectionProxy(object): |
---|
109 | """Allows interception of statement execution by Connections. |
---|
110 | |
---|
111 | Either or both of the ``execute()`` and ``cursor_execute()`` |
---|
112 | may be implemented to intercept compiled statement and |
---|
113 | cursor level executions, e.g.:: |
---|
114 | |
---|
115 | class MyProxy(ConnectionProxy): |
---|
116 | def execute(self, conn, execute, clauseelement, *multiparams, **params): |
---|
117 | print "compiled statement:", clauseelement |
---|
118 | return execute(clauseelement, *multiparams, **params) |
---|
119 | |
---|
120 | def cursor_execute(self, execute, cursor, statement, parameters, context, executemany): |
---|
121 | print "raw statement:", statement |
---|
122 | return execute(cursor, statement, parameters, context) |
---|
123 | |
---|
124 | The ``execute`` argument is a function that will fulfill the default |
---|
125 | execution behavior for the operation. The signature illustrated |
---|
126 | in the example should be used. |
---|
127 | |
---|
128 | The proxy is installed into an :class:`~sqlalchemy.engine.Engine` via |
---|
129 | the ``proxy`` argument:: |
---|
130 | |
---|
131 | e = create_engine('someurl://', proxy=MyProxy()) |
---|
132 | |
---|
133 | """ |
---|
134 | def execute(self, conn, execute, clauseelement, *multiparams, **params): |
---|
135 | """Intercept high level execute() events.""" |
---|
136 | |
---|
137 | return execute(clauseelement, *multiparams, **params) |
---|
138 | |
---|
139 | def cursor_execute(self, execute, cursor, statement, parameters, context, executemany): |
---|
140 | """Intercept low-level cursor execute() events.""" |
---|
141 | |
---|
142 | return execute(cursor, statement, parameters, context) |
---|
143 | |
---|
144 | |
---|