From: Mike Bayer Date: Fri, 31 Jan 2014 22:57:17 +0000 (-0500) Subject: - Fixed bug whereby SQLite compiler failed to propagate compiler arguments X-Git-Tag: rel_0_9_2~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b360dbf7ebb7cc5bb290847fdd9818d205244a94;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Fixed bug whereby SQLite compiler failed to propagate compiler arguments such as "literal binds" into a CAST expression. - Fixed bug whereby binary type would fail in some cases if used with a "test" dialect, such as a DefaultDialect or other dialect with no DBAPI. - Fixed bug where "literal binds" wouldn't work with a bound parameter that's a binary type. A similar, but different, issue is fixed in 0.8. --- diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst index 8f1daf0037..fbb6db3355 100644 --- a/doc/build/changelog/changelog_09.rst +++ b/doc/build/changelog/changelog_09.rst @@ -14,6 +14,26 @@ .. changelog:: :version: 0.9.2 + .. change:: + :tags: bug, sqlite + + Fixed bug whereby SQLite compiler failed to propagate compiler arguments + such as "literal binds" into a CAST expression. + + .. change:: + :tags: bug, sql + + Fixed bug whereby binary type would fail in some cases + if used with a "test" dialect, such as a DefaultDialect or other + dialect with no DBAPI. + + .. change:: + :tags: bug, sql, py3k + + Fixed bug where "literal binds" wouldn't work with a bound parameter + that's a binary type. A similar, but different, issue is fixed + in 0.8. + .. change:: :tags: bug, sql :tickets: 2927 diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py index d8aa58c2c1..4e1223eeaf 100644 --- a/lib/sqlalchemy/dialects/sqlite/base.py +++ b/lib/sqlalchemy/dialects/sqlite/base.py @@ -456,9 +456,9 @@ class SQLiteCompiler(compiler.SQLCompiler): def visit_cast(self, cast, **kwargs): if self.dialect.supports_cast: - return super(SQLiteCompiler, self).visit_cast(cast) + return super(SQLiteCompiler, self).visit_cast(cast, **kwargs) else: - return self.process(cast.clause) + return self.process(cast.clause, **kwargs) def visit_extract(self, extract, **kw): try: diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 4448f7c7b0..673e5f89b7 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -961,7 +961,6 @@ class SQLCompiler(Compiled): literal_binds=False, skip_bind_expression=False, **kwargs): - if not skip_bind_expression and bindparam.type._has_bind_expression: bind_expression = bindparam.type.bind_expression(bindparam) return self.process(bind_expression, diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index d779caaeac..61d906e1c5 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -790,7 +790,7 @@ class _Binary(TypeEngine): def literal_processor(self, dialect): def process(value): - value = value.decode(self.dialect.encoding).replace("'", "''") + value = value.decode(dialect.encoding).replace("'", "''") return "'%s'" % value return process @@ -801,6 +801,9 @@ class _Binary(TypeEngine): # Python 3 - sqlite3 doesn't need the `Binary` conversion # here, though pg8000 does to indicate "bytea" def bind_processor(self, dialect): + if dialect.dbapi is None: + return None + DBAPIBinary = dialect.dbapi.Binary def process(value): diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 53b9f68fc6..cd9d318645 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -1185,6 +1185,12 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): dialect=dialect ) + self.assert_compile( + select([literal(util.b("foo"))]), + "SELECT 'foo' AS anon_1", + dialect=dialect + ) + assert_raises_message( exc.CompileError, "Bind parameter 'foo' without a renderable value not allowed here.", diff --git a/test/sql/test_types.py b/test/sql/test_types.py index 3df19874bf..fd927b51ac 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -1203,6 +1203,17 @@ class BinaryTest(fixtures.TestBase, AssertsExecutionResults): count().scalar(), 1) + def test_literal_roundtrip(self): + compiled = select([cast(literal(util.b("foo")), LargeBinary)]).compile( + dialect=testing.db.dialect, + compile_kwargs={"literal_binds": True}) + result = testing.db.execute(compiled) + eq_(result.scalar(), util.b("foo")) + + def test_bind_processor_no_dbapi(self): + b = LargeBinary() + eq_(b.bind_processor(default.DefaultDialect()), None) + def load_stream(self, name): f = os.path.join(os.path.dirname(__file__), "..", name) return open(f, mode='rb').read()