From: Date: March 7 2006 9:01pm Subject: Connector/J commit: r5024 - in branches: branch_3_1/connector-j branch_3_1/connector-j/src/com/mysql/jdbc branch_3_1/connector-j/src/testsuite/regression branch_5_0/connector-j branch_5_0/connector-j/src/com/mysql/jdbc branch_5_0/connector-j/src/testsuite/regression branch_5_1/connector-j branch_5_1/connector-j/src/com/mysql/jdbc branch_5_1/connector-j/src/testsuite/regression List-Archive: http://lists.mysql.com/commits/3555 X-Bug: 18041 Message-Id: <200603072001.k27K1BQV020464@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: branches/branch_3_1/connector-j/CHANGES branches/branch_3_1/connector-j/src/com/mysql/jdbc/MysqlIO.java branches/branch_3_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java branches/branch_3_1/connector-j/src/testsuite/regression/StatementRegressionTest.java branches/branch_5_0/connector-j/CHANGES branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java branches/branch_5_0/connector-j/src/testsuite/regression/StatementRegressionTest.java branches/branch_5_1/connector-j/CHANGES branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java branches/branch_5_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java branches/branch_5_1/connector-j/src/testsuite/regression/StatementRegressionTest.java Log: Fixed BUG#18041 - Server-side prepared statements don't cause truncation exceptions to be thrown when truncation happens. Modified: branches/branch_3_1/connector-j/CHANGES =================================================================== --- branches/branch_3_1/connector-j/CHANGES 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_3_1/connector-j/CHANGES 2006-03-07 20:01:06 UTC (rev 5024) @@ -57,6 +57,9 @@ - Fixed BUG#15570 - ReplicationConnection incorrectly copies state, doesn't transfer connection context correctly when transitioning between the same read-only states. + + - Fixed BUG#18041 - Server-side prepared statements don't cause + truncation exceptions to be thrown when truncation happens. 11-30-05 - Version 3.1.12 Modified: branches/branch_3_1/connector-j/src/com/mysql/jdbc/MysqlIO.java =================================================================== --- branches/branch_3_1/connector-j/src/com/mysql/jdbc/MysqlIO.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_3_1/connector-j/src/com/mysql/jdbc/MysqlIO.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -1408,7 +1408,8 @@ boolean moreRowSetsExist = checkForMoreResults & serverHasMoreResults; while (moreRowSetsExist) { - Buffer fieldPacket = readPacket(); + Buffer fieldPacket = checkErrorPacket(); + fieldPacket.setPosition(0); if ((fieldPacket.readByte(0) == 0) && (fieldPacket.readByte(1) == 0) && @@ -2627,6 +2628,24 @@ reclaimLargeSharedSendPacket(); } } + + void enableMultiQueries() throws SQLException { + Buffer buf = getSharedSendPacket(); + + buf.clear(); + buf.writeByte((byte)MysqlDefs.COM_SET_OPTION); + buf.writeInt(0); + sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null); + } + + void disableMultiQueries() throws SQLException { + Buffer buf = getSharedSendPacket(); + + buf.clear(); + buf.writeByte((byte)MysqlDefs.COM_SET_OPTION); + buf.writeInt(1); + sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null); + } private final void send(Buffer packet, int packetLen) throws SQLException { @@ -3404,7 +3423,11 @@ } } - private void scanForAndThrowDataTruncation() throws SQLException { + boolean hadWarnings() { + return this.hadWarnings; + } + + void scanForAndThrowDataTruncation() throws SQLException { if ((this.streamingData == null) && versionMeetsMinimum(4, 1, 0) && this.connection.getJdbcCompliantTruncation()) { SQLError.convertShowWarningsToSQLWarnings(this.connection, Modified: branches/branch_3_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java =================================================================== --- branches/branch_3_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_3_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -1193,6 +1193,10 @@ } } + if (mysql.hadWarnings()) { + mysql.scanForAndThrowDataTruncation(); + } + return rs; } } Modified: branches/branch_3_1/connector-j/src/testsuite/regression/StatementRegressionTest.java =================================================================== --- branches/branch_3_1/connector-j/src/testsuite/regression/StatementRegressionTest.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_3_1/connector-j/src/testsuite/regression/StatementRegressionTest.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -791,6 +791,47 @@ } } + /** + * 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 (stmt != null) { + stmt.close(); + } + + if (truncConn != null) { + truncConn.close(); + } + } + } + } + private void testStreamsForBug15024(boolean shouldBeClosedStream, boolean shouldBeClosedReader) throws SQLException { IsClosedInputStream bIn = new IsClosedInputStream(new byte[4]); Modified: branches/branch_5_0/connector-j/CHANGES =================================================================== --- branches/branch_5_0/connector-j/CHANGES 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_0/connector-j/CHANGES 2006-03-07 20:01:06 UTC (rev 5024) @@ -160,6 +160,9 @@ - Fixed BUG#15570 - ReplicationConnection incorrectly copies state, doesn't transfer connection context correctly when transitioning between the same read-only states. + + - Fixed BUG#18041 - Server-side prepared statements don't cause + truncation exceptions to be thrown when truncation happens. 11-30-05 - Version 3.1.12 Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -2981,7 +2981,11 @@ } } - private void scanForAndThrowDataTruncation() throws SQLException { + boolean hadWarnings() { + return this.hadWarnings; + } + + void scanForAndThrowDataTruncation() throws SQLException { if ((this.streamingData == null) && versionMeetsMinimum(4, 1, 0) && this.connection.getJdbcCompliantTruncation()) { SQLError.convertShowWarningsToSQLWarnings(this.connection, Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -1011,7 +1011,7 @@ if (this.parameterBindings[i].isLongData) { if (firstFound && boundTimeToCheck != this.parameterBindings[i].boundBeforeExecutionNum) { - throw SQLError.createSQLException(Messages + throw new SQLException(Messages .getString("ServerPreparedStatement.11") //$NON-NLS-1$ + Messages.getString("ServerPreparedStatement.12"), //$NON-NLS-1$ SQLError.SQL_STATE_DRIVER_NOT_CAPABLE); @@ -1028,11 +1028,10 @@ serverResetStatement(); } - // Check bindings for (int i = 0; i < this.parameterCount; i++) { if (!this.parameterBindings[i].isSet) { - throw SQLError.createSQLException(Messages + throw new SQLException(Messages .getString("ServerPreparedStatement.13") + (i + 1) //$NON-NLS-1$ + Messages.getString("ServerPreparedStatement.14"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ @@ -1063,28 +1062,9 @@ packet.writeByte((byte) MysqlDefs.COM_EXECUTE); packet.writeLong(this.serverStatementId); - boolean usingCursor = false; - if (this.connection.versionMeetsMinimum(4, 1, 2)) { - // we only create cursor-backed result sets if - // a) The query is a SELECT - // b) The server supports it - // c) We know it is forward-only (note this doesn't - // preclude updatable result sets) - // d) The user has set a fetch size - if (this.resultFields != null && - this.connection.isCursorFetchEnabled() - && getResultSetType() == ResultSet.TYPE_FORWARD_ONLY - && getResultSetConcurrency() == ResultSet.CONCUR_READ_ONLY - && getFetchSize() > 0) { - packet.writeByte(MysqlDefs.OPEN_CURSOR_FLAG); - usingCursor = true; - } else { - packet.writeByte((byte) 0); // placeholder for flags - } - - packet.writeLong(1); // placeholder for parameter - // iterations + packet.writeByte((byte) 0); // placeholder for flags + packet.writeLong(1); // placeholder for parameter iterations } /* Reserve place for null-marker bytes */ @@ -1144,104 +1124,83 @@ begin = System.currentTimeMillis(); } - this.wasCancelled = false; + Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE, + null, packet, false, null); + - CancelThread timeoutThread = null; - try { - if (this.timeout != 0 - && this.connection.versionMeetsMinimum(5, 0, 0) - && usingCursor /* FIXME: Not supported currently */) { - timeoutThread = new CancelThread(this.timeout); - new Thread(timeoutThread).start(); - } - - Buffer resultPacket = mysql.sendCommand(MysqlDefs.COM_EXECUTE, - null, packet, false, null); - - if (timeoutThread != null) { - timeoutThread.dontCancel(); - timeoutThread = null; - } - - if (this.wasCancelled) { - this.wasCancelled = false; - throw new MySQLTimeoutException(); - } + this.connection.incrementNumberOfPreparedExecutes(); + + if (this.connection.getProfileSql()) { + this.eventSink = ProfileEventSink.getInstance(this.connection); + + this.eventSink.consumeEvent(new ProfilerEvent( + ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$ + this.connection.getId(), this.statementId, -1, System + .currentTimeMillis(), (int) (System + .currentTimeMillis() - begin), null, + new Throwable(), truncateQueryToLog(asSql(true)))); + } + + com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this, + maxRowsToRetrieve, this.resultSetType, + this.resultSetConcurrency, createStreamingResultSet, + this.currentCatalog, resultPacket, true, this.fieldCount, + true); + - this.connection.incrementNumberOfPreparedExecutes(); - - if (this.connection.getProfileSql()) { - this.eventSink = ProfileEventSink.getInstance(this.connection); - - this.eventSink.consumeEvent(new ProfilerEvent( - ProfilerEvent.TYPE_EXECUTE, "", this.currentCatalog, //$NON-NLS-1$ - this.connectionId, this.statementId, -1, System - .currentTimeMillis(), (int) (System - .currentTimeMillis() - begin), null, - new Throwable(), truncateQueryToLog(asSql(true)))); - } - - com.mysql.jdbc.ResultSet rs = mysql.readAllResults(this, - maxRowsToRetrieve, this.resultSetType, - this.resultSetConcurrency, createStreamingResultSet, - this.currentCatalog, resultPacket, true, this.fieldCount, - true); - - - if (!createStreamingResultSet && - this.serverNeedsResetBeforeEachExecution) { - serverResetStatement(); // clear any long data... - } - - this.sendTypesToServer = false; - this.results = rs; - + if (!createStreamingResultSet && + this.serverNeedsResetBeforeEachExecution) { + serverResetStatement(); // clear any long data... + } + + this.sendTypesToServer = false; + this.results = rs; + + if (this.connection.getLogSlowQueries() + || this.connection.getGatherPerformanceMetrics()) { + long elapsedTime = System.currentTimeMillis() - begin; + if (this.connection.getLogSlowQueries() - || this.connection.getGatherPerformanceMetrics()) { - long elapsedTime = System.currentTimeMillis() - begin; - - if (this.connection.getLogSlowQueries() - && (elapsedTime >= this.connection - .getSlowQueryThresholdMillis())) { - StringBuffer mesgBuf = new StringBuffer( - 48 + this.originalSql.length()); - mesgBuf.append(Messages - .getString("ServerPreparedStatement.15")); //$NON-NLS-1$ - mesgBuf.append(this.connection - .getSlowQueryThresholdMillis()); - mesgBuf.append(Messages - .getString("ServerPreparedStatement.15a")); //$NON-NLS-1$ - mesgBuf.append(elapsedTime); - mesgBuf.append(Messages - .getString("ServerPreparedStatement.16")); //$NON-NLS-1$ - - mesgBuf.append("as prepared: "); - mesgBuf.append(this.originalSql); - mesgBuf.append("\n\n with parameters bound:\n\n"); - mesgBuf.append(asSql(true)); - - this.connection.getLog().logWarn(mesgBuf.toString()); - - if (this.connection.getExplainSlowQueries()) { - String queryAsString = asSql(true); - - mysql.explainSlowQuery(queryAsString.getBytes(), - queryAsString); - } + && (elapsedTime >= this.connection + .getSlowQueryThresholdMillis())) { + StringBuffer mesgBuf = new StringBuffer( + 48 + this.originalSql.length()); + mesgBuf.append(Messages + .getString("ServerPreparedStatement.15")); //$NON-NLS-1$ + mesgBuf.append(this.connection + .getSlowQueryThresholdMillis()); + mesgBuf.append(Messages + .getString("ServerPreparedStatement.15a")); //$NON-NLS-1$ + mesgBuf.append(elapsedTime); + mesgBuf.append(Messages + .getString("ServerPreparedStatement.16")); //$NON-NLS-1$ + + mesgBuf.append("as prepared: "); + mesgBuf.append(this.originalSql); + mesgBuf.append("\n\n with parameters bound:\n\n"); + mesgBuf.append(asSql(true)); + + this.connection.getLog().logWarn(mesgBuf.toString()); + + if (this.connection.getExplainSlowQueries()) { + String queryAsString = asSql(true); + + mysql.explainSlowQuery(queryAsString.getBytes(), + queryAsString); } - - if (this.connection.getGatherPerformanceMetrics()) { - this.connection.registerQueryExecutionTime(elapsedTime); - } } - - return rs; - } finally { - if (timeoutThread != null) { - timeoutThread.dontCancel(); + + if (this.connection.getGatherPerformanceMetrics()) { + this.connection.registerQueryExecutionTime(elapsedTime); } } + + if (mysql.hadWarnings()) { + mysql.scanForAndThrowDataTruncation(); + } + + return rs; } } Modified: branches/branch_5_0/connector-j/src/testsuite/regression/StatementRegressionTest.java =================================================================== --- branches/branch_5_0/connector-j/src/testsuite/regression/StatementRegressionTest.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_0/connector-j/src/testsuite/regression/StatementRegressionTest.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -3038,4 +3038,45 @@ } } + /** + * 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 (stmt != null) { + stmt.close(); + } + + if (truncConn != null) { + truncConn.close(); + } + } + } + } + } Modified: branches/branch_5_1/connector-j/CHANGES =================================================================== --- branches/branch_5_1/connector-j/CHANGES 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_1/connector-j/CHANGES 2006-03-07 20:01:06 UTC (rev 5024) @@ -162,6 +162,9 @@ - Fixed BUG#15570 - ReplicationConnection incorrectly copies state, doesn't transfer connection context correctly when transitioning between the same read-only states. + + - Fixed BUG#18041 - Server-side prepared statements don't cause + truncation exceptions to be thrown when truncation happens. 11-30-05 - Version 3.1.12 Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java =================================================================== --- branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -2336,7 +2336,11 @@ } - private void scanForAndThrowDataTruncation() throws SQLException { + boolean hadWarnings() { + return this.hadWarnings; + } + + void scanForAndThrowDataTruncation() throws SQLException { if ((this.streamingData == null) && versionMeetsMinimum(4, 1, 0) && this.connection.getJdbcCompliantTruncation()) { SQLError.convertShowWarningsToSQLWarnings(this.connection, Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java =================================================================== --- branches/branch_5_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/ServerPreparedStatement.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -1213,6 +1213,10 @@ } } + if (mysql.hadWarnings()) { + mysql.scanForAndThrowDataTruncation(); + } + return rs; } finally { if (timeoutThread != null) { Modified: branches/branch_5_1/connector-j/src/testsuite/regression/StatementRegressionTest.java =================================================================== --- branches/branch_5_1/connector-j/src/testsuite/regression/StatementRegressionTest.java 2006-03-07 01:02:10 UTC (rev 5023) +++ branches/branch_5_1/connector-j/src/testsuite/regression/StatementRegressionTest.java 2006-03-07 20:01:06 UTC (rev 5024) @@ -3038,4 +3038,45 @@ } } + /** + * 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 (stmt != null) { + stmt.close(); + } + + if (truncConn != null) { + truncConn.close(); + } + } + } + } + }