From 9c29290a99509b44bfc9263c863ade3823a3df3b Mon Sep 17 00:00:00 2001 From: John Bolliger Date: Thu, 25 Jun 2026 12:02:24 -0700 Subject: [PATCH] Fix PostgreSQL connection leak on failed establishment If post-connect setup (PGConnection unwrap / addDataType registration) throws, close the freshly-opened physical connection before propagating, otherwise the server-side backend leaks - the caller only ever sees the exception and never gets a handle to close. Mirrors the native adapter discarding a connection that could not be fully established. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../PostgreSQLRubyJdbcConnection.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java b/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java index ded69a537..7b7383c7c 100644 --- a/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +++ b/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java @@ -241,19 +241,35 @@ protected Connection newConnection() throws RaiseException, SQLException { } throw ex; } - final PGConnection pgConnection; - if ( connection instanceof PGConnection ) { - pgConnection = (PGConnection) connection; + // The physical connection is open now; if any of the post-connect + // setup below fails we must close it, otherwise the server-side backend + // leaks (the caller only sees the exception and never gets a handle to + // close). This mirrors the native adapter discarding a connection that + // could not be fully established. + try { + final PGConnection pgConnection; + if ( connection instanceof PGConnection ) { + pgConnection = (PGConnection) connection; + } + else { + pgConnection = connection.unwrap(PGConnection.class); + } + pgConnection.addDataType("daterange", DateRangeType.class); + pgConnection.addDataType("tsrange", TsRangeType.class); + pgConnection.addDataType("tstzrange", TstzRangeType.class); + pgConnection.addDataType("int4range", Int4RangeType.class); + pgConnection.addDataType("int8range", Int8RangeType.class); + pgConnection.addDataType("numrange", NumRangeType.class); } - else { - pgConnection = connection.unwrap(PGConnection.class); + catch (SQLException|RuntimeException ex) { + try { + connection.close(); + } + catch (SQLException closeError) { + ex.addSuppressed(closeError); + } + throw ex; } - pgConnection.addDataType("daterange", DateRangeType.class); - pgConnection.addDataType("tsrange", TsRangeType.class); - pgConnection.addDataType("tstzrange", TstzRangeType.class); - pgConnection.addDataType("int4range", Int4RangeType.class); - pgConnection.addDataType("int8range", Int8RangeType.class); - pgConnection.addDataType("numrange", NumRangeType.class); return connection; }