summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/engine/interfaces.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-06-04 17:29:20 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-02-21 17:53:33 -0500
commitf559f378c47811b5528ad1769cb86925e85fd1e5 (patch)
treefd8325501a96cf1e4280c15f267f63b2af7b5f97 /lib/sqlalchemy/engine/interfaces.py
parent93b7767d00267ebe149cabcae7246b6796352eb8 (diff)
downloadsqlalchemy-f559f378c47811b5528ad1769cb86925e85fd1e5.tar.gz
Result initial introduction
This builds on cc718cccc0bf8a01abdf4068c7ea4f3 which moved RowProxy to Row, allowing Row to be more like a named tuple. - KeyedTuple in ORM is replaced with Row - ResultSetMetaData broken out into "simple" and "cursor" versions for ORM and Core, as well as LegacyCursor version. - Row now has _mapping attribute that supplies full mapping behavior. Row and SimpleRow both have named tuple behavior otherwise. LegacyRow has some mapping features on the tuple which emit deprecation warnings (e.g. keys(), values(), etc). the biggest change for mapping->tuple is the behavior of __contains__ which moves from testing of "key in row" to "value in row". - ResultProxy breaks into ResultProxy and FutureResult (interim), the latter has the newer APIs. Made available to dialects using execution options. - internal reflection methods and most tests move off of implicit Row mapping behavior and move to row._mapping, result.mappings() method using future result - a new strategy system for cursor handling replaces the various subclasses of RowProxy - some execution context adjustments. We will leave EC in but refined things like get_result_proxy() and out parameter handling. Dialects for 1.4 will need to adjust from get_result_proxy() to get_result_cursor_strategy(), if they are using this method - out parameter handling now accommodated by get_out_parameter_values() EC method. Oracle changes for this. external dialect for DB2 for example will also need to adjust for this. - deprecate case_insensitive flag for engine / result, this feature is not used mapping-methods on Row are deprecated, and replaced with Row._mapping.<meth>, including: row.keys() -> use row._mapping.keys() row.items() -> use row._mapping.items() row.values() -> use row._mapping.values() key in row -> use key in row._mapping int in row -> use int < len(row) Fixes: #4710 Fixes: #4878 Change-Id: Ieb9085e9bcff564359095b754da9ae0af55679f0
Diffstat (limited to 'lib/sqlalchemy/engine/interfaces.py')
-rw-r--r--lib/sqlalchemy/engine/interfaces.py101
1 files changed, 97 insertions, 4 deletions
diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py
index 237eb0f2f..3d4308df2 100644
--- a/lib/sqlalchemy/engine/interfaces.py
+++ b/lib/sqlalchemy/engine/interfaces.py
@@ -1044,6 +1044,44 @@ class ExecutionContext(object):
raise NotImplementedError()
+ def get_out_parameter_values(self, out_param_names):
+ """Return a sequence of OUT parameter values from a cursor.
+
+ For dialects that support OUT parameters, this method will be called
+ when there is a :class:`.SQLCompiler` object which has the
+ :attr:`.SQLCompiler.has_out_parameters` flag set. This flag in turn
+ will be set to True if the statement itself has :class:`.BindParameter`
+ objects that have the ``.isoutparam`` flag set which are consumed by
+ the :meth:`.SQLCompiler.visit_bindparam` method. If the dialect
+ compiler produces :class:`.BindParameter` objects with ``.isoutparam``
+ set which are not handled by :meth:`.SQLCompiler.visit_bindparam`, it
+ should set this flag explicitly.
+
+ The list of names that were rendered for each bound parameter
+ is passed to the method. The method should then return a sequence of
+ values corresponding to the list of parameter objects. Unlike in
+ previous SQLAlchemy versions, the values can be the **raw values** from
+ the DBAPI; the execution context will apply the appropriate type
+ handler based on what's present in self.compiled.binds and update the
+ values. The processed dictionary will then be made available via the
+ ``.out_parameters`` collection on the result object. Note that
+ SQLAlchemy 1.4 has multiple kinds of result object as part of the 2.0
+ transition.
+
+ .. versionadded:: 1.4 - added
+ :meth:`.ExecutionContext.get_out_parameter_values`, which is invoked
+ automatically by the :class:`.DefaultExecutionContext` when there
+ are :class:`.BindParameter` objects with the ``.isoutparam`` flag
+ set. This replaces the practice of setting out parameters within
+ the now-removed ``get_result_proxy()`` method.
+
+ .. seealso::
+
+ :meth:`.ExecutionContext.get_result_cursor_strategy`
+
+ """
+ raise NotImplementedError()
+
def post_exec(self):
"""Called after the execution of a compiled statement.
@@ -1054,12 +1092,67 @@ class ExecutionContext(object):
raise NotImplementedError()
- def result(self):
- """Return a result object corresponding to this ExecutionContext.
+ def get_result_cursor_strategy(self, result):
+ """Return a result cursor strategy for a given result object.
- Returns a ResultProxy.
- """
+ This method is implemented by the :class:`.DefaultDialect` and is
+ only needed by implementing dialects in the case where some special
+ steps regarding the cursor must be taken, such as manufacturing
+ fake results from some other element of the cursor, or pre-buffering
+ the cursor's results.
+
+ A simplified version of the default implementation is::
+
+ from sqlalchemy.engine.result import DefaultCursorFetchStrategy
+
+ class MyExecutionContext(DefaultExecutionContext):
+ def get_result_cursor_strategy(self, result):
+ return DefaultCursorFetchStrategy.create(result)
+
+ Above, the :class:`.DefaultCursorFetchStrategy` will be applied
+ to the result object. For results that are pre-buffered from a
+ cursor that might be closed, an implementation might be::
+
+ from sqlalchemy.engine.result import (
+ FullyBufferedCursorFetchStrategy
+ )
+
+ class MyExecutionContext(DefaultExecutionContext):
+ _pre_buffered_result = None
+
+ def pre_exec(self):
+ if self.special_condition_prebuffer_cursor():
+ self._pre_buffered_result = (
+ self.cursor.description,
+ self.cursor.fetchall()
+ )
+
+ def get_result_cursor_strategy(self, result):
+ if self._pre_buffered_result:
+ description, cursor_buffer = self._pre_buffered_result
+ return (
+ FullyBufferedCursorFetchStrategy.
+ create_from_buffer(
+ result, description, cursor_buffer
+ )
+ )
+ else:
+ return DefaultCursorFetchStrategy.create(result)
+
+ This method replaces the previous not-quite-documented
+ ``get_result_proxy()`` method.
+
+ .. versionadded:: 1.4 - result objects now interpret cursor results
+ based on a pluggable "strategy" object, which is delivered
+ by the :class:`.ExecutionContext` via the
+ :meth:`.ExecutionContext.get_result_cursor_strategy` method.
+
+ .. seealso::
+
+ :meth:`.ExecutionContext.get_out_parameter_values`
+
+ """
raise NotImplementedError()
def handle_dbapi_exception(self, e):