diff options
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r-- | lib/sqlalchemy/cextension/resultproxy.c | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/base.py | 32 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 4 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/expression.py | 14 |
4 files changed, 41 insertions, 11 deletions
diff --git a/lib/sqlalchemy/cextension/resultproxy.c b/lib/sqlalchemy/cextension/resultproxy.c index 5af94771b..cfc0e3530 100644 --- a/lib/sqlalchemy/cextension/resultproxy.c +++ b/lib/sqlalchemy/cextension/resultproxy.c @@ -278,7 +278,7 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key) return NULL; } - indexobject = PyTuple_GetItem(record, 1); + indexobject = PyTuple_GetItem(record, 2); if (indexobject == NULL) return NULL; diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 3c6127845..36365e524 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -2461,9 +2461,9 @@ except ImportError: def __getitem__(self, key): try: - processor, index = self._keymap[key] + processor, obj, index = self._keymap[key] except KeyError: - processor, index = self._parent._key_fallback(key) + processor, obj, index = self._parent._key_fallback(key) except TypeError: if isinstance(key, slice): l = [] @@ -2596,7 +2596,7 @@ class ResultMetaData(object): processor = type_._cached_result_processor(dialect, coltype) processors.append(processor) - rec = (processor, i) + rec = (processor, obj, i) # indexes as keys. This is only needed for the Python version of # RowProxy (the C version uses a faster path for integer indexes). @@ -2608,7 +2608,7 @@ class ResultMetaData(object): # columns colliding by name is not a problem as long as the # user does not try to access them (ie use an index directly, # or the more precise ColumnElement) - keymap[name.lower()] = (processor, None) + keymap[name.lower()] = (processor, obj, None) if dialect.requires_name_normalize: colname = dialect.normalize_name(colname) @@ -2630,9 +2630,9 @@ class ResultMetaData(object): row. """ - rec = (processor, i) = self._keymap[origname.lower()] + rec = (processor, obj, i) = self._keymap[origname.lower()] if self._keymap.setdefault(name, rec) is not rec: - self._keymap[name] = (processor, None) + self._keymap[name] = (processor, obj, None) def _key_fallback(self, key, raiseerr=True): map = self._keymap @@ -2646,7 +2646,17 @@ class ResultMetaData(object): if key._label and key._label.lower() in map: result = map[key._label.lower()] elif hasattr(key, 'name') and key.name.lower() in map: + # match is only on name. search + # extra hard to make sure this isn't a column/ + # label name overlap result = map[key.name.lower()] + + if result[1] is not None: + for obj in result[1]: + if key._compare_name_for_result(obj): + break + else: + result = None if result is None: if raiseerr: raise exc.NoSuchColumnError( @@ -2668,7 +2678,7 @@ class ResultMetaData(object): return { '_pickled_keymap': dict( (key, index) - for key, (processor, index) in self._keymap.iteritems() + for key, (processor, obj, index) in self._keymap.iteritems() if isinstance(key, (basestring, int)) ), 'keys': self.keys @@ -2680,7 +2690,9 @@ class ResultMetaData(object): self._processors = [None for _ in xrange(len(state['keys']))] self._keymap = keymap = {} for key, index in state['_pickled_keymap'].iteritems(): - keymap[key] = (None, index) + # not preserving "obj" here, unfortunately our + # proxy comparison fails with the unpickle + keymap[key] = (None, None, index) self.keys = state['keys'] self._echo = False @@ -3213,8 +3225,8 @@ class BufferedColumnResultProxy(ResultProxy): # replace the all type processors by None processors. metadata._processors = [None for _ in xrange(len(metadata.keys))] keymap = {} - for k, (func, index) in metadata._keymap.iteritems(): - keymap[k] = (None, index) + for k, (func, obj, index) in metadata._keymap.iteritems(): + keymap[k] = (None, obj, index) self._metadata._keymap = keymap def fetchall(self): diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 724e7dc2a..c63ae1aea 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -158,6 +158,10 @@ class _CompileLabel(visitors.Visitable): self.name = name @property + def proxy_set(self): + return self.element.proxy_set + + @property def type(self): return self.element.type diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 9f2a16195..bff086e4b 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -2087,6 +2087,13 @@ class ColumnElement(ClauseElement, _CompareMixin): return bool(self.proxy_set.intersection(othercolumn.proxy_set)) + def _compare_name_for_result(self, other): + """Return True if the given column element compares to this one + when targeting within a result row.""" + + return hasattr(other, 'name') and hasattr(self, 'name') and \ + other.name == self.name + def _make_proxy(self, selectable, name=None): """Create a new :class:`.ColumnElement` representing this :class:`.ColumnElement` as it appears in the select list of a @@ -3919,6 +3926,13 @@ class ColumnClause(_Immutable, ColumnElement): self.type = sqltypes.to_instance(type_) self.is_literal = is_literal + def _compare_name_for_result(self, other): + if self.table is not None and hasattr(other, 'proxy_set'): + return other.proxy_set.intersection(self.proxy_set) + else: + return super(ColumnClause, self).\ + _compare_name_for_result(other) + def _get_table(self): return self.__dict__['table'] def _set_table(self, table): |