[#3430] JDBC escape syntax is not correctly rendered from plain SQL when plain SQL contains newlines
This commit is contained in:
parent
5d51daac63
commit
524155e53a
@ -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<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
|
||||
public void testPlainSQLAndJDBCEscapeSyntax() throws Exception {
|
||||
Record result = create()
|
||||
Record r1 = create()
|
||||
.select(
|
||||
field("{d '2014-01-01'}", Date.class).as("a"),
|
||||
field("{t '19:00:00'}", Time.class).as("b"),
|
||||
@ -681,8 +682,18 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
)
|
||||
.fetchOne();
|
||||
|
||||
assertEquals(Date.valueOf("2014-01-01"), result.getValue(0));
|
||||
assertEquals(Time.valueOf("19:00:00"), result.getValue(1));
|
||||
assertEquals(Timestamp.valueOf("2014-01-01 19:00:00"), result.getValue(2));
|
||||
assertEquals(Date.valueOf("2014-01-01"), r1.getValue(0));
|
||||
assertEquals(Time.valueOf("19:00:00"), r1.getValue(1));
|
||||
assertEquals(Timestamp.valueOf("2014-01-01 19:00:00"), r1.getValue(2));
|
||||
|
||||
// [#3430] Don't let newline characters break the parsing of JDBC escape syntax:
|
||||
Record r2 = create()
|
||||
.select(one().as("one"))
|
||||
.where("{d '2014-01-01'} < {d '2014-01-02'}\n"
|
||||
+ "and {t '00:00:00'} < {t '01:00:00'}\n"
|
||||
+ "and {ts '2014-01-01 00:00:00'} < {ts '2014-01-02 00:00:00'}")
|
||||
.fetchOne();
|
||||
|
||||
assertEquals(1, r2.getValue(0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,9 +314,24 @@ final class Utils {
|
||||
private static final Pattern PLUS_PATTERN = Pattern.compile("\\+(-+)(?=\\+)");
|
||||
|
||||
/**
|
||||
* A pattern for the JDBC escape syntax
|
||||
* All characters that are matched by Java's interpretation of \s.
|
||||
* <p>
|
||||
* 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 <code>index</code> of a <code>char[]</code>
|
||||
*
|
||||
* @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 <code>peekAny</code>
|
||||
* 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 <code>index</code> of a
|
||||
* <code>char[]</code>
|
||||
*
|
||||
* @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 <code>peekAny</code>
|
||||
* 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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user