/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. The MySQL Connector/J is licensed under the terms of the GPLv2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, 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 FLOSS License Exception <http://www.mysql.com/about/legal/licensing/foss-exception.html>. 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.regression; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.CharArrayReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.Reader; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.sql.Array; import java.sql.BatchUpdateException; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DataTruncation; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.TimeZone; import testsuite.BaseTestCase; import testsuite.UnreliableSocketFactory; import com.mysql.jdbc.CachedResultSetMetaData; import com.mysql.jdbc.CharsetMapping; import com.mysql.jdbc.Field; import com.mysql.jdbc.MySQLConnection; import com.mysql.jdbc.NonRegisteringDriver; import com.mysql.jdbc.ParameterBindings; import com.mysql.jdbc.ResultSetInternalMethods; import com.mysql.jdbc.SQLError; import com.mysql.jdbc.ServerPreparedStatement; import com.mysql.jdbc.StatementImpl; import com.mysql.jdbc.StatementInterceptor; import com.mysql.jdbc.StatementInterceptorV2; import com.mysql.jdbc.exceptions.MySQLTimeoutException; import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource; /** * Regression tests for the Statement class * * @author Mark Matthews */ public class StatementRegressionTest extends BaseTestCase { class PrepareThread extends Thread { Connection c; PrepareThread(Connection cn) { this.c = cn; } public void run() { for (int i = 0; i < 20; i++) // force this to end eventually { try { this.c.prepareStatement("SELECT 1"); StatementRegressionTest.this.testServerPrepStmtDeadlockCounter++; Thread.sleep(400); } catch (SQLException sqlEx) { throw new RuntimeException(sqlEx); } catch (InterruptedException e) { e.printStackTrace(); } } } } static int count = 0; static int nextID = 1; // The next ID we expected to generate /* * Each row in this table is to be converted into a single REPLACE * statement. If the value is zero, a new record is to be created using then * autoincrement feature. If the value is non-zero, the existing row of that * value is to be replace with, obviously, the same key. I expect one * Generated Key for each zero value - but I would accept one key for each * value, with non-zero values coming back as themselves. */ static final int[][] tests = { { 0 }, // generate 1 { 1, 0, 0 }, // update 1, generate 2, 3 { 2, 0, 0, }, // update 2, generate 3, 4 }; /** * Runs all test cases in this test suite * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(StatementRegressionTest.class); } protected int testServerPrepStmtDeadlockCounter = 0; /** * Constructor for StatementRegressionTest. * * @param name * the name of the test to run */ public StatementRegressionTest(String name) { super(name); } private void addBatchItems(Statement statement, PreparedStatement pStmt, String tableName, int i) throws SQLException { pStmt.setString(1, "ps_batch_" + i); pStmt.setString(2, "ps_batch_" + i); pStmt.addBatch(); statement.addBatch("INSERT INTO " + tableName + " (strdata1, strdata2) VALUES " + "(\"s_batch_" + i + "\",\"s_batch_" + i + "\")"); } private void createGGKTables() throws Exception { // Delete and recreate table dropGGKTables(); createTable( "testggk", "(id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,val INT NOT NULL)", "MYISAM"); } private void doGGKTestPreparedStatement(int[] values, boolean useUpdate) throws Exception { // Generate the the multiple replace command StringBuffer cmd = new StringBuffer("REPLACE INTO testggk VALUES "); int newKeys = 0; for (int i = 0; i < values.length; i++) { cmd.append("("); if (values[i] == 0) { cmd.append("NULL"); newKeys += 1; } else { cmd.append(values[i]); } cmd.append(", "); cmd.append(count++); cmd.append("), "); } cmd.setLength(cmd.length() - 2); // trim the final ", " // execute and print it System.out.println(cmd.toString()); PreparedStatement pStmt = this.conn.prepareStatement(cmd.toString(), Statement.RETURN_GENERATED_KEYS); if (useUpdate) { pStmt.executeUpdate(); } else { pStmt.execute(); } // print out what actually happened System.out.println("Expect " + newKeys + " generated keys, starting from " + nextID); this.rs = pStmt.getGeneratedKeys(); StringBuffer res = new StringBuffer("Got keys"); int[] generatedKeys = new int[newKeys]; int i = 0; while (this.rs.next()) { if (i < generatedKeys.length) { generatedKeys[i] = this.rs.getInt(1); } i++; res.append(" " + this.rs.getInt(1)); } int numberOfGeneratedKeys = i; assertTrue( "Didn't retrieve expected number of generated keys, expected " + newKeys + ", found " + numberOfGeneratedKeys, numberOfGeneratedKeys == newKeys); assertTrue("Keys didn't start with correct sequence: ", generatedKeys[0] == nextID); System.out.println(res.toString()); // Read and print the new state of the table this.rs = this.stmt.executeQuery("SELECT id, val FROM testggk"); System.out.println("New table contents "); while (this.rs.next()) System.out.println("Id " + this.rs.getString(1) + " val " + this.rs.getString(2)); // Tidy up System.out.println(""); nextID += newKeys; } private void doGGKTestStatement(int[] values, boolean useUpdate) throws Exception { // Generate the the multiple replace command StringBuffer cmd = new StringBuffer("REPLACE INTO testggk VALUES "); int newKeys = 0; for (int i = 0; i < values.length; i++) { cmd.append("("); if (values[i] == 0) { cmd.append("NULL"); newKeys += 1; } else { cmd.append(values[i]); } cmd.append(", "); cmd.append(count++); cmd.append("), "); } cmd.setLength(cmd.length() - 2); // trim the final ", " // execute and print it System.out.println(cmd.toString()); if (useUpdate) { this.stmt.executeUpdate(cmd.toString(), Statement.RETURN_GENERATED_KEYS); } else { this.stmt.execute(cmd.toString(), Statement.RETURN_GENERATED_KEYS); } // print out what actually happened System.out.println("Expect " + newKeys + " generated keys, starting from " + nextID); this.rs = this.stmt.getGeneratedKeys(); StringBuffer res = new StringBuffer("Got keys"); int[] generatedKeys = new int[newKeys]; int i = 0; while (this.rs.next()) { if (i < generatedKeys.length) { generatedKeys[i] = this.rs.getInt(1); } i++; res.append(" " + this.rs.getInt(1)); } int numberOfGeneratedKeys = i; assertTrue( "Didn't retrieve expected number of generated keys, expected " + newKeys + ", found " + numberOfGeneratedKeys, numberOfGeneratedKeys == newKeys); assertTrue("Keys didn't start with correct sequence: ", generatedKeys[0] == nextID); System.out.println(res.toString()); // Read and print the new state of the table this.rs = this.stmt.executeQuery("SELECT id, val FROM testggk"); System.out.println("New table contents "); while (this.rs.next()) System.out.println("Id " + this.rs.getString(1) + " val " + this.rs.getString(2)); // Tidy up System.out.println(""); nextID += newKeys; } private void dropGGKTables() throws Exception { this.stmt.executeUpdate("DROP TABLE IF EXISTS testggk"); } /** * @param pStmt * @param catId * @throws SQLException */ private void execQueryBug5191(PreparedStatement pStmt, int catId) throws SQLException { pStmt.setInt(1, catId); this.rs = pStmt.executeQuery(); assertTrue(this.rs.next()); assertTrue(this.rs.next()); // assertTrue(rs.next()); assertFalse(this.rs.next()); } private String getByteArrayString(byte[] ba) { StringBuffer buffer = new StringBuffer(); if (ba != null) { for (int i = 0; i < ba.length; i++) { buffer.append("0x" + Integer.toHexString(ba[i] & 0xff) + " "); } } else { buffer.append("null"); } return buffer.toString(); } /** * @param continueBatchOnError * @throws SQLException */ private void innerBug6823(boolean continueBatchOnError) throws SQLException { Properties continueBatchOnErrorProps = new Properties(); continueBatchOnErrorProps.setProperty("continueBatchOnError", String.valueOf(continueBatchOnError)); this.conn = getConnectionWithProps(continueBatchOnErrorProps); Statement statement = this.conn.createStatement(); String tableName = "testBug6823"; createTable(tableName, "(id int not null primary key auto_increment," + " strdata1 varchar(255) not null, strdata2 varchar(255)," + " UNIQUE INDEX (strdata1(100)))"); PreparedStatement pStmt = this.conn.prepareStatement("INSERT INTO " + tableName + " (strdata1, strdata2) VALUES (?,?)"); int c = 0; addBatchItems(statement, pStmt, tableName, ++c); addBatchItems(statement, pStmt, tableName, ++c); addBatchItems(statement, pStmt, tableName, ++c); addBatchItems(statement, pStmt, tableName, c); // duplicate entry addBatchItems(statement, pStmt, tableName, ++c); addBatchItems(statement, pStmt, tableName, ++c); int expectedUpdateCounts = continueBatchOnError ? 6 : 3; BatchUpdateException e1 = null; BatchUpdateException e2 = null; int[] updateCountsPstmt = null; try { updateCountsPstmt = pStmt.executeBatch(); } catch (BatchUpdateException e) { e1 = e; updateCountsPstmt = e1.getUpdateCounts(); } int[] updateCountsStmt = null; try { updateCountsStmt = statement.executeBatch(); } catch (BatchUpdateException e) { e2 = e; updateCountsStmt = e1.getUpdateCounts(); } assertNotNull(e1); assertNotNull(e2); assertEquals(expectedUpdateCounts, updateCountsPstmt.length); assertEquals(expectedUpdateCounts, updateCountsStmt.length); if (continueBatchOnError) { assertTrue(updateCountsPstmt[3] == Statement.EXECUTE_FAILED); assertTrue(updateCountsStmt[3] == Statement.EXECUTE_FAILED); } int psRows = 0; this.rs = this.stmt.executeQuery("SELECT * from " + tableName + " WHERE strdata1 like \"ps_%\""); while (this.rs.next()) { psRows++; } assertTrue(psRows > 0); int sRows = 0; this.rs = this.stmt.executeQuery("SELECT * from " + tableName + " WHERE strdata1 like \"s_%\""); while (this.rs.next()) { sRows++; } assertTrue(sRows > 0); assertTrue(psRows + "!=" + sRows, psRows == sRows); } /** * Tests fix for BUG#10155, double quotes not recognized when parsing * client-side prepared statements. * * @throws Exception * if the test fails. */ public void testBug10155() throws Exception { this.conn .prepareStatement( "SELECT \"Test question mark? Test single quote'\"") .executeQuery().close(); } /** * Tests fix for BUG#10630, Statement.getWarnings() fails with NPE if * statement has been closed. */ public void testBug10630() throws Exception { Connection conn2 = null; Statement stmt2 = null; try { conn2 = getConnectionWithProps((Properties) null); stmt2 = conn2.createStatement(); conn2.close(); stmt2.getWarnings(); fail("Should've caught an exception here"); } catch (SQLException sqlEx) { assertEquals("08003", sqlEx.getSQLState()); } finally { if (stmt2 != null) { stmt2.close(); } if (conn2 != null) { conn2.close(); } } } /** * Tests fix for BUG#11115, Varbinary data corrupted when using server-side * prepared statements. */ public void testBug11115() throws Exception { String tableName = "testBug11115"; if (versionMeetsMinimum(4, 1, 0)) { createTable(tableName, "(pwd VARBINARY(30)) DEFAULT CHARACTER SET utf8", "InnoDB"); byte[] bytesToTest = new byte[] { 17, 120, -1, -73, -5 }; PreparedStatement insStmt = this.conn .prepareStatement("INSERT INTO " + tableName + " (pwd) VALUES (?)"); insStmt.setBytes(1, bytesToTest); insStmt.executeUpdate(); this.rs = this.stmt.executeQuery("SELECT pwd FROM " + tableName); this.rs.next(); byte[] fromDatabase = this.rs.getBytes(1); assertEquals(bytesToTest.length, fromDatabase.length); for (int i = 0; i < bytesToTest.length; i++) { assertEquals(bytesToTest[i], fromDatabase[i]); } this.rs = this.conn .prepareStatement("SELECT pwd FROM " + tableName) .executeQuery(); this.rs.next(); fromDatabase = this.rs.getBytes(1); assertEquals(bytesToTest.length, fromDatabase.length); for (int i = 0; i < bytesToTest.length; i++) { assertEquals(bytesToTest[i], fromDatabase[i]); } } } public void testBug11540() throws Exception { Locale originalLocale = Locale.getDefault(); Connection thaiConn = null; Statement thaiStmt = null; PreparedStatement thaiPrepStmt = null; try { createTable("testBug11540", "(field1 DATE, field2 TIMESTAMP)"); this.stmt .executeUpdate("INSERT INTO testBug11540 VALUES (NOW(), NOW())"); Locale.setDefault(new Locale("th", "TH")); Properties props = new Properties(); props.setProperty("jdbcCompliantTruncation", "false"); thaiConn = getConnectionWithProps(props); thaiStmt = thaiConn.createStatement(); this.rs = thaiStmt .executeQuery("SELECT field1, field2 FROM testBug11540"); this.rs.next(); Date origDate = this.rs.getDate(1); Timestamp origTimestamp = this.rs.getTimestamp(1); this.rs.close(); thaiStmt.executeUpdate("TRUNCATE TABLE testBug11540"); thaiPrepStmt = ((com.mysql.jdbc.Connection) thaiConn) .clientPrepareStatement("INSERT INTO testBug11540 VALUES (?,?)"); thaiPrepStmt.setDate(1, origDate); thaiPrepStmt.setTimestamp(2, origTimestamp); thaiPrepStmt.executeUpdate(); this.rs = thaiStmt .executeQuery("SELECT field1, field2 FROM testBug11540"); this.rs.next(); Date testDate = this.rs.getDate(1); Timestamp testTimestamp = this.rs.getTimestamp(1); this.rs.close(); assertEquals(origDate, testDate); assertEquals(origTimestamp, testTimestamp); } finally { Locale.setDefault(originalLocale); } } /** * Tests fix for BUG#11663, autoGenerateTestcaseScript uses bogus parameter * names for server-side prepared statements. * * @throws Exception * if the test fails. */ public void testBug11663() throws Exception { if (versionMeetsMinimum(4, 1, 0) && ((com.mysql.jdbc.Connection) this.conn) .getUseServerPreparedStmts()) { Connection testcaseGenCon = null; PrintStream oldErr = System.err; try { createTable("testBug11663", "(field1 int)"); Properties props = new Properties(); props.setProperty("autoGenerateTestcaseScript", "true"); testcaseGenCon = getConnectionWithProps(props); ByteArrayOutputStream testStream = new ByteArrayOutputStream(); PrintStream testErr = new PrintStream(testStream); System.setErr(testErr); this.pstmt = testcaseGenCon .prepareStatement("SELECT field1 FROM testBug11663 WHERE field1=?"); this.pstmt.setInt(1, 1); this.pstmt.execute(); System.setErr(oldErr); String testString = new String(testStream.toByteArray()); int setIndex = testString.indexOf("SET @debug_stmt_param"); int equalsIndex = testString.indexOf("=", setIndex); String paramName = testString.substring(setIndex + 4, equalsIndex); int usingIndex = testString.indexOf("USING " + paramName, equalsIndex); assertTrue(usingIndex != -1); } finally { System.setErr(oldErr); if (this.pstmt != null) { this.pstmt.close(); this.pstmt = null; } if (testcaseGenCon != null) { testcaseGenCon.close(); } } } } /** * Tests fix for BUG#11798 - Pstmt.setObject(...., Types.BOOLEAN) throws * exception. * * @throws Exception * if the test fails. */ public void testBug11798() throws Exception { if (isRunningOnJdk131()) { return; // test not valid on JDK-1.3.1 } try { this.pstmt = this.conn.prepareStatement("SELECT ?"); this.pstmt.setObject(1, Boolean.TRUE, Types.BOOLEAN); this.pstmt.setObject(1, new BigDecimal("1"), Types.BOOLEAN); this.pstmt.setObject(1, "true", Types.BOOLEAN); } finally { if (this.pstmt != null) { this.pstmt.close(); this.pstmt = null; } } } /** * Tests fix for BUG#13255 - Reconnect during middle of executeBatch() * should not happen. * * @throws Exception * if the test fails. */ public void testBug13255() throws Exception { createTable("testBug13255", "(field_1 int)"); Properties props = new Properties(); props.setProperty("autoReconnect", "true"); Connection reconnectConn = null; Statement reconnectStmt = null; PreparedStatement reconnectPStmt = null; try { reconnectConn = getConnectionWithProps(props); reconnectStmt = reconnectConn.createStatement(); String connectionId = getSingleIndexedValueWithQuery(reconnectConn, 1, "SELECT CONNECTION_ID()").toString(); reconnectStmt.addBatch("INSERT INTO testBug13255 VALUES (1)"); reconnectStmt.addBatch("INSERT INTO testBug13255 VALUES (2)"); reconnectStmt.addBatch("KILL " + connectionId); for (int i = 0; i < 100; i++) { reconnectStmt.addBatch("INSERT INTO testBug13255 VALUES (" + i + ")"); } try { reconnectStmt.executeBatch(); } catch (SQLException sqlEx) { // We expect this...we killed the connection } assertEquals(2, getRowCount("testBug13255")); this.stmt.executeUpdate("TRUNCATE TABLE testBug13255"); reconnectConn.close(); reconnectConn = getConnectionWithProps(props); connectionId = getSingleIndexedValueWithQuery(reconnectConn, 1, "SELECT CONNECTION_ID()").toString(); reconnectPStmt = reconnectConn .prepareStatement("INSERT INTO testBug13255 VALUES (?)"); reconnectPStmt.setInt(1, 1); reconnectPStmt.addBatch(); reconnectPStmt.setInt(1, 2); reconnectPStmt.addBatch(); reconnectPStmt.addBatch("KILL " + connectionId); for (int i = 3; i < 100; i++) { reconnectPStmt.setInt(1, i); reconnectPStmt.addBatch(); } try { reconnectPStmt.executeBatch(); } catch (SQLException sqlEx) { // We expect this...we killed the connection } assertEquals(2, getRowCount("testBug13255")); } finally { if (reconnectStmt != null) { reconnectStmt.close(); } if (reconnectConn != null) { reconnectConn.close(); } } } /** * Tests fix for BUG#15024 - Driver incorrectly closes streams passed as * arguments to PreparedStatements. * * @throws Exception * if the test fails. */ public void testBug15024() throws Exception { createTable("testBug15024", "(field1 BLOB)"); try { this.pstmt = this.conn .prepareStatement("INSERT INTO testBug15024 VALUES (?)"); testStreamsForBug15024(false, false); Properties props = new Properties(); props.setProperty("useConfigs", "3-0-Compat"); Connection compatConn = null; try { compatConn = getConnectionWithProps(props); this.pstmt = compatConn .prepareStatement("INSERT INTO testBug15024 VALUES (?)"); testStreamsForBug15024(true, false); } finally { if (compatConn != null) { compatConn.close(); } } } finally { if (this.pstmt != null) { PreparedStatement toClose = this.pstmt; this.pstmt = null; toClose.close(); } } } /** * PreparedStatement should call EscapeProcessor.escapeSQL? * * @throws Exception * if the test fails */ public void testBug15141() throws Exception { try { createTable("testBug15141", "(field1 VARCHAR(32))"); this.stmt.executeUpdate("INSERT INTO testBug15141 VALUES ('abc')"); this.pstmt = this.conn .prepareStatement("select {d '1997-05-24'} FROM testBug15141"); this.rs = this.pstmt.executeQuery(); assertTrue(this.rs.next()); assertEquals("1997-05-24", this.rs.getString(1)); this.rs.close(); this.rs = null; this.pstmt.close(); this.pstmt = null; this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement("select {d '1997-05-24'} FROM testBug15141"); this.rs = this.pstmt.executeQuery(); assertTrue(this.rs.next()); assertEquals("1997-05-24", this.rs.getString(1)); this.rs.close(); this.rs = null; this.pstmt.close(); this.pstmt = null; } finally { if (this.rs != null) { ResultSet toCloseRs = this.rs; this.rs = null; toCloseRs.close(); } if (this.pstmt != null) { PreparedStatement toClosePstmt = this.pstmt; this.pstmt = null; toClosePstmt.close(); } } } /** * Tests fix for BUG#18041 - Server-side prepared statements don't cause * truncation exceptions to be thrown. * * @throws Exception * if the test fails */ public void testBug18041() throws Exception { if (versionMeetsMinimum(4, 1)) { createTable("testBug18041", "(`a` tinyint(4) NOT NULL," + "`b` char(4) default NULL)"); Properties props = new Properties(); props.setProperty("jdbcCompliantTruncation", "true"); props.setProperty("useServerPrepStmts", "true"); Connection truncConn = null; PreparedStatement stm = null; try { truncConn = getConnectionWithProps(props); stm = truncConn .prepareStatement("insert into testBug18041 values (?,?)"); stm.setInt(1, 1000); stm.setString(2, "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"); stm.executeUpdate(); fail("Truncation exception should have been thrown"); } catch (DataTruncation truncEx) { // we expect this } finally { if (this.stmt != null) { this.stmt.close(); } if (truncConn != null) { truncConn.close(); } } } } private void testStreamsForBug15024(boolean shouldBeClosedStream, boolean shouldBeClosedReader) throws SQLException { IsClosedInputStream bIn = new IsClosedInputStream(new byte[4]); IsClosedReader readerIn = new IsClosedReader("abcdef"); this.pstmt.setBinaryStream(1, bIn, 4); this.pstmt.execute(); assertEquals(shouldBeClosedStream, bIn.isClosed()); this.pstmt.setCharacterStream(1, readerIn, 6); this.pstmt.execute(); assertEquals(shouldBeClosedReader, readerIn.isClosed()); this.pstmt.close(); } class IsClosedReader extends StringReader { boolean isClosed = false; public IsClosedReader(String arg0) { super(arg0); } public void close() { super.close(); this.isClosed = true; } public boolean isClosed() { return this.isClosed; } } class IsClosedInputStream extends ByteArrayInputStream { boolean isClosed = false; public IsClosedInputStream(byte[] arg0, int arg1, int arg2) { super(arg0, arg1, arg2); } public IsClosedInputStream(byte[] arg0) { super(arg0); } public void close() throws IOException { super.close(); this.isClosed = true; } public boolean isClosed() { return this.isClosed; } } /** * Tests fix for BUG#1774 -- Truncated words after double quote * * @throws Exception * if the test fails. */ public void testBug1774() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1774"); this.stmt .executeUpdate("CREATE TABLE testBug1774 (field1 VARCHAR(255))"); PreparedStatement pStmt = this.conn .prepareStatement("INSERT INTO testBug1774 VALUES (?)"); String testString = "The word contains \" character"; pStmt.setString(1, testString); pStmt.executeUpdate(); this.rs = this.stmt.executeQuery("SELECT * FROM testBug1774"); this.rs.next(); assertEquals(this.rs.getString(1), testString); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1774"); } } /** * Tests fix for BUG#1901 -- PreparedStatement.setObject(int, Object, int, * int) doesn't support CLOB or BLOB types. * * @throws Exception * if this test fails for any reason */ public void testBug1901() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1901"); this.stmt .executeUpdate("CREATE TABLE testBug1901 (field1 VARCHAR(255))"); this.stmt.executeUpdate("INSERT INTO testBug1901 VALUES ('aaa')"); this.rs = this.stmt.executeQuery("SELECT field1 FROM testBug1901"); this.rs.next(); Clob valueAsClob = this.rs.getClob(1); Blob valueAsBlob = this.rs.getBlob(1); PreparedStatement pStmt = this.conn .prepareStatement("INSERT INTO testBug1901 VALUES (?)"); pStmt.setObject(1, valueAsClob, java.sql.Types.CLOB, 0); pStmt.executeUpdate(); pStmt.setObject(1, valueAsBlob, java.sql.Types.BLOB, 0); pStmt.executeUpdate(); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1901"); } } /** * Test fix for BUG#1933 -- Driver property 'maxRows' has no effect. * * @throws Exception * if the test fails. */ public void testBug1933() throws Exception { if (versionMeetsMinimum(4, 0)) { Connection maxRowsConn = null; PreparedStatement maxRowsPrepStmt = null; Statement maxRowsStmt = null; try { Properties props = new Properties(); props.setProperty("maxRows", "1"); maxRowsConn = getConnectionWithProps(props); maxRowsStmt = maxRowsConn.createStatement(); assertTrue(maxRowsStmt.getMaxRows() == 1); this.rs = maxRowsStmt.executeQuery("SELECT 1 UNION SELECT 2"); this.rs.next(); maxRowsPrepStmt = maxRowsConn .prepareStatement("SELECT 1 UNION SELECT 2"); assertTrue(maxRowsPrepStmt.getMaxRows() == 1); this.rs = maxRowsPrepStmt.executeQuery(); this.rs.next(); assertTrue(!this.rs.next()); props.setProperty("useServerPrepStmts", "false"); maxRowsConn = getConnectionWithProps(props); maxRowsPrepStmt = maxRowsConn .prepareStatement("SELECT 1 UNION SELECT 2"); assertTrue(maxRowsPrepStmt.getMaxRows() == 1); this.rs = maxRowsPrepStmt.executeQuery(); this.rs.next(); assertTrue(!this.rs.next()); } finally { if (maxRowsConn != null) { maxRowsConn.close(); } } } } /** * Tests the fix for BUG#1934 -- prepareStatement dies silently when * encountering Statement.RETURN_GENERATED_KEY * * @throws Exception * if the test fails */ public void testBug1934() throws Exception { if (isRunningOnJdk131()) { return; // test not valid on JDK-1.3.1 } try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1934"); this.stmt.executeUpdate("CREATE TABLE testBug1934 (field1 INT)"); System.out.println("Before prepareStatement()"); this.pstmt = this.conn.prepareStatement( "INSERT INTO testBug1934 VALUES (?)", java.sql.Statement.RETURN_GENERATED_KEYS); assertTrue(this.pstmt != null); System.out.println("After prepareStatement() - " + this.pstmt); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1934"); } } /** * Tests fix for BUG#1958 - Improper bounds checking on * PreparedStatement.setFoo(). * * @throws Exception * if the test fails. */ public void testBug1958() throws Exception { PreparedStatement pStmt = null; try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1958"); this.stmt.executeUpdate("CREATE TABLE testBug1958 (field1 int)"); pStmt = this.conn .prepareStatement("SELECT * FROM testBug1958 WHERE field1 IN (?, ?, ?)"); try { pStmt.setInt(4, 1); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_ILLEGAL_ARGUMENT.equals(sqlEx .getSQLState())); } } finally { if (pStmt != null) { pStmt.close(); } this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug1958"); } } /** * Tests the fix for BUG#2606, server-side prepared statements not returning * datatype YEAR correctly. * * @throws Exception * if the test fails. */ public void testBug2606() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug2606"); this.stmt .executeUpdate("CREATE TABLE testBug2606(year_field YEAR)"); this.stmt.executeUpdate("INSERT INTO testBug2606 VALUES (2004)"); PreparedStatement yrPstmt = this.conn .prepareStatement("SELECT year_field FROM testBug2606"); this.rs = yrPstmt.executeQuery(); assertTrue(this.rs.next()); assertEquals(2004, this.rs.getInt(1)); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug2606"); } } /** * Tests the fix for BUG#2671, nulls encoded incorrectly in server-side * prepared statements. * * @throws Exception * if an error occurs. */ public void testBug2671() throws Exception { if (versionMeetsMinimum(4, 1)) { createTable("test3", "(" + " `field1` int(8) NOT NULL auto_increment," + " `field2` int(8) unsigned zerofill default NULL," + " `field3` varchar(30) binary NOT NULL default ''," + " `field4` varchar(100) default NULL," + " `field5` datetime NULL default '0000-00-00 00:00:00'," + " PRIMARY KEY (`field1`)," + " UNIQUE KEY `unq_id` (`field2`)," + " UNIQUE KEY (`field3`)," + " UNIQUE KEY (`field2`)" + " ) CHARACTER SET utf8", "InnoDB"); this.stmt .executeUpdate("insert into test3 (field1, field3, field4) values (1,'blewis','Bob Lewis')"); String query = " " + "UPDATE " + " test3 " + "SET " + " field2=? " + " ,field3=? " + " ,field4=? " + " ,field5=? " + "WHERE " + " field1 = ? "; java.sql.Date mydate = null; this.pstmt = this.conn.prepareStatement(query); this.pstmt.setInt(1, 13); this.pstmt.setString(2, "abc"); this.pstmt.setString(3, "def"); this.pstmt.setDate(4, mydate); this.pstmt.setInt(5, 1); int retval = this.pstmt.executeUpdate(); assertTrue(retval == 1); } } /** * Tests fix for BUG#3103 -- java.util.Date not accepted as parameter to * PreparedStatement.setObject(). * * @throws Exception * if the test fails * * @deprecated uses deprecated methods of Date class */ public void testBug3103() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3103"); if (versionMeetsMinimum(5, 6, 4)) { this.stmt.executeUpdate("CREATE TABLE testBug3103 (field1 DATETIME(3))"); } else { this.stmt.executeUpdate("CREATE TABLE testBug3103 (field1 DATETIME)"); } PreparedStatement pStmt = this.conn .prepareStatement("INSERT INTO testBug3103 VALUES (?)"); java.util.Date utilDate = new java.util.Date(); pStmt.setObject(1, utilDate); pStmt.executeUpdate(); this.rs = this.stmt.executeQuery("SELECT field1 FROM testBug3103"); this.rs.next(); java.util.Date retrUtilDate = new java.util.Date(this.rs .getTimestamp(1).getTime()); // We can only compare on the day/month/year hour/minute/second // interval, because the timestamp has added milliseconds to the // internal date... assertTrue( "Dates not equal", (utilDate.getMonth() == retrUtilDate.getMonth()) && (utilDate.getDate() == retrUtilDate.getDate()) && (utilDate.getYear() == retrUtilDate.getYear()) && (utilDate.getHours() == retrUtilDate.getHours()) && (utilDate.getMinutes() == retrUtilDate .getMinutes()) && (utilDate.getSeconds() == retrUtilDate .getSeconds())); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3103"); } } /** * Tests fix for BUG#3520 * * @throws Exception * ... */ public void testBug3520() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS t"); this.stmt.executeUpdate("CREATE TABLE t (s1 int,primary key (s1))"); this.stmt.executeUpdate("INSERT INTO t VALUES (1)"); this.stmt.executeUpdate("INSERT INTO t VALUES (1)"); } catch (SQLException sqlEx) { System.out.println(sqlEx.getSQLState()); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS t"); } } /** * Test fix for BUG#3557 -- UpdatableResultSet not picking up default values * * @throws Exception * if test fails. */ public void testBug3557() throws Exception { boolean populateDefaults = ((com.mysql.jdbc.ConnectionProperties) this.conn) .getPopulateInsertRowWithDefaultValues(); try { ((com.mysql.jdbc.ConnectionProperties) this.conn) .setPopulateInsertRowWithDefaultValues(true); this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3557"); this.stmt.executeUpdate("CREATE TABLE testBug3557 ( " + "`a` varchar(255) NOT NULL default 'XYZ', " + "`b` varchar(255) default '123', " + "PRIMARY KEY (`a`(100)))"); Statement updStmt = this.conn .createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); this.rs = updStmt.executeQuery("SELECT * FROM testBug3557"); assertTrue(this.rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE); this.rs.moveToInsertRow(); assertEquals("XYZ", this.rs.getObject(1)); assertEquals("123", this.rs.getObject(2)); } finally { ((com.mysql.jdbc.ConnectionProperties) this.conn) .setPopulateInsertRowWithDefaultValues(populateDefaults); this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3557"); } } /** * Tests fix for BUG#3620 -- Timezone not respected correctly. * * @throws SQLException * if the test fails. */ public void testBug3620() throws SQLException { if (isRunningOnJRockit()) { // bug with their timezones return; } if (isRunningOnJdk131()) { // bug with timezones, no update // for new DST in USA return; } // FIXME: This test is sensitive to being in CST/CDT it seems if (!TimeZone.getDefault().equals( TimeZone.getTimeZone("America/Chicago"))) { return; } long epsillon = 3000; // 3 seconds time difference try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3620"); this.stmt .executeUpdate("CREATE TABLE testBug3620 (field1 TIMESTAMP)"); PreparedStatement tsPstmt = this.conn .prepareStatement("INSERT INTO testBug3620 VALUES (?)"); Calendar pointInTime = Calendar.getInstance(); pointInTime.set(2004, 02, 29, 10, 0, 0); long pointInTimeOffset = pointInTime.getTimeZone().getRawOffset(); java.sql.Timestamp ts = new java.sql.Timestamp(pointInTime .getTime().getTime()); tsPstmt.setTimestamp(1, ts); tsPstmt.executeUpdate(); String tsValueAsString = getSingleValue("testBug3620", "field1", null).toString(); System.out.println("Timestamp as string with no calendar: " + tsValueAsString.toString()); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); this.stmt.executeUpdate("DELETE FROM testBug3620"); Properties props = new Properties(); props.put("useTimezone", "true"); // props.put("serverTimezone", "UTC"); Connection tzConn = getConnectionWithProps(props); Statement tsStmt = tzConn.createStatement(); tsPstmt = tzConn .prepareStatement("INSERT INTO testBug3620 VALUES (?)"); tsPstmt.setTimestamp(1, ts, cal); tsPstmt.executeUpdate(); tsValueAsString = getSingleValue("testBug3620", "field1", null) .toString(); Timestamp tsValueAsTimestamp = (Timestamp) getSingleValue( "testBug3620", "field1", null); System.out.println("Timestamp as string with UTC calendar: " + tsValueAsString.toString()); System.out.println("Timestamp as Timestamp with UTC calendar: " + tsValueAsTimestamp); this.rs = tsStmt.executeQuery("SELECT field1 FROM testBug3620"); this.rs.next(); Timestamp tsValueUTC = this.rs.getTimestamp(1, cal); // // We use this testcase with other vendors, JDBC spec // requires result set fields can only be read once, // although MySQL doesn't require this ;) // this.rs = tsStmt.executeQuery("SELECT field1 FROM testBug3620"); this.rs.next(); Timestamp tsValueStmtNoCal = this.rs.getTimestamp(1); System.out .println("Timestamp specifying UTC calendar from normal statement: " + tsValueUTC.toString()); PreparedStatement tsPstmtRetr = tzConn .prepareStatement("SELECT field1 FROM testBug3620"); this.rs = tsPstmtRetr.executeQuery(); this.rs.next(); Timestamp tsValuePstmtUTC = this.rs.getTimestamp(1, cal); System.out .println("Timestamp specifying UTC calendar from prepared statement: " + tsValuePstmtUTC.toString()); // // We use this testcase with other vendors, JDBC spec // requires result set fields can only be read once, // although MySQL doesn't require this ;) // this.rs = tsPstmtRetr.executeQuery(); this.rs.next(); Timestamp tsValuePstmtNoCal = this.rs.getTimestamp(1); System.out .println("Timestamp specifying no calendar from prepared statement: " + tsValuePstmtNoCal.toString()); long stmtDeltaTWithCal = (ts.getTime() - tsValueStmtNoCal.getTime()); long deltaOrig = Math.abs(stmtDeltaTWithCal - pointInTimeOffset); assertTrue( "Difference between original timestamp and timestamp retrieved using java.sql.Statement " + "set in database using UTC calendar is not ~= " + epsillon + ", it is actually " + deltaOrig, (deltaOrig < epsillon)); long pStmtDeltaTWithCal = (ts.getTime() - tsValuePstmtNoCal .getTime()); System.out .println(Math.abs(pStmtDeltaTWithCal - pointInTimeOffset) + " < " + epsillon + (Math.abs(pStmtDeltaTWithCal - pointInTimeOffset) < epsillon)); assertTrue( "Difference between original timestamp and timestamp retrieved using java.sql.PreparedStatement " + "set in database using UTC calendar is not ~= " + epsillon + ", it is actually " + pStmtDeltaTWithCal, (Math.abs(pStmtDeltaTWithCal - pointInTimeOffset) < epsillon)); System.out .println("Difference between original ts and ts with no calendar: " + (ts.getTime() - tsValuePstmtNoCal.getTime()) + ", offset should be " + pointInTimeOffset); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3620"); } } /** * Tests that DataTruncation is thrown when data is truncated. * * @throws Exception * if the test fails. */ public void testBug3697() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3697"); this.stmt .executeUpdate("CREATE TABLE testBug3697 (field1 VARCHAR(255))"); StringBuffer updateBuf = new StringBuffer( "INSERT INTO testBug3697 VALUES ('"); for (int i = 0; i < 512; i++) { updateBuf.append("A"); } updateBuf.append("')"); try { this.stmt.executeUpdate(updateBuf.toString()); } catch (DataTruncation dtEx) { // This is an expected exception.... } SQLWarning warningChain = this.stmt.getWarnings(); System.out.println(warningChain); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3697"); } } /** * Tests fix for BUG#3804, data truncation on server should throw * DataTruncation exception. * * @throws Exception * if the test fails */ public void testBug3804() throws Exception { if (versionMeetsMinimum(4, 1)) { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3804"); this.stmt .executeUpdate("CREATE TABLE testBug3804 (field1 VARCHAR(5))"); boolean caughtTruncation = false; try { this.stmt .executeUpdate("INSERT INTO testBug3804 VALUES ('1234567')"); } catch (DataTruncation truncationEx) { caughtTruncation = true; System.out.println(truncationEx); } assertTrue("Data truncation exception should've been thrown", caughtTruncation); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3804"); } } } /** * Tests BUG#3873 - PreparedStatement.executeBatch() not returning all * generated keys (even though that's not JDBC compliant). * * @throws Exception * if the test fails */ public void testBug3873() throws Exception { if (isRunningOnJdk131()) { return; // test not valid on JDK-1.3.1 } PreparedStatement batchStmt = null; try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3873"); this.stmt .executeUpdate("CREATE TABLE testBug3873 (keyField INT NOT NULL PRIMARY KEY AUTO_INCREMENT, dataField VARCHAR(32))"); batchStmt = this.conn.prepareStatement( "INSERT INTO testBug3873 (dataField) VALUES (?)", Statement.RETURN_GENERATED_KEYS); batchStmt.setString(1, "abc"); batchStmt.addBatch(); batchStmt.setString(1, "def"); batchStmt.addBatch(); batchStmt.setString(1, "ghi"); batchStmt.addBatch(); @SuppressWarnings("unused") int[] updateCounts = batchStmt.executeBatch(); this.rs = batchStmt.getGeneratedKeys(); while (this.rs.next()) { System.out.println(this.rs.getInt(1)); } this.rs = batchStmt.getGeneratedKeys(); assertTrue(this.rs.next()); assertTrue(1 == this.rs.getInt(1)); assertTrue(this.rs.next()); assertTrue(2 == this.rs.getInt(1)); assertTrue(this.rs.next()); assertTrue(3 == this.rs.getInt(1)); assertTrue(!this.rs.next()); } finally { if (batchStmt != null) { batchStmt.close(); } this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug3873"); } } /** * Tests fix for BUG#4119 -- misbehavior in a managed environment from * MVCSoft JDO * * @throws Exception * if the test fails. */ public void testBug4119() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4119"); this.stmt.executeUpdate("CREATE TABLE `testBug4119` (" + "`field1` varchar(255) NOT NULL default ''," + "`field2` bigint(20) default NULL," + "`field3` int(11) default NULL," + "`field4` datetime default NULL," + "`field5` varchar(75) default NULL," + "`field6` varchar(75) default NULL," + "`field7` varchar(75) default NULL," + "`field8` datetime default NULL," + " PRIMARY KEY (`field1`(100))" + ")"); PreparedStatement pStmt = this.conn .prepareStatement("insert into testBug4119 (field2, field3," + "field4, field5, field6, field7, field8, field1) values (?, ?," + "?, ?, ?, ?, ?, ?)"); pStmt.setString(1, "0"); pStmt.setString(2, "0"); pStmt.setTimestamp(3, new java.sql.Timestamp(System.currentTimeMillis())); pStmt.setString(4, "ABC"); pStmt.setString(5, "DEF"); pStmt.setString(6, "AA"); pStmt.setTimestamp(7, new java.sql.Timestamp(System.currentTimeMillis())); pStmt.setString(8, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); pStmt.executeUpdate(); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4119"); } } /** * Tests fix for BUG#4311 - Error in JDBC retrieval of mediumint column when * using prepared statements and binary result sets. * * @throws Exception * if the test fails. */ public void testBug4311() throws Exception { try { int lowValue = -8388608; int highValue = 8388607; this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4311"); this.stmt .executeUpdate("CREATE TABLE testBug4311 (low MEDIUMINT, high MEDIUMINT)"); this.stmt.executeUpdate("INSERT INTO testBug4311 VALUES (" + lowValue + ", " + highValue + ")"); PreparedStatement pStmt = this.conn .prepareStatement("SELECT low, high FROM testBug4311"); this.rs = pStmt.executeQuery(); assertTrue(this.rs.next()); assertTrue(this.rs.getInt(1) == lowValue); assertTrue(this.rs.getInt(2) == highValue); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4311"); } } /** * Tests fix for BUG#4510 -- Statement.getGeneratedKeys() fails when key > * 32767 * * @throws Exception * if the test fails */ public void testBug4510() throws Exception { if (isRunningOnJdk131()) { return; // test not valid on JDK-1.3.1 } try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4510"); this.stmt.executeUpdate("CREATE TABLE testBug4510 (" + "field1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT," + "field2 VARCHAR(100))"); this.stmt .executeUpdate("INSERT INTO testBug4510 (field1, field2) VALUES (32767, 'bar')"); PreparedStatement p = this.conn.prepareStatement( "insert into testBug4510 (field2) values (?)", Statement.RETURN_GENERATED_KEYS); p.setString(1, "blah"); p.executeUpdate(); ResultSet genKeysRs = p.getGeneratedKeys(); genKeysRs.next(); System.out.println("Id: " + genKeysRs.getInt(1)); genKeysRs.close(); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4510"); } } /** * Server doesn't accept everything as a server-side prepared statement, so * by default we scan for stuff it can't handle. * * @throws SQLException */ public void testBug4718() throws SQLException { if (versionMeetsMinimum(4, 1, 0) && ((com.mysql.jdbc.Connection) this.conn) .getUseServerPreparedStmts()) { this.pstmt = this.conn.prepareStatement("SELECT 1 LIMIT ?"); assertTrue(this.pstmt instanceof com.mysql.jdbc.PreparedStatement); this.pstmt = this.conn.prepareStatement("SELECT 1 LIMIT 1"); assertTrue(this.pstmt instanceof com.mysql.jdbc.ServerPreparedStatement); this.pstmt = this.conn.prepareStatement("SELECT 1 LIMIT 1, ?"); assertTrue(this.pstmt instanceof com.mysql.jdbc.PreparedStatement); try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4718"); this.stmt .executeUpdate("CREATE TABLE testBug4718 (field1 char(32))"); this.pstmt = this.conn .prepareStatement("ALTER TABLE testBug4718 ADD INDEX (field1)"); assertTrue(this.pstmt instanceof com.mysql.jdbc.PreparedStatement); this.pstmt = this.conn.prepareStatement("SELECT 1"); assertTrue(this.pstmt instanceof ServerPreparedStatement); this.pstmt = this.conn .prepareStatement("UPDATE testBug4718 SET field1=1"); assertTrue(this.pstmt instanceof ServerPreparedStatement); this.pstmt = this.conn .prepareStatement("UPDATE testBug4718 SET field1=1 LIMIT 1"); assertTrue(this.pstmt instanceof ServerPreparedStatement); this.pstmt = this.conn .prepareStatement("UPDATE testBug4718 SET field1=1 LIMIT ?"); assertTrue(this.pstmt instanceof com.mysql.jdbc.PreparedStatement); this.pstmt = this.conn .prepareStatement("UPDATE testBug4718 SET field1='Will we ignore LIMIT ?,?'"); assertTrue(this.pstmt instanceof ServerPreparedStatement); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug4718"); } } } /** * Tests fix for BUG#5012 -- ServerPreparedStatements dealing with return of * DECIMAL type don't work. * * @throws Exception * if the test fails. */ public void testBug5012() throws Exception { PreparedStatement pStmt = null; String valueAsString = "12345.12"; try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug5012"); this.stmt .executeUpdate("CREATE TABLE testBug5012(field1 DECIMAL(10,2))"); this.stmt.executeUpdate("INSERT INTO testBug5012 VALUES (" + valueAsString + ")"); pStmt = this.conn .prepareStatement("SELECT field1 FROM testBug5012"); this.rs = pStmt.executeQuery(); assertTrue(this.rs.next()); assertEquals(new BigDecimal(valueAsString), this.rs.getBigDecimal(1)); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug5012"); if (pStmt != null) { pStmt.close(); } } } /** * Tests fix for BUG#5133 -- PreparedStatement.toString() doesn't return * correct value if no parameters are present in statement. * * @throws Exception */ public void testBug5133() throws Exception { String query = "SELECT 1"; String output = this.conn.prepareStatement(query).toString(); System.out.println(output); assertTrue(output.indexOf(query) != -1); } /** * Tests for BUG#5191 -- PreparedStatement.executeQuery() gives * OutOfMemoryError * * @throws Exception * if the test fails. */ public void testBug5191() throws Exception { PreparedStatement pStmt = null; try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug5191Q"); this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug5191C"); this.stmt.executeUpdate("CREATE TABLE testBug5191Q" + "(QuestionId int NOT NULL AUTO_INCREMENT, " + "Text VARCHAR(200), " + "PRIMARY KEY(QuestionId))"); this.stmt.executeUpdate("CREATE TABLE testBug5191C" + "(CategoryId int, " + "QuestionId int)"); String[] questions = new String[] { "What is your name?", "What is your quest?", "What is the airspeed velocity of an unladen swollow?", "How many roads must a man walk?", "Where's the tea?", }; for (int i = 0; i < questions.length; i++) { this.stmt.executeUpdate("INSERT INTO testBug5191Q(Text)" + " VALUES (\"" + questions[i] + "\")"); int catagory = (i < 3) ? 0 : i; this.stmt.executeUpdate("INSERT INTO testBug5191C" + "(CategoryId, QuestionId) VALUES (" + catagory + ", " + i + ")"); /* * this.stmt.executeUpdate("INSERT INTO testBug5191C" + * "(CategoryId, QuestionId) VALUES (" + catagory + ", (SELECT * testBug5191Q.QuestionId" + " FROM testBug5191Q " + "WHERE * testBug5191Q.Text LIKE '" + questions[i] + "'))"); */ } pStmt = this.conn.prepareStatement("SELECT qc.QuestionId, q.Text " + "FROM testBug5191Q q, testBug5191C qc " + "WHERE qc.CategoryId = ? " + " AND q.QuestionId = qc.QuestionId"); int catId = 0; for (int i = 0; i < 100; i++) { execQueryBug5191(pStmt, catId); } } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug5191Q"); this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug5191C"); if (pStmt != null) { pStmt.close(); } } } public void testBug5235() throws Exception { Properties props = new Properties(); props.setProperty("zeroDateTimeBehavior", "convertToNull"); Connection convertToNullConn = getConnectionWithProps(props); Statement convertToNullStmt = convertToNullConn.createStatement(); try { convertToNullStmt.executeUpdate("DROP TABLE IF EXISTS testBug5235"); convertToNullStmt .executeUpdate("CREATE TABLE testBug5235(field1 DATE)"); convertToNullStmt .executeUpdate("INSERT INTO testBug5235 (field1) VALUES ('0000-00-00')"); PreparedStatement ps = convertToNullConn .prepareStatement("SELECT field1 FROM testBug5235"); this.rs = ps.executeQuery(); if (this.rs.next()) { Date d = (Date) this.rs.getObject("field1"); System.out.println("date: " + d); } } finally { convertToNullStmt.executeUpdate("DROP TABLE IF EXISTS testBug5235"); } } public void testBug5450() throws Exception { if (versionMeetsMinimum(4, 1)) { String table = "testBug5450"; String column = "policyname"; try { Properties props = new Properties(); props.setProperty("characterEncoding", "utf-8"); Connection utf8Conn = getConnectionWithProps(props); Statement utfStmt = utf8Conn.createStatement(); this.stmt.executeUpdate("DROP TABLE IF EXISTS " + table); this.stmt.executeUpdate("CREATE TABLE " + table + "(policyid int NOT NULL AUTO_INCREMENT, " + column + " VARCHAR(200), " + "PRIMARY KEY(policyid)) DEFAULT CHARACTER SET utf8"); String pname0 = "inserted \uac00 - foo - \u4e00"; utfStmt.executeUpdate("INSERT INTO " + table + "(" + column + ")" + " VALUES (\"" + pname0 + "\")"); this.rs = utfStmt.executeQuery("SELECT " + column + " FROM " + table); this.rs.first(); String pname1 = this.rs.getString(column); assertEquals(pname0, pname1); byte[] bytes = this.rs.getBytes(column); String pname2 = new String(bytes, "utf-8"); assertEquals(pname1, pname2); utfStmt.executeUpdate("delete from " + table + " where " + column + " like 'insert%'"); PreparedStatement s1 = utf8Conn.prepareStatement("insert into " + table + "(" + column + ") values (?)"); s1.setString(1, pname0); s1.executeUpdate(); String byteesque = "byte " + pname0; byte[] newbytes = byteesque.getBytes("utf-8"); s1.setBytes(1, newbytes); s1.executeUpdate(); this.rs = utfStmt.executeQuery("select " + column + " from " + table + " where " + column + " like 'insert%'"); this.rs.first(); String pname3 = this.rs.getString(column); assertEquals(pname0, pname3); this.rs = utfStmt.executeQuery("select " + column + " from " + table + " where " + column + " like 'byte insert%'"); this.rs.first(); String pname4 = this.rs.getString(column); assertEquals(byteesque, pname4); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS " + table); } } } public void testBug5510() throws Exception { // This is a server bug that should be fixed by 4.1.6 if (versionMeetsMinimum(4, 1, 6)) { createTable( "`testBug5510`", "(" + "`a` bigint(20) NOT NULL auto_increment," + "`b` varchar(64) default NULL," + "`c` varchar(64) default NULL," + "`d` varchar(255) default NULL," + "`e` int(11) default NULL," + "`f` varchar(32) default NULL," + "`g` varchar(32) default NULL," + "`h` varchar(80) default NULL," + "`i` varchar(255) default NULL," + "`j` varchar(255) default NULL," + "`k` varchar(255) default NULL," + "`l` varchar(32) default NULL," + "`m` varchar(32) default NULL," + "`n` timestamp NOT NULL default CURRENT_TIMESTAMP on update" + " CURRENT_TIMESTAMP," + "`o` int(11) default NULL," + "`p` int(11) default NULL," + "PRIMARY KEY (`a`)" + ") DEFAULT CHARSET=latin1", "InnoDB "); PreparedStatement pStmt = this.conn .prepareStatement("INSERT INTO testBug5510 (a) VALUES (?)"); pStmt.setNull(1, 0); pStmt.executeUpdate(); } } /** * Tests fix for BUG#5874, timezone correction goes in wrong 'direction' * when useTimezone=true and server timezone differs from client timezone. * * @throws Exception * if the test fails. */ public void testBug5874() throws Exception { /* * try { String clientTimezoneName = "America/Los_Angeles"; String * serverTimezoneName = "America/Chicago"; * * TimeZone.setDefault(TimeZone.getTimeZone(clientTimezoneName)); * * long epsillon = 3000; // 3 seconds difference * * long clientTimezoneOffsetMillis = TimeZone.getDefault() * .getRawOffset(); long serverTimezoneOffsetMillis = * TimeZone.getTimeZone( serverTimezoneName).getRawOffset(); * * long offsetDifference = clientTimezoneOffsetMillis - * serverTimezoneOffsetMillis; * * Properties props = new Properties(); props.put("useTimezone", * "true"); props.put("serverTimezone", serverTimezoneName); * * Connection tzConn = getConnectionWithProps(props); Statement tzStmt = * tzConn.createStatement(); * tzStmt.executeUpdate("DROP TABLE IF EXISTS timeTest"); tzStmt * .executeUpdate("CREATE TABLE timeTest (tstamp DATETIME, t TIME)"); * * PreparedStatement pstmt = tzConn * .prepareStatement("INSERT INTO timeTest VALUES (?, ?)"); * * long now = System.currentTimeMillis(); // Time in milliseconds // * since 1/1/1970 GMT * * Timestamp nowTstamp = new Timestamp(now); Time nowTime = new * Time(now); * * pstmt.setTimestamp(1, nowTstamp); pstmt.setTime(2, nowTime); * pstmt.executeUpdate(); * * this.rs = tzStmt.executeQuery("SELECT * from timeTest"); * * // Timestamps look like this: 2004-11-29 13:43:21 SimpleDateFormat * timestampFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); * SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); * * while (this.rs.next()) { // Driver now converts/checks * DATE/TIME/TIMESTAMP/DATETIME types // when calling getString()... * String retrTimestampString = new String(this.rs.getBytes(1)); * Timestamp retrTimestamp = this.rs.getTimestamp(1); * * java.util.Date timestampOnServer = timestampFormat * .parse(retrTimestampString); * * long retrievedOffsetForTimestamp = retrTimestamp.getTime() - * timestampOnServer.getTime(); * * assertTrue( * "Difference between original timestamp and timestamp retrieved using client timezone is not " * + offsetDifference, (Math .abs(retrievedOffsetForTimestamp - * offsetDifference) < epsillon)); * * String retrTimeString = new String(this.rs.getBytes(2)); Time * retrTime = this.rs.getTime(2); * * java.util.Date timeOnServerAsDate = timeFormat * .parse(retrTimeString); Time timeOnServer = new * Time(timeOnServerAsDate.getTime()); * * long retrievedOffsetForTime = retrTime.getTime() - * timeOnServer.getTime(); * * assertTrue( * "Difference between original times and time retrieved using client timezone is not " * + offsetDifference, (Math.abs(retrievedOffsetForTime - * offsetDifference) < epsillon)); } } finally { * this.stmt.executeUpdate("DROP TABLE IF EXISTS timeTest"); } */ } public void testBug6823() throws SQLException { innerBug6823(true); innerBug6823(false); } public void testBug7461() throws Exception { String tableName = "testBug7461"; try { createTable(tableName, "(field1 varchar(4))"); File tempFile = File.createTempFile("mysql-test", ".txt"); tempFile.deleteOnExit(); FileOutputStream fOut = new FileOutputStream(tempFile); fOut.write("abcdefghijklmnop".getBytes()); fOut.close(); try { this.stmt.executeQuery("LOAD DATA LOCAL INFILE '" + tempFile.toString() + "' INTO TABLE " + tableName); } catch (SQLException sqlEx) { this.stmt.getWarnings(); } } finally { dropTable(tableName); } } public void testBug8181() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug8181"); this.stmt .executeUpdate("CREATE TABLE testBug8181(col1 VARCHAR(20),col2 INT)"); this.pstmt = this.conn .prepareStatement("INSERT INTO testBug8181(col1,col2) VALUES(?,?)"); for (int i = 0; i < 20; i++) { this.pstmt.setString(1, "Test " + i); this.pstmt.setInt(2, i); this.pstmt.addBatch(); } this.pstmt.executeBatch(); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testBug8181"); if (this.pstmt != null) { this.pstmt.close(); } } } /** * Tests fix for BUG#8487 - PreparedStatements not creating streaming result * sets. * * @throws Exception * if the test fails. */ public void testBug8487() throws Exception { try { this.pstmt = this.conn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); this.pstmt.setFetchSize(Integer.MIN_VALUE); this.rs = this.pstmt.executeQuery(); try { this.conn.createStatement().executeQuery("SELECT 2"); fail("Should have caught a streaming exception here"); } catch (SQLException sqlEx) { assertTrue(sqlEx.getMessage() != null && sqlEx.getMessage().indexOf("Streaming") != -1); } } finally { if (this.rs != null) { while (this.rs.next()) ; this.rs.close(); } if (this.pstmt != null) { this.pstmt.close(); } } } /** * Tests multiple statement support with fix for BUG#9704. * * @throws Exception * DOCUMENT ME! */ public void testBug9704() 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 you can close a statement twice without an NPE. * * @throws Exception * if an error occurs. */ public void testCloseTwice() throws Exception { Statement closeMe = this.conn.createStatement(); closeMe.close(); closeMe.close(); } public void testCsc4194() throws Exception { if (isRunningOnJdk131()) { return; // test not valid on JDK-1.3.1 } try { "".getBytes("Windows-31J"); } catch (UnsupportedEncodingException ex) { return; // test doesn't work on this platform } Connection sjisConn = null; Connection windows31JConn = null; try { String tableNameText = "testCsc4194Text"; String tableNameBlob = "testCsc4194Blob"; createTable(tableNameBlob, "(field1 BLOB)"); String charset = ""; if (versionMeetsMinimum(5, 0, 3) || versionMeetsMinimum(4, 1, 12)) { charset = " CHARACTER SET cp932"; } else if (versionMeetsMinimum(4, 1, 0)) { charset = " CHARACTER SET sjis"; } createTable(tableNameText, "(field1 TEXT)" + charset); Properties windows31JProps = new Properties(); windows31JProps.setProperty("useUnicode", "true"); windows31JProps.setProperty("characterEncoding", "Windows-31J"); windows31JConn = getConnectionWithProps(windows31JProps); testCsc4194InsertCheckBlob(windows31JConn, tableNameBlob); if (versionMeetsMinimum(4, 1, 0)) { testCsc4194InsertCheckText(windows31JConn, tableNameText, "Windows-31J"); } Properties sjisProps = new Properties(); sjisProps.setProperty("useUnicode", "true"); sjisProps.setProperty("characterEncoding", "sjis"); sjisConn = getConnectionWithProps(sjisProps); testCsc4194InsertCheckBlob(sjisConn, tableNameBlob); if (versionMeetsMinimum(5, 0, 3)) { testCsc4194InsertCheckText(sjisConn, tableNameText, "Windows-31J"); } } finally { if (windows31JConn != null) { windows31JConn.close(); } if (sjisConn != null) { sjisConn.close(); } } } private void testCsc4194InsertCheckBlob(Connection c, String tableName) throws Exception { byte[] bArray = new byte[] { (byte) 0xac, (byte) 0xed, (byte) 0x00, (byte) 0x05 }; PreparedStatement testStmt = c.prepareStatement("INSERT INTO " + tableName + " VALUES (?)"); testStmt.setBytes(1, bArray); testStmt.executeUpdate(); this.rs = c.createStatement().executeQuery( "SELECT field1 FROM " + tableName); assertTrue(this.rs.next()); assertEquals(getByteArrayString(bArray), getByteArrayString(this.rs.getBytes(1))); this.rs.close(); } private void testCsc4194InsertCheckText(Connection c, String tableName, String encoding) throws Exception { byte[] kabuInShiftJIS = { (byte) 0x87, // a double-byte // charater("kabu") in Shift JIS (byte) 0x8a, }; String expected = new String(kabuInShiftJIS, encoding); PreparedStatement testStmt = c.prepareStatement("INSERT INTO " + tableName + " VALUES (?)"); testStmt.setString(1, expected); testStmt.executeUpdate(); this.rs = c.createStatement().executeQuery( "SELECT field1 FROM " + tableName); assertTrue(this.rs.next()); assertEquals(expected, this.rs.getString(1)); this.rs.close(); } /** * Tests all forms of statements influencing getGeneratedKeys(). * * @throws Exception * if the test fails. */ public void testGetGeneratedKeysAllCases() throws Exception { if (isRunningOnJdk131()) { return; // test not valid on JDK-1.3.1 } System.out.println("Using Statement.executeUpdate()\n"); try { createGGKTables(); // Do the tests for (int i = 0; i < tests.length; i++) { doGGKTestStatement(tests[i], true); } } finally { dropGGKTables(); } nextID = 1; count = 0; System.out.println("Using Statement.execute()\n"); try { createGGKTables(); // Do the tests for (int i = 0; i < tests.length; i++) { doGGKTestStatement(tests[i], false); } } finally { dropGGKTables(); } nextID = 1; count = 0; System.out.println("Using PreparedStatement.executeUpdate()\n"); try { createGGKTables(); // Do the tests for (int i = 0; i < tests.length; i++) { doGGKTestPreparedStatement(tests[i], true); } } finally { dropGGKTables(); } nextID = 1; count = 0; System.out.println("Using PreparedStatement.execute()\n"); try { createGGKTables(); // Do the tests for (int i = 0; i < tests.length; i++) { doGGKTestPreparedStatement(tests[i], false); } } finally { dropGGKTables(); } } /** * Tests that max_rows and 'limit' don't cause exceptions to be thrown. * * @throws Exception * if the test fails. */ public void testLimitAndMaxRows() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testMaxRowsAndLimit"); this.stmt .executeUpdate("CREATE TABLE testMaxRowsAndLimit(limitField INT)"); for (int i = 0; i < 500; i++) { this.stmt .executeUpdate("INSERT INTO testMaxRowsAndLimit VALUES (" + i + ")"); } this.stmt.setMaxRows(250); this.stmt .executeQuery("SELECT limitField FROM testMaxRowsAndLimit"); } finally { this.stmt.setMaxRows(0); this.stmt.executeUpdate("DROP TABLE IF EXISTS testMaxRowsAndLimit"); } } /* * public void testBug9595() throws Exception { double[] vals = new double[] * {52.21, 52.22, 52.23, 52.24}; * * createTable("testBug9595", "(field1 DECIMAL(10,2), sortField INT)"); * * this.pstmt = this.conn.prepareStatement("INSERT INTO testBug9595 VALUES * (?, ?)"); // Try setting as doubles for (int i = 0; i < vals.length; i++) * { this.pstmt.setDouble(1, vals[i]); this.pstmt.setInt(2, i); * this.pstmt.executeUpdate(); } * * this.pstmt = this.conn.prepareStatement("SELECT field1 FROM testBug9595 * ORDER BY sortField"); this.rs = this.pstmt.executeQuery(); * * int i = 0; * * while (this.rs.next()) { double valToTest = vals[i++]; * * assertEquals(this.rs.getDouble(1), valToTest, 0.001); * assertEquals(this.rs.getBigDecimal(1).doubleValue(), valToTest, 0.001); } * * this.pstmt = this.conn.prepareStatement("INSERT INTO testBug9595 VALUES * (?, ?)"); * * this.stmt.executeUpdate("TRUNCATE TABLE testBug9595"); // Now, as * BigDecimals for (i = 0; i < vals.length; i++) { BigDecimal foo = new * BigDecimal(vals[i]); * * this.pstmt.setObject(1, foo, Types.DECIMAL, 2); this.pstmt.setInt(2, i); * this.pstmt.executeUpdate(); } * * this.pstmt = this.conn.prepareStatement("SELECT field1 FROM testBug9595 * ORDER BY sortField"); this.rs = this.pstmt.executeQuery(); * * i = 0; * * while (this.rs.next()) { double valToTest = vals[i++]; * System.out.println(this.rs.getString(1)); * assertEquals(this.rs.getDouble(1), valToTest, 0.001); * assertEquals(this.rs.getBigDecimal(1).doubleValue(), valToTest, 0.001); } * } */ /** * Tests that 'LOAD DATA LOCAL INFILE' works * * @throws Exception * if any errors occur */ public void testLoadData() throws Exception { try { //int maxAllowedPacket = 1048576; this.stmt.executeUpdate("DROP TABLE IF EXISTS loadDataRegress"); this.stmt .executeUpdate("CREATE TABLE loadDataRegress (field1 int, field2 int)"); File tempFile = File.createTempFile("mysql", ".txt"); // tempFile.deleteOnExit(); System.out.println(tempFile); Writer out = new FileWriter(tempFile); int localCount = 0; int rowCount = 128; // maxAllowedPacket * 4; for (int i = 0; i < rowCount; i++) { out.write((localCount++) + "\t" + (localCount++) + "\n"); } out.close(); StringBuffer fileNameBuf = null; if (File.separatorChar == '\\') { fileNameBuf = new StringBuffer(); String fileName = tempFile.getAbsolutePath(); int fileNameLength = fileName.length(); for (int i = 0; i < fileNameLength; i++) { char c = fileName.charAt(i); if (c == '\\') { fileNameBuf.append("/"); } else { fileNameBuf.append(c); } } } else { fileNameBuf = new StringBuffer(tempFile.getAbsolutePath()); } int updateCount = this.stmt .executeUpdate("LOAD DATA LOCAL INFILE '" + fileNameBuf.toString() + "' INTO TABLE loadDataRegress" + " CHARACTER SET " + CharsetMapping.getMysqlEncodingForJavaEncoding(((MySQLConnection)this.conn).getEncoding(), (com.mysql.jdbc.Connection) this.conn)); assertTrue(updateCount == rowCount); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS loadDataRegress"); } } public void testNullClob() throws Exception { createTable("testNullClob", "(field1 TEXT NULL)"); PreparedStatement pStmt = null; try { pStmt = this.conn .prepareStatement("INSERT INTO testNullClob VALUES (?)"); pStmt.setClob(1, null); pStmt.executeUpdate(); } finally { if (pStmt != null) { pStmt.close(); } } } /** * Tests fix for BUG#1658 * * @throws Exception * if the fix for parameter bounds checking doesn't work. */ public void testParameterBoundsCheck() throws Exception { try { this.stmt .executeUpdate("DROP TABLE IF EXISTS testParameterBoundsCheck"); this.stmt .executeUpdate("CREATE TABLE testParameterBoundsCheck(f1 int, f2 int, f3 int, f4 int, f5 int)"); PreparedStatement _pstmt = this.conn .prepareStatement("UPDATE testParameterBoundsCheck SET f1=?, f2=?,f3=?,f4=? WHERE f5=?"); _pstmt.setString(1, ""); _pstmt.setString(2, ""); try { _pstmt.setString(25, ""); } catch (SQLException sqlEx) { assertTrue(SQLError.SQL_STATE_ILLEGAL_ARGUMENT.equals(sqlEx .getSQLState())); } } finally { this.stmt .executeUpdate("DROP TABLE IF EXISTS testParameterBoundsCheck"); } } public void testPStmtTypesBug() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testPStmtTypesBug"); this.stmt .executeUpdate("CREATE TABLE testPStmtTypesBug(field1 INT)"); this.pstmt = this.conn .prepareStatement("INSERT INTO testPStmtTypesBug VALUES (?)"); this.pstmt.setObject(1, null, Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setInt(1, 1); this.pstmt.addBatch(); this.pstmt.executeBatch(); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testPStmtTypesBug"); } } /** * Tests fix for BUG#1511 * * @throws Exception * if the quoteid parsing fix in PreparedStatement doesn't work. */ public void testQuotedIdRecognition() throws Exception { if (!this.versionMeetsMinimum(4, 1)) { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS testQuotedId"); this.stmt .executeUpdate("CREATE TABLE testQuotedId (col1 VARCHAR(32))"); PreparedStatement pStmt = this.conn .prepareStatement("SELECT * FROM testQuotedId WHERE col1='ABC`DEF' or col1=?"); pStmt.setString(1, "foo"); pStmt.execute(); this.stmt.executeUpdate("DROP TABLE IF EXISTS testQuotedId2"); this.stmt .executeUpdate("CREATE TABLE testQuotedId2 (`Works?` INT)"); pStmt = this.conn .prepareStatement("INSERT INTO testQuotedId2 (`Works?`) VALUES (?)"); pStmt.setInt(1, 1); pStmt.executeUpdate(); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS testQuotedId"); this.stmt.executeUpdate("DROP TABLE IF EXISTS testQuotedId2"); } } } /** * Tests for BUG#9288, parameter index out of range if LIKE, ESCAPE '\' * present in query. * * @throws Exception * if the test fails. */ /* * public void testBug9288() throws Exception { String tableName = * "testBug9288"; PreparedStatement pStmt = null; * * try { createTable(tableName, "(field1 VARCHAR(32), field2 INT)"); pStmt = * ((com.mysql.jdbc.Connection)this.conn).clientPrepareStatement( "SELECT * COUNT(1) FROM " + tableName + " WHERE " + "field1 LIKE '%' ESCAPE '\\' * AND " + "field2 > ?"); pStmt.setInt(1, 0); * * this.rs = pStmt.executeQuery(); } finally { if (this.rs != null) { * this.rs.close(); this.rs = null; } * * if (pStmt != null) { pStmt.close(); } } } */ /* * public void testBug10999() throws Exception { if (versionMeetsMinimum(5, * 0, 5)) { * * String tableName = "testBug10999"; String updateTrigName = * "testBug10999Update"; String insertTrigName = "testBug10999Insert"; try { * createTable(tableName, "(pkfield INT PRIMARY KEY NOT NULL AUTO_INCREMENT, * field1 VARCHAR(32))"); * * try { this.stmt.executeUpdate("DROP TRIGGER " + updateTrigName); } catch * (SQLException sqlEx) { // ignore for now } * * this.stmt.executeUpdate("CREATE TRIGGER " + updateTrigName + " AFTER * UPDATE ON " + tableName + " FOR EACH ROW " + "BEGIN " + "END"); * * try { this.stmt.executeUpdate("DROP TRIGGER " + insertTrigName); } catch * (SQLException sqlEx) { // ignore } * * this.stmt.executeUpdate("CREATE TRIGGER " + insertTrigName + " AFTER * INSERT ON " + tableName + " FOR EACH ROW " + " BEGIN " + "END"); * * this.conn.setAutoCommit(false); * * String updateSQL = "INSERT INTO " + tableName + " (field1) VALUES * ('abcdefg')"; int rowCount = this.stmt.executeUpdate(updateSQL, * Statement.RETURN_GENERATED_KEYS); * * this.rs = stmt.getGeneratedKeys(); if (rs.next()) { * System.out.println(rs.getInt(1)); int id = rs.getInt(1); //if * (log.isDebugEnabled()) // log.debug("Retrieved ID = " + id); } //else { * //log.error("Can't retrieve ID with getGeneratedKeys."); // Retrieve ID * using a SELECT statement instead. // querySQL = "SELECT id from tab1 * WHERE ..."; * * //if (log.isDebugEnabled()) // log.debug(querySQL); * * //rs = stmt.executeQuery(querySQL); this.rs = * this.stmt.executeQuery("SELECT pkfield FROM " + tableName); } finally { * this.conn.setAutoCommit(true); * * try { this.stmt.executeUpdate("DROP TRIGGER IF EXISTS " + * insertTrigName); } catch (SQLException sqlEx) { // ignore } * * try { this.stmt.executeUpdate("DROP TRIGGER IF EXISTS " + * updateTrigName); } catch (SQLException sqlEx) { // ignore } } } } */ /** * Tests that binary dates/times are encoded/decoded correctly. * * @throws Exception * if the test fails. * * @deprecated because we need to use this particular constructor for the * date class, as Calendar-constructed dates don't pass the * .equals() test :( */ public void testServerPrepStmtAndDate() throws Exception { try { this.stmt .executeUpdate("DROP TABLE IF EXISTS testServerPrepStmtAndDate"); this.stmt.executeUpdate("CREATE TABLE testServerPrepStmtAndDate(" + "`P_ID` int(10) NOT NULL default '0'," + "`H_ID` int(10) NOT NULL default '0'," + "`R_ID` int(10) NOT NULL default '0'," + "`H_Age` int(10) default NULL," + "`R_Date` date NOT NULL default '0000-00-00'," + "`Comments` varchar(255) default NULL," + "`Weight` int(10) default NULL," + "`HeadGear` char(1) NOT NULL default ''," + "`FinPos` int(10) default NULL," + "`Jock_ID` int(10) default NULL," + "`BtnByPrev` double default NULL," + "`BtnByWinner` double default NULL," + "`Jock_All` int(10) default NULL," + "`Draw` int(10) default NULL," + "`SF` int(10) default NULL," + "`RHR` int(10) default NULL," + "`ORating` int(10) default NULL," + "`Odds` double default NULL," + "`RaceFormPlus` int(10) default NULL," + "`PrevPerform` int(10) default NULL," + "`TrainerID` int(10) NOT NULL default '0'," + "`DaysSinceRun` int(10) default NULL," + "UNIQUE KEY `P_ID` (`P_ID`)," + "UNIQUE KEY `R_H_ID` (`R_ID`,`H_ID`)," + "KEY `R_Date` (`R_Date`)," + "KEY `H_Age` (`H_Age`)," + "KEY `TrainerID` (`TrainerID`)," + "KEY `H_ID` (`H_ID`)" + ")"); Date dt = new java.sql.Date(102, 1, 2); // Note, this represents the // date 2002-02-02 PreparedStatement pStmt2 = this.conn .prepareStatement("INSERT INTO testServerPrepStmtAndDate (P_ID, R_Date) VALUES (171576, ?)"); pStmt2.setDate(1, dt); pStmt2.executeUpdate(); pStmt2.close(); this.rs = this.stmt .executeQuery("SELECT R_Date FROM testServerPrepStmtAndDate"); this.rs.next(); System.out.println("Date that was stored (as String) " + this.rs.getString(1)); // comes back as 2002-02-02 PreparedStatement pStmt = this.conn .prepareStatement("Select P_ID,R_Date from testServerPrepStmtAndDate Where R_Date = ? and P_ID = 171576"); pStmt.setDate(1, dt); this.rs = pStmt.executeQuery(); assertTrue(this.rs.next()); assertEquals("171576", this.rs.getString(1)); assertEquals(dt, this.rs.getDate(2)); } finally { this.stmt .executeUpdate("DROP TABLE IF EXISTS testServerPrepStmtAndDate"); } } public void testServerPrepStmtDeadlock() throws Exception { Connection c = getConnectionWithProps((Properties) null); Thread testThread1 = new PrepareThread(c); Thread testThread2 = new PrepareThread(c); testThread1.start(); testThread2.start(); Thread.sleep(30000); assertTrue(this.testServerPrepStmtDeadlockCounter >= 10); } /** * Tests PreparedStatement.setCharacterStream() to ensure it accepts > 4K * streams * * @throws Exception * if an error occurs. */ public void testSetCharacterStream() throws Exception { try { ((com.mysql.jdbc.Connection) this.conn).setTraceProtocol(true); this.stmt .executeUpdate("DROP TABLE IF EXISTS charStreamRegressTest"); this.stmt .executeUpdate("CREATE TABLE charStreamRegressTest(field1 text)"); this.pstmt = this.conn .prepareStatement("INSERT INTO charStreamRegressTest VALUES (?)"); // char[] charBuf = new char[16384]; char[] charBuf = new char[32]; for (int i = 0; i < charBuf.length; i++) { charBuf[i] = 'A'; } CharArrayReader reader = new CharArrayReader(charBuf); this.pstmt.setCharacterStream(1, reader, charBuf.length); this.pstmt.executeUpdate(); this.rs = this.stmt .executeQuery("SELECT LENGTH(field1) FROM charStreamRegressTest"); this.rs.next(); System.out.println("Character stream length: " + this.rs.getString(1)); this.rs = this.stmt .executeQuery("SELECT field1 FROM charStreamRegressTest"); this.rs.next(); String result = this.rs.getString(1); assertTrue(result.length() == charBuf.length); this.stmt.execute("TRUNCATE TABLE charStreamRegressTest"); // Test that EOF is not thrown reader = new CharArrayReader(charBuf); this.pstmt.clearParameters(); this.pstmt.setCharacterStream(1, reader, charBuf.length); this.pstmt.executeUpdate(); this.rs = this.stmt .executeQuery("SELECT LENGTH(field1) FROM charStreamRegressTest"); this.rs.next(); System.out.println("Character stream length: " + this.rs.getString(1)); this.rs = this.stmt .executeQuery("SELECT field1 FROM charStreamRegressTest"); this.rs.next(); result = this.rs.getString(1); assertTrue("Retrieved value of length " + result.length() + " != length of inserted value " + charBuf.length, result.length() == charBuf.length); // Test single quotes inside identifers this.stmt .executeUpdate("DROP TABLE IF EXISTS `charStream'RegressTest`"); this.stmt .executeUpdate("CREATE TABLE `charStream'RegressTest`(field1 text)"); this.pstmt = this.conn .prepareStatement("INSERT INTO `charStream'RegressTest` VALUES (?)"); reader = new CharArrayReader(charBuf); this.pstmt.setCharacterStream(1, reader, (charBuf.length * 2)); this.pstmt.executeUpdate(); this.rs = this.stmt .executeQuery("SELECT field1 FROM `charStream'RegressTest`"); this.rs.next(); result = this.rs.getString(1); assertTrue("Retrieved value of length " + result.length() + " != length of inserted value " + charBuf.length, result.length() == charBuf.length); } finally { ((com.mysql.jdbc.Connection) this.conn).setTraceProtocol(false); if (this.rs != null) { try { this.rs.close(); } catch (Exception ex) { // ignore } this.rs = null; } this.stmt .executeUpdate("DROP TABLE IF EXISTS `charStream'RegressTest`"); this.stmt .executeUpdate("DROP TABLE IF EXISTS charStreamRegressTest"); } } /** * Tests a bug where Statement.setFetchSize() does not work for values other * than 0 or Integer.MIN_VALUE * * @throws Exception * if any errors occur */ public void testSetFetchSize() throws Exception { int oldFetchSize = this.stmt.getFetchSize(); try { this.stmt.setFetchSize(10); } finally { this.stmt.setFetchSize(oldFetchSize); } } /** * Tests fix for BUG#907 * * @throws Exception * if an error occurs */ public void testSetMaxRows() throws Exception { Statement maxRowsStmt = null; try { maxRowsStmt = this.conn.createStatement(); maxRowsStmt.setMaxRows(1); maxRowsStmt.executeQuery("SELECT 1"); } finally { if (maxRowsStmt != null) { maxRowsStmt.close(); } } } /** * Tests for timestamp NPEs occuring in binary-format timestamps. * * @throws Exception * DOCUMENT ME! * * @deprecated yes, we know we are using deprecated methods here :) */ public void testTimestampNPE() throws Exception { try { Timestamp ts = new Timestamp(System.currentTimeMillis()); this.stmt.executeUpdate("DROP TABLE IF EXISTS testTimestampNPE"); this.stmt .executeUpdate("CREATE TABLE testTimestampNPE (field1 TIMESTAMP)"); this.pstmt = this.conn .prepareStatement("INSERT INTO testTimestampNPE VALUES (?)"); this.pstmt.setTimestamp(1, ts); this.pstmt.executeUpdate(); this.pstmt = this.conn .prepareStatement("SELECT field1 FROM testTimestampNPE"); this.rs = this.pstmt.executeQuery(); this.rs.next(); System.out.println(this.rs.getString(1)); this.rs.getDate(1); Timestamp rTs = this.rs.getTimestamp(1); assertTrue("Retrieved year of " + rTs.getYear() + " does not match " + ts.getYear(), rTs.getYear() == ts.getYear()); assertTrue("Retrieved month of " + rTs.getMonth() + " does not match " + ts.getMonth(), rTs.getMonth() == ts.getMonth()); assertTrue("Retrieved date of " + rTs.getDate() + " does not match " + ts.getDate(), rTs.getDate() == ts.getDate()); } finally { } } public void testTruncationWithChar() throws Exception { try { this.stmt .executeUpdate("DROP TABLE IF EXISTS testTruncationWithChar"); this.stmt .executeUpdate("CREATE TABLE testTruncationWithChar (field1 char(2))"); this.pstmt = this.conn .prepareStatement("INSERT INTO testTruncationWithChar VALUES (?)"); this.pstmt.setString(1, "00"); this.pstmt.executeUpdate(); } finally { this.stmt .executeUpdate("DROP TABLE IF EXISTS testTruncationWithChar"); } } /** * Tests fix for updatable streams being supported in updatable result sets. * * @throws Exception * if the test fails. */ public void testUpdatableStream() throws Exception { try { this.stmt.executeUpdate("DROP TABLE IF EXISTS updateStreamTest"); this.stmt .executeUpdate("CREATE TABLE updateStreamTest (keyField INT NOT NULL AUTO_INCREMENT PRIMARY KEY, field1 BLOB)"); int streamLength = 16385; byte[] streamData = new byte[streamLength]; /* create an updatable statement */ Statement updStmt = this.conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); /* fill the resultset with some values */ ResultSet updRs = updStmt .executeQuery("SELECT * FROM updateStreamTest"); /* move to insertRow */ updRs.moveToInsertRow(); /* update the table */ updRs.updateBinaryStream("field1", new ByteArrayInputStream( streamData), streamLength); updRs.insertRow(); } finally { this.stmt.executeUpdate("DROP TABLE IF EXISTS updateStreamTest"); } } /** * Tests fix for BUG#15383 - PreparedStatement.setObject() serializes * BigInteger as object, rather than sending as numeric value (and is thus * not complementary to .getObject() on an UNSIGNED LONG type). * * @throws Exception * if the test fails. */ public void testBug15383() throws Exception { createTable( "testBug15383", "(id INTEGER UNSIGNED NOT NULL " + "AUTO_INCREMENT,value BIGINT UNSIGNED NULL DEFAULT 0,PRIMARY " + "KEY(id))", "InnoDB"); this.stmt.executeUpdate("INSERT INTO testBug15383(value) VALUES(1)"); Statement updatableStmt = this.conn.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); try { this.rs = updatableStmt.executeQuery("SELECT * from testBug15383"); assertTrue(this.rs.next()); Object bigIntObj = this.rs.getObject("value"); assertEquals("java.math.BigInteger", bigIntObj.getClass().getName()); this.rs.updateObject("value", new BigInteger("3")); this.rs.updateRow(); assertEquals("3", this.rs.getString("value")); } finally { if (this.rs != null) { ResultSet toClose = this.rs; this.rs = null; toClose.close(); } if (updatableStmt != null) { updatableStmt.close(); } } } /** * Tests fix for BUG#17099 - Statement.getGeneratedKeys() throws NPE when no * query has been processed. * * @throws Exception * if the test fails */ public void testBug17099() throws Exception { if (isRunningOnJdk131()) { return; // test not valid } PreparedStatement pStmt = this.conn.prepareStatement("SELECT 1", Statement.RETURN_GENERATED_KEYS); assertNotNull(pStmt.getGeneratedKeys()); if (versionMeetsMinimum(4, 1)) { pStmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement("SELECT 1", Statement.RETURN_GENERATED_KEYS); assertNotNull(pStmt.getGeneratedKeys()); } } /** * Tests fix for BUG#17587 - clearParameters() on a closed prepared * statement causes NPE. * * @throws Exception * if the test fails. */ public void testBug17587() throws Exception { createTable("testBug17857", "(field1 int)"); PreparedStatement pStmt = null; try { pStmt = this.conn .prepareStatement("INSERT INTO testBug17857 VALUES (?)"); pStmt.close(); try { pStmt.clearParameters(); } catch (SQLException sqlEx) { assertEquals("08003", sqlEx.getSQLState()); } pStmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement("INSERT INTO testBug17857 VALUES (?)"); pStmt.close(); try { pStmt.clearParameters(); } catch (SQLException sqlEx) { assertEquals("08003", sqlEx.getSQLState()); } } finally { if (pStmt != null) { pStmt.close(); } } } /** * Tests fix for BUG#18740 - Data truncation and getWarnings() only returns * last warning in set. * * @throws Exception * if the test fails. */ public void testBug18740() throws Exception { if (!versionMeetsMinimum(5, 0, 2)) { createTable("testWarnings", "(field1 smallint(6)," + "field2 varchar(6)," + "UNIQUE KEY field1(field1))"); try { this.stmt.executeUpdate("INSERT INTO testWarnings VALUES " + "(10001, 'data1')," + "(10002, 'data2 foo')," + "(10003, 'data3')," + "(10004999, 'data4')," + "(10005, 'data5')"); } catch (SQLException sqlEx) { String sqlStateToCompare = "01004"; if (isJdbc4()) { sqlStateToCompare = "22001"; } assertEquals(sqlStateToCompare, sqlEx.getSQLState()); assertEquals(sqlStateToCompare, sqlEx.getNextException() .getSQLState()); SQLWarning sqlWarn = this.stmt.getWarnings(); assertEquals("01000", sqlWarn.getSQLState()); assertEquals("01000", sqlWarn.getNextWarning().getSQLState()); } } } protected boolean isJdbc4() { boolean isJdbc4; try { Class.forName("java.sql.Wrapper"); isJdbc4 = true; } catch (Throwable t) { isJdbc4 = false; } return isJdbc4; } /** * Tests fix for BUG#19615, PreparedStatement.setObject(int, Object, int) * doesn't respect scale of BigDecimals. * * @throws Exception * if the test fails. */ public void testBug19615() throws Exception { createTable("testBug19615", "(field1 DECIMAL(19, 12))"); BigDecimal dec = new BigDecimal("1.234567"); this.pstmt = this.conn .prepareStatement("INSERT INTO testBug19615 VALUES (?)"); this.pstmt.setObject(1, dec, Types.DECIMAL); this.pstmt.executeUpdate(); this.pstmt.close(); this.rs = this.stmt.executeQuery("SELECT field1 FROM testBug19615"); this.rs.next(); assertEquals(dec, this.rs.getBigDecimal(1).setScale(6)); this.rs.close(); this.stmt.executeUpdate("TRUNCATE TABLE testBug19615"); this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement("INSERT INTO testBug19615 VALUES (?)"); this.pstmt.setObject(1, dec, Types.DECIMAL); this.pstmt.executeUpdate(); this.pstmt.close(); this.rs = this.stmt.executeQuery("SELECT field1 FROM testBug19615"); this.rs.next(); assertEquals(dec, this.rs.getBigDecimal(1).setScale(6)); this.rs.close(); } /** * Tests fix for BUG#20029 - NPE thrown from executeBatch(). * * @throws Exception */ public void testBug20029() throws Exception { createTable("testBug20029", ("(field1 int)")); long initialTimeout = 20; // may need to raise this depending on // environment // we try and do this automatically in this // testcase for (int i = 0; i < 10; i++) { final Connection toBeKilledConn = getConnectionWithProps(new Properties()); final long timeout = initialTimeout; PreparedStatement toBeKilledPstmt = null; try { toBeKilledPstmt = ((com.mysql.jdbc.Connection) toBeKilledConn) .clientPrepareStatement("INSERT INTO testBug20029 VALUES (?)"); for (int j = 0; j < 1000; j++) { toBeKilledPstmt.setInt(1, j); toBeKilledPstmt.addBatch(); } Thread t = new Thread() { public void run() { try { sleep(timeout); toBeKilledConn.close(); } catch (Throwable thr) { } } }; t.start(); try { if (!toBeKilledConn.isClosed()) { initialTimeout *= 2; continue; } toBeKilledPstmt.executeBatch(); fail("Should've caught a SQLException for the statement being closed here"); } catch (BatchUpdateException batchEx) { assertEquals("08003", batchEx.getSQLState()); break; } catch (SQLException sqlEx) { assertEquals("08003", sqlEx.getSQLState()); break; } fail("Connection didn't close while in the middle of PreparedStatement.executeBatch()"); } finally { if (toBeKilledPstmt != null) { toBeKilledPstmt.close(); } if (toBeKilledConn != null) { toBeKilledConn.close(); } } } } /** * Fixes BUG#20687 - Can't pool server-side prepared statements, exception * raised when re-using them. * * @throws Exception * if the test fails. */ public void testBug20687() throws Exception { if (!isRunningOnJdk131() && versionMeetsMinimum(5, 0)) { createTable("testBug20687", "(field1 int)"); Connection poolingConn = null; Properties props = new Properties(); props.setProperty("cachePrepStmts", "true"); props.setProperty("useServerPrepStmts", "true"); PreparedStatement pstmt1 = null; PreparedStatement pstmt2 = null; try { poolingConn = getConnectionWithProps(props); pstmt1 = poolingConn .prepareStatement("SELECT field1 FROM testBug20687"); pstmt1.executeQuery(); pstmt1.close(); pstmt2 = poolingConn .prepareStatement("SELECT field1 FROM testBug20687"); pstmt2.executeQuery(); assertTrue(pstmt1 == pstmt2); pstmt2.close(); } finally { if (pstmt1 != null) { pstmt1.close(); } if (pstmt2 != null) { pstmt2.close(); } if (poolingConn != null) { poolingConn.close(); } } } } public void testLikeWithBackslashes() throws Exception { if (!versionMeetsMinimum(5, 0, 0)) { return; } Connection noBackslashEscapesConn = null; try { Properties props = new Properties(); props.setProperty("sessionVariables", "sql_mode=NO_BACKSLASH_ESCAPES"); noBackslashEscapesConn = getConnectionWithProps(props); createTable( "X_TEST", "(userName varchar(32) not null, ivalue integer, CNAME varchar(255), bvalue CHAR(1), svalue varchar(255), ACTIVE CHAR(1), primary key (userName))"); String insert_sql = "insert into X_TEST (ivalue, CNAME, bvalue, svalue, ACTIVE, userName) values (?, ?, ?, ?, ?, ?)"; this.pstmt = noBackslashEscapesConn.prepareStatement(insert_sql); this.pstmt.setInt(1, 0); this.pstmt.setString(2, "c:\\jetson"); this.pstmt.setInt(3, 1); this.pstmt.setString(4, "c:\\jetson"); this.pstmt.setInt(5, 1); this.pstmt.setString(6, "c:\\jetson"); this.pstmt.execute(); String select_sql = "select user0_.userName as userName0_0_, user0_.ivalue as ivalue0_0_, user0_.CNAME as CNAME0_0_, user0_.bvalue as bvalue0_0_, user0_.svalue as svalue0_0_, user0_.ACTIVE as ACTIVE0_0_ from X_TEST user0_ where user0_.userName like ?"; this.pstmt = noBackslashEscapesConn.prepareStatement(select_sql); this.pstmt.setString(1, "c:\\j%"); // if we comment out the previous line and uncomment the following, // the like clause matches // this.pstmt.setString(1,"c:\\\\j%"); System.out.println("about to execute query " + select_sql); this.rs = this.pstmt.executeQuery(); assertTrue(this.rs.next()); } finally { if (noBackslashEscapesConn != null) { noBackslashEscapesConn.close(); } } } /** * Tests fix for BUG#20650 - Statement.cancel() causes NullPointerException * if underlying connection has been closed due to server failure. * * @throws Exception * if the test fails. */ public void testBug20650() throws Exception { Connection closedConn = null; Statement cancelStmt = null; try { closedConn = getConnectionWithProps((String) null); cancelStmt = closedConn.createStatement(); closedConn.close(); cancelStmt.cancel(); } finally { if (cancelStmt != null) { cancelStmt.close(); } if (closedConn != null && !closedConn.isClosed()) { closedConn.close(); } } } /** * Tests fix for BUG#20888 - escape of quotes in client-side prepared * statements parsing not respected. * * @throws Exception * if the test fails. */ public void testBug20888() throws Exception { String s = "SELECT 'What do you think about D\\'Artanian''?', \"What do you think about D\\\"Artanian\"\"?\""; this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement(s); this.rs = this.pstmt.executeQuery(); this.rs.next(); assertEquals(this.rs.getString(1), "What do you think about D'Artanian'?"); assertEquals(this.rs.getString(2), "What do you think about D\"Artanian\"?"); } /** * Tests Bug#21207 - Driver throws NPE when tracing prepared statements that * have been closed (in asSQL()). * * @throws Exception * if the test fails */ public void testBug21207() throws Exception { this.pstmt = this.conn.prepareStatement("SELECT 1"); this.pstmt.close(); this.pstmt.toString(); // this used to cause an NPE } /** * Tests BUG#21438, server-side PS fails when using jdbcCompliantTruncation. * If either is set to FALSE (&useServerPrepStmts=false or * &jdbcCompliantTruncation=false) test succedes. * * @throws Exception * if the test fails. */ public void testBug21438() throws Exception { createTable("testBug21438", "(t_id int(10), test_date timestamp NOT NULL,primary key t_pk (t_id));"); assertEquals( 1, this.stmt .executeUpdate("insert into testBug21438 values (1,NOW());")); if (this.versionMeetsMinimum(4, 1)) { this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .serverPrepareStatement("UPDATE testBug21438 SET test_date=ADDDATE(?,INTERVAL 1 YEAR) WHERE t_id=1;"); Timestamp ts = new Timestamp(System.currentTimeMillis()); ts.setNanos(999999999); this.pstmt.setTimestamp(1, ts); assertEquals(1, this.pstmt.executeUpdate()); Timestamp future = (Timestamp) getSingleIndexedValueWithQuery(1, "SELECT test_date FROM testBug21438"); assertEquals(future.getYear() - ts.getYear(), 1); } } /** * Tests fix for BUG#22359 - Driver was using millis for * Statement.setQueryTimeout() when spec says argument is seconds. * * @throws Exception * if the test fails. */ public void testBug22359() throws Exception { if (versionMeetsMinimum(5, 0)) { Statement timeoutStmt = null; try { timeoutStmt = this.conn.createStatement(); timeoutStmt.setQueryTimeout(2); long begin = System.currentTimeMillis(); try { timeoutStmt.execute("SELECT SLEEP(30)"); fail("Query didn't time out"); } catch (MySQLTimeoutException timeoutEx) { long end = System.currentTimeMillis(); assertTrue((end - begin) > 1000); } } finally { if (timeoutStmt != null) { timeoutStmt.close(); } } } } /** * Tests fix for BUG#22290 - Driver issues truncation on write exception * when it shouldn't (due to sending big decimal incorrectly to server with * server-side prepared statement). * * @throws Exception * if the test fails. */ public void testBug22290() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; } createTable( "testbug22290", "(`id` int(11) NOT NULL default '1',`cost` decimal(10,2) NOT NULL,PRIMARY KEY (`id`))" + " DEFAULT CHARSET=utf8", "InnoDB"); assertEquals( this.stmt .executeUpdate("INSERT INTO testbug22290 (`id`,`cost`) VALUES (1,'1.00')"), 1); Connection configuredConn = null; try { Properties props = new Properties(); props.setProperty("sessionVariables", "sql_mode='STRICT_TRANS_TABLES'"); configuredConn = getConnectionWithProps(props); this.pstmt = configuredConn .prepareStatement("update testbug22290 set cost = cost + ? where id = 1"); this.pstmt.setBigDecimal(1, new BigDecimal("1.11")); assertEquals(this.pstmt.executeUpdate(), 1); assertEquals( this.stmt .executeUpdate("UPDATE testbug22290 SET cost='1.00'"), 1); this.pstmt = ((com.mysql.jdbc.Connection) configuredConn) .clientPrepareStatement("update testbug22290 set cost = cost + ? where id = 1"); this.pstmt.setBigDecimal(1, new BigDecimal("1.11")); assertEquals(this.pstmt.executeUpdate(), 1); } finally { if (configuredConn != null) { configuredConn.close(); } } } public void testClientPreparedSetBoolean() throws Exception { this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement("SELECT ?"); this.pstmt.setBoolean(1, false); assertEquals( "SELECT 0", this.pstmt.toString().substring( this.pstmt.toString().indexOf("SELECT"))); this.pstmt.setBoolean(1, true); assertEquals( "SELECT 1", this.pstmt.toString().substring( this.pstmt.toString().indexOf("SELECT"))); } /** * Tests fix for BUG#24360 .setFetchSize() breaks prepared SHOW and other * commands. * * @throws Exception * if the test fails */ public void testBug24360() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; } Connection c = null; Properties props = new Properties(); props.setProperty("useServerPrepStmts", "true"); try { c = getConnectionWithProps(props); this.pstmt = c.prepareStatement("SHOW PROCESSLIST"); this.pstmt.setFetchSize(5); this.pstmt.execute(); } finally { if (c != null) { c.close(); } } } /** * Tests fix for BUG#24344 - useJDBCCompliantTimezoneShift with server-side * prepared statements gives different behavior than when using client-side * prepared statements. (this is now fixed if moving from server-side * prepared statements to client-side prepared statements by setting * "useSSPSCompatibleTimezoneShift" to "true", as the driver can't tell if * this is a new deployment that never used server-side prepared statements, * or if it is an existing deployment that is switching to client-side * prepared statements from server-side prepared statements. * * @throws Exception * if the test fails */ public void testBug24344() throws Exception { if (!versionMeetsMinimum(4, 1)) { return; // need SSPS } super.createTable("testBug24344", "(i INT AUTO_INCREMENT, t1 DATETIME, PRIMARY KEY (i)) ENGINE = MyISAM"); Connection conn2 = null; try { Properties props = new Properties(); props.setProperty("useServerPrepStmts", "true"); props.setProperty("useJDBCCompliantTimezoneShift", "true"); conn2 = super.getConnectionWithProps(props); this.pstmt = conn2 .prepareStatement("INSERT INTO testBug24344 (t1) VALUES (?)"); Calendar c = Calendar.getInstance(); this.pstmt.setTimestamp(1, new Timestamp(c.getTime().getTime())); this.pstmt.execute(); this.pstmt.close(); conn2.close(); props.setProperty("useServerPrepStmts", "false"); props.setProperty("useJDBCCompliantTimezoneShift", "true"); props.setProperty("useSSPSCompatibleTimezoneShift", "true"); conn2 = super.getConnectionWithProps(props); this.pstmt = conn2 .prepareStatement("INSERT INTO testBug24344 (t1) VALUES (?)"); this.pstmt.setTimestamp(1, new Timestamp(c.getTime().getTime())); this.pstmt.execute(); this.pstmt.close(); conn2.close(); props.setProperty("useServerPrepStmts", "false"); props.setProperty("useJDBCCompliantTimezoneShift", "false"); props.setProperty("useSSPSCompatibleTimezoneShift", "false"); conn2 = super.getConnectionWithProps(props); this.pstmt = conn2 .prepareStatement("INSERT INTO testBug24344 (t1) VALUES (?)"); this.pstmt.setTimestamp(1, new Timestamp(c.getTime().getTime())); this.pstmt.execute(); this.pstmt.close(); Statement s = conn2.createStatement(); this.rs = s .executeQuery("SELECT t1 FROM testBug24344 ORDER BY i ASC"); Timestamp[] dates = new Timestamp[3]; int i = 0; while (rs.next()) { dates[i++] = rs.getTimestamp(1); } assertEquals("Number of rows should be 3.", 3, i); assertEquals(dates[0], dates[1]); assertTrue(!dates[1].equals(dates[2])); } finally { if (conn2 != null) { conn2.close(); } } } /** * Tests fix for BUG#25073 - rewriting batched statements leaks internal * statement instances, and causes a memory leak. * * @throws Exception * if the test fails. */ public void testBug25073() throws Exception { if (isRunningOnJdk131()) { return; } Properties props = new Properties(); props.setProperty("rewriteBatchedStatements", "true"); Connection multiConn = getConnectionWithProps(props); createTable("testBug25073", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); Statement multiStmt = multiConn.createStatement(); multiStmt.addBatch("INSERT INTO testBug25073(field1) VALUES (1)"); multiStmt.addBatch("INSERT INTO testBug25073(field1) VALUES (2)"); multiStmt.addBatch("INSERT INTO testBug25073(field1) VALUES (3)"); multiStmt.addBatch("INSERT INTO testBug25073(field1) VALUES (4)"); multiStmt.addBatch("UPDATE testBug25073 SET field1=5 WHERE field1=1"); multiStmt .addBatch("UPDATE testBug25073 SET field1=6 WHERE field1=2 OR field1=3"); int beforeOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); multiStmt.executeBatch(); int afterOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); assertEquals(beforeOpenStatementCount, afterOpenStatementCount); createTable("testBug25073", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); props.clear(); props.setProperty("rewriteBatchedStatements", "true"); props.setProperty("maxAllowedPacket", "1024"); props.setProperty("dumpQueriesOnException", "true"); props.setProperty("maxQuerySizeToLog", String.valueOf(1024 * 1024 * 2)); multiConn = getConnectionWithProps(props); multiStmt = multiConn.createStatement(); for (int i = 0; i < 1000; i++) { multiStmt.addBatch("INSERT INTO testBug25073(field1) VALUES (" + i + ")"); } beforeOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); multiStmt.executeBatch(); afterOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); assertEquals(beforeOpenStatementCount, afterOpenStatementCount); createTable("testBug25073", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); props.clear(); props.setProperty("useServerPrepStmts", "false"); props.setProperty("rewriteBatchedStatements", "true"); props.setProperty("dumpQueriesOnException", "true"); props.setProperty("maxQuerySizeToLog", String.valueOf(1024 * 1024 * 2)); multiConn = getConnectionWithProps(props); PreparedStatement pStmt = multiConn.prepareStatement( "INSERT INTO testBug25073(field1) VALUES (?)", Statement.RETURN_GENERATED_KEYS); for (int i = 0; i < 1000; i++) { pStmt.setInt(1, i); pStmt.addBatch(); } beforeOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); pStmt.executeBatch(); afterOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); assertEquals(beforeOpenStatementCount, afterOpenStatementCount); createTable("testBug25073", "(pk_field INT PRIMARY KEY NOT NULL AUTO_INCREMENT, field1 INT)"); props.setProperty("useServerPrepStmts", "false"); props.setProperty("rewriteBatchedStatements", "true"); props.setProperty("maxAllowedPacket", "1024"); props.setProperty("dumpQueriesOnException", "true"); props.setProperty("maxQuerySizeToLog", String.valueOf(1024 * 1024 * 2)); multiConn = getConnectionWithProps(props); pStmt = multiConn.prepareStatement( "INSERT INTO testBug25073(field1) VALUES (?)", Statement.RETURN_GENERATED_KEYS); for (int i = 0; i < 1000; i++) { pStmt.setInt(1, i); pStmt.addBatch(); } beforeOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); pStmt.executeBatch(); afterOpenStatementCount = ((com.mysql.jdbc.Connection) multiConn) .getActiveStatementCount(); assertEquals(beforeOpenStatementCount, afterOpenStatementCount); } /** * Tests fix for BUG#25009 - Results from updates not handled correctly in * multi-statement queries. * * @throws Exception * if the test fails. */ public void testBug25009() throws Exception { if (!versionMeetsMinimum(4, 1)) { return; } Properties props = new Properties(); props.setProperty("allowMultiQueries", "true"); Connection multiConn = getConnectionWithProps(props); createTable("testBug25009", "(field1 INT)"); try { Statement multiStmt = multiConn.createStatement(); multiStmt .execute("SELECT 1;SET @a=1; SET @b=2; SET @c=3; INSERT INTO testBug25009 VALUES (1)"); assertEquals(-1, multiStmt.getUpdateCount()); this.rs = multiStmt.getResultSet(); assertTrue(this.rs.next()); assertEquals(multiStmt.getMoreResults(), false); for (int i = 0; i < 3; i++) { assertEquals(0, multiStmt.getUpdateCount()); assertEquals(multiStmt.getMoreResults(), false); } assertEquals(1, multiStmt.getUpdateCount()); this.rs = multiStmt.executeQuery("SELECT field1 FROM testBug25009"); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); } finally { if (multiConn != null) { multiConn.close(); } } } /** * Tests fix for BUG#25025 - Client-side prepared statement parser gets * confused by in-line (slash-star) comments and therefore can't rewrite * batched statements or reliably detect type of statements when they're * used. * * @throws Exception * if the test fails. */ public void testBug25025() throws Exception { Connection multiConn = null; createTable("testBug25025", "(field1 INT)"); try { Properties props = new Properties(); props.setProperty("rewriteBatchedStatements", "true"); props.setProperty("useServerPrepStmts", "false"); multiConn = getConnectionWithProps(props); this.pstmt = multiConn .prepareStatement("/* insert foo.bar.baz INSERT INTO foo VALUES (?,?,?,?) to trick parser */ INSERT into testBug25025 VALUES (?)"); this.pstmt.setInt(1, 1); this.pstmt.addBatch(); this.pstmt.setInt(1, 2); this.pstmt.addBatch(); this.pstmt.setInt(1, 3); this.pstmt.addBatch(); int[] counts = this.pstmt.executeBatch(); assertEquals(3, counts.length); assertEquals(1, counts[0]); assertEquals(1, counts[1]); assertEquals(1, counts[2]); assertEquals(true, ((com.mysql.jdbc.PreparedStatement) this.pstmt) .canRewriteAsMultiValueInsertAtSqlLevel()); } finally { if (multiConn != null) { multiConn.close(); } } } public void testBustedGGKWithPSExecute() throws Exception { createTable("sequence", "(sequence_name VARCHAR(32) NOT NULL PRIMARY KEY, next_val BIGINT NOT NULL)"); // Populate with the initial value stmt.executeUpdate("INSERT INTO sequence VALUES ('test-sequence', 1234)"); // Atomic operation to increment and return next value PreparedStatement pStmt = null; try { pStmt = this.conn .prepareStatement( "UPDATE sequence SET next_val=LAST_INSERT_ID(next_val + ?) WHERE sequence_name = ?", Statement.RETURN_GENERATED_KEYS); pStmt.setInt(1, 4); pStmt.setString(2, "test-sequence"); pStmt.execute(); this.rs = pStmt.getGeneratedKeys(); this.rs.next(); assertEquals(1238, this.rs.getLong(1)); } finally { if (pStmt != null) { pStmt.close(); } } } /** * Tests fix for BUG#28256 - When connection is in read-only mode, queries * that are parentheized incorrectly identified as DML. * * @throws Exception */ public void testBug28256() throws Exception { try { this.conn.setReadOnly(true); this.stmt.execute("(SELECT 1) UNION (SELECT 2)"); this.conn.prepareStatement("(SELECT 1) UNION (SELECT 2)").execute(); if (versionMeetsMinimum(4, 1)) { ((com.mysql.jdbc.Connection) this.conn).serverPrepareStatement( "(SELECT 1) UNION (SELECT 2)").execute(); } } finally { this.conn.setReadOnly(false); } } /** * Tests fix for BUG#28469 - PreparedStatement.getMetaData() for statements * containing leading one-line comments is not returned correctly. * * As part of this fix, we also overhauled detection of DML for * executeQuery() and SELECTs for executeUpdate() in plain and prepared * statements to be aware of the same types of comments. * * @throws Exception */ public void testBug28469() throws Exception { PreparedStatement commentStmt = null; try { String[] statementsToTest = { "-- COMMENT\nSELECT 1", "# COMMENT\nSELECT 1", "/* comment */ SELECT 1" }; for (int i = 0; i < statementsToTest.length; i++) { commentStmt = this.conn.prepareStatement(statementsToTest[i]); assertNotNull(commentStmt.getMetaData()); try { commentStmt.executeUpdate(); fail("Should not be able to call executeUpdate() on a SELECT statement!"); } catch (SQLException sqlEx) { // expected } this.rs = commentStmt.executeQuery(); this.rs.next(); assertEquals(1, this.rs.getInt(1)); } createTable("testBug28469", "(field1 INT)"); String[] updatesToTest = { "-- COMMENT\nUPDATE testBug28469 SET field1 = 2", "# COMMENT\nUPDATE testBug28469 SET field1 = 2", "/* comment */ UPDATE testBug28469 SET field1 = 2" }; for (int i = 0; i < updatesToTest.length; i++) { commentStmt = this.conn.prepareStatement(updatesToTest[i]); assertNull(commentStmt.getMetaData()); try { commentStmt.executeQuery(); fail("Should not be able to call executeQuery() on a SELECT statement!"); } catch (SQLException sqlEx) { // expected } try { this.stmt.executeQuery(updatesToTest[i]); fail("Should not be able to call executeQuery() on a SELECT statement!"); } catch (SQLException sqlEx) { // expected } } } finally { if (commentStmt != null) { commentStmt.close(); } } } /** * Tests error with slash-star comment at EOL * * @throws Exception * if the test fails. */ public void testCommentParsing() throws Exception { createTable("PERSON", "(NAME VARCHAR(32), PERID VARCHAR(32))"); this.pstmt = this.conn .prepareStatement("SELECT NAME AS name2749_0_, PERID AS perid2749_0_ FROM PERSON WHERE PERID=? /*FOR UPDATE*/"); } /** * Tests fix for BUG#28851 - parser in client-side prepared statements eats * character following '/' if it's not a multi-line comment. * * @throws Exception * if the test fails. */ public void testBug28851() throws Exception { this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement("SELECT 1/?"); this.pstmt.setInt(1, 1); this.rs = this.pstmt.executeQuery(); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); } /** * Tests fix for BUG#28596 - parser in client-side prepared statements runs * to end of statement, rather than end-of-line for '#' comments. * * Also added support for '--' single-line comments * * @throws Exception * if the test fails. */ public void testBug28596() throws Exception { String query = "SELECT #\n" + "?, #\n" + "? #?\r\n" + ",-- abcdefg \n" + "?"; this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .clientPrepareStatement(query); this.pstmt.setInt(1, 1); this.pstmt.setInt(2, 2); this.pstmt.setInt(3, 3); assertEquals(3, this.pstmt.getParameterMetaData().getParameterCount()); this.rs = this.pstmt.executeQuery(); assertTrue(this.rs.next()); assertEquals(1, this.rs.getInt(1)); assertEquals(2, this.rs.getInt(2)); assertEquals(3, this.rs.getInt(3)); } /** * Tests fix for BUG#30550 - executeBatch() on an empty batch when there are * no elements in the batch causes a divide-by-zero error when rewriting is * enabled. * * @throws Exception * if the test fails */ public void testBug30550() throws Exception { createTable("testBug30550", "(field1 int)"); Connection rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true"); PreparedStatement batchPStmt = null; Statement batchStmt = null; try { batchStmt = rewriteConn.createStatement(); assertEquals(0, batchStmt.executeBatch().length); batchStmt.addBatch("INSERT INTO testBug30550 VALUES (1)"); int[] counts = batchStmt.executeBatch(); assertEquals(1, counts.length); assertEquals(1, counts[0]); assertEquals(0, batchStmt.executeBatch().length); batchPStmt = rewriteConn .prepareStatement("INSERT INTO testBug30550 VALUES (?)"); batchPStmt.setInt(1, 1); assertEquals(0, batchPStmt.executeBatch().length); batchPStmt.addBatch(); counts = batchPStmt.executeBatch(); assertEquals(1, counts.length); assertEquals(1, counts[0]); assertEquals(0, batchPStmt.executeBatch().length); } finally { if (batchPStmt != null) { batchPStmt.close(); } if (batchStmt != null) { batchStmt.close(); } if (rewriteConn != null) { rewriteConn.close(); } } } /** * Tests fix for Bug#27412 - cached metadata with * PreparedStatement.execute() throws NullPointerException. * * @throws Exception */ public void testBug27412() throws Exception { Properties props = new Properties(); props.put("useServerPrepStmts", "false"); props.put("cachePreparedStatements", "true"); props.put("cacheResultSetMetadata", "true"); Connection conn2 = getConnectionWithProps(props); PreparedStatement pstm = conn2.prepareStatement("SELECT 1"); try { assertTrue(pstm.execute()); } finally { pstm.close(); conn2.close(); } } public void testBustedGGKColumnNames() throws Exception { createTable("testBustedGGKColumnNames", "(field1 int primary key auto_increment)"); this.stmt.executeUpdate( "INSERT INTO testBustedGGKColumnNames VALUES (null)", Statement.RETURN_GENERATED_KEYS); assertEquals("GENERATED_KEY", this.stmt.getGeneratedKeys() .getMetaData().getColumnName(1)); this.pstmt = this.conn.prepareStatement( "INSERT INTO testBustedGGKColumnNames VALUES (null)", Statement.RETURN_GENERATED_KEYS); this.pstmt.executeUpdate(); assertEquals("GENERATED_KEY", this.pstmt.getGeneratedKeys() .getMetaData().getColumnName(1)); if (versionMeetsMinimum(4, 1, 0)) { this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .serverPrepareStatement( "INSERT INTO testBustedGGKColumnNames VALUES (null)", Statement.RETURN_GENERATED_KEYS); this.pstmt.executeUpdate(); assertEquals("GENERATED_KEY", this.pstmt.getGeneratedKeys() .getMetaData().getColumnName(1)); } } public void testLancesBitMappingBug() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; } createTable("Bit_TabXXX", "( `MAX_VAL` BIT default NULL, " + "`MIN_VAL` BIT default NULL, `NULL_VAL` BIT default NULL) " + "DEFAULT CHARSET=latin1", "InnoDB"); // add Bit_In_MinXXX procedure createProcedure("Bit_In_MinXXX", "(MIN_PARAM TINYINT(1)) begin update Bit_TabXXX set MIN_VAL=MIN_PARAM; end"); createProcedure("Bit_In_MaxXXX", "(MAX_PARAM TINYINT(1)) begin update Bit_TabXXX set MAX_VAL=MAX_PARAM; end"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); String sPrepStmt = "{call Bit_In_MinXXX(?)}"; this.pstmt = conn.prepareStatement(sPrepStmt); this.pstmt.setObject(1, "true", java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "true", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, "false", java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "false", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, "1", java.sql.Types.BIT); // fails this.pstmt.executeUpdate(); assertEquals( "true", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, "0", java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "false", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, Boolean.TRUE, java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "true", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, Boolean.FALSE, java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "false", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, new Boolean(true), java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "true", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, new Boolean(false), java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "false", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, new Byte("1"), java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "true", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); this.stmt.execute("TRUNCATE TABLE Bit_TabXXX"); this.stmt.execute("insert into Bit_TabXXX values(null,0,null)"); this.pstmt.setObject(1, new Byte("0"), java.sql.Types.BIT); this.pstmt.executeUpdate(); assertEquals( "false", getSingleIndexedValueWithQuery(1, "SELECT MIN_VAL FROM Bit_TabXXX").toString()); } /** * Tests fix for BUG#32577 - no way to store two timestamp/datetime values * that happens over the DST switchover, as the hours end up being the same * when sent as the literal that MySQL requires. * * Note that to get this scenario to work with MySQL (since it doesn't * support per-value timezones), you need to configure your server (or * session) to be in UTC, and tell the driver not to use the legacy * date/time code by setting "useLegacyDatetimeCode" to "false". This will * cause the driver to always convert to/from the server and client timezone * consistently. * * @throws Exception */ public void testBug32577() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; } createTable("testBug32577", "(id INT, field_datetime DATETIME, field_timestamp TIMESTAMP)"); Properties props = new Properties(); props.setProperty("useLegacyDatetimeCode", "false"); props.setProperty("sessionVariables", "time_zone='+0:00'"); props.setProperty("serverTimezone", "UTC"); Connection nonLegacyConn = getConnectionWithProps(props); try { long earlier = 1194154200000L; long later = 1194157800000L; this.pstmt = nonLegacyConn .prepareStatement("INSERT INTO testBug32577 VALUES (?,?,?)"); Timestamp ts = new Timestamp(earlier); this.pstmt.setInt(1, 1); this.pstmt.setTimestamp(2, ts); this.pstmt.setTimestamp(3, ts); this.pstmt.executeUpdate(); ts = new Timestamp(later); this.pstmt.setInt(1, 2); this.pstmt.setTimestamp(2, ts); this.pstmt.setTimestamp(3, ts); this.pstmt.executeUpdate(); this.rs = nonLegacyConn .createStatement() .executeQuery( "SELECT id, field_datetime, field_timestamp " + ", UNIX_TIMESTAMP(field_datetime), UNIX_TIMESTAMP(field_timestamp) " + "FROM testBug32577 ORDER BY id ASC"); this.rs.next(); //java.util.Date date1 = new Date(this.rs.getTimestamp(2).getTime()); Timestamp ts1 = this.rs.getTimestamp(3); long datetimeSeconds1 = rs.getLong(4) * 1000; long timestampSeconds1 = rs.getLong(5) * 1000; this.rs.next(); //java.util.Date date2 = new Date(this.rs.getTimestamp(2).getTime()); Timestamp ts2 = this.rs.getTimestamp(3); long datetimeSeconds2 = rs.getLong(4) * 1000; long timestampSeconds2 = rs.getLong(5) * 1000; assertEquals(later, datetimeSeconds2); assertEquals(later, timestampSeconds2); assertEquals(earlier, datetimeSeconds1); assertEquals(earlier, timestampSeconds1); SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm z"); sdf.setTimeZone(TimeZone.getTimeZone("America/New York")); System.out.println(sdf.format(ts2)); System.out.println(sdf.format(ts1)); } finally { if (nonLegacyConn != null) { nonLegacyConn.close(); } } } /** * Tests fix for BUG#30508 - ResultSet returned by * Statement.getGeneratedKeys() is not closed automatically when statement * that created it is closed. * * @throws Exception */ public void testBug30508() throws Exception { createTable("testBug30508", "(k INT PRIMARY KEY NOT NULL AUTO_INCREMENT, p VARCHAR(32))"); try { Statement ggkStatement = this.conn.createStatement(); ggkStatement.executeUpdate( "INSERT INTO testBug30508 (p) VALUES ('abc')", Statement.RETURN_GENERATED_KEYS); this.rs = ggkStatement.getGeneratedKeys(); ggkStatement.close(); this.rs.next(); fail("Should've had an exception here"); } catch (SQLException sqlEx) { assertEquals("S1000", sqlEx.getSQLState()); } try { this.pstmt = this.conn.prepareStatement("SELECT 1", Statement.RETURN_GENERATED_KEYS); this.rs = this.pstmt.getGeneratedKeys(); this.pstmt.close(); this.rs.next(); fail("Should've had an exception here"); } catch (SQLException sqlEx) { assertEquals("S1000", sqlEx.getSQLState()); } if (versionMeetsMinimum(5, 0)) { createProcedure("testBug30508", "() BEGIN SELECT 1; END"); try { this.pstmt = this.conn.prepareCall("{CALL testBug30508()}"); this.rs = this.pstmt.getGeneratedKeys(); this.pstmt.close(); this.rs.next(); fail("Should've had an exception here"); } catch (SQLException sqlEx) { assertEquals("S1000", sqlEx.getSQLState()); } } } public void testMoreLanceBugs() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; } createTable("Bit_Tab", "( `MAX_VAL` BIT default NULL, " + "`MIN_VAL` BIT default NULL, `NULL_VAL` BIT default NULL) " + "DEFAULT CHARSET=latin1", "InnoDB"); // this.stmt.execute("insert into Bit_Tab values(null,0,null)"); createProcedure( "Bit_Proc", "(out MAX_PARAM TINYINT, out MIN_PARAM TINYINT, out NULL_PARAM TINYINT) " + "begin select MAX_VAL, MIN_VAL, NULL_VAL into MAX_PARAM, MIN_PARAM, NULL_PARAM from Bit_Tab; end "); Boolean minBooleanVal; Boolean oRetVal; String Min_Val_Query = "SELECT MIN_VAL from Bit_Tab"; String Min_Insert = "insert into Bit_Tab values(1,0,null)"; // System.out.println("Value to insert=" + extractVal(Min_Insert,1)); CallableStatement cstmt; this.stmt.executeUpdate("delete from Bit_Tab"); this.stmt.executeUpdate(Min_Insert); cstmt = this.conn.prepareCall("{call Bit_Proc(?,?,?)}"); cstmt.registerOutParameter(1, java.sql.Types.BIT); cstmt.registerOutParameter(2, java.sql.Types.BIT); cstmt.registerOutParameter(3, java.sql.Types.BIT); cstmt.executeUpdate(); boolean bRetVal = cstmt.getBoolean(2); oRetVal = new Boolean(bRetVal); minBooleanVal = new Boolean("false"); this.rs = this.stmt.executeQuery(Min_Val_Query); assertEquals(minBooleanVal, oRetVal); } public void testBug33823() { new ResultSetInternalMethods() { public void buildIndexMapping() throws SQLException { } public void clearNextResult() { } public ResultSetInternalMethods copy() throws SQLException { return null; } public char getFirstCharOfQuery() { return 0; } public ResultSetInternalMethods getNextResultSet() { return null; } public Object getObjectStoredProc(int columnIndex, int desiredSqlType) throws SQLException { return null; } public Object getObjectStoredProc(int i, Map<Object, Object> map, int desiredSqlType) throws SQLException { return null; } public Object getObjectStoredProc(String columnName, int desiredSqlType) throws SQLException { return null; } public Object getObjectStoredProc(String colName, Map<Object, Object> map, int desiredSqlType) throws SQLException { return null; } public String getServerInfo() { return null; } public long getUpdateCount() { return 0; } public long getUpdateID() { return 0; } public void initializeFromCachedMetaData( CachedResultSetMetaData cachedMetaData) { cachedMetaData.getFields(); } public void initializeWithMetadata() throws SQLException { } public void populateCachedMetaData( CachedResultSetMetaData cachedMetaData) throws SQLException { } public void realClose(boolean calledExplicitly) throws SQLException { } public boolean reallyResult() { return false; } public void redefineFieldsForDBMD(Field[] metadataFields) { } public void setFirstCharOfQuery(char firstCharUpperCase) { } public void setOwningStatement(StatementImpl owningStatement) { } public void setStatementUsedForFetchingRows( com.mysql.jdbc.PreparedStatement stmt) { } public void setWrapperStatement(Statement wrapperStatement) { } public boolean absolute(int row) throws SQLException { return false; } public void afterLast() throws SQLException { } public void beforeFirst() throws SQLException { } public void cancelRowUpdates() throws SQLException { } public void clearWarnings() throws SQLException { } public void close() throws SQLException { } public void deleteRow() throws SQLException { } public int findColumn(String columnName) throws SQLException { return 0; } public boolean first() throws SQLException { return false; } public Array getArray(int i) throws SQLException { return null; } public Array getArray(String colName) throws SQLException { return null; } public InputStream getAsciiStream(int columnIndex) throws SQLException { return null; } public InputStream getAsciiStream(String columnName) throws SQLException { return null; } public BigDecimal getBigDecimal(int columnIndex) throws SQLException { return null; } public BigDecimal getBigDecimal(String columnName) throws SQLException { return null; } public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { return null; } public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { return null; } public InputStream getBinaryStream(int columnIndex) throws SQLException { return null; } public InputStream getBinaryStream(String columnName) throws SQLException { return null; } public Blob getBlob(int i) throws SQLException { return null; } public Blob getBlob(String colName) throws SQLException { return null; } public boolean getBoolean(int columnIndex) throws SQLException { return false; } public boolean getBoolean(String columnName) throws SQLException { return false; } public byte getByte(int columnIndex) throws SQLException { return 0; } public byte getByte(String columnName) throws SQLException { return 0; } public byte[] getBytes(int columnIndex) throws SQLException { return null; } public byte[] getBytes(String columnName) throws SQLException { return null; } public Reader getCharacterStream(int columnIndex) throws SQLException { return null; } public Reader getCharacterStream(String columnName) throws SQLException { return null; } public Clob getClob(int i) throws SQLException { return null; } public Clob getClob(String colName) throws SQLException { return null; } public int getConcurrency() throws SQLException { return 0; } public String getCursorName() throws SQLException { return null; } public Date getDate(int columnIndex) throws SQLException { return null; } public Date getDate(String columnName) throws SQLException { return null; } public Date getDate(int columnIndex, Calendar cal) throws SQLException { return null; } public Date getDate(String columnName, Calendar cal) throws SQLException { return null; } public double getDouble(int columnIndex) throws SQLException { return 0; } public double getDouble(String columnName) throws SQLException { return 0; } public int getFetchDirection() throws SQLException { return 0; } public int getFetchSize() throws SQLException { return 0; } public float getFloat(int columnIndex) throws SQLException { return 0; } public float getFloat(String columnName) throws SQLException { return 0; } public int getInt(int columnIndex) throws SQLException { return 0; } public int getInt(String columnName) throws SQLException { return 0; } public long getLong(int columnIndex) throws SQLException { return 0; } public long getLong(String columnName) throws SQLException { return 0; } public ResultSetMetaData getMetaData() throws SQLException { return null; } public Object getObject(int columnIndex) throws SQLException { return null; } public Object getObject(String columnName) throws SQLException { return null; } public Object getObject(int arg0, Map<String,Class<?>> arg1) throws SQLException { return null; } public Object getObject(String arg0, Map<String,Class<?>> arg1) throws SQLException { return null; } public Ref getRef(int i) throws SQLException { return null; } public Ref getRef(String colName) throws SQLException { return null; } public int getRow() throws SQLException { return 0; } public short getShort(int columnIndex) throws SQLException { return 0; } public short getShort(String columnName) throws SQLException { return 0; } public Statement getStatement() throws SQLException { return null; } public String getString(int columnIndex) throws SQLException { return null; } public String getString(String columnName) throws SQLException { return null; } public Time getTime(int columnIndex) throws SQLException { return null; } public Time getTime(String columnName) throws SQLException { return null; } public Time getTime(int columnIndex, Calendar cal) throws SQLException { return null; } public Time getTime(String columnName, Calendar cal) throws SQLException { return null; } public Timestamp getTimestamp(int columnIndex) throws SQLException { return null; } public Timestamp getTimestamp(String columnName) throws SQLException { return null; } public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { return null; } public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException { return null; } public int getType() throws SQLException { return 0; } public URL getURL(int columnIndex) throws SQLException { return null; } public URL getURL(String columnName) throws SQLException { return null; } public InputStream getUnicodeStream(int columnIndex) throws SQLException { return null; } public InputStream getUnicodeStream(String columnName) throws SQLException { return null; } public SQLWarning getWarnings() throws SQLException { return null; } public void insertRow() throws SQLException { } public boolean isAfterLast() throws SQLException { return false; } public boolean isBeforeFirst() throws SQLException { return false; } public boolean isFirst() throws SQLException { return false; } public boolean isLast() throws SQLException { return false; } public boolean last() throws SQLException { return false; } public void moveToCurrentRow() throws SQLException { } public void moveToInsertRow() throws SQLException { } public boolean next() throws SQLException { return false; } public boolean previous() throws SQLException { return false; } public void refreshRow() throws SQLException { } public boolean relative(int rows) throws SQLException { return false; } public boolean rowDeleted() throws SQLException { return false; } public boolean rowInserted() throws SQLException { return false; } public boolean rowUpdated() throws SQLException { return false; } public void setFetchDirection(int direction) throws SQLException { } public void setFetchSize(int rows) throws SQLException { } public void updateArray(int columnIndex, Array x) throws SQLException { } public void updateArray(String columnName, Array x) throws SQLException { } public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { } public void updateAsciiStream(String columnName, InputStream x, int length) throws SQLException { } public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { } public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException { } public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { } public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException { } public void updateBlob(int columnIndex, Blob x) throws SQLException { } public void updateBlob(String columnName, Blob x) throws SQLException { } public void updateBoolean(int columnIndex, boolean x) throws SQLException { } public void updateBoolean(String columnName, boolean x) throws SQLException { } public void updateByte(int columnIndex, byte x) throws SQLException { } public void updateByte(String columnName, byte x) throws SQLException { } public void updateBytes(int columnIndex, byte[] x) throws SQLException { } public void updateBytes(String columnName, byte[] x) throws SQLException { } public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { } public void updateCharacterStream(String columnName, Reader reader, int length) throws SQLException { } public void updateClob(int columnIndex, Clob x) throws SQLException { } public void updateClob(String columnName, Clob x) throws SQLException { } public void updateDate(int columnIndex, Date x) throws SQLException { } public void updateDate(String columnName, Date x) throws SQLException { } public void updateDouble(int columnIndex, double x) throws SQLException { } public void updateDouble(String columnName, double x) throws SQLException { } public void updateFloat(int columnIndex, float x) throws SQLException { } public void updateFloat(String columnName, float x) throws SQLException { } public void updateInt(int columnIndex, int x) throws SQLException { } public void updateInt(String columnName, int x) throws SQLException { } public void updateLong(int columnIndex, long x) throws SQLException { } public void updateLong(String columnName, long x) throws SQLException { } public void updateNull(int columnIndex) throws SQLException { } public void updateNull(String columnName) throws SQLException { } public void updateObject(int columnIndex, Object x) throws SQLException { } public void updateObject(String columnName, Object x) throws SQLException { } public void updateObject(int columnIndex, Object x, int scale) throws SQLException { } public void updateObject(String columnName, Object x, int scale) throws SQLException { } public void updateRef(int columnIndex, Ref x) throws SQLException { } public void updateRef(String columnName, Ref x) throws SQLException { } public void updateRow() throws SQLException { } public void updateShort(int columnIndex, short x) throws SQLException { } public void updateShort(String columnName, short x) throws SQLException { } public void updateString(int columnIndex, String x) throws SQLException { } public void updateString(String columnName, String x) throws SQLException { } public void updateTime(int columnIndex, Time x) throws SQLException { } public void updateTime(String columnName, Time x) throws SQLException { } public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { } public void updateTimestamp(String columnName, Timestamp x) throws SQLException { } public boolean wasNull() throws SQLException { return false; } public int getBytesSize() throws SQLException { return 0; } }; } /** * Tests fix for BUG#34093 - Statements with batched values do not return * correct values for getGeneratedKeys() when "rewriteBatchedStatements" is * set to "true", and the statement has an "ON DUPLICATE KEY UPDATE" clause. * * @throws Exception * if the test fails. */ public void testBug34093() throws Exception { Connection rewriteConn = null; rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true"); checkBug34093(rewriteConn); rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true,useServerPrepStmts=true"); checkBug34093(rewriteConn); } private void checkBug34093(Connection rewriteConn) throws Exception { try { String ddl = "(autoIncId INT NOT NULL PRIMARY KEY AUTO_INCREMENT, uniqueTextKey VARCHAR(255), UNIQUE KEY (uniqueTextKey(100)))"; String[] sequence = { "c", "a", "d", "b" }; String sql = "insert into testBug30493 (uniqueTextKey) values (?) on duplicate key UPDATE autoIncId = last_insert_id( autoIncId )"; String tablePrimeSql = "INSERT INTO testBug30493 (uniqueTextKey) VALUES ('a'), ('b'), ('c'), ('d')"; // setup the rewritten and non-written statements Statement stmts[] = new Statement[2]; PreparedStatement pstmts[] = new PreparedStatement[2]; stmts[0] = conn.createStatement(); stmts[1] = rewriteConn.createStatement(); pstmts[0] = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); pstmts[1] = rewriteConn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); for (int i = 0; i < sequence.length; ++i) { String sqlLiteral = sql.replaceFirst("\\?", "'" + sequence[i] + "'"); stmts[0].addBatch(sqlLiteral); stmts[1].addBatch(sqlLiteral); pstmts[0].setString(1, sequence[i]); pstmts[0].addBatch(); pstmts[1].setString(1, sequence[i]); pstmts[1].addBatch(); } // run the test once for Statement, and once for PreparedStatement Statement stmtSets[][] = new Statement[2][]; stmtSets[0] = stmts; stmtSets[1] = pstmts; for (int stmtSet = 0; stmtSet < 2; ++stmtSet) { Statement testStmts[] = stmtSets[stmtSet]; createTable("testBug30493", ddl); this.stmt.executeUpdate(tablePrimeSql); int nonRwUpdateCounts[] = testStmts[0].executeBatch(); ResultSet nonRewrittenRsKeys = testStmts[0].getGeneratedKeys(); createTable("testBug30493", ddl); this.stmt.executeUpdate(tablePrimeSql); int expectedUpdateCount = versionMeetsMinimum(5, 1, 0) ? 2 : 1; int rwUpdateCounts[] = testStmts[1].executeBatch(); ResultSet rewrittenRsKeys = testStmts[1].getGeneratedKeys(); for (int i = 0; i < 4; ++i) { assertEquals(expectedUpdateCount, nonRwUpdateCounts[i]); assertEquals(expectedUpdateCount, rwUpdateCounts[i]); } assertResultSetLength(nonRewrittenRsKeys, 4); assertResultSetLength(rewrittenRsKeys, 4); assertResultSetsEqual(nonRewrittenRsKeys, rewrittenRsKeys); } } finally { if (rewriteConn != null) { rewriteConn.close(); } } } public void testBug34093_nonbatch() throws Exception { Connection rewriteConn = null; try { String ddl = "(autoIncId INT NOT NULL PRIMARY KEY AUTO_INCREMENT, uniqueTextKey VARCHAR(255) UNIQUE KEY)"; String sql = "insert into testBug30493 (uniqueTextKey) values ('c') on duplicate key UPDATE autoIncId = last_insert_id( autoIncId )"; String tablePrimeSql = "INSERT INTO testBug30493 (uniqueTextKey) VALUES ('a'), ('b'), ('c'), ('d')"; try { createTable("testBug30493", ddl); } catch (SQLException sqlEx) { if (sqlEx.getMessage().indexOf("max key length") != -1) { createTable( "testBug30493", "(autoIncId INT NOT NULL PRIMARY KEY AUTO_INCREMENT, uniqueTextKey VARCHAR(180) UNIQUE KEY)"); } } stmt.executeUpdate(tablePrimeSql); Statement stmt1 = conn.createStatement(); stmt1.execute(sql, Statement.RETURN_GENERATED_KEYS); int expectedUpdateCount = versionMeetsMinimum(5, 1, 0) ? 2 : 1; assertEquals(expectedUpdateCount, stmt1.getUpdateCount()); ResultSet stmtKeys = stmt1.getGeneratedKeys(); assertResultSetLength(stmtKeys, 1); try { createTable("testBug30493", ddl); } catch (SQLException sqlEx) { if (sqlEx.getMessage().indexOf("max key length") != -1) { createTable( "testBug30493", "(autoIncId INT NOT NULL PRIMARY KEY AUTO_INCREMENT, uniqueTextKey VARCHAR(180) UNIQUE KEY)"); } } stmt.executeUpdate(tablePrimeSql); pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); pstmt.execute(); assertEquals(expectedUpdateCount, pstmt.getUpdateCount()); ResultSet pstmtKeys = pstmt.getGeneratedKeys(); assertResultSetLength(pstmtKeys, 1); assertResultSetsEqual(stmtKeys, pstmtKeys); } finally { if (rewriteConn != null) { rewriteConn.close(); } } } public void testBug34518() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; } Connection fetchConn = getConnectionWithProps("useCursorFetch=true"); Statement fetchStmt = fetchConn.createStatement(); int stmtCount = ((com.mysql.jdbc.Connection) fetchConn) .getActiveStatementCount(); fetchStmt.setFetchSize(100); this.rs = fetchStmt.executeQuery("SELECT 1"); assertEquals( ((com.mysql.jdbc.Connection) fetchConn) .getActiveStatementCount(), stmtCount + 1); this.rs.close(); assertEquals( ((com.mysql.jdbc.Connection) fetchConn) .getActiveStatementCount(), stmtCount); } public void testBug35170() throws Exception { Statement stt = null; try { stt = this.conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); stt.setFetchSize(Integer.MIN_VALUE); this.rs = stt.executeQuery("select 1"); this.rs.next(); while (!this.rs.isAfterLast()) { this.rs.getString(1); this.rs.next(); } } finally { if (stt != null) { stt.close(); } } } /* * public void testBug35307() throws Exception { createTable("testBug35307", * "(`id` int(11) unsigned NOT NULL auto_increment," + * "`field` varchar(20) NOT NULL," + "`date` datetime NOT NULL," + * "PRIMARY KEY (`id`)" + ") ENGINE=MyISAM DEFAULT CHARSET=latin1"); * * this.stmt.executeUpdate("INSERT INTO testBug35307 (field) values ('works')" * ); } */ public void testBug35666() throws Exception { Connection loggingConn = getConnectionWithProps("logSlowQueries=true"); this.pstmt = ((com.mysql.jdbc.Connection) loggingConn) .serverPrepareStatement("SELECT SLEEP(4)"); this.pstmt.execute(); } public void testDeadlockBatchBehavior() throws Exception { try { createTable("t1", "(id INTEGER, x INTEGER)", "INNODB"); createTable("t2", "(id INTEGER, x INTEGER)", "INNODB"); this.stmt.executeUpdate("INSERT INTO t1 VALUES (0, 0)"); this.conn.setAutoCommit(false); this.conn.createStatement().executeQuery( "SELECT * FROM t1 WHERE id=0 FOR UPDATE"); final Connection deadlockConn = getConnectionWithProps("includeInnodbStatusInDeadlockExceptions=true"); deadlockConn.setAutoCommit(false); final Statement deadlockStmt = deadlockConn.createStatement(); deadlockStmt.executeUpdate("INSERT INTO t2 VALUES (1, 0)"); deadlockStmt.executeQuery("SELECT * FROM t2 WHERE id=0 FOR UPDATE"); new Thread() { public void run() { try { deadlockStmt.addBatch("INSERT INTO t2 VALUES (1, 0)"); deadlockStmt.addBatch("INSERT INTO t2 VALUES (2, 0)"); deadlockStmt.addBatch("UPDATE t1 SET x=2 WHERE id=0"); deadlockStmt.executeBatch(); } catch (SQLException sqlEx) { sqlEx.printStackTrace(); try { deadlockConn.rollback(); } catch (SQLException e) { e.printStackTrace(); } } } }.run(); this.stmt.executeUpdate("INSERT INTO t1 VALUES (0, 0)"); } catch (BatchUpdateException sqlEx) { int[] updateCounts = sqlEx.getUpdateCounts(); for (int i = 0; i < updateCounts.length; i++) { System.out.println(updateCounts[i]); } } finally { this.conn.rollback(); this.conn.setAutoCommit(true); } } public void testBug39352() throws Exception { Connection affectedRowsConn = getConnectionWithProps("useAffectedRows=true"); try { createTable("bug39352", "(id INT PRIMARY KEY, data VARCHAR(100))"); assertEquals( 1, this.stmt .executeUpdate("INSERT INTO bug39352 (id,data) values (1,'a')")); int rowsAffected = this.stmt .executeUpdate("INSERT INTO bug39352 (id, data) VALUES(2, 'bb') " + "ON DUPLICATE KEY " + "UPDATE data=values(data)"); assertEquals("First UPD failed", 1, rowsAffected); rowsAffected = affectedRowsConn.createStatement().executeUpdate( "INSERT INTO bug39352 (id, data) VALUES(2, 'bbb') " + "ON DUPLICATE KEY " + "UPDATE data=values(data)"); assertEquals("2nd UPD failed", 2, rowsAffected); rowsAffected = affectedRowsConn.createStatement().executeUpdate( "INSERT INTO bug39352 (id, data) VALUES(2, 'bbb') " + "ON DUPLICATE KEY " + "UPDATE data=values(data)"); assertEquals("3rd UPD failed", 0, rowsAffected); } finally { affectedRowsConn.close(); } } public void testBug38747() throws Exception { try { this.conn.setReadOnly(true); this.pstmt = this.conn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); this.pstmt.setFetchSize(Integer.MIN_VALUE); this.rs = this.pstmt.executeQuery(); while (this.rs.next()) ; this.rs.close(); this.pstmt.close(); } finally { this.conn.setReadOnly(false); } } public void testBug39956() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; } ResultSet enginesRs = this.conn.createStatement().executeQuery( "SHOW ENGINES"); while (enginesRs.next()) { if ("YES".equalsIgnoreCase(enginesRs.getString("Support")) || "DEFAULT".equalsIgnoreCase(enginesRs .getString("Support"))) { String engineName = enginesRs.getString("Engine"); if ("CSV".equalsIgnoreCase(engineName) || "BLACKHOLE".equalsIgnoreCase(engineName) || "FEDERATED".equalsIgnoreCase(engineName) || "MRG_MYISAM".equalsIgnoreCase(engineName) || "PARTITION".equalsIgnoreCase(engineName) || "EXAMPLE".equalsIgnoreCase(engineName) || "PERFORMANCE_SCHEMA".equalsIgnoreCase(engineName) || engineName.endsWith("_SCHEMA")) { continue; // not supported } if ("ARCHIVE".equalsIgnoreCase(engineName) && !versionMeetsMinimum(5, 1, 6)) { continue; } String tableName = "testBug39956_" + engineName; Connection twoConn = getConnectionWithProps("sessionVariables=auto_increment_increment=2"); try { for (int i = 0; i < 2; i++) { createTable(tableName, "(k int primary key auto_increment, p varchar(4)) ENGINE=" + engineName); ((com.mysql.jdbc.Connection) twoConn) .setRewriteBatchedStatements(i == 1); this.pstmt = twoConn.prepareStatement("INSERT INTO " + tableName + " (p) VALUES (?)", Statement.RETURN_GENERATED_KEYS); this.pstmt.setString(1, "a"); this.pstmt.addBatch(); this.pstmt.setString(1, "b"); this.pstmt.addBatch(); this.pstmt.executeBatch(); this.rs = this.pstmt.getGeneratedKeys(); this.rs.next(); assertEquals("For engine " + engineName + ((i == 1) ? " rewritten " : " plain "), 1, this.rs.getInt(1)); this.rs.next(); assertEquals("For engine " + engineName + ((i == 1) ? " rewritten " : " plain "), 3, this.rs.getInt(1)); createTable(tableName, "(k int primary key auto_increment, p varchar(4)) ENGINE=" + engineName); Statement twoStmt = twoConn.createStatement(); for (int j = 0; j < 10; j++) { twoStmt.addBatch("INSERT INTO " + tableName + " (p) VALUES ('" + j + "')"); } twoStmt.executeBatch(); // UGH: No getGeneratedKeys() // support in JDBC spec, but we // allow it...might have to // rewrite test if/when we don't this.rs = twoStmt.getGeneratedKeys(); int key = 1; for (int j = 0; j < 10; j++) { this.rs.next(); assertEquals("For engine " + engineName + ((i == 1) ? " rewritten " : " plain "), key, this.rs.getInt(1)); key += 2; } } } finally { if (twoConn != null) { twoConn.close(); } } } } } public void testBug34185() throws Exception { this.stmt.executeQuery("SELECT 1"); try { this.stmt.getGeneratedKeys(); fail("Expected exception"); } catch (SQLException sqlEx) { assertEquals(SQLError.SQL_STATE_ILLEGAL_ARGUMENT, sqlEx.getSQLState()); } this.pstmt = this.conn.prepareStatement("SELECT 1"); try { this.pstmt.execute(); this.pstmt.getGeneratedKeys(); fail("Expected exception"); } catch (SQLException sqlEx) { assertEquals(SQLError.SQL_STATE_ILLEGAL_ARGUMENT, sqlEx.getSQLState()); } } public void testBug41161() throws Exception { createTable("testBug41161", "(a int, b int)"); Connection rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true"); try { this.pstmt = rewriteConn .prepareStatement("INSERT INTO testBug41161 (a, b) VALUES (?, ?, ?)"); this.pstmt.setInt(1, 1); this.pstmt.setInt(2, 1); try { this.pstmt.addBatch(); fail("Should have thrown an exception"); } catch (SQLException sqlEx) { assertEquals("07001", sqlEx.getSQLState()); } this.pstmt.executeBatch(); // NPE when this bug exists } finally { rewriteConn.close(); } } /** * Ensures that cases listed in Bug#41448 actually work - we don't think * there's a bug here right now */ public void testBug41448() throws Exception { createTable("testBug41448", "(pk INT PRIMARY KEY AUTO_INCREMENT, field1 VARCHAR(4))"); stmt.executeUpdate("INSERT INTO testBug41448 (field1) VALUES ('abc')", Statement.RETURN_GENERATED_KEYS); stmt.getGeneratedKeys(); stmt.executeUpdate("INSERT INTO testBug41448 (field1) VALUES ('def')", new int[] { 1 }); stmt.getGeneratedKeys(); stmt.executeUpdate("INSERT INTO testBug41448 (field1) VALUES ('ghi')", new String[] { "pk" }); stmt.getGeneratedKeys(); stmt.executeUpdate("INSERT INTO testBug41448 (field1) VALUES ('ghi')"); try { stmt.getGeneratedKeys(); fail("Expected a SQLException here"); } catch (SQLException sqlEx) { // expected } stmt.execute("INSERT INTO testBug41448 (field1) VALUES ('jkl')", Statement.RETURN_GENERATED_KEYS); stmt.getGeneratedKeys(); stmt.execute("INSERT INTO testBug41448 (field1) VALUES ('mno')", new int[] { 1 }); stmt.getGeneratedKeys(); stmt.execute("INSERT INTO testBug41448 (field1) VALUES ('pqr')", new String[] { "pk" }); stmt.getGeneratedKeys(); stmt.execute("INSERT INTO testBug41448 (field1) VALUES ('stu')"); try { stmt.getGeneratedKeys(); fail("Expected a SQLException here"); } catch (SQLException sqlEx) { // expected } this.pstmt = this.conn.prepareStatement( "INSERT INTO testBug41448 (field1) VALUES (?)", Statement.RETURN_GENERATED_KEYS); this.pstmt.setString(1, "abc"); this.pstmt.executeUpdate(); this.pstmt.getGeneratedKeys(); this.pstmt.execute(); this.pstmt.getGeneratedKeys(); this.pstmt = this.conn .prepareStatement( "INSERT INTO testBug41448 (field1) VALUES (?)", new int[] { 1 }); this.pstmt.setString(1, "abc"); this.pstmt.executeUpdate(); this.pstmt.getGeneratedKeys(); this.pstmt.execute(); this.pstmt.getGeneratedKeys(); this.pstmt = this.conn.prepareStatement( "INSERT INTO testBug41448 (field1) VALUES (?)", new String[] { "pk" }); this.pstmt.setString(1, "abc"); this.pstmt.executeUpdate(); this.pstmt.getGeneratedKeys(); this.pstmt.execute(); this.pstmt.getGeneratedKeys(); this.pstmt = this.conn .prepareStatement("INSERT INTO testBug41448 (field1) VALUES (?)"); this.pstmt.setString(1, "abc"); this.pstmt.executeUpdate(); try { this.pstmt.getGeneratedKeys(); fail("Expected a SQLException here"); } catch (SQLException sqlEx) { // expected } this.pstmt.execute(); try { this.pstmt.getGeneratedKeys(); fail("Expected a SQLException here"); } catch (SQLException sqlEx) { // expected } } public void testBug48172() throws Exception { createTable("testBatchInsert", "(a INT PRIMARY KEY AUTO_INCREMENT)"); Connection rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true,dumpQueriesOnException=true"); assertEquals( "0", getSingleIndexedValueWithQuery(rewriteConn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); this.pstmt = rewriteConn .prepareStatement("INSERT INTO testBatchInsert VALUES (?)"); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.executeBatch(); assertEquals( "1", getSingleIndexedValueWithQuery(rewriteConn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); this.pstmt = rewriteConn .prepareStatement("INSERT INTO `testBatchInsert`VALUES (?)"); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.executeBatch(); assertEquals( "2", getSingleIndexedValueWithQuery(rewriteConn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); this.pstmt = rewriteConn .prepareStatement("INSERT INTO testBatchInsert VALUES(?)"); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.executeBatch(); assertEquals( "3", getSingleIndexedValueWithQuery(rewriteConn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); this.pstmt = rewriteConn .prepareStatement("INSERT INTO testBatchInsert VALUES\n(?)"); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.setNull(1, java.sql.Types.INTEGER); this.pstmt.addBatch(); this.pstmt.executeBatch(); assertEquals( "4", getSingleIndexedValueWithQuery(rewriteConn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); } /** * Tests fix for Bug#41532 - regression in performance for batched inserts * when using ON DUPLICATE KEY UPDATE */ public void testBug41532() throws Exception { createTable( "testBug41532", "(ID" + " INTEGER, S1 VARCHAR(100), S2 VARCHAR(100), S3 VARCHAR(100), D1 DATETIME, D2 DATETIME, D3 DATETIME, N1 DECIMAL(28,6), N2 DECIMAL(28,6), N3 DECIMAL(28,6), UNIQUE KEY" + " UNIQUE_KEY_TEST_DUPLICATE (ID) )"); int numTests = 5000; Connection rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true,dumpQueriesOnException=true"); assertEquals( "0", getSingleIndexedValueWithQuery(rewriteConn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); long batchedTime = timeBatch(rewriteConn, numTests); assertEquals( "1", getSingleIndexedValueWithQuery(rewriteConn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); this.stmt.executeUpdate("TRUNCATE TABLE testBug41532"); assertEquals( "0", getSingleIndexedValueWithQuery(this.conn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); long unbatchedTime = timeBatch(this.conn, numTests); assertEquals( String.valueOf(numTests), getSingleIndexedValueWithQuery(this.conn, 2, "SHOW SESSION STATUS LIKE 'Com_insert'").toString()); assertTrue(batchedTime < unbatchedTime); rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true,useCursorFetch=true,defaultFetchSize=10000"); timeBatch(rewriteConn, numTests); } private long timeBatch(Connection c, int numberOfRows) throws SQLException { this.pstmt = c .prepareStatement("INSERT INTO testBug41532(ID, S1, S2, S3, D1," + "D2, D3, N1, N2, N3) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + " ON DUPLICATE KEY" + " UPDATE S1 = VALUES(S1), S2 = VALUES(S2), S3 = VALUES(S3), D1 = VALUES(D1), D2 =" + " VALUES(D2), D3 = VALUES(D3), N1 = N1 + VALUES(N1), N2 = N2 + VALUES(N2), N2 = N2 +" + " VALUES(N2)"); c.setAutoCommit(false); c.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); Date d1 = new Date(currentTimeMillis()); Date d2 = new Date(currentTimeMillis() + 1000000); Date d3 = new Date(currentTimeMillis() + 1250000); for (int i = 0; i < numberOfRows; i++) { this.pstmt.setObject(1, new Integer(i), Types.INTEGER); this.pstmt.setObject(2, String.valueOf(i), Types.VARCHAR); this.pstmt.setObject(3, String.valueOf(i * 0.1), Types.VARCHAR); this.pstmt.setObject(4, String.valueOf(i / 3), Types.VARCHAR); this.pstmt.setObject(5, new Timestamp(d1.getTime()), Types.TIMESTAMP); this.pstmt.setObject(6, new Timestamp(d2.getTime()), Types.TIMESTAMP); this.pstmt.setObject(7, new Timestamp(d3.getTime()), Types.TIMESTAMP); this.pstmt.setObject(8, new BigDecimal(i + 0.1), Types.DECIMAL); this.pstmt.setObject(9, new BigDecimal(i * 0.1), Types.DECIMAL); this.pstmt.setObject(10, new BigDecimal(i / 3), Types.DECIMAL); this.pstmt.addBatch(); } long startTime = currentTimeMillis(); this.pstmt.executeBatch(); c.commit(); long stopTime = currentTimeMillis(); rs = conn.createStatement().executeQuery( "SELECT COUNT(*) FROM testBug41532"); assertTrue(rs.next()); assertEquals(numberOfRows, rs.getInt(1)); return stopTime - startTime; } /** * Tests fix for Bug#44056 - Statement.getGeneratedKeys() retains result set * instances until statement is closed. */ public void testBug44056() throws Exception { createTable("testBug44056", "(pk int primary key not null auto_increment)"); Statement newStmt = this.conn.createStatement(); try { newStmt.executeUpdate("INSERT INTO testBug44056 VALUES (null)", Statement.RETURN_GENERATED_KEYS); checkOpenResultsFor44056(newStmt); this.pstmt = this.conn.prepareStatement( "INSERT INTO testBug44056 VALUES (null)", Statement.RETURN_GENERATED_KEYS); this.pstmt.executeUpdate(); checkOpenResultsFor44056(this.pstmt); this.pstmt = ((com.mysql.jdbc.Connection) this.conn) .serverPrepareStatement( "INSERT INTO testBug44056 VALUES (null)", Statement.RETURN_GENERATED_KEYS); this.pstmt.executeUpdate(); checkOpenResultsFor44056(this.pstmt); } finally { newStmt.close(); } } private void checkOpenResultsFor44056(Statement newStmt) throws SQLException { this.rs = newStmt.getGeneratedKeys(); assertEquals(1, ((com.mysql.jdbc.Statement) newStmt).getOpenResultSetCount()); this.rs.close(); assertEquals(0, ((com.mysql.jdbc.Statement) newStmt).getOpenResultSetCount()); } /** * Bug #41730 - SQL Injection when using U+00A5 and SJIS/Windows-31J */ public void testBug41730() throws Exception { try { "".getBytes("sjis"); } catch (UnsupportedEncodingException ex) { return; // test doesn't work on this platform } Connection conn2 = null; PreparedStatement pstmt2 = null; try { conn2 = getConnectionWithProps("characterEncoding=sjis"); pstmt2 = conn2.prepareStatement("select ?"); pstmt2.setString(1, "\u00A5'"); // this will throw an exception with a syntax error if it fails pstmt2.executeQuery(); } finally { try { if (pstmt2 != null) pstmt2.close(); } catch (SQLException ex) { } try { if (conn2 != null) conn2.close(); } catch (SQLException ex) { } } } public void testBug43196() throws Exception { createTable( "`bug43196`", "(`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, `a` bigint(20) unsigned NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;"); Connection conn1 = null; try { assertEquals(1, this.stmt.executeUpdate( "INSERT INTO bug43196 (a) VALUES (1)", Statement.RETURN_GENERATED_KEYS)); this.rs = this.stmt.getGeneratedKeys(); if (this.rs.next()) { Object id = this.rs.getObject(1);// use long assertEquals(Long.class, id.getClass()); } this.rs.close(); this.rs = this.stmt.executeQuery("select id from bug43196"); if (this.rs.next()) { Object id = this.rs.getObject(1);// use BigInteger assertEquals(BigInteger.class, id.getClass()); } this.rs.close(); // insert a id > Long.MAX_VALUE(9223372036854775807) assertEquals( 1, this.stmt .executeUpdate( "insert into bug43196(id,a) values(18446744073709551200,1)", Statement.RETURN_GENERATED_KEYS)); this.rs = this.stmt.getGeneratedKeys(); this.rs.first(); assertTrue("No rows returned", this.rs.isFirst()); assertEquals("18446744073709551200", this.rs.getObject(1) .toString()); } finally { if (conn1 != null) { conn1.close(); } } } /** * Bug #42253 - multiple escaped quotes cause exception from * EscapeProcessor. */ public void testBug42253() throws Exception { rs = stmt.executeQuery("select '\\'\\'','{t\\'}'"); rs.next(); assertEquals("''", rs.getString(1)); assertEquals("{t'}", rs.getString(2)); } /** * Bug #41566 - Quotes within comments not correctly ignored by escape * parser */ public void testBug41566() throws Exception { rs = stmt .executeQuery("-- this should't change the literal\n select '{1}'"); rs.next(); assertEquals("{1}", rs.getString(1)); } /* * Bug #40439 - Error rewriting batched statement if table name ends with * "values". */ public void testBug40439() throws Exception { Connection conn2 = null; try { createTable("testBug40439VALUES", "(x int)"); conn2 = getConnectionWithProps("rewriteBatchedStatements=true"); PreparedStatement ps = conn2 .prepareStatement("insert into testBug40439VALUES (x) values (?)"); ps.setInt(1, 1); ps.addBatch(); ps.setInt(1, 2); ps.addBatch(); ps.executeBatch(); } finally { if (conn2 != null) try { conn2.close(); } catch (SQLException ex) { } } } public static class Bug39426Interceptor implements StatementInterceptor { public static List<Integer> vals = new ArrayList<Integer>(); String prevSql; public void destroy() { } public boolean executeTopLevelOnly() { return false; } public void init(com.mysql.jdbc.Connection conn, Properties props) throws SQLException { } public ResultSetInternalMethods postProcess(String sql, com.mysql.jdbc.Statement interceptedStatement, ResultSetInternalMethods originalResultSet, com.mysql.jdbc.Connection connection) throws SQLException { return null; } public ResultSetInternalMethods preProcess(String sql, com.mysql.jdbc.Statement interceptedStatement, com.mysql.jdbc.Connection connection) throws SQLException { String asSql = sql; if (interceptedStatement instanceof com.mysql.jdbc.PreparedStatement) { asSql = interceptedStatement.toString(); int firstColon = asSql.indexOf(":"); asSql = asSql.substring(firstColon + 2); if (asSql.equals(prevSql)) throw new RuntimeException( "Previous statement matched current: " + sql); prevSql = asSql; ParameterBindings b = ((com.mysql.jdbc.PreparedStatement) interceptedStatement) .getParameterBindings(); vals.add(new Integer(b.getInt(1))); } return null; } } /** * Bug #39426 - executeBatch passes most recent PreparedStatement params to * StatementInterceptor */ public void testBug39426() throws Exception { Connection c = null; try { createTable("testBug39426", "(x int)"); c = getConnectionWithProps("statementInterceptors=testsuite.regression.StatementRegressionTest$Bug39426Interceptor,useServerPrepStmts=false"); PreparedStatement ps = c .prepareStatement("insert into testBug39426 values (?)"); ps.setInt(1, 1); ps.addBatch(); ps.setInt(1, 2); ps.addBatch(); ps.setInt(1, 3); ps.addBatch(); ps.executeBatch(); List<Integer> vals = Bug39426Interceptor.vals; assertEquals(new Integer(1), vals.get(0)); assertEquals(new Integer(2), vals.get(1)); assertEquals(new Integer(3), vals.get(2)); } finally { if (c != null) c.close(); } } public void testBugDupeKeySingle() throws Exception { createTable("testBugDupeKeySingle", "(field1 int not null primary key)"); Connection conn2 = null; try { conn2 = getConnectionWithProps("rewriteBatchedStatements=true"); this.pstmt = conn2 .prepareStatement("INSERT INTO testBugDupeKeySingle VALUES (?) ON DUPLICATE KEY UPDATE field1=VALUES(field1)"); this.pstmt.setInt(1, 1); this.pstmt.addBatch(); this.pstmt.executeBatch(); // this should be a syntax error this.pstmt = conn2 .prepareStatement("INSERT INTO testBugDupeKeySingle VALUES (?) ON DUPLICATE KEY UPDATE"); this.pstmt.setInt(1, 1); this.pstmt.addBatch(); try { this.pstmt.executeBatch(); } catch (SQLException sqlEx) { assertEquals(SQLError.SQL_STATE_SYNTAX_ERROR, sqlEx.getSQLState()); } this.pstmt = conn2 .prepareStatement("INSERT INTO testBugDupeKeySingle VALUES (?)"); this.pstmt.setInt(1, 2); this.pstmt.addBatch(); this.pstmt.executeBatch(); this.pstmt.setInt(1, 3); this.pstmt.setInt(1, 4); this.pstmt.executeBatch(); } finally { if (conn2 != null) { conn2.close(); } } } /** * Bug #37458 - MySQL 5.1 returns generated keys in ascending order */ public void testBug37458() throws Exception { int ids[] = { 13, 1, 8 }; String vals[] = { "c", "a", "b" }; createTable("testBug37458", "(id int not null auto_increment, val varchar(100), " + "primary key (id), unique (val))"); stmt.executeUpdate("insert into testBug37458 values (1, 'a'), (8, 'b'), (13, 'c')"); pstmt = conn.prepareStatement( "insert into testBug37458 (val) values (?) " + "on duplicate key update id = last_insert_id(id)", PreparedStatement.RETURN_GENERATED_KEYS); for (int i = 0; i < ids.length; ++i) { pstmt.setString(1, vals[i]); pstmt.addBatch(); } pstmt.executeBatch(); ResultSet keys = pstmt.getGeneratedKeys(); for (int i = 0; i < ids.length; ++i) { assertTrue(keys.next()); assertEquals(ids[i], keys.getInt(1)); } } public void testBug34555() throws Exception { if (!versionMeetsMinimum(5, 0)) { return; // no KILL QUERY prior to this } createTable("testBug34555", "(field1 int)", "INNODB"); this.stmt.executeUpdate("INSERT INTO testBug34555 VALUES (0)"); final Connection lockerConn = getConnectionWithProps(""); lockerConn.setAutoCommit(false); lockerConn.createStatement().execute( "SELECT * FROM testBug34555 WHERE field1=0 FOR UPDATE"); this.conn.setAutoCommit(false); this.pstmt = this.conn .prepareStatement("UPDATE testBug34555 SET field1=1 WHERE field1=?"); this.pstmt.setQueryTimeout(1); this.pstmt.setInt(1, 0); this.pstmt.addBatch(); this.pstmt.setInt(1, 2); this.pstmt.addBatch(); try { this.pstmt.executeBatch(); } catch (BatchUpdateException batchEx) { assertTrue(batchEx.getMessage().startsWith("Statement cancelled")); } finally { this.conn.setAutoCommit(true); lockerConn.commit(); } } public void testBug46788() throws Exception { createTable("testBug46788", "(modified varchar(32), id varchar(32))"); Connection rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true"); this.pstmt = rewriteConn .prepareStatement("insert into testBug46788 (modified,id) values (?,?) ON DUPLICATE KEY UPDATE modified=?"); this.pstmt.setString(1, "theID"); this.pstmt.setString(2, "Hello_world_"); this.pstmt.setString(3, "Hello_world_"); for (int i = 0; i < 10; i++) { this.pstmt.addBatch(); } this.pstmt.executeBatch(); } public void testBug31193() throws Exception { createTable("bug31193", "(sometime datetime, junk text)"); Connection fetchConn = getConnectionWithProps("useCursorFetch=true"); Statement fetchStmt = fetchConn.createStatement(); fetchStmt.setFetchSize(10000); assertEquals( 1, fetchStmt .executeUpdate("INSERT INTO bug31193 (sometime) values ('2007-01-01 12:34:56.7')")); this.rs = fetchStmt.executeQuery("SELECT * FROM bug31193"); this.rs.next(); String badDatetime = this.rs.getString("sometime"); this.rs = fetchStmt.executeQuery("SELECT sometime FROM bug31193"); this.rs.next(); String goodDatetime = this.rs.getString("sometime"); assertEquals(goodDatetime, badDatetime); } public void testBug51666() throws Exception { Connection testConn = getConnectionWithProps("statementInterceptors=" + IncrementStatementCountInterceptor.class.getName()); createTable("testStatementInterceptorCount", "(field1 int)"); this.stmt .executeUpdate("INSERT INTO testStatementInterceptorCount VALUES (0)"); ResultSet testRs = testConn.createStatement().executeQuery( "SHOW SESSION STATUS LIKE 'Com_select'"); testRs.next(); int s = testRs.getInt(2); testConn.createStatement().executeQuery("SELECT 1"); testRs = testConn.createStatement().executeQuery( "SHOW SESSION STATUS LIKE 'Com_select'"); testRs.next(); assertEquals(s + 1, testRs.getInt(2)); } public void testBug51776() throws Exception { Properties props = new Properties(); NonRegisteringDriver d = new NonRegisteringDriver(); this.copyBasePropertiesIntoProps(props, d); props.setProperty("socketFactory", "testsuite.UnreliableSocketFactory"); Properties parsed = d.parseURL(BaseTestCase.dbUrl, props); String db = parsed .getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY); String port = parsed .getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY); String host = getPortFreeHostname(props, d); UnreliableSocketFactory.flushAllHostLists(); UnreliableSocketFactory.mapHost("first", host); props.remove(NonRegisteringDriver.HOST_PROPERTY_KEY); Connection testConn = getConnectionWithProps("jdbc:mysql://first:" + port + "/" + db, props); testConn.setAutoCommit(false); testConn.createStatement().execute("SELECT 1"); UnreliableSocketFactory.downHost("first"); try { testConn.rollback(); fail("Should receive SQLException on rollback()."); } catch (SQLException e) { } } public static class IncrementStatementCountInterceptor implements StatementInterceptorV2 { public void destroy() { } public boolean executeTopLevelOnly() { return false; } public void init(com.mysql.jdbc.Connection conn, Properties props) throws SQLException { } public ResultSetInternalMethods postProcess(String sql, com.mysql.jdbc.Statement interceptedStatement, ResultSetInternalMethods originalResultSet, com.mysql.jdbc.Connection connection, int warningCount, boolean noIndexUsed, boolean noGoodIndexUsed, SQLException statementException) throws SQLException { return null; } public ResultSetInternalMethods preProcess(String sql, com.mysql.jdbc.Statement interceptedStatement, com.mysql.jdbc.Connection conn) throws SQLException { java.sql.Statement test = conn.createStatement(); if (sql.equals("SELECT 1")) { return (ResultSetInternalMethods) test .executeQuery("/* execute this, not the original */ SELECT 1"); } return null; } } public void testReversalOfScanFlags() throws Exception { createTable("testReversalOfScanFlags", "(field1 int)"); this.stmt .executeUpdate("INSERT INTO testReversalOfScanFlags VALUES (1),(2),(3)"); Connection scanningConn = getConnectionWithProps("statementInterceptors=" + ScanDetectingInterceptor.class.getName()); try { ScanDetectingInterceptor.watchForScans = true; scanningConn.createStatement().executeQuery( "SELECT field1 FROM testReversalOfScanFlags"); assertTrue(ScanDetectingInterceptor.hasSeenScan); assertFalse(ScanDetectingInterceptor.hasSeenBadIndex); } finally { scanningConn.close(); } } public static class ScanDetectingInterceptor implements StatementInterceptorV2 { static boolean watchForScans = false; static boolean hasSeenScan = false; static boolean hasSeenBadIndex = false; public void destroy() { } public boolean executeTopLevelOnly() { return false; } public void init(com.mysql.jdbc.Connection conn, Properties props) throws SQLException { } public ResultSetInternalMethods postProcess(String sql, com.mysql.jdbc.Statement interceptedStatement, ResultSetInternalMethods originalResultSet, com.mysql.jdbc.Connection connection, int warningCount, boolean noIndexUsed, boolean noGoodIndexUsed, SQLException statementException) throws SQLException { if (watchForScans) { if (noIndexUsed) { hasSeenScan = true; } if (noGoodIndexUsed) { hasSeenBadIndex = true; } } return null; } public ResultSetInternalMethods preProcess(String sql, com.mysql.jdbc.Statement interceptedStatement, com.mysql.jdbc.Connection connection) throws SQLException { return null; } } /** * Tests fix for Bug#51704, rewritten batched statements don't honor escape * processing flag of Statement that they are created for */ public void testBug51704() throws Exception { createTable("testBug51704", "(field1 TIMESTAMP)"); Connection rewriteConn = getConnectionWithProps("rewriteBatchedStatements=true"); Statement rewriteStmt = rewriteConn.createStatement(); try { rewriteStmt.setEscapeProcessing(false); for (int i = 0; i < 20; i++) { rewriteStmt .addBatch("INSERT INTO testBug51704 VALUES ({tsp '2002-11-12 10:00:00'})"); } rewriteStmt.executeBatch(); // this should pass, because mysqld // doesn't validate any escape // sequences, // it just strips them, where our escape // processor validates them Statement batchStmt = conn.createStatement(); batchStmt.setEscapeProcessing(false); batchStmt .addBatch("INSERT INTO testBug51704 VALUES ({tsp '2002-11-12 10:00:00'})"); batchStmt.executeBatch(); // same here } finally { rewriteConn.close(); } } public void testBug54175() throws Exception { if (!versionMeetsMinimum(5, 5)) { return; } Connection utf8conn = getConnectionWithProps("characterEncoding=utf8"); createTable("testBug54175", "(a VARCHAR(10)) CHARACTER SET utf8mb4"); stmt.execute("INSERT INTO testBug54175 VALUES(0xF0AFA6B2)"); rs = utf8conn.createStatement().executeQuery( "SELECT * FROM testBug54175"); assertTrue(rs.next()); assertEquals(55422, rs.getString(1).charAt(0)); } /** * Tests fix for Bug#58728, NPE in com.mysql.jdbc.jdbc2.optional.StatementWrappe.getResultSet() * ((com.mysql.jdbc.ResultSetInternalMethods) rs).setWrapperStatement(this); * when rs is null */ public void testBug58728() throws Exception { createTable("testbug58728", "(Id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, txt VARCHAR(50))","InnoDB"); this.stmt.executeUpdate("INSERT INTO testbug58728 VALUES (NULL, 'Text 1'), (NULL, 'Text 2')"); MysqlConnectionPoolDataSource pds = new MysqlConnectionPoolDataSource(); pds.setUrl(dbUrl); Statement stmt1 = pds.getPooledConnection().getConnection().createStatement(); stmt1.executeUpdate("UPDATE testbug58728 SET txt = 'New text' WHERE Id > 0"); ResultSet rs1 = stmt1.getResultSet(); stmt1.close(); if (rs1 != null) { rs1.close(); } } public void testBug61501() throws Exception { createTable("testBug61501", "(id int)"); stmt.executeUpdate("INSERT INTO testBug61501 VALUES (1)"); String sql = "SELECT id FROM testBug61501 where id=1"; pstmt = conn.prepareStatement(sql); pstmt.executeQuery(); pstmt.cancel(); pstmt.close(); pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); stmt.cancel(); stmt.executeQuery(sql); stmt.cancel(); stmt.execute(sql); pstmt = ((com.mysql.jdbc.Connection) conn).serverPrepareStatement(sql); pstmt.execute(); pstmt.cancel(); pstmt.execute(); sql = "INSERT INTO testBug61501 VALUES (2)"; pstmt = conn.prepareStatement(sql); pstmt.execute(); assertEquals(1, pstmt.getUpdateCount()); pstmt.cancel(); pstmt.close(); pstmt = conn.prepareStatement(sql); assertEquals(1, pstmt.executeUpdate()); stmt.cancel(); assertEquals(1, stmt.executeUpdate(sql)); stmt.cancel(); stmt.execute(sql); assertEquals(1, stmt.getUpdateCount()); pstmt = ((com.mysql.jdbc.Connection) conn).serverPrepareStatement(sql); pstmt.execute(); assertEquals(1, pstmt.getUpdateCount()); pstmt.cancel(); pstmt.close(); pstmt = ((com.mysql.jdbc.Connection) conn).serverPrepareStatement(sql); assertEquals(1, pstmt.executeUpdate()); pstmt.cancel(); pstmt.addBatch(); pstmt.addBatch(); pstmt.addBatch(); int[] counts = pstmt.executeBatch(); for (int i = 0; i < counts.length; i++) { assertEquals(1, counts[i]); } pstmt = conn.prepareStatement(sql); pstmt.cancel(); pstmt.addBatch(); pstmt.addBatch(); pstmt.addBatch(); counts = pstmt.executeBatch(); for (int i = 0; i < counts.length; i++) { assertEquals(1, counts[i]); } stmt.cancel(); stmt.addBatch(sql); stmt.addBatch(sql); stmt.addBatch(sql); counts = stmt.executeBatch(); for (int i = 0; i < counts.length; i++) { assertEquals(1, counts[i]); } } public void testbug61866() throws Exception { createProcedure("WARN_PROCEDURE", "() BEGIN DECLARE l_done INT; SELECT 1 INTO l_done FROM DUAL WHERE 1=2; END"); this.pstmt = this.conn.prepareCall("{CALL WARN_PROCEDURE()}"); this.pstmt.execute(); assertTrue("No warning when expected", this.pstmt.getWarnings().toString().contentEquals("java.sql.SQLWarning: No data - zero rows fetched, selected, or processed")); this.pstmt.clearWarnings(); assertNull("Warning when not expected", this.pstmt.getWarnings()); } public void testbug12565726() throws Exception { // Not putting the space between VALUES() and ON DUPLICATE KEY UPDATE // causes C/J a) enter rewriting the query altrhough it has ON UPDATE // and b) to generate the wrong query with multiple ON DUPLICATE KEY Properties props = new Properties(); props.put("rewriteBatchedStatements","true"); props.put("useServerPrepStmts","false"); props.put("enablePacketDebug","true"); this.conn = getConnectionWithProps(props); this.stmt = this.conn.createStatement(); try { createTable("testbug12565726", "(id int primary key, txt1 varchar(32))"); this.stmt.executeUpdate("INSERT INTO testbug12565726 " + "(id, txt1) VALUES (1, 'something')"); this.pstmt = this.conn.prepareStatement("INSERT INTO " + "testbug12565726 (id, txt1) " + "VALUES (?, ?)ON DUPLICATE KEY UPDATE " + "id=LAST_INSERT_ID(id)+10"); this.pstmt.setInt(1, 1); this.pstmt.setString(2, "something else"); this.pstmt.addBatch(); this.pstmt.setInt(1, 2); this.pstmt.setString(2, "hope it is not error again!"); this.pstmt.addBatch(); this.pstmt.executeBatch(); } finally { } } public void testBug36478() throws Exception { createTable("testBug36478", "(`limit` varchar(255) not null primary key, id_limit INT, limit1 INT, maxlimit2 INT)"); this.stmt.execute("INSERT INTO testBug36478 VALUES ('bahblah',1,1,1)"); this.stmt.execute("INSERT INTO testBug36478 VALUES ('bahblah2',2,2,2)"); this.pstmt = this.conn.prepareStatement("select 1 FROM testBug36478"); this.pstmt.setMaxRows(1); this.rs = this.pstmt.executeQuery(); this.rs.first(); assertTrue(this.rs.isFirst()); assertTrue(this.rs.isLast()); this.pstmt = this.conn.prepareStatement("select `limit`, id_limit, limit1, maxlimit2 FROM testBug36478"); this.pstmt.setMaxRows(0); this.rs = this.pstmt.executeQuery(); this.rs.first(); assertTrue(this.rs.isFirst()); assertFalse(this.rs.isLast()); //SSPS Connection _conn = null; PreparedStatement s = null; try { Properties props = new Properties(); props.setProperty("useServerPrepStmts", "true"); _conn = getConnectionWithProps(props); s = _conn.prepareStatement("select 1 FROM testBug36478"); s.setMaxRows(1); ResultSet _rs = s.executeQuery(); _rs.first(); assertTrue(_rs.isFirst()); assertTrue(_rs.isLast()); s = _conn.prepareStatement("select `limit`, id_limit, limit1, maxlimit2 FROM testBug36478"); s.setMaxRows(0); _rs = s.executeQuery(); _rs.first(); assertTrue(_rs.isFirst()); assertFalse(_rs.isLast()); } finally { if (s != null) { s.close(); } if (_conn != null) { _conn.close(); } } } /** * Tests fix for BUG#40279 - Timestamp values get truncated when passed as prepared statement parameters * (and duplicate BUG#60584 - prepared statements truncate milliseconds) * * [13 Sep 2012 21:06] Mark Matthews * This was fixed with http://bazaar.launchpad.net/~mysql/connectorj/5.1/revision/1107 in 2011, * it supports MySQL-5.6.4 or later. * * But that fix did not cover useLegacyDatetimeCode=true case. * * @throws Exception */ public void testBug40279() throws Exception { if (!versionMeetsMinimum(5, 6, 4)) { return; } createTable("testBug40279", "(f1 int, f2 timestamp(6))"); Timestamp ts = new Timestamp(1300791248001L); Connection ps_conn_legacy = null; Connection ps_conn_nolegacy = null; Connection ssps_conn_legacy = null; Connection ssps_conn_nolegacy = null; try { Properties props = new Properties(); props.setProperty("serverTimezone", "UTC"); props.setProperty("useLegacyDatetimeCode", "true"); props.setProperty("useServerPrepStmts", "false"); ps_conn_legacy = getConnectionWithProps(props); props.setProperty("useLegacyDatetimeCode", "false"); ps_conn_nolegacy = getConnectionWithProps(props); props.setProperty("useLegacyDatetimeCode", "true"); props.setProperty("useServerPrepStmts", "true"); ssps_conn_legacy = getConnectionWithProps(props); props.setProperty("useLegacyDatetimeCode", "false"); ssps_conn_nolegacy = getConnectionWithProps(props); this.pstmt = ps_conn_legacy.prepareStatement("INSERT INTO testBug40279(f1, f2) VALUES (?, ?)"); this.pstmt.setInt(1, 1); this.pstmt.setTimestamp(2, ts); this.pstmt.execute(); this.pstmt.close(); this.pstmt = ps_conn_nolegacy.prepareStatement("INSERT INTO testBug40279(f1, f2) VALUES (?, ?)"); this.pstmt.setInt(1, 2); this.pstmt.setTimestamp(2, ts); this.pstmt.execute(); this.pstmt.close(); this.pstmt = ssps_conn_legacy.prepareStatement("INSERT INTO testBug40279(f1, f2) VALUES (?, ?)"); this.pstmt.setInt(1, 3); this.pstmt.setTimestamp(2, ts); this.pstmt.execute(); this.pstmt.close(); this.pstmt = ssps_conn_nolegacy.prepareStatement("INSERT INTO testBug40279(f1, f2) VALUES (?, ?)"); this.pstmt.setInt(1, 4); this.pstmt.setTimestamp(2, ts); this.pstmt.execute(); this.pstmt.close(); this.rs = this.stmt.executeQuery("SELECT f2 FROM testBug40279"); while (this.rs.next()) { assertEquals(ts.getNanos(), this.rs.getTimestamp("f2").getNanos()); } } finally { if (ps_conn_legacy != null) { ps_conn_legacy.close(); } if (ps_conn_nolegacy != null) { ps_conn_nolegacy.close(); } if (ssps_conn_legacy != null) { ssps_conn_legacy.close(); } if (ssps_conn_nolegacy != null) { ssps_conn_nolegacy.close(); } } } /** * Tests fix for BUG#35653 - executeQuery() in Statement.java let "TRUNCATE" queries being executed. * "RENAME" is also filtered now. * * @throws Exception */ public void testBug35653() throws Exception { createTable("testBug35653", "(f1 int)"); try { this.stmt.executeQuery("TRUNCATE testBug35653"); fail("executeQuery() shouldn't allow TRUNCATE"); } catch (SQLException e) { assertTrue(SQLError.SQL_STATE_ILLEGAL_ARGUMENT == e.getSQLState()); } try { this.stmt.executeQuery("RENAME TABLE testBug35653 TO testBug35653_new"); fail("executeQuery() shouldn't allow RENAME"); } catch (SQLException e) { assertTrue(SQLError.SQL_STATE_ILLEGAL_ARGUMENT == e.getSQLState()); } finally { dropTable("testBug35653_new"); } } /** * Tests fix for BUG#64805 - StatementImpl$CancelTask occasionally throws NullPointerExceptions. * * @throws Exception */ public void testBug64805() throws Exception { try { this.stmt.setQueryTimeout(5); this.stmt.executeQuery("select sleep(5)"); } catch (NullPointerException e) { e.printStackTrace(); fail(); } catch (Exception e) { if (e instanceof MySQLTimeoutException) { // expected behavior in slow environment } else { throw e; } } } }