]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Use ``;`` instead of ``select 1`` to ping PostgreSQL
authorFederico Caselli <cfederico87@gmail.com>
Tue, 13 Sep 2022 19:47:50 +0000 (21:47 +0200)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 15 Sep 2022 13:31:44 +0000 (09:31 -0400)
Fixes: #8491
Change-Id: I941d2a3cf92e5609e2045a53cec94522340951db

doc/build/changelog/unreleased_20/8491.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/postgresql/asyncpg.py
lib/sqlalchemy/dialects/postgresql/pg8000.py
lib/sqlalchemy/dialects/postgresql/psycopg.py
lib/sqlalchemy/testing/suite/test_dialect.py

diff --git a/doc/build/changelog/unreleased_20/8491.rst b/doc/build/changelog/unreleased_20/8491.rst
new file mode 100644 (file)
index 0000000..1555157
--- /dev/null
@@ -0,0 +1,12 @@
+.. change::
+    :tags: usecase, postgresql
+    :tickets: 8491
+
+    The "ping" query emitted when configuring
+    :paramref:`_sa.create_engine.pool_pre_ping` for psycopg, asyncpg and
+    pg8000, but not for psycopg2, has been changed to be an empty query (``;``)
+    instead of ``SELECT 1``; additionally, for the asyncpg driver, the
+    unnecessary use of a prepared statement for this query has been fixed.
+    Rationale is to eliminate the need for PostgreSQL to produce a query plan
+    when the ping is emitted. The operation is not currently supported by the
+    ``psycopg2`` driver which continues to use ``SELECT 1``.
\ No newline at end of file
index a84bece4fd46fa7f5afd3fa62314308e69d7de31..4cc04d20aee5be5f6ab5d03a6aadffd1ae33d885 100644 (file)
@@ -741,6 +741,12 @@ class AsyncAdapt_asyncpg_connection(AdaptedConnection):
         else:
             self.isolation_level = self._isolation_setting
 
+    def ping(self):
+        try:
+            _ = self.await_(self._connection.fetchrow(";"))
+        except Exception as error:
+            self._handle_exception(error)
+
     def set_isolation_level(self, level):
         if self._started:
             self.rollback()
@@ -996,6 +1002,17 @@ class PGDialect_asyncpg(PGDialect):
         util.coerce_kw_type(opts, "port", int)
         return ([], opts)
 
+    def do_ping(self, dbapi_connection):
+        try:
+            dbapi_connection.ping()
+        except self.dbapi.Error as err:
+            if self.is_disconnect(err, dbapi_connection, None):
+                return False
+            else:
+                raise
+        else:
+            return True
+
     @classmethod
     def get_pool_class(cls, url):
 
index ce9a3bb6c1193d395dc73a7c73a0694b5374841c..d4b159b73b21e4f55c4fd011ba248d4ca64d88c6 100644 (file)
@@ -559,5 +559,9 @@ class PGDialect_pg8000(PGDialect):
         else:
             return None
 
+    @util.memoized_property
+    def _dialect_specific_select_one(self):
+        return ";"
+
 
 dialect = PGDialect_pg8000
index 633357a74062be377adb09ea9e039b410b74528c..371bf2bc232d75f5509a306316091d6e91f0edfa 100644 (file)
@@ -505,6 +505,10 @@ class PGDialect_psycopg(_PGDialect_common_psycopg):
         else:
             self.do_commit(connection.connection)
 
+    @util.memoized_property
+    def _dialect_specific_select_one(self):
+        return ";"
+
 
 class AsyncAdapt_psycopg_cursor:
     __slots__ = ("_cursor", "await_", "_rows")
index 55276e21b2e0cfcc6813e055018852c9d58edc50..bb2dd6574f97724d262ea64de078015e545a1f2b 100644 (file)
@@ -8,6 +8,7 @@ from .. import config
 from .. import engines
 from .. import eq_
 from .. import fixtures
+from .. import is_true
 from .. import ne_
 from .. import provide_metadata
 from ..assertions import expect_raises_message
@@ -24,6 +25,16 @@ from ... import select
 from ... import String
 
 
+class PingTest(fixtures.TestBase):
+    __backend__ = True
+
+    def test_do_ping(self):
+        with testing.db.connect() as conn:
+            is_true(
+                testing.db.dialect.do_ping(conn.connection.dbapi_connection)
+            )
+
+
 class ExceptionTest(fixtures.TablesTest):
     """Test basic exception wrapping.