fix bug where parameters of cast target type were not passed along

This was yet another bug that resulted from what I've been warning about:
the use of untypesafe getChild() methods in SQB. So I've gone through and
removed even more of those, to further reduce the probability of this kind
of bug in the future.
This commit is contained in:
Gavin King 2023-07-25 13:07:26 +02:00
parent dfc282adb1
commit b53732d141
1 changed files with 129 additions and 165 deletions

View File

@ -2550,22 +2550,21 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitLikeEscape(HqlParser.LikeEscapeContext ctx) { public Object visitLikeEscape(HqlParser.LikeEscapeContext ctx) {
final ParseTree child = ctx.getChild( 1 ); final HqlParser.ParameterContext parameter = ctx.parameter();
if ( child instanceof HqlParser.NamedParameterContext ) { if ( parameter instanceof HqlParser.NamedParameterContext ) {
return visitNamedParameter( return visitNamedParameter(
(HqlParser.NamedParameterContext) child, (HqlParser.NamedParameterContext) parameter,
creationContext.getNodeBuilder().getCharacterType() creationContext.getNodeBuilder().getCharacterType()
); );
} }
else if ( child instanceof HqlParser.PositionalParameterContext ) { else if ( parameter instanceof HqlParser.PositionalParameterContext ) {
return visitPositionalParameter( return visitPositionalParameter(
(HqlParser.PositionalParameterContext) child, (HqlParser.PositionalParameterContext) parameter,
creationContext.getNodeBuilder().getCharacterType() creationContext.getNodeBuilder().getCharacterType()
); );
} }
else { else {
assert child instanceof TerminalNode; final TerminalNode terminalNode = (TerminalNode) ctx.getChild( 1 );
final TerminalNode terminalNode = (TerminalNode) child;
final String escape = unquoteStringLiteral( terminalNode.getText() ); final String escape = unquoteStringLiteral( terminalNode.getText() );
if ( escape.length() != 1 ) { if ( escape.length() != 1 ) {
throw new SemanticException( throw new SemanticException(
@ -2583,13 +2582,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmPredicate visitMemberOfPredicate(HqlParser.MemberOfPredicateContext ctx) { public SqmPredicate visitMemberOfPredicate(HqlParser.MemberOfPredicateContext ctx) {
final boolean negated = ctx.NOT() != null; final boolean negated = ctx.NOT() != null;
final SqmPath<?> sqmPluralPath = consumeDomainPath( final SqmPath<?> sqmPluralPath = consumeDomainPath( ctx.path() );
(HqlParser.PathContext) ctx.getChild( ctx.getChildCount() - 1 )
);
if ( sqmPluralPath.getReferencedPathSource() instanceof PluralPersistentAttribute ) { if ( sqmPluralPath.getReferencedPathSource() instanceof PluralPersistentAttribute ) {
return new SqmMemberOfPredicate( return new SqmMemberOfPredicate(
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ), (SqmExpression<?>) ctx.expression().accept( this ),
sqmPluralPath, sqmPluralPath,
negated, negated,
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
@ -2724,37 +2720,41 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitEntityTypeExpression(HqlParser.EntityTypeExpressionContext ctx) { public Object visitEntityTypeExpression(HqlParser.EntityTypeExpressionContext ctx) {
final ParseTree pathOrParameter = ctx.getChild( 0 ).getChild( 2 ); final HqlParser.EntityTypeReferenceContext entityTypeReferenceContext = ctx.entityTypeReference();
// can be one of 2 forms: // can be one of 2 forms:
// 1) TYPE( some.path ) // 1) TYPE( some.path )
// 2) TYPE( :someParam ) // 2) TYPE( :someParam )
if ( pathOrParameter instanceof HqlParser.ParameterContext ) { final HqlParser.ParameterContext parameter = entityTypeReferenceContext.parameter();
final HqlParser.PathContext path = entityTypeReferenceContext.path();
if ( parameter != null ) {
// we have form (2) // we have form (2)
return new SqmParameterizedEntityType<>( return new SqmParameterizedEntityType<>(
(SqmParameter<?>) pathOrParameter.accept( this ), (SqmParameter<?>) parameter.accept( this ),
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
} }
else if ( pathOrParameter instanceof HqlParser.PathContext ) { else if ( path != null ) {
// we have form (1) // we have form (1)
return ( (SqmPath<?>) pathOrParameter.accept( this ) ).type(); final SqmPath<?> sqmPath = (SqmPath<?>) path.accept( this );
return sqmPath.type();
}
else {
throw new ParsingException( "Could not interpret grammar context as entity type expression: " + ctx.getText() );
} }
throw new ParsingException( "Could not interpret grammar context as 'entity type' expression : " + ctx.getText() );
} }
@Override @Override
public SqmExpression<?> visitEntityIdExpression(HqlParser.EntityIdExpressionContext ctx) { public SqmExpression<?> visitEntityIdExpression(HqlParser.EntityIdExpressionContext ctx) {
return visitEntityIdReference( (HqlParser.EntityIdReferenceContext) ctx.getChild( 0 ) ); return visitEntityIdReference( ctx.entityIdReference() );
} }
@Override @Override
public SqmPath<?> visitEntityIdReference(HqlParser.EntityIdReferenceContext ctx) { public SqmPath<?> visitEntityIdReference(HqlParser.EntityIdReferenceContext ctx) {
if ( ctx.getChildCount() == 5 ) { if ( ctx.pathContinuation() != null ) {
throw new UnsupportedOperationException( "Path continuation from `id()` reference not yet implemented" ); throw new UnsupportedOperationException( "Path continuation from 'id()' reference not yet implemented" );
} }
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); final SqmPath<?> sqmPath = consumeDomainPath( ctx.path() );
final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType(); final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
if ( sqmPathType instanceof IdentifiableDomainType<?> ) { if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
@ -2772,12 +2772,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmExpression<?> visitEntityVersionExpression(HqlParser.EntityVersionExpressionContext ctx) { public SqmExpression<?> visitEntityVersionExpression(HqlParser.EntityVersionExpressionContext ctx) {
return visitEntityVersionReference( (HqlParser.EntityVersionReferenceContext) ctx.getChild( 0 ) ); return visitEntityVersionReference( ctx.entityVersionReference() );
} }
@Override @Override
public SqmPath<?> visitEntityVersionReference(HqlParser.EntityVersionReferenceContext ctx) { public SqmPath<?> visitEntityVersionReference(HqlParser.EntityVersionReferenceContext ctx) {
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); final SqmPath<?> sqmPath = consumeDomainPath( ctx.path() );
final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType(); final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
if ( sqmPathType instanceof IdentifiableDomainType<?> ) { if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
@ -2803,12 +2803,16 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmPath<?> visitEntityNaturalIdExpression(HqlParser.EntityNaturalIdExpressionContext ctx) { public SqmPath<?> visitEntityNaturalIdExpression(HqlParser.EntityNaturalIdExpressionContext ctx) {
return visitEntityNaturalIdReference( (HqlParser.EntityNaturalIdReferenceContext) ctx.getChild( 0 ) ); return visitEntityNaturalIdReference( ctx.entityNaturalIdReference() );
} }
@Override @Override
public SqmPath<?> visitEntityNaturalIdReference(HqlParser.EntityNaturalIdReferenceContext ctx) { public SqmPath<?> visitEntityNaturalIdReference(HqlParser.EntityNaturalIdReferenceContext ctx) {
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); if ( ctx.pathContinuation() != null ) {
throw new UnsupportedOperationException( "Path continuation from 'naturalid()' reference not yet implemented" );
}
final SqmPath<?> sqmPath = consumeDomainPath( ctx.path() );
final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType(); final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
if ( sqmPathType instanceof IdentifiableDomainType<?> ) { if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
@ -2874,7 +2878,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmMapEntryReference<?, ?> visitMapEntrySelection(HqlParser.MapEntrySelectionContext ctx) { public SqmMapEntryReference<?, ?> visitMapEntrySelection(HqlParser.MapEntrySelectionContext ctx) {
return new SqmMapEntryReference<>( return new SqmMapEntryReference<>(
consumePluralAttributeReference( (HqlParser.PathContext) ctx.getChild( 2 ) ), consumePluralAttributeReference( ctx.path() ),
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
} }
@ -2886,8 +2890,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
} }
return getFunctionDescriptor( "concat" ).generateSqmExpression( return getFunctionDescriptor( "concat" ).generateSqmExpression(
asList( asList(
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ), (SqmExpression<?>) ctx.expression( 0 ).accept( this ),
(SqmExpression<?>) ctx.getChild( 2 ).accept( this ) (SqmExpression<?>) ctx.expression( 1 ).accept( this )
), ),
null, null,
creationContext.getQueryEngine() creationContext.getQueryEngine()
@ -2986,8 +2990,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitToDurationExpression(HqlParser.ToDurationExpressionContext ctx) { public Object visitToDurationExpression(HqlParser.ToDurationExpressionContext ctx) {
return new SqmToDuration<>( return new SqmToDuration<>(
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ), (SqmExpression<?>) ctx.expression().accept( this ),
toDurationUnit( (SqmExtractUnit<?>) ctx.getChild( 1 ).accept( this ) ), toDurationUnit( (SqmExtractUnit<?>) ctx.datetimeField().accept( this ) ),
resolveExpressibleTypeBasic( Duration.class ), resolveExpressibleTypeBasic( Duration.class ),
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
@ -3037,8 +3041,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
); );
} }
final SqmExpression<?> expressionToCollate = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> expressionToCollate = (SqmExpression<?>) ctx.expression().accept( this );
final SqmCollation castTargetExpression = (SqmCollation) ctx.getChild( 4 ).accept( this ); final SqmCollation castTargetExpression = (SqmCollation) ctx.collation().accept( this );
return getFunctionDescriptor("collate").generateSqmExpression( return getFunctionDescriptor("collate").generateSqmExpression(
asList( expressionToCollate, castTargetExpression ), asList( expressionToCollate, castTargetExpression ),
@ -3050,7 +3054,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitCollation(HqlParser.CollationContext ctx) { public Object visitCollation(HqlParser.CollationContext ctx) {
return new SqmCollation( return new SqmCollation(
ctx.getChild( 0 ).getText(), ctx.simplePath().getText(),
null, null,
creationContext.getNodeBuilder() ); creationContext.getNodeBuilder() );
} }
@ -3085,61 +3089,52 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return ctx.getChild( 0 ).accept( this ); return ctx.getChild( 0 ).accept( this );
} }
@Override @Override @SuppressWarnings({"rawtypes", "unchecked"})
public SqmCaseSimple<?, ?> visitSimpleCaseList(HqlParser.SimpleCaseListContext ctx) { public SqmCaseSimple<?, ?> visitSimpleCaseList(HqlParser.SimpleCaseListContext ctx) {
final int size = ctx.getChildCount(); final int size = ctx.simpleCaseWhen().size();
//noinspection unchecked final SqmCaseSimple caseExpression = new SqmCaseSimple<>(
final SqmCaseSimple<Object, Object> caseExpression = new SqmCaseSimple<>( (SqmExpression<?>) ctx.expressionOrPredicate().accept( this ),
(SqmExpression<Object>) ctx.getChild( 1 ).accept( this ),
null, null,
size - 3, size,
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
for ( int i = 2; i < size; i++ ) { for ( int i = 0; i < size; i++ ) {
final ParseTree parseTree = ctx.getChild( i ); final HqlParser.SimpleCaseWhenContext simpleCaseWhenContext = ctx.simpleCaseWhen( i );
if ( parseTree instanceof HqlParser.SimpleCaseWhenContext ) {
//noinspection unchecked
caseExpression.when( caseExpression.when(
(SqmExpression<Object>) parseTree.getChild( 1 ).accept( this ), (SqmExpression<?>) simpleCaseWhenContext.expression().accept( this ),
(SqmExpression<Object>) parseTree.getChild( 3 ).accept( this ) (SqmExpression<?>) simpleCaseWhenContext.expressionOrPredicate().accept( this )
); );
} }
}
final ParseTree lastChild = ctx.getChild( ctx.getChildCount() - 2 ); final HqlParser.CaseOtherwiseContext caseOtherwiseContext = ctx.caseOtherwise();
if ( lastChild instanceof HqlParser.CaseOtherwiseContext ) { if ( caseOtherwiseContext != null ) {
//noinspection unchecked caseExpression.otherwise( (SqmExpression<?>) caseOtherwiseContext.expressionOrPredicate().accept( this ) );
caseExpression.otherwise( (SqmExpression<Object>) lastChild.getChild( 1 ).accept( this ) );
} }
return caseExpression; return caseExpression;
} }
@Override @Override @SuppressWarnings({"rawtypes", "unchecked"})
public SqmCaseSearched<?> visitSearchedCaseList(HqlParser.SearchedCaseListContext ctx) { public SqmCaseSearched<?> visitSearchedCaseList(HqlParser.SearchedCaseListContext ctx) {
final int size = ctx.getChildCount(); final int size = ctx.searchedCaseWhen().size();
final SqmCaseSearched<Object> caseExpression = new SqmCaseSearched<>( final SqmCaseSearched caseExpression = new SqmCaseSearched<>(
null, null,
size - 2, size,
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
for ( int i = 1; i < size; i++ ) { for ( int i = 0; i < size; i++ ) {
final ParseTree parseTree = ctx.getChild( i ); final HqlParser.SearchedCaseWhenContext searchedCaseWhenContext = ctx.searchedCaseWhen( i );
if ( parseTree instanceof HqlParser.SearchedCaseWhenContext ) {
//noinspection unchecked
caseExpression.when( caseExpression.when(
(SqmPredicate) parseTree.getChild( 1 ).accept( this ), (SqmPredicate) searchedCaseWhenContext.predicate().accept( this ),
(SqmExpression<Object>) parseTree.getChild( 3 ).accept( this ) (SqmExpression<?>) searchedCaseWhenContext.expressionOrPredicate().accept( this )
); );
} }
}
final ParseTree lastChild = ctx.getChild( ctx.getChildCount() - 2 ); final HqlParser.CaseOtherwiseContext caseOtherwiseContext = ctx.caseOtherwise();
if ( lastChild instanceof HqlParser.CaseOtherwiseContext ) { if ( caseOtherwiseContext != null ) {
//noinspection unchecked caseExpression.otherwise( (SqmExpression<?>) caseOtherwiseContext.expressionOrPredicate().accept( this ) );
caseExpression.otherwise( (SqmExpression<Object>) lastChild.getChild( 1 ).accept( this ) );
} }
return caseExpression; return caseExpression;
@ -4334,21 +4329,14 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitExtractFunction(HqlParser.ExtractFunctionContext ctx) { public Object visitExtractFunction(HqlParser.ExtractFunctionContext ctx) {
final SqmExpression<?> expressionToExtract = (SqmExpression<?>) ctx.getChild( ctx.getChildCount() - 2 )
.accept( this );
// visitDateOrTimeField() needs to know if we're extracting from a
// JDBC Timestamp or from a java.time LocalDateTime/OffsetDateTime
isExtractingJdbcTemporalType = isJdbcTemporalType( expressionToExtract.getNodeType() );
final SqmExtractUnit<?> extractFieldExpression; final SqmExtractUnit<?> extractFieldExpression;
if ( ctx.getChild( 0 ) instanceof TerminalNode ) { if ( ctx.extractField() != null ) {
//for the case of the full ANSI syntax "extract(field from arg)" //for the case of the full ANSI syntax "extract(field from arg)"
extractFieldExpression = (SqmExtractUnit<?>) ctx.getChild( 2 ).accept(this); extractFieldExpression = (SqmExtractUnit<?>) ctx.extractField().accept(this);
} }
else { else {
//for the shorter legacy Hibernate syntax "field(arg)" //for the shorter legacy Hibernate syntax "field(arg)"
extractFieldExpression = (SqmExtractUnit<?>) ctx.getChild( 0 ).accept(this); extractFieldExpression = (SqmExtractUnit<?>) ctx.datetimeField().accept(this);
// //Prefer an existing native version if available // //Prefer an existing native version if available
// final SqmFunctionDescriptor functionDescriptor = getFunctionDescriptor( extractFieldExpression.getUnit().name() ); // final SqmFunctionDescriptor functionDescriptor = getFunctionDescriptor( extractFieldExpression.getUnit().name() );
// if ( functionDescriptor != null ) { // if ( functionDescriptor != null ) {
@ -4361,6 +4349,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
// } // }
} }
final SqmExpression<?> expressionToExtract = (SqmExpression<?>) ctx.expression().accept( this );
// visitDateOrTimeField() needs to know if we're extracting from a
// JDBC Timestamp or from a java.time LocalDateTime/OffsetDateTime
isExtractingJdbcTemporalType = isJdbcTemporalType( expressionToExtract.getNodeType() );
return getFunctionDescriptor("extract").generateSqmExpression( return getFunctionDescriptor("extract").generateSqmExpression(
asList( extractFieldExpression, expressionToExtract ), asList( extractFieldExpression, expressionToExtract ),
extractFieldExpression.getType(), extractFieldExpression.getType(),
@ -4370,10 +4363,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitTruncFunction(HqlParser.TruncFunctionContext ctx) { public Object visitTruncFunction(HqlParser.TruncFunctionContext ctx) {
final SqmExpression<?> expression = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> expression = (SqmExpression<?>) ctx.expression(0).accept( this );
final SqmTypedNode<?> secondArg; final SqmTypedNode<?> secondArg;
if ( ctx.getChildCount() == 6 ) { if ( ctx.expression().size() > 1 ) {
secondArg = (SqmTypedNode<?>) ctx.getChild( 4 ).accept( this ); secondArg = (SqmTypedNode<?>) ctx.expression(1).accept( this );
}
else if ( ctx.datetimeField() != null ) {
secondArg = (SqmTypedNode<?>) ctx.datetimeField().accept( this );
} }
else { else {
secondArg = null; secondArg = null;
@ -4388,7 +4384,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitFormat(HqlParser.FormatContext ctx) { public Object visitFormat(HqlParser.FormatContext ctx) {
final String format = unquoteStringLiteral( ctx.getChild( 0 ).getText() ); final String format = unquoteStringLiteral( ctx.STRING_LITERAL().getText() );
return new SqmFormat( return new SqmFormat(
format, format,
resolveExpressibleTypeBasic( String.class ), resolveExpressibleTypeBasic( String.class ),
@ -4398,8 +4394,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmExpression<?> visitFormatFunction(HqlParser.FormatFunctionContext ctx) { public SqmExpression<?> visitFormatFunction(HqlParser.FormatFunctionContext ctx) {
final SqmExpression<?> expressionToCast = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> expressionToCast = (SqmExpression<?>) ctx.expression().accept( this );
final SqmLiteral<?> format = (SqmLiteral<?>) ctx.getChild( 4 ).accept( this ); final SqmLiteral<?> format = (SqmLiteral<?>) ctx.format().accept( this );
return getFunctionDescriptor("format").generateSqmExpression( return getFunctionDescriptor("format").generateSqmExpression(
asList( expressionToCast, format ), asList( expressionToCast, format ),
@ -4410,8 +4406,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmExpression<?> visitCastFunction(HqlParser.CastFunctionContext ctx) { public SqmExpression<?> visitCastFunction(HqlParser.CastFunctionContext ctx) {
final SqmExpression<?> expressionToCast = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> expressionToCast = (SqmExpression<?>) ctx.expression().accept( this );
final SqmCastTarget<?> castTargetExpression = (SqmCastTarget<?>) ctx.getChild( 4 ).accept( this ); final SqmCastTarget<?> castTargetExpression = (SqmCastTarget<?>) ctx.castTarget().accept( this );
return getFunctionDescriptor("cast").generateSqmExpression( return getFunctionDescriptor("cast").generateSqmExpression(
asList( expressionToCast, castTargetExpression ), asList( expressionToCast, castTargetExpression ),
@ -4422,20 +4418,14 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmCastTarget<?> visitCastTarget(HqlParser.CastTargetContext castTargetContext) { public SqmCastTarget<?> visitCastTarget(HqlParser.CastTargetContext castTargetContext) {
final HqlParser.CastTargetTypeContext castTargetTypeContext = (HqlParser.CastTargetTypeContext) castTargetContext.getChild( 0 ); final HqlParser.CastTargetTypeContext castTargetTypeContext = castTargetContext.castTargetType();
final String targetName = castTargetTypeContext.fullTargetName; final String targetName = castTargetTypeContext.fullTargetName;
Long length = null; final TerminalNode firstArg = castTargetContext.INTEGER_LITERAL(0);
Integer precision = null; final TerminalNode secondArg = castTargetContext.INTEGER_LITERAL(1);
Integer scale = null; final Long length = firstArg == null ? null : Long.valueOf( firstArg.getText() );
switch ( castTargetTypeContext.getChildCount() ) { final Integer precision = firstArg == null ? null : Integer.valueOf( firstArg.getText() );
case 6: final Integer scale = secondArg == null ? null : Integer.valueOf( secondArg.getText() );
scale = Integer.valueOf( castTargetTypeContext.getChild( 4 ).getText() );
case 4:
length = Long.valueOf( castTargetTypeContext.getChild( 2 ).getText() );
precision = length.intValue();
break;
}
return new SqmCastTarget<>( return new SqmCastTarget<>(
(ReturnableType<?>) (ReturnableType<?>)
@ -4451,8 +4441,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitPositionFunction(HqlParser.PositionFunctionContext ctx) { public Object visitPositionFunction(HqlParser.PositionFunctionContext ctx) {
final SqmExpression<?> pattern = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> pattern = (SqmExpression<?>) ctx.positionFunctionPatternArgument().accept( this );
final SqmExpression<?> string = (SqmExpression<?>) ctx.getChild( 4 ).accept( this ); final SqmExpression<?> string = (SqmExpression<?>) ctx.positionFunctionStringArgument().accept( this );
return getFunctionDescriptor("position").generateSqmExpression( return getFunctionDescriptor("position").generateSqmExpression(
asList( pattern, string ), asList( pattern, string ),
@ -4463,16 +4453,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public Object visitOverlayFunction(HqlParser.OverlayFunctionContext ctx) { public Object visitOverlayFunction(HqlParser.OverlayFunctionContext ctx) {
final SqmExpression<?> string = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> string = (SqmExpression<?>) ctx.overlayFunctionStringArgument().accept( this );
final SqmExpression<?> replacement = (SqmExpression<?>) ctx.getChild( 4 ).accept( this ); final SqmExpression<?> replacement = (SqmExpression<?>) ctx.overlayFunctionReplacementArgument().accept( this );
final SqmExpression<?> start = (SqmExpression<?>) ctx.getChild( 6 ).accept( this ); final SqmExpression<?> start = (SqmExpression<?>) ctx.overlayFunctionStartArgument().accept( this );
final SqmExpression<?> length; final SqmExpression<?> length = ctx.overlayFunctionLengthArgument() != null
if ( ctx.getChildCount() == 10 ) { ? (SqmExpression<?>) ctx.overlayFunctionLengthArgument().accept( this )
length = (SqmExpression<?>) ctx.getChild( 8 ).accept( this ); : null;
}
else {
length = null;
}
return getFunctionDescriptor("overlay").generateSqmExpression( return getFunctionDescriptor("overlay").generateSqmExpression(
length == null length == null
@ -4772,15 +4758,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmExpression<?> visitSubstringFunction(HqlParser.SubstringFunctionContext ctx) { public SqmExpression<?> visitSubstringFunction(HqlParser.SubstringFunctionContext ctx) {
final SqmExpression<?> source = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> source = (SqmExpression<?>) ctx.expression().accept( this );
final SqmExpression<?> start = (SqmExpression<?>) ctx.getChild( 4 ).accept( this ); final SqmExpression<?> start = (SqmExpression<?>) ctx.substringFunctionStartArgument().accept( this );
final SqmExpression<?> length; final SqmExpression<?> length = ctx.substringFunctionLengthArgument() != null
if ( ctx.getChildCount() == 8 ) { ? (SqmExpression<?>) ctx.substringFunctionLengthArgument().accept( this )
length = (SqmExpression<?>) ctx.getChild( 6 ).accept( this ); : null;
}
else {
length = null;
}
return getFunctionDescriptor("substring").generateSqmExpression( return getFunctionDescriptor("substring").generateSqmExpression(
length == null ? asList( source, start ) : asList( source, start, length ), length == null ? asList( source, start ) : asList( source, start, length ),
@ -4791,16 +4773,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmExpression<?> visitPadFunction(HqlParser.PadFunctionContext ctx) { public SqmExpression<?> visitPadFunction(HqlParser.PadFunctionContext ctx) {
final SqmExpression<?> source = (SqmExpression<?>) ctx.getChild( 2 ).accept( this ); final SqmExpression<?> source = (SqmExpression<?>) ctx.expression().accept( this );
final SqmExpression<?> length = (SqmExpression<?>) ctx.getChild( 4 ).accept(this); final SqmExpression<?> length = (SqmExpression<?>) ctx.padLength().accept(this);
final SqmTrimSpecification padSpec = visitPadSpecification( (HqlParser.PadSpecificationContext) ctx.getChild( 5 ) ); final SqmTrimSpecification padSpec = visitPadSpecification( ctx.padSpecification() );
final SqmLiteral<Character> padChar; final SqmLiteral<Character> padChar = ctx.padCharacter() != null
if ( ctx.getChildCount() == 8 ) { ? visitPadCharacter( ctx.padCharacter() )
padChar = visitPadCharacter( (HqlParser.PadCharacterContext) ctx.getChild( 6 ) ); : null;
}
else {
padChar = null;
}
return getFunctionDescriptor("pad").generateSqmExpression( return getFunctionDescriptor("pad").generateSqmExpression(
padChar != null padChar != null
? asList( source, length, padSpec, padChar ) ? asList( source, length, padSpec, padChar )
@ -4838,25 +4817,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmExpression<?> visitTrimFunction(HqlParser.TrimFunctionContext ctx) { public SqmExpression<?> visitTrimFunction(HqlParser.TrimFunctionContext ctx) {
final SqmExpression<?> source = (SqmExpression<?>) ctx.getChild( ctx.getChildCount() - 2 ).accept( this ); final SqmExpression<?> source = (SqmExpression<?>) ctx.expression().accept( this );
final SqmTrimSpecification trimSpec; final SqmTrimSpecification trimSpec = visitTrimSpecification( ctx.trimSpecification() );;
final SqmLiteral<Character> trimChar; final SqmLiteral<Character> trimChar = visitTrimCharacter( ctx.trimCharacter() );
int index = 2;
ParseTree parseTree = ctx.getChild( index );
if ( parseTree instanceof HqlParser.TrimSpecificationContext ) {
trimSpec = visitTrimSpecification( (HqlParser.TrimSpecificationContext) parseTree );
index = 3;
}
else {
trimSpec = visitTrimSpecification( null );
}
parseTree = ctx.getChild( index );
if ( parseTree instanceof HqlParser.TrimCharacterContext ) {
trimChar = visitTrimCharacter( (HqlParser.TrimCharacterContext) parseTree );
}
else {
trimChar = visitTrimCharacter( null );
}
return getFunctionDescriptor("trim").generateSqmExpression( return getFunctionDescriptor("trim").generateSqmExpression(
asList( asList(
@ -4871,22 +4834,24 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override @Override
public SqmTrimSpecification visitTrimSpecification(HqlParser.TrimSpecificationContext ctx) { public SqmTrimSpecification visitTrimSpecification(HqlParser.TrimSpecificationContext ctx) {
TrimSpec spec = TrimSpec.BOTH; // JPA says the default is BOTH // JPA says the default is BOTH
final TrimSpec spec = ctx != null ? trimSpec( ctx ) : TrimSpec.BOTH;
return new SqmTrimSpecification( spec, creationContext.getNodeBuilder() );
}
if ( ctx != null ) { private static TrimSpec trimSpec(HqlParser.TrimSpecificationContext ctx) {
switch ( ( (TerminalNode) ctx.getChild( 0 ) ).getSymbol().getType() ) { switch ( ( (TerminalNode) ctx.getChild( 0 ) ).getSymbol().getType() ) {
case HqlParser.LEADING: case HqlParser.LEADING:
spec = TrimSpec.LEADING; return TrimSpec.LEADING;
break;
case HqlParser.TRAILING: case HqlParser.TRAILING:
spec = TrimSpec.TRAILING; return TrimSpec.TRAILING;
break; case HqlParser.BOTH:
return TrimSpec.BOTH;
default:
throw new ParsingException( "Unrecognized trim specification" );
} }
} }
return new SqmTrimSpecification( spec, creationContext.getNodeBuilder() );
}
@Override @Override
public SqmLiteral<Character> visitTrimCharacter(HqlParser.TrimCharacterContext ctx) { public SqmLiteral<Character> visitTrimCharacter(HqlParser.TrimCharacterContext ctx) {
final String trimCharText = ctx != null final String trimCharText = ctx != null
@ -4913,7 +4878,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
); );
} }
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isIndexedPluralAttribute(SqmPath<?> path) { private boolean isIndexedPluralAttribute(SqmPath<?> path) {
return path.getReferencedPathSource() instanceof PluralPersistentAttribute; return path.getReferencedPathSource() instanceof PluralPersistentAttribute;
} }