diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-10-16 16:00:37 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-10-16 16:00:37 +0000 |
commit | c262a3b9e5bf621bd30806c13d43eb9871d9805b (patch) | |
tree | 0403a02c4cbc960ce0370a2d1587a5bffd25db13 | |
parent | d12392c38d570b4a3c14a02c75e2ea9476c34ffb (diff) | |
download | sqlalchemy-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-- | CHANGES | 7 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/query.py | 16 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 2 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | test/orm/mapper.py | 7 | ||||
-rw-r--r-- | test/sql/query.py | 11 |
6 files changed, 39 insertions, 6 deletions
@@ -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") @@ -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') |