diff --git a/core/parser/src/main/java/com/blazebit/persistence/parser/expression/AbstractExpressionFactory.java b/core/parser/src/main/java/com/blazebit/persistence/parser/expression/AbstractExpressionFactory.java index 24eef1ea0e..ac03920d3b 100644 --- a/core/parser/src/main/java/com/blazebit/persistence/parser/expression/AbstractExpressionFactory.java +++ b/core/parser/src/main/java/com/blazebit/persistence/parser/expression/AbstractExpressionFactory.java @@ -20,6 +20,7 @@ import com.blazebit.persistence.parser.JPQLNextParser; import com.blazebit.persistence.parser.predicate.Predicate; import org.antlr.v4.runtime.ANTLRErrorListener; +import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Parser; @@ -157,7 +158,8 @@ private Expression createExpression(RuleInvoker ruleInvoker, String expression, if (expression.isEmpty()) { throw new IllegalArgumentException("expression"); } - JPQLNextLexer l = new JPQLNextLexer(CharStreams.fromString(expression)); + CharStream inputCharStream = CharStreams.fromString(expression); + JPQLNextLexer l = new JPQLNextLexer(inputCharStream); configureLexer(l); CommonTokenStream tokens = new CommonTokenStream(l); JPQLNextParser p = new JPQLNextParser(tokens); @@ -182,7 +184,7 @@ private Expression createExpression(RuleInvoker ruleInvoker, String expression, LOG.finest(ctx.toStringTree()); } - JPQLNextExpressionVisitorImpl visitor = new JPQLNextExpressionVisitorImpl(functions, enumTypes, entityTypes, minEnumSegmentCount, minEntitySegmentCount, macroConfiguration == null ? Collections.EMPTY_MAP : macroConfiguration.macros, usedMacros, allowOuter, allowQuantifiedPredicates, allowObjectExpression); + JPQLNextExpressionVisitorImpl visitor = new JPQLNextExpressionVisitorImpl(functions, enumTypes, entityTypes, minEnumSegmentCount, minEntitySegmentCount, macroConfiguration == null ? Collections.EMPTY_MAP : macroConfiguration.macros, usedMacros, allowOuter, allowQuantifiedPredicates, allowObjectExpression, inputCharStream); Expression parsedExpression = visitor.visit(ctx); if (optimize) { parsedExpression = parsedExpression.accept(optimizer); diff --git a/core/parser/src/main/java/com/blazebit/persistence/parser/expression/JPQLNextExpressionVisitorImpl.java b/core/parser/src/main/java/com/blazebit/persistence/parser/expression/JPQLNextExpressionVisitorImpl.java index c2d6f45ca0..cd6eeb6e77 100644 --- a/core/parser/src/main/java/com/blazebit/persistence/parser/expression/JPQLNextExpressionVisitorImpl.java +++ b/core/parser/src/main/java/com/blazebit/persistence/parser/expression/JPQLNextExpressionVisitorImpl.java @@ -36,8 +36,10 @@ import com.blazebit.persistence.parser.predicate.Predicate; import com.blazebit.persistence.parser.predicate.PredicateQuantifier; import com.blazebit.persistence.parser.util.TypeUtils; +import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.tree.ErrorNode; import org.antlr.v4.runtime.tree.TerminalNode; @@ -65,8 +67,9 @@ public class JPQLNextExpressionVisitorImpl extends JPQLNextParserBaseVisitor functions, Map>> enums, Map> entities, int minEnumSegmentCount, int minEntitySegmentCount, Map macros, Set usedMacros, boolean allowOuter, boolean allowQuantifiedPredicates, boolean allowObjectExpression) { + public JPQLNextExpressionVisitorImpl(Map functions, Map>> enums, Map> entities, int minEnumSegmentCount, int minEntitySegmentCount, Map macros, Set usedMacros, boolean allowOuter, boolean allowQuantifiedPredicates, boolean allowObjectExpression, CharStream input) { this.functions = functions; this.enums = enums; this.entities = entities; @@ -77,6 +80,7 @@ public JPQLNextExpressionVisitorImpl(Map functions, MapemptyList()); case "outer": if (!allowOuter) { - throw new SyntaxErrorException("Invalid disallowed use of OUTER in: " + ctx.getText()); + throw new SyntaxErrorException("Invalid disallowed use of OUTER in: " + getInputText(ctx)); } case "concat": case "substring": @@ -443,13 +447,13 @@ private Expression handleMacro(String name, List arguments, ParserRu try { return macro.apply(arguments); } catch (RuntimeException ex) { - throw new IllegalArgumentException("Could not apply the macro for the expression: " + ctx.getText(), ex); + throw new IllegalArgumentException("Could not apply the macro for the expression: " + getInputText(ctx), ex); } } private void failDistinct(boolean distinct, ParserRuleContext ctx) { if (distinct) { - throw new SyntaxErrorException("Invalid use of DISTINCT for function: " + ctx.getText()); + throw new SyntaxErrorException("Invalid use of DISTINCT for function: " + getInputText(ctx)); } } @@ -575,7 +579,7 @@ private OrderByItem createOrderByItem(JPQLNextParser.OrderByItemContext ctx) { boolean asc = true; boolean nullsFirst = true; if (ctx.STRING_LITERAL() != null) { - throw new SyntaxErrorException("Collations are not yet supported: " + ctx.getText()); + throw new SyntaxErrorException("Collations are not yet supported: " + getInputText(ctx)); } if (ctx.DESC() != null) { asc = false; @@ -593,10 +597,10 @@ public Expression visitPathExpression(JPQLNextParser.PathExpressionContext ctx) if (expression instanceof PathExpression) { List expressions = ((PathExpression) expression).getExpressions(); if (expressions.size() == 1 && expressions.get(0) instanceof TreatExpression) { - throw new SyntaxErrorException("A top level treat expression is not allowed. Consider to further dereference the expression: " + ctx.getText()); + throw new SyntaxErrorException("A top level treat expression is not allowed. Consider to further dereference the expression: " + getInputText(ctx)); } } else if (expression instanceof TreatExpression) { - throw new SyntaxErrorException("A top level treat expression is not allowed. Consider to further dereference the expression: " + ctx.getText()); + throw new SyntaxErrorException("A top level treat expression is not allowed. Consider to further dereference the expression: " + getInputText(ctx)); } } return expression; @@ -870,7 +874,7 @@ public Expression visitQuantifiedSimpleGreaterThanOrEqualPredicate(JPQLNextParse private void failQuantified(ParserRuleContext ctx, Token qualifier) { if (qualifier != null && !allowQuantifiedPredicates) { - throw new SyntaxErrorException("The use of quantifiers is not allowed in the context of the expression: " + ctx.getText()); + throw new SyntaxErrorException("The use of quantifiers is not allowed in the context of the expression: " + getInputText(ctx)); } } @@ -948,7 +952,7 @@ public Expression visitLikePredicate(JPQLNextParser.LikePredicateContext ctx) { if (expression instanceof LiteralExpression) { escapeCharacter = ((LiteralExpression) expression).getValue().toString().charAt(0); } else { - throw new SyntaxErrorException("Only a character literal is allowed as escape character in like predicate: " + ctx.getText()); + throw new SyntaxErrorException("Only a character literal is allowed as escape character in like predicate: " + getInputText(ctx)); } } return new LikePredicate( @@ -1026,4 +1030,11 @@ private Expression createEntityTypeLiteral(String entityLiteralStr) { } return new EntityLiteral(entityType, entityLiteralStr); } + + private String getInputText(ParserRuleContext ctx) { + int from = ctx.start.getStartIndex(); + int to = ctx.stop.getStopIndex(); + Interval interval = new Interval(from,to); + return input.getText(interval); + } } diff --git a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/metamodel/AbstractAttribute.java b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/metamodel/AbstractAttribute.java index b96d718833..a070e58dc1 100644 --- a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/metamodel/AbstractAttribute.java +++ b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/metamodel/AbstractAttribute.java @@ -392,7 +392,7 @@ public Map getCollectionJoinMappings(ManagedType managedType return Collections.emptyMap(); } - context.getTypeValidationExpressionFactory().createSimpleExpression(expression, false).accept(visitor); + context.getTypeValidationExpressionFactory().createSimpleExpression(expression, false, false, true).accept(visitor); Map mappings = new HashMap<>(); boolean aggregate = getAttributeType() == AttributeType.SINGULAR; @@ -589,7 +589,7 @@ private static void validateTypesCompatible(ManagedType managedType, String e ScalarTargetResolvingExpressionVisitor visitor = new ScalarTargetResolvingExpressionVisitor(managedType, context.getEntityMetamodel(), context.getJpqlFunctions()); try { - context.getTypeValidationExpressionFactory().createSimpleExpression(expression, false).accept(visitor); + context.getTypeValidationExpressionFactory().createSimpleExpression(expression, false, false, true).accept(visitor); } catch (SyntaxErrorException ex) { context.addError("Syntax error in " + expressionLocation + " '" + expression + "' of the " + location + ": " + ex.getMessage()); } catch (IllegalArgumentException ex) { diff --git a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/mapper/TupleElementMapperBuilder.java b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/mapper/TupleElementMapperBuilder.java index 9497514cda..c4dac4244d 100644 --- a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/mapper/TupleElementMapperBuilder.java +++ b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/mapper/TupleElementMapperBuilder.java @@ -191,7 +191,7 @@ private void applyMapping(StringBuilder sb, String prefixParts, String mapping, return; } if (prefixParts != null && !prefixParts.isEmpty()) { - Expression expr = ef.createSimpleExpression(mapping, false); + Expression expr = ef.createSimpleExpression(mapping, false, false, true); EmbeddingViewJpqlMacro embeddingViewJpqlMacro = (EmbeddingViewJpqlMacro) ef.getDefaultMacroConfiguration().get("EMBEDDING_VIEW").getState()[0]; SimpleQueryGenerator generator = new PrefixingQueryGenerator(Collections.singletonList(prefixParts), embeddingViewJpqlMacro.getEmbeddingViewPath(), CorrelatedSubqueryEmbeddingViewJpqlMacro.CORRELATION_EMBEDDING_VIEW_ALIAS, skippedAlias); generator.setQueryBuffer(sb);