diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index 03afea2410..b91223c7d3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -5379,6 +5379,8 @@ class ParserImpl implements Parser { parse(ctx, '\''); StringBuilder sb = new StringBuilder(); + + characterLoop: for (int i = ctx.position; i < ctx.sql.length; i++) { char c1 = ctx.character(i); @@ -5432,15 +5434,18 @@ class ParserImpl implements Parser { break; } - // Unicode character value + // Unicode character value UTF-16 case 'u': - case 'U': - - // 16-bit (TODO 32-bit) c1 = (char) Integer.parseInt(new String(ctx.sql, i + 1, 4), 16); i += 4; break; + // Unicode character value UTF-32 + case 'U': + sb.appendCodePoint(Integer.parseInt(new String(ctx.sql, i + 1, 8), 16)); + i += 8; + continue characterLoop; + default: // Octal byte value diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 9c14bd62f3..396012a86c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -1777,19 +1777,49 @@ final class Tools { for (;;) { // [#3000] [#3630] Consume backslash-escaped characters if needed - if (sqlChars[i] == '\\' && needsBackslashEscaping) { + if (sqlChars[i] == '\\' && needsBackslashEscaping) render.sql(sqlChars[i++]); - } // Consume an escaped apostrophe - else if (peek(sqlChars, i, "''")) { + else if (peek(sqlChars, i, "''")) render.sql(sqlChars[i++]); - } // Break on the terminal string literal delimiter - else if (peek(sqlChars, i, "'")) { + else if (peek(sqlChars, i, "'")) + break; + + // Consume string literal content + render.sql(sqlChars[i++]); + } + + // Consume the terminal string literal delimiter + render.sql(sqlChars[i]); + } + + // [#6704] PostgreSQL supports additional quoted string literals, which we must skip: E'...' + else if ((sqlChars[i] == 'e' || sqlChars[i] == 'E') + && ctx.family() == POSTGRES + && i + 1 < sqlChars.length + && sqlChars[i + 1] == '\'') { + + // Consume the initial string literal delimiters + render.sql(sqlChars[i++]); + render.sql(sqlChars[i++]); + + // Consume the whole string literal + for (;;) { + + // [#3000] [#3630] Consume backslash-escaped characters if needed + if (sqlChars[i] == '\\') + render.sql(sqlChars[i++]); + + // Consume an escaped apostrophe + else if (peek(sqlChars, i, "''")) + render.sql(sqlChars[i++]); + + // Break on the terminal string literal delimiter + else if (peek(sqlChars, i, "'")) break; - } // Consume string literal content render.sql(sqlChars[i++]); @@ -1861,15 +1891,13 @@ final class Tools { for (;;) { // Consume an escaped quote - if (peek(sqlChars, i, quotes[QUOTE_END_DELIMITER_ESCAPED][delimiter])) { + if (peek(sqlChars, i, quotes[QUOTE_END_DELIMITER_ESCAPED][delimiter])) for (int d = 0; d < quotes[QUOTE_END_DELIMITER_ESCAPED][delimiter].length(); d++) render.sql(sqlChars[i++]); - } // Break on the terminal identifier delimiter - else if (peek(sqlChars, i, quotes[QUOTE_END_DELIMITER][delimiter])) { + else if (peek(sqlChars, i, quotes[QUOTE_END_DELIMITER][delimiter])) break; - } // Consume identifier content render.sql(sqlChars[i++]); @@ -1923,9 +1951,8 @@ final class Tools { .castMode(previous); } - if (bind != null) { + if (bind != null) bind.visit(substitute); - } } // [#1432] Inline substitues for {numbered placeholders} outside of string literals