From 1294532109442bbc07facc47315beab5537de156 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 20 Oct 2009 16:56:15 +0000 Subject: [PATCH] - Repeat expressions in the columns clause of a select are deduped based on the identity of each clause element, not the actual string. This allows positional elements to render correctly even if they all render identically, such as "qmark" style bind parameters. [ticket:1574] --- CHANGES | 7 ++++++ lib/sqlalchemy/sql/compiler.py | 6 ++--- test/sql/test_select.py | 42 ++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 231f97828f..4a6b28bde3 100644 --- a/CHANGES +++ b/CHANGES @@ -27,6 +27,13 @@ CHANGES - Fixed the "numeric" paramstyle, which apparently is the default paramstyle used by Informixdb. + - Repeat expressions in the columns clause of a select + are deduped based on the identity of each clause element, + not the actual string. This allows positional + elements to render correctly even if they all render + identically, such as "qmark" style bind parameters. + [ticket:1574] + - postgresql - Added support for reflecting the DOUBLE PRECISION type, via a new postgres.PGDoublePrecision object. diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 9c06d99277..5e2de5b034 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -530,16 +530,16 @@ class DefaultCompiler(engine.Compiled): column_clause_args = {} # the actual list of columns to print in the SELECT column list. - inner_columns = util.unique_list( + inner_columns = [ c for c in [ self.process( self.label_select_column(select, co, asfrom=asfrom), within_columns_clause=True, **column_clause_args) - for co in select.inner_columns + for co in util.unique_list(select.inner_columns) ] if c is not None - ) + ] text = "SELECT " # we're off to a good start ! if select._prefixes: diff --git a/test/sql/test_select.py b/test/sql/test_select.py index 941973e5fb..51cdaeb52c 100644 --- a/test/sql/test_select.py +++ b/test/sql/test_select.py @@ -183,7 +183,49 @@ sq.myothertable_othername AS sq_myothertable_othername FROM (" + sqstring + ") A , dialect=default.DefaultDialect(paramstyle='pyformat') ) + def test_dupe_columns(self): + """test that deduping is performed against clause element identity, not rendered result.""" + self.assert_compile( + select([column('a'), column('a'), column('a')]), + "SELECT a, a, a" + , dialect=default.DefaultDialect() + ) + + c = column('a') + self.assert_compile( + select([c, c, c]), + "SELECT a" + , dialect=default.DefaultDialect() + ) + + a, b = column('a'), column('b') + self.assert_compile( + select([a, b, b, b, a, a]), + "SELECT a, b" + , dialect=default.DefaultDialect() + ) + + self.assert_compile( + select([bindparam('a'), bindparam('b'), bindparam('c')]), + "SELECT :a, :b, :c" + , dialect=default.DefaultDialect(paramstyle='named') + ) + + self.assert_compile( + select([bindparam('a'), bindparam('b'), bindparam('c')]), + "SELECT ?, ?, ?" + , dialect=default.DefaultDialect(paramstyle='qmark'), + ) + + self.assert_compile( + select(["a", "a", "a"]), + "SELECT a, a, a" + ) + + s = select([bindparam('a'), bindparam('b'), bindparam('c')]) + s = s.compile(dialect=default.DefaultDialect(paramstyle='qmark')) + eq_(s.positiontup, ['a', 'b', 'c']) def test_nested_uselabels(self): """test nested anonymous label generation. this -- 2.47.3