From: Federico Caselli Date: Wed, 29 Apr 2026 20:11:35 +0000 (+0200) Subject: Postgresql default to no backslash escaping X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=08eee60332fbd3bbf7da6885b5de3748b40fb36a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Postgresql default to no backslash escaping Changed the default backslash escape value in the PostgreSQL dialect to ``False`` to align it with the default value of ``standard_conforming_strings=on``. This change should not affect most users since the value is set at driver initialization on first connect. Fixes: #13268 Change-Id: I9b7986f1ee466fab3cab88e3f6117e313e3376cd --- diff --git a/doc/build/changelog/unreleased_21/11450.rst b/doc/build/changelog/unreleased_21/11450.rst index 371f86dec1..3f60d15c3d 100644 --- a/doc/build/changelog/unreleased_21/11450.rst +++ b/doc/build/changelog/unreleased_21/11450.rst @@ -4,4 +4,4 @@ Added :paramref:`.selectinload.chunksize` parameter to :func`.selectinload` allowing users to configure the number of primary keys sent per IN clause - when loading reltaionships. Pull request courtesy bekapono. + when loading relationships. Pull request courtesy bekapono. diff --git a/doc/build/changelog/unreleased_21/13268.rst b/doc/build/changelog/unreleased_21/13268.rst new file mode 100644 index 0000000000..b55c4da9b1 --- /dev/null +++ b/doc/build/changelog/unreleased_21/13268.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: postgresql, usecase + :tickets: 13268 + + Changed the default backslash escape value in the PostgreSQL dialect to + ``False`` to align it with the default value of + ``standard_conforming_strings=on``. This change should not affect most users + since the value is set at driver initialization on first connect. diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index 1702bc70c9..58c925d08b 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -3522,7 +3522,7 @@ class PGDialect(default.DefaultDialect): reflection_options = ("postgresql_ignore_search_path",) - _backslash_escapes = True + _backslash_escapes = False _supports_create_index_concurrently = True _supports_drop_index_concurrently = True _supports_jsonb_subscripting = True diff --git a/test/dialect/postgresql/test_compiler.py b/test/dialect/postgresql/test_compiler.py index 142a7c808f..fc460cac18 100644 --- a/test/dialect/postgresql/test_compiler.py +++ b/test/dialect/postgresql/test_compiler.py @@ -3265,7 +3265,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): dialect = postgresql.dialect() self.assert_compile( sql.column("foo").ilike("bar", escape="\\"), - "foo ILIKE %(foo_1)s::VARCHAR ESCAPE '\\\\'", + "foo ILIKE %(foo_1)s::VARCHAR ESCAPE '\\'", ) self.assert_compile( @@ -3276,7 +3276,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): self.assert_compile( sql.column("foo").notilike("bar", escape="\\"), - "foo NOT ILIKE %(foo_1)s::VARCHAR ESCAPE '\\\\'", + "foo NOT ILIKE %(foo_1)s::VARCHAR ESCAPE '\\'", ) self.assert_compile( diff --git a/test/dialect/postgresql/test_dialect.py b/test/dialect/postgresql/test_dialect.py index ce8ff27a2d..e9ee74aac2 100644 --- a/test/dialect/postgresql/test_dialect.py +++ b/test/dialect/postgresql/test_dialect.py @@ -989,17 +989,18 @@ class MiscBackendTest( def test_backslash_escapes_detection(self, explicit_setting, expected): engine = engines.testing_engine() - if explicit_setting is not None: - - @event.listens_for(engine, "connect", insert=True) - @event.listens_for(engine, "first_connect", insert=True) - def connect(dbapi_connection, connection_record): - cursor = dbapi_connection.cursor() - cursor.execute( - "SET SESSION standard_conforming_strings = %s" - % ("off" if not explicit_setting else "on") - ) - dbapi_connection.commit() + # check the default value before connect + eq_(engine.dialect._backslash_escapes, False) + + @event.listens_for(engine, "connect", insert=True) + @event.listens_for(engine, "first_connect", insert=True) + def connect(dbapi_connection, connection_record): + cursor = dbapi_connection.cursor() + cursor.execute( + "SET SESSION standard_conforming_strings = %s" + % ("off" if not explicit_setting else "on") + ) + dbapi_connection.commit() with engine.connect(): eq_(engine.dialect._backslash_escapes, expected) diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py index d1f2233d94..a815cb6317 100644 --- a/test/sql/test_operators.py +++ b/test/sql/test_operators.py @@ -3219,14 +3219,14 @@ class LikeTest(fixtures.TestBase, testing.AssertsCompiledSQL): def test_like_7(self): self.assert_compile( self.table1.c.myid.ilike("somstr", escape="\\"), - "mytable.myid ILIKE %(myid_1)s::VARCHAR ESCAPE '\\\\'", + "mytable.myid ILIKE %(myid_1)s::VARCHAR ESCAPE '\\'", dialect=postgresql.dialect(), ) def test_like_8(self): self.assert_compile( ~self.table1.c.myid.ilike("somstr", escape="\\"), - "mytable.myid NOT ILIKE %(myid_1)s::VARCHAR ESCAPE '\\\\'", + "mytable.myid NOT ILIKE %(myid_1)s::VARCHAR ESCAPE '\\'", dialect=postgresql.dialect(), )