diff --git a/integration-tests/mysql-client-tests/java/MySQLConnectorTest.java b/integration-tests/mysql-client-tests/java/MySQLConnectorTest.java index 689aa4b79c1..3bed99ab294 100644 --- a/integration-tests/mysql-client-tests/java/MySQLConnectorTest.java +++ b/integration-tests/mysql-client-tests/java/MySQLConnectorTest.java @@ -1,8 +1,10 @@ import java.sql.Connection; import java.sql.DriverManager; +import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; public class MySQLConnectorTest { @@ -62,6 +64,59 @@ public class MySQLConnectorTest { }; public static void main(String[] args) { + testStatements(args); + testServerSideCursors(args); + System.exit(0); + } + + // testServerSideCursors does a simple smoke test with server-side cursors to make sure + // results can be read. Note that we don't test results here; this is just a high level + // smoke test that we can execute server-side cursors logic without the server erroring out. + // This test was added for a regression where server-side cursor logic was getting + // corrupted result set memory and sending invalid data to the client, which caused the + // server to error out and crash the connection. If any errors are encountered, a stack trace + // is printed and this function exits with a non-zero code. + // For more details, see: https://github.com/dolthub/dolt/issues/9125 + private static void testServerSideCursors(String[] args) { + String user = args[0]; + String port = args[1]; + String db = args[2]; + + try { + String url = "jdbc:mysql://127.0.0.1:" + port + "/" + db + + "?useServerPrepStmts=true&useCursorFetch=true"; + Connection conn = DriverManager.getConnection(url, user, ""); + + executePreparedQuery(conn, "SELECT 1;"); + executePreparedQuery(conn, "SELECT database();"); + executePreparedQuery(conn, "SHOW COLLATION;"); + executePreparedQuery(conn, "SHOW COLLATION;"); + executePreparedQuery(conn, "SHOW COLLATION;"); + } catch (SQLException ex) { + System.out.println("An error occurred."); + ex.printStackTrace(); + System.exit(1); + } + } + + // executePreparedQuery executes the specified |query| using |conn| as a prepared statement, + // and uses server-side cursor to fetch results. This method does not do any validation of + // results from the query. It is simply a smoke test to ensure the connection doesn't crash. + private static void executePreparedQuery(Connection conn, String query) throws SQLException { + PreparedStatement stmt = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY); + stmt.setFetchSize(25); // needed to ensure a server-side cursor is used + + ResultSet rs = stmt.executeQuery(); + while (rs.next()) {} + + rs.close(); + stmt.close(); + } + + // testStatements executes the queries from |queries| and asserts their results from + // |expectedResults|. If any errors are encountered, a stack trace is printed and this + // function exits with a non-zero code. + private static void testStatements(String[] args) { Connection conn = null; String user = args[0]; @@ -109,7 +164,6 @@ public static void main(String[] args) { } } } - System.exit(0); } catch (SQLException ex) { System.out.println("An error occurred."); ex.printStackTrace();