summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-10-16 16:00:37 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-10-16 16:00:37 +0000
commitc262a3b9e5bf621bd30806c13d43eb9871d9805b (patch)
tree0403a02c4cbc960ce0370a2d1587a5bffd25db13
parentd12392c38d570b4a3c14a02c75e2ea9476c34ffb (diff)
downloadsqlalchemy-c262a3b9e5bf621bd30806c13d43eb9871d9805b.tar.gz
- query.get() and related functions (like many-to-one lazyloading)
generate randomly-generated bind parameter names, to prevent name conflicts with bind parameters that already exist in the mapped selectable.
-rw-r--r--CHANGES7
-rw-r--r--lib/sqlalchemy/orm/query.py16
-rw-r--r--lib/sqlalchemy/orm/strategies.py2
-rw-r--r--setup.py2
-rw-r--r--test/orm/mapper.py7
-rw-r--r--test/sql/query.py11
6 files changed, 39 insertions, 6 deletions
diff --git a/CHANGES b/CHANGES
index 70c875381..973db91da 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+0.3.12
+- orm
+ - query.get() and related functions (like many-to-one lazyloading)
+ generate randomly-generated bind parameter names, to prevent
+ name conflicts with bind parameters that already exist in the
+ mapped selectable.
+
0.3.11
- sql
- tweak DISTINCT precedence for clauses like
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index d51fd75c3..a85410369 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -35,10 +35,17 @@ class Query(object):
self.is_polymorphic = self.mapper is not self.select_mapper
self._session = session
if not hasattr(self.mapper, '_get_clause'):
+ def bind_label():
+ # this generation should be deterministic
+ # in 0.4
+ return "get_" + hex(random.randint(0, 65535))[2:]
_get_clause = sql.and_()
+ _get_binds = {}
for primary_key in self.primary_key_columns:
- _get_clause.clauses.append(primary_key == sql.bindparam(primary_key._label, type=primary_key.type, unique=True))
- self.mapper._get_clause = _get_clause
+ bind = sql.bindparam(bind_label(), type=primary_key.type)
+ _get_binds[primary_key] = bind
+ _get_clause.clauses.append(primary_key == bind)
+ self.mapper._get_clause = (_get_clause, _get_binds)
self._entities = []
self._get_clause = self.mapper._get_clause
@@ -1062,13 +1069,14 @@ class Query(object):
else:
ident = util.to_list(ident)
params = {}
+ (_get_clause, _get_binds) = self._get_clause
try:
for i, primary_key in enumerate(self.primary_key_columns):
- params[primary_key._label] = ident[i]
+ params[_get_binds[primary_key].key] = ident[i]
except IndexError:
raise exceptions.InvalidRequestError("Could not find enough values to formulate primary key for query.get(); primary key columns are %s" % ', '.join(["'%s'" % str(c) for c in self.primary_key_columns]))
try:
- statement = self.compile(self._get_clause, lockmode=lockmode)
+ statement = self.compile(_get_clause, lockmode=lockmode)
return self._select_statement(statement, params=params, populate_existing=reload, version_check=(lockmode is not None))[0]
except IndexError:
return None
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 462954f6b..7a5b3bbaa 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -167,7 +167,7 @@ class LazyLoader(AbstractRelationLoader):
# determine if our "lazywhere" clause is the same as the mapper's
# get() clause. then we can just use mapper.get()
- self.use_get = not self.uselist and query.Query(self.mapper)._get_clause.compare(self.lazywhere)
+ self.use_get = not self.uselist and query.Query(self.mapper)._get_clause[0].compare(self.lazywhere)
if self.use_get:
self.logger.info(str(self.parent_property) + " will use query.get() to optimize instance loads")
diff --git a/setup.py b/setup.py
index 092d0d508..fa1901af9 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@ use_setuptools()
from setuptools import setup, find_packages
setup(name = "SQLAlchemy",
- version = "0.3.11",
+ version = "0.3.12",
description = "Database Abstraction Library",
author = "Mike Bayer",
author_email = "mike_mp@zzzcomputing.com",
diff --git a/test/orm/mapper.py b/test/orm/mapper.py
index 77776e73e..f2e204c43 100644
--- a/test/orm/mapper.py
+++ b/test/orm/mapper.py
@@ -35,6 +35,13 @@ class MapperTest(MapperSuperTest):
u2 = s.get(User, 7)
self.assert_(u is not u2)
+ def testgetparamnames(self):
+ s = users.select(users.c.user_id!=12).alias('users')
+ mapper(User, s)
+ sess = create_session()
+ assert sess.query(User).get(7).user_name == 'jack'
+
+
def testunicodeget(self):
"""test that Query.get properly sets up the type for the bind parameter. using unicode would normally fail
on postgres, mysql and oracle unless it is converted to an encoded string"""
diff --git a/test/sql/query.py b/test/sql/query.py
index 6880b33f2..f8594c13f 100644
--- a/test/sql/query.py
+++ b/test/sql/query.py
@@ -280,6 +280,17 @@ class QueryTest(PersistTest):
assert False
except exceptions.InvalidRequestError, e:
assert str(e) == "Ambiguous column name 'user_id' in result set! try 'use_labels' option on select statement."
+
+ def test_column_label_targeting(self):
+ users.insert().execute(user_id=7, user_name='ed')
+
+ for s in (
+ users.select().alias('foo'),
+ users.select().alias(users.name),
+ ):
+ row = s.select(use_labels=True).execute().fetchone()
+ assert row[s.c.user_id] == 7
+ assert row[s.c.user_name] == 'ed'
def test_keys(self):
self.users.insert().execute(user_id=1, user_name='foo')