diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java index 196747395b2..90c34614b5f 100644 --- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java +++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java @@ -328,6 +328,7 @@ public void run() { LOGGER.warn("Error close connection", e1); } } + Thread.currentThread().interrupt(); } return completer; } diff --git a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java index 2fe6dc3aab8..cc5002b22a8 100644 --- a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java +++ b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java @@ -34,6 +34,7 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.sql.Connection; @@ -52,6 +53,7 @@ import static java.lang.String.format; import static org.apache.zeppelin.jdbc.JDBCInterpreter.COMMON_MAX_LINE; import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_DRIVER; +import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_KEY; import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_PASSWORD; import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_PRECODE; import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_STATEMENT_PRECODE; @@ -510,6 +512,35 @@ void testAutoCompletion() throws IOException, InterpreterException { assertEquals(true, completionList.contains(correctCompletionKeyword)); } + @Test + void testCreateOrUpdateSqlCompleterRestoresInterruptStatusOnTimeout() throws Exception { + Properties properties = new Properties(); + properties.setProperty("common.max_count", "1000"); + properties.setProperty("common.max_retry", "3"); + properties.setProperty("default.driver", "org.h2.Driver"); + properties.setProperty("default.url", getJdbcConnection()); + properties.setProperty("default.user", ""); + properties.setProperty("default.password", ""); + JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(properties); + + // createOrUpdateSqlCompleter is private, so invoke it via reflection. + Method createOrUpdateSqlCompleter = JDBCInterpreter.class.getDeclaredMethod( + "createOrUpdateSqlCompleter", SqlCompleter.class, Connection.class, String.class, + String.class, int.class); + createOrUpdateSqlCompleter.setAccessible(true); + + // Entering already interrupted makes awaitTermination throw InterruptedException + // immediately, deterministically hitting the catch block under test. + Thread.currentThread().interrupt(); + try { + createOrUpdateSqlCompleter.invoke(jdbcInterpreter, null, null, DEFAULT_KEY, "sel", 3); + assertTrue(Thread.currentThread().isInterrupted()); + } finally { + // Clear the interrupt flag so it doesn't leak into subsequent tests. + Thread.interrupted(); + } + } + private Properties getDBProperty(String dbPrefix, String dbUser, String dbPassowrd) throws IOException {