summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/engine/cursor.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/engine/cursor.py')
-rw-r--r--lib/sqlalchemy/engine/cursor.py243
1 files changed, 40 insertions, 203 deletions
diff --git a/lib/sqlalchemy/engine/cursor.py b/lib/sqlalchemy/engine/cursor.py
index 5e6078f86..049422617 100644
--- a/lib/sqlalchemy/engine/cursor.py
+++ b/lib/sqlalchemy/engine/cursor.py
@@ -16,10 +16,10 @@ from .result import Result
from .result import ResultMetaData
from .result import SimpleResultMetaData
from .result import tuplegetter
-from .row import LegacyRow
+from .row import Row
from .. import exc
from .. import util
-from ..sql import expression
+from ..sql import elements
from ..sql import sqltypes
from ..sql import util as sql_util
from ..sql.base import _generative
@@ -53,7 +53,8 @@ class CursorResultMetaData(ResultMetaData):
"_keymap_by_result_column_idx",
"_tuplefilter",
"_translated_indexes",
- "_safe_for_cache"
+ "_safe_for_cache",
+ "_unpickled"
# don't need _unique_filters support here for now. Can be added
# if a need arises.
)
@@ -82,6 +83,7 @@ class CursorResultMetaData(ResultMetaData):
new_metadata = self.__class__.__new__(self.__class__)
new_metadata.case_sensitive = self.case_sensitive
+ new_metadata._unpickled = self._unpickled
new_metadata._processors = self._processors
new_metadata._keys = new_keys
new_metadata._tuplefilter = tup
@@ -143,6 +145,7 @@ class CursorResultMetaData(ResultMetaData):
md._keymap[new] = rec
md.case_sensitive = self.case_sensitive
+ md._unpickled = self._unpickled
md._processors = self._processors
assert not self._tuplefilter
md._tuplefilter = None
@@ -158,7 +161,7 @@ class CursorResultMetaData(ResultMetaData):
self._tuplefilter = None
self._translated_indexes = None
self.case_sensitive = dialect.case_sensitive
- self._safe_for_cache = False
+ self._safe_for_cache = self._unpickled = False
if context.result_column_struct:
(
@@ -610,14 +613,34 @@ class CursorResultMetaData(ResultMetaData):
)
def _key_fallback(self, key, err, raiseerr=True):
+
+ # we apparently have not marked .case_sensitive as
+ # RemovedIn20. I still think we should remove it as I can't
+ # imagine anyone is using it, however lets make that a separate
+ # commit.
+ if not self.case_sensitive and isinstance(key, util.string_types):
+ map_ = self._keymap
+ result = map_.get(key.lower())
+ if result is not None:
+ return result
+
if raiseerr:
- util.raise_(
- exc.NoSuchColumnError(
- "Could not locate column in row for column '%s'"
- % util.string_or_unprintable(key)
- ),
- replace_context=err,
- )
+ if self._unpickled and isinstance(key, elements.ColumnElement):
+ util.raise_(
+ exc.NoSuchColumnError(
+ "Row was unpickled; lookup by ColumnElement "
+ "is unsupported"
+ ),
+ replace_context=err,
+ )
+ else:
+ util.raise_(
+ exc.NoSuchColumnError(
+ "Could not locate column in row for column '%s'"
+ % util.string_or_unprintable(key)
+ ),
+ replace_context=err,
+ )
else:
return None
@@ -694,7 +717,7 @@ class CursorResultMetaData(ResultMetaData):
}
self._keys = state["_keys"]
self.case_sensitive = state["case_sensitive"]
-
+ self._unpickled = True
if state["_translated_indexes"]:
self._translated_indexes = state["_translated_indexes"]
self._tuplefilter = tuplegetter(*self._translated_indexes)
@@ -702,116 +725,6 @@ class CursorResultMetaData(ResultMetaData):
self._translated_indexes = self._tuplefilter = None
-class LegacyCursorResultMetaData(CursorResultMetaData):
- __slots__ = ()
-
- def _contains(self, value, row):
- key = value
- if key in self._keymap:
- util.warn_deprecated_20(
- "Using the 'in' operator to test for string or column "
- "keys, or integer indexes, in a :class:`.Row` object is "
- "deprecated and will "
- "be removed in a future release. "
- "Use the `Row._fields` or `Row._mapping` attribute, i.e. "
- "'key in row._fields'",
- )
- return True
- else:
- return self._key_fallback(key, None, False) is not None
-
- def _key_fallback(self, key, err, raiseerr=True):
- map_ = self._keymap
- result = None
-
- if isinstance(key, util.string_types):
- result = map_.get(key if self.case_sensitive else key.lower())
- elif isinstance(key, expression.ColumnElement):
- if (
- key._tq_label
- and (
- key._tq_label
- if self.case_sensitive
- else key._tq_label.lower()
- )
- in map_
- ):
- result = map_[
- key._tq_label
- if self.case_sensitive
- else key._tq_label.lower()
- ]
- elif (
- hasattr(key, "name")
- and (key.name if self.case_sensitive else key.name.lower())
- in map_
- ):
- # match is only on name.
- result = map_[
- key.name if self.case_sensitive else key.name.lower()
- ]
-
- # search extra hard to make sure this
- # isn't a column/label name overlap.
- # this check isn't currently available if the row
- # was unpickled.
- if result is not None and result[MD_OBJECTS] not in (
- None,
- _UNPICKLED,
- ):
- for obj in result[MD_OBJECTS]:
- if key._compare_name_for_result(obj):
- break
- else:
- result = None
- if result is not None:
- if result[MD_OBJECTS] is _UNPICKLED:
- util.warn_deprecated(
- "Retrieving row values using Column objects from a "
- "row that was unpickled is deprecated; adequate "
- "state cannot be pickled for this to be efficient. "
- "This usage will raise KeyError in a future release.",
- version="1.4",
- )
- else:
- util.warn_deprecated(
- "Retrieving row values using Column objects with only "
- "matching names as keys is deprecated, and will raise "
- "KeyError in a future release; only Column "
- "objects that are explicitly part of the statement "
- "object should be used.",
- version="1.4",
- )
- if result is None:
- if raiseerr:
- util.raise_(
- exc.NoSuchColumnError(
- "Could not locate column in row for column '%s'"
- % util.string_or_unprintable(key)
- ),
- replace_context=err,
- )
- else:
- return None
- else:
- map_[key] = result
- return result
-
- def _warn_for_nonint(self, key):
- util.warn_deprecated_20(
- "Using non-integer/slice indices on Row is deprecated and will "
- "be removed in version 2.0; please use row._mapping[<key>], or "
- "the mappings() accessor on the Result object.",
- stacklevel=4,
- )
-
- def _has_key(self, key):
- if key in self._keymap:
- return True
- else:
- return self._key_fallback(key, None, False) is not None
-
-
class ResultFetchStrategy(object):
"""Define a fetching strategy for a result object.
@@ -1205,19 +1118,7 @@ class _NoResultMetaData(ResultMetaData):
self._we_dont_return_rows()
-class _LegacyNoResultMetaData(_NoResultMetaData):
- @property
- def keys(self):
- util.warn_deprecated_20(
- "Calling the .keys() method on a result set that does not return "
- "rows is deprecated and will raise ResourceClosedError in "
- "SQLAlchemy 2.0.",
- )
- return []
-
-
_NO_RESULT_METADATA = _NoResultMetaData()
-_LEGACY_NO_RESULT_METADATA = _LegacyNoResultMetaData()
class BaseCursorResult(object):
@@ -1750,10 +1651,9 @@ class BaseCursorResult(object):
class CursorResult(BaseCursorResult, Result):
"""A Result that is representing state from a DBAPI cursor.
- .. versionchanged:: 1.4 The :class:`.CursorResult` and
- :class:`.LegacyCursorResult`
- classes replace the previous :class:`.ResultProxy` interface.
- These classes are based on the :class:`.Result` calling API
+ .. versionchanged:: 1.4 The :class:`.CursorResult``
+ class replaces the previous :class:`.ResultProxy` interface.
+ This classes are based on the :class:`.Result` calling API
which provides an updated usage model and calling facade for
SQLAlchemy Core and SQLAlchemy ORM.
@@ -1762,14 +1662,6 @@ class CursorResult(BaseCursorResult, Result):
the DBAPI. Through the use of filters such as the :meth:`.Result.scalars`
method, other kinds of objects may also be returned.
- Within the scope of the 1.x series of SQLAlchemy, Core SQL results in
- version 1.4 return an instance of :class:`._engine.LegacyCursorResult`
- which takes the place of the ``CursorResult`` class used for the 1.3 series
- and previously. This object returns rows as :class:`.LegacyRow` objects,
- which maintains Python mapping (i.e. dictionary) like behaviors upon the
- object itself. Going forward, the :attr:`.Row._mapping` attribute should
- be used for dictionary behaviors.
-
.. seealso::
:ref:`coretutorial_selecting` - introductory material for accessing
@@ -1839,62 +1731,7 @@ class CursorResult(BaseCursorResult, Result):
self.cursor_strategy.yield_per(self, self.cursor, num)
-class LegacyCursorResult(CursorResult):
- """Legacy version of :class:`.CursorResult`.
-
- This class includes connection "connection autoclose" behavior for use with
- "connectionless" execution, as well as delivers rows using the
- :class:`.LegacyRow` row implementation.
-
- .. versionadded:: 1.4
-
- """
-
- _autoclose_connection = False
- _process_row = LegacyRow
- _cursor_metadata = LegacyCursorResultMetaData
- _cursor_strategy_cls = CursorFetchStrategy
-
- _no_result_metadata = _LEGACY_NO_RESULT_METADATA
-
- def close(self):
- """Close this :class:`_engine.LegacyCursorResult`.
-
- This method has the same behavior as that of
- :meth:`._engine.CursorResult`, but it also may close
- the underlying :class:`.Connection` for the case of "connectionless"
- execution.
-
- .. deprecated:: 2.0 "connectionless" execution is deprecated and will
- be removed in version 2.0. Version 2.0 will feature the
- :class:`_future.Result`
- object that will no longer affect the status
- of the originating connection in any case.
-
- After this method is called, it is no longer valid to call upon
- the fetch methods, which will raise a :class:`.ResourceClosedError`
- on subsequent use.
-
- .. seealso::
-
- :ref:`connections_toplevel`
-
- :ref:`dbengine_implicit`
- """
- self._soft_close(hard=True)
-
- def _soft_close(self, hard=False):
- soft_closed = self._soft_closed
- super(LegacyCursorResult, self)._soft_close(hard=hard)
- if (
- not soft_closed
- and self._soft_closed
- and self._autoclose_connection
- ):
- self.connection.close()
-
-
-ResultProxy = LegacyCursorResult
+ResultProxy = CursorResult
class BufferedRowResultProxy(ResultProxy):
@@ -1919,7 +1756,7 @@ class FullyBufferedResultProxy(ResultProxy):
_cursor_strategy_cls = FullyBufferedCursorFetchStrategy
-class BufferedColumnRow(LegacyRow):
+class BufferedColumnRow(Row):
"""Row is now BufferedColumn in all cases"""