]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- query.get() and related functions (like many-to-one lazyloading)
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 16 Oct 2007 16:00:37 +0000 (16:00 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 16 Oct 2007 16:00:37 +0000 (16:00 +0000)
generate randomly-generated bind parameter names, to prevent
name conflicts with bind parameters that already exist in the
mapped selectable.

CHANGES
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/strategies.py
setup.py
test/orm/mapper.py
test/sql/query.py

diff --git a/CHANGES b/CHANGES
index 70c875381668142786c8061a2f1671b8313434ed..973db91da712f1e1f6d92a3211f6b5d8e466b0dc 100644 (file)
--- 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
index d51fd75c38f458897d0223ee024b0a0860be9282..a85410369b27b8fee39c7217ab01850c8face7bb 100644 (file)
@@ -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
index 462954f6bbe6582b42e27c4404ca3ea9b8beb005..7a5b3bbaa06c2a8f63b4a8e87dd916682b5733e8 100644 (file)
@@ -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")
 
index 092d0d50858104af1b27b1a2eaa66844fa0b71c8..fa1901af91c335fece5f4f9379d15898aaba7082 100644 (file)
--- 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",
index 77776e73e867267a2dbe0405295e135352077259..f2e204c43866f3619cd98579870bfdcc0d7d9322 100644 (file)
@@ -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"""
index 6880b33f2c66e4b95adce47a7e0b4b4701d8c607..f8594c13fa27d8f7cb94b7896a0bb768492e61f2 100644 (file)
@@ -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')