HHH-13785 : HQL/Criteria function support

- preliminary work on updated tree handling.  See SqmFunctionDescriptor, SqmFunctionRegistry and SqmFunction
This commit is contained in:
Steve Ebersole 2019-12-20 17:44:18 -06:00
parent 6925fe5ab4
commit 3e89772bb8
49 changed files with 1402 additions and 1387 deletions

View File

@ -60,7 +60,7 @@ import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;

View File

@ -32,7 +32,7 @@ import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;

View File

@ -35,7 +35,7 @@ import org.hibernate.query.QueryLiteralRendering;
import org.hibernate.query.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.hibernate.QueryException;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.type.Type;
/**
@ -24,7 +25,7 @@ import org.hibernate.type.Type;
* @author David Channon
* @author Steve Ebersole
*
* @deprecated Replaced by {@link org.hibernate.query.sqm.function.SqmFunction}
* @deprecated Replaced by {@link SqmFunction}
*/
@Deprecated
public interface SQLFunction {

View File

@ -10,13 +10,14 @@ import java.util.Map;
import java.util.TreeMap;
import org.hibernate.dialect.Dialect;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
/**
* Defines a registry for SQLFunction instances
*
* @author Steve Ebersole
*
* @deprecated Replaced by {@link org.hibernate.query.sqm.function.SqmFunction}
* @deprecated Replaced by {@link SqmFunction}
*/
@Deprecated
public class SQLFunctionRegistry {

View File

@ -18,7 +18,6 @@ import org.hibernate.query.hql.spi.SqmCreationOptions;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
@ -590,14 +589,6 @@ public class QuerySplitter {
);
}
@Override
public SqmFunction visitFunction(SqmFunction functionProducer) {
// todo (6.0) : likely this needs a copy too
// how to model that?
// for now, return the same reference
return functionProducer;
}
@Override
public SqmLiteral visitLiteral(SqmLiteral literal) {
return new SqmLiteral(

View File

@ -11,8 +11,8 @@ import java.math.BigInteger;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -56,16 +56,11 @@ 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.SqmCastTarget;
import org.hibernate.query.sqm.function.SqmDistinct;
import org.hibernate.query.sqm.function.SqmExtractUnit;
import org.hibernate.query.sqm.function.SqmStar;
import org.hibernate.query.sqm.function.SqmTrimSpecification;
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.internal.ParameterCollector;
import org.hibernate.query.sqm.internal.SqmDmlCreationProcessingState;
import org.hibernate.query.sqm.internal.SqmQuerySpecCreationProcessingStateStandardImpl;
import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate;
import org.hibernate.query.sqm.produce.function.spi.NamedSqmFunctionTemplate;
import org.hibernate.query.sqm.spi.ParameterDeclarationContext;
import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
@ -85,8 +80,13 @@ import org.hibernate.query.sqm.tree.expression.LiteralHelper;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
@ -94,6 +94,8 @@ import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.tree.from.DowncastLocation;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
@ -131,6 +133,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.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.jboss.logging.Logger;
@ -1305,13 +1308,15 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
}
//noinspection unchecked
return getFunctionTemplate( "concat" ).makeSqmFunctionExpression(
(List) asList(
return new SqmFunction(
"concat",
getFunctionDescriptor( "concat" ),
StandardBasicTypes.STRING,
asList(
ctx.expression( 0 ).accept( this ),
ctx.expression( 1 ).accept( this )
),
resolveExpressableTypeBasic( String.class ),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -1386,10 +1391,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
SqmExpression<?> divisor = (SqmExpression) ctx.expression( 1 ).accept( this );
//noinspection unchecked
return getFunctionTemplate("mod").makeSqmFunctionExpression(
asList( dividend, divisor ),
return new SqmFunction(
"mod",
getFunctionDescriptor( "mod" ),
(AllowableFunctionReturnType) dividend.getNodeType(),
creationContext.getQueryEngine()
asList( dividend, divisor ),
creationContext.getNodeBuilder()
);
}
@ -1455,38 +1462,46 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
@Override
public SqmExpression visitCurrentDateFunction(HqlParser.CurrentDateFunctionContext ctx) {
return getFunctionTemplate("current_date")
.makeSqmFunctionExpression(
resolveExpressableTypeBasic( Date.class ),
creationContext.getQueryEngine()
);
//noinspection unchecked
return new SqmFunction(
"current_date",
getFunctionDescriptor( "current_date" ),
StandardBasicTypes.DATE,
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitCurrentTimeFunction(HqlParser.CurrentTimeFunctionContext ctx) {
return getFunctionTemplate("current_time")
.makeSqmFunctionExpression(
resolveExpressableTypeBasic( Time.class ),
creationContext.getQueryEngine()
);
//noinspection unchecked
return new SqmFunction(
"current_time",
getFunctionDescriptor( "current_time" ),
StandardBasicTypes.TIME,
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitCurrentTimestampFunction(HqlParser.CurrentTimestampFunctionContext ctx) {
return getFunctionTemplate("current_timestamp")
.makeSqmFunctionExpression(
resolveExpressableTypeBasic( Timestamp.class ),
creationContext.getQueryEngine()
);
//noinspection unchecked
return new SqmFunction(
"current_timestamp",
getFunctionDescriptor( "current_timestamp" ),
StandardBasicTypes.TIMESTAMP,
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitCurrentInstantFunction(HqlParser.CurrentInstantFunctionContext ctx) {
return getFunctionTemplate("current_timestamp")
.makeSqmFunctionExpression(
resolveExpressableTypeBasic( Instant.class ),
creationContext.getQueryEngine()
);
//noinspection unchecked
return new SqmFunction(
"current_instant",
getFunctionDescriptor( "current_instant" ),
StandardBasicTypes.INSTANT,
creationContext.getNodeBuilder()
);
}
@Override
@ -1502,12 +1517,14 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
type = arg.getNodeType();
}
return getFunctionTemplate("least")
.makeSqmFunctionExpression(
arguments,
(AllowableFunctionReturnType<?>) type,
creationContext.getQueryEngine()
);
//noinspection unchecked
return new SqmFunction(
"least",
getFunctionDescriptor( "least" ),
(AllowableFunctionReturnType<?>) type,
arguments,
creationContext.getNodeBuilder()
);
}
@Override
@ -1523,12 +1540,14 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
type = arg.getNodeType();
}
return getFunctionTemplate("greatest")
.makeSqmFunctionExpression(
arguments,
(AllowableFunctionReturnType<?>) type,
creationContext.getQueryEngine()
);
//noinspection unchecked
return new SqmFunction(
"greatest",
getFunctionDescriptor( "greatest" ),
type,
arguments,
creationContext.getNodeBuilder()
);
}
@Override
@ -1544,12 +1563,14 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
type = arg.getNodeType();
}
return getFunctionTemplate("coalesce")
.makeSqmFunctionExpression(
arguments,
(AllowableFunctionReturnType<?>) type,
creationContext.getQueryEngine()
);
//noinspection unchecked
return new SqmFunction(
"coalesce",
getFunctionDescriptor( "coalesce" ),
type,
arguments,
creationContext.getNodeBuilder()
);
}
@Override
@ -1558,10 +1579,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg2 = (SqmExpression) ctx.nullIf().expression( 1 ).accept( this );
//noinspection unchecked
return getFunctionTemplate("nullif").makeSqmFunctionExpression(
return new SqmFunction(
"nullif",
getFunctionDescriptor( "nullif" ),
arg1.getNodeType(),
asList( arg1, arg2 ),
(AllowableFunctionReturnType) arg1.getNodeType(),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -1819,14 +1842,18 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final String functionName = ctx.jpaNonStandardFunctionName().STRING_LITERAL().getText().toLowerCase();
final List<SqmTypedNode<?>> functionArguments = visitNonStandardFunctionArguments( ctx.nonStandardFunctionArguments() );
SqmFunctionTemplate functionTemplate = getFunctionTemplate( functionName );
if (functionTemplate == null) {
functionTemplate = new NamedSqmFunctionTemplate( functionName, true, null, null );
SqmFunctionDescriptor functionDescriptor = getFunctionDescriptor( functionName );
if (functionDescriptor == null) {
functionDescriptor = new NamedSqmFunctionDescriptor( functionName, functionName, true, null );
}
return functionTemplate.makeSqmFunctionExpression(
functionArguments,
//noinspection unchecked
return new SqmFunction(
functionName,
functionDescriptor,
null,
creationContext.getQueryEngine()
functionArguments,
creationContext.getNodeBuilder()
);
}
@ -1843,14 +1870,18 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final String functionName = ctx.nonStandardFunctionName().getText().toLowerCase();
final List<SqmTypedNode<?>> functionArguments = visitNonStandardFunctionArguments( ctx.nonStandardFunctionArguments() );
SqmFunctionTemplate functionTemplate = getFunctionTemplate( functionName);
if (functionTemplate == null) {
functionTemplate = new NamedSqmFunctionTemplate( functionName, true, null, null );
SqmFunctionDescriptor functionDescriptor = getFunctionDescriptor( functionName);
if ( functionDescriptor == null ) {
functionDescriptor = new NamedSqmFunctionDescriptor( functionName, functionName, true, null );
}
return functionTemplate.makeSqmFunctionExpression(
functionArguments,
//noinspection unchecked
return new SqmFunction(
functionName,
functionDescriptor,
null,
creationContext.getQueryEngine()
functionArguments,
creationContext.getNodeBuilder()
);
}
@ -1888,10 +1919,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("ceiling").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType) resolveExpressableTypeBasic( Long.class ),
creationContext.getQueryEngine()
return new SqmFunction(
"ceiling",
getFunctionDescriptor( "ceiling" ),
StandardBasicTypes.LONG,
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@ -1900,15 +1933,17 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("floor").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType) resolveExpressableTypeBasic( Long.class ),
creationContext.getQueryEngine()
return new SqmFunction(
"floor",
getFunctionDescriptor( "floor" ),
StandardBasicTypes.LONG,
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
private SqmFunctionTemplate getFunctionTemplate(String name) {
return creationContext.getQueryEngine().getSqmFunctionRegistry().findFunctionTemplate( name );
private SqmFunctionDescriptor getFunctionDescriptor(String name) {
return creationContext.getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor( name );
}
@Override
@ -1916,10 +1951,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("abs").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType) arg.getNodeType(),
creationContext.getQueryEngine()
return new SqmFunction(
"abs",
getFunctionDescriptor( "abs" ),
arg.getNodeType(),
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@ -1928,10 +1965,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("sign").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType) resolveExpressableTypeBasic( Integer.class ),
creationContext.getQueryEngine()
return new SqmFunction(
"sign",
getFunctionDescriptor( "sign" ),
StandardBasicTypes.INTEGER,
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@ -1941,10 +1980,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression divisor = (SqmExpression) ctx.modDivisorArgument().accept( this );
//noinspection unchecked
return getFunctionTemplate("mod").makeSqmFunctionExpression(
return new SqmFunction(
"mod",
getFunctionDescriptor( "mod" ),
dividend.getNodeType(),
asList( dividend, divisor ),
(AllowableFunctionReturnType) dividend.getNodeType(),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -1954,21 +1995,28 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression power = (SqmExpression) ctx.powerPowerArgument().accept( this );
//noinspection unchecked
return getFunctionTemplate("power").makeSqmFunctionExpression(
return new SqmFunction(
"power",
getFunctionDescriptor( "power" ),
base.getNodeType(),
asList( base, power ),
(AllowableFunctionReturnType) base.getNodeType(),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitTrigFunction(HqlParser.TrigFunctionContext ctx) {
final String functionName = ctx.trigFunctionName().getText();
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
return getFunctionTemplate( ctx.trigFunctionName().getText() ).makeSqmFunctionExpression(
arg,
resolveExpressableTypeBasic( Double.class ),
creationContext.getQueryEngine()
//noinspection unchecked
return new SqmFunction(
functionName,
getFunctionDescriptor( functionName ),
StandardBasicTypes.DOUBLE,
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@ -1977,10 +2025,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("sqrt").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType) arg.getNodeType(),
creationContext.getQueryEngine()
return new SqmFunction(
"sqrt",
getFunctionDescriptor( "sqrt" ),
arg.getNodeType(),
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@ -1990,10 +2040,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression precision = (SqmExpression) ctx.roundFunctionPrecision().expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("round").makeSqmFunctionExpression(
asList(arg, precision),
(AllowableFunctionReturnType) arg.getNodeType(),
creationContext.getQueryEngine()
return new SqmFunction(
"round",
getFunctionDescriptor( "round" ),
arg.getNodeType(),
asList( arg, precision ),
creationContext.getNodeBuilder()
);
}
@ -2003,10 +2055,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression cos = (SqmExpression) ctx.expression().get( 1).accept( this );
//noinspection unchecked
return getFunctionTemplate("atan2").makeSqmFunctionExpression(
return new SqmFunction(
"atan2",
getFunctionDescriptor( "atan2" ),
sin.getNodeType(),
asList(sin, cos),
(AllowableFunctionReturnType) sin.getNodeType(),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -2015,12 +2069,13 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("ln").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType) arg.getNodeType(),
creationContext.getQueryEngine()
return new SqmFunction(
"ln",
getFunctionDescriptor( "ln" ),
arg.getNodeType(),
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@Override
@ -2028,10 +2083,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("exp").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType) arg.getNodeType(),
creationContext.getQueryEngine()
return new SqmFunction(
"exp",
getFunctionDescriptor( "exp" ),
arg.getNodeType(),
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@ -2156,29 +2213,27 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
}
//noinspection unchecked
return getFunctionTemplate("extract").makeSqmFunctionExpression(
return new SqmFunction(
"extract",
getFunctionDescriptor( "extract" ),
extractFieldExpression.getNodeType(),
asList( extractFieldExpression, expressionToExtract ),
extractFieldExpression.getType(),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitCastFunction(HqlParser.CastFunctionContext ctx) {
final SqmExpression<?> expressionToCast = (SqmExpression) ctx.expression().accept( this );
final SqmCastTarget<?> castTargetExpression = interpretCastTarget( ctx.castTarget() );
//getSessionFactory().getTypeConfiguration().resolveCastTargetType( ctx.dataType().IDENTIFIER().getText() )
// if ( !AllowableFunctionReturnType.class.isInstance( castTargetExpression ) ) {
// throw new SqmProductionException( "Found cast target expression [%s] which is not allowed as a function return" );
// }
return getFunctionTemplate("cast").makeSqmFunctionExpression(
//noinspection unchecked
return new SqmFunction(
"cast",
getFunctionDescriptor( "cast" ),
castTargetExpression.getNodeType(),
asList( expressionToCast, castTargetExpression ),
castTargetExpression.getType(),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -2252,23 +2307,25 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
public SqmExpression visitUpperFunction(HqlParser.UpperFunctionContext ctx) {
final SqmExpression expression = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("upper").makeSqmFunctionExpression(
expression,
(AllowableFunctionReturnType) expression.getNodeType(),
creationContext.getQueryEngine()
return new SqmFunction(
"upper",
getFunctionDescriptor( "upper" ),
expression.getNodeType(),
Collections.singletonList( expression ),
creationContext.getNodeBuilder()
);
}
@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.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("lower").makeSqmFunctionExpression(
expression,
(AllowableFunctionReturnType) expression.getNodeType(),
creationContext.getQueryEngine()
return new SqmFunction(
"lower",
getFunctionDescriptor( "lower" ),
expression.getNodeType(),
Collections.singletonList( expression ),
creationContext.getNodeBuilder()
);
}
@ -2279,10 +2336,13 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
arguments.add( (SqmTypedNode<?>) argument.accept( this ) );
}
return getFunctionTemplate("concat").makeSqmFunctionExpression(
//noinspection unchecked
return new SqmFunction(
"concat",
getFunctionDescriptor( "concat" ),
StandardBasicTypes.STRING,
arguments,
resolveExpressableTypeBasic( String.class ),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -2290,10 +2350,13 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
public Object visitLengthFunction(HqlParser.LengthFunctionContext ctx) {
final SqmExpression arg = (SqmExpression) ctx.expression().accept( this );
return getFunctionTemplate("character_length").makeSqmFunctionExpression(
arg,
resolveExpressableTypeBasic( Integer.class ),
creationContext.getQueryEngine()
//noinspection unchecked
return new SqmFunction(
"character_length",
getFunctionDescriptor( "character_length" ),
StandardBasicTypes.INTEGER,
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@ -2302,10 +2365,13 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression<?> string = (SqmExpression) ctx.positionFunctionStringArgument().accept( this );
final SqmExpression<?> pattern = (SqmExpression) ctx.positionFunctionPatternArgument().accept( this );
return getFunctionTemplate("locate").makeSqmFunctionExpression(
//noinspection unchecked
return new SqmFunction(
"locate",
getFunctionDescriptor( "locate" ),
StandardBasicTypes.INTEGER,
asList( pattern, string ),
resolveExpressableTypeBasic( Integer.class ),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -2317,12 +2383,15 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
? null
: (SqmExpression) ctx.locateFunctionStartArgument().accept( this );
return getFunctionTemplate("locate").makeSqmFunctionExpression(
//noinspection unchecked
return new SqmFunction(
"locate",
getFunctionDescriptor( "locate" ),
StandardBasicTypes.INTEGER,
start == null
? asList( pattern, string )
: asList( pattern, string, start ),
resolveExpressableTypeBasic( Integer.class ),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@ -2333,84 +2402,110 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression<?> pattern = (SqmExpression) ctx.replaceFunctionPatternArgument().accept( this );
final SqmExpression<?> replacement = (SqmExpression) ctx.replaceFunctionReplacementArgument().accept( this );
return getFunctionTemplate("replace").makeSqmFunctionExpression(
//noinspection unchecked
return new SqmFunction(
"replace",
getFunctionDescriptor( "replace" ),
StandardBasicTypes.INTEGER,
asList( string, pattern, replacement ),
resolveExpressableTypeBasic( String.class ),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}
@Override
public Object visitStrFunction(HqlParser.StrFunctionContext ctx) {
final SqmExpression<?> arg = (SqmExpression) ctx.expression().accept( this );
AllowableFunctionReturnType<String> type = resolveExpressableTypeBasic( String.class );
return getFunctionTemplate("cast").makeSqmFunctionExpression(
asList( arg, new SqmCastTarget<>( type, creationContext.getNodeBuilder() ) ),
final AllowableFunctionReturnType<String> type = resolveExpressableTypeBasic( String.class );
final SqmCastTarget<String> castTarget = new SqmCastTarget<>( type, creationContext.getNodeBuilder() );
//noinspection unchecked
return new SqmFunction(
"cast",
getFunctionDescriptor( "cast" ),
type,
creationContext.getQueryEngine()
asList( arg, castTarget ),
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitMaxFunction(HqlParser.MaxFunctionContext ctx) {
final SqmExpression<?> arg = (SqmExpression) ctx.expression().accept( this );
//ignore DISTINCT
return getFunctionTemplate("max").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType<?>) arg.getNodeType(),
creationContext.getQueryEngine()
//noinspection unchecked
return new SqmFunction(
"max",
getFunctionDescriptor( "max" ),
arg.getNodeType(),
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitMinFunction(HqlParser.MinFunctionContext ctx) {
final SqmExpression<?> arg = (SqmExpression) ctx.expression().accept( this );
//ignore DISTINCT
return getFunctionTemplate("min").makeSqmFunctionExpression(
arg,
(AllowableFunctionReturnType<?>) arg.getNodeType(),
creationContext.getQueryEngine()
//noinspection unchecked
return new SqmFunction(
"min",
getFunctionDescriptor( "min" ),
arg.getNodeType(),
Collections.singletonList( arg ),
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitSumFunction(HqlParser.SumFunctionContext ctx) {
final SqmExpression<?> arg = (SqmExpression) ctx.expression().accept( this );
SqmTypedNode<?> argument = ctx.DISTINCT() != null ? new SqmDistinct<>( arg, getCreationContext().getNodeBuilder()) : arg;
final SqmTypedNode<?> argument = ctx.DISTINCT() != null
? new SqmDistinct<>( arg, getCreationContext().getNodeBuilder() )
: arg;
return getFunctionTemplate("sum").makeSqmFunctionExpression(
argument,
(AllowableFunctionReturnType<?>) arg.getNodeType(),
creationContext.getQueryEngine()
//noinspection unchecked
return new SqmFunction(
"sum",
getFunctionDescriptor( "sum" ),
arg.getNodeType(),
Collections.singletonList( argument ),
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitAvgFunction(HqlParser.AvgFunctionContext ctx) {
final SqmExpression<?> arg = (SqmExpression) ctx.expression().accept( this );
SqmTypedNode<?> argument = ctx.DISTINCT() != null ? new SqmDistinct<>( arg, getCreationContext().getNodeBuilder()) : arg;
final SqmTypedNode<?> argument = ctx.DISTINCT() != null
? new SqmDistinct<>( arg, getCreationContext().getNodeBuilder() )
: arg;
return getFunctionTemplate("avg").makeSqmFunctionExpression(
argument,
resolveExpressableTypeBasic( Double.class ),
creationContext.getQueryEngine()
//noinspection unchecked
return new SqmFunction(
"avg",
getFunctionDescriptor( "avg" ),
arg.getNodeType(),
Collections.singletonList( argument ),
creationContext.getNodeBuilder()
);
}
@Override
public SqmExpression visitCountFunction(HqlParser.CountFunctionContext ctx) {
final SqmExpression<?> arg = ctx.ASTERISK() != null
? new SqmStar( getCreationContext().getNodeBuilder() )
: (SqmExpression) ctx.expression().accept( this );
SqmTypedNode<?> argument = ctx.DISTINCT() != null ? new SqmDistinct<>( arg, getCreationContext().getNodeBuilder() ) : arg;
final SqmTypedNode<?> argument = ctx.DISTINCT() != null
? new SqmDistinct<>( arg, getCreationContext().getNodeBuilder() )
: arg;
return getFunctionTemplate("count").makeSqmFunctionExpression(
argument,
resolveExpressableTypeBasic( Long.class ),
creationContext.getQueryEngine()
//noinspection unchecked
return new SqmFunction(
"count",
getFunctionDescriptor( "count" ),
StandardBasicTypes.LONG,
Collections.singletonList( argument ),
creationContext.getNodeBuilder()
);
}
@ -2423,12 +2518,13 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
: (SqmExpression) ctx.substringFunctionLengthArgument().accept( this );
//noinspection unchecked
return getFunctionTemplate("substring").makeSqmFunctionExpression(
length==null ? asList( source, start ) : asList( source, start, length ),
resolveExpressableTypeBasic( String.class ),
creationContext.getQueryEngine()
return new SqmFunction(
"substring",
getFunctionDescriptor( "substring" ),
StandardBasicTypes.STRING,
length == null ? asList( source, start ) : asList( source, start, length ),
creationContext.getNodeBuilder()
);
}
@Override
@ -2436,14 +2532,16 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
final SqmExpression source = (SqmExpression) ctx.expression().accept( this );
//noinspection unchecked
return getFunctionTemplate("trim").makeSqmFunctionExpression(
return new SqmFunction(
"trim",
getFunctionDescriptor( "trim" ),
StandardBasicTypes.STRING,
asList(
interpretTrimSpecification( ctx.trimSpecification() ),
visitTrimCharacter( ctx.trimCharacter() ),
source
),
resolveExpressableTypeBasic( String.class ),
creationContext.getQueryEngine()
creationContext.getNodeBuilder()
);
}

View File

@ -29,7 +29,7 @@ import org.hibernate.query.named.NamedQueryRepository;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.internal.SqmCreationOptionsStandard;
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory;

View File

@ -50,7 +50,6 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmSetJoin;
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -62,7 +61,7 @@ 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.service.ServiceRegistry;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.type.spi.TypeConfiguration;
/**

View File

@ -25,8 +25,11 @@ import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
@ -39,12 +42,10 @@ import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.function.SqmCastTarget;
import org.hibernate.query.sqm.function.SqmDistinct;
import org.hibernate.query.sqm.function.SqmExtractUnit;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.function.SqmStar;
import org.hibernate.query.sqm.function.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
@ -196,15 +197,21 @@ public interface SemanticQueryWalker<T> {
T visitUnaryOperationExpression(SqmUnaryOperation<?> expression);
T visitFunction(SqmFunction tSqmFunction);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// expressions - non-standard functions
T visitExtractUnit(SqmExtractUnit extractUnit);
T visitFunction(SqmFunction<?> sqmFunction);
T visitCastTarget(SqmCastTarget sqmCastTarget);
T visitTrimSpecification(SqmTrimSpecification trimSpecification);
T visitDistinct(SqmDistinct distinct);
T visitStar(SqmStar sqmStar);
T visitCoalesce(SqmCoalesce sqmCoalesce);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// expressions - standard functions
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// predicates
@ -262,14 +269,4 @@ public interface SemanticQueryWalker<T> {
T visitMapEntryFunction(SqmMapEntryReference function);
T visitFullyQualifiedClass(Class<?> namedClass);
T visitExtractUnit(SqmExtractUnit extractUnit);
T visitCastTarget(SqmCastTarget sqmCastTarget);
T visitTrimSpecification(SqmTrimSpecification trimSpecification);
T visitDistinct(SqmDistinct distinct);
T visitStar(SqmStar sqmStar);
}

View File

@ -0,0 +1,111 @@
/*
* 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
/**
* @author Steve Ebersole
*/
public abstract class AbstractSelfRenderingFunctionTemplate extends AbstractSqmFunctionDescriptor {
private final ArgumentsValidator argumentsValidator;
public AbstractSelfRenderingFunctionTemplate(ArgumentsValidator argumentsValidator) {
super();
this.argumentsValidator = argumentsValidator == null
? StandardArgumentsValidators.NONE
: argumentsValidator;
}
@Override
public Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> sqmArguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState) {
argumentsValidator.validate( sqmArguments );
// todo (6.0) : work out the specifics of the type resolution
final List<SqlAstNode> sqlAstArgs;
if ( sqmArguments == null || sqmArguments.isEmpty() ) {
sqlAstArgs = Collections.emptyList();
}
else if ( sqmArguments.size() == 1 ) {
sqlAstArgs = Collections.singletonList(
(SqlAstNode) sqmArguments.get( 0 ).accept( converter )
);
}
else {
sqlAstArgs = new ArrayList<>( sqmArguments.size() );
for ( int i = 0; i < sqmArguments.size(); i++ ) {
final SqmVisitableNode sqmVisitableNode = sqmArguments.get( i );
sqlAstArgs.add( (SqlAstNode) sqmVisitableNode.accept( converter ) );
}
}
return new SelfRenderingSqlFunctionExpression(
functionName,
inferableTypeAccess.get(),
sqlAstArgs,
getRenderingSupport()
);
}
protected abstract FunctionRenderingSupport getRenderingSupport();
private static class SelfRenderingSqlFunctionExpression implements SelfRenderingExpression {
private final String name;
private final MappingModelExpressable type;
private final List<SqlAstNode> arguments;
private final FunctionRenderingSupport renderingSupport;
public SelfRenderingSqlFunctionExpression(
String name,
MappingModelExpressable type,
List<SqlAstNode> arguments,
FunctionRenderingSupport renderingSupport) {
this.name = name;
this.type = type;
this.arguments = arguments;
this.renderingSupport = renderingSupport;
}
@Override
public void renderToSql(
SqlAppender sqlAppender,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {
renderingSupport.render( sqlAppender, name, arguments, walker, sessionFactory );
}
@Override
public MappingModelExpressable getExpressionType() {
return type;
}
}
}

View File

@ -0,0 +1,115 @@
/*
* 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
/**
* Support for SQM function descriptors which ultimately render themselves
*
* @author Steve Ebersole
*/
public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescriptor {
private final ArgumentsValidator argumentsValidator;
public AbstractSqmFunctionDescriptor() {
this( null );
}
public AbstractSqmFunctionDescriptor(ArgumentsValidator argumentsValidator) {
this.argumentsValidator = argumentsValidator == null
? StandardArgumentsValidators.NONE
: argumentsValidator;
}
@Override
public Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> sqmArguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState) {
argumentsValidator.validate( sqmArguments );
// todo (6.0) : work out the specifics of the type resolution
final List<SqlAstNode> sqlAstArgs;
if ( sqmArguments == null || sqmArguments.isEmpty() ) {
sqlAstArgs = Collections.emptyList();
}
else if ( sqmArguments.size() == 1 ) {
sqlAstArgs = Collections.singletonList(
(SqlAstNode) sqmArguments.get( 0 ).accept( converter )
);
}
else {
sqlAstArgs = new ArrayList<>( sqmArguments.size() );
for ( int i = 0; i < sqmArguments.size(); i++ ) {
final SqmVisitableNode sqmVisitableNode = sqmArguments.get( i );
sqlAstArgs.add( (SqlAstNode) sqmVisitableNode.accept( converter ) );
}
}
return new SelfRenderingSqlFunctionExpression(
functionName,
inferableTypeAccess.get(),
sqlAstArgs,
getRenderingSupport()
);
}
protected abstract FunctionRenderingSupport getRenderingSupport();
private static class SelfRenderingSqlFunctionExpression implements SelfRenderingExpression {
private final String name;
private final MappingModelExpressable type;
private final List<SqlAstNode> arguments;
private final FunctionRenderingSupport renderingSupport;
public SelfRenderingSqlFunctionExpression(
String name,
MappingModelExpressable type,
List<SqlAstNode> arguments,
FunctionRenderingSupport renderingSupport) {
this.name = name;
this.type = type;
this.arguments = arguments;
this.renderingSupport = renderingSupport;
}
@Override
public void renderToSql(
SqlAppender sqlAppender,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {
renderingSupport.render( sqlAppender, name, arguments, walker, sessionFactory );
}
@Override
public MappingModelExpressable getExpressionType() {
return type;
}
}
}

View File

@ -4,18 +4,14 @@
* 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.produce.function.spi;
package org.hibernate.query.sqm.function;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.jboss.logging.Logger;
@ -24,8 +20,8 @@ import org.jboss.logging.Logger;
* @author Steve Ebersole
*/
public class FunctionAsExpressionTemplate
extends AbstractSelfRenderingFunctionTemplate
implements SelfRenderingFunctionSupport {
extends AbstractSqmFunctionDescriptor
implements FunctionRenderingSupport {
private static final Logger log = Logger.getLogger( FunctionAsExpressionTemplate.class );
@ -37,28 +33,22 @@ public class FunctionAsExpressionTemplate
String expressionStart,
String argumentSeparator,
String expressionEnd,
FunctionReturnTypeResolver returnTypeResolver,
ArgumentsValidator argumentsValidator,
String name) {
super( name, returnTypeResolver, argumentsValidator );
ArgumentsValidator argumentsValidator) {
super( argumentsValidator );
this.expressionStart = expressionStart;
this.argumentSeparator = argumentSeparator;
this.expressionEnd = expressionEnd;
}
@Override
protected SelfRenderingFunctionSupport getRenderingFunctionSupport(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<?> resolvedReturnType,
QueryEngine queryEngine) {
protected FunctionRenderingSupport getRenderingSupport() {
return this;
}
@Override
@SuppressWarnings("unchecked")
public void render(
SqlAppender sqlAppender,
List<SqlAstNode> sqlAstArguments,
String functionName, List<SqlAstNode> sqlAstArguments,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {
sqlAppender.appendSql( expressionStart );
@ -68,31 +58,15 @@ public class FunctionAsExpressionTemplate
}
else {
// render the first argument..
renderArgument( sqlAppender, sqlAstArguments.get( 0 ), walker, sessionFactory );
sqlAstArguments.get( 0 ).accept( walker );
// render the rest of the arguments, preceded by the separator
for ( int i = 1; i < sqlAstArguments.size(); i++ ) {
sqlAppender.appendSql( argumentSeparator );
renderArgument( sqlAppender, sqlAstArguments.get( i ), walker, sessionFactory );
sqlAstArguments.get( i ).accept( walker );
}
}
sqlAppender.appendSql( expressionEnd );
}
/**
* Called from {@link #render} to render an argument.
*
* @param sqlAppender The sql appender to append the rendered argument.
* @param sqlAstArgument The argument being processed.
* @param walker The walker to use for rendering {@link SqlAstNode} expressions
* @param sessionFactory The session factory
*/
protected void renderArgument(
SqlAppender sqlAppender,
SqlAstNode sqlAstArgument,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {
sqlAstArgument.accept( walker );
}
}

View File

@ -4,7 +4,7 @@
* 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.produce.function.spi;
package org.hibernate.query.sqm.function;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -14,14 +14,14 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
import java.util.List;
/**
* Support for SqmFunctionTemplates that ultimately want to
* perform SQL rendering themselves
* Support for SqmFunctionDescriptors that ultimately want to perform SQL rendering themselves
*
* @author Steve Ebersole
*/
public interface SelfRenderingFunctionSupport {
public interface FunctionRenderingSupport {
void render(
SqlAppender sqlAppender,
String functionName,
List<SqlAstNode> sqlAstArguments,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory);

View File

@ -0,0 +1,76 @@
/*
* 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;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
/**
* Acts as a wrapper to another SqmFunctionTemplate - upon rendering uses the
* standard JDBC escape sequence (i.e. `{fn blah}`) when rendering the SQL.
*
* @author Steve Ebersole
*/
public class JdbcEscapeFunctionDescriptor implements SqmFunctionDescriptor {
private final SqmFunctionDescriptor wrapped;
@SuppressWarnings("WeakerAccess")
public JdbcEscapeFunctionDescriptor(SqmFunctionDescriptor wrapped) {
this.wrapped = wrapped;
}
@Override
public Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> sqmArguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState) {
final Expression wrappedExpression = wrapped.generateSqlExpression(
functionName,
sqmArguments,
inferableTypeAccess,
converter,
creationState
);
return new EscapeExpression( wrappedExpression );
}
private static class EscapeExpression implements SelfRenderingExpression {
private final Expression wrappedExpression;
EscapeExpression(Expression wrappedExpression) {
this.wrappedExpression = wrappedExpression;
}
@Override
public void renderToSql(
SqlAppender sqlAppender,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {
sqlAppender.appendSql( "{fn " );
wrappedExpression.accept( walker );
sqlAppender.appendSql( "}" );
}
@Override
public MappingModelExpressable getExpressionType() {
return wrappedExpression.getExpressionType();
}
}
}

View File

@ -0,0 +1,82 @@
/*
* 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;
import java.util.Locale;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.sql.ast.tree.SqlAstNode;
/**
* Provides a standard implementation that supports the majority of the HQL
* functions that are translated to SQL. The Dialect and its sub-classes use
* this class to provide details required for processing of the associated
* function.
*
* @author David Channon
* @author Steve Ebersole
*/
public class NamedSqmFunctionDescriptor extends AbstractSqmFunctionDescriptor {
private final String functionKey;
private final String functionName;
private final boolean useParenthesesWhenNoArgs;
public NamedSqmFunctionDescriptor(
String functionKey,
String functionName,
boolean useParenthesesWhenNoArgs,
ArgumentsValidator argumentsValidator) {
super( argumentsValidator );
this.functionKey = functionKey;
this.functionName = functionName;
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
}
public String getFunctionKey() {
return functionKey;
}
public String getFunctionName() {
return functionName;
}
@Override
protected FunctionRenderingSupport getRenderingSupport() {
return (sqlAppender, functionName1, sqlAstArguments, walker, sessionFactory) -> {
final boolean useParens = useParenthesesWhenNoArgs || !sqlAstArguments.isEmpty();
sqlAppender.appendSql( functionName );
if ( useParens ) {
sqlAppender.appendSql( "(" );
}
boolean firstPass = true;
for ( SqlAstNode sqlAstArgument : sqlAstArguments ) {
if ( !firstPass ) {
sqlAppender.appendSql( ", " );
}
sqlAstArgument.accept( walker );
firstPass = false;
}
if ( useParens ) {
sqlAppender.appendSql( ")" );
}
};
}
@Override
public String toString() {
return String.format(
Locale.ROOT,
"NamedSqmFunctionTemplate(%s)",
functionName
);
}
}

View File

@ -4,22 +4,19 @@
* 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.produce.function.spi;
package org.hibernate.query.sqm.function;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import java.util.List;
/**
* Represents HQL functions that can have different representations in different SQL dialects where that
* difference can be handled via a template/pattern.
@ -33,8 +30,8 @@ import java.util.List;
* @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
*/
public class PatternBasedSqmFunctionTemplate
extends AbstractSelfRenderingFunctionTemplate
implements SelfRenderingFunctionSupport {
extends AbstractSqmFunctionDescriptor
implements FunctionRenderingSupport {
private final PatternRenderer renderer;
/**
@ -43,11 +40,8 @@ public class PatternBasedSqmFunctionTemplate
public PatternBasedSqmFunctionTemplate(
PatternRenderer renderer,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
String name) {
FunctionReturnTypeResolver returnTypeResolver) {
super(
name,
returnTypeResolver,
argumentsValidator != null
? argumentsValidator
// If no validator is given, it's still better to validate against the parameter count as given
@ -58,16 +52,14 @@ public class PatternBasedSqmFunctionTemplate
}
@Override
protected SelfRenderingFunctionSupport getRenderingFunctionSupport(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<?> impliedResultType,
QueryEngine queryEngine) {
protected FunctionRenderingSupport getRenderingSupport() {
return this;
}
@Override
public void render(
SqlAppender sqlAppender,
String functionName,
List<SqlAstNode> sqlAstArguments,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {

View File

@ -1,40 +0,0 @@
/*
* 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;
import org.hibernate.query.criteria.JpaFunction;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
/**
* Contract for functions impls that would like to control the
* translation of the SQM expression into the SQL AST function
* <p/>
* {@link #convertToSqlAst} is the main contract here. It will
* be called as we walk the SQM tree to generate SQL AST and
* asked to produce the equivalent SQL AST expression
*
* @author Steve Ebersole
*/
public interface SqmFunction<T> extends SqmExpression<T>, JpaFunction<T>, DomainResultProducer<T> {
// /**
// * Generate the SQL AST form of the function as an expression.
// *
// * To be able to use this in the select-clause, the returned
// * expression must also implement the
// * {@link DomainResultProducer}
// * contract
// */
// Expression convertToSqlAst(SqmToSqlAstConverter walker);
//
@Override
default <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitFunction( this );
}
}

View File

@ -0,0 +1,39 @@
/*
* 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;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.Incubating;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression;
/**
* Extension for supplying support for non-standard (ANSI SQL) functions in HQL and Criteria queries.
*
* Ultimately acts as a factory for SQM function expressions.
*
* @author David Channon
* @author Steve Ebersole
*/
@Incubating
public interface SqmFunctionDescriptor {
/**
* Generate a representation of the described function as a SQL AST node
*/
Expression generateSqlExpression(
String functionName,
List<? extends SqmVisitableNode> arguments,
Supplier<MappingModelExpressable> inferableTypeAccess,
SqmToSqlAstConverter converter,
SqlAstCreationState creationState);
}

View File

@ -0,0 +1,218 @@
/*
* 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;
import java.util.Map;
import java.util.TreeMap;
import org.hibernate.Incubating;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.produce.function.NamedFunctionDescriptorBuilder;
import org.hibernate.query.sqm.produce.function.PatternFunctionDescriptorBuilder;
import org.hibernate.query.sqm.produce.function.VarArgsFunctionDescriptorBuilder;
import org.jboss.logging.Logger;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
/**
* Defines a registry for SQLFunction instances
*
* @author Steve Ebersole
*/
@Incubating
public class SqmFunctionRegistry {
private static final Logger log = Logger.getLogger( SqmFunctionRegistry.class );
private final Map<String, SqmFunctionDescriptor> functionMap = new TreeMap<>( CASE_INSENSITIVE_ORDER );
private final Map<String,String> alternateKeyMap = new TreeMap<>( CASE_INSENSITIVE_ORDER );
public SqmFunctionRegistry() {
log.tracef( "SqmFunctionRegistry created" );
}
/**
* Find a SqmFunctionTemplate by name. Returns {@code null} if
* no such function is found.
*/
public SqmFunctionDescriptor findFunctionDescriptor(String functionName) {
SqmFunctionDescriptor found = null;
final String alternateKeyResolution = alternateKeyMap.get( functionName );
if ( alternateKeyResolution != null ) {
found = functionMap.get( alternateKeyResolution );
}
if ( found == null ) {
found = functionMap.get( functionName );
}
return found;
}
/**
* Register a function descriptor by name
*/
public SqmFunctionDescriptor register(String registrationKey, SqmFunctionDescriptor function) {
final SqmFunctionDescriptor priorRegistration = functionMap.put( registrationKey, function );
log.debugf(
"Registered SqmFunctionTemplate [%s] under %s; prior registration was %s",
function,
registrationKey,
priorRegistration
);
return function;
}
/**
* Register a pattern-based descriptor by name. Shortcut for building the descriptor via
* {@link #patternDescriptorBuilder} accepting its defaults.
*/
public SqmFunctionDescriptor registerPattern(String name, String pattern) {
return patternDescriptorBuilder( name, pattern ).register();
}
/**
* Register a pattern-based descriptor by name and invariant return type. Shortcut for building the descriptor
* via {@link #patternDescriptorBuilder} accepting its defaults.
*/
public SqmFunctionDescriptor registerPattern(String name, String pattern, AllowableFunctionReturnType returnType) {
return patternDescriptorBuilder( name, pattern )
.setInvariantType( returnType )
.register();
}
/**
* Get a builder for creating and registering a pattern-based function descriptor.
*
* @param registrationKey The name under which the descriptor will get registered
* @param pattern The pattern defining the the underlying function call
*
* @return The builder
*/
public PatternFunctionDescriptorBuilder patternDescriptorBuilder(String registrationKey, String pattern) {
return new PatternFunctionDescriptorBuilder( this, registrationKey, pattern );
}
/**
* Register a descriptor by name. Shortcut for building a descriptor via {@link #namedDescriptorBuilder} using the
* passed name as both the registration key and underlying SQL function name and accepting the builder's defaults.
*
* @param name The function name (and registration key)
*/
public SqmFunctionDescriptor registerNamed(String name) {
return namedDescriptorBuilder( name ).register();
}
/**
* Register a named descriptor by name and invariant return type. Shortcut for building
* a descriptor via {@link #namedDescriptorBuilder} using the passed name as both the
* registration key and underlying SQL function name and accepting the builder's defaults.
*
* @param name The function name (and registration key)
*/
public SqmFunctionDescriptor registerNamed(String name, AllowableFunctionReturnType returnType) {
return namedDescriptorBuilder( name ).setInvariantType( returnType ).register();
}
/**
* Get a builder for creating and registering a name-based function descriptor using the passed name as
* both the registration key and underlying SQL function name
*
* @param name The function name (and registration key)
*
* @return The builder
*/
public NamedFunctionDescriptorBuilder namedDescriptorBuilder(String name) {
return namedDescriptorBuilder( name, name );
}
/**
* Get a builder for creating and registering a name-based function descriptor.
*
* @param registrationKey The name under which the descriptor will get registered
* @param name The underlying SQL function name to use
*
* @return The builder
*/
public NamedFunctionDescriptorBuilder namedDescriptorBuilder(String registrationKey, String name) {
return new NamedFunctionDescriptorBuilder( this, registrationKey, name );
}
public NamedFunctionDescriptorBuilder noArgsBuilder(String name) {
return noArgsBuilder( name, name );
}
public NamedFunctionDescriptorBuilder noArgsBuilder(String registrationKey, String name) {
return namedDescriptorBuilder( registrationKey, name )
.setExactArgumentCount( 0 );
}
public VarArgsFunctionDescriptorBuilder varArgsBuilder(String registrationKey, String begin, String sep, String end) {
return new VarArgsFunctionDescriptorBuilder( this, registrationKey, begin, sep, end );
}
/**
* Specialized registration method for registering a named template for functions
* expecting zero arguments. Short-cut for building a named template via
* {@link #namedDescriptorBuilder} specifying zero arguments and accepting the
* rest of the builder's defaults.
*
* @param name The function name (and registration key)
*/
public SqmFunctionDescriptor registerNoArgs(String name) {
return registerNoArgs( name, name );
}
public SqmFunctionDescriptor registerNoArgs(String registrationKey, String name) {
return noArgsBuilder( registrationKey, name ).register();
}
public SqmFunctionDescriptor registerNoArgs(String name, AllowableFunctionReturnType returnType) {
return registerNoArgs( name, name, returnType );
}
public SqmFunctionDescriptor registerNoArgs(String registrationKey, String name, AllowableFunctionReturnType returnType) {
return noArgsBuilder( registrationKey, name )
.setInvariantType( returnType )
.register();
}
public SqmFunctionDescriptor registerVarArgs(String registrationKey, AllowableFunctionReturnType returnType, String begin, String sep, String end) {
return varArgsBuilder( registrationKey, begin, sep, end )
.setInvariantType( returnType )
.register();
}
public SqmFunctionDescriptor wrapInJdbcEscape(String registrationKey, SqmFunctionDescriptor wrapped) {
final JdbcEscapeFunctionDescriptor wrapperTemplate = new JdbcEscapeFunctionDescriptor( wrapped );
register( registrationKey, wrapperTemplate );
return wrapperTemplate;
}
public void registerAlternateKey(String alternateKey, String mappedKey) {
log.debugf( "Registering alternate key : %s -> %s", alternateKey, mappedKey );
alternateKeyMap.put( alternateKey, mappedKey );
}
/**
* Overlay the functions registered here on top of the
* incoming registry, potentially overriding its registrations
*/
public void overlay(SqmFunctionRegistry registryToOverly) {
// NOTE : done in this "direction" as it is easier to access the
// functionMap directly in performing this operation
functionMap.forEach( registryToOverly::register );
alternateKeyMap.forEach( registryToOverly::registerAlternateKey );
}
public void close() {
functionMap.clear();
alternateKeyMap.clear();
}
}

View File

@ -1,52 +0,0 @@
/*
* 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;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.produce.function.internal.SelfRenderingSqmFunction;
/**
* Adds a JDBC function escape (i.e. `{fn <wrapped-function-call>}) around the wrapped function
*
* @author Steve Ebersole
* @author Gavin King
*/
public class SqmJdbcFunctionEscapeWrapper<T>
extends SelfRenderingSqmFunction<T> {
private final SelfRenderingSqmFunction<?> wrappedSqmFunction;
public SqmJdbcFunctionEscapeWrapper(
SelfRenderingSqmFunction<T> wrappedSqmFunction,
NodeBuilder nodeBuilder) {
super(
(sqlAppender,
sqlAstArguments,
walker,
sessionFactory) -> {
sqlAppender.appendSql( "{fn " );
wrappedSqmFunction.getRenderingSupport().render(
sqlAppender,
sqlAstArguments,
walker,
sessionFactory
);
sqlAppender.appendSql( "}" );
},
wrappedSqmFunction.getArguments(),
wrappedSqmFunction.getNodeType(),
nodeBuilder,
wrappedSqmFunction.getFunctionName()
);
this.wrappedSqmFunction = wrappedSqmFunction;
}
@Override
public String asLoggableText() {
return "wrapped-function[ " + wrappedSqmFunction.asLoggableText() + " ]";
}
}

View File

@ -47,6 +47,6 @@
* * str - generally defined as `cast(?1 as CHAR )`
* * non-standard functions
* * using JPA's function('function_name', [args]*) syntax.
* * directly leveraging Hibernate's {@link org.hibernate.query.sqm.produce.function.SqmFunctionRegistry}
* * directly leveraging Hibernate's {@link org.hibernate.query.sqm.function.SqmFunctionRegistry}
*/
package org.hibernate.query.sqm.function;

View File

@ -37,12 +37,13 @@ import org.hibernate.QueryException;
import org.hibernate.SortOrder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.BinaryArithmeticOperator;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.SemanticException;
import org.hibernate.query.TrimSpec;
import org.hibernate.query.UnaryArithmeticOperator;
import org.hibernate.query.criteria.JpaCoalesce;
@ -52,12 +53,10 @@ import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate;
import org.hibernate.query.sqm.function.SqmCastTarget;
import org.hibernate.query.sqm.function.SqmDistinct;
import org.hibernate.query.sqm.function.SqmTrimSpecification;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.tree.SqmNode;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.SqmBagJoin;
@ -66,18 +65,22 @@ import org.hibernate.query.sqm.tree.domain.SqmMapJoin;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmSetJoin;
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.function.SqmCoalesce;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
@ -100,7 +103,6 @@ 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.service.ServiceRegistry;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.type.StandardBasicTypes;
import static java.util.Arrays.asList;
@ -112,7 +114,7 @@ import static org.hibernate.query.internal.QueryHelper.highestPrecedenceType;
*
* @author Steve Ebersole
*/
public class SqmCriteriaNodeBuilder implements NodeBuilder {
public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
/**
* Simplified creation from a SessionFactory
*/
@ -152,6 +154,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
return queryEngine;
}
@Override
public JpaMetamodel getJpaMetamodel() {
return domainModel;
}
public void close() {
// for potential future use
}
@ -188,13 +195,14 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override
public <X, T> SqmExpression<X> cast(JpaExpression<T> expression, Class<X> castTargetJavaType) {
final BasicDomainType type = getTypeConfiguration().standardBasicTypeForJavaType( castTargetJavaType );
//noinspection unchecked
BasicDomainType<X> type = getTypeConfiguration().standardBasicTypeForJavaType( castTargetJavaType );
//noinspection unchecked
return getFunctionTemplate("cast").makeSqmFunctionExpression(
asList( (SqmTypedNode) expression, new SqmCastTarget<>( type, this ) ),
return new SqmFunction(
"cast",
getFunctionDescriptor( "cast" ),
type,
queryEngine
asList( (SqmTypedNode) expression, new SqmCastTarget<>( type, this ) ),
this
);
}
@ -439,19 +447,24 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override
public <N extends Number> SqmExpression<Double> avg(Expression<N> argument) {
//noinspection unchecked
return getFunctionTemplate("avg").makeSqmFunctionExpression(
(SqmTypedNode) argument,
return new SqmFunction(
"avg",
getFunctionDescriptor( "avg" ),
StandardBasicTypes.DOUBLE,
queryEngine
Collections.singletonList( (SqmTypedNode) argument ),
this
);
}
@Override
public <N extends Number> SqmExpression<N> sum(Expression<N> argument) {
return getFunctionTemplate("sum").makeSqmFunctionExpression(
(SqmTypedNode) argument,
(AllowableFunctionReturnType<N>) ((SqmExpression<N>) argument).getNodeType(),
queryEngine
//noinspection unchecked
return new SqmFunction(
"sum",
getFunctionDescriptor( "sum" ),
( (SqmExpression<N>) argument ).getNodeType(),
Collections.singletonList( (SqmTypedNode) argument ),
this
);
}
@ -467,19 +480,25 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override
public <N extends Number> SqmExpression<N> max(Expression<N> argument) {
return getFunctionTemplate("max").makeSqmFunctionExpression(
(SqmTypedNode) argument,
(AllowableFunctionReturnType<N>) ((SqmExpression<N>) argument).getNodeType(),
queryEngine
//noinspection unchecked
return new SqmFunction(
"max",
getFunctionDescriptor( "max" ),
( (SqmExpression<N>) argument ).getNodeType(),
Collections.singletonList( (SqmTypedNode) argument ),
this
);
}
@Override
public <N extends Number> SqmExpression<N> min(Expression<N> argument) {
return getFunctionTemplate("min").makeSqmFunctionExpression(
(SqmTypedNode) argument,
(AllowableFunctionReturnType<N>) ((SqmExpression<N>) argument).getNodeType(),
queryEngine
//noinspection unchecked
return new SqmFunction(
"min",
getFunctionDescriptor( "min" ),
( (SqmExpression<N>) argument ).getNodeType(),
Collections.singletonList( (SqmTypedNode) argument ),
this
);
}
@ -496,20 +515,24 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override
public SqmExpression<Long> count(Expression<?> argument) {
//noinspection unchecked
return getFunctionTemplate("count").makeSqmFunctionExpression(
(SqmTypedNode) argument,
return new SqmFunction(
"count",
getFunctionDescriptor( "count" ),
StandardBasicTypes.LONG,
queryEngine
Collections.singletonList( (SqmExpression) argument ),
this
);
}
@Override
public SqmExpression<Long> countDistinct(Expression<?> argument) {
//noinspection unchecked
return getFunctionTemplate("count").makeSqmFunctionExpression(
new SqmDistinct<>( (SqmExpression<?>) argument, getQueryEngine().getCriteriaBuilder() ),
return new SqmFunction(
"count",
getFunctionDescriptor( "count" ),
StandardBasicTypes.LONG,
queryEngine
Collections.singletonList( new SqmDistinct( (SqmExpression) argument, this ) ),
this
);
}
@ -524,10 +547,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override
public <N extends Number> SqmExpression<N> abs(Expression<N> x) {
return getFunctionTemplate("abs").makeSqmFunctionExpression(
(SqmTypedNode) x,
(AllowableFunctionReturnType<N>) ((SqmExpression<N>) x).getNodeType(),
queryEngine
//noinspection unchecked
return new SqmFunction(
"abs",
getFunctionDescriptor( "abs" ),
( (SqmExpression<N>) x ).getNodeType(),
Collections.singletonList( (SqmExpression) x ),
this
);
}
@ -663,13 +689,15 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override
public SqmExpression<Double> sqrt(Expression<? extends Number> x) {
//noinspection unchecked
return getFunctionTemplate("sqrt").makeSqmFunctionExpression(
(SqmTypedNode) x,
(AllowableFunctionReturnType) QueryHelper.highestPrecedenceType2(
((SqmExpression) x).getNodeType(),
return new SqmFunction(
"sqrt",
getFunctionDescriptor( "sqrt" ),
QueryHelper.highestPrecedenceType2(
( (SqmExpression) x ).getNodeType(),
StandardBasicTypes.DOUBLE
),
queryEngine
Collections.singletonList( (SqmExpression) x ),
this
);
}
@ -787,14 +815,16 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
final SqmExpression xSqmExpression = (SqmExpression) x;
final SqmExpression ySqmExpression = (SqmExpression) y;
//noinspection unchecked
return getFunctionTemplate( "concat" ).makeSqmFunctionExpression(
asList( xSqmExpression, ySqmExpression ),
(AllowableFunctionReturnType) highestPrecedenceType(
return new SqmFunction(
"concat",
getFunctionDescriptor( "concat" ),
highestPrecedenceType(
xSqmExpression.getNodeType(),
ySqmExpression.getNodeType(),
StandardBasicTypes.STRING
),
getQueryEngine()
asList( xSqmExpression, ySqmExpression ),
this
);
}
@ -803,14 +833,16 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
final SqmExpression xSqmExpression = (SqmExpression) x;
final SqmExpression ySqmExpression = literal( y );
//noinspection unchecked
return getFunctionTemplate( "concat" ).makeSqmFunctionExpression(
asList( xSqmExpression, ySqmExpression ),
(AllowableFunctionReturnType) highestPrecedenceType(
return new SqmFunction(
"concat",
getFunctionDescriptor( "concat" ),
highestPrecedenceType(
xSqmExpression.getNodeType(),
ySqmExpression.getNodeType(),
StandardBasicTypes.STRING
),
getQueryEngine()
asList( xSqmExpression, ySqmExpression ),
this
);
}
@ -819,14 +851,16 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
final SqmExpression xSqmExpression = literal( x );
final SqmExpression ySqmExpression = (SqmExpression) y;
//noinspection unchecked
return getFunctionTemplate( "concat" ).makeSqmFunctionExpression(
asList( xSqmExpression, ySqmExpression ),
(AllowableFunctionReturnType) highestPrecedenceType(
return new SqmFunction(
"concat",
getFunctionDescriptor( "concat" ),
highestPrecedenceType(
xSqmExpression.getNodeType(),
ySqmExpression.getNodeType(),
StandardBasicTypes.STRING
),
getQueryEngine()
asList( xSqmExpression, ySqmExpression ),
this
);
}
@ -835,14 +869,16 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
final SqmExpression xSqmExpression = literal( x );
final SqmExpression ySqmExpression = literal( y );
//noinspection unchecked
return getFunctionTemplate( "concat" ).makeSqmFunctionExpression(
asList( xSqmExpression, ySqmExpression ),
(AllowableFunctionReturnType) highestPrecedenceType(
return new SqmFunction(
"concat",
getFunctionDescriptor( "concat" ),
highestPrecedenceType(
xSqmExpression.getNodeType(),
ySqmExpression.getNodeType(),
StandardBasicTypes.STRING
),
getQueryEngine()
asList( xSqmExpression, ySqmExpression ),
this
);
}
@ -862,10 +898,12 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
);
//noinspection unchecked
return getFunctionTemplate( "substring" ).makeSqmFunctionExpression(
len==null ? asList( source, from ) : asList( source, from, len ),
return new SqmFunction(
"substring",
getFunctionDescriptor( "substring" ),
resultType,
getQueryEngine()
len==null ? asList( source, from ) : asList( source, from, len ),
this
);
}
@ -903,25 +941,28 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
private SqmFunction<String> createTrimNode(TrimSpec trimSpecification, SqmExpression trimCharacter, SqmExpression source) {
final ArrayList<SqmTypedNode<?>> arguments = new ArrayList<>();
if ( trimSpecification != null ) {
arguments.add(
new SqmTrimSpecification( trimSpecification, this )
);
}
final ArrayList<SqmNode> arguments = new ArrayList<>();
if ( trimCharacter != null ) {
arguments.add( trimCharacter );
}
arguments.add( source );
//noinspection unchecked
return getFunctionTemplate( "trim" ).makeSqmFunctionExpression(
arguments,
(AllowableFunctionReturnType) QueryHelper.highestPrecedenceType2( source.getNodeType(), StandardBasicTypes.STRING ),
getQueryEngine()
if ( trimSpecification != null ) {
arguments.add(
new SqmTrimSpecification( trimSpecification, this )
);
}
if ( trimCharacter != null ) {
arguments.add( trimCharacter );
}
arguments.add( source );
//noinspection unchecked
return new SqmFunction(
"trim",
getFunctionDescriptor( "trim" ),
QueryHelper.highestPrecedenceType2( source.getNodeType(), StandardBasicTypes.STRING ),
arguments,
this
);
}
@Override
@ -978,10 +1019,12 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
);
//noinspection unchecked
return getFunctionTemplate( "lower" ).makeSqmFunctionExpression(
(SqmExpression) x,
return new SqmFunction(
"lower",
getFunctionDescriptor( "lower" ),
type,
getQueryEngine()
Collections.singletonList( (SqmExpression) x ),
this
);
}
@ -993,24 +1036,27 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
);
//noinspection unchecked
return getFunctionTemplate( "upper" ).makeSqmFunctionExpression(
(SqmExpression) x,
return new SqmFunction(
"upper",
getFunctionDescriptor( "upper" ),
type,
getQueryEngine()
Collections.singletonList( (SqmExpression) x ),
this
);
}
@Override
public SqmFunction<Integer> length(Expression<String> argument) {
//noinspection unchecked
return getFunctionTemplate( "length" ).makeSqmFunctionExpression(
(SqmExpression) argument,
return new SqmFunction(
"length",
getFunctionDescriptor( "length" ),
(AllowableFunctionReturnType) highestPrecedenceType(
((SqmExpression) argument).getNodeType(),
StandardBasicTypes.INTEGER
),
getQueryEngine()
Collections.singletonList( (SqmExpression) argument ),
this
);
}
@ -1047,12 +1093,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
}
//noinspection unchecked
return getFunctionTemplate("locate").makeSqmFunctionExpression(
arguments,
return new SqmFunction(
"locate",
getFunctionDescriptor( "locate" ),
type,
getQueryEngine()
arguments,
this
);
}
@Override
@ -1085,55 +1132,65 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override
public SqmFunction<Date> currentDate() {
//noinspection unchecked
// return getFunctionTemplate("current_date").makeSqmFunctionExpression(
// StandardBasicTypes.DATE,
// queryEngine
// );
throw new NotYetImplementedFor6Exception( getClass() );
return new SqmFunction(
"current_date",
getFunctionDescriptor( "current_date" ),
StandardBasicTypes.DATE,
Collections.emptyList(),
this
);
}
@Override
public SqmFunction<Timestamp> currentTimestamp() {
//noinspection unchecked
// return getFunctionTemplate("current_timestamp").makeSqmFunctionExpression(
// StandardBasicTypes.TIMESTAMP,
// queryEngine
// );
throw new NotYetImplementedFor6Exception( getClass() );
return new SqmFunction(
"current_timestamp",
getFunctionDescriptor( "current_timestamp" ),
StandardBasicTypes.TIMESTAMP,
Collections.emptyList(),
this
);
}
@Override
public SqmFunction<Time> currentTime() {
//noinspection unchecked
// return getFunctionTemplate("current_time").makeSqmFunctionExpression(
// StandardBasicTypes.TIME,
// queryEngine
// );
throw new NotYetImplementedFor6Exception( getClass() );
return new SqmFunction(
"current_time",
getFunctionDescriptor( "current_time" ),
StandardBasicTypes.TIME,
Collections.emptyList(),
this
);
}
@Override
public SqmFunction<Instant> currentInstant() {
//noinspection unchecked
return getFunctionTemplate("current_timestamp").makeSqmFunctionExpression(
return new SqmFunction(
"current_instant",
getFunctionDescriptor( "current_instant" ),
StandardBasicTypes.INSTANT,
queryEngine
Collections.emptyList(),
this
);
}
@Override
public <T> SqmFunction<T> function(String name, Class<T> type, Expression<?>[] args) {
final SqmFunctionTemplate functionTemplate = getFunctionTemplate(name);
final SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( name);
if ( functionTemplate == null ) {
throw new SemanticException( "Could not resolve function named `" + name + "`" );
}
//noinspection unchecked
return functionTemplate.makeSqmFunctionExpression(
(List) expressionList( args ),
return new SqmFunction<>(
name,
getFunctionDescriptor( name ),
getTypeConfiguration().standardBasicTypeForJavaType( type ),
getQueryEngine()
(List) expressionList( args ),
this
);
}
@ -1254,16 +1311,17 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
second.getNodeType()
);
return getFunctionTemplate("nullif").makeSqmFunctionExpression(
asList( first, second ),
return new SqmFunction<>(
"nullif",
getFunctionDescriptor( "nullif" ),
type,
getQueryEngine()
asList( first, second ),
this
);
}
private SqmFunctionTemplate getFunctionTemplate(String name) {
return queryEngine.getSqmFunctionRegistry().findFunctionTemplate(name);
private SqmFunctionDescriptor getFunctionDescriptor(String name) {
return queryEngine.getSqmFunctionRegistry().findFunctionDescriptor( name);
}
@Override

View File

@ -27,29 +27,30 @@ import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.function.SqmCastTarget;
import org.hibernate.query.sqm.function.SqmDistinct;
import org.hibernate.query.sqm.function.SqmExtractUnit;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.function.SqmStar;
import org.hibernate.query.sqm.function.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
@ -605,7 +606,12 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
}
@Override
public Object visitFunction(SqmFunction sqmFunction) {
public Object visitFunction(SqmFunction tSqmFunction) {
return null;
}
@Override
public Object visitCoalesce(SqmCoalesce sqmCoalesce) {
return null;
}

View File

@ -8,16 +8,16 @@ package org.hibernate.query.sqm.produce.function;
import java.util.List;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* @author Steve Ebersole
*/
@FunctionalInterface
public interface ArgumentsValidator {
/**
* The main (functional) operation defining validation
* Validate the arguments
*/
void validate(List<SqmTypedNode<?>> arguments);
void validate(List<? extends SqmVisitableNode> arguments);
}

View File

@ -1,46 +0,0 @@
/*
* 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.produce.function;
import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.internal.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.produce.function.spi.AbstractSqmFunctionTemplate;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.function.SqmJdbcFunctionEscapeWrapper;
/**
* Acts as a wrapper to another SqmFunctionTemplate - upon rendering uses the
* standard JDBC escape sequence (i.e. `{fn blah}`) when rendering the SQL.
*
* @author Steve Ebersole
*/
public class JdbcFunctionEscapeWrapperTemplate
extends AbstractSqmFunctionTemplate {
private final SqmFunctionTemplate wrapped;
public JdbcFunctionEscapeWrapperTemplate(SqmFunctionTemplate wrapped) {
this.wrapped = wrapped;
}
@Override
protected <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine) {
return new SqmJdbcFunctionEscapeWrapper<>(
wrapped.makeSqmFunctionExpression(
arguments,
impliedResultType,
queryEngine
),
queryEngine.getCriteriaBuilder()
);
}
}

View File

@ -7,15 +7,17 @@
package org.hibernate.query.sqm.produce.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.produce.function.spi.NamedSqmFunctionTemplate;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public class NamedFunctionTemplateBuilder {
private static final Logger log = Logger.getLogger( NamedFunctionTemplateBuilder.class );
public class NamedFunctionDescriptorBuilder {
private static final Logger log = Logger.getLogger( NamedFunctionDescriptorBuilder.class );
private final SqmFunctionRegistry registry;
private final String registrationKey;
@ -27,54 +29,53 @@ public class NamedFunctionTemplateBuilder {
private boolean useParenthesesWhenNoArgs;
public NamedFunctionTemplateBuilder(SqmFunctionRegistry registry, String registrationKey, String functionName) {
public NamedFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String functionName) {
this.registry = registry;
this.registrationKey = registrationKey;
this.functionName = functionName;
}
public NamedFunctionTemplateBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
public NamedFunctionDescriptorBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
this.argumentsValidator = argumentsValidator;
return this;
}
public NamedFunctionTemplateBuilder setArgumentCountBetween(int min, int max) {
public NamedFunctionDescriptorBuilder setArgumentCountBetween(int min, int max) {
return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) );
}
public NamedFunctionTemplateBuilder setExactArgumentCount(int exactArgumentCount) {
public NamedFunctionDescriptorBuilder setExactArgumentCount(int exactArgumentCount) {
return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) );
}
public NamedFunctionTemplateBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
public NamedFunctionDescriptorBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
this.returnTypeResolver = returnTypeResolver;
return this;
}
public NamedFunctionTemplateBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
public NamedFunctionDescriptorBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) );
return this;
}
public NamedFunctionTemplateBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) {
public NamedFunctionDescriptorBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) {
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
return this;
}
public SqmFunctionTemplate register() {
public SqmFunctionDescriptor register() {
return registry.register(
registrationKey,
template()
build()
);
}
public SqmFunctionTemplate template() {
return new NamedSqmFunctionTemplate(
public SqmFunctionDescriptor build() {
return new NamedSqmFunctionDescriptor(
registrationKey,
functionName,
useParenthesesWhenNoArgs,
argumentsValidator,
returnTypeResolver,
registrationKey
argumentsValidator
);
}
}

View File

@ -7,13 +7,15 @@
package org.hibernate.query.sqm.produce.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.query.sqm.produce.function.spi.PatternBasedSqmFunctionTemplate;
import org.hibernate.query.sqm.function.PatternBasedSqmFunctionTemplate;
/**
* @author Steve Ebersole
*/
public class PatternFunctionTemplateBuilder {
public class PatternFunctionDescriptorBuilder {
private final SqmFunctionRegistry registry;
private final String registrationKey;
private final String pattern;
@ -23,50 +25,49 @@ public class PatternFunctionTemplateBuilder {
private boolean useParenthesesWhenNoArgs;
public PatternFunctionTemplateBuilder(SqmFunctionRegistry registry, String registrationKey, String pattern) {
public PatternFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String pattern) {
this.registry = registry;
this.registrationKey = registrationKey;
this.pattern = pattern;
}
public PatternFunctionTemplateBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
public PatternFunctionDescriptorBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
this.argumentsValidator = argumentsValidator;
return this;
}
public PatternFunctionTemplateBuilder setExactArgumentCount(int exactArgumentCount) {
public PatternFunctionDescriptorBuilder setExactArgumentCount(int exactArgumentCount) {
return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) );
}
public PatternFunctionTemplateBuilder setArgumentCountBetween(int min, int max) {
public PatternFunctionDescriptorBuilder setArgumentCountBetween(int min, int max) {
return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) );
}
public PatternFunctionTemplateBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
public PatternFunctionDescriptorBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
this.returnTypeResolver = returnTypeResolver;
return this;
}
public PatternFunctionTemplateBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
public PatternFunctionDescriptorBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) );
return this;
}
public PatternFunctionTemplateBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) {
public PatternFunctionDescriptorBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) {
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
return this;
}
public SqmFunctionTemplate register() {
public SqmFunctionDescriptor register() {
return registry.register( registrationKey, template() );
}
public SqmFunctionTemplate template() {
public SqmFunctionDescriptor template() {
return new PatternBasedSqmFunctionTemplate(
new PatternRenderer( pattern, useParenthesesWhenNoArgs ),
argumentsValidator,
returnTypeResolver,
registrationKey
returnTypeResolver
);
}
}

View File

@ -1,215 +0,0 @@
/*
* 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.produce.function;
import java.util.Map;
import java.util.TreeMap;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.jboss.logging.Logger;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
/**
* Defines a registry for SQLFunction instances
*
* @author Steve Ebersole
*/
public class SqmFunctionRegistry {
private static final Logger log = Logger.getLogger( SqmFunctionRegistry.class );
private final Map<String,SqmFunctionTemplate> functionMap = new TreeMap<>( CASE_INSENSITIVE_ORDER );
private final Map<String,String> alternateKeyMap = new TreeMap<>( CASE_INSENSITIVE_ORDER );
public SqmFunctionRegistry() {
log.tracef( "SqmFunctionRegistry created" );
}
/**
* Find a SqmFunctionTemplate by name. Returns {@code null} if
* no such function is found.
*/
public SqmFunctionTemplate findFunctionTemplate(String functionName) {
SqmFunctionTemplate found = null;
final String alternateKeyResolution = alternateKeyMap.get( functionName );
if ( alternateKeyResolution != null ) {
found = functionMap.get( alternateKeyResolution );
}
if ( found == null ) {
found = functionMap.get( functionName );
}
return found;
}
/**
* Register a function template by name
*/
public SqmFunctionTemplate register(String registrationKey, SqmFunctionTemplate function) {
final SqmFunctionTemplate priorRegistration = functionMap.put( registrationKey, function );
log.debugf(
"Registered SqmFunctionTemplate [%s] under %s; prior registration was %s",
function,
registrationKey,
priorRegistration
);
return function;
}
/**
* Register a pattern-based template by name. Shortcut for building the template
* via {@link #patternTemplateBuilder} accepting its defaults.
*/
public SqmFunctionTemplate registerPattern(String name, String pattern) {
return patternTemplateBuilder( name, pattern ).register();
}
/**
* Register a pattern-based template by name and invariant return type. Shortcut for building the template
* via {@link #patternTemplateBuilder} accepting its defaults.
*/
public SqmFunctionTemplate registerPattern(String name, String pattern, AllowableFunctionReturnType returnType) {
return patternTemplateBuilder( name, pattern )
.setInvariantType( returnType )
.register();
}
/**
* Get a builder for creating and registering a pattern-based function template.
*
* @param registrationKey The name under which the template will get registered
* @param pattern The pattern defining the the underlying function call
*
* @return The builder
*/
public PatternFunctionTemplateBuilder patternTemplateBuilder(String registrationKey, String pattern) {
return new PatternFunctionTemplateBuilder( this, registrationKey, pattern );
}
/**
* Register a named template by name. Shortcut for building a template via
* {@link #namedTemplateBuilder} using the passed name as both the registration
* key and underlying SQL function name and accepting the builder's defaults.
*
* @param name The function name (and registration key)
*/
public SqmFunctionTemplate registerNamed(String name) {
return namedTemplateBuilder( name ).register();
}
/**
* Register a named template by name and invariant return type. Shortcut for building
* a template via {@link #namedTemplateBuilder} using the passed name as both the
* registration key and underlying SQL function name and accepting the builder's defaults.
*
* @param name The function name (and registration key)
*/
public SqmFunctionTemplate registerNamed(String name, AllowableFunctionReturnType returnType) {
return namedTemplateBuilder( name ).setInvariantType( returnType ).register();
}
/**
* Get a builder for creating and registering a name-based function template
* using the passed name as both the registration key and underlying SQL
* function name
*
* @param name The function name (and registration key)
*
* @return The builder
*/
public NamedFunctionTemplateBuilder namedTemplateBuilder(String name) {
return namedTemplateBuilder( name, name );
}
/**
* Get a builder for creating and registering a name-based function template.
*
* @param registrationKey The name under which the template will get registered
* @param name The underlying SQL function name to use
*
* @return The builder
*/
public NamedFunctionTemplateBuilder namedTemplateBuilder(String registrationKey, String name) {
return new NamedFunctionTemplateBuilder( this, registrationKey, name );
}
public NamedFunctionTemplateBuilder noArgsBuilder(String name) {
return noArgsBuilder( name, name );
}
public NamedFunctionTemplateBuilder noArgsBuilder(String registrationKey, String name) {
return namedTemplateBuilder( registrationKey, name )
.setExactArgumentCount( 0 );
}
public VarArgsFunctionTemplateBuilder varArgsBuilder(String registrationKey, String begin, String sep, String end) {
return new VarArgsFunctionTemplateBuilder( this, registrationKey, begin, sep, end );
}
/**
* Specialized registration method for registering a named template for functions
* expecting zero arguments. Short-cut for building a named template via
* {@link #namedTemplateBuilder} specifying zero arguments and accepting the
* rest of the builder's defaults.
*
* @param name The function name (and registration key)
*/
public SqmFunctionTemplate registerNoArgs(String name) {
return registerNoArgs( name, name );
}
public SqmFunctionTemplate registerNoArgs(String registrationKey, String name) {
return noArgsBuilder( registrationKey, name ).register();
}
public SqmFunctionTemplate registerNoArgs(String name, AllowableFunctionReturnType returnType) {
return registerNoArgs( name, name, returnType );
}
public SqmFunctionTemplate registerNoArgs(String registrationKey, String name, AllowableFunctionReturnType returnType) {
return noArgsBuilder( registrationKey, name )
.setInvariantType( returnType )
.register();
}
public SqmFunctionTemplate registerVarArgs(String registrationKey, AllowableFunctionReturnType returnType, String begin, String sep, String end) {
return varArgsBuilder( registrationKey, begin, sep, end )
.setInvariantType( returnType )
.register();
}
public SqmFunctionTemplate wrapInJdbcEscape(String registrationKey, SqmFunctionTemplate wrapped) {
final JdbcFunctionEscapeWrapperTemplate wrapperTemplate = new JdbcFunctionEscapeWrapperTemplate( wrapped );
register( registrationKey, wrapperTemplate );
return wrapperTemplate;
}
public void registerAlternateKey(String alternateKey, String mappedKey) {
log.debugf( "Registering alternate key : %s -> %s", alternateKey, mappedKey );
alternateKeyMap.put( alternateKey, mappedKey );
}
/**
* Overlay the functions registered here on top of the
* incoming registry, potentially overriding its registrations
*/
public void overlay(SqmFunctionRegistry registryToOverly) {
// NOTE : done in this "direction" as it is easier to access the
// functionMap directly in performing this operation
functionMap.forEach( registryToOverly::register );
alternateKeyMap.forEach( registryToOverly::registerAlternateKey );
}
public void close() {
functionMap.clear();
alternateKeyMap.clear();
}
}

View File

@ -1,85 +0,0 @@
/*
* 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.produce.function;
import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.internal.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
/**
* Extension for supplying support for non-standard (ANSI SQL) functions
* in HQL and Criteria queries.
* <p/>
* Ultimately acts as a factory for SQM function expressions.
*
* @author David Channon
* @author Steve Ebersole
*/
public interface SqmFunctionTemplate {
/**
* Generate an SqmExpression instance from this template.
* <p/>
* Note that this returns SqmExpression rather than the more
* restrictive SqmFunctionExpression to allow implementors
* to transform the source function expression into any
* "expressable form".
*/
<T> SelfRenderingSqmFunction<T> makeSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine);
default <T> SelfRenderingSqmFunction<T> makeSqmFunctionExpression(
SqmTypedNode<?> argument,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine) {
return makeSqmFunctionExpression(
singletonList(argument),
impliedResultType,
queryEngine
);
}
default <T> SelfRenderingSqmFunction<T> makeSqmFunctionExpression(
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine) {
return makeSqmFunctionExpression(
emptyList(),
impliedResultType,
queryEngine
);
}
/**
* Will a call to the described function always include
* parentheses?
* <p>
* SqmFunctionTemplate is generally used for rendering of a function.
* However there are cases where Hibernate needs to consume a fragment
* and decide if a token represents a function name. In cases where
* the token is followed by an open-paren we can safely assume the
* token is a function name. However, if the next token is not an
* open-paren, the token can still represent a function provided that
* the function has a "no paren" form in the case of no arguments. E.g.
* Many databases do not require parentheses on functions like
* `current_timestamp`, etc. This method helps account for those
* cases.
* <p>
* Note that the most common case, by far, is that a function will always
* include the parentheses - therefore this return is defined as true by
* default.
*/
default boolean alwaysIncludesParentheses() {
return true;
}
}

View File

@ -11,6 +11,7 @@ import java.util.List;
import java.util.Locale;
import org.hibernate.QueryException;
import org.hibernate.query.sqm.tree.SqmTypedNode;
/**
* @author Steve Ebersole
@ -100,16 +101,21 @@ public final class StandardArgumentsValidators {
public static ArgumentsValidator of(Class<?> javaType) {
return arguments -> arguments.forEach(
arg -> {
Class<?> argType = arg.getNodeType().getExpressableJavaTypeDescriptor().getJavaType();
if ( !javaType.isAssignableFrom(argType) ) {
throw new QueryException(
String.format(
Locale.ROOT,
"Function expects arguments to be of type %s, but %s found",
javaType.getName(),
argType.getName()
)
);
if ( arg instanceof SqmTypedNode ) {
Class<?> argType = ( (SqmTypedNode) arg ).getNodeType().getExpressableJavaTypeDescriptor().getJavaType();
if ( !javaType.isAssignableFrom(argType) ) {
throw new QueryException(
String.format(
Locale.ROOT,
"Function expects arguments to be of type %s, but %s found",
javaType.getName(),
argType.getName()
)
);
}
}
else {
throw new QueryException( "Found un-typed arguments with typed argument validator" );
}
}
);

View File

@ -7,15 +7,17 @@
package org.hibernate.query.sqm.produce.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.produce.function.spi.FunctionAsExpressionTemplate;
import org.hibernate.query.sqm.function.FunctionAsExpressionTemplate;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.jboss.logging.Logger;
/**
* @author Christian Beikov
*/
public class VarArgsFunctionTemplateBuilder {
private static final Logger log = Logger.getLogger( VarArgsFunctionTemplateBuilder.class );
public class VarArgsFunctionDescriptorBuilder {
private static final Logger log = Logger.getLogger( VarArgsFunctionDescriptorBuilder.class );
private final SqmFunctionRegistry registry;
private final String registrationKey;
@ -25,9 +27,8 @@ public class VarArgsFunctionTemplateBuilder {
private final String end;
private ArgumentsValidator argumentsValidator;
private FunctionReturnTypeResolver returnTypeResolver;
public VarArgsFunctionTemplateBuilder(SqmFunctionRegistry registry, String registrationKey, String begin, String sep, String end) {
public VarArgsFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String begin, String sep, String end) {
this.registry = registry;
this.registrationKey = registrationKey;
this.begin = begin;
@ -35,43 +36,41 @@ public class VarArgsFunctionTemplateBuilder {
this.end = end;
}
public VarArgsFunctionTemplateBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
public VarArgsFunctionDescriptorBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
this.argumentsValidator = argumentsValidator;
return this;
}
public VarArgsFunctionTemplateBuilder setArgumentCountBetween(int min, int max) {
public VarArgsFunctionDescriptorBuilder setArgumentCountBetween(int min, int max) {
return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) );
}
public VarArgsFunctionTemplateBuilder setMinArgumentCount(int min) {
public VarArgsFunctionDescriptorBuilder setMinArgumentCount(int min) {
return setArgumentsValidator( StandardArgumentsValidators.min( min ) );
}
public VarArgsFunctionTemplateBuilder setExactArgumentCount(int exactArgumentCount) {
public VarArgsFunctionDescriptorBuilder setExactArgumentCount(int exactArgumentCount) {
return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) );
}
public VarArgsFunctionTemplateBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
this.returnTypeResolver = returnTypeResolver;
public VarArgsFunctionDescriptorBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
// this.returnTypeResolver = returnTypeResolver;
return this;
}
public VarArgsFunctionTemplateBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
public VarArgsFunctionDescriptorBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) );
return this;
}
public SqmFunctionTemplate register() {
public SqmFunctionDescriptor register() {
return registry.register(
registrationKey,
new FunctionAsExpressionTemplate(
begin,
sep,
end,
returnTypeResolver,
argumentsValidator,
registrationKey
argumentsValidator
)
);
}

View File

@ -1,58 +0,0 @@
/*
* 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.produce.function.internal;
import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.produce.function.spi.SelfRenderingFunctionSupport;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression;
/**
* @author Steve Ebersole
*/
public class SelfRenderingSqmFunction<T>
extends AbstractSqmExpression<T>
implements SqmFunction<T> {
private final String name;
private final SelfRenderingFunctionSupport renderingSupport;
private final List<SqmTypedNode<?>> arguments;
public SelfRenderingSqmFunction(
SelfRenderingFunctionSupport renderingSupport,
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
NodeBuilder nodeBuilder,
String name) {
super( impliedResultType, nodeBuilder );
this.renderingSupport = renderingSupport;
this.arguments = arguments;
this.name = name;
}
public List<SqmTypedNode<?>> getArguments() {
return arguments;
}
@Override
public AllowableFunctionReturnType<T> getNodeType() {
return (AllowableFunctionReturnType<T>) super.getNodeType();
}
public SelfRenderingFunctionSupport getRenderingSupport() {
return renderingSupport;
}
@Override
public String getFunctionName() {
return name;
}
}

View File

@ -6,7 +6,7 @@
*/
/**
* Package defining support for {@link org.hibernate.query.sqm.produce.function.SqmFunctionTemplate} handling.
* Package defining support for {@link org.hibernate.query.sqm.function.SqmFunctionDescriptor} handling.
* <p/>
* Between {@link org.hibernate.query.sqm.produce.function.ArgumentsValidator} and
* {@link org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver} creating

View File

@ -1,51 +0,0 @@
/*
* 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.produce.function.spi;
import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.internal.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.tree.SqmTypedNode;
/**
* @author Steve Ebersole
*/
public abstract class AbstractSelfRenderingFunctionTemplate extends AbstractSqmFunctionTemplate {
private final String name;
public AbstractSelfRenderingFunctionTemplate(
String name,
FunctionReturnTypeResolver returnTypeResolver,
ArgumentsValidator argumentsValidator) {
super( argumentsValidator, returnTypeResolver );
this.name = name;
}
@Override
protected <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> resolvedReturnType,
QueryEngine queryEngine) {
//noinspection unchecked
return new SelfRenderingSqmFunction(
getRenderingFunctionSupport( arguments, resolvedReturnType, queryEngine ),
arguments,
resolvedReturnType,
queryEngine.getCriteriaBuilder(),
name
);
}
protected abstract SelfRenderingFunctionSupport getRenderingFunctionSupport(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<?> resolvedReturnType,
QueryEngine queryEngine);
}

View File

@ -1,67 +0,0 @@
/*
* 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.produce.function.spi;
import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.tree.SqmTypedNode;
/**
* @author Steve Ebersole
*/
public abstract class AbstractSqmFunctionTemplate implements SqmFunctionTemplate {
private final ArgumentsValidator argumentsValidator;
private final FunctionReturnTypeResolver returnTypeResolver;
public AbstractSqmFunctionTemplate() {
this( null, null );
}
public AbstractSqmFunctionTemplate(ArgumentsValidator argumentsValidator) {
this( argumentsValidator, null );
}
public AbstractSqmFunctionTemplate(
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver) {
this.argumentsValidator = argumentsValidator == null
? StandardArgumentsValidators.NONE
: argumentsValidator;
this.returnTypeResolver = returnTypeResolver == null
? StandardFunctionReturnTypeResolvers.useFirstNonNull()
: returnTypeResolver;
}
@Override
@SuppressWarnings("unchecked")
public final <T> SelfRenderingSqmFunction<T> makeSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine) {
argumentsValidator.validate( arguments );
return generateSqmFunctionExpression(
arguments,
(AllowableFunctionReturnType<T>) //this cast is not truly correct
returnTypeResolver.resolveFunctionReturnType( impliedResultType, arguments ),
queryEngine
);
}
protected abstract <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine);
}

View File

@ -1,126 +0,0 @@
/*
* 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.produce.function.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode;
import java.util.List;
import java.util.Locale;
/**
* Provides a standard implementation that supports the majority of the HQL
* functions that are translated to SQL. The Dialect and its sub-classes use
* this class to provide details required for processing of the associated
* function.
*
* @author David Channon
* @author Steve Ebersole
*/
public class NamedSqmFunctionTemplate
extends AbstractSelfRenderingFunctionTemplate
implements SelfRenderingFunctionSupport {
private final String functionName;
private final boolean useParenthesesWhenNoArgs;
public NamedSqmFunctionTemplate(
String functionName,
boolean useParenthesesWhenNoArgs,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver) {
this( functionName, useParenthesesWhenNoArgs, argumentsValidator, returnTypeResolver, functionName );
}
public NamedSqmFunctionTemplate(
String functionName,
boolean useParenthesesWhenNoArgs,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
String name) {
super( name, returnTypeResolver, argumentsValidator );
this.functionName = functionName;
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
}
/**
* Function name accessor
*
* @return The function name.
*/
public String getName() {
return functionName;
}
@Override
protected SelfRenderingFunctionSupport getRenderingFunctionSupport(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<?> impliedResultType,
QueryEngine queryEngine) {
return this;
}
@Override
public void render(
SqlAppender sqlAppender,
List<SqlAstNode> sqlAstArguments,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {
final boolean useParens = useParenthesesWhenNoArgs || !sqlAstArguments.isEmpty();
sqlAppender.appendSql( functionName );
if ( useParens ) {
sqlAppender.appendSql( "(" );
}
boolean firstPass = true;
for ( SqlAstNode sqlAstArgument : sqlAstArguments ) {
if ( !firstPass ) {
sqlAppender.appendSql( ", " );
}
renderArgument( sqlAppender, sqlAstArgument, walker, sessionFactory );
firstPass = false;
}
if ( useParens ) {
sqlAppender.appendSql( ")" );
}
}
/**
* Called from {@link #render} to render an argument.
*
* @param sqlAppender The sql appender to append the rendered argument.
* @param sqlAstArgument The argument being processed.
* @param walker The walker to use for rendering {@link SqlAstNode} expressions
* @param sessionFactory The session factory
*/
protected void renderArgument(
SqlAppender sqlAppender,
SqlAstNode sqlAstArgument,
SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) {
sqlAstArgument.accept( walker );
}
@Override
public String toString() {
return String.format(
Locale.ROOT,
"NamedSqmFunctionTemplate(%s)",
functionName
);
}
}

View File

@ -1,66 +0,0 @@
/*
* 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.produce.function.spi;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.internal.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import java.util.List;
/**
* @author Gavin King
*/
public class PairedFunctionTemplate extends AbstractSqmFunctionTemplate {
private SqmFunctionTemplate binaryFunction;
private SqmFunctionTemplate ternaryFunction;
public PairedFunctionTemplate(
SqmFunctionTemplate binaryFunction,
SqmFunctionTemplate ternaryFunction) {
super( StandardArgumentsValidators.between( 2, 3 ) );
this.binaryFunction = binaryFunction;
this.ternaryFunction = ternaryFunction;
}
public static void register(
QueryEngine queryEngine,
String name,
AllowableFunctionReturnType type,
String pattern2,
String pattern3) {
queryEngine.getSqmFunctionRegistry().register(
name,
new PairedFunctionTemplate(
queryEngine.getSqmFunctionRegistry()
.patternTemplateBuilder( name, pattern2 )
.setExactArgumentCount( 2 )
.setInvariantType( type)
.template(),
queryEngine.getSqmFunctionRegistry()
.patternTemplateBuilder( name, pattern3 )
.setExactArgumentCount( 3 )
.setInvariantType( type )
.template()
)
);
}
@Override
protected <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine) {
return ( arguments.size()<3 ? binaryFunction : ternaryFunction )
.makeSqmFunctionExpression( arguments, impliedResultType, queryEngine );
}
}

View File

@ -8,12 +8,6 @@ package org.hibernate.query.sqm.spi;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.function.SqmCastTarget;
import org.hibernate.query.sqm.function.SqmDistinct;
import org.hibernate.query.sqm.function.SqmExtractUnit;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.function.SqmStar;
import org.hibernate.query.sqm.function.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
@ -34,19 +28,26 @@ import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
@ -81,7 +82,6 @@ import org.hibernate.query.sqm.tree.update.SqmAssignment;
import org.hibernate.query.sqm.tree.update.SqmSetClause;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.tree.expression.Expression;
/**
* Base support for an SQM walker
@ -494,6 +494,11 @@ public class BaseSemanticQueryWalker implements SemanticQueryWalker<Object> {
return castTarget;
}
@Override
public Object visitCoalesce(SqmCoalesce sqmCoalesce) {
return sqmCoalesce;
}
@Override
public Object visitTrimSpecification(SqmTrimSpecification trimSpecification) {
return trimSpecification;

View File

@ -37,7 +37,7 @@ import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.InterpretationException;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
@ -66,6 +66,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
@ -924,43 +925,28 @@ public abstract class BaseSqmToSqlAstConverter
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// non-standard functions
@Override
public Object visitFunction(SqmFunction sqmFunction) {
throw new NotYetImplementedFor6Exception( getClass() );
// shallownessStack.push( Shallowness.FUNCTION );
// try {
// return new NonStandardFunction(
// sqmFunction.getFunctionName(),
// determineValueMapping( sqmFunction ),
// visitArguments( sqmFunction.getArguments() )
// );
// }
// finally {
// shallownessStack.pop();
// }
public Expression visitFunction(SqmFunction sqmFunction) {
final SqmFunctionDescriptor functionDescriptor = creationContext.getSessionFactory()
.getQueryEngine()
.getSqmFunctionRegistry()
.findFunctionDescriptor( sqmFunction.getFunctionName() );
shallownessStack.push( Shallowness.FUNCTION );
try {
return functionDescriptor.generateSqlExpression(
sqmFunction.getFunctionName(),
sqmFunction.getArguments(),
inferableTypeAccessStack.getCurrent(),
this,
this
);
}
finally {
shallownessStack.pop();
}
}
// private List<Expression> visitArguments(List<SqmExpression> sqmArguments) {
// if ( sqmArguments == null || sqmArguments.isEmpty() ) {
// return Collections.emptyList();
// }
//
// final ArrayList<Expression> sqlAstArguments = new ArrayList<>();
// for ( SqmExpression sqmArgument : sqmArguments ) {
// sqlAstArguments.add( (Expression) sqmArgument.accept( this ) );
// }
//
// return sqlAstArguments;
// }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// standard functions
// @Override
// public Object visitAbsFunction(SqmAbsFunction function) {

View File

@ -4,12 +4,12 @@
* 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;
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -25,17 +25,13 @@ public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T>
this.type = type;
}
public AllowableFunctionReturnType<T> getType() {
return type;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitCastTarget(this);
}
@Override
public SqmExpressable<T> getNodeType() {
return type;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitCastTarget( this );
}
}

View File

@ -4,11 +4,10 @@
* 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;
package org.hibernate.query.sqm.tree.expression;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.Expression;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
@ -16,38 +15,39 @@ import org.hibernate.query.criteria.JpaCoalesce;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate;
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
/**
* Specialized CASE statement for resolving the first non-null value in a list of values
*
* @author Steve Ebersole
* @author Gavin King
*/
public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoalesce<T>, DomainResultProducer<T> {
private List<SqmExpression<? extends T>> arguments = new ArrayList<>();
private SqmFunctionTemplate coalesceFunction;
public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoalesce<T> {
private final SqmFunctionDescriptor functionDescriptor;
private final List<SqmExpression<? extends T>> arguments;
public SqmCoalesce(NodeBuilder nodeBuilder) {
this( null, nodeBuilder );
}
public SqmCoalesce(AllowableFunctionReturnType<T> type, NodeBuilder nodeBuilder) {
public SqmCoalesce(SqmExpressable<T> type, NodeBuilder nodeBuilder) {
super( type, nodeBuilder );
coalesceFunction = nodeBuilder.getQueryEngine().getSqmFunctionRegistry().findFunctionTemplate("coalesce");
functionDescriptor = nodeBuilder.getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor( "coalesce" );
this.arguments = new ArrayList<>();
}
public SqmCoalesce(SqmExpressable<T> type, int numberOfArguments, NodeBuilder nodeBuilder) {
super( type, nodeBuilder );
functionDescriptor = nodeBuilder.getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor( "coalesce" );
this.arguments = new ArrayList<>( numberOfArguments );
}
public SqmFunctionDescriptor getFunctionDescriptor() {
return functionDescriptor;
}
public void value(SqmExpression<? extends T> expression) {
arguments.add( expression );
//TODO: improve this
// if ( getNodeType() == null ) {
setExpressableType( expression.getNodeType() );
// }
}
public List<SqmExpression<? extends T>> getArguments() {
@ -56,13 +56,7 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitFunction(
coalesceFunction.makeSqmFunctionExpression(
new ArrayList<>(arguments),
(AllowableFunctionReturnType<?>) getNodeType(),
nodeBuilder().getQueryEngine()
)
);
return walker.visitCoalesce( this );
}
@Override

View File

@ -4,7 +4,7 @@
* 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;
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;

View File

@ -13,7 +13,6 @@ import java.util.function.Consumer;
import javax.persistence.criteria.Expression;
import org.hibernate.annotations.Remove;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.sqm.SqmExpressable;
@ -100,11 +99,14 @@ public interface SqmExpression<T> extends SqmSelectableNode<T>, JpaExpression<T>
SqmPredicate in(Expression<Collection<?>> values);
default <X> SqmExpression<X> castAs(DomainType<X> type) {
return nodeBuilder().getQueryEngine()
.getSqmFunctionRegistry()
.findFunctionTemplate( "cast" )
.makeSqmFunctionExpression( this, ( AllowableFunctionReturnType<X>) type, nodeBuilder().getQueryEngine() );
return new SqmFunction<>(
"cast",
nodeBuilder().getQueryEngine()
.getSqmFunctionRegistry()
.findFunctionDescriptor( "cast" ),
type,
nodeBuilder()
);
}
}

View File

@ -4,7 +4,7 @@
* 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;
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder;

View File

@ -0,0 +1,77 @@
/*
* 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.tree.expression;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.query.criteria.JpaFunction;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.tree.SqmNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* An SQM function
*
* @author Steve Ebersole
*/
public class SqmFunction<T> extends AbstractSqmExpression<T> implements JpaFunction<T>, DomainResultProducer<T> {
// this function-name is the one used to resolve the descriptor from the function registry (which may or may not be a db function name)
private final String functionName;
private final SqmFunctionDescriptor functionDescriptor;
private List<SqmVisitableNode> arguments;
public SqmFunction(
String functionName,
SqmFunctionDescriptor functionDescriptor,
SqmExpressable<T> type,
NodeBuilder criteriaBuilder) {
super( type, criteriaBuilder );
this.functionName = functionName;
this.functionDescriptor = functionDescriptor;
}
public SqmFunction(
String functionName,
SqmFunctionDescriptor functionDescriptor,
SqmExpressable<T> type,
List<SqmVisitableNode> arguments,
NodeBuilder criteriaBuilder) {
super( type, criteriaBuilder );
this.functionName = functionName;
this.functionDescriptor = functionDescriptor;
this.arguments = arguments;
}
@Override
public String getFunctionName() {
return functionName;
}
public List<SqmVisitableNode> getArguments() {
return arguments;
}
public void addArgument(SqmVisitableNode argument) {
assert argument != null;
if ( arguments == null ) {
arguments = new ArrayList<>();
}
arguments.add( argument );
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitFunction( this );
}
}

View File

@ -4,11 +4,10 @@
* 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;
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression;
/**
* @author Gavin King

View File

@ -4,7 +4,7 @@
* 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;
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.TrimSpec;
import org.hibernate.query.sqm.NodeBuilder;

View File

@ -8,16 +8,15 @@ package org.hibernate.orm.test.query.hql;
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
import org.hibernate.orm.test.query.sqm.domain.Person;
import org.hibernate.query.sqm.function.SqmCoalesce;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.TestingUtil;
import org.junit.jupiter.api.Test;
@ -87,7 +86,6 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
}
@Test
@FailureExpected( reason = "Support for functions not yet defined" )
public void testBasicCoalesceExpression() {
SqmSelectStatement select = interpretSelect(
"select coalesce(p.nickName, p.mate.nickName) from Person p"
@ -95,9 +93,9 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
assertThat( select.getQuerySpec().getSelectClause().getSelections(), hasSize( 1 ) );
final SqmCoalesce<?> coalesce = TestingUtil.cast(
final SqmFunction<?> coalesce = TestingUtil.cast(
select.getQuerySpec().getSelectClause().getSelections().get( 0 ).getSelectableNode(),
SqmCoalesce.class
SqmFunction.class
);
assertThat( coalesce.getArguments(), hasSize( 2 ) );
@ -105,7 +103,6 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
}
@Test
@FailureExpected( reason = "Support for functions not yet defined" )
public void testBasicNullifExpression() {
SqmSelectStatement select = interpretSelect(
"select nullif(p.nickName, p.mate.nickName) from Person p"