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.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; 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.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector; 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.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; 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.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector; 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.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; 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.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.jdbc.spi.StatementInspector;

View File

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

View File

@ -10,13 +10,14 @@ import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
/** /**
* Defines a registry for SQLFunction instances * Defines a registry for SQLFunction instances
* *
* @author Steve Ebersole * @author Steve Ebersole
* *
* @deprecated Replaced by {@link org.hibernate.query.sqm.function.SqmFunction} * @deprecated Replaced by {@link SqmFunction}
*/ */
@Deprecated @Deprecated
public class SQLFunctionRegistry { 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.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmCreationState; import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.hql.spi.SqmPathRegistry; 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.BaseSemanticQueryWalker;
import org.hibernate.query.sqm.spi.SqmCreationContext; import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; 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 @Override
public SqmLiteral visitLiteral(SqmLiteral literal) { public SqmLiteral visitLiteral(SqmLiteral literal) {
return new SqmLiteral( return new SqmLiteral(

View File

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

View File

@ -29,7 +29,7 @@ import org.hibernate.query.named.NamedQueryRepository;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.internal.SqmCreationOptionsStandard; import org.hibernate.query.sqm.internal.SqmCreationOptionsStandard;
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder; 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.spi.SqmCreationContext;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory; 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.SqmSetJoin;
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin; import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
import org.hibernate.query.sqm.tree.expression.SqmExpression; 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.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple; import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.from.SqmRoot; 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.select.SqmSubQuery;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.service.ServiceRegistry; 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; 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.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched; import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple; 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.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter; 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.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral; import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression; 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.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple; import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation; import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.function.SqmCastTarget; import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.function.SqmDistinct; import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.function.SqmExtractUnit; import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.function.SqmFunction; import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
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.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin; import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin; import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
@ -196,15 +197,21 @@ public interface SemanticQueryWalker<T> {
T visitUnaryOperationExpression(SqmUnaryOperation<?> expression); T visitUnaryOperationExpression(SqmUnaryOperation<?> expression);
T visitFunction(SqmFunction tSqmFunction);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ T visitExtractUnit(SqmExtractUnit extractUnit);
// expressions - non-standard functions
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 // predicates
@ -262,14 +269,4 @@ public interface SemanticQueryWalker<T> {
T visitMapEntryFunction(SqmMapEntryReference function); T visitMapEntryFunction(SqmMapEntryReference function);
T visitFullyQualifiedClass(Class<?> namedClass); 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 * 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 * 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 java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor; 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.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.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -24,8 +20,8 @@ import org.jboss.logging.Logger;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class FunctionAsExpressionTemplate public class FunctionAsExpressionTemplate
extends AbstractSelfRenderingFunctionTemplate extends AbstractSqmFunctionDescriptor
implements SelfRenderingFunctionSupport { implements FunctionRenderingSupport {
private static final Logger log = Logger.getLogger( FunctionAsExpressionTemplate.class ); private static final Logger log = Logger.getLogger( FunctionAsExpressionTemplate.class );
@ -37,28 +33,22 @@ public class FunctionAsExpressionTemplate
String expressionStart, String expressionStart,
String argumentSeparator, String argumentSeparator,
String expressionEnd, String expressionEnd,
FunctionReturnTypeResolver returnTypeResolver, ArgumentsValidator argumentsValidator) {
ArgumentsValidator argumentsValidator, super( argumentsValidator );
String name) {
super( name, returnTypeResolver, argumentsValidator );
this.expressionStart = expressionStart; this.expressionStart = expressionStart;
this.argumentSeparator = argumentSeparator; this.argumentSeparator = argumentSeparator;
this.expressionEnd = expressionEnd; this.expressionEnd = expressionEnd;
} }
@Override @Override
protected SelfRenderingFunctionSupport getRenderingFunctionSupport( protected FunctionRenderingSupport getRenderingSupport() {
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<?> resolvedReturnType,
QueryEngine queryEngine) {
return this; return this;
} }
@Override @Override
@SuppressWarnings("unchecked")
public void render( public void render(
SqlAppender sqlAppender, SqlAppender sqlAppender,
List<SqlAstNode> sqlAstArguments, String functionName, List<SqlAstNode> sqlAstArguments,
SqlAstWalker walker, SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
sqlAppender.appendSql( expressionStart ); sqlAppender.appendSql( expressionStart );
@ -68,31 +58,15 @@ public class FunctionAsExpressionTemplate
} }
else { else {
// render the first argument.. // 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 // render the rest of the arguments, preceded by the separator
for ( int i = 1; i < sqlAstArguments.size(); i++ ) { for ( int i = 1; i < sqlAstArguments.size(); i++ ) {
sqlAppender.appendSql( argumentSeparator ); sqlAppender.appendSql( argumentSeparator );
renderArgument( sqlAppender, sqlAstArguments.get( i ), walker, sessionFactory ); sqlAstArguments.get( i ).accept( walker );
} }
} }
sqlAppender.appendSql( expressionEnd ); 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 * 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 * 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.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.spi.SqlAppender;
@ -14,14 +14,14 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
import java.util.List; import java.util.List;
/** /**
* Support for SqmFunctionTemplates that ultimately want to * Support for SqmFunctionDescriptors that ultimately want to perform SQL rendering themselves
* perform SQL rendering themselves
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface SelfRenderingFunctionSupport { public interface FunctionRenderingSupport {
void render( void render(
SqlAppender sqlAppender, SqlAppender sqlAppender,
String functionName,
List<SqlAstNode> sqlAstArguments, List<SqlAstNode> sqlAstArguments,
SqlAstWalker walker, SqlAstWalker walker,
SessionFactoryImplementor sessionFactory); 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 * 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 * 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.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.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer; 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.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode; 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 * Represents HQL functions that can have different representations in different SQL dialects where that
* difference can be handled via a template/pattern. * 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> * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
*/ */
public class PatternBasedSqmFunctionTemplate public class PatternBasedSqmFunctionTemplate
extends AbstractSelfRenderingFunctionTemplate extends AbstractSqmFunctionDescriptor
implements SelfRenderingFunctionSupport { implements FunctionRenderingSupport {
private final PatternRenderer renderer; private final PatternRenderer renderer;
/** /**
@ -43,11 +40,8 @@ public class PatternBasedSqmFunctionTemplate
public PatternBasedSqmFunctionTemplate( public PatternBasedSqmFunctionTemplate(
PatternRenderer renderer, PatternRenderer renderer,
ArgumentsValidator argumentsValidator, ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver, FunctionReturnTypeResolver returnTypeResolver) {
String name) {
super( super(
name,
returnTypeResolver,
argumentsValidator != null argumentsValidator != null
? argumentsValidator ? argumentsValidator
// If no validator is given, it's still better to validate against the parameter count as given // 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 @Override
protected SelfRenderingFunctionSupport getRenderingFunctionSupport( protected FunctionRenderingSupport getRenderingSupport() {
List<SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<?> impliedResultType,
QueryEngine queryEngine) {
return this; return this;
} }
@Override @Override
public void render( public void render(
SqlAppender sqlAppender, SqlAppender sqlAppender,
String functionName,
List<SqlAstNode> sqlAstArguments, List<SqlAstNode> sqlAstArguments,
SqlAstWalker walker, SqlAstWalker walker,
SessionFactoryImplementor sessionFactory) { 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 )` * * str - generally defined as `cast(?1 as CHAR )`
* * non-standard functions * * non-standard functions
* * using JPA's function('function_name', [args]*) syntax. * * 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; package org.hibernate.query.sqm.function;

View File

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

View File

@ -8,16 +8,16 @@ package org.hibernate.query.sqm.produce.function;
import java.util.List; import java.util.List;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@FunctionalInterface
public interface ArgumentsValidator { 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; package org.hibernate.query.sqm.produce.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; 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; import org.jboss.logging.Logger;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class NamedFunctionTemplateBuilder { public class NamedFunctionDescriptorBuilder {
private static final Logger log = Logger.getLogger( NamedFunctionTemplateBuilder.class ); private static final Logger log = Logger.getLogger( NamedFunctionDescriptorBuilder.class );
private final SqmFunctionRegistry registry; private final SqmFunctionRegistry registry;
private final String registrationKey; private final String registrationKey;
@ -27,54 +29,53 @@ public class NamedFunctionTemplateBuilder {
private boolean useParenthesesWhenNoArgs; private boolean useParenthesesWhenNoArgs;
public NamedFunctionTemplateBuilder(SqmFunctionRegistry registry, String registrationKey, String functionName) { public NamedFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String functionName) {
this.registry = registry; this.registry = registry;
this.registrationKey = registrationKey; this.registrationKey = registrationKey;
this.functionName = functionName; this.functionName = functionName;
} }
public NamedFunctionTemplateBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) { public NamedFunctionDescriptorBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
this.argumentsValidator = argumentsValidator; this.argumentsValidator = argumentsValidator;
return this; return this;
} }
public NamedFunctionTemplateBuilder setArgumentCountBetween(int min, int max) { public NamedFunctionDescriptorBuilder setArgumentCountBetween(int min, int max) {
return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) ); return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) );
} }
public NamedFunctionTemplateBuilder setExactArgumentCount(int exactArgumentCount) { public NamedFunctionDescriptorBuilder setExactArgumentCount(int exactArgumentCount) {
return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) ); return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) );
} }
public NamedFunctionTemplateBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) { public NamedFunctionDescriptorBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
this.returnTypeResolver = returnTypeResolver; this.returnTypeResolver = returnTypeResolver;
return this; return this;
} }
public NamedFunctionTemplateBuilder setInvariantType(AllowableFunctionReturnType invariantType) { public NamedFunctionDescriptorBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) ); setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) );
return this; return this;
} }
public NamedFunctionTemplateBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) { public NamedFunctionDescriptorBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) {
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs; this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
return this; return this;
} }
public SqmFunctionTemplate register() { public SqmFunctionDescriptor register() {
return registry.register( return registry.register(
registrationKey, registrationKey,
template() build()
); );
} }
public SqmFunctionTemplate template() { public SqmFunctionDescriptor build() {
return new NamedSqmFunctionTemplate( return new NamedSqmFunctionDescriptor(
registrationKey,
functionName, functionName,
useParenthesesWhenNoArgs, useParenthesesWhenNoArgs,
argumentsValidator, argumentsValidator
returnTypeResolver,
registrationKey
); );
} }
} }

View File

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

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 java.util.Locale;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.query.sqm.tree.SqmTypedNode;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -100,7 +101,8 @@ public final class StandardArgumentsValidators {
public static ArgumentsValidator of(Class<?> javaType) { public static ArgumentsValidator of(Class<?> javaType) {
return arguments -> arguments.forEach( return arguments -> arguments.forEach(
arg -> { arg -> {
Class<?> argType = arg.getNodeType().getExpressableJavaTypeDescriptor().getJavaType(); if ( arg instanceof SqmTypedNode ) {
Class<?> argType = ( (SqmTypedNode) arg ).getNodeType().getExpressableJavaTypeDescriptor().getJavaType();
if ( !javaType.isAssignableFrom(argType) ) { if ( !javaType.isAssignableFrom(argType) ) {
throw new QueryException( throw new QueryException(
String.format( String.format(
@ -112,6 +114,10 @@ public final class StandardArgumentsValidators {
); );
} }
} }
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; package org.hibernate.query.sqm.produce.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; 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; import org.jboss.logging.Logger;
/** /**
* @author Christian Beikov * @author Christian Beikov
*/ */
public class VarArgsFunctionTemplateBuilder { public class VarArgsFunctionDescriptorBuilder {
private static final Logger log = Logger.getLogger( VarArgsFunctionTemplateBuilder.class ); private static final Logger log = Logger.getLogger( VarArgsFunctionDescriptorBuilder.class );
private final SqmFunctionRegistry registry; private final SqmFunctionRegistry registry;
private final String registrationKey; private final String registrationKey;
@ -25,9 +27,8 @@ public class VarArgsFunctionTemplateBuilder {
private final String end; private final String end;
private ArgumentsValidator argumentsValidator; 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.registry = registry;
this.registrationKey = registrationKey; this.registrationKey = registrationKey;
this.begin = begin; this.begin = begin;
@ -35,43 +36,41 @@ public class VarArgsFunctionTemplateBuilder {
this.end = end; this.end = end;
} }
public VarArgsFunctionTemplateBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) { public VarArgsFunctionDescriptorBuilder setArgumentsValidator(ArgumentsValidator argumentsValidator) {
this.argumentsValidator = argumentsValidator; this.argumentsValidator = argumentsValidator;
return this; return this;
} }
public VarArgsFunctionTemplateBuilder setArgumentCountBetween(int min, int max) { public VarArgsFunctionDescriptorBuilder setArgumentCountBetween(int min, int max) {
return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) ); return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) );
} }
public VarArgsFunctionTemplateBuilder setMinArgumentCount(int min) { public VarArgsFunctionDescriptorBuilder setMinArgumentCount(int min) {
return setArgumentsValidator( StandardArgumentsValidators.min( min ) ); return setArgumentsValidator( StandardArgumentsValidators.min( min ) );
} }
public VarArgsFunctionTemplateBuilder setExactArgumentCount(int exactArgumentCount) { public VarArgsFunctionDescriptorBuilder setExactArgumentCount(int exactArgumentCount) {
return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) ); return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) );
} }
public VarArgsFunctionTemplateBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) { public VarArgsFunctionDescriptorBuilder setReturnTypeResolver(FunctionReturnTypeResolver returnTypeResolver) {
this.returnTypeResolver = returnTypeResolver; // this.returnTypeResolver = returnTypeResolver;
return this; return this;
} }
public VarArgsFunctionTemplateBuilder setInvariantType(AllowableFunctionReturnType invariantType) { public VarArgsFunctionDescriptorBuilder setInvariantType(AllowableFunctionReturnType invariantType) {
setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) ); setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) );
return this; return this;
} }
public SqmFunctionTemplate register() { public SqmFunctionDescriptor register() {
return registry.register( return registry.register(
registrationKey, registrationKey,
new FunctionAsExpressionTemplate( new FunctionAsExpressionTemplate(
begin, begin,
sep, sep,
end, end,
returnTypeResolver, argumentsValidator
argumentsValidator,
registrationKey
) )
); );
} }

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/> * <p/>
* Between {@link org.hibernate.query.sqm.produce.function.ArgumentsValidator} and * Between {@link org.hibernate.query.sqm.produce.function.ArgumentsValidator} and
* {@link org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver} creating * {@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.NotYetImplementedFor6Exception;
import org.hibernate.query.sqm.SemanticQueryWalker; 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.SqmCteConsumer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; 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.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched; import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple; 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.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral; import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral; 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.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter; 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.SqmPathEntityType;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter; import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression; import org.hibernate.query.sqm.tree.expression.SqmRestrictedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple; import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation; 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.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin; import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin; 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.SqmSetClause;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.tree.expression.Expression;
/** /**
* Base support for an SQM walker * Base support for an SQM walker
@ -494,6 +494,11 @@ public class BaseSemanticQueryWalker implements SemanticQueryWalker<Object> {
return castTarget; return castTarget;
} }
@Override
public Object visitCoalesce(SqmCoalesce sqmCoalesce) {
return sqmCoalesce;
}
@Override @Override
public Object visitTrimSpecification(SqmTrimSpecification trimSpecification) { public Object visitTrimSpecification(SqmTrimSpecification trimSpecification) {
return 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.InterpretationException;
import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SqmPathSource; 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.DomainParameterXref;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper; import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker; 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.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral; 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.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmLiteral; import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter; import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
@ -924,42 +925,27 @@ public abstract class BaseSqmToSqlAstConverter
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// non-standard functions
@Override @Override
public Object visitFunction(SqmFunction sqmFunction) { public Expression visitFunction(SqmFunction sqmFunction) {
throw new NotYetImplementedFor6Exception( getClass() ); final SqmFunctionDescriptor functionDescriptor = creationContext.getSessionFactory()
// shallownessStack.push( Shallowness.FUNCTION ); .getQueryEngine()
// try { .getSqmFunctionRegistry()
// return new NonStandardFunction( .findFunctionDescriptor( sqmFunction.getFunctionName() );
// sqmFunction.getFunctionName(),
// determineValueMapping( sqmFunction ), shallownessStack.push( Shallowness.FUNCTION );
// visitArguments( sqmFunction.getArguments() ) try {
// ); return functionDescriptor.generateSqlExpression(
// } sqmFunction.getFunctionName(),
// finally { sqmFunction.getArguments(),
// shallownessStack.pop(); 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 // @Override

View File

@ -4,12 +4,12 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later * 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 * 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.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SemanticQueryWalker; 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.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -25,17 +25,13 @@ public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T>
this.type = type; this.type = type;
} }
public AllowableFunctionReturnType<T> getType() {
return type;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitCastTarget(this);
}
@Override @Override
public SqmExpressable<T> getNodeType() { public SqmExpressable<T> getNodeType() {
return type; 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 * 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 * 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.ArrayList;
import java.util.List; import java.util.List;
import javax.persistence.criteria.Expression; import javax.persistence.criteria.Expression;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; 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.criteria.JpaExpression;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate; import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression; import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
/** /**
* Specialized CASE statement for resolving the first non-null value in a list of values
*
* @author Steve Ebersole * @author Steve Ebersole
* @author Gavin King * @author Gavin King
*/ */
public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoalesce<T>, DomainResultProducer<T> { public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoalesce<T> {
private final SqmFunctionDescriptor functionDescriptor;
private List<SqmExpression<? extends T>> arguments = new ArrayList<>(); private final List<SqmExpression<? extends T>> arguments;
private SqmFunctionTemplate coalesceFunction;
public SqmCoalesce(NodeBuilder nodeBuilder) { public SqmCoalesce(NodeBuilder nodeBuilder) {
this( null, nodeBuilder ); this( null, nodeBuilder );
} }
public SqmCoalesce(AllowableFunctionReturnType<T> type, NodeBuilder nodeBuilder) { public SqmCoalesce(SqmExpressable<T> type, NodeBuilder nodeBuilder) {
super( type, 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) { public void value(SqmExpression<? extends T> expression) {
arguments.add( expression ); arguments.add( expression );
//TODO: improve this
// if ( getNodeType() == null ) {
setExpressableType( expression.getNodeType() );
// }
} }
public List<SqmExpression<? extends T>> getArguments() { public List<SqmExpression<? extends T>> getArguments() {
@ -56,13 +56,7 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
@Override @Override
public <X> X accept(SemanticQueryWalker<X> walker) { public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitFunction( return walker.visitCoalesce( this );
coalesceFunction.makeSqmFunctionExpression(
new ArrayList<>(arguments),
(AllowableFunctionReturnType<?>) getNodeType(),
nodeBuilder().getQueryEngine()
)
);
} }
@Override @Override

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later * 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 * 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.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmExpressable;

View File

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

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later * 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 * 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.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder; 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 * 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 * 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.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression;
/** /**
* @author Gavin King * @author Gavin King

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later * 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 * 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.TrimSpec;
import org.hibernate.query.sqm.NodeBuilder; 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.BaseSqmUnitTest;
import org.hibernate.orm.test.query.sqm.domain.Person; 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.domain.SqmPath;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched; import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple; 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.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode; import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.TestingUtil; import org.hibernate.testing.orm.junit.TestingUtil;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -87,7 +86,6 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
} }
@Test @Test
@FailureExpected( reason = "Support for functions not yet defined" )
public void testBasicCoalesceExpression() { public void testBasicCoalesceExpression() {
SqmSelectStatement select = interpretSelect( SqmSelectStatement select = interpretSelect(
"select coalesce(p.nickName, p.mate.nickName) from Person p" "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 ) ); assertThat( select.getQuerySpec().getSelectClause().getSelections(), hasSize( 1 ) );
final SqmCoalesce<?> coalesce = TestingUtil.cast( final SqmFunction<?> coalesce = TestingUtil.cast(
select.getQuerySpec().getSelectClause().getSelections().get( 0 ).getSelectableNode(), select.getQuerySpec().getSelectClause().getSelections().get( 0 ).getSelectableNode(),
SqmCoalesce.class SqmFunction.class
); );
assertThat( coalesce.getArguments(), hasSize( 2 ) ); assertThat( coalesce.getArguments(), hasSize( 2 ) );
@ -105,7 +103,6 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
} }
@Test @Test
@FailureExpected( reason = "Support for functions not yet defined" )
public void testBasicNullifExpression() { public void testBasicNullifExpression() {
SqmSelectStatement select = interpretSelect( SqmSelectStatement select = interpretSelect(
"select nullif(p.nickName, p.mate.nickName) from Person p" "select nullif(p.nickName, p.mate.nickName) from Person p"