summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-01-22 14:04:20 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2012-01-22 14:04:20 -0500
commit09a503e49724b61a8119f0b7855a990a29fc1521 (patch)
treedc2c87cc9291f31b99c2248beb42f26e0f70786d /lib/sqlalchemy
parentc9a1e570ad68028e0de0551155caeae313c9c7fd (diff)
downloadsqlalchemy-09a503e49724b61a8119f0b7855a990a29fc1521.tar.gz
- [bug] Fixed bug whereby a table-bound Column
object named "<a>_<b>" which matched a column labeled as "<tablename>_<colname>" could match inappropriately when targeting in a result set row. [ticket:2377] - requires that we change the tuple format in RowProxy. Makes an improvement to the cases tested against an unpickled RowProxy as well though doesn't solve the problem there entirely.
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/cextension/resultproxy.c2
-rw-r--r--lib/sqlalchemy/engine/base.py32
-rw-r--r--lib/sqlalchemy/sql/compiler.py4
-rw-r--r--lib/sqlalchemy/sql/expression.py14
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):