HHH-13785 : HQL/Criteria function support
- preliminary work on updated tree handling. See SqmFunctionDescriptor, SqmFunctionRegistry and SqmFunction
This commit is contained in:
parent
6925fe5ab4
commit
3e89772bb8
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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);
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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) {
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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() + " ]";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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" );
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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;
|
|
@ -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()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue