From 524155e53a798a9ff6aeb94d9bf751e01fa5981c Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Tue, 22 Jul 2014 11:12:24 +0200 Subject: [PATCH] [#3430] JDBC escape syntax is not correctly rendered from plain SQL when plain SQL contains newlines --- .../test/all/testcases/PlainSQLTests.java | 19 ++++-- jOOQ/src/main/java/org/jooq/impl/Utils.java | 63 +++++++++++++++++-- 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/jOOQ-test/src/test/java/org/jooq/test/all/testcases/PlainSQLTests.java b/jOOQ-test/src/test/java/org/jooq/test/all/testcases/PlainSQLTests.java index 7e33ee6e0b..eb9ac964ba 100644 --- a/jOOQ-test/src/test/java/org/jooq/test/all/testcases/PlainSQLTests.java +++ b/jOOQ-test/src/test/java/org/jooq/test/all/testcases/PlainSQLTests.java @@ -51,6 +51,7 @@ import static org.jooq.impl.DSL.fieldByName; import static org.jooq.impl.DSL.function; import static org.jooq.impl.DSL.inline; import static org.jooq.impl.DSL.name; +import static org.jooq.impl.DSL.one; import static org.jooq.impl.DSL.param; import static org.jooq.impl.DSL.table; import static org.jooq.impl.DSL.tableByName; @@ -673,7 +674,7 @@ extends BaseTest + * For a more accurate set of whitespaces, refer to + * http://stackoverflow.com/a/4731164/521799. In the event of SQL + * processing, it is probably safe to ignore most of those alternative + * Unicode whitespaces. */ - private static final Pattern JDBC_ESCAPE_PATTERN = Pattern.compile("\\{(fn|d|t|ts)\\b.*"); + private static final String WHITESPACE = " \t\n\u000B\f\r"; + + /** + * Acceptable prefixes for JDBC escape syntax. + */ + private static final String[] JDBC_ESCAPE_PREFIXES = { + "{fn ", + "{d ", + "{t ", + "{ts " + }; // ------------------------------------------------------------------------ // XXX: Record constructors and related methods @@ -1213,7 +1228,7 @@ final class Utils { else if (sqlChars[i] == '{') { // [#1461] Be careful not to match any JDBC escape syntax - if (JDBC_ESCAPE_PATTERN.matcher(sql.substring(i)).matches()) { + if (peekAny(sqlChars, i, JDBC_ESCAPE_PREFIXES, true)) { render.sql(sqlChars[i]); } @@ -1257,13 +1272,38 @@ final class Utils { * @param peek The string to peek for */ static final boolean peek(char[] sqlChars, int index, String peek) { + return peek(sqlChars, index, peek, false); + } + + /** + * Peek for a string at a given index of a char[] + * + * @param sqlChars The char array to peek into + * @param index The index within the char array to peek for a string + * @param peek The string to peek for + * @param anyWhitespace A whitespace character in peekAny + * represents "any" whitespace character as defined in + * {@link #WHITESPACE}, or in Java Regex "\s". + */ + static final boolean peek(char[] sqlChars, int index, String peek, boolean anyWhitespace) { char[] peekArray = peek.toCharArray(); + peekArrayLoop: for (int i = 0; i < peekArray.length; i++) { if (index + i >= sqlChars.length) { return false; } if (sqlChars[index + i] != peekArray[i]) { + + // [#3430] In some cases, we don't care about the type of whitespace. + if (anyWhitespace && peekArray[i] == ' ') { + for (int j = 0; j < WHITESPACE.length(); j++) { + if (sqlChars[index + i] == WHITESPACE.charAt(j)) { + continue peekArrayLoop; + } + } + } + return false; } } @@ -1279,8 +1319,23 @@ final class Utils { * @param peekAny The strings to peek for */ static final boolean peekAny(char[] sqlChars, int index, String[] peekAny) { + return peekAny(sqlChars, index, peekAny, false); + } + + /** + * Peek for several strings at a given index of a + * char[] + * + * @param sqlChars The char array to peek into + * @param index The index within the char array to peek for a string + * @param peekAny The strings to peek for + * @param anyWhitespace A whitespace character in peekAny + * represents "any" whitespace character as defined in + * {@link #WHITESPACE}, or in Java Regex "\s". + */ + static final boolean peekAny(char[] sqlChars, int index, String[] peekAny, boolean anyWhitespace) { for (String peek : peekAny) - if (peek(sqlChars, index, peek)) + if (peek(sqlChars, index, peek, anyWhitespace)) return true; return false;