[jOOQ/jOOQ#18480] Parser doesn't recognise built-in functions when quoted
This commit is contained in:
parent
c237949fa0
commit
8a21c7b98c
@ -227,6 +227,10 @@ abstract class AbstractParseContext extends AbstractScope {
|
||||
|
||||
abstract int afterWhitespace(int p);
|
||||
|
||||
final char lower(char c) {
|
||||
return c >= 'A' && c <= 'Z' ? (char) (c + ('a' - 'A')) : c;
|
||||
}
|
||||
|
||||
final char upper(char c) {
|
||||
return c >= 'a' && c <= 'z' ? (char) (c - ('a' - 'A')) : c;
|
||||
}
|
||||
@ -340,6 +344,10 @@ abstract class AbstractParseContext extends AbstractScope {
|
||||
return character() == c;
|
||||
}
|
||||
|
||||
final boolean peek(char c, int p) {
|
||||
return character(p) == c;
|
||||
}
|
||||
|
||||
public final boolean peek(String string) {
|
||||
return peek(string, position());
|
||||
}
|
||||
|
||||
@ -55,6 +55,7 @@ import static org.jooq.JoinType.JOIN;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.DERBY;
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
// ...
|
||||
@ -515,6 +516,7 @@ import static org.jooq.impl.Tools.asInt;
|
||||
import static org.jooq.impl.Tools.deleteQueryImpl;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.impl.Tools.normaliseNameCase;
|
||||
import static org.jooq.impl.Tools.parseNameCase;
|
||||
import static org.jooq.impl.Tools.selectQueryImpl;
|
||||
import static org.jooq.impl.Tools.updateQueryImpl;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_PARSE_ON_CONFLICT;
|
||||
@ -755,6 +757,7 @@ import org.jooq.XMLAttributes;
|
||||
import org.jooq.XMLTableColumnPathStep;
|
||||
import org.jooq.XMLTableColumnsStep;
|
||||
import org.jooq.XMLTablePassingStep;
|
||||
import org.jooq.conf.ParseNameCase;
|
||||
import org.jooq.conf.ParseSearchSchema;
|
||||
import org.jooq.conf.ParseUnknownFunctions;
|
||||
import org.jooq.conf.ParseUnsupportedSyntax;
|
||||
@ -927,7 +930,7 @@ final class DefaultParseContext extends AbstractParseContext implements ParseCon
|
||||
|
||||
|
||||
static final Set<SQLDialect> SUPPORTS_HASH_COMMENT_SYNTAX = SQLDialect.supportedBy(MARIADB, MYSQL);
|
||||
static final Set<SQLDialect> NO_SUPPORT_QUOTED_BUILT_IN_FUNCION_NAMES = SQLDialect.supportedBy(DERBY, HSQLDB);
|
||||
static final Set<SQLDialect> NO_SUPPORT_QUOTED_BUILT_IN_FUNCION_NAMES = SQLDialect.supportedBy(DERBY, FIREBIRD, HSQLDB);
|
||||
|
||||
final Queries parse() {
|
||||
return wrap(() -> {
|
||||
@ -8982,7 +8985,22 @@ final class DefaultParseContext extends AbstractParseContext implements ParseCon
|
||||
|
||||
|
||||
|
||||
switch (characterUpper()) {
|
||||
char u = characterUpper();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// [#18480] Allow for quoted built-in function identifiers
|
||||
switch (u) {
|
||||
case '`':
|
||||
case '[':
|
||||
case '"':
|
||||
u = characterNextUpper();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (u) {
|
||||
|
||||
// [#8821] Known prefixes so far:
|
||||
case ':':
|
||||
@ -9419,7 +9437,7 @@ final class DefaultParseContext extends AbstractParseContext implements ParseCon
|
||||
|
||||
case 'L':
|
||||
if (parseFunctionNameIf("LOWER", "LCASE"))
|
||||
return lower((Field) parseFieldParenthesised());
|
||||
return DSL.lower((Field) parseFieldParenthesised());
|
||||
else if (parseFunctionNameIf("LPAD", "leftPad"))
|
||||
return parseFunctionArgs3(DSL::lpad, DSL::lpad);
|
||||
else if (parseFunctionNameIf("LTRIM"))
|
||||
@ -13603,6 +13621,14 @@ final class DefaultParseContext extends AbstractParseContext implements ParseCon
|
||||
: 0;
|
||||
}
|
||||
|
||||
private final char peekQuote(boolean allowAposQuotes, int p) {
|
||||
return peek('"', p) ? '"'
|
||||
: peek('`', p) ? '`'
|
||||
: peek('[', p) ? ']'
|
||||
: allowAposQuotes && peek('\'', p) ? '\''
|
||||
: 0;
|
||||
}
|
||||
|
||||
private final DataType<?> parseCastDataType() {
|
||||
char character = characterUpper();
|
||||
|
||||
@ -15287,8 +15313,41 @@ final class DefaultParseContext extends AbstractParseContext implements ParseCon
|
||||
|
||||
int skip = afterWhitespace(p, peekIntoParens) - p;
|
||||
|
||||
// [#18480] Function names are allowed to be quoted
|
||||
char quoteEnd = requireFunction ? peekQuote(false, p + skip) : 0;
|
||||
boolean quoted = quoteEnd != 0;
|
||||
ParseNameCase nameCase = null;
|
||||
|
||||
if (quoted) {
|
||||
if (NO_SUPPORT_QUOTED_BUILT_IN_FUNCION_NAMES.contains(parseDialect()))
|
||||
return false;
|
||||
|
||||
nameCase = parseNameCase(configuration);
|
||||
switch (parseDialect()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
caseSensitive =
|
||||
nameCase != ParseNameCase.AS_IS
|
||||
&& nameCase != ParseNameCase.LOWER;
|
||||
break;
|
||||
}
|
||||
|
||||
skip++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = keyword.charAt(i);
|
||||
|
||||
if (caseSensitive && (
|
||||
nameCase == ParseNameCase.LOWER_IF_UNQUOTED ||
|
||||
nameCase == ParseNameCase.LOWER))
|
||||
c = lower(c);
|
||||
|
||||
int pos = p + i + skip;
|
||||
|
||||
switch (c) {
|
||||
@ -15313,6 +15372,15 @@ final class DefaultParseContext extends AbstractParseContext implements ParseCon
|
||||
|
||||
int pos = p + length + skip;
|
||||
|
||||
if (quoted) {
|
||||
if (character(pos) == quoteEnd) {
|
||||
pos++;
|
||||
skip++;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// [#8806] A keyword that is followed by a period is very likely an identifier
|
||||
if (isIdentifierPart(pos) || character(pos) == '.')
|
||||
return false;
|
||||
|
||||
@ -7212,7 +7212,7 @@ final class Tools {
|
||||
* Get the {@link ParseNameCase}, looking up the default value from the
|
||||
* parse dialect.
|
||||
*/
|
||||
private static final ParseNameCase parseNameCase(Configuration configuration) {
|
||||
static final ParseNameCase parseNameCase(Configuration configuration) {
|
||||
ParseNameCase result = defaultIfNull(configuration.settings().getParseNameCase(), ParseNameCase.DEFAULT);
|
||||
|
||||
if (result == ParseNameCase.DEFAULT) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user