/* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. The MySQL Connector/J is licensed under the terms of the GPLv2 , like most MySQL Connectors. There are special exceptions to the terms and conditions of the GPLv2 as it is applied to this software, see the FOSS License Exception . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package testsuite.simple; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.CharArrayReader; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; import java.math.BigDecimal; import java.sql.BatchUpdateException; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.Properties; import com.mysql.jdbc.CharsetMapping; import com.mysql.jdbc.MySQLConnection; import com.mysql.jdbc.NotImplemented; import com.mysql.jdbc.ParameterBindings; import com.mysql.jdbc.SQLError; import com.mysql.jdbc.StringUtils; import com.mysql.jdbc.exceptions.MySQLStatementCancelledException; import com.mysql.jdbc.exceptions.MySQLTimeoutException; import com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor; import testsuite.BaseTestCase; public class StatementsTest extends BaseTestCase { private static final int MAX_COLUMN_LENGTH = 255; private static final int MAX_COLUMNS_TO_TEST = 40; private static final int STEP = 8; /** * Runs all test cases in this test suite * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(StatementsTest.class); } /** * Creates a new StatementsTest object. * * @param name */ public StatementsTest(String name) { super(name); } @Override public void setUp() throws Exception { super.setUp(); this.stmt.executeUpdate("DROP TABLE IF EXISTS statement_test"); this.stmt.executeUpdate("DROP TABLE IF EXISTS statement_batch_test"); this.stmt.executeUpdate( "CREATE TABLE statement_test (id int not null primary key auto_increment, strdata1 varchar(255) not null, strdata2 varchar(255))"); try { this.stmt.executeUpdate("CREATE TABLE statement_batch_test (id int not null primary key auto_increment, " + "strdata1 varchar(255) not null, strdata2 varchar(255), UNIQUE INDEX (strdata1))"); } catch (SQLException sqlEx) { if (sqlEx.getMessage().indexOf("max key length") != -1) { createTable("statement_batch_test", "(id int not null primary key auto_increment, strdata1 varchar(175) not null, strdata2 varchar(175), " + "UNIQUE INDEX (strdata1))"); } } for (int i = 6; i < MAX_COLUMNS_TO_TEST; i += STEP) { this.stmt.executeUpdate("DROP TABLE IF EXISTS statement_col_test_" + i); StringBuilder insertBuf = new StringBuilder("INSERT INTO statement_col_test_"); StringBuilder stmtBuf = new StringBuilder("CREATE TABLE IF NOT EXISTS statement_col_test_"); stmtBuf.append(i); insertBuf.append(i); stmtBuf.append(" ("); insertBuf.append(" VALUES ("); boolean firstTime = true; for (int j = 0; j < i; j++) { if (!firstTime) { stmtBuf.append(","); insertBuf.append(","); } else { firstTime = false; } stmtBuf.append("col_"); stmtBuf.append(j); stmtBuf.append(" VARCHAR("); stmtBuf.append(MAX_COLUMN_LENGTH); stmtBuf.append(")"); insertBuf.append("'"); int numChars = 16; for (int k = 0; k < numChars; k++) { insertBuf.append("A"); } insertBuf.append("'"); } stmtBuf.append(")"); insertBuf.append(")"); this.stmt.executeUpdate(stmtBuf.toString()); this.stmt.executeUpdate(insertBuf.toString()); } // explicitly set the catalog to exercise code in execute(), executeQuery() and executeUpdate() // FIXME: Only works on Windows! // this.conn.setCatalog(this.conn.getCatalog().toUpperCase()); } @Override public void tearDown() throws Exception { try { this.stmt.executeUpdate("DROP TABLE statement_test"); for (int i = 6; i < MAX_COLUMNS_TO_TEST; i += STEP) { StringBuilder stmtBuf = new StringBuilder("DROP TABLE IF EXISTS statement_col_test_"); stmtBuf.append(i); this.stmt.executeUpdate(stmtBuf.toString()); } try { this.stmt.executeUpdate("DROP TABLE statement_batch_test"); } catch (SQLException sqlEx) { } } finally { super.tearDown(); } } public void testAccessorsAndMutators() throws SQLException { assertTrue("Connection can not be null, and must be same connection", this.stmt.getConnection() == this.conn); // Set max rows, to exercise code in execute(), executeQuery() and executeUpdate() Statement accessorStmt = null; try { accessorStmt = this.conn.createStatement(); accessorStmt.setMaxRows(1); accessorStmt.setMaxRows(0); // FIXME, test that this actually affects rows returned accessorStmt.setMaxFieldSize(255); assertTrue("Max field size should match what was set", accessorStmt.getMaxFieldSize() == 255); try { accessorStmt.setMaxFieldSize(Integer.MAX_VALUE); fail("Should not be able to set max field size > max_packet_size"); } catch (SQLException sqlEx) { // ignore } accessorStmt.setCursorName("undef"); accessorStmt.setEscapeProcessing(true); accessorStmt.setFetchDirection(java.sql.ResultSet.FETCH_FORWARD); int fetchDirection = accessorStmt.getFetchDirection(); assertTrue("Set fetch direction != get fetch direction", fetchDirection == java.sql.ResultSet.FETCH_FORWARD); try { accessorStmt.setFetchDirection(Integer.MAX_VALUE); fail("Should not be able to set fetch direction to invalid value"); } catch (SQLException sqlEx) { // ignore } try { accessorStmt.setMaxRows(50000000 + 10); fail("Should not be able to set max rows > 50000000"); } catch (SQLException sqlEx) { // ignore } try { accessorStmt.setMaxRows(Integer.MIN_VALUE); fail("Should not be able to set max rows < 0"); } catch (SQLException sqlEx) { // ignore } int fetchSize = this.stmt.getFetchSize(); try { accessorStmt.setMaxRows(4); accessorStmt.setFetchSize(Integer.MAX_VALUE); fail("Should not be able to set FetchSize > max rows"); } catch (SQLException sqlEx) { // ignore } try { accessorStmt.setFetchSize(-2); fail("Should not be able to set FetchSize < 0"); } catch (SQLException sqlEx) { // ignore } assertTrue("Fetch size before invalid setFetchSize() calls should match fetch size now", fetchSize == this.stmt.getFetchSize()); } finally { if (accessorStmt != null) { try { accessorStmt.close(); } catch (SQLException sqlEx) { // ignore } accessorStmt = null; } } } public void testAutoIncrement() throws SQLException { try { this.stmt.setFetchSize(Integer.MIN_VALUE); this.stmt.executeUpdate("INSERT INTO statement_test (strdata1) values ('blah')", Statement.RETURN_GENERATED_KEYS); int autoIncKeyFromApi = -1; this.rs = this.stmt.getGeneratedKeys(); if (this.rs.next()) { autoIncKeyFromApi = this.rs.getInt(1); } else { fail("Failed to retrieve AUTO_INCREMENT using Statement.getGeneratedKeys()"); } this.rs.close(); int autoIncKeyFromFunc = -1; this.rs = this.stmt.executeQuery("SELECT LAST_INSERT_ID()"); if (this.rs.next()) { autoIncKeyFromFunc = this.rs.getInt(1); } else { fail("Failed to retrieve AUTO_INCREMENT using LAST_INSERT_ID()"); } if ((autoIncKeyFromApi != -1) && (autoIncKeyFromFunc != -1)) { assertTrue("Key retrieved from API (" + autoIncKeyFromApi + ") does not match key retrieved from LAST_INSERT_ID() " + autoIncKeyFromFunc + ") function", autoIncKeyFromApi == autoIncKeyFromFunc); } else { fail("AutoIncrement keys were '0'"); } } finally { if (this.rs != null) { try { this.rs.close(); } catch (Exception ex) { // ignore } } this.rs = null; } } /** * Tests all variants of numerical types (signed/unsigned) for correct * operation when used as return values from a prepared statement. * * @throws Exception */ public void testBinaryResultSetNumericTypes() throws Exception { /* * TINYINT 1 -128 127 SMALLINT 2 -32768 32767 MEDIUMINT 3 -8388608 * 8388607 INT 4 -2147483648 2147483647 BIGINT 8 -9223372036854775808 * 9223372036854775807 */ String unsignedMinimum = "0"; String tiMinimum = "-128"; String tiMaximum = "127"; String utiMaximum = "255"; String siMinimum = "-32768"; String siMaximum = "32767"; String usiMaximum = "65535"; String miMinimum = "-8388608"; String miMaximum = "8388607"; String umiMaximum = "16777215"; String iMinimum = "-2147483648"; String iMaximum = "2147483647"; String uiMaximum = "4294967295"; String biMinimum = "-9223372036854775808"; String biMaximum = "9223372036854775807"; String ubiMaximum = "18446744073709551615"; try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBinaryResultSetNumericTypes"); this.stmt.executeUpdate("CREATE TABLE testBinaryResultSetNumericTypes(rowOrder TINYINT, ti TINYINT,uti TINYINT UNSIGNED, si SMALLINT," + "usi SMALLINT UNSIGNED, mi MEDIUMINT,umi MEDIUMINT UNSIGNED, i INT, ui INT UNSIGNED,bi BIGINT, ubi BIGINT UNSIGNED)"); PreparedStatement inserter = this.conn.prepareStatement("INSERT INTO testBinaryResultSetNumericTypes VALUES (?,?,?,?,?,?,?,?,?,?,?)"); inserter.setInt(1, 0); inserter.setString(2, tiMinimum); inserter.setString(3, unsignedMinimum); inserter.setString(4, siMinimum); inserter.setString(5, unsignedMinimum); inserter.setString(6, miMinimum); inserter.setString(7, unsignedMinimum); inserter.setString(8, iMinimum); inserter.setString(9, unsignedMinimum); inserter.setString(10, biMinimum); inserter.setString(11, unsignedMinimum); inserter.executeUpdate(); inserter.setInt(1, 1); inserter.setString(2, tiMaximum); inserter.setString(3, utiMaximum); inserter.setString(4, siMaximum); inserter.setString(5, usiMaximum); inserter.setString(6, miMaximum); inserter.setString(7, umiMaximum); inserter.setString(8, iMaximum); inserter.setString(9, uiMaximum); inserter.setString(10, biMaximum); inserter.setString(11, ubiMaximum); inserter.executeUpdate(); PreparedStatement selector = this.conn.prepareStatement("SELECT * FROM testBinaryResultSetNumericTypes ORDER by rowOrder ASC"); this.rs = selector.executeQuery(); assertTrue(this.rs.next()); assertTrue(this.rs.getString(2).equals(tiMinimum)); assertTrue(this.rs.getString(3).equals(unsignedMinimum)); assertTrue(this.rs.getString(4).equals(siMinimum)); assertTrue(this.rs.getString(5).equals(unsignedMinimum)); assertTrue(this.rs.getString(6).equals(miMinimum)); assertTrue(this.rs.getString(7).equals(unsignedMinimum)); assertTrue(this.rs.getString(8).equals(iMinimum)); assertTrue(this.rs.getString(9).equals(unsignedMinimum)); assertTrue(this.rs.getString(10).equals(biMinimum)); assertTrue(this.rs.getString(11).equals(unsignedMinimum)); assertTrue(this.rs.next()); assertTrue(this.rs.getString(2) + " != " + tiMaximum, this.rs.getString(2).equals(tiMaximum)); assertTrue(this.rs.getString(3) + " != " + utiMaximum, this.rs.getString(3).equals(utiMaximum)); assertTrue(this.rs.getString(4) + " != " + siMaximum, this.rs.getString(4).equals(siMaximum)); assertTrue(this.rs.getString(5) + " != " + usiMaximum, this.rs.getString(5).equals(usiMaximum)); assertTrue(this.rs.getString(6) + " != " + miMaximum, this.rs.getString(6).equals(miMaximum)); assertTrue(this.rs.getString(7) + " != " + umiMaximum, this.rs.getString(7).equals(umiMaximum)); assertTrue(this.rs.getString(8) + " != " + iMaximum, this.rs.getString(8).equals(iMaximum)); assertTrue(this.rs.getString(9) + " != " + uiMaximum, this.rs.getString(9).equals(uiMaximum)); assertTrue(this.rs.getString(10) + " != " + biMaximum, this.rs.getString(10).equals(biMaximum)); assertTrue(this.rs.getString(11) + " != " + ubiMaximum, this.rs.getString(11).equals(ubiMaximum)); assertTrue(!this.rs.next()); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBinaryResultSetNumericTypes"); } } /** * Tests stored procedure functionality * * @throws Exception * if an error occurs. */ public void testCallableStatement() throws Exception { if (versionMeetsMinimum(5, 0)) { CallableStatement cStmt = null; String stringVal = "abcdefg"; int intVal = 42; try { try { this.stmt.executeUpdate("DROP PROCEDURE testCallStmt"); } catch (SQLException sqlEx) { if (sqlEx.getMessage().indexOf("does not exist") == -1) { throw sqlEx; } } this.stmt.executeUpdate("DROP TABLE IF EXISTS callStmtTbl"); this.stmt.executeUpdate("CREATE TABLE callStmtTbl (x CHAR(16), y INT)"); this.stmt.executeUpdate("CREATE PROCEDURE testCallStmt(n INT, x CHAR(16), y INT) WHILE n DO SET n = n - 1;" + " INSERT INTO callStmtTbl VALUES (x, y); END WHILE;"); int rowsToCheck = 15; cStmt = this.conn.prepareCall("{call testCallStmt(?,?,?)}"); cStmt.setInt(1, rowsToCheck); cStmt.setString(2, stringVal); cStmt.setInt(3, intVal); cStmt.execute(); this.rs = this.stmt.executeQuery("SELECT x,y FROM callStmtTbl"); int numRows = 0; while (this.rs.next()) { assertTrue(this.rs.getString(1).equals(stringVal) && (this.rs.getInt(2) == intVal)); numRows++; } this.rs.close(); this.rs = null; cStmt.close(); cStmt = null; System.out.println(rowsToCheck + " rows returned"); assertTrue(numRows == rowsToCheck); } finally { try { this.stmt.executeUpdate("DROP PROCEDURE testCallStmt"); } catch (SQLException sqlEx) { if (sqlEx.getMessage().indexOf("does not exist") == -1) { throw sqlEx; } } this.stmt.executeUpdate("DROP TABLE IF EXISTS callStmtTbl"); if (cStmt != null) { cStmt.close(); } } } } public void testCancelStatement() throws Exception { if (versionMeetsMinimum(5, 0)) { Connection cancelConn = null; try { cancelConn = getConnectionWithProps((String) null); final Statement cancelStmt = cancelConn.createStatement(); cancelStmt.setQueryTimeout(1); long begin = System.currentTimeMillis(); try { cancelStmt.execute("SELECT SLEEP(30)"); } catch (SQLException sqlEx) { assertTrue("Probably wasn't actually cancelled", System.currentTimeMillis() - begin < 30000); } for (int i = 0; i < 1000; i++) { try { cancelStmt.executeQuery("SELECT 1"); } catch (SQLException timedOutEx) { break; } } // Make sure we can still use the connection... cancelStmt.setQueryTimeout(0); this.rs = cancelStmt.executeQuery("SELECT 1"); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); cancelStmt.setQueryTimeout(0); new Thread() { @Override public void run() { try { try { sleep(5000); } catch (InterruptedException iEx) { // ignore } cancelStmt.cancel(); } catch (SQLException sqlEx) { throw new RuntimeException(sqlEx.toString()); } } }.start(); begin = System.currentTimeMillis(); try { cancelStmt.execute("SELECT SLEEP(30)"); } catch (SQLException sqlEx) { assertTrue("Probably wasn't actually cancelled", System.currentTimeMillis() - begin < 30000); } for (int i = 0; i < 1000; i++) { try { cancelStmt.executeQuery("SELECT 1"); } catch (SQLException timedOutEx) { break; } } // Make sure we can still use the connection... this.rs = cancelStmt.executeQuery("SELECT 1"); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); final PreparedStatement cancelPstmt = cancelConn.prepareStatement("SELECT SLEEP(30)"); cancelPstmt.setQueryTimeout(1); begin = System.currentTimeMillis(); try { cancelPstmt.execute(); } catch (SQLException sqlEx) { assertTrue("Probably wasn't actually cancelled", System.currentTimeMillis() - begin < 30000); } for (int i = 0; i < 1000; i++) { try { cancelPstmt.executeQuery("SELECT 1"); } catch (SQLException timedOutEx) { break; } } // Make sure we can still use the connection... this.rs = cancelStmt.executeQuery("SELECT 1"); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); cancelPstmt.setQueryTimeout(0); new Thread() { @Override public void run() { try { try { sleep(5000); } catch (InterruptedException iEx) { // ignore } cancelPstmt.cancel(); } catch (SQLException sqlEx) { throw new RuntimeException(sqlEx.toString()); } } }.start(); begin = System.currentTimeMillis(); try { cancelPstmt.execute(); } catch (SQLException sqlEx) { assertTrue("Probably wasn't actually cancelled", System.currentTimeMillis() - begin < 30000); } for (int i = 0; i < 1000; i++) { try { cancelPstmt.executeQuery("SELECT 1"); } catch (SQLException timedOutEx) { break; } } // Make sure we can still use the connection... this.rs = cancelStmt.executeQuery("SELECT 1"); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); final PreparedStatement cancelClientPstmt = ((com.mysql.jdbc.Connection) cancelConn).clientPrepareStatement("SELECT SLEEP(30)"); cancelClientPstmt.setQueryTimeout(1); begin = System.currentTimeMillis(); try { cancelClientPstmt.execute(); } catch (SQLException sqlEx) { assertTrue("Probably wasn't actually cancelled", System.currentTimeMillis() - begin < 30000); } for (int i = 0; i < 1000; i++) { try { cancelStmt.executeQuery("SELECT 1"); } catch (SQLException timedOutEx) { break; } } // Make sure we can still use the connection... this.rs = cancelStmt.executeQuery("SELECT 1"); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); cancelClientPstmt.setQueryTimeout(0); new Thread() { @Override public void run() { try { try { sleep(5000); } catch (InterruptedException iEx) { // ignore } cancelClientPstmt.cancel(); } catch (SQLException sqlEx) { throw new RuntimeException(sqlEx.toString()); } } }.start(); begin = System.currentTimeMillis(); try { cancelClientPstmt.execute(); } catch (SQLException sqlEx) { assertTrue("Probably wasn't actually cancelled", System.currentTimeMillis() - begin < 30000); } for (int i = 0; i < 1000; i++) { try { cancelClientPstmt.executeQuery("SELECT 1"); } catch (SQLException timedOutEx) { break; } } // Make sure we can still use the connection... this.rs = cancelStmt.executeQuery("SELECT 1"); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); Connection forceCancel = getConnectionWithProps("queryTimeoutKillsConnection=true"); Statement forceStmt = forceCancel.createStatement(); forceStmt.setQueryTimeout(1); try { forceStmt.execute("SELECT SLEEP(30)"); fail("Statement should have been cancelled"); } catch (MySQLTimeoutException timeout) { // expected } int count = 1000; for (; count > 0; count--) { if (forceCancel.isClosed()) { break; } Thread.sleep(100); } if (count == 0) { fail("Connection was never killed"); } try { forceCancel.setAutoCommit(true); // should fail too } catch (SQLException sqlEx) { assertTrue(sqlEx.getCause() instanceof MySQLStatementCancelledException); } } finally { if (this.rs != null) { ResultSet toClose = this.rs; this.rs = null; toClose.close(); } if (cancelConn != null) { cancelConn.close(); } } } } public void testClose() throws SQLException { Statement closeStmt = null; boolean exceptionAfterClosed = false; try { closeStmt = this.conn.createStatement(); closeStmt.close(); try { closeStmt.executeQuery("SELECT 1"); } catch (SQLException sqlEx) { exceptionAfterClosed = true; } } finally { if (closeStmt != null) { try { closeStmt.close(); } catch (SQLException sqlEx) { /* ignore */ } } closeStmt = null; } assertTrue("Operations not allowed on Statement after .close() is called!", exceptionAfterClosed); } public void testEnableStreamingResults() throws Exception { Statement streamStmt = this.conn.createStatement(); ((com.mysql.jdbc.Statement) streamStmt).enableStreamingResults(); assertEquals(streamStmt.getFetchSize(), Integer.MIN_VALUE); assertEquals(streamStmt.getResultSetType(), ResultSet.TYPE_FORWARD_ONLY); } public void testHoldingResultSetsOverClose() throws Exception { Properties props = new Properties(); props.setProperty("holdResultsOpenOverStatementClose", "true"); Connection conn2 = getConnectionWithProps(props); Statement stmt2 = null; PreparedStatement pstmt2 = null; ResultSet rs2 = null; try { stmt2 = conn2.createStatement(); this.rs = stmt2.executeQuery("SELECT 1"); this.rs.next(); this.rs.getInt(1); stmt2.close(); this.rs.getInt(1); stmt2 = conn2.createStatement(); stmt2.execute("SELECT 1"); this.rs = stmt2.getResultSet(); this.rs.next(); this.rs.getInt(1); stmt2.execute("SELECT 2"); this.rs.getInt(1); pstmt2 = conn2.prepareStatement("SELECT 1"); this.rs = pstmt2.executeQuery(); this.rs.next(); this.rs.getInt(1); pstmt2.close(); this.rs.getInt(1); pstmt2 = conn2.prepareStatement("SELECT 1"); this.rs = pstmt2.executeQuery(); this.rs.next(); this.rs.getInt(1); rs2 = pstmt2.executeQuery(); this.rs.getInt(1); pstmt2.execute(); this.rs.getInt(1); rs2.close(); pstmt2 = ((com.mysql.jdbc.Connection) conn2).clientPrepareStatement("SELECT 1"); this.rs = pstmt2.executeQuery(); this.rs.next(); this.rs.getInt(1); pstmt2.close(); this.rs.getInt(1); pstmt2 = ((com.mysql.jdbc.Connection) conn2).clientPrepareStatement("SELECT 1"); this.rs = pstmt2.executeQuery(); this.rs.next(); this.rs.getInt(1); rs2 = pstmt2.executeQuery(); this.rs.getInt(1); pstmt2.execute(); this.rs.getInt(1); rs2.close(); stmt2 = conn2.createStatement(); this.rs = stmt2.executeQuery("SELECT 1"); this.rs.next(); this.rs.getInt(1); rs2 = stmt2.executeQuery("SELECT 2"); this.rs.getInt(1); this.rs = stmt2.executeQuery("SELECT 1"); this.rs.next(); this.rs.getInt(1); stmt2.executeUpdate("SET @var=1"); this.rs.getInt(1); stmt2.execute("SET @var=2"); this.rs.getInt(1); rs2.close(); } finally { if (stmt2 != null) { stmt2.close(); } } } public void testInsert() throws SQLException { try { boolean autoCommit = this.conn.getAutoCommit(); // Test running a query for an update. It should fail. try { this.conn.setAutoCommit(false); this.stmt.executeUpdate("SELECT * FROM statement_test"); } catch (SQLException sqlEx) { assertTrue("Exception thrown for unknown reason", sqlEx.getSQLState().equalsIgnoreCase("01S03")); } finally { this.conn.setAutoCommit(autoCommit); } // Test running a update for an query. It should fail. try { this.conn.setAutoCommit(false); this.rs = this.stmt.executeQuery("UPDATE statement_test SET strdata1='blah' WHERE 1=0"); } catch (SQLException sqlEx) { assertTrue("Exception thrown for unknown reason", sqlEx.getSQLState().equalsIgnoreCase(SQLError.SQL_STATE_ILLEGAL_ARGUMENT)); } finally { this.conn.setAutoCommit(autoCommit); } for (int i = 0; i < 10; i++) { int updateCount = this.stmt.executeUpdate("INSERT INTO statement_test (strdata1,strdata2) values ('abcdefg', 'poi')"); assertTrue("Update count must be '1', was '" + updateCount + "'", (updateCount == 1)); } int insertIdFromGeneratedKeys = Integer.MIN_VALUE; this.stmt.executeUpdate("INSERT INTO statement_test (strdata1, strdata2) values ('a', 'a'), ('b', 'b'), ('c', 'c')", Statement.RETURN_GENERATED_KEYS); this.rs = this.stmt.getGeneratedKeys(); if (this.rs.next()) { insertIdFromGeneratedKeys = this.rs.getInt(1); } this.rs.close(); this.rs = this.stmt.executeQuery("SELECT LAST_INSERT_ID()"); int insertIdFromServer = Integer.MIN_VALUE; if (this.rs.next()) { insertIdFromServer = this.rs.getInt(1); } assertEquals(insertIdFromGeneratedKeys, insertIdFromServer); } finally { if (this.rs != null) { try { this.rs.close(); } catch (Exception ex) { // ignore } } this.rs = null; } } /** * Tests multiple statement support * * @throws Exception */ public void testMultiStatements() throws Exception { if (versionMeetsMinimum(4, 1)) { Connection multiStmtConn = null; Statement multiStmt = null; try { Properties props = new Properties(); props.setProperty("allowMultiQueries", "true"); multiStmtConn = getConnectionWithProps(props); multiStmt = multiStmtConn.createStatement(); multiStmt.executeUpdate("DROP TABLE IF EXISTS testMultiStatements"); multiStmt.executeUpdate("CREATE TABLE testMultiStatements (field1 VARCHAR(255), field2 INT, field3 DOUBLE)"); multiStmt.executeUpdate("INSERT INTO testMultiStatements VALUES ('abcd', 1, 2)"); multiStmt.execute("SELECT field1 FROM testMultiStatements WHERE field1='abcd';UPDATE testMultiStatements SET field3=3;" + "SELECT field3 FROM testMultiStatements WHERE field3=3"); this.rs = multiStmt.getResultSet(); assertTrue(this.rs.next()); assertTrue("abcd".equals(this.rs.getString(1))); this.rs.close(); // Next should be an update count... assertTrue(!multiStmt.getMoreResults()); assertTrue("Update count was " + multiStmt.getUpdateCount() + ", expected 1", multiStmt.getUpdateCount() == 1); assertTrue(multiStmt.getMoreResults()); this.rs = multiStmt.getResultSet(); assertTrue(this.rs.next()); assertTrue(this.rs.getDouble(1) == 3); // End of multi results assertTrue(!multiStmt.getMoreResults()); assertTrue(multiStmt.getUpdateCount() == -1); } finally { if (multiStmt != null) { multiStmt.executeUpdate("DROP TABLE IF EXISTS testMultiStatements"); multiStmt.close(); } if (multiStmtConn != null) { multiStmtConn.close(); } } } } /** * Tests that NULLs and '' work correctly. * * @throws SQLException * if an error occurs */ public void testNulls() throws SQLException { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS nullTest"); this.stmt.executeUpdate("CREATE TABLE IF NOT EXISTS nullTest (field_1 CHAR(20), rowOrder INT)"); this.stmt.executeUpdate("INSERT INTO nullTest VALUES (null, 1), ('', 2)"); this.rs = this.stmt.executeQuery("SELECT field_1 FROM nullTest ORDER BY rowOrder"); this.rs.next(); assertTrue("NULL field not returned as NULL", (this.rs.getString("field_1") == null) && this.rs.wasNull()); this.rs.next(); assertTrue("Empty field not returned as \"\"", this.rs.getString("field_1").equals("") && !this.rs.wasNull()); this.rs.close(); } finally { if (this.rs != null) { try { this.rs.close(); } catch (Exception ex) { // ignore } } this.stmt.executeUpdate("DROP TABLE IF EXISTS nullTest"); } } public void testParsedConversionWarning() throws Exception { if (versionMeetsMinimum(4, 1)) { try { Properties props = new Properties(); props.setProperty("useUsageAdvisor", "true"); Connection warnConn = getConnectionWithProps(props); this.stmt.executeUpdate("DROP TABLE IF EXISTS testParsedConversionWarning"); this.stmt.executeUpdate("CREATE TABLE testParsedConversionWarning(field1 VARCHAR(255))"); this.stmt.executeUpdate("INSERT INTO testParsedConversionWarning VALUES ('1.0')"); PreparedStatement badStmt = warnConn.prepareStatement("SELECT field1 FROM testParsedConversionWarning"); this.rs = badStmt.executeQuery(); assertTrue(this.rs.next()); this.rs.getFloat(1); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testParsedConversionWarning"); } } } public void testPreparedStatement() throws SQLException { this.stmt.executeUpdate("INSERT INTO statement_test (id, strdata1,strdata2) values (999,'abcdefg', 'poi')"); this.pstmt = this.conn.prepareStatement("UPDATE statement_test SET strdata1=?, strdata2=? where id=999"); this.pstmt.setString(1, "iop"); this.pstmt.setString(2, "higjklmn"); int updateCount = this.pstmt.executeUpdate(); assertTrue("Update count must be '1', was '" + updateCount + "'", (updateCount == 1)); this.pstmt.clearParameters(); this.pstmt.close(); this.rs = this.stmt.executeQuery("SELECT id, strdata1, strdata2 FROM statement_test"); assertTrue(this.rs.next()); assertTrue(this.rs.getInt(1) == 999); assertTrue("Expected 'iop', received '" + this.rs.getString(2) + "'", "iop".equals(this.rs.getString(2))); assertTrue("Expected 'higjklmn', received '" + this.rs.getString(3) + "'", "higjklmn".equals(this.rs.getString(3))); } public void testPreparedStatementBatch() throws SQLException { this.pstmt = this.conn.prepareStatement("INSERT INTO statement_batch_test (strdata1, strdata2) VALUES (?,?)"); for (int i = 0; i < 1000; i++) { this.pstmt.setString(1, "batch_" + i); this.pstmt.setString(2, "batch_" + i); this.pstmt.addBatch(); } int[] updateCounts = this.pstmt.executeBatch(); for (int i = 0; i < updateCounts.length; i++) { assertTrue("Update count must be '1', was '" + updateCounts[i] + "'", (updateCounts[i] == 1)); } } public void testRowFetch() throws Exception { if (versionMeetsMinimum(5, 0, 5)) { createTable("testRowFetch", "(field1 int)"); this.stmt.executeUpdate("INSERT INTO testRowFetch VALUES (1)"); Connection fetchConn = null; Properties props = new Properties(); props.setProperty("useCursorFetch", "true"); try { fetchConn = getConnectionWithProps(props); PreparedStatement fetchStmt = fetchConn.prepareStatement("SELECT field1 FROM testRowFetch WHERE field1=1"); fetchStmt.setFetchSize(10); this.rs = fetchStmt.executeQuery(); assertTrue(this.rs.next()); this.stmt.executeUpdate("INSERT INTO testRowFetch VALUES (2), (3)"); fetchStmt = fetchConn.prepareStatement("SELECT field1 FROM testRowFetch ORDER BY field1"); fetchStmt.setFetchSize(1); this.rs = fetchStmt.executeQuery(); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); assertTrue(this.rs.next()); assertEquals(2, this.rs.getInt(1)); assertTrue(this.rs.next()); assertEquals(3, this.rs.getInt(1)); assertEquals(false, this.rs.next()); this.rs = fetchStmt.executeQuery(); } finally { if (fetchConn != null) { fetchConn.close(); } } } } public void testSelectColumns() throws SQLException { for (int i = 6; i < MAX_COLUMNS_TO_TEST; i += STEP) { long start = System.currentTimeMillis(); this.rs = this.stmt.executeQuery("SELECT * from statement_col_test_" + i); if (this.rs.next()) { } long end = System.currentTimeMillis(); System.out.println(i + " columns = " + (end - start) + " ms"); } } /** * Tests for PreparedStatement.setObject() * * @throws Exception */ public void testSetObject() throws Exception { Properties props = new Properties(); props.put("noDatetimeStringSync", "true"); // value=true for #5 Connection conn1 = getConnectionWithProps(props); Statement stmt1 = conn1.createStatement(); createTable("t1", " (c1 DECIMAL," // instance of String + "c2 VARCHAR(255)," // instance of String + "c3 BLOB," // instance of byte[] + "c4 DATE," // instance of java.util.Date + "c5 TIMESTAMP," // instance of String + "c6 TIME," // instance of String + "c7 TIME)"); // instance of java.sql.Timestamp this.pstmt = conn1.prepareStatement("INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?, ?)"); long currentTime = System.currentTimeMillis(); this.pstmt.setObject(1, "1000", Types.DECIMAL); this.pstmt.setObject(2, "2000", Types.VARCHAR); this.pstmt.setObject(3, new byte[] { 0 }, Types.BLOB); this.pstmt.setObject(4, new java.util.Date(currentTime), Types.DATE); this.pstmt.setObject(5, "2000-01-01 23-59-59", Types.TIMESTAMP); this.pstmt.setObject(6, "11:22:33", Types.TIME); this.pstmt.setObject(7, new java.sql.Timestamp(currentTime), Types.TIME); this.pstmt.execute(); this.rs = stmt1.executeQuery("SELECT * FROM t1"); this.rs.next(); assertEquals("1000", this.rs.getString(1)); assertEquals("2000", this.rs.getString(2)); assertEquals(1, ((byte[]) this.rs.getObject(3)).length); assertEquals(0, ((byte[]) this.rs.getObject(3))[0]); assertEquals(new java.sql.Date(currentTime).toString(), this.rs.getDate(4).toString()); if (versionMeetsMinimum(4, 1)) { assertEquals("2000-01-01 23:59:59", this.rs.getString(5)); } else { assertEquals("20000101235959", this.rs.getString(5)); } assertEquals("11:22:33", this.rs.getString(6)); assertEquals(new java.sql.Time(currentTime).toString(), this.rs.getString(7)); } public void testStatementRewriteBatch() throws Exception { for (int j = 0; j < 2; j++) { Properties props = new Properties(); if (j == 0) { props.setProperty("useServerPrepStmts", "true"); } props.setProperty("rewriteBatchedStatements", "true"); Connection multiConn = getConnectionWithProps(props); createTable("testStatementRewriteBatch", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); Statement multiStmt = multiConn.createStatement(); multiStmt.addBatch("INSERT INTO testStatementRewriteBatch(field1) VALUES (1)"); multiStmt.addBatch("INSERT INTO testStatementRewriteBatch(field1) VALUES (2)"); multiStmt.addBatch("INSERT INTO testStatementRewriteBatch(field1) VALUES (3)"); multiStmt.addBatch("INSERT INTO testStatementRewriteBatch(field1) VALUES (4)"); multiStmt.addBatch("UPDATE testStatementRewriteBatch SET field1=5 WHERE field1=1"); multiStmt.addBatch("UPDATE testStatementRewriteBatch SET field1=6 WHERE field1=2 OR field1=3"); int[] counts = multiStmt.executeBatch(); ResultSet genKeys = multiStmt.getGeneratedKeys(); for (int i = 1; i < 5; i++) { genKeys.next(); assertEquals(i, genKeys.getInt(1)); } assertEquals(counts.length, 6); assertEquals(counts[0], 1); assertEquals(counts[1], 1); assertEquals(counts[2], 1); assertEquals(counts[3], 1); assertEquals(counts[4], 1); assertEquals(counts[5], 2); this.rs = multiStmt.executeQuery("SELECT field1 FROM testStatementRewriteBatch ORDER BY field1"); assertTrue(this.rs.next()); assertEquals(this.rs.getInt(1), 4); assertTrue(this.rs.next()); assertEquals(this.rs.getInt(1), 5); assertTrue(this.rs.next()); assertEquals(this.rs.getInt(1), 6); assertTrue(this.rs.next()); assertEquals(this.rs.getInt(1), 6); createTable("testStatementRewriteBatch", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); props.clear(); props.setProperty("rewriteBatchedStatements", "true"); props.setProperty("maxAllowedPacket", "1024"); multiConn = getConnectionWithProps(props); multiStmt = multiConn.createStatement(); for (int i = 0; i < 1000; i++) { multiStmt.addBatch("INSERT INTO testStatementRewriteBatch(field1) VALUES (" + i + ")"); } multiStmt.executeBatch(); genKeys = multiStmt.getGeneratedKeys(); for (int i = 1; i < 1000; i++) { genKeys.next(); assertEquals(i, genKeys.getInt(1)); } createTable("testStatementRewriteBatch", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); props.clear(); props.setProperty("useServerPrepStmts", j == 0 ? "true" : "false"); props.setProperty("rewriteBatchedStatements", "true"); multiConn = getConnectionWithProps(props); PreparedStatement pStmt = null; pStmt = multiConn.prepareStatement("INSERT INTO testStatementRewriteBatch(field1) VALUES (?)", Statement.RETURN_GENERATED_KEYS); for (int i = 0; i < 1000; i++) { pStmt.setInt(1, i); pStmt.addBatch(); } pStmt.executeBatch(); genKeys = pStmt.getGeneratedKeys(); for (int i = 1; i < 1000; i++) { genKeys.next(); assertEquals(i, genKeys.getInt(1)); } createTable("testStatementRewriteBatch", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); props.setProperty("useServerPrepStmts", j == 0 ? "true" : "false"); props.setProperty("rewriteBatchedStatements", "true"); props.setProperty("maxAllowedPacket", j == 0 ? "10240" : "1024"); multiConn = getConnectionWithProps(props); pStmt = multiConn.prepareStatement("INSERT INTO testStatementRewriteBatch(field1) VALUES (?)", Statement.RETURN_GENERATED_KEYS); for (int i = 0; i < 1000; i++) { pStmt.setInt(1, i); pStmt.addBatch(); } pStmt.executeBatch(); genKeys = pStmt.getGeneratedKeys(); for (int i = 1; i < 1000; i++) { genKeys.next(); assertEquals(i, genKeys.getInt(1)); } Object[][] differentTypes = new Object[1000][14]; createTable("rewriteBatchTypes", "(internalOrder int, f1 tinyint null, " + "f2 smallint null, f3 int null, f4 bigint null, " + "f5 decimal(8, 2) null, f6 float null, f7 double null, " + "f8 varchar(255) null, f9 text null, f10 blob null, f11 blob null, " + (versionMeetsMinimum(5, 6, 4) ? "f12 datetime(3) null, f13 time(3) null, f14 date null)" : "f12 datetime null, f13 time null, f14 date null)")); for (int i = 0; i < 1000; i++) { differentTypes[i][0] = Math.random() < .5 ? null : new Byte((byte) (Math.random() * 127)); differentTypes[i][1] = Math.random() < .5 ? null : new Short((short) (Math.random() * Short.MAX_VALUE)); differentTypes[i][2] = Math.random() < .5 ? null : new Integer((int) (Math.random() * Integer.MAX_VALUE)); differentTypes[i][3] = Math.random() < .5 ? null : new Long((long) (Math.random() * Long.MAX_VALUE)); differentTypes[i][4] = Math.random() < .5 ? null : new BigDecimal("19.95"); differentTypes[i][5] = Math.random() < .5 ? null : new Float(3 + ((float) (Math.random()))); differentTypes[i][6] = Math.random() < .5 ? null : new Double(3 + (Math.random())); differentTypes[i][7] = Math.random() < .5 ? null : randomString(); differentTypes[i][8] = Math.random() < .5 ? null : randomString(); differentTypes[i][9] = Math.random() < .5 ? null : randomString().getBytes(); differentTypes[i][10] = Math.random() < .5 ? null : randomString().getBytes(); differentTypes[i][11] = Math.random() < .5 ? null : new Timestamp(System.currentTimeMillis()); differentTypes[i][12] = Math.random() < .5 ? null : new Time(System.currentTimeMillis()); differentTypes[i][13] = Math.random() < .5 ? null : new Date(System.currentTimeMillis()); } props.setProperty("useServerPrepStmts", j == 0 ? "true" : "false"); props.setProperty("rewriteBatchedStatements", "true"); props.setProperty("maxAllowedPacket", j == 0 ? "10240" : "1024"); multiConn = getConnectionWithProps(props); pStmt = multiConn.prepareStatement( "INSERT INTO rewriteBatchTypes(internalOrder,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14) VALUES " + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); for (int i = 0; i < 1000; i++) { pStmt.setInt(1, i); for (int k = 0; k < 14; k++) { if (k == 8) { String asString = (String) differentTypes[i][k]; if (asString == null) { pStmt.setObject(k + 2, null); } else { pStmt.setCharacterStream(k + 2, new StringReader(asString), asString.length()); } } else if (k == 9) { byte[] asBytes = (byte[]) differentTypes[i][k]; if (asBytes == null) { pStmt.setObject(k + 2, null); } else { pStmt.setBinaryStream(k + 2, new ByteArrayInputStream(asBytes), asBytes.length); } } else { pStmt.setObject(k + 2, differentTypes[i][k]); } } pStmt.addBatch(); } pStmt.executeBatch(); this.rs = this.stmt .executeQuery("SELECT f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14 FROM rewriteBatchTypes ORDER BY internalOrder"); int idx = 0; // We need to format this ourselves, since we have to strip the nanos off of TIMESTAMPs, so .equals() doesn't really work... SimpleDateFormat sdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US); while (this.rs.next()) { for (int k = 0; k < 14; k++) { if (differentTypes[idx][k] == null) { assertTrue("On row " + idx + " expected NULL, found " + this.rs.getObject(k + 1) + " in column " + (k + 1), this.rs.getObject(k + 1) == null); } else { String className = differentTypes[idx][k].getClass().getName(); if (className.equals("java.io.StringReader")) { StringReader reader = (StringReader) differentTypes[idx][k]; StringBuilder buf = new StringBuilder(); int c = 0; while ((c = reader.read()) != -1) { buf.append((char) c); } String asString = this.rs.getString(k + 1); assertEquals("On row " + idx + ", column " + (k + 1), buf.toString(), asString); } else if (differentTypes[idx][k] instanceof java.io.InputStream) { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); int bytesRead = 0; byte[] buf = new byte[128]; InputStream in = (InputStream) differentTypes[idx][k]; while ((bytesRead = in.read(buf)) != -1) { bOut.write(buf, 0, bytesRead); } byte[] expected = bOut.toByteArray(); byte[] actual = this.rs.getBytes(k + 1); assertEquals("On row " + idx + ", column " + (k + 1), StringUtils.dumpAsHex(expected, expected.length), StringUtils.dumpAsHex(actual, actual.length)); } else if (differentTypes[idx][k] instanceof byte[]) { byte[] expected = (byte[]) differentTypes[idx][k]; byte[] actual = this.rs.getBytes(k + 1); assertEquals("On row " + idx + ", column " + (k + 1), StringUtils.dumpAsHex(expected, expected.length), StringUtils.dumpAsHex(actual, actual.length)); } else if (differentTypes[idx][k] instanceof Timestamp) { assertEquals("On row " + idx + ", column " + (k + 1), sdf.format(differentTypes[idx][k]), sdf.format(this.rs.getObject(k + 1))); } else if (differentTypes[idx][k] instanceof Double) { assertEquals("On row " + idx + ", column " + (k + 1), ((Double) differentTypes[idx][k]).doubleValue(), this.rs.getDouble(k + 1), .1); } else if (differentTypes[idx][k] instanceof Float) { assertEquals("On row " + idx + ", column " + (k + 1), ((Float) differentTypes[idx][k]).floatValue(), this.rs.getFloat(k + 1), .1); } else if (className.equals("java.lang.Byte")) { // special mapping in JDBC for ResultSet.getObject() assertEquals("On row " + idx + ", column " + (k + 1), new Integer(((Byte) differentTypes[idx][k]).byteValue()), this.rs.getObject(k + 1)); } else if (className.equals("java.lang.Short")) { // special mapping in JDBC for ResultSet.getObject() assertEquals("On row " + idx + ", column " + (k + 1), new Integer(((Short) differentTypes[idx][k]).shortValue()), this.rs.getObject(k + 1)); } else { assertEquals("On row " + idx + ", column " + (k + 1) + " (" + differentTypes[idx][k].getClass() + "/" + this.rs.getObject(k + 1).getClass(), differentTypes[idx][k].toString(), this.rs.getObject(k + 1).toString()); } } } idx++; } } } public void testBatchRewriteErrors() throws Exception { createTable("rewriteErrors", "(field1 int not null primary key) ENGINE=MyISAM"); Properties props = new Properties(); Connection multiConn = null; for (int j = 0; j < 2; j++) { props.setProperty("useServerPrepStmts", "false"); if (j == 1) { props.setProperty("continueBatchOnError", "false"); } else { props.setProperty("continueBatchOnError", "true"); } props.setProperty("maxAllowedPacket", "4096"); props.setProperty("rewriteBatchedStatements", "true"); multiConn = getConnectionWithProps(props); this.pstmt = multiConn.prepareStatement("INSERT INTO rewriteErrors VALUES (?)"); Statement multiStmt = multiConn.createStatement(); for (int i = 0; i < 4096; i++) { multiStmt.addBatch("INSERT INTO rewriteErrors VALUES (" + i + ")"); this.pstmt.setInt(1, i); this.pstmt.addBatch(); } multiStmt.addBatch("INSERT INTO rewriteErrors VALUES (2048)"); this.pstmt.setInt(1, 2048); this.pstmt.addBatch(); try { this.pstmt.executeBatch(); } catch (BatchUpdateException bUpE) { int[] counts = bUpE.getUpdateCounts(); for (int i = 4059; i < counts.length; i++) { assertEquals(counts[i], Statement.EXECUTE_FAILED); } // this depends on max_allowed_packet, only a sanity check assertTrue(getRowCount("rewriteErrors") >= 4000); } this.stmt.execute("TRUNCATE TABLE rewriteErrors"); try { multiStmt.executeBatch(); } catch (BatchUpdateException bUpE) { int[] counts = bUpE.getUpdateCounts(); for (int i = 4094; i < counts.length; i++) { assertEquals(counts[i], Statement.EXECUTE_FAILED); } // this depends on max_allowed_packet, only a sanity check assertTrue(getRowCount("rewriteErrors") >= 4000); } if (versionMeetsMinimum(5, 0)) { this.stmt.execute("TRUNCATE TABLE rewriteErrors"); createProcedure("sp_rewriteErrors", "(param1 INT)\nBEGIN\nINSERT INTO rewriteErrors VALUES (param1);\nEND"); CallableStatement cStmt = multiConn.prepareCall("{ CALL sp_rewriteErrors(?)}"); for (int i = 0; i < 4096; i++) { cStmt.setInt(1, i); cStmt.addBatch(); } cStmt.setInt(1, 2048); cStmt.addBatch(); try { cStmt.executeBatch(); } catch (BatchUpdateException bUpE) { int[] counts = bUpE.getUpdateCounts(); for (int i = 4093; i < counts.length; i++) { assertEquals(counts[i], Statement.EXECUTE_FAILED); } // this depends on max_allowed_packet, only a sanity check assertTrue(getRowCount("rewriteErrors") >= 4000); } } } } public void testStreamChange() throws Exception { createTable("testStreamChange", "(field1 varchar(32), field2 int, field3 TEXT, field4 BLOB)"); this.pstmt = this.conn.prepareStatement("INSERT INTO testStreamChange VALUES (?, ?, ?, ?)"); try { this.pstmt.setString(1, "A"); this.pstmt.setInt(2, 1); char[] cArray = { 'A', 'B', 'C' }; Reader r = new CharArrayReader(cArray); this.pstmt.setCharacterStream(3, r, cArray.length); byte[] bArray = { 'D', 'E', 'F' }; ByteArrayInputStream bais = new ByteArrayInputStream(bArray); this.pstmt.setBinaryStream(4, bais, bArray.length); assertEquals(1, this.pstmt.executeUpdate()); this.rs = this.stmt.executeQuery("SELECT field3, field4 from testStreamChange where field1='A'"); this.rs.next(); assertEquals("ABC", this.rs.getString(1)); assertEquals("DEF", this.rs.getString(2)); char[] ucArray = { 'C', 'E', 'S', 'U' }; this.pstmt.setString(1, "CESU"); this.pstmt.setInt(2, 3); Reader ucReader = new CharArrayReader(ucArray); this.pstmt.setCharacterStream(3, ucReader, ucArray.length); this.pstmt.setBinaryStream(4, null, 0); assertEquals(1, this.pstmt.executeUpdate()); this.rs = this.stmt.executeQuery("SELECT field3, field4 from testStreamChange where field1='CESU'"); this.rs.next(); assertEquals("CESU", this.rs.getString(1)); assertEquals(null, this.rs.getString(2)); } finally { if (this.rs != null) { this.rs.close(); this.rs = null; } if (this.pstmt != null) { this.pstmt.close(); this.pstmt = null; } } } public void testStubbed() throws SQLException { try { this.stmt.getResultSetHoldability(); } catch (NotImplemented notImplEx) { } } public void testTruncationOnRead() throws Exception { this.rs = this.stmt.executeQuery("SELECT '" + Long.MAX_VALUE + "'"); this.rs.next(); try { this.rs.getByte(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getShort(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getInt(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } this.rs = this.stmt.executeQuery("SELECT '" + Double.MAX_VALUE + "'"); this.rs.next(); try { this.rs.getByte(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getShort(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getInt(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getLong(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getLong(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } PreparedStatement pStmt = null; System.out.println("Testing prepared statements with binary result sets now"); try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testTruncationOnRead"); this.stmt.executeUpdate("CREATE TABLE testTruncationOnRead(intField INTEGER, bigintField BIGINT, doubleField DOUBLE)"); this.stmt.executeUpdate("INSERT INTO testTruncationOnRead VALUES (" + Integer.MAX_VALUE + ", " + Long.MAX_VALUE + ", " + Double.MAX_VALUE + ")"); this.stmt.executeUpdate("INSERT INTO testTruncationOnRead VALUES (" + Integer.MIN_VALUE + ", " + Long.MIN_VALUE + ", " + Double.MIN_VALUE + ")"); pStmt = this.conn.prepareStatement("SELECT intField, bigintField, doubleField FROM testTruncationOnRead ORDER BY intField DESC"); this.rs = pStmt.executeQuery(); this.rs.next(); try { this.rs.getByte(1); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getInt(2); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } try { this.rs.getLong(3); fail("Should've thrown an out-of-range exception"); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE.equals(sqlEx.getSQLState())); } } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testTruncationOnRead"); } } public void testStatementInterceptors() throws Exception { Connection interceptedConn = null; /* * try { * Properties props = new Properties(); * props.setProperty("statementInterceptors", "com.mysql.jdbc.interceptors.ResultSetScannerInterceptor"); * props.setProperty("resultSetScannerRegex", ".*"); * interceptedConn = getConnectionWithProps(props); * this.rs = interceptedConn.createStatement().executeQuery("SELECT 'abc'"); * this.rs.next(); * this.rs.getString(1); * } finally { * closeMemberJDBCResources(); * * if (interceptedConn != null) { * interceptedConn.close(); * } * } */ try { Properties props = new Properties(); props.setProperty("statementInterceptors", ServerStatusDiffInterceptor.class.getName()); interceptedConn = getConnectionWithProps(props); this.rs = interceptedConn.createStatement().executeQuery("SELECT 'abc'"); } finally { if (interceptedConn != null) { interceptedConn.close(); } } } public void testParameterBindings() throws Exception { // Need to check character set stuff, so need a new connection Connection utfConn = getConnectionWithProps("characterEncoding=utf-8,treatUtilDateAsTimestamp=false,autoDeserialize=true"); java.util.Date now = new java.util.Date(); Object[] valuesToTest = new Object[] { new Byte(Byte.MIN_VALUE), new Short(Short.MIN_VALUE), new Integer(Integer.MIN_VALUE), new Long(Long.MIN_VALUE), new Double(Double.MIN_VALUE), "\u4E2D\u6587", new BigDecimal(Math.PI), null, // to test isNull now // to test serialization }; StringBuilder statementText = new StringBuilder("SELECT ?"); for (int i = 1; i < valuesToTest.length; i++) { statementText.append(",?"); } this.pstmt = utfConn.prepareStatement(statementText.toString()); for (int i = 0; i < valuesToTest.length; i++) { this.pstmt.setObject(i + 1, valuesToTest[i]); } ParameterBindings bindings = ((com.mysql.jdbc.PreparedStatement) this.pstmt).getParameterBindings(); for (int i = 0; i < valuesToTest.length; i++) { Object boundObject = bindings.getObject(i + 1); if (boundObject == null || valuesToTest[i] == null) { continue; } Class boundObjectClass = boundObject.getClass(); Class testObjectClass = valuesToTest[i].getClass(); if (boundObject instanceof Number) { assertEquals("For binding #" + (i + 1) + " of class " + boundObjectClass + " compared to " + testObjectClass, boundObject.toString(), valuesToTest[i].toString()); } else if (boundObject instanceof Date) { } else { assertEquals("For binding #" + (i + 1) + " of class " + boundObjectClass + " compared to " + testObjectClass, boundObject, valuesToTest[i]); } } } public void testLocalInfileHooked() throws Exception { createTable("localInfileHooked", "(field1 int, field2 varchar(255))"); String streamData = "1\tabcd\n2\tefgh\n3\tijkl"; InputStream stream = new ByteArrayInputStream(streamData.getBytes()); try { ((com.mysql.jdbc.Statement) this.stmt).setLocalInfileInputStream(stream); this.stmt.execute("LOAD DATA LOCAL INFILE 'bogusFileName' INTO TABLE localInfileHooked CHARACTER SET " + CharsetMapping.getMysqlCharsetForJavaEncoding(((MySQLConnection) this.conn).getEncoding(), (com.mysql.jdbc.Connection) this.conn)); assertEquals(-1, stream.read()); this.rs = this.stmt.executeQuery("SELECT field2 FROM localInfileHooked ORDER BY field1 ASC"); this.rs.next(); assertEquals("abcd", this.rs.getString(1)); this.rs.next(); assertEquals("efgh", this.rs.getString(1)); this.rs.next(); assertEquals("ijkl", this.rs.getString(1)); } finally { ((com.mysql.jdbc.Statement) this.stmt).setLocalInfileInputStream(null); } } }