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

public class ShowEngineStatusNotWorking {
   StringBuilder resultSummary = new StringBuilder();

   private void runQuery(String query, boolean cursorFetch) {
      try {
         addResult(runInThread(query, cursorFetch));
      } catch (Exception e) {
         addResult("Got exception: " + e.getMessage());
         //e.printStackTrace();
      }
   }

   private void addResult(String msg) {
      System.out.println(msg);
      resultSummary.append(msg).append("\n");
   }

   private static String format(String query, boolean useCursorFetch) {
      return "QUERY: '" + query + "' cursorFetch:" + useCursorFetch;
   }

   /**
    * Run the query
    */
   private static String run(String query, boolean cursorFetch) {
      boolean hasResult;
      int resultSize = 0;
      Statement st;
      Connection conn = null;
      final long start = System.currentTimeMillis();
      long execTime;
      try {
         conn = setupConnection(cursorFetch);
         st = conn.createStatement();
         System.out.println("Connected:" + conn.getMetaData().getDriverVersion());
         ResultSet rs = st.executeQuery(query);
         execTime = System.currentTimeMillis() - start;
         hasResult = rs.next();
         if (hasResult) {
            while (hasResult) {
               resultSize++;
               String col1 = rs.getString(1);
               hasResult = rs.next();
               System.out.println(col1);
            }
         }
      } catch (Exception e) {
         return "Exception: " + e.getMessage();
      } finally {

        if (conn != null) {
           try {
              conn.close();
           } catch (SQLException e) {
              System.out.println("Exception closing connection");
           }
        }
      }

      String resultStr =  resultSize > 0 ? "Results: " + resultSize : "Results: none";
      return resultStr + "  Exec time:" + execTime +"ms";
   }

   private String runInThread(String query, boolean cursorFetch) {
      String resultStr;
      final ExecutorService executor = Executors.newSingleThreadExecutor();
      final Future<?> future = executor.submit((Callable<Object>) () -> ShowEngineStatusNotWorking.run(query, cursorFetch));
      try {
         final String result = (String) future.get(30, TimeUnit.SECONDS);
         return format(query, cursorFetch) + "  " + result;
      } catch (TimeoutException e) {
         resultStr = "TimeoutException (30secs)";
         future.cancel(true);
      } catch (InterruptedException e) {
         resultStr = "InterruptedException";
         System.out.println("task interrupted");
      } catch (ExecutionException e) {
         resultStr = "InterruptedException";
         System.out.println("task aborted");
      } finally {
         executor.shutdownNow();
      }

      return format(query, cursorFetch) + "   " + resultStr;
   }

   private static Connection setupConnection(boolean useCursorFetch) {
      Connection conn;
      String myDriver = "com.mysql.jdbc.Driver";
      String myUrl = "jdbc:mysql://localhost:3307/";
      Properties connectionProps = new Properties();
      connectionProps.put("user", "root");
      connectionProps.put("password", "somerootpassword");

      if (useCursorFetch) {
         connectionProps.put("defaultFetchSize", "5000");
         connectionProps.put("useCursorFetch", "true");
      }
      try {
         Class.forName(myDriver);
         conn = DriverManager.getConnection(myUrl, connectionProps);
      } catch (ClassNotFoundException | SQLException e) {
         throw new RuntimeException(e);
      }
      return conn;
   }

   public static void main(String[] args) {
      ShowEngineStatusNotWorking show = new ShowEngineStatusNotWorking();
      show.runQuery("show engine `InnoDB` STATUS", true);   // WORKS OK
      show.runQuery("show engine `InnoDB` STATUS", false);  // WORKS OK
      show.runQuery("show engine `BLACKHOLE` STATUS", true); // Hangs
      show.runQuery("show engine `BLACKHOLE` STATUS", false); // WORKS OK
      try {
         Thread.sleep(40000);
      } catch (InterruptedException e) {
         throw new RuntimeException(e);
      }
      System.out.println("\n\nSummary:\n" + show.resultSummary);
   }
}