From 525dc82ee2294ec95716955f382a03b24b7d7f11 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 29 May 2009 21:57:15 +0000 Subject: [PATCH] merged -r5987:5991 of trunk --- CHANGES | 15 +++++++++++++++ lib/sqlalchemy/sql/compiler.py | 2 +- lib/sqlalchemy/sql/expression.py | 2 +- test/sql/query.py | 15 --------------- test/sql/select.py | 16 +++++++++++++++- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/CHANGES b/CHANGES index 4f47bfe09f..94a0acf88a 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,21 @@ CHANGES - orm - Fixed bug introduced in 0.5.4 whereby Composite types fail when default-holding columns are flushed. + +- sql + - Removed an obscure feature of execute() (including connection, + engine, Session) whereby a bindparam() construct can be sent as + a key to the params dictionary. This usage is undocumented + and is at the core of an issue whereby the bindparam() object + created implicitly by a text() construct may have the same + hash value as a string placed in the params dictionary and + may result in an inappropriate match when computing the final + bind parameters. Internal checks for this condition would + add significant latency to the critical task of parameter + rendering, so the behavior is removed. This is a backwards + incompatible change for any application that may have been + using this feature, however the feature has never been + documented. 0.5.4p2 ======= diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index db864daa00..66018934e1 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -225,7 +225,7 @@ class SQLCompiler(engine.Compiled): params = util.column_dict(params) pd = {} for bindparam, name in self.bind_names.iteritems(): - for paramname in (bindparam, bindparam.key, bindparam.shortname, name): + for paramname in (bindparam.key, bindparam.shortname, name): if paramname in params: pd[name] = params[paramname] break diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 3fd95642e6..68696ae8e4 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -2098,7 +2098,7 @@ class _TextClause(ClauseElement): if bindparams is not None: for b in bindparams: self.bindparams[b.key] = b - + @property def type(self): if self.typemap is not None and len(self.typemap) == 1: diff --git a/test/sql/query.py b/test/sql/query.py index b124428c63..4e1faa1c50 100644 --- a/test/sql/query.py +++ b/test/sql/query.py @@ -313,21 +313,6 @@ class QueryTest(TestBase): r = s.execute(userid='fred').fetchall() assert len(r) == 1 - u = bindparam('userid', unique=True) - s = users.select(and_(users.c.user_name==u, users.c.user_name==u)) - r = s.execute({u:'fred'}).fetchall() - assert len(r) == 1 - - def test_bindparams_in_params(self): - """test that a _BindParamClause itself can be a key in the params dict""" - - users.insert().execute(user_id = 7, user_name = 'jack') - users.insert().execute(user_id = 8, user_name = 'fred') - - u = bindparam('userid') - r = users.select(users.c.user_name==u).execute({u:'fred'}).fetchall() - assert len(r) == 1 - def test_bindparam_shortname(self): """test the 'shortname' field on BindParamClause.""" users.insert().execute(user_id = 7, user_name = 'jack') diff --git a/test/sql/select.py b/test/sql/select.py index 4bee94e142..ee0cb6b392 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -1157,7 +1157,21 @@ UNION SELECT mytable.myid FROM mytable" s = select([table1], or_(table1.c.myid==7, table1.c.myid==8, table1.c.myid==bindparam('myid_1'))) self.assertRaisesMessage(exc.CompileError, "conflicts with unique bind parameter of the same name", str, s) - + def test_binds_no_hash_collision(self): + """test that construct_params doesn't corrupt dict due to hash collisions""" + + total_params = 100000 + + in_clause = [':in%d' % i for i in range(total_params)] + params = dict(('in%d' % i, i) for i in range(total_params)) + sql = 'text clause %s' % ', '.join(in_clause) + t = text(sql) + assert len(t.bindparams) == total_params + c = t.compile() + pp = c.construct_params(params) + assert len(set(pp)) == total_params + assert len(set(pp.values())) == total_params + def test_bind_as_col(self): t = table('foo', column('id')) -- 2.47.3