Cleanup the grammar and generify same-structured function rules
This commit is contained in:
parent
07ec4f208d
commit
be485796b1
|
@ -242,6 +242,10 @@ void runBuildOnNode(String label, Closure body) {
|
|||
timeout( [time: 90, unit: 'MINUTES'], body )
|
||||
}
|
||||
finally {
|
||||
// If this is a PR, we clean the workspace at the end
|
||||
if ( env.CHANGE_BRANCH != null ) {
|
||||
cleanWs()
|
||||
}
|
||||
pruneDockerContainers()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -525,26 +525,6 @@ searchedCaseWhen
|
|||
: WHEN predicate THEN expression
|
||||
;
|
||||
|
||||
greatestFunction
|
||||
: GREATEST LEFT_PAREN expression (COMMA expression)+ RIGHT_PAREN
|
||||
;
|
||||
|
||||
leastFunction
|
||||
: LEAST LEFT_PAREN expression (COMMA expression)+ RIGHT_PAREN
|
||||
;
|
||||
|
||||
coalesceFunction
|
||||
: COALESCE LEFT_PAREN expression (COMMA expression)+ RIGHT_PAREN
|
||||
;
|
||||
|
||||
ifnullFunction
|
||||
: IFNULL LEFT_PAREN expression COMMA expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
nullifFunction
|
||||
: NULLIF LEFT_PAREN expression COMMA expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
literal
|
||||
: STRING_LITERAL
|
||||
| INTEGER_LITERAL
|
||||
|
@ -652,7 +632,7 @@ function
|
|||
| jpaCollectionFunction
|
||||
| hqlCollectionFunction
|
||||
| jpaNonStandardFunction
|
||||
| nonStandardFunction
|
||||
| genericFunction
|
||||
;
|
||||
|
||||
jpaNonStandardFunction
|
||||
|
@ -663,16 +643,16 @@ jpaNonStandardFunctionName
|
|||
: STRING_LITERAL
|
||||
;
|
||||
|
||||
nonStandardFunction
|
||||
: nonStandardFunctionName LEFT_PAREN nonStandardFunctionArguments? RIGHT_PAREN
|
||||
genericFunction
|
||||
: genericFunctionName LEFT_PAREN (nonStandardFunctionArguments | ASTERISK)? RIGHT_PAREN filterClause?
|
||||
;
|
||||
|
||||
nonStandardFunctionName
|
||||
genericFunctionName
|
||||
: dotIdentifierSequence
|
||||
;
|
||||
|
||||
nonStandardFunctionArguments
|
||||
: (datetimeField COMMA)? expression (COMMA expression)*
|
||||
: (DISTINCT | datetimeField COMMA)? expression (COMMA expression)*
|
||||
;
|
||||
|
||||
jpaCollectionFunction
|
||||
|
@ -688,35 +668,10 @@ hqlCollectionFunction
|
|||
;
|
||||
|
||||
aggregateFunction
|
||||
: avgFunction
|
||||
| sumFunction
|
||||
| minFunction
|
||||
| maxFunction
|
||||
| countFunction
|
||||
| everyFunction
|
||||
: everyFunction
|
||||
| anyFunction
|
||||
;
|
||||
|
||||
avgFunction
|
||||
: AVG LEFT_PAREN DISTINCT? expression RIGHT_PAREN filterClause?
|
||||
;
|
||||
|
||||
sumFunction
|
||||
: SUM LEFT_PAREN DISTINCT? expression RIGHT_PAREN filterClause?
|
||||
;
|
||||
|
||||
minFunction
|
||||
: MIN LEFT_PAREN DISTINCT? expression RIGHT_PAREN filterClause?
|
||||
;
|
||||
|
||||
maxFunction
|
||||
: MAX LEFT_PAREN DISTINCT? expression RIGHT_PAREN filterClause?
|
||||
;
|
||||
|
||||
countFunction
|
||||
: COUNT LEFT_PAREN DISTINCT? (expression | ASTERISK) RIGHT_PAREN filterClause?
|
||||
;
|
||||
|
||||
everyFunction
|
||||
: (EVERY|ALL) LEFT_PAREN predicate RIGHT_PAREN filterClause?
|
||||
| (EVERY|ALL) LEFT_PAREN subQuery RIGHT_PAREN
|
||||
|
@ -736,38 +691,12 @@ filterClause
|
|||
standardFunction
|
||||
: castFunction
|
||||
| extractFunction
|
||||
| coalesceFunction
|
||||
| nullifFunction
|
||||
| ifnullFunction
|
||||
| formatFunction
|
||||
| concatFunction
|
||||
| substringFunction
|
||||
| leftFunction
|
||||
| rightFunction
|
||||
| overlayFunction
|
||||
| replaceFunction
|
||||
| trimFunction
|
||||
| padFunction
|
||||
| upperFunction
|
||||
| lowerFunction
|
||||
| locateFunction
|
||||
| positionFunction
|
||||
| lengthFunction
|
||||
| absFunction
|
||||
| signFunction
|
||||
| sqrtFunction
|
||||
| lnFunction
|
||||
| expFunction
|
||||
| modFunction
|
||||
| powerFunction
|
||||
| ceilingFunction
|
||||
| floorFunction
|
||||
| roundFunction
|
||||
| trigFunction
|
||||
| atan2Function
|
||||
| strFunction
|
||||
| greatestFunction
|
||||
| leastFunction
|
||||
| currentDateFunction
|
||||
| currentTimeFunction
|
||||
| currentTimestampFunction
|
||||
|
@ -797,17 +726,6 @@ castTargetType
|
|||
: (i=identifier { $fullTargetName = _localctx.i.getText(); }) (DOT c=identifier { $fullTargetName += ("." + _localctx.c.getText() ); })*
|
||||
;
|
||||
|
||||
concatFunction
|
||||
: CONCAT LEFT_PAREN expression (COMMA expression)+ RIGHT_PAREN
|
||||
;
|
||||
|
||||
leftFunction
|
||||
: LEFT LEFT_PAREN expression COMMA expression RIGHT_PAREN
|
||||
;
|
||||
rightFunction
|
||||
: RIGHT LEFT_PAREN expression COMMA expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
substringFunction
|
||||
: SUBSTRING LEFT_PAREN expression COMMA substringFunctionStartArgument (COMMA substringFunctionLengthArgument)? RIGHT_PAREN
|
||||
| SUBSTRING LEFT_PAREN expression FROM substringFunctionStartArgument (FOR substringFunctionLengthArgument)? RIGHT_PAREN
|
||||
|
@ -852,30 +770,6 @@ padLength
|
|||
: expression
|
||||
;
|
||||
|
||||
upperFunction
|
||||
: UPPER LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
lowerFunction
|
||||
: LOWER LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
locateFunction
|
||||
: LOCATE LEFT_PAREN locateFunctionPatternArgument COMMA locateFunctionStringArgument (COMMA locateFunctionStartArgument)? RIGHT_PAREN
|
||||
;
|
||||
|
||||
locateFunctionPatternArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
locateFunctionStringArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
locateFunctionStartArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
overlayFunction
|
||||
: OVERLAY LEFT_PAREN overlayFunctionStringArgument PLACING overlayFunctionReplacementArgument FROM overlayFunctionStartArgument (FOR overlayFunctionLengthArgument)? RIGHT_PAREN
|
||||
;
|
||||
|
@ -896,108 +790,6 @@ overlayFunctionLengthArgument
|
|||
: expression
|
||||
;
|
||||
|
||||
replaceFunction
|
||||
: REPLACE LEFT_PAREN replaceFunctionStringArgument COMMA replaceFunctionPatternArgument COMMA replaceFunctionReplacementArgument RIGHT_PAREN
|
||||
;
|
||||
|
||||
replaceFunctionStringArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
replaceFunctionPatternArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
replaceFunctionReplacementArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
lengthFunction
|
||||
: LENGTH LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
absFunction
|
||||
: ABS LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
signFunction
|
||||
: SIGN LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
sqrtFunction
|
||||
: SQRT LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
lnFunction
|
||||
: LN LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
expFunction
|
||||
: EXP LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
powerFunction
|
||||
: POWER LEFT_PAREN powerBaseArgument COMMA powerPowerArgument RIGHT_PAREN
|
||||
;
|
||||
|
||||
powerBaseArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
powerPowerArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
modFunction
|
||||
: MOD LEFT_PAREN modDividendArgument COMMA modDivisorArgument RIGHT_PAREN
|
||||
;
|
||||
|
||||
modDividendArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
modDivisorArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
ceilingFunction
|
||||
: CEILING LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
floorFunction
|
||||
: FLOOR LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
roundFunction
|
||||
: ROUND LEFT_PAREN expression COMMA roundFunctionPrecision RIGHT_PAREN
|
||||
;
|
||||
|
||||
roundFunctionPrecision
|
||||
: expression
|
||||
;
|
||||
|
||||
trigFunction
|
||||
: trigFunctionName LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
trigFunctionName
|
||||
: COS
|
||||
| SIN
|
||||
| TAN
|
||||
| ACOS
|
||||
| ASIN
|
||||
| ATAN
|
||||
//ATAN2 is different!
|
||||
;
|
||||
|
||||
atan2Function
|
||||
: ATAN2 LEFT_PAREN expression COMMA expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
strFunction
|
||||
: STR LEFT_PAREN expression RIGHT_PAREN
|
||||
;
|
||||
|
||||
currentDateFunction
|
||||
: CURRENT_DATE (LEFT_PAREN RIGHT_PAREN)?
|
||||
| CURRENT DATE
|
||||
|
@ -1125,16 +917,19 @@ rollup
|
|||
identifier
|
||||
: IDENTIFIER
|
||||
| (ABS
|
||||
| ACOS
|
||||
| ALL
|
||||
| AND
|
||||
| ANY
|
||||
| AS
|
||||
| ASC
|
||||
| ASIN
|
||||
| ATAN
|
||||
| ATAN2
|
||||
| AVG
|
||||
| BY
|
||||
| BETWEEN
|
||||
| BOTH
|
||||
| BY
|
||||
| CASE
|
||||
| CAST
|
||||
| CEILING
|
||||
|
@ -1142,15 +937,16 @@ identifier
|
|||
| COALESCE
|
||||
| COLLATE
|
||||
| CONCAT
|
||||
| COS
|
||||
| COUNT
|
||||
| CROSS
|
||||
| CURRENT_DATE
|
||||
| CURRENT_INSTANT
|
||||
| CURRENT_TIME
|
||||
| CURRENT_TIMESTAMP
|
||||
| DAY
|
||||
| DATE
|
||||
| DAY
|
||||
| DAY
|
||||
| DELETE
|
||||
| DESC
|
||||
| DISTINCT
|
||||
|
@ -1159,17 +955,17 @@ identifier
|
|||
| EMPTY
|
||||
| END
|
||||
| ENTRY
|
||||
| EVERY
|
||||
| ESCAPE
|
||||
| EVERY
|
||||
| EXISTS
|
||||
| EXP
|
||||
| EXTRACT
|
||||
| FETCH
|
||||
| FILTER
|
||||
| FLOOR
|
||||
| FROM
|
||||
| FOR
|
||||
| FORMAT
|
||||
| FROM
|
||||
| FULL
|
||||
| FUNCTION
|
||||
| GREATEST
|
||||
|
@ -1202,13 +998,13 @@ identifier
|
|||
| MAXELEMENT
|
||||
| MAXINDEX
|
||||
| MEMBER
|
||||
| MEMBER
|
||||
| MICROSECOND
|
||||
| MILLISECOND
|
||||
| MIN
|
||||
| MINELEMENT
|
||||
| MININDEX
|
||||
| MINUTE
|
||||
| MEMBER
|
||||
| MOD
|
||||
| MONTH
|
||||
| NANOSECOND
|
||||
|
@ -1228,18 +1024,20 @@ identifier
|
|||
| QUARTER
|
||||
| REPLACE
|
||||
| RIGHT
|
||||
| ROUND
|
||||
| RIGHT
|
||||
| ROUND
|
||||
| SECOND
|
||||
| SELECT
|
||||
| SET
|
||||
| SIGN
|
||||
| SIN
|
||||
| SIZE
|
||||
| SOME
|
||||
| SQRT
|
||||
| STR
|
||||
| SUBSTRING
|
||||
| SUM
|
||||
| TAN
|
||||
| THEN
|
||||
| TIME
|
||||
| TIMESTAMP
|
||||
|
@ -1257,8 +1055,7 @@ identifier
|
|||
| WEEK
|
||||
| WHERE
|
||||
| WITH
|
||||
| YEAR
|
||||
| trigFunctionName) {
|
||||
| YEAR) {
|
||||
logUseOfReservedWordAsIdentifier( getCurrentToken() );
|
||||
}
|
||||
;
|
||||
|
|
|
@ -64,6 +64,8 @@ import java.sql.Types;
|
|||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
|
||||
|
||||
/**
|
||||
* Hibernate Dialect for Apache Derby / Cloudscape 10
|
||||
*
|
||||
|
@ -203,8 +205,8 @@ public class DerbyDialect extends Dialect {
|
|||
CommonFunctionFactory.power_expLn( queryEngine );
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "round", "floor(?1*1e?2+0.5)/1e?2")
|
||||
.setReturnTypeResolver( useArgType(1) )
|
||||
.setExactArgumentCount( 2 )
|
||||
.setInvariantType( StandardBasicTypes.DOUBLE )
|
||||
.register();
|
||||
|
||||
//no way I can see to pad with anything other than spaces
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.dialect.function;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.FunctionKind;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -27,7 +28,7 @@ public class CaseWhenEveryAnyEmulation extends AbstractSqmSelfRenderingFunctionD
|
|||
public CaseWhenEveryAnyEmulation(boolean every) {
|
||||
super(
|
||||
every ? "every" : "any",
|
||||
true,
|
||||
FunctionKind.AGGREGATE,
|
||||
StandardArgumentsValidators.exactly( 1 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.BOOLEAN )
|
||||
);
|
||||
|
|
|
@ -47,7 +47,7 @@ public class CastStrEmulation
|
|||
asList(
|
||||
argument,
|
||||
new SqmCastTarget<>(
|
||||
impliedResultType,
|
||||
StandardBasicTypes.STRING,
|
||||
argument.nodeBuilder()
|
||||
)
|
||||
),
|
||||
|
|
|
@ -16,6 +16,9 @@ import java.util.function.Supplier;
|
|||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
|
@ -1612,6 +1615,7 @@ public class CommonFunctionFactory {
|
|||
|
||||
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("power")
|
||||
.setExactArgumentCount(2)
|
||||
.setReturnTypeResolver( new PowerReturnTypeResolver() )
|
||||
.register();
|
||||
}
|
||||
|
||||
|
@ -1625,7 +1629,7 @@ public class CommonFunctionFactory {
|
|||
public static void power_expLn(QueryEngine queryEngine) {
|
||||
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "power", "exp(ln(?1)*?2)")
|
||||
.setExactArgumentCount( 2 )
|
||||
.setInvariantType( StandardBasicTypes.DOUBLE )
|
||||
.setReturnTypeResolver( new PowerReturnTypeResolver() )
|
||||
.register();
|
||||
}
|
||||
|
||||
|
@ -1863,4 +1867,45 @@ public class CommonFunctionFactory {
|
|||
.register();
|
||||
}
|
||||
|
||||
private static class PowerReturnTypeResolver implements FunctionReturnTypeResolver {
|
||||
|
||||
@Override
|
||||
public AllowableFunctionReturnType<?> resolveFunctionReturnType(
|
||||
AllowableFunctionReturnType<?> impliedType,
|
||||
List<? extends SqmTypedNode<?>> arguments,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
final JdbcMapping baseType = StandardFunctionReturnTypeResolvers
|
||||
.extractArgumentJdbcMapping( typeConfiguration, arguments, 1 );
|
||||
final JdbcMapping powerType = StandardFunctionReturnTypeResolvers
|
||||
.extractArgumentJdbcMapping( typeConfiguration, arguments, 2 );
|
||||
|
||||
if ( baseType.getJdbcTypeDescriptor().isDecimal() ) {
|
||||
return (AllowableFunctionReturnType<?>) arguments.get( 0 ).getNodeType();
|
||||
}
|
||||
else if ( powerType.getJdbcTypeDescriptor().isDecimal() ) {
|
||||
return (AllowableFunctionReturnType<?>) arguments.get( 1 ).getNodeType();
|
||||
}
|
||||
return typeConfiguration.getBasicTypeForJavaType( Double.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValuedMapping resolveFunctionReturnType(
|
||||
Supplier<BasicValuedMapping> impliedTypeAccess, List<? extends SqlAstNode> arguments) {
|
||||
final BasicValuedMapping baseMapping = StandardFunctionReturnTypeResolvers.extractArgumentValuedMapping(
|
||||
arguments,
|
||||
1
|
||||
);
|
||||
final BasicValuedMapping powerMapping = StandardFunctionReturnTypeResolvers.extractArgumentValuedMapping(
|
||||
arguments,
|
||||
2
|
||||
);
|
||||
if ( baseMapping.getJdbcMapping().getJdbcTypeDescriptor().isDecimal() ) {
|
||||
return baseMapping;
|
||||
}
|
||||
else if ( powerMapping.getJdbcMapping().getJdbcTypeDescriptor().isDecimal() ) {
|
||||
return powerMapping;
|
||||
}
|
||||
return StandardBasicTypes.DOUBLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.FunctionKind;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
|
||||
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
|
||||
|
@ -34,7 +35,7 @@ public class EveryAnyEmulation extends AbstractSqmSelfRenderingFunctionDescripto
|
|||
public EveryAnyEmulation(boolean every) {
|
||||
super(
|
||||
every ? "every" : "any",
|
||||
true,
|
||||
FunctionKind.AGGREGATE,
|
||||
StandardArgumentsValidators.exactly( 1 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.BOOLEAN )
|
||||
);
|
||||
|
|
|
@ -55,7 +55,8 @@ public class InsertSubstringOverlayEmulation
|
|||
AllowableFunctionReturnType<T> impliedResultType,
|
||||
QueryEngine queryEngine,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
BasicType<Integer> intType = typeConfiguration.getBasicTypeForJavaType(Integer.class);
|
||||
final BasicType<Integer> intType = typeConfiguration.getBasicTypeForJavaType( Integer.class );
|
||||
final BasicType<String> stringType = typeConfiguration.getBasicTypeForJavaType( String.class );
|
||||
|
||||
SqmTypedNode<?> string = arguments.get(0);
|
||||
SqmTypedNode<?> replacement = arguments.get(1);
|
||||
|
@ -93,7 +94,6 @@ public class InsertSubstringOverlayEmulation
|
|||
intType,
|
||||
queryEngine.getCriteriaBuilder()
|
||||
);
|
||||
SqmExpressable<Object> stringType = (SqmExpressable<Object>) impliedResultType;
|
||||
SqmTypedNode<?> restString = substring.generateSqmExpression(
|
||||
asList( string, startPlusLength ),
|
||||
impliedResultType,
|
||||
|
@ -101,7 +101,7 @@ public class InsertSubstringOverlayEmulation
|
|||
typeConfiguration
|
||||
);
|
||||
if ( strictSubstring ) {
|
||||
restString = (SqmTypedNode<?>) new SqmCaseSearched<>( stringType, start.nodeBuilder() )
|
||||
restString = new SqmCaseSearched<>( stringType, start.nodeBuilder() )
|
||||
.when(
|
||||
new SqmComparisonPredicate(
|
||||
startPlusLength,
|
||||
|
@ -114,8 +114,8 @@ public class InsertSubstringOverlayEmulation
|
|||
),
|
||||
string.nodeBuilder()
|
||||
),
|
||||
(Expression<?>) new SqmLiteral<>( "", stringType, string.nodeBuilder() )
|
||||
).otherwise( (Expression<?>) restString );
|
||||
new SqmLiteral<>( "", stringType, string.nodeBuilder() )
|
||||
).otherwise( (Expression<? extends String>) restString );
|
||||
}
|
||||
return concat.generateSqmExpression(
|
||||
asList(
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.dialect.function;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.FunctionKind;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -27,7 +28,7 @@ public class SQLServerEveryAnyEmulation extends AbstractSqmSelfRenderingFunction
|
|||
public SQLServerEveryAnyEmulation(boolean every) {
|
||||
super(
|
||||
every ? "every" : "any",
|
||||
true,
|
||||
FunctionKind.AGGREGATE,
|
||||
StandardArgumentsValidators.exactly( 1 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.BOOLEAN )
|
||||
);
|
||||
|
|
|
@ -26,9 +26,11 @@ import java.util.ArrayList;
|
|||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
|
@ -76,6 +78,7 @@ import org.hibernate.query.sqm.SqmQuerySource;
|
|||
import org.hibernate.query.sqm.SqmTreeCreationLogger;
|
||||
import org.hibernate.query.sqm.StrictJpaComplianceViolation;
|
||||
import org.hibernate.query.sqm.UnknownEntityException;
|
||||
import org.hibernate.query.sqm.function.FunctionKind;
|
||||
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.internal.ParameterCollector;
|
||||
|
@ -177,6 +180,7 @@ import org.hibernate.query.sqm.tree.select.SqmSelection;
|
|||
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
|
@ -220,6 +224,35 @@ import static org.hibernate.type.spi.TypeConfiguration.isJdbcTemporalType;
|
|||
public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implements SqmCreationState {
|
||||
|
||||
private static final Logger log = Logger.getLogger( SemanticQueryBuilder.class );
|
||||
private static final Set<String> JPA_STANDARD_FUNCTIONS;
|
||||
|
||||
static {
|
||||
final Set<String> jpaStandardFunctions = new HashSet<>();
|
||||
// Extracted from the BNF in JPA spec 4.14.
|
||||
jpaStandardFunctions.add( "avg" );
|
||||
jpaStandardFunctions.add( "max" );
|
||||
jpaStandardFunctions.add( "min" );
|
||||
jpaStandardFunctions.add( "sum" );
|
||||
jpaStandardFunctions.add( "count" );
|
||||
jpaStandardFunctions.add( "length" );
|
||||
jpaStandardFunctions.add( "locate" );
|
||||
jpaStandardFunctions.add( "abs" );
|
||||
jpaStandardFunctions.add( "sqrt" );
|
||||
jpaStandardFunctions.add( "mod" );
|
||||
jpaStandardFunctions.add( "size" );
|
||||
jpaStandardFunctions.add( "index" );
|
||||
jpaStandardFunctions.add( "current_date" );
|
||||
jpaStandardFunctions.add( "current_time" );
|
||||
jpaStandardFunctions.add( "current_timestamp" );
|
||||
jpaStandardFunctions.add( "concat" );
|
||||
jpaStandardFunctions.add( "substring" );
|
||||
jpaStandardFunctions.add( "trim" );
|
||||
jpaStandardFunctions.add( "lower" );
|
||||
jpaStandardFunctions.add( "upper" );
|
||||
jpaStandardFunctions.add( "coalesce" );
|
||||
jpaStandardFunctions.add( "nullif" );
|
||||
JPA_STANDARD_FUNCTIONS = jpaStandardFunctions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point into analysis of HQL/JPQL parse tree - producing a semantic model of the
|
||||
|
@ -2192,7 +2225,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ),
|
||||
(SqmExpression<?>) ctx.getChild( 2 ).accept( this )
|
||||
),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
|
@ -2264,7 +2297,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
if ( operator == BinaryArithmeticOperator.MODULO ) {
|
||||
return getFunctionDescriptor("mod").generateSqmExpression(
|
||||
asList( left, right ),
|
||||
(AllowableFunctionReturnType<?>) left.getNodeType(),
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
|
@ -2505,68 +2538,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLeastFunction(HqlParser.LeastFunctionContext ctx) {
|
||||
final List<SqmExpression<?>> arguments = visitExpressions( ctx );
|
||||
return getFunctionDescriptor("least")
|
||||
.generateSqmExpression(
|
||||
arguments,
|
||||
(AllowableFunctionReturnType<?>) arguments.get( 0 ).getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitGreatestFunction(HqlParser.GreatestFunctionContext ctx) {
|
||||
final List<SqmExpression<?>> arguments = visitExpressions( ctx );
|
||||
return getFunctionDescriptor("greatest")
|
||||
.generateSqmExpression(
|
||||
arguments,
|
||||
(AllowableFunctionReturnType<?>) arguments.get( 0 ).getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitCoalesceFunction(HqlParser.CoalesceFunctionContext ctx) {
|
||||
final List<SqmExpression<?>> arguments = visitExpressions( ctx );
|
||||
return getFunctionDescriptor("coalesce")
|
||||
.generateSqmExpression(
|
||||
arguments,
|
||||
(AllowableFunctionReturnType<?>) arguments.get( 0 ).getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitNullifFunction(HqlParser.NullifFunctionContext ctx) {
|
||||
final SqmExpression<?> arg1 = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> arg2 = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("nullif").generateSqmExpression(
|
||||
asList( arg1, arg2 ),
|
||||
(AllowableFunctionReturnType<?>) arg1.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitIfnullFunction(HqlParser.IfnullFunctionContext ctx) {
|
||||
final SqmExpression<?> arg1 = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> arg2 = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("ifnull").generateSqmExpression(
|
||||
asList( arg1, arg2 ),
|
||||
(AllowableFunctionReturnType<?>) arg1.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitLiteralExpression(HqlParser.LiteralExpressionContext ctx) {
|
||||
return (SqmExpression<?>) ctx.getChild( 0 ).accept( this );
|
||||
|
@ -3129,39 +3100,66 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitNonStandardFunction(HqlParser.NonStandardFunctionContext ctx) {
|
||||
if ( creationOptions.useStrictJpaCompliance() ) {
|
||||
public Object visitGenericFunction(HqlParser.GenericFunctionContext ctx) {
|
||||
final String originalFunctionName = ctx.getChild( 0 ).getText();
|
||||
final String functionName = originalFunctionName.toLowerCase();
|
||||
if ( creationOptions.useStrictJpaCompliance() && !JPA_STANDARD_FUNCTIONS.contains( functionName ) ) {
|
||||
throw new StrictJpaComplianceViolation(
|
||||
"Encountered non-compliant non-standard function call [" +
|
||||
ctx.nonStandardFunctionName() + "], but strict JPA " +
|
||||
originalFunctionName + "], but strict JPA " +
|
||||
"compliance was requested; use JPA's FUNCTION(functionName[,...]) " +
|
||||
"syntax name instead",
|
||||
StrictJpaComplianceViolation.Type.FUNCTION_CALL
|
||||
);
|
||||
}
|
||||
|
||||
final String functionName = ctx.getChild( 0 ).getText().toLowerCase();
|
||||
//noinspection unchecked
|
||||
final List<SqmTypedNode<?>> functionArguments = ctx.getChildCount() == 3
|
||||
? emptyList()
|
||||
: (List<SqmTypedNode<?>>) ctx.getChild( 2 ).accept( this );
|
||||
final ParseTree argumentChild = ctx.getChild( 2 );
|
||||
final List<SqmTypedNode<?>> functionArguments;
|
||||
if ( argumentChild instanceof HqlParser.NonStandardFunctionArgumentsContext ) {
|
||||
functionArguments = (List<SqmTypedNode<?>>) argumentChild.accept( this );
|
||||
}
|
||||
else if ( "*".equals( argumentChild.getText() ) ) {
|
||||
functionArguments = Collections.singletonList( new SqmStar( getCreationContext().getNodeBuilder() ) );
|
||||
}
|
||||
else {
|
||||
functionArguments = emptyList();
|
||||
}
|
||||
|
||||
final SqmPredicate filterExpression = getFilterExpression( ctx );
|
||||
SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( functionName );
|
||||
if ( functionTemplate == null ) {
|
||||
functionTemplate = new NamedSqmFunctionDescriptor(
|
||||
functionName,
|
||||
true,
|
||||
null,
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.OBJECT_TYPE )
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.OBJECT_TYPE ),
|
||||
functionName,
|
||||
filterExpression != null ? FunctionKind.AGGREGATE : FunctionKind.NORMAL,
|
||||
null,
|
||||
SqlAstNodeRenderingMode.DEFAULT
|
||||
);
|
||||
}
|
||||
|
||||
return functionTemplate.generateSqmExpression(
|
||||
functionArguments,
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
if ( functionTemplate.getFunctionKind() == FunctionKind.AGGREGATE ) {
|
||||
return functionTemplate.generateAggregateSqmExpression(
|
||||
functionArguments,
|
||||
filterExpression,
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
else {
|
||||
if ( filterExpression != null ) {
|
||||
throw new ParsingException( "Illegal use of a FILTER clause for non-aggregate function: " + originalFunctionName );
|
||||
}
|
||||
return functionTemplate.generateSqmExpression(
|
||||
functionArguments,
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3173,11 +3171,16 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
final List<SqmTypedNode<?>> arguments = new ArrayList<>( estimateArgumentCount );
|
||||
int i = 0;
|
||||
|
||||
boolean distinct = false;
|
||||
final ParseTree firstChild = ctx.getChild( 0 );
|
||||
if ( firstChild instanceof HqlParser.DatetimeFieldContext ) {
|
||||
arguments.add( toDurationUnit( (SqmExtractUnit<?>) firstChild.accept( this ) ) );
|
||||
i += 2;
|
||||
}
|
||||
else if ( firstChild instanceof TerminalNode ) {
|
||||
distinct = true;
|
||||
i++;
|
||||
}
|
||||
|
||||
for ( ; i < size; i += 2 ) {
|
||||
// we handle the final argument differently...
|
||||
|
@ -3189,6 +3192,22 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
}
|
||||
|
||||
if ( distinct ) {
|
||||
final NodeBuilder nodeBuilder = getCreationContext().getNodeBuilder();
|
||||
if ( arguments.size() == 1 ) {
|
||||
arguments.set( 0, new SqmDistinct<>( (SqmExpression<?>) arguments.get( 0 ), nodeBuilder ) );
|
||||
}
|
||||
else {
|
||||
final List<SqmTypedNode<?>> newArguments = new ArrayList<>( 1 );
|
||||
//noinspection unchecked
|
||||
newArguments.add(
|
||||
new SqmDistinct<>(
|
||||
new SqmTuple<>( (List<SqmExpression<?>>) (List<?>) arguments, nodeBuilder ), nodeBuilder
|
||||
)
|
||||
);
|
||||
return newArguments;
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
|
@ -3204,161 +3223,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitCeilingFunction(HqlParser.CeilingFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("ceiling").generateSqmExpression(
|
||||
arg,
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitFloorFunction(HqlParser.FloorFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("floor").generateSqmExpression(
|
||||
arg,
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmFunctionDescriptor getFunctionDescriptor(String name) {
|
||||
return creationContext.getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitAbsFunction(HqlParser.AbsFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("abs").generateSqmExpression(
|
||||
arg,
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitSignFunction(HqlParser.SignFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("sign").generateSqmExpression(
|
||||
arg,
|
||||
resolveExpressableTypeBasic( Integer.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitModFunction(HqlParser.ModFunctionContext ctx) {
|
||||
final SqmExpression<?> dividend = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> divisor = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("mod").generateSqmExpression(
|
||||
asList( dividend, divisor ),
|
||||
(AllowableFunctionReturnType<?>) dividend.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitPowerFunction(HqlParser.PowerFunctionContext ctx) {
|
||||
final SqmExpression<?> base = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> power = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("power").generateSqmExpression(
|
||||
asList( base, power ),
|
||||
(AllowableFunctionReturnType<?>) base.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitTrigFunction(HqlParser.TrigFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor( ctx.getChild( 0 ).getText() ).generateSqmExpression(
|
||||
arg,
|
||||
resolveExpressableTypeBasic( Double.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitSqrtFunction(HqlParser.SqrtFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("sqrt").generateSqmExpression(
|
||||
arg,
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitRoundFunction(HqlParser.RoundFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> precision = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("round").generateSqmExpression(
|
||||
asList(arg, precision),
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitAtan2Function(HqlParser.Atan2FunctionContext ctx) {
|
||||
final SqmExpression<?> sin = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> cos = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("atan2").generateSqmExpression(
|
||||
asList(sin, cos),
|
||||
(AllowableFunctionReturnType<?>) sin.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitLnFunction(HqlParser.LnFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("ln").generateSqmExpression(
|
||||
arg,
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitExpFunction(HqlParser.ExpFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("exp").generateSqmExpression(
|
||||
arg,
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDatetimeField(HqlParser.DatetimeFieldContext ctx) {
|
||||
public SqmExtractUnit<?> visitDatetimeField(HqlParser.DatetimeFieldContext ctx) {
|
||||
final NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
|
||||
switch ( ( (TerminalNode) ctx.getChild( 0 ) ).getSymbol().getType() ) {
|
||||
case HqlParser.DAY:
|
||||
|
@ -3416,7 +3286,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
nodeBuilder
|
||||
);
|
||||
}
|
||||
throw new ParsingException("Unsupported datetime field [" + ctx.getText() + "]");
|
||||
throw new ParsingException( "Unsupported datetime field [" + ctx.getText() + "]" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3551,7 +3421,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
|
||||
return getFunctionDescriptor("format").generateSqmExpression(
|
||||
asList( expressionToCast, format ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
|
@ -3599,60 +3469,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitUpperFunction(HqlParser.UpperFunctionContext ctx) {
|
||||
final SqmExpression<?> expression = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
return getFunctionDescriptor("upper").generateSqmExpression(
|
||||
expression,
|
||||
(AllowableFunctionReturnType<?>) expression.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitLowerFunction(HqlParser.LowerFunctionContext ctx) {
|
||||
// todo (6.0) : why pass both the expression and its expression-type?
|
||||
// can't we just pass the expression?
|
||||
final SqmExpression<?> expression = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
return getFunctionDescriptor("lower").generateSqmExpression(
|
||||
expression,
|
||||
(AllowableFunctionReturnType<?>) expression.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitConcatFunction(HqlParser.ConcatFunctionContext ctx) {
|
||||
final int size = ctx.getChildCount();
|
||||
// Shift 1 bit instead of division by 2
|
||||
final int estimateArgumentCount = (size >> 1) - 1;
|
||||
final List<SqmTypedNode<?>> arguments = new ArrayList<>( estimateArgumentCount );
|
||||
for ( int i = 2; i < size; i += 2 ) {
|
||||
arguments.add( (SqmTypedNode<?>) ctx.getChild( i ).accept( this ) );
|
||||
}
|
||||
|
||||
return getFunctionDescriptor("concat").generateSqmExpression(
|
||||
arguments,
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLengthFunction(HqlParser.LengthFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("length").generateSqmExpression(
|
||||
arg,
|
||||
resolveExpressableTypeBasic( Integer.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitPositionFunction(HqlParser.PositionFunctionContext ctx) {
|
||||
final SqmExpression<?> pattern = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
@ -3660,29 +3476,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
|
||||
return getFunctionDescriptor("position").generateSqmExpression(
|
||||
asList( pattern, string ),
|
||||
resolveExpressableTypeBasic( Integer.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLocateFunction(HqlParser.LocateFunctionContext ctx) {
|
||||
final SqmExpression<?> pattern = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> string = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
final SqmExpression<?> start;
|
||||
if ( ctx.getChildCount() == 8 ) {
|
||||
start = (SqmExpression<?>) ctx.getChild( 6 ).accept( this );
|
||||
}
|
||||
else {
|
||||
start = null;
|
||||
}
|
||||
|
||||
return getFunctionDescriptor("locate").generateSqmExpression(
|
||||
start == null
|
||||
? asList( pattern, string )
|
||||
: asList( pattern, string, start ),
|
||||
resolveExpressableTypeBasic( Integer.class ),
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
|
@ -3705,76 +3499,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
length == null
|
||||
? asList( string, replacement, start )
|
||||
: asList( string, replacement, start, length ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitReplaceFunction(HqlParser.ReplaceFunctionContext ctx) {
|
||||
final SqmExpression<?> string = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> pattern = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
final SqmExpression<?> replacement = (SqmExpression<?>) ctx.getChild( 6 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("replace").generateSqmExpression(
|
||||
asList( string, pattern, replacement ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitStrFunction(HqlParser.StrFunctionContext ctx) {
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
return getFunctionDescriptor("str").generateSqmExpression(
|
||||
singletonList( arg ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitMaxFunction(HqlParser.MaxFunctionContext ctx) {
|
||||
final SqmPredicate filterExpression = getFilterExpression( ctx );
|
||||
final int expressionIndex = ctx.getChildCount() - ( filterExpression == null ? 2 : 3 );
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( expressionIndex ).accept( this );
|
||||
//ignore DISTINCT
|
||||
return getFunctionDescriptor("max").generateAggregateSqmExpression(
|
||||
singletonList( arg ),
|
||||
filterExpression,
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitMinFunction(HqlParser.MinFunctionContext ctx) {
|
||||
final SqmPredicate filterExpression = getFilterExpression( ctx );
|
||||
final int expressionIndex = ctx.getChildCount() - ( filterExpression == null ? 2 : 3 );
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( expressionIndex ).accept( this );
|
||||
//ignore DISTINCT
|
||||
return getFunctionDescriptor("min").generateAggregateSqmExpression(
|
||||
singletonList( arg ),
|
||||
filterExpression,
|
||||
(AllowableFunctionReturnType<?>) arg.getNodeType(),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitSumFunction(HqlParser.SumFunctionContext ctx) {
|
||||
final SqmPredicate filterExpression = getFilterExpression( ctx );
|
||||
final int expressionIndex = ctx.getChildCount() - ( filterExpression == null ? 2 : 3 );
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( expressionIndex ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("sum").generateAggregateSqmExpression(
|
||||
singletonList( applyDistinct( arg, ctx ) ),
|
||||
filterExpression,
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
|
@ -3905,51 +3629,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
return (SqmSubQuery<X>) subQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitAvgFunction(HqlParser.AvgFunctionContext ctx) {
|
||||
final SqmPredicate filterExpression = getFilterExpression( ctx );
|
||||
final int expressionIndex = ctx.getChildCount() - ( filterExpression == null ? 2 : 3 );
|
||||
final SqmExpression<?> arg = (SqmExpression<?>) ctx.getChild( expressionIndex ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("avg").generateAggregateSqmExpression(
|
||||
singletonList( applyDistinct( arg, ctx ) ),
|
||||
filterExpression,
|
||||
resolveExpressableTypeBasic( Double.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitCountFunction(HqlParser.CountFunctionContext ctx) {
|
||||
final SqmPredicate filterExpression = getFilterExpression( ctx );
|
||||
final int expressionIndex = ctx.getChildCount() - ( filterExpression == null ? 2 : 3 );
|
||||
final ParseTree argumentChild = ctx.getChild( expressionIndex );
|
||||
final SqmExpression<?> arg;
|
||||
if ( argumentChild instanceof TerminalNode ) {
|
||||
arg = new SqmStar( getCreationContext().getNodeBuilder() );
|
||||
}
|
||||
else {
|
||||
arg = (SqmExpression<?>) argumentChild.accept( this );
|
||||
}
|
||||
|
||||
return getFunctionDescriptor("count").generateAggregateSqmExpression(
|
||||
singletonList( applyDistinct( arg, ctx ) ),
|
||||
filterExpression,
|
||||
resolveExpressableTypeBasic( Long.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmTypedNode<?> applyDistinct(SqmExpression<?> expression, ParseTree functionCtx) {
|
||||
final ParseTree node = functionCtx.getChild( 2 );
|
||||
if ( node instanceof TerminalNode && ( (TerminalNode) node ).getSymbol().getType() == HqlParser.DISTINCT ) {
|
||||
return new SqmDistinct<>( expression, getCreationContext().getNodeBuilder() );
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private SqmPredicate getFilterExpression(ParseTree functionCtx) {
|
||||
final ParseTree lastChild = functionCtx.getChild( functionCtx.getChildCount() - 1 );
|
||||
if ( lastChild instanceof HqlParser.FilterClauseContext ) {
|
||||
|
@ -3990,38 +3669,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
|
||||
return getFunctionDescriptor("substring").generateSqmExpression(
|
||||
length == null ? asList( source, start ) : asList( source, start, length ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitLeftFunction(HqlParser.LeftFunctionContext ctx) {
|
||||
final SqmExpression<?> source = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> length = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("left").generateSqmExpression(
|
||||
asList( source, length ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getNodeBuilder().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitRightFunction(HqlParser.RightFunctionContext ctx) {
|
||||
final SqmExpression<?> source = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
final SqmExpression<?> length = (SqmExpression<?>) ctx.getChild( 4 ).accept( this );
|
||||
|
||||
return getFunctionDescriptor("right").generateSqmExpression(
|
||||
asList( source, length ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getNodeBuilder().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmExpression<?> visitPadFunction(HqlParser.PadFunctionContext ctx) {
|
||||
final SqmExpression<?> source = (SqmExpression<?>) ctx.getChild( 2 ).accept( this );
|
||||
|
@ -4038,7 +3691,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
padChar != null
|
||||
? asList( source, length, padSpec, padChar )
|
||||
: asList( source, length, padSpec ),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
|
@ -4100,7 +3753,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
trimChar,
|
||||
source
|
||||
),
|
||||
resolveExpressableTypeBasic( String.class ),
|
||||
null,
|
||||
creationContext.getQueryEngine(),
|
||||
creationContext.getJpaMetamodel().getTypeConfiguration()
|
||||
);
|
||||
|
|
|
@ -26,16 +26,28 @@ import java.util.List;
|
|||
public abstract class AbstractSqmSelfRenderingFunctionDescriptor
|
||||
extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport {
|
||||
|
||||
private final boolean isAggregate;
|
||||
private final FunctionKind functionKind;
|
||||
|
||||
public AbstractSqmSelfRenderingFunctionDescriptor(String name, ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver) {
|
||||
public AbstractSqmSelfRenderingFunctionDescriptor(
|
||||
String name,
|
||||
ArgumentsValidator argumentsValidator,
|
||||
FunctionReturnTypeResolver returnTypeResolver) {
|
||||
super( name, argumentsValidator, returnTypeResolver );
|
||||
this.isAggregate = false;
|
||||
this.functionKind = FunctionKind.NORMAL;
|
||||
}
|
||||
|
||||
public AbstractSqmSelfRenderingFunctionDescriptor(String name, boolean isAggregate, ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver) {
|
||||
public AbstractSqmSelfRenderingFunctionDescriptor(
|
||||
String name,
|
||||
FunctionKind functionKind,
|
||||
ArgumentsValidator argumentsValidator,
|
||||
FunctionReturnTypeResolver returnTypeResolver) {
|
||||
super( name, argumentsValidator, returnTypeResolver );
|
||||
this.isAggregate = isAggregate;
|
||||
this.functionKind = functionKind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionKind getFunctionKind() {
|
||||
return functionKind;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,7 +56,7 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor
|
|||
AllowableFunctionReturnType<T> impliedResultType,
|
||||
QueryEngine queryEngine,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
if ( isAggregate ) {
|
||||
if ( functionKind == FunctionKind.AGGREGATE ) {
|
||||
return generateAggregateSqmExpression( arguments, null, impliedResultType, queryEngine, typeConfiguration );
|
||||
}
|
||||
return new SelfRenderingSqmFunction<>(
|
||||
|
@ -65,7 +77,7 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor
|
|||
AllowableFunctionReturnType<T> impliedResultType,
|
||||
QueryEngine queryEngine,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
if ( !isAggregate ) {
|
||||
if ( functionKind != FunctionKind.AGGREGATE ) {
|
||||
throw new UnsupportedOperationException( "The function " + getName() + " is not an aggregate function!" );
|
||||
}
|
||||
return new SelfRenderingSqmAggregateFunction<>(
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.function;
|
||||
|
||||
/**
|
||||
* The kind of a function e.g. normal, aggregate etc.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public enum FunctionKind {
|
||||
NORMAL,
|
||||
AGGREGATE;
|
||||
}
|
|
@ -46,7 +46,7 @@ public class NamedSqmFunctionDescriptor
|
|||
argumentsValidator,
|
||||
returnTypeResolver,
|
||||
functionName,
|
||||
false,
|
||||
FunctionKind.NORMAL,
|
||||
null,
|
||||
SqlAstNodeRenderingMode.DEFAULT
|
||||
);
|
||||
|
@ -58,10 +58,10 @@ public class NamedSqmFunctionDescriptor
|
|||
ArgumentsValidator argumentsValidator,
|
||||
FunctionReturnTypeResolver returnTypeResolver,
|
||||
String name,
|
||||
boolean isAggregate,
|
||||
FunctionKind functionKind,
|
||||
String argumentListSignature,
|
||||
SqlAstNodeRenderingMode argumentRenderingMode) {
|
||||
super( name, isAggregate, argumentsValidator, returnTypeResolver );
|
||||
super( name, functionKind, argumentsValidator, returnTypeResolver );
|
||||
|
||||
this.functionName = functionName;
|
||||
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
|
||||
|
|
|
@ -48,11 +48,11 @@ public class PatternBasedSqmFunctionDescriptor
|
|||
ArgumentsValidator argumentsValidator,
|
||||
FunctionReturnTypeResolver returnTypeResolver,
|
||||
String name,
|
||||
boolean isAggregate,
|
||||
FunctionKind functionKind,
|
||||
String argumentListSignature) {
|
||||
super(
|
||||
name,
|
||||
isAggregate,
|
||||
functionKind,
|
||||
argumentsValidator != null
|
||||
? argumentsValidator
|
||||
// If no validator is given, it's still better to
|
||||
|
|
|
@ -118,4 +118,8 @@ public interface SqmFunctionDescriptor {
|
|||
default String getSignature(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
default FunctionKind getFunctionKind() {
|
||||
return FunctionKind.NORMAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public class SqmFunctionRegistry {
|
|||
* @return The builder
|
||||
*/
|
||||
public PatternFunctionDescriptorBuilder patternDescriptorBuilder(String registrationKey, String pattern) {
|
||||
return new PatternFunctionDescriptorBuilder( this, registrationKey, false, pattern );
|
||||
return new PatternFunctionDescriptorBuilder( this, registrationKey, FunctionKind.NORMAL, pattern );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +124,7 @@ public class SqmFunctionRegistry {
|
|||
* @return The builder
|
||||
*/
|
||||
public PatternFunctionDescriptorBuilder patternAggregateDescriptorBuilder(String registrationKey, String pattern) {
|
||||
return new PatternFunctionDescriptorBuilder( this, registrationKey, true, pattern );
|
||||
return new PatternFunctionDescriptorBuilder( this, registrationKey, FunctionKind.AGGREGATE, pattern );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,7 +184,7 @@ public class SqmFunctionRegistry {
|
|||
* @return The builder
|
||||
*/
|
||||
public NamedFunctionDescriptorBuilder namedDescriptorBuilder(String registrationKey, String name) {
|
||||
return new NamedFunctionDescriptorBuilder( this, registrationKey, false, name );
|
||||
return new NamedFunctionDescriptorBuilder( this, registrationKey, FunctionKind.NORMAL, name );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +196,7 @@ public class SqmFunctionRegistry {
|
|||
* @return The builder
|
||||
*/
|
||||
public NamedFunctionDescriptorBuilder namedAggregateDescriptorBuilder(String registrationKey, String name) {
|
||||
return new NamedFunctionDescriptorBuilder( this, registrationKey, true, name );
|
||||
return new NamedFunctionDescriptorBuilder( this, registrationKey, FunctionKind.AGGREGATE, name );
|
||||
}
|
||||
|
||||
public NamedFunctionDescriptorBuilder noArgsBuilder(String name) {
|
||||
|
|
|
@ -246,13 +246,12 @@ public class QuerySqmImpl<R>
|
|||
final SqmQuerySpec<R> sqmQuerySpec = (SqmQuerySpec<R>) queryPart;
|
||||
final List<SqmSelection<?>> sqmSelections = sqmQuerySpec.getSelectClause().getSelections();
|
||||
|
||||
// make sure there is at least one root
|
||||
final List<SqmRoot<?>> sqmRoots = sqmQuerySpec.getFromClause().getRoots();
|
||||
if ( sqmRoots == null || sqmRoots.isEmpty() ) {
|
||||
throw new IllegalArgumentException( "Criteria did not define any query roots" );
|
||||
}
|
||||
|
||||
if ( sqmSelections == null || sqmSelections.isEmpty() ) {
|
||||
// make sure there is at least one root
|
||||
final List<SqmRoot<?>> sqmRoots = sqmQuerySpec.getFromClause().getRoots();
|
||||
if ( sqmRoots == null || sqmRoots.isEmpty() ) {
|
||||
throw new IllegalArgumentException( "Criteria did not define any query roots" );
|
||||
}
|
||||
// if there is a single root, use that as the selection
|
||||
if ( sqmRoots.size() == 1 ) {
|
||||
final SqmRoot<?> sqmRoot = sqmRoots.get( 0 );
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.produce.function;
|
||||
|
||||
import org.hibernate.query.sqm.function.FunctionKind;
|
||||
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
|
@ -19,7 +20,7 @@ public class NamedFunctionDescriptorBuilder {
|
|||
|
||||
private final SqmFunctionRegistry registry;
|
||||
private final String registrationKey;
|
||||
private final boolean isAggregate;
|
||||
private final FunctionKind functionKind;
|
||||
|
||||
private final String functionName;
|
||||
|
||||
|
@ -33,11 +34,11 @@ public class NamedFunctionDescriptorBuilder {
|
|||
public NamedFunctionDescriptorBuilder(
|
||||
SqmFunctionRegistry registry,
|
||||
String registrationKey,
|
||||
boolean isAggregate,
|
||||
FunctionKind functionKind,
|
||||
String functionName) {
|
||||
this.registry = registry;
|
||||
this.registrationKey = registrationKey;
|
||||
this.isAggregate = isAggregate;
|
||||
this.functionKind = functionKind;
|
||||
this.functionName = functionName;
|
||||
}
|
||||
|
||||
|
@ -94,7 +95,7 @@ public class NamedFunctionDescriptorBuilder {
|
|||
argumentsValidator,
|
||||
returnTypeResolver,
|
||||
registrationKey,
|
||||
isAggregate,
|
||||
functionKind,
|
||||
argumentListSignature,
|
||||
argumentRenderingMode
|
||||
);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.produce.function;
|
||||
|
||||
import org.hibernate.query.sqm.function.FunctionKind;
|
||||
import org.hibernate.query.sqm.function.PatternBasedSqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
|
@ -19,7 +20,7 @@ import org.hibernate.type.BasicType;
|
|||
public class PatternFunctionDescriptorBuilder {
|
||||
private final SqmFunctionRegistry registry;
|
||||
private final String registrationKey;
|
||||
private final boolean isAggregate;
|
||||
private final FunctionKind functionKind;
|
||||
private final String pattern;
|
||||
private String argumentListSignature;
|
||||
|
||||
|
@ -27,10 +28,14 @@ public class PatternFunctionDescriptorBuilder {
|
|||
private FunctionReturnTypeResolver returnTypeResolver;
|
||||
private SqlAstNodeRenderingMode argumentRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||
|
||||
public PatternFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, boolean isAggregate, String pattern) {
|
||||
public PatternFunctionDescriptorBuilder(
|
||||
SqmFunctionRegistry registry,
|
||||
String registrationKey,
|
||||
FunctionKind functionKind,
|
||||
String pattern) {
|
||||
this.registry = registry;
|
||||
this.registrationKey = registrationKey;
|
||||
this.isAggregate = isAggregate;
|
||||
this.functionKind = functionKind;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
|
@ -73,7 +78,7 @@ public class PatternFunctionDescriptorBuilder {
|
|||
argumentsValidator,
|
||||
returnTypeResolver,
|
||||
registrationKey,
|
||||
isAggregate,
|
||||
functionKind,
|
||||
argumentListSignature
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.function.Supplier;
|
|||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
|
@ -220,6 +221,35 @@ public class StandardFunctionReturnTypeResolvers {
|
|||
return (AllowableFunctionReturnType<?>) specifiedArgType;
|
||||
}
|
||||
|
||||
public static JdbcMapping extractArgumentJdbcMapping(
|
||||
TypeConfiguration typeConfiguration,
|
||||
List<? extends SqmTypedNode<?>> arguments,
|
||||
int position) {
|
||||
final SqmTypedNode<?> specifiedArgument = arguments.get( position - 1 );
|
||||
final SqmExpressable<?> specifiedArgType = specifiedArgument.getNodeType();
|
||||
if ( specifiedArgType instanceof BasicType<?> ) {
|
||||
return ( (BasicType<?>) specifiedArgType ).getJdbcMapping();
|
||||
}
|
||||
else {
|
||||
final BasicType<?> basicType = typeConfiguration.getBasicTypeForJavaType(
|
||||
specifiedArgType.getExpressableJavaTypeDescriptor().getJavaTypeClass()
|
||||
);
|
||||
if ( basicType == null ) {
|
||||
throw new QueryException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Function argument [%s] of type [%s] at specified position [%d] in call arguments was not typed as basic type",
|
||||
specifiedArgument,
|
||||
specifiedArgType,
|
||||
position
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return basicType.getJdbcMapping();
|
||||
}
|
||||
}
|
||||
|
||||
public static BasicValuedMapping extractArgumentValuedMapping(List<? extends SqlAstNode> arguments, int position) {
|
||||
final SqlAstNode specifiedArgument = arguments.get( position-1 );
|
||||
final JdbcMappingContainer specifiedArgType = specifiedArgument instanceof Expression
|
||||
|
|
|
@ -50,14 +50,16 @@ public class SqmCaseSearched<R>
|
|||
return otherwise;
|
||||
}
|
||||
|
||||
public void when(SqmPredicate predicate, SqmExpression<R> result) {
|
||||
public SqmCaseSearched<R> when(SqmPredicate predicate, SqmExpression<R> result) {
|
||||
whenFragments.add( new WhenFragment<>( predicate, result ) );
|
||||
applyInferableResultType( result.getNodeType() );
|
||||
return this;
|
||||
}
|
||||
|
||||
public void otherwise(SqmExpression<R> otherwiseExpression) {
|
||||
public SqmCaseSearched<R> otherwise(SqmExpression<R> otherwiseExpression) {
|
||||
this.otherwise = otherwiseExpression;
|
||||
applyInferableResultType( otherwiseExpression.getNodeType() );
|
||||
return this;
|
||||
}
|
||||
|
||||
private void applyInferableResultType(SqmExpressable<?> type) {
|
||||
|
@ -144,20 +146,20 @@ public class SqmCaseSearched<R>
|
|||
}
|
||||
|
||||
@Override
|
||||
public JpaSearchedCase<R> when(Expression<Boolean> condition, Expression<? extends R> result) {
|
||||
public SqmCaseSearched<R> when(Expression<Boolean> condition, Expression<? extends R> result) {
|
||||
//noinspection unchecked
|
||||
when( nodeBuilder().wrap( condition ), (SqmExpression) result );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaExpression<R> otherwise(R result) {
|
||||
public SqmExpression<R> otherwise(R result) {
|
||||
otherwise( nodeBuilder().value( result ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaExpression<R> otherwise(Expression<? extends R> result) {
|
||||
public SqmExpression<R> otherwise(Expression<? extends R> result) {
|
||||
//noinspection unchecked
|
||||
otherwise( (SqmExpression) result );
|
||||
return this;
|
||||
|
|
|
@ -111,6 +111,25 @@ public interface JdbcTypeDescriptor extends Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
default boolean isFloat() {
|
||||
switch ( getJdbcTypeCode() ) {
|
||||
case Types.FLOAT:
|
||||
case Types.REAL:
|
||||
case Types.DOUBLE:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isDecimal() {
|
||||
switch ( getJdbcTypeCode() ) {
|
||||
case Types.DECIMAL:
|
||||
case Types.NUMERIC:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isNumber() {
|
||||
switch ( getJdbcTypeCode() ) {
|
||||
case Types.BIT:
|
||||
|
|
|
@ -27,6 +27,8 @@ import java.time.LocalDate;
|
|||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.anyOf;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
@ -42,6 +44,8 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
@SessionFactory
|
||||
public class FunctionTests {
|
||||
|
||||
public static final double ERROR = 0.00001d;
|
||||
|
||||
@BeforeAll
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
|
@ -163,7 +167,13 @@ public class FunctionTests {
|
|||
.list();
|
||||
assertThat( session.createQuery("select abs(-2)").getSingleResult(), is(2) );
|
||||
assertThat( session.createQuery("select sign(-2)").getSingleResult(), is(-1) );
|
||||
assertThat( session.createQuery("select power(3.0,2.0)").getSingleResult(), is(9.0f) );
|
||||
assertThat(
|
||||
session.createQuery("select power(3.0,2.0)", Double.class).getSingleResult(),
|
||||
// The LN/EXP emulation can cause some precision loss
|
||||
// i.e. on Derby the 16th decimal for LN(3.0) is off by 1 when compared to e.g. PostgreSQL
|
||||
// Fetching the result as float would "hide" the error as that would do some rounding
|
||||
Matchers.closeTo( 9.0d, ERROR )
|
||||
);
|
||||
assertThat( session.createQuery("select round(32.12345,2)").getSingleResult(), is(32.12f) );
|
||||
assertThat( session.createQuery("select mod(3,2)").getSingleResult(), is(1) );
|
||||
assertThat( session.createQuery("select 3%2").getSingleResult(), is(1) );
|
||||
|
|
Loading…
Reference in New Issue