From: Mike Bayer Date: Tue, 16 Oct 2007 16:00:37 +0000 (+0000) Subject: - query.get() and related functions (like many-to-one lazyloading) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c262a3b9e5bf621bd30806c13d43eb9871d9805b;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - 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. --- diff --git a/CHANGES b/CHANGES index 70c8753816..973db91da7 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 d51fd75c38..a85410369b 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 462954f6bb..7a5b3bbaa0 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 092d0d5085..fa1901af91 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 77776e73e8..f2e204c438 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 6880b33f2c..f8594c13fa 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')