diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java index 64d610fa1..125e38a82 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.expression.operators.relational; import java.util.Locale; +import java.util.regex.Pattern; import net.sf.jsqlparser.expression.BinaryExpression; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; @@ -174,9 +175,11 @@ public LikeExpression withRightExpression(Expression arg0) { public enum KeyWord { LIKE, ILIKE, RLIKE, REGEXP_LIKE, REGEXP, GLOB, SIMILAR_TO, MATCH_ANY, MATCH_ALL, MATCH_PHRASE, MATCH_PHRASE_PREFIX, MATCH_REGEXP; + private static final Pattern WHITESPACE = Pattern.compile("\\s+"); + public static KeyWord from(String keyword) { return Enum.valueOf(KeyWord.class, - keyword.toUpperCase(Locale.ROOT).replaceAll("\\s+", "_")); + WHITESPACE.matcher(keyword.toUpperCase(Locale.ROOT)).replaceAll("_")); } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 7339e68ba..103dbd21b 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -1333,12 +1333,8 @@ public class CCJSqlParser extends AbstractJSqlParser { * everywhere else, e.g. f(content). */ private void consumeXmlLeadingKeyword(Function function) { - String name = function.getName(); - if (name == null) { - return; - } - name = name.toUpperCase(java.util.Locale.ROOT); - if (!"XMLPARSE".equals(name) && !"XMLELEMENT".equals(name) && !"XMLFOREST".equals(name)) { + if (!hasUnqualifiedName(function, "XMLPARSE") && !hasUnqualifiedName(function, "XMLELEMENT") + && !hasUnqualifiedName(function, "XMLFOREST")) { return; } Token token = getToken(1); @@ -1358,6 +1354,12 @@ public class CCJSqlParser extends AbstractJSqlParser { function.setExtraKeyword(getNextToken().image); } + // Matches the single name part, since getName() joins the parts into a new string on each call. + private static boolean hasUnqualifiedName(Function function, String name) { + List nameParts = function.getMultipartName(); + return nameParts != null && nameParts.size() == 1 && name.equalsIgnoreCase(nameParts.get(0)); + } + /** * An unquoted YEAR, MONTH, DAY, HOUR, MINUTE or SECOND passed on its own as a function argument, as in * DATEADD(day, 1, d), is a date unit. Anywhere else it is an ordinary identifier, so it is parsed as a @@ -12181,14 +12183,20 @@ Expression Condition(): Expression result; Expression left; // Leading NOT / ! prefixes, leftmost token wraps outermost (issue #1170). - final Deque exclamationMarks = new ArrayDeque(); + Deque exclamationMarks = null; int oraclePrior = EqualsTo.NO_ORACLE_PRIOR; int oracleJoin = EqualsTo.NO_ORACLE_JOIN; } { ( LOOKAHEAD({ getToken(1).kind == K_NOT || "!".equals(getToken(1).image) }) - ( { exclamationMarks.addFirst(Boolean.FALSE); } | "!" { exclamationMarks.addFirst(Boolean.TRUE); } ) + ( | "!" ) + { + if (exclamationMarks == null) { + exclamationMarks = new ArrayDeque(); + } + exclamationMarks.addFirst("!".equals(getToken(0).image)); + } )* ( LOOKAHEAD( JdbcNamedParameter() ":", { @@ -12258,7 +12266,7 @@ Expression Condition(): && result instanceof SupportsOldOracleJoinSyntax) { ((SupportsOldOracleJoinSyntax) result).setOraclePriorPosition(oraclePrior); } - while (!exclamationMarks.isEmpty()) { + while (exclamationMarks != null && !exclamationMarks.isEmpty()) { result = new NotExpression(result, exclamationMarks.pollFirst()); } return result; @@ -13192,21 +13200,29 @@ Expression PrimaryExpression() #PrimaryExpression: Token token = null; Token sign = null; Token innerSign; - List innerSigns = new ArrayList(); + List innerSigns = null; ColDataType type = null; boolean not = false; boolean exclamationMarkNot = false; boolean dateExpressionAllowed = true; ExpressionList list; - final List> jsonIdents = new ArrayList>(); + List> jsonIdents = null; } { [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] [ ( sign="+" | sign="-" | sign="~" ) // DuckDB's chained signs, e.g. - -1 or +-+1 - ( LOOKAHEAD(1) ( innerSign="+" | innerSign="-" | innerSign="~" ) { innerSigns.add(innerSign); } )* + ( + LOOKAHEAD(1) ( innerSign="+" | innerSign="-" | innerSign="~" ) + { + if (innerSigns == null) { + innerSigns = new ArrayList(); + } + innerSigns.add(innerSign); + } + )* ] ( { retval = new NullValue(); } @@ -13405,6 +13421,9 @@ Expression PrimaryExpression() #PrimaryExpression: expression=SimpleExpression() ) { + if (jsonIdents == null) { + jsonIdents = new ArrayList>(); + } jsonIdents.add(new AbstractMap.SimpleEntry(expression, token.image )); } )+ @@ -13424,8 +13443,10 @@ Expression PrimaryExpression() #PrimaryExpression: timezoneExpr.setLeftExpression(retval); retval=timezoneExpr; } - for (int i = innerSigns.size() - 1; i >= 0; i--) { - retval = new SignedExpression(innerSigns.get(i).image.charAt(0), retval); + if (innerSigns != null) { + for (int i = innerSigns.size() - 1; i >= 0; i--) { + retval = new SignedExpression(innerSigns.get(i).image.charAt(0), retval); + } } if (sign != null) { retval = new SignedExpression(sign.image.charAt(0), retval); @@ -15420,7 +15441,7 @@ ExpressionList FunctionArgumentList(Function retval): Token extraKeywordToken; } { - { if ("XMLFOREST".equalsIgnoreCase(retval.getName())) { return XmlForestArguments(); } } + { if (hasUnqualifiedName(retval, "XMLFOREST")) { return XmlForestArguments(); } } [ LOOKAHEAD(2) extraKeywordToken = { retval.setExtraKeyword(extraKeywordToken.image); } ] expressionList=ExpressionList() // explicit lookahead: InternalFunction accepts ORDER BY after IGNORE NULLS too