From a7dd68f98bee462b816ffcad3fae9600e63b02d6 Mon Sep 17 00:00:00 2001 From: joeljons Date: Mon, 16 Mar 2026 22:54:57 +0100 Subject: [PATCH 1/2] Bind to localhost when finding available ports Signed-off-by: joeljons --- .../impl/common/ClientConfigurator.java | 2 +- .../impl/common/ClientConfiguratorTest.java | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/databricks/jdbc/dbclient/impl/common/ClientConfigurator.java b/src/main/java/com/databricks/jdbc/dbclient/impl/common/ClientConfigurator.java index e6c296e54e..b64bbe3a44 100644 --- a/src/main/java/com/databricks/jdbc/dbclient/impl/common/ClientConfigurator.java +++ b/src/main/java/com/databricks/jdbc/dbclient/impl/common/ClientConfigurator.java @@ -286,7 +286,7 @@ public int findAvailablePort(List initialPorts) { boolean isPortAvailable(int port) { try (ServerSocket serverSocket = new ServerSocket()) { serverSocket.setReuseAddress(true); - serverSocket.bind(new InetSocketAddress(port)); + serverSocket.bind(new InetSocketAddress("localhost", port)); return true; } catch (IOException e) { return false; diff --git a/src/test/java/com/databricks/jdbc/dbclient/impl/common/ClientConfiguratorTest.java b/src/test/java/com/databricks/jdbc/dbclient/impl/common/ClientConfiguratorTest.java index 2a76d22905..ccf11201be 100644 --- a/src/test/java/com/databricks/jdbc/dbclient/impl/common/ClientConfiguratorTest.java +++ b/src/test/java/com/databricks/jdbc/dbclient/impl/common/ClientConfiguratorTest.java @@ -392,11 +392,19 @@ void testFindAvailablePort() throws Exception { int result = configurator.findAvailablePort(ports); assertEquals(availablePort, result); + // Test with a single available port which is bound to the wildcard address + try (ServerSocket serverSocket = new ServerSocket()) { + serverSocket.setReuseAddress(true); + serverSocket.bind(new InetSocketAddress(availablePort)); + result = configurator.findAvailablePort(ports); + assertEquals(availablePort, result); + } + // Test with multiple ports, first unavailable int secondAvailablePort = findFreePort(); try (ServerSocket serverSocket = new ServerSocket()) { serverSocket.setReuseAddress(true); - serverSocket.bind(new InetSocketAddress(availablePort)); + serverSocket.bind(new InetSocketAddress("localhost", availablePort)); ports = List.of(availablePort, secondAvailablePort); result = configurator.findAvailablePort(ports); assertEquals(secondAvailablePort, result); @@ -405,7 +413,7 @@ void testFindAvailablePort() throws Exception { // Test incremental search - first port unavailable, finds next available in sequence try (ServerSocket serverSocket2 = new ServerSocket()) { serverSocket2.setReuseAddress(true); - serverSocket2.bind(new InetSocketAddress(availablePort)); + serverSocket2.bind(new InetSocketAddress("localhost", availablePort)); ports = List.of(availablePort); result = configurator.findAvailablePort(ports); assertTrue( @@ -414,7 +422,7 @@ void testFindAvailablePort() throws Exception { // 3. The returned port should actually be available try (ServerSocket testSocket = new ServerSocket()) { testSocket.setReuseAddress(true); - testSocket.bind(new InetSocketAddress(result)); + testSocket.bind(new InetSocketAddress("localhost", result)); assertNotNull(testSocket, "Returned port should be available for binding"); } } @@ -441,9 +449,9 @@ void testFindAvailablePortThrowsExceptionWhenNoPortsAvailable() throws Exception try (ServerSocket socket1 = new ServerSocket(); ServerSocket socket2 = new ServerSocket()) { socket1.setReuseAddress(true); - socket1.bind(new InetSocketAddress(port1)); + socket1.bind(new InetSocketAddress("localhost", port1)); socket2.setReuseAddress(true); - socket2.bind(new InetSocketAddress(port2)); + socket2.bind(new InetSocketAddress("localhost", port2)); // First test with multiple specified ports List unavailablePorts = List.of(port1, port2); @@ -473,7 +481,7 @@ protected boolean isPortAvailable(int port) { private int findFreePort() { try (ServerSocket socket = new ServerSocket()) { socket.setReuseAddress(true); - socket.bind(new InetSocketAddress(0)); + socket.bind(new InetSocketAddress("localhost", 0)); return socket.getLocalPort(); } catch (IOException e) { throw new RuntimeException("Failed to find free port", e); From 5a409303a4f016d3aa89ebc9337295fecf907a4a Mon Sep 17 00:00:00 2001 From: joeljons Date: Tue, 17 Mar 2026 12:25:24 +0100 Subject: [PATCH 2/2] Add changelog entry Signed-off-by: joeljons --- NEXT_CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 8a427736ac..def870d3ae 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -17,6 +17,7 @@ - `DatabaseMetaData.getColumns()` with null catalog parameter now retrieves columns from all available catalogs when using SQL Execution API. ### Fixed +- Fixed local port availability check to bind to `localhost` instead of the wildcard address. This prevents the OAuth browser authentication from failing when the port is already used. - Fixed statement timeout when the server returns `TIMEDOUT_STATE` directly in the `ExecuteStatement` response (e.g. query queued under load), the driver now throws `SQLTimeoutException` instead of `DatabricksHttpException`. - Fixed Thrift polling infinite loop when server restarts invalidate operation handles, and added configurable timeout (`MetadataOperationTimeout`, default 300s) with sleep between polls for metadata operations. - Fixed `DatabricksParameterMetaData.countParameters` and `DatabricksStatement.trimCommentsAndWhitespaces` with a `SqlCommentParser` utility class.