From: Date: January 10 2007 11:49pm Subject: Connector/J commit: r6291 - 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/17895 X-Bug: 25399 Message-Id: <200701102249.l0AMnTHU017590@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/EscapeProcessor.java branches/branch_5_0/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java trunk/connector-j/CHANGES trunk/connector-j/src/com/mysql/jdbc/EscapeProcessor.java trunk/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java Log: Fixed BUG#25399 - EscapeProcessor gets confused by multiple backslashes. We now push the responsibility of syntax errors back on to the server for most escape sequences. Modified: branches/branch_5_0/connector-j/CHANGES =================================================================== --- branches/branch_5_0/connector-j/CHANGES 2007-01-10 22:22:08 UTC (rev 6290) +++ branches/branch_5_0/connector-j/CHANGES 2007-01-10 22:49:25 UTC (rev 6291) @@ -68,7 +68,11 @@ - Fixed BUG#23303 - DatabaseMetaData.getSchemas() doesn't return a TABLE_CATALOG column. - + + - Fixed BUG#25399 - EscapeProcessor gets confused by multiple + backslashes. We now push the responsibility of syntax errors back + on to the server for most escape sequences. + 10-20-06 - Version 5.0.4 - Fixed BUG#21379 - column names don't match metadata in cases Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/EscapeProcessor.java =================================================================== --- branches/branch_5_0/connector-j/src/com/mysql/jdbc/EscapeProcessor.java 2007-01-10 22:22:08 UTC (rev 6290) +++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/EscapeProcessor.java 2007-01-10 22:49:25 UTC (rev 6291) @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2004 MySQL AB + Copyright (C) 2002-2007 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -186,18 +186,16 @@ escapeSequence = st.nextToken(); if (escapeSequence.length() < 3) { - throw SQLError.createSQLException( - "Syntax error for escape sequence '" - + token + "'", "42000"); - } + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { + - escapeSequence = escapeSequence.substring(1, + escapeSequence = escapeSequence.substring(1, escapeSequence.length() - 1); - replaceEscapeSequence = true; + replaceEscapeSequence = true; + } } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for escape sequence '" - + token + "'", "42000"); + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{fn")) { @@ -222,148 +220,146 @@ int endPos = token.lastIndexOf('\''); // no } if ((startPos == -1) || (endPos == -1)) { - throw SQLError.createSQLException( - "Syntax error for DATE escape sequence '" - + token + "'", "42000"); + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { + + String argument = token.substring(startPos, endPos); + + try { + StringTokenizer st = new StringTokenizer(argument, + " -"); + String year4 = st.nextToken(); + String month2 = st.nextToken(); + String day2 = st.nextToken(); + String dateString = "'" + year4 + "-" + month2 + + "-" + day2 + "'"; + newSql.append(dateString); + } catch (java.util.NoSuchElementException e) { + throw SQLError.createSQLException( + "Syntax error for DATE escape sequence '" + + argument + "'", "42000"); + } } - - String argument = token.substring(startPos, endPos); - - try { - StringTokenizer st = new StringTokenizer(argument, - " -"); - String year4 = st.nextToken(); - String month2 = st.nextToken(); - String day2 = st.nextToken(); - String dateString = "'" + year4 + "-" + month2 - + "-" + day2 + "'"; - newSql.append(dateString); - } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for DATE escape sequence '" - + argument + "'", "42000"); - } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{ts")) { int startPos = token.indexOf('\'') + 1; int endPos = token.lastIndexOf('\''); // no } if ((startPos == -1) || (endPos == -1)) { - throw SQLError.createSQLException( - "Syntax error for TIMESTAMP escape sequence '" - + token + "'", "42000"); - } + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { - String argument = token.substring(startPos, endPos); - - try { - StringTokenizer st = new StringTokenizer(argument, - " .-:"); - String year4 = st.nextToken(); - String month2 = st.nextToken(); - String day2 = st.nextToken(); - String hour = st.nextToken(); - String minute = st.nextToken(); - String second = st.nextToken(); - - /* - * For now, we get the fractional seconds part, but - * we don't use it, as MySQL doesn't support it in - * it's TIMESTAMP data type - * - * String fractionalSecond = ""; - * - * if (st.hasMoreTokens()) { fractionalSecond = - * st.nextToken(); } - */ - /* - * Use the full format because number format will - * not work for "between" clauses. - * - * Ref. Mysql Docs - * - * You can specify DATETIME, DATE and TIMESTAMP - * values using any of a common set of formats: - * - * As a string in either 'YYYY-MM-DD HH:MM:SS' or - * 'YY-MM-DD HH:MM:SS' format. - * - * Thanks to Craig Longman for pointing out this bug - */ - if (!conn.getUseTimezone() && !conn.getUseJDBCCompliantTimezoneShift()) { - newSql.append("'").append(year4).append("-") - .append(month2).append("-").append(day2) - .append(" ").append(hour).append(":") - .append(minute).append(":").append(second) - .append("'"); - } else { - Calendar sessionCalendar; - - if (conn != null) { - sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + String argument = token.substring(startPos, endPos); + + try { + StringTokenizer st = new StringTokenizer(argument, + " .-:"); + String year4 = st.nextToken(); + String month2 = st.nextToken(); + String day2 = st.nextToken(); + String hour = st.nextToken(); + String minute = st.nextToken(); + String second = st.nextToken(); + + /* + * For now, we get the fractional seconds part, but + * we don't use it, as MySQL doesn't support it in + * it's TIMESTAMP data type + * + * String fractionalSecond = ""; + * + * if (st.hasMoreTokens()) { fractionalSecond = + * st.nextToken(); } + */ + /* + * Use the full format because number format will + * not work for "between" clauses. + * + * Ref. Mysql Docs + * + * You can specify DATETIME, DATE and TIMESTAMP + * values using any of a common set of formats: + * + * As a string in either 'YYYY-MM-DD HH:MM:SS' or + * 'YY-MM-DD HH:MM:SS' format. + * + * Thanks to Craig Longman for pointing out this bug + */ + if (!conn.getUseTimezone() && !conn.getUseJDBCCompliantTimezoneShift()) { + newSql.append("'").append(year4).append("-") + .append(month2).append("-").append(day2) + .append(" ").append(hour).append(":") + .append(minute).append(":").append(second) + .append("'"); } else { - sessionCalendar = new GregorianCalendar(); - sessionCalendar.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - try { - int year4Int = Integer.parseInt(year4); - int month2Int = Integer.parseInt(month2); - int day2Int = Integer.parseInt(day2); - int hourInt = Integer.parseInt(hour); - int minuteInt = Integer.parseInt(minute); - int secondInt = Integer.parseInt(second); + Calendar sessionCalendar; - synchronized (sessionCalendar) { - boolean useGmtMillis = conn.getUseGmtMillisForDatetimes(); - - Timestamp toBeAdjusted = TimeUtil.fastTimestampCreate(useGmtMillis, - useGmtMillis ? Calendar.getInstance(TimeZone.getTimeZone("GMT")): null, - sessionCalendar, - year4Int, - month2Int, - day2Int, - hourInt, - minuteInt, - secondInt, - 0); + if (conn != null) { + sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + } else { + sessionCalendar = new GregorianCalendar(); + sessionCalendar.setTimeZone(TimeZone.getTimeZone("GMT")); + } - Timestamp inServerTimezone = TimeUtil.changeTimezone( - conn, + try { + int year4Int = Integer.parseInt(year4); + int month2Int = Integer.parseInt(month2); + int day2Int = Integer.parseInt(day2); + int hourInt = Integer.parseInt(hour); + int minuteInt = Integer.parseInt(minute); + int secondInt = Integer.parseInt(second); + + synchronized (sessionCalendar) { + boolean useGmtMillis = conn.getUseGmtMillisForDatetimes(); + + Timestamp toBeAdjusted = TimeUtil.fastTimestampCreate(useGmtMillis, + useGmtMillis ? Calendar.getInstance(TimeZone.getTimeZone("GMT")): null, sessionCalendar, - null, - toBeAdjusted, - sessionCalendar.getTimeZone(), - conn.getServerTimezoneTZ(), - false); + year4Int, + month2Int, + day2Int, + hourInt, + minuteInt, + secondInt, + 0); - - newSql.append("'"); - - String timezoneLiteral = inServerTimezone.toString(); - - int indexOfDot = timezoneLiteral.indexOf("."); - - if (indexOfDot != -1) { - timezoneLiteral = timezoneLiteral.substring(0, indexOfDot); + Timestamp inServerTimezone = TimeUtil.changeTimezone( + conn, + sessionCalendar, + null, + toBeAdjusted, + sessionCalendar.getTimeZone(), + conn.getServerTimezoneTZ(), + false); + + + newSql.append("'"); + + String timezoneLiteral = inServerTimezone.toString(); + + int indexOfDot = timezoneLiteral.indexOf("."); + + if (indexOfDot != -1) { + timezoneLiteral = timezoneLiteral.substring(0, indexOfDot); + } + + newSql.append(timezoneLiteral); } - newSql.append(timezoneLiteral); - } + newSql.append("'"); + - newSql.append("'"); - - - } catch (NumberFormatException nfe) { - throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" - + token + "'.", - SQLError.SQL_STATE_ILLEGAL_ARGUMENT); + } catch (NumberFormatException nfe) { + throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" + + token + "'.", + SQLError.SQL_STATE_ILLEGAL_ARGUMENT); + } } + } catch (java.util.NoSuchElementException e) { + throw SQLError.createSQLException( + "Syntax error for TIMESTAMP escape sequence '" + + argument + "'", "42000"); } - } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for TIMESTAMP escape sequence '" - + argument + "'", "42000"); } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{t")) { @@ -371,69 +367,68 @@ int endPos = token.lastIndexOf('\''); // no } if ((startPos == -1) || (endPos == -1)) { - throw SQLError.createSQLException( - "Syntax error for TIME escape sequence '" - + token + "'", "42000"); - } + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { - String argument = token.substring(startPos, endPos); - - try { - StringTokenizer st = new StringTokenizer(argument, - " :"); - String hour = st.nextToken(); - String minute = st.nextToken(); - String second = st.nextToken(); - - if (!conn.getUseTimezone()) { - String timeString = "'" + hour + ":" + minute + ":" - + second + "'"; - newSql.append(timeString); - } else { - Calendar sessionCalendar = null; + String argument = token.substring(startPos, endPos); + + try { + StringTokenizer st = new StringTokenizer(argument, + " :"); + String hour = st.nextToken(); + String minute = st.nextToken(); + String second = st.nextToken(); - if (conn != null) { - sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + if (!conn.getUseTimezone()) { + String timeString = "'" + hour + ":" + minute + ":" + + second + "'"; + newSql.append(timeString); } else { - sessionCalendar = new GregorianCalendar(); - } - - try { - int hourInt = Integer.parseInt(hour); - int minuteInt = Integer.parseInt(minute); - int secondInt = Integer.parseInt(second); + Calendar sessionCalendar = null; - synchronized (sessionCalendar) { - Time toBeAdjusted = TimeUtil.fastTimeCreate( - sessionCalendar, - hourInt, - minuteInt, - secondInt); + if (conn != null) { + sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + } else { + sessionCalendar = new GregorianCalendar(); + } + + try { + int hourInt = Integer.parseInt(hour); + int minuteInt = Integer.parseInt(minute); + int secondInt = Integer.parseInt(second); - Time inServerTimezone = TimeUtil.changeTimezone( - conn, - sessionCalendar, - null, - toBeAdjusted, - sessionCalendar.getTimeZone(), - conn.getServerTimezoneTZ(), - false); - - newSql.append("'"); - newSql.append(inServerTimezone.toString()); - newSql.append("'"); + synchronized (sessionCalendar) { + Time toBeAdjusted = TimeUtil.fastTimeCreate( + sessionCalendar, + hourInt, + minuteInt, + secondInt); + + Time inServerTimezone = TimeUtil.changeTimezone( + conn, + sessionCalendar, + null, + toBeAdjusted, + sessionCalendar.getTimeZone(), + conn.getServerTimezoneTZ(), + false); + + newSql.append("'"); + newSql.append(inServerTimezone.toString()); + newSql.append("'"); + } + + } catch (NumberFormatException nfe) { + throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" + + token + "'.", + SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } - - } catch (NumberFormatException nfe) { - throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" - + token + "'.", - SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } + } catch (java.util.NoSuchElementException e) { + throw SQLError.createSQLException( + "Syntax error for escape sequence '" + + argument + "'", "42000"); } - } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for escape sequence '" - + argument + "'", "42000"); } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{call") Modified: branches/branch_5_0/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java =================================================================== --- branches/branch_5_0/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java 2007-01-10 22:22:08 UTC (rev 6290) +++ branches/branch_5_0/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java 2007-01-10 22:49:25 UTC (rev 6291) @@ -1,5 +1,5 @@ /* - Copyright (C) 2005 MySQL AB + Copyright (C) 2005-2007 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -84,4 +84,14 @@ assertEquals("select '{\"','}'", this.conn .nativeSQL("select '{\"','}'")); } + + /** + * Tests fix for BUG#25399 - EscapeProcessor gets confused by multiple backslashes + * + * @throws Exception if the test fails. + */ + public void testBug25399() throws Exception { + assertEquals("\\' {d}", + getSingleValueWithQuery("SELECT '\\\\\\' {d}'")); + } } Modified: trunk/connector-j/CHANGES =================================================================== --- trunk/connector-j/CHANGES 2007-01-10 22:22:08 UTC (rev 6290) +++ trunk/connector-j/CHANGES 2007-01-10 22:49:25 UTC (rev 6291) @@ -64,7 +64,11 @@ - Fixed BUG#23303 - DatabaseMetaData.getSchemas() doesn't return a TABLE_CATALOG column. - + + - Fixed BUG#25399 - EscapeProcessor gets confused by multiple + backslashes. We now push the responsibility of syntax errors back + on to the server for most escape sequences. + 10-20-06 - Version 5.0.4 - Fixed BUG#21379 - column names don't match metadata in cases Modified: trunk/connector-j/src/com/mysql/jdbc/EscapeProcessor.java =================================================================== --- trunk/connector-j/src/com/mysql/jdbc/EscapeProcessor.java 2007-01-10 22:22:08 UTC (rev 6290) +++ trunk/connector-j/src/com/mysql/jdbc/EscapeProcessor.java 2007-01-10 22:49:25 UTC (rev 6291) @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2004 MySQL AB + Copyright (C) 2002-2007 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -186,18 +186,16 @@ escapeSequence = st.nextToken(); if (escapeSequence.length() < 3) { - throw SQLError.createSQLException( - "Syntax error for escape sequence '" - + token + "'", "42000"); - } + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { + - escapeSequence = escapeSequence.substring(1, + escapeSequence = escapeSequence.substring(1, escapeSequence.length() - 1); - replaceEscapeSequence = true; + replaceEscapeSequence = true; + } } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for escape sequence '" - + token + "'", "42000"); + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{fn")) { @@ -222,148 +220,146 @@ int endPos = token.lastIndexOf('\''); // no } if ((startPos == -1) || (endPos == -1)) { - throw SQLError.createSQLException( - "Syntax error for DATE escape sequence '" - + token + "'", "42000"); + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { + + String argument = token.substring(startPos, endPos); + + try { + StringTokenizer st = new StringTokenizer(argument, + " -"); + String year4 = st.nextToken(); + String month2 = st.nextToken(); + String day2 = st.nextToken(); + String dateString = "'" + year4 + "-" + month2 + + "-" + day2 + "'"; + newSql.append(dateString); + } catch (java.util.NoSuchElementException e) { + throw SQLError.createSQLException( + "Syntax error for DATE escape sequence '" + + argument + "'", "42000"); + } } - - String argument = token.substring(startPos, endPos); - - try { - StringTokenizer st = new StringTokenizer(argument, - " -"); - String year4 = st.nextToken(); - String month2 = st.nextToken(); - String day2 = st.nextToken(); - String dateString = "'" + year4 + "-" + month2 - + "-" + day2 + "'"; - newSql.append(dateString); - } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for DATE escape sequence '" - + argument + "'", "42000"); - } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{ts")) { int startPos = token.indexOf('\'') + 1; int endPos = token.lastIndexOf('\''); // no } if ((startPos == -1) || (endPos == -1)) { - throw SQLError.createSQLException( - "Syntax error for TIMESTAMP escape sequence '" - + token + "'", "42000"); - } + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { - String argument = token.substring(startPos, endPos); - - try { - StringTokenizer st = new StringTokenizer(argument, - " .-:"); - String year4 = st.nextToken(); - String month2 = st.nextToken(); - String day2 = st.nextToken(); - String hour = st.nextToken(); - String minute = st.nextToken(); - String second = st.nextToken(); - - /* - * For now, we get the fractional seconds part, but - * we don't use it, as MySQL doesn't support it in - * it's TIMESTAMP data type - * - * String fractionalSecond = ""; - * - * if (st.hasMoreTokens()) { fractionalSecond = - * st.nextToken(); } - */ - /* - * Use the full format because number format will - * not work for "between" clauses. - * - * Ref. Mysql Docs - * - * You can specify DATETIME, DATE and TIMESTAMP - * values using any of a common set of formats: - * - * As a string in either 'YYYY-MM-DD HH:MM:SS' or - * 'YY-MM-DD HH:MM:SS' format. - * - * Thanks to Craig Longman for pointing out this bug - */ - if (!conn.getUseTimezone() && !conn.getUseJDBCCompliantTimezoneShift()) { - newSql.append("'").append(year4).append("-") - .append(month2).append("-").append(day2) - .append(" ").append(hour).append(":") - .append(minute).append(":").append(second) - .append("'"); - } else { - Calendar sessionCalendar; - - if (conn != null) { - sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + String argument = token.substring(startPos, endPos); + + try { + StringTokenizer st = new StringTokenizer(argument, + " .-:"); + String year4 = st.nextToken(); + String month2 = st.nextToken(); + String day2 = st.nextToken(); + String hour = st.nextToken(); + String minute = st.nextToken(); + String second = st.nextToken(); + + /* + * For now, we get the fractional seconds part, but + * we don't use it, as MySQL doesn't support it in + * it's TIMESTAMP data type + * + * String fractionalSecond = ""; + * + * if (st.hasMoreTokens()) { fractionalSecond = + * st.nextToken(); } + */ + /* + * Use the full format because number format will + * not work for "between" clauses. + * + * Ref. Mysql Docs + * + * You can specify DATETIME, DATE and TIMESTAMP + * values using any of a common set of formats: + * + * As a string in either 'YYYY-MM-DD HH:MM:SS' or + * 'YY-MM-DD HH:MM:SS' format. + * + * Thanks to Craig Longman for pointing out this bug + */ + if (!conn.getUseTimezone() && !conn.getUseJDBCCompliantTimezoneShift()) { + newSql.append("'").append(year4).append("-") + .append(month2).append("-").append(day2) + .append(" ").append(hour).append(":") + .append(minute).append(":").append(second) + .append("'"); } else { - sessionCalendar = new GregorianCalendar(); - sessionCalendar.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - try { - int year4Int = Integer.parseInt(year4); - int month2Int = Integer.parseInt(month2); - int day2Int = Integer.parseInt(day2); - int hourInt = Integer.parseInt(hour); - int minuteInt = Integer.parseInt(minute); - int secondInt = Integer.parseInt(second); + Calendar sessionCalendar; - synchronized (sessionCalendar) { - boolean useGmtMillis = conn.getUseGmtMillisForDatetimes(); - - Timestamp toBeAdjusted = TimeUtil.fastTimestampCreate(useGmtMillis, - useGmtMillis ? Calendar.getInstance(TimeZone.getTimeZone("GMT")): null, - sessionCalendar, - year4Int, - month2Int, - day2Int, - hourInt, - minuteInt, - secondInt, - 0); + if (conn != null) { + sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + } else { + sessionCalendar = new GregorianCalendar(); + sessionCalendar.setTimeZone(TimeZone.getTimeZone("GMT")); + } - Timestamp inServerTimezone = TimeUtil.changeTimezone( - conn, + try { + int year4Int = Integer.parseInt(year4); + int month2Int = Integer.parseInt(month2); + int day2Int = Integer.parseInt(day2); + int hourInt = Integer.parseInt(hour); + int minuteInt = Integer.parseInt(minute); + int secondInt = Integer.parseInt(second); + + synchronized (sessionCalendar) { + boolean useGmtMillis = conn.getUseGmtMillisForDatetimes(); + + Timestamp toBeAdjusted = TimeUtil.fastTimestampCreate(useGmtMillis, + useGmtMillis ? Calendar.getInstance(TimeZone.getTimeZone("GMT")): null, sessionCalendar, - null, - toBeAdjusted, - sessionCalendar.getTimeZone(), - conn.getServerTimezoneTZ(), - false); + year4Int, + month2Int, + day2Int, + hourInt, + minuteInt, + secondInt, + 0); - - newSql.append("'"); - - String timezoneLiteral = inServerTimezone.toString(); - - int indexOfDot = timezoneLiteral.indexOf("."); - - if (indexOfDot != -1) { - timezoneLiteral = timezoneLiteral.substring(0, indexOfDot); + Timestamp inServerTimezone = TimeUtil.changeTimezone( + conn, + sessionCalendar, + null, + toBeAdjusted, + sessionCalendar.getTimeZone(), + conn.getServerTimezoneTZ(), + false); + + + newSql.append("'"); + + String timezoneLiteral = inServerTimezone.toString(); + + int indexOfDot = timezoneLiteral.indexOf("."); + + if (indexOfDot != -1) { + timezoneLiteral = timezoneLiteral.substring(0, indexOfDot); + } + + newSql.append(timezoneLiteral); } - newSql.append(timezoneLiteral); - } + newSql.append("'"); + - newSql.append("'"); - - - } catch (NumberFormatException nfe) { - throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" - + token + "'.", - SQLError.SQL_STATE_ILLEGAL_ARGUMENT); + } catch (NumberFormatException nfe) { + throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" + + token + "'.", + SQLError.SQL_STATE_ILLEGAL_ARGUMENT); + } } + } catch (java.util.NoSuchElementException e) { + throw SQLError.createSQLException( + "Syntax error for TIMESTAMP escape sequence '" + + argument + "'", "42000"); } - } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for TIMESTAMP escape sequence '" - + argument + "'", "42000"); } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, "{t")) { @@ -371,81 +367,80 @@ int endPos = token.lastIndexOf('\''); // no } if ((startPos == -1) || (endPos == -1)) { - throw SQLError.createSQLException( - "Syntax error for TIME escape sequence '" - + token + "'", "42000"); - } + newSql.append(token); // it's just part of the query, push possible syntax errors onto server's shoulders + } else { - String argument = token.substring(startPos, endPos); - - try { - StringTokenizer st = new StringTokenizer(argument, - " :"); - String hour = st.nextToken(); - String minute = st.nextToken(); - String second = st.nextToken(); - - if (!conn.getUseTimezone()) { - String timeString = "'" + hour + ":" + minute + ":" - + second + "'"; - newSql.append(timeString); - } else { - Calendar sessionCalendar = null; + String argument = token.substring(startPos, endPos); + + try { + StringTokenizer st = new StringTokenizer(argument, + " :"); + String hour = st.nextToken(); + String minute = st.nextToken(); + String second = st.nextToken(); - if (conn != null) { - sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + if (!conn.getUseTimezone()) { + String timeString = "'" + hour + ":" + minute + ":" + + second + "'"; + newSql.append(timeString); } else { - sessionCalendar = new GregorianCalendar(); - } - - try { - int hourInt = Integer.parseInt(hour); - int minuteInt = Integer.parseInt(minute); - int secondInt = Integer.parseInt(second); + Calendar sessionCalendar = null; - synchronized (sessionCalendar) { - Time toBeAdjusted = TimeUtil.fastTimeCreate( - sessionCalendar, - hourInt, - minuteInt, - secondInt); + if (conn != null) { + sessionCalendar = conn.getCalendarInstanceForSessionOrNew(); + } else { + sessionCalendar = new GregorianCalendar(); + } + + try { + int hourInt = Integer.parseInt(hour); + int minuteInt = Integer.parseInt(minute); + int secondInt = Integer.parseInt(second); - Time inServerTimezone = TimeUtil.changeTimezone( - conn, - sessionCalendar, - null, - toBeAdjusted, - sessionCalendar.getTimeZone(), - conn.getServerTimezoneTZ(), - false); - - newSql.append("'"); - newSql.append(inServerTimezone.toString()); - newSql.append("'"); + synchronized (sessionCalendar) { + Time toBeAdjusted = TimeUtil.fastTimeCreate( + sessionCalendar, + hourInt, + minuteInt, + secondInt); + + Time inServerTimezone = TimeUtil.changeTimezone( + conn, + sessionCalendar, + null, + toBeAdjusted, + sessionCalendar.getTimeZone(), + conn.getServerTimezoneTZ(), + false); + + newSql.append("'"); + newSql.append(inServerTimezone.toString()); + newSql.append("'"); + } + + } catch (NumberFormatException nfe) { + throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" + + token + "'.", + SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } - - } catch (NumberFormatException nfe) { - throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '" - + token + "'.", - SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } + } catch (java.util.NoSuchElementException e) { + throw SQLError.createSQLException( + "Syntax error for escape sequence '" + + argument + "'", "42000"); } - } catch (java.util.NoSuchElementException e) { - throw SQLError.createSQLException( - "Syntax error for escape sequence '" - + argument + "'", "42000"); } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, - "{call") - || StringUtils.startsWithIgnoreCase(collapsedToken, - "{?=call")) { + "{call") + || StringUtils.startsWithIgnoreCase(collapsedToken, + "{?=call")) { int startPos = StringUtils.indexOfIgnoreCase(token, - "CALL") + 5; + "CALL") + 5; int endPos = token.length() - 1; - + if (StringUtils.startsWithIgnoreCase(collapsedToken, - "{?=call")) { + "{?=call")) { callingStoredFunction = true; newSql.append("SELECT "); newSql.append(token.substring(startPos, endPos)); @@ -454,7 +449,7 @@ newSql.append("CALL "); newSql.append(token.substring(startPos, endPos)); } - + for (int i = endPos - 1; i >= startPos; i--) { char c = token.charAt(i); @@ -470,7 +465,7 @@ break; } } else if (StringUtils.startsWithIgnoreCase(collapsedToken, - "{oj")) { + "{oj")) { // MySQL already handles this escape sequence // because of ODBC. Cool. newSql.append(token); Modified: trunk/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java =================================================================== --- trunk/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java 2007-01-10 22:22:08 UTC (rev 6290) +++ trunk/connector-j/src/testsuite/regression/EscapeProcessorRegressionTest.java 2007-01-10 22:49:25 UTC (rev 6291) @@ -1,5 +1,5 @@ /* - Copyright (C) 2005 MySQL AB + Copyright (C) 2005-2007 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -84,4 +84,14 @@ assertEquals("select '{\"','}'", this.conn .nativeSQL("select '{\"','}'")); } + + /** + * Tests fix for BUG#25399 - EscapeProcessor gets confused by multiple backslashes + * + * @throws Exception if the test fails. + */ + public void testBug25399() throws Exception { + assertEquals("\\' {d}", + getSingleValueWithQuery("SELECT '\\\\\\' {d}'")); + } }