apache/arrow-java

[Java] Invocation of close method from ArrowFlightConnection throws a SQLException when using catalog as parameter

Open

#66 ouverte le 17 juil. 2024

Voir sur GitHub
 (5 commentaires) (0 réactions) (1 assigné)Java (132 forks)auto 404
Type: bughelp wanted

Métriques du dépôt

Stars
 (89 stars)
Métriques de merge PR
 (Métriques PR en attente)

Description

Describe the bug, including details regarding any error messages, version, and platform.

Affected version flight-sql-jdbc-driver version 17.0.0

Description

With flight-sql-jdbc-driver version 17 the method org.apache.arrow.driver.jdbc.ArrowFlightConnection#close returns a SQLException when the connection has defined a value for catalog parameter.

I was testing this change and I am facing a problem when the java.sql.Connection#close method of the JDBC connection is called.

I am receiving the following error invoking the method.

Exception in thread "main" java.sql.SQLException: UNKNOWN: Uncaught exception in the SynchronizationContext. Re-thrown.
	at org.apache.calcite.avatica.Helper.createException(Helper.java:56)
	at org.apache.calcite.avatica.Helper.createException(Helper.java:41)
	at org.apache.arrow.driver.jdbc.ArrowFlightConnection.close(ArrowFlightConnection.java:187)
	at com.arrowflight.test.Main.test7(Main.java:249)
	at com.arrowflight.test.Main.main(Main.java:27)
Caused by: io.grpc.StatusRuntimeException: UNKNOWN: Uncaught exception in the SynchronizationContext. Re-thrown.
	at io.grpc.Status.asRuntimeException(Status.java:525)
	at io.grpc.internal.RetriableStream$1.uncaughtException(RetriableStream.java:75)
	at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:96)
	at io.grpc.SynchronizationContext.execute(SynchronizationContext.java:126)
	at io.grpc.internal.RetriableStream.safeCloseMasterListener(RetriableStream.java:838)
	at io.grpc.internal.RetriableStream.cancel(RetriableStream.java:531)
	at io.grpc.internal.RetriableStream.start(RetriableStream.java:393)
	at io.grpc.internal.ClientCallImpl.startInternal(ClientCallImpl.java:285)
	at io.grpc.internal.ClientCallImpl.start(ClientCallImpl.java:184)
	at io.grpc.ForwardingClientCall.start(ForwardingClientCall.java:32)
	at org.apache.arrow.flight.grpc.ClientInterceptorAdapter$FlightClientCall.start(ClientInterceptorAdapter.java:142)
	at io.grpc.ForwardingClientCall.start(ForwardingClientCall.java:32)
	at io.grpc.stub.MetadataUtils$HeaderAttachingClientInterceptor$HeaderAttachingClientCall.start(MetadataUtils.java:75)
	at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:335)
	at io.grpc.stub.ClientCalls.asyncUnaryRequestCall(ClientCalls.java:311)
	at io.grpc.stub.ClientCalls.blockingServerStreamingCall(ClientCalls.java:210)
	at org.apache.arrow.flight.impl.FlightServiceGrpc$FlightServiceBlockingStub.doAction(FlightServiceGrpc.java:874)
	at org.apache.arrow.flight.FlightClient.doAction(FlightClient.java:168)
	at org.apache.arrow.flight.FlightClient.closeSession(FlightClient.java:686)
	at org.apache.arrow.flight.sql.FlightSqlClient.closeSession(FlightSqlClient.java:998)
	at org.apache.arrow.driver.jdbc.client.ArrowFlightSqlClientHandler.close(ArrowFlightSqlClientHandler.java:224)
	at org.apache.arrow.util.AutoCloseables.close(AutoCloseables.java:97)
	at org.apache.arrow.util.AutoCloseables.close(AutoCloseables.java:75)
	at org.apache.arrow.driver.jdbc.ArrowFlightConnection.close(ArrowFlightConnection.java:181)
	... 2 more
Caused by: java.util.concurrent.RejectedExecutionException: Task io.grpc.internal.SerializingExecutor@6ecdbab8 rejected from java.util.concurrent.ThreadPoolExecutor@3dd4a6fa[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 25]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
	at io.grpc.internal.SerializingExecutor.schedule(SerializingExecutor.java:102)
	at io.grpc.internal.SerializingExecutor.execute(SerializingExecutor.java:95)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.closedInternal(ClientCallImpl.java:736)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.closed(ClientCallImpl.java:680)
	at io.grpc.internal.RetriableStream$4.run(RetriableStream.java:843)
	at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:94)
	... 23 more

I think the reason is the following. Checking this code:

https://github.com/apache/arrow/blob/6a2e19a852b367c72d7b12da4d104456491ed8b7/java/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightConnection.java#L174-L189

https://github.com/apache/arrow/blob/6a2e19a852b367c72d7b12da4d104456491ed8b7/java/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightConnection.java#L174-L189

I think that line line 181 from org.apache.arrow.driver.jdbc.ArrowFlightConnection#close should be remove for avoding the problem. The close is already done at 175.

Also, I would remove the is if: https://github.com/apache/arrow/blob/6a2e19a852b367c72d7b12da4d104456491ed8b7/java/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/client/ArrowFlightSqlClientHandler.java#L222-L225 why not invoking the closeSession when the catalog was not set?

It can be reproducible with this code:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

public class CloseIssue {
    private static final String URL = "jdbc:arrow-flight-sql://localhost:9994?catalog=mydatabase&useEncryption=0";

    public static void main(String[] args) throws Exception {
        Class.forName("org.apache.arrow.driver.jdbc.ArrowFlightJdbcDriver");
        try (Connection conn = DriverManager.getConnection(URL, "admin", "admin")) {
            try (PreparedStatement pst = conn.prepareStatement("select 1");
                 ResultSet rs = pst.executeQuery()) {
                ResultSetMetaData rsm = rs.getMetaData();
                for (int i = 1; i <= rsm.getColumnCount(); i++) {
                    System.out.print(rsm.getColumnName(i) + " (" + rsm.getColumnType(i) + ") ");
                }
            }
        }
    }
}

This problems does not happen with prior versions, so it can be considered a regression.

Component(s)

Java

Guide contributeur