diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcCloseable.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcCloseable.java new file mode 100644 index 0000000000..74671437d8 --- /dev/null +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcCloseable.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.arrow.adbc.core; + +import java.util.Arrays; + +/** + * An ADBC resource which can be closed. + */ +public interface AdbcCloseable extends AutoCloseable { + @Override + void close() throws AdbcException; + + /** + * Closes all autoCloseables if not null and suppresses subsequent exceptions if more than one. + * @param autoCloseables the closeables to close + */ + public static void close(AdbcCloseable... adbcCloseables) throws AdbcException { + close(Arrays.asList(adbcCloseables)); + } + + /** + * Closes all {@link AdbcCloseable} instances if not null and suppresses subsequent exceptions if more than one. + * @param ac the closeables to close + */ + public static void close(Iterable ac) throws AdbcException { + // this method can be called on a single object if it implements Iterable + // like for example VectorContainer make sure we handle that properly + if (ac == null) { + return; + } else if (ac instanceof AdbcCloseable) { + ((AdbcCloseable) ac).close(); + return; + } + + AdbcException topLevelException = null; + for (AdbcCloseable closeable : ac) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (AdbcException e) { + if (topLevelException == null) { + topLevelException = e; + } else if (e != topLevelException) { + topLevelException.addSuppressed(e); + } + } + } + if (topLevelException != null) { + throw topLevelException; + } + } +} diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java index 060c65e816..744079a88d 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java @@ -28,7 +28,7 @@ *

Connections are not required to be thread-safe, but they can be used from multiple threads so * long as clients take care to serialize accesses to a connection. */ -public interface AdbcConnection extends AutoCloseable, AdbcOptions { +public interface AdbcConnection extends AdbcCloseable, AdbcOptions { /** * Cancel execution of a query. * diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java index 723acfc0da..79565281d8 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java @@ -24,7 +24,7 @@ * remote/networked databases, for in-memory databases, this object provides an explicit point of * ownership. */ -public interface AdbcDatabase extends AutoCloseable, AdbcOptions { +public interface AdbcDatabase extends AdbcCloseable, AdbcOptions { /** Create a new connection to the database. */ AdbcConnection connect() throws AdbcException; } diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java index 193bbaa96c..25a5c620f0 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java @@ -72,6 +72,11 @@ public static AdbcException io(String message) { return new AdbcException(message, /*cause*/ null, AdbcStatusCode.IO, null, 0); } + /** Create a new exception with code {@link AdbcStatusCode#IO} from an existing exception. */ + public static AdbcException io(Throwable cause) { + return new AdbcException(cause.getMessage(), cause, AdbcStatusCode.IO, null, 0); + } + /** Create a new exception with code {@link AdbcStatusCode#INVALID_STATE}. */ public static AdbcException invalidState(String message) { return new AdbcException(message, /*cause*/ null, AdbcStatusCode.INVALID_STATE, null, 0); diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java index a1f9e0f3b4..c26380aa83 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java @@ -41,7 +41,7 @@ *

Statements are not required to be thread-safe, but they can be used from multiple threads so * long as clients take care to serialize accesses to a statement. */ -public interface AdbcStatement extends AutoCloseable, AdbcOptions { +public interface AdbcStatement extends AdbcCloseable, AdbcOptions { /** * Cancel execution of a query. * @@ -181,7 +181,7 @@ default Schema getParameterSchema() throws AdbcException { void prepare() throws AdbcException; /** The result of executing a query with a result set. */ - class QueryResult implements AutoCloseable { + class QueryResult implements AdbcCloseable { private final long affectedRows; private final ArrowReader reader; @@ -206,8 +206,12 @@ public String toString() { /** Close the contained reader. */ @Override - public void close() throws IOException { - reader.close(); + public void close() throws AdbcException { + try { + reader.close(); + } catch (IOException e) { + throw AdbcException.io(e); + } } } diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java index f099cb64c8..39ddd1e21e 100644 --- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java +++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java @@ -204,9 +204,15 @@ public void setAutoCommit(boolean enableAutoCommit) throws AdbcException { } @Override - public void close() throws Exception { + public void close() throws AdbcException { clientCache.invalidateAll(); - AutoCloseables.close(client, allocator); + try { + AutoCloseables.close(client, allocator); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw AdbcException.io(e); + } } @Override diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDatabase.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDatabase.java index af8221d6b0..e40326ef45 100644 --- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDatabase.java +++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDatabase.java @@ -76,7 +76,7 @@ public AdbcConnection connect() throws AdbcException { } @Override - public void close() throws Exception {} + public void close() throws AdbcException {} @Override public String toString() { diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java index 6a00ca2346..4bc10e5f60 100644 --- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java +++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java @@ -309,10 +309,10 @@ public void prepare() throws AdbcException { } @Override - public void close() throws Exception { + public void close() throws AdbcException { // TODO(https://github.com/apache/arrow/issues/39814): this is annotated wrongly upstream if (preparedStatement != null) { - AutoCloseables.close(preparedStatement); + preparedStatement.close(); } } diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java index 2987815d14..086946acab 100644 --- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java +++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java @@ -508,8 +508,14 @@ public void setIsolationLevel(IsolationLevel level) throws AdbcException { } @Override - public void close() throws Exception { - AutoCloseables.close(connection, allocator); + public void close() throws AdbcException { + try { + AutoCloseables.close(connection, allocator); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw AdbcException.io(e); + } } private void checkAutoCommit() throws AdbcException, SQLException { diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDataSourceDatabase.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDataSourceDatabase.java index 2f6b7154cb..c860383562 100644 --- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDataSourceDatabase.java +++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDataSourceDatabase.java @@ -77,9 +77,13 @@ public AdbcConnection connect() throws AdbcException { } @Override - public void close() throws Exception { + public void close() throws AdbcException { if (connection != null) { - connection.close(); + try { + connection.close(); + } catch (SQLException e) { + throw AdbcException.io(e); + } } connection = null; } diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java index 339c31adc1..9072ff9708 100644 --- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java +++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java @@ -371,8 +371,14 @@ public void prepare() throws AdbcException { } @Override - public void close() throws Exception { - AutoCloseables.close(reader, resultSet, statement); + public void close() throws AdbcException { + try { + AutoCloseables.close(reader, resultSet, statement); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw AdbcException.io(e); + } } private static final class BulkState {