summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-02-20 20:22:38 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2016-02-20 20:22:38 -0500
commit8ad968f33100baeb3b13c7e0b724b6b79ab4277f (patch)
tree2a4081d4cec903327ce6b3c6d374858d3218a92a /lib
parent60a9d2da25da68466130771afc3f35c9473aca02 (diff)
downloadsqlalchemy-8ad968f33100baeb3b13c7e0b724b6b79ab4277f.tar.gz
- reworked the way the "select_wraps_for" expression is
handled within visit_select(); this attribute was added in the 1.0 series to accommodate the subquery wrapping behavior of SQL Server and Oracle while also working with positional column targeting and no longer relying upon "key fallback" in order to target columns in such a statement. The IBM DB2 third-party dialect also has this use case, but its implementation is using regular expressions to rewrite the textual SELECT only and does not make use of a "wrapped" select at this time. The logic no longer attempts to reconcile proxy set collections as this was not deterministic, and instead assumes that the select() and the wrapper select() match their columns postionally, at least for the column positions they have in common, so it is now very simple and safe. fixes #3657. - as a side effect of #3657 it was also revealed that the strategy of calling upon a ResultProxy._getter was not correctly calling into NoSuchColumnError when an expected column was not present, and instead returned None up to loading.instances() to produce NoneType failures; added a raiseerr argument to _getter() which is called when we aren't expecting None, fixes #3658.
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/engine/result.py8
-rw-r--r--lib/sqlalchemy/orm/loading.py2
-rw-r--r--lib/sqlalchemy/orm/strategies.py2
-rw-r--r--lib/sqlalchemy/sql/compiler.py10
4 files changed, 9 insertions, 13 deletions
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index c069fcedf..f09b0b40b 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -561,11 +561,11 @@ class ResultMetaData(object):
else:
return self._key_fallback(key, False) is not None
- def _getter(self, key):
+ def _getter(self, key, raiseerr=True):
if key in self._keymap:
processor, obj, index = self._keymap[key]
else:
- ret = self._key_fallback(key, False)
+ ret = self._key_fallback(key, raiseerr)
if ret is None:
return None
processor, obj, index = ret
@@ -640,13 +640,13 @@ class ResultProxy(object):
context.engine._should_log_debug()
self._init_metadata()
- def _getter(self, key):
+ def _getter(self, key, raiseerr=True):
try:
getter = self._metadata._getter
except AttributeError:
return self._non_result(None)
else:
- return getter(key)
+ return getter(key, raiseerr)
def _has_key(self, key):
try:
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index b8bc205d4..d457f3c63 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -316,7 +316,7 @@ def _instance_processor(
else:
if adapter:
col = adapter.columns[col]
- getter = result._getter(col)
+ getter = result._getter(col, False)
if getter:
populators["quick"].append((prop.key, getter))
else:
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 7d816e626..370cb974b 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -174,7 +174,7 @@ class ColumnLoader(LoaderStrategy):
for col in self.columns:
if adapter:
col = adapter.columns[col]
- getter = result._getter(col)
+ getter = result._getter(col, False)
if getter:
populators["quick"].append((self.key, getter))
break
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index a2fc0fe68..b75dc1c07 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -1638,15 +1638,11 @@ class SQLCompiler(Compiled):
if populate_result_map and select_wraps_for is not None:
# if this select is a compiler-generated wrapper,
# rewrite the targeted columns in the result map
- wrapped_inner_columns = set(select_wraps_for.inner_columns)
+
translate = dict(
- (outer, inner.pop()) for outer, inner in [
- (
- outer,
- outer.proxy_set.intersection(wrapped_inner_columns))
- for outer in select.inner_columns
- ] if inner
+ zip(select.inner_columns, select_wraps_for.inner_columns)
)
+
self._result_columns = [
(key, name, tuple(translate.get(o, o) for o in obj), type_)
for key, name, obj, type_ in self._result_columns