Fixed issue where the :paramref:`.ColumnOperators.like.escape` and similar
parameters did not allow an empty string as an argument that would be
passed through as the "escape" character; this is a supported syntax by
PostgreSQL. Pull requset courtesy Martin Caslavsky.
Fixes: #9907
Closes: #9908
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/9908
Pull-request-sha:
d7ecc1778a07b17adfa58050b44f6e2945dd1448
Change-Id: I39adb765a1b9650fe891883ed0973df66adc4e81
--- /dev/null
+.. change::
+ :tags: bug, postgresql
+ :tickets: 9907
+
+ Fixed issue where the :paramref:`.ColumnOperators.like.escape` and similar
+ parameters did not allow an empty string as an argument that would be
+ passed through as the "escape" character; this is a supported syntax by
+ PostgreSQL. Pull requset courtesy Martin Caslavsky.
self.process(binary.right, **kw),
) + (
" ESCAPE " + self.render_literal_value(escape, sqltypes.STRINGTYPE)
- if escape
+ if escape is not None
else ""
)
self.process(binary.right, **kw),
) + (
" ESCAPE " + self.render_literal_value(escape, sqltypes.STRINGTYPE)
- if escape
+ if escape is not None
else ""
)
binary.right._compiler_dispatch(self, **kw),
) + (
" ESCAPE " + self.render_literal_value(escape, sqltypes.STRINGTYPE)
- if escape
+ if escape is not None
else ""
)
binary.right._compiler_dispatch(self, **kw),
) + (
" ESCAPE " + self.render_literal_value(escape, sqltypes.STRINGTYPE)
- if escape
+ if escape is not None
else ""
)
from sqlalchemy import select
from sqlalchemy import Sequence
from sqlalchemy import SmallInteger
+from sqlalchemy import sql
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import testing
"SELECT c1 # c2 AS anon_1",
)
+ def test_ilike_escaping(self):
+ dialect = postgresql.dialect()
+ self.assert_compile(
+ sql.column("foo").ilike("bar", escape="\\"),
+ "foo ILIKE %(foo_1)s ESCAPE '\\\\'",
+ )
+
+ self.assert_compile(
+ sql.column("foo").ilike("bar", escape=""),
+ "foo ILIKE %(foo_1)s ESCAPE ''",
+ dialect=dialect,
+ )
+
+ self.assert_compile(
+ sql.column("foo").notilike("bar", escape="\\"),
+ "foo NOT ILIKE %(foo_1)s ESCAPE '\\\\'",
+ )
+
+ self.assert_compile(
+ sql.column("foo").notilike("bar", escape=""),
+ "foo NOT ILIKE %(foo_1)s ESCAPE ''",
+ dialect=dialect,
+ )
+
class InsertOnConflictTest(fixtures.TablesTest, AssertsCompiledSQL):
__dialect__ = postgresql.dialect()
checkparams={"x_1": "a%b_c"},
)
+ def test_like_escape_empty(self):
+ self.assert_compile(
+ column("x").like("y", escape=""),
+ "x LIKE :x_1 ESCAPE ''",
+ checkparams={"x_1": "y"},
+ )
+
def test_ilike(self):
self.assert_compile(
column("x").ilike("y"),
checkparams={"x_1": "a%b_c"},
)
+ def test_ilike_escape_empty(self):
+ self.assert_compile(
+ column("x").ilike("y", escape=""),
+ "lower(x) LIKE lower(:x_1) ESCAPE ''",
+ checkparams={"x_1": "y"},
+ )
+
def test_not_like(self):
self.assert_compile(
column("x").not_like("y"),
checkparams={"x_1": "a%b_c"},
)
+ def test_not_like_escape_empty(self):
+ self.assert_compile(
+ column("x").not_like("y", escape=""),
+ "x NOT LIKE :x_1 ESCAPE ''",
+ checkparams={"x_1": "y"},
+ )
+
def test_not_ilike(self):
self.assert_compile(
column("x").not_ilike("y"),
checkparams={"x_1": "a%b_c"},
)
+ def test_not_ilike_escape_empty(self):
+ self.assert_compile(
+ column("x").not_ilike("y", escape=""),
+ "lower(x) NOT LIKE lower(:x_1) ESCAPE ''",
+ checkparams={"x_1": "y"},
+ )
+
def test_startswith(self):
self.assert_compile(
column("x").startswith("y"),