From: Date: March 23 2007 6:36pm Subject: Connector/J commit: r6367 - branches/branch_5_0/connector-j branches/branch_5_0/connector-j/src/com/mysql/jdbc branches/branch_5_0/connector-j/src/testsuite/regression trunk/connector-j trunk/connector-j/src/com/mysql/jdbc trunk/connector-j/src/testsuite/regression List-Archive: http://lists.mysql.com/commits/22813 X-Bug: 27400 Message-Id: <200703231736.l2NHa9HO008001@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: branches/branch_5_0/connector-j/CHANGES branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java branches/branch_5_0/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java trunk/connector-j/CHANGES trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java trunk/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java Log: Fixed BUG#27400 - CALL /* ... */ some_proc() doesn't work. As a side effect of this fix, you can now use /* */ and # comments when preparing statements using client-side prepared statement emulation. If the comments happen to contain parameter markers '?', they will be treated as belonging to the comment (i.e. not recognized) rather than being a parameter of the statement. Note that the statement when sent to the server will contain the comments as-is, they're not stripped during the process of preparing the PreparedStatement or CallableStatement. Modified: branches/branch_5_0/connector-j/CHANGES =================================================================== --- branches/branch_5_0/connector-j/CHANGES 2007-03-23 03:54:54 UTC (rev 6366) +++ branches/branch_5_0/connector-j/CHANGES 2007-03-23 17:36:06 UTC (rev 6367) @@ -48,7 +48,19 @@ hadn't been cancelled by the driver. High-load environments might want to consider disabling this functionality. (this configuration property is part of the "maxPerformance" configuration bundle). - + + - Fixed BUG#27400 - CALL /* ... */ some_proc() doesn't work. As a side effect + of this fix, you can now use /* */ and # comments when preparing statements using + client-side prepared statement emulation. + + If the comments happen to contain parameter markers '?', they will be treated + as belonging to the comment (i.e. not recognized) rather than being a parameter + of the statement. + + Note that the statement when sent to the server will contain the comments + as-is, they're not stripped during the process of preparing the PreparedStatement + or CallableStatement. + 03-01-07 - Version 5.0.5 - Fixed BUG#23645 - Some collations/character sets reported as "unknown" Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java 2007-03-23 03:54:54 UTC (rev 6366) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java 2007-03-23 17:36:06 UTC (rev 6367) @@ -823,13 +823,16 @@ } private String extractProcedureName() throws SQLException { + String sanitizedSql = StringUtils.stripComments(this.originalSql, + "`\"'", "`\"'", true, false, true, true); + // TODO: Do this with less memory allocation - int endCallIndex = StringUtils.indexOfIgnoreCase(this.originalSql, + int endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql, "CALL "); //$NON-NLS-1$ int offset = 5; if (endCallIndex == -1) { - endCallIndex = StringUtils.indexOfIgnoreCase(this.originalSql, + endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql, "SELECT "); offset = 7; } @@ -837,7 +840,7 @@ if (endCallIndex != -1) { StringBuffer nameBuf = new StringBuffer(); - String trimmedStatement = this.originalSql.substring( + String trimmedStatement = sanitizedSql.substring( endCallIndex + offset).trim(); int statementLength = trimmedStatement.length(); @@ -854,9 +857,9 @@ return nameBuf.toString(); } + throw SQLError.createSQLException(Messages.getString("CallableStatement.1"), //$NON-NLS-1$ SQLError.SQL_STATE_GENERAL_ERROR); - } /** Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-03-23 03:54:54 UTC (rev 6366) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-03-23 17:36:06 UTC (rev 6367) @@ -141,7 +141,10 @@ byte[][] staticSql = null; /** - * + * Represents the "parsed" state of a client-side + * prepared statement, with the statement broken up into + * it's static and dynamic (where parameters are bound) + * parts. */ public ParseInfo(String sql, Connection conn, java.sql.DatabaseMetaData dbmd, String encoding, @@ -231,9 +234,30 @@ quoteChar = 0; } } else { - if ((c == '\'') || (c == '"')) { - inQuotes = true; - quoteChar = c; + if (c == '#') { + // run out to end of line + i = this.statementLength - 1; + continue; + } else if (c == '/' && (i + 1) < this.statementLength) { + // Comment? + c = sql.charAt(i + 1); + + if (c == '*') { + i+= 2; + + for (int j = i; j < this.statementLength; j++) { + i++; + c = sql.charAt(j); + + if (c == '*' && (j + 1) < this.statementLength) { + if (sql.charAt(j + 1) == '/') { + i++; + c = sql.charAt(i); + break; // comment done + } + } + } + } } else if ((c == '\'') || (c == '"')) { inQuotes = true; quoteChar = c; Modified: branches/branch_5_0/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java =================================================================== --- branches/branch_5_0/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java 2007-03-23 03:54:54 UTC (rev 6366) +++ branches/branch_5_0/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java 2007-03-23 17:36:06 UTC (rev 6367) @@ -1065,4 +1065,29 @@ closeMemberJDBCResources(); } } + + /** + * Tests fix for BUG#27400 - CALL [comment] some_proc() doesn't work + */ + public void testBug27400() throws Exception { + if (!versionMeetsMinimum(5, 0)) { + return; // SPs not supported + } + + createProcedure("testBug27400", "(a INT, b VARCHAR(32)) BEGIN SELECT 1; END"); + + CallableStatement cStmt = null; + + try { + cStmt = this.conn.prepareCall("{CALL /* SOME COMMENT */ testBug27400( /* does this work too? */ ?, ?)} # and a commented ? here too"); + assertTrue(cStmt.toString().indexOf("/*") != -1); // we don't want to strip the comments + cStmt.setInt(1, 1); + cStmt.setString(2, "bleh"); + cStmt.execute(); + } finally { + if (cStmt != null) { + cStmt.close(); + } + } + } } Modified: trunk/connector-j/CHANGES =================================================================== --- trunk/connector-j/CHANGES 2007-03-23 03:54:54 UTC (rev 6366) +++ trunk/connector-j/CHANGES 2007-03-23 17:36:06 UTC (rev 6367) @@ -73,7 +73,19 @@ hadn't been cancelled by the driver. High-load environments might want to consider disabling this functionality. (this configuration property is part of the "maxPerformance" configuration bundle). - + + - Fixed BUG#27400 - CALL /* ... */ some_proc() doesn't work. As a side effect + of this fix, you can now use /* */ and # comments when preparing statements using + client-side prepared statement emulation. + + If the comments happen to contain parameter markers '?', they will be treated + as belonging to the comment (i.e. not recognized) rather than being a parameter + of the statement. + + Note that the statement when sent to the server will contain the comments + as-is, they're not stripped during the process of preparing the PreparedStatement + or CallableStatement. + 03-01-07 - Version 5.0.5 - Fixed BUG#23645 - Some collations/character sets reported as "unknown" Modified: trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java =================================================================== --- trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java 2007-03-23 03:54:54 UTC (rev 6366) +++ trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java 2007-03-23 17:36:06 UTC (rev 6367) @@ -922,13 +922,16 @@ } private String extractProcedureName() throws SQLException { + String sanitizedSql = StringUtils.stripComments(this.originalSql, + "`\"'", "`\"'", true, false, true, true); + // TODO: Do this with less memory allocation - int endCallIndex = StringUtils.indexOfIgnoreCase(this.originalSql, + int endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql, "CALL "); //$NON-NLS-1$ int offset = 5; if (endCallIndex == -1) { - endCallIndex = StringUtils.indexOfIgnoreCase(this.originalSql, + endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql, "SELECT "); offset = 7; } @@ -936,7 +939,7 @@ if (endCallIndex != -1) { StringBuffer nameBuf = new StringBuffer(); - String trimmedStatement = this.originalSql.substring( + String trimmedStatement = sanitizedSql.substring( endCallIndex + offset).trim(); int statementLength = trimmedStatement.length(); @@ -953,9 +956,9 @@ return nameBuf.toString(); } + throw SQLError.createSQLException(Messages.getString("CallableStatement.1"), //$NON-NLS-1$ SQLError.SQL_STATE_GENERAL_ERROR); - } /** Modified: trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java =================================================================== --- trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-03-23 03:54:54 UTC (rev 6366) +++ trunk/connector-j/src/com/mysql/jdbc/PreparedStatement.java 2007-03-23 17:36:06 UTC (rev 6367) @@ -180,7 +180,10 @@ byte[][] staticSql = null; /** - * + * Represents the "parsed" state of a client-side + * prepared statement, with the statement broken up into + * it's static and dynamic (where parameters are bound) + * parts. */ public ParseInfo(String sql, Connection conn, java.sql.DatabaseMetaData dbmd, String encoding, @@ -270,9 +273,30 @@ quoteChar = 0; } } else { - if ((c == '\'') || (c == '"')) { - inQuotes = true; - quoteChar = c; + if (c == '#') { + // run out to end of line + i = this.statementLength - 1; + continue; + } else if (c == '/' && (i + 1) < this.statementLength) { + // Comment? + c = sql.charAt(i + 1); + + if (c == '*') { + i+= 2; + + for (int j = i; j < this.statementLength; j++) { + i++; + c = sql.charAt(j); + + if (c == '*' && (j + 1) < this.statementLength) { + if (sql.charAt(j + 1) == '/') { + i++; + c = sql.charAt(i); + break; // comment done + } + } + } + } } else if ((c == '\'') || (c == '"')) { inQuotes = true; quoteChar = c; Modified: trunk/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java =================================================================== --- trunk/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java 2007-03-23 03:54:54 UTC (rev 6366) +++ trunk/connector-j/src/testsuite/regression/CallableStatementRegressionTest.java 2007-03-23 17:36:06 UTC (rev 6367) @@ -1063,4 +1063,29 @@ closeMemberJDBCResources(); } } + + /** + * Tests fix for BUG#27400 - CALL [comment] some_proc() doesn't work + */ + public void testBug27400() throws Exception { + if (!versionMeetsMinimum(5, 0)) { + return; // SPs not supported + } + + createProcedure("testBug27400", "(a INT, b VARCHAR(32)) BEGIN SELECT 1; END"); + + CallableStatement cStmt = null; + + try { + cStmt = this.conn.prepareCall("{CALL /* SOME COMMENT */ testBug27400( /* does this work too? */ ?, ?)} # and a commented ? here too"); + assertTrue(cStmt.toString().indexOf("/*") != -1); // we don't want to strip the comments + cStmt.setInt(1, 1); + cStmt.setString(2, "bleh"); + cStmt.execute(); + } finally { + if (cStmt != null) { + cStmt.close(); + } + } + } }