microsoft/mssql-jdbc

When connecting with encrypt=true method, the Connection.abort(Executor) method does not work correctly

FischerRo2 opened this issue · 4 comments

Driver version

Provide the JDBC driver version (e.g. 10.2.0).
12.4.1

SQL Server version

Microsoft SQL Server 2017 (RTM-CU31-GDR) (KB5021126) - 14.0.3460.9 (X64) Jan 25 2023 08:42:43 Copyright (C) 2017 Microsoft Corporation Developer Edition (64-bit) on Windows Server 2012 R2 Datacenter 6.3 (Build 9600: ) (Hypervisor)

Client Operating System

Windows 10

JAVA/JVM version

11.0.13+8

Problem description

if using Connections with encrypt=true it ist not possible to break an running Call () to the Database with the jdbc Connection Method
This is the stack trace of the hanging connection, which cannot be aborted using the abort(executor) method from the other thread
grafik
In my test I using die command "waitfor DELAY '00:10:00' to simulate a bad long running SQL.

The Problem is that with enabled ssl encryption the method "final void close()" in the class TDSChannel is calling disableSSL():

        if (null != sslSocket)
            disableSSL();

and this Method is using the same java lock witch is using in the method ProxyInputStream.readInternal(...).

Expected behavior

The corresponding socket is closed and the hanging thread aborts with a SQLException

Actual behavior

The on DB call hanging Thread can not abort.

Thanks for the ticket.

This is an interesting issue. I am looking into the problem and will try a replicate the issue for further investigation.

hi @FischerRo2

Can you please share any repro code that would reproduce the issue? What is the connection string you are using?

Also, just to clarify, are you only seeing this issue when encrypt=true? i.e. does it work with encrypt=false?

hi @lilgreenbird
yes i only see the issue with encrypt=true or without the property, respectively.

With encrypt=false, correctly the db connection socket is closed and the running thread waiting for the database connection is interrupted with an exception.
Simple Java test case:

package jdbc;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

import java.sql.Statement;
import java.sql.*;
import java.util.Properties;

/**
 * @author github.com/FischerRo2
 * 
 * Simple Testcase To Check Connection.abort
 */
class AbortTest {

	@Test
	void test() throws SQLException, InterruptedException {
		
		String testdburl  = System.getProperty("testdburl");
		String testdbuser = System.getProperty("testdbuser");
		String testdbpw = System.getProperty("testdbpw");
		assertNotNull(testdburl,"no testdburl Systemproperty");		 
		assertNotNull(testdbuser,"no testdbuser Systemproperty"); // user
		assertNotNull(testdbpw,"no testdbpw Systemproperty"); // password
		
		Properties props = new Properties();
		props.put("user", testdbuser);
		props.put("password", testdbpw);
		class ExceptionValue {
			volatile SQLException value;
		}
		Connection threadConnection = DriverManager.getConnection(testdburl, props);
		
		ExceptionValue exceptionValue = new ExceptionValue();
		Thread thread = new Thread( () -> {  
			try (Connection con = threadConnection;
					Statement statement= con.createStatement()  ) {
				statement.executeUpdate("waitfor DELAY '00:00:02'"); /// 2000 milliseconds Wait
				
			} catch (SQLException e) {
				exceptionValue.value = e;
			}	
		});
		
		long time = System.currentTimeMillis();
		thread.start();
		Thread.sleep(200L); // 200 milliseconds Wait
		assertTrue(thread.isAlive(), "Database Connection not ok? Thread exception: " + exceptionValue.value);
		threadConnection.abort(command -> new Thread(command, "DB-Connection-Abort").start());
		Thread.sleep(500L);
		assertFalse(thread.isAlive(), "Thread should not Alive");
		assertNotNull(exceptionValue.value, "Thread has not throw an SQLException");
		thread.join();
		System.out.println(System.currentTimeMillis() - time);
	}
	

}

We believe we have identified a defect and are looking into possible resolutions. We will update you when we have more details