Implement support for special parameter rendering through functions to support using certain Derby functions with parameters
This commit is contained in:
parent
b6dc77280f
commit
003fddccb5
|
@ -40,6 +40,7 @@ import org.hibernate.procedure.spi.CallableStatementSupport;
|
|||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
|
@ -814,7 +815,7 @@ public abstract class AbstractHANADialect extends Dialect {
|
|||
CommonFunctionFactory.weekQuarter( queryEngine );
|
||||
CommonFunctionFactory.daynameMonthname( queryEngine );
|
||||
CommonFunctionFactory.lastDay( queryEngine );
|
||||
CommonFunctionFactory.characterLength_length( queryEngine );
|
||||
CommonFunctionFactory.characterLength_length( queryEngine, SqlAstNodeRenderingMode.DEFAULT );
|
||||
CommonFunctionFactory.ascii( queryEngine );
|
||||
CommonFunctionFactory.chr_char( queryEngine );
|
||||
CommonFunctionFactory.addYearsMonthsDaysHoursMinutesSeconds( queryEngine );
|
||||
|
|
|
@ -11,7 +11,8 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
|||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.DerbyConcatEmulation;
|
||||
import org.hibernate.dialect.function.DerbyLpadFunction;
|
||||
import org.hibernate.dialect.function.DerbyRpadFunction;
|
||||
import org.hibernate.dialect.function.IndividualLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.function.InsertSubstringOverlayEmulation;
|
||||
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
|
||||
|
@ -41,6 +42,7 @@ import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
|||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.CaseFragment;
|
||||
import org.hibernate.sql.DerbyCaseFragment;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
|
@ -170,6 +172,7 @@ public class DerbyDialect extends Dialect {
|
|||
public void initializeFunctionRegistry(QueryEngine queryEngine) {
|
||||
super.initializeFunctionRegistry( queryEngine );
|
||||
|
||||
CommonFunctionFactory.concat_pipeOperator( queryEngine );
|
||||
CommonFunctionFactory.cot( queryEngine );
|
||||
CommonFunctionFactory.chr_char( queryEngine );
|
||||
CommonFunctionFactory.degrees( queryEngine );
|
||||
|
@ -187,7 +190,7 @@ public class DerbyDialect extends Dialect {
|
|||
CommonFunctionFactory.stddevPopSamp( queryEngine );
|
||||
CommonFunctionFactory.substring_substr( queryEngine );
|
||||
CommonFunctionFactory.leftRight_substrLength( queryEngine );
|
||||
CommonFunctionFactory.characterLength_length( queryEngine );
|
||||
CommonFunctionFactory.characterLength_length( queryEngine, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
CommonFunctionFactory.power_expLn( queryEngine );
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "round", "floor(?1*1e?2+0.5)/1e?2")
|
||||
|
@ -195,21 +198,9 @@ public class DerbyDialect extends Dialect {
|
|||
.setInvariantType( StandardBasicTypes.DOUBLE )
|
||||
.register();
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatEmulation() );
|
||||
|
||||
//no way I can see to pad with anything other than spaces
|
||||
// TODO: To support parameters, we have to inline the values
|
||||
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "lpad", "case when length(?1)<?2 then substr(char('',?2)||?1,length(?1)+1) else ?1 end" )
|
||||
.setInvariantType( StandardBasicTypes.STRING )
|
||||
.setExactArgumentCount( 2 )
|
||||
.setArgumentListSignature("(string, length)")
|
||||
.register();
|
||||
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "rpad", "case when length(?1)<?2 then substr(?1||char('',?2),1,?2) else ?1 end" )
|
||||
.setInvariantType( StandardBasicTypes.STRING )
|
||||
.setExactArgumentCount( 2 )
|
||||
.setArgumentListSignature("(string, length)")
|
||||
.register();
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "lpad", new DerbyLpadFunction() );
|
||||
queryEngine.getSqmFunctionRegistry().register( "rpad", new DerbyRpadFunction() );
|
||||
queryEngine.getSqmFunctionRegistry().register( "least", new IndividualLeastGreatestEmulation( true ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "greatest", new IndividualLeastGreatestEmulation( false ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "overlay", new InsertSubstringOverlayEmulation( true ) );
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
|
|||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.*;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
|
@ -157,7 +158,7 @@ public class OracleDialect extends Dialect {
|
|||
CommonFunctionFactory.rownumRowid( queryEngine );
|
||||
CommonFunctionFactory.sysdate( queryEngine );
|
||||
CommonFunctionFactory.systimestamp( queryEngine );
|
||||
CommonFunctionFactory.characterLength_length( queryEngine );
|
||||
CommonFunctionFactory.characterLength_length( queryEngine, SqlAstNodeRenderingMode.DEFAULT );
|
||||
CommonFunctionFactory.addMonths( queryEngine );
|
||||
CommonFunctionFactory.monthsBetween( queryEngine );
|
||||
CommonFunctionFactory.everyAny_sumCaseCase( queryEngine );
|
||||
|
|
|
@ -178,6 +178,7 @@ public class SpannerDialect extends Dialect {
|
|||
.register();
|
||||
|
||||
// String Functions
|
||||
CommonFunctionFactory.concat_pipeOperator( queryEngine );
|
||||
CommonFunctionFactory.trim2( queryEngine );
|
||||
CommonFunctionFactory.reverse( queryEngine );
|
||||
CommonFunctionFactory.repeat( queryEngine );
|
||||
|
|
|
@ -17,7 +17,8 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
|
|||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
|
@ -52,7 +53,7 @@ public class CastFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void render(SqlAppender sqlAppender, List<SqlAstNode> arguments, SqlAstWalker walker) {
|
||||
public void render(SqlAppender sqlAppender, List<SqlAstNode> arguments, SqlAstTranslator<?> walker) {
|
||||
final Expression source = (Expression) arguments.get( 0 );
|
||||
final JdbcMapping sourceMapping = ( (SqlExpressable) source.getExpressionType() ).getJdbcMapping();
|
||||
final CastType sourceType = getCastType( sourceMapping );
|
||||
|
@ -63,7 +64,7 @@ public class CastFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
|||
|
||||
String cast = dialect.castPattern( sourceType, targetType );
|
||||
|
||||
new PatternRenderer( cast ).render( sqlAppender, arguments, walker );
|
||||
new PatternRenderer( cast, SqlAstNodeRenderingMode.DEFAULT ).render( sqlAppender, arguments, walker );
|
||||
}
|
||||
|
||||
private CastType getCastType(JdbcMapping sourceMapping) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.dialect.function;
|
||||
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
|
||||
|
@ -1163,10 +1164,11 @@ public class CommonFunctionFactory {
|
|||
/**
|
||||
* Oracle-style
|
||||
*/
|
||||
public static void characterLength_length(QueryEngine queryEngine) {
|
||||
public static void characterLength_length(QueryEngine queryEngine, SqlAstNodeRenderingMode argumentRenderingMode) {
|
||||
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "length" )
|
||||
.setInvariantType( StandardBasicTypes.INTEGER )
|
||||
.setExactArgumentCount( 1 )
|
||||
.setArgumentRenderingMode( argumentRenderingMode )
|
||||
.register();
|
||||
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "character_length", "length" );
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.hibernate.dialect.function;
|
|||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
@ -37,7 +37,7 @@ public class CurrentFunction
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
sqlAppender.appendSql(sql);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.hibernate.dialect.OracleDialect;
|
|||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -44,7 +44,7 @@ public class DB2FormatEmulation
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression datetime = (Expression) arguments.get(0);
|
||||
final boolean isTime = TypeConfiguration.getSqlTemporalType( datetime.getExpressionType() ) == TemporalType.TIME;
|
||||
final Format format = (Format) arguments.get(1);
|
||||
|
|
|
@ -1,70 +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.dialect.function;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
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.expression.JdbcParameter;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Casts query parameters using the Derby varchar() function
|
||||
* before concatenating them using the || operator.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class DerbyConcatEmulation
|
||||
extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
public DerbyConcatEmulation() {
|
||||
super(
|
||||
"concat",
|
||||
StandardArgumentsValidators.min( 1 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
int numberOfArguments = arguments.size();
|
||||
if ( numberOfArguments > 1 ) {
|
||||
sqlAppender.appendSql("(");
|
||||
}
|
||||
for ( int i = 0; i < numberOfArguments; i++ ) {
|
||||
SqlAstNode argument = arguments.get( i );
|
||||
if ( i > 0 ) {
|
||||
sqlAppender.appendSql("||");
|
||||
}
|
||||
boolean param = argument instanceof JdbcParameter;
|
||||
if ( param ) {
|
||||
sqlAppender.appendSql("cast(");
|
||||
}
|
||||
argument.accept(walker);
|
||||
if ( param ) {
|
||||
sqlAppender.appendSql(" as long varchar)");
|
||||
}
|
||||
}
|
||||
if ( numberOfArguments > 1 ) {
|
||||
sqlAppender.appendSql(")");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(string0[, string1[, ...]])";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.dialect.function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
/**
|
||||
* A derby implementation for lpad.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class DerbyLpadFunction
|
||||
extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
public DerbyLpadFunction() {
|
||||
super(
|
||||
"lpad",
|
||||
StandardArgumentsValidators.exactly( 2 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final SqlAstNode string = arguments.get( 0 );
|
||||
final SqlAstNode length = arguments.get( 1 );
|
||||
sqlAppender.appendSql( "case when length(" );
|
||||
walker.render( string, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.appendSql( ")<" );
|
||||
walker.render( length, SqlAstNodeRenderingMode.DEFAULT );
|
||||
sqlAppender.appendSql( " then substr(char(''," );
|
||||
// The char function for Derby always needs a literal value
|
||||
walker.render( length, SqlAstNodeRenderingMode.INLINE_PARAMETERS );
|
||||
sqlAppender.appendSql( ")||" );
|
||||
walker.render( string, SqlAstNodeRenderingMode.DEFAULT );
|
||||
sqlAppender.appendSql( ",length(" );
|
||||
walker.render( string, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.appendSql( ")+1) else " );
|
||||
walker.render( string, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.appendSql( " end" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(string, length)";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.dialect.function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
/**
|
||||
* A derby implementation for rpad.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class DerbyRpadFunction
|
||||
extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
public DerbyRpadFunction() {
|
||||
super(
|
||||
"rpad",
|
||||
StandardArgumentsValidators.exactly( 2 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final SqlAstNode string = arguments.get( 0 );
|
||||
final SqlAstNode length = arguments.get( 1 );
|
||||
sqlAppender.appendSql( "case when length(" );
|
||||
walker.render( string, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.appendSql( ")<" );
|
||||
walker.render( length, SqlAstNodeRenderingMode.DEFAULT );
|
||||
sqlAppender.appendSql( " then substr(" );
|
||||
walker.render( string, SqlAstNodeRenderingMode.DEFAULT );
|
||||
sqlAppender.appendSql( "||char(''," );
|
||||
// The char function for Derby always needs a literal value
|
||||
walker.render( length, SqlAstNodeRenderingMode.INLINE_PARAMETERS );
|
||||
sqlAppender.appendSql( "),1," );
|
||||
walker.render( length, SqlAstNodeRenderingMode.DEFAULT );
|
||||
sqlAppender.appendSql( ") else " );
|
||||
walker.render( string, SqlAstNodeRenderingMode.DEFAULT );
|
||||
sqlAppender.appendSql( " end" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(string, length)";
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import java.util.List;
|
|||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
|
@ -37,7 +37,7 @@ public class IndividualLeastGreatestEmulation
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
final int numberOfArguments = arguments.size();
|
||||
if ( numberOfArguments > 1 ) {
|
||||
final int lastArgument = numberOfArguments - 1;
|
||||
|
|
|
@ -11,11 +11,9 @@ import java.util.List;
|
|||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -39,7 +37,7 @@ public class QuantifiedLeastGreatestEmulation
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
final int numberOfArguments = arguments.size();
|
||||
if ( numberOfArguments > 1 ) {
|
||||
final int lastArgument = numberOfArguments - 1;
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.hibernate.dialect.SQLServerDialect;
|
|||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -43,7 +43,7 @@ public class SQLServerFormatFunction extends AbstractSqmSelfRenderingFunctionDes
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression datetime = (Expression) arguments.get(0);
|
||||
final boolean isTime = TypeConfiguration.getSqlTemporalType( datetime.getExpressionType() ) == TemporalType.TIME;
|
||||
final Format format = (Format) arguments.get(1);
|
||||
|
|
|
@ -13,7 +13,8 @@ import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
|||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
|
@ -45,7 +46,7 @@ public class TimestampaddFunction
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
|
||||
DurationUnit field = (DurationUnit) arguments.get(0);
|
||||
Expression to = (Expression) arguments.get(2);
|
||||
|
@ -55,7 +56,7 @@ public class TimestampaddFunction
|
|||
TypeConfiguration.getSqlTemporalType( to.getExpressionType() )
|
||||
);
|
||||
|
||||
new PatternRenderer( pattern ).render( sqlAppender, arguments, walker );
|
||||
new PatternRenderer( pattern, SqlAstNodeRenderingMode.DEFAULT ).render( sqlAppender, arguments, walker );
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
|
@ -13,7 +13,8 @@ import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
|||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
|
@ -46,7 +47,7 @@ public class TimestampdiffFunction
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
|
||||
DurationUnit field = (DurationUnit) arguments.get(0);
|
||||
Expression from = (Expression) arguments.get(1);
|
||||
|
@ -58,7 +59,7 @@ public class TimestampdiffFunction
|
|||
TypeConfiguration.getSqlTemporalType( to.getExpressionType() )
|
||||
);
|
||||
|
||||
new PatternRenderer( pattern ).render( sqlAppender, arguments, walker );
|
||||
new PatternRenderer( pattern, SqlAstNodeRenderingMode.DEFAULT ).render( sqlAppender, arguments, walker );
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
|
@ -12,7 +12,8 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
|
|||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -40,14 +41,15 @@ public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void render(SqlAppender sqlAppender, List<SqlAstNode> sqlAstArguments, SqlAstWalker walker) {
|
||||
public void render(SqlAppender sqlAppender, List<SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
|
||||
final TrimSpec specification = ( (TrimSpecification) sqlAstArguments.get( 0 ) ).getSpecification();
|
||||
final Character trimCharacter = ( (QueryLiteral<Character>) sqlAstArguments.get( 1 ) ).getLiteralValue();
|
||||
final Expression sourceExpr = (Expression) sqlAstArguments.get( 2 );
|
||||
|
||||
String trim = dialect.trimPattern( specification, trimCharacter );
|
||||
|
||||
new PatternRenderer( trim ).render( sqlAppender, Collections.singletonList( sourceExpr ), walker );
|
||||
new PatternRenderer( trim, SqlAstNodeRenderingMode.DEFAULT )
|
||||
.render( sqlAppender, Collections.singletonList( sourceExpr ), walker );
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
|
@ -11,7 +11,7 @@ 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.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -51,6 +51,6 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor
|
|||
public abstract void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> sqlAstArguments,
|
||||
SqlAstWalker walker);
|
||||
SqlAstTranslator<?> walker);
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.function;
|
||||
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
@ -27,5 +28,5 @@ public interface FunctionRenderingSupport {
|
|||
void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> sqlAstArguments,
|
||||
SqlAstWalker walker);
|
||||
SqlAstTranslator<?> walker);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ package org.hibernate.query.sqm.function;
|
|||
|
||||
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
|
@ -29,13 +30,22 @@ public class NamedSqmFunctionDescriptor
|
|||
private final String functionName;
|
||||
private final boolean useParenthesesWhenNoArgs;
|
||||
private final String argumentListSignature;
|
||||
private final SqlAstNodeRenderingMode argumentRenderingMode;
|
||||
|
||||
public NamedSqmFunctionDescriptor(
|
||||
String functionName,
|
||||
boolean useParenthesesWhenNoArgs,
|
||||
ArgumentsValidator argumentsValidator,
|
||||
FunctionReturnTypeResolver returnTypeResolver) {
|
||||
this( functionName, useParenthesesWhenNoArgs, argumentsValidator, returnTypeResolver, functionName, null );
|
||||
this(
|
||||
functionName,
|
||||
useParenthesesWhenNoArgs,
|
||||
argumentsValidator,
|
||||
returnTypeResolver,
|
||||
functionName,
|
||||
null,
|
||||
SqlAstNodeRenderingMode.DEFAULT
|
||||
);
|
||||
}
|
||||
|
||||
public NamedSqmFunctionDescriptor(
|
||||
|
@ -44,12 +54,14 @@ public class NamedSqmFunctionDescriptor
|
|||
ArgumentsValidator argumentsValidator,
|
||||
FunctionReturnTypeResolver returnTypeResolver,
|
||||
String name,
|
||||
String argumentListSignature) {
|
||||
String argumentListSignature,
|
||||
SqlAstNodeRenderingMode argumentRenderingMode) {
|
||||
super( name, argumentsValidator, returnTypeResolver );
|
||||
|
||||
this.functionName = functionName;
|
||||
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
|
||||
this.argumentListSignature = argumentListSignature;
|
||||
this.argumentRenderingMode = argumentRenderingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,7 +87,7 @@ public class NamedSqmFunctionDescriptor
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> sqlAstArguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
final boolean useParens = useParenthesesWhenNoArgs || !sqlAstArguments.isEmpty();
|
||||
|
||||
sqlAppender.appendSql( functionName );
|
||||
|
@ -88,7 +100,7 @@ public class NamedSqmFunctionDescriptor
|
|||
if ( !firstPass ) {
|
||||
sqlAppender.appendSql( ", " );
|
||||
}
|
||||
sqlAstArgument.accept(walker);
|
||||
walker.render( sqlAstArgument, argumentRenderingMode );
|
||||
firstPass = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
|
|||
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class PatternBasedSqmFunctionDescriptor
|
|||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> sqlAstArguments,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
renderer.render( sqlAppender, sqlAstArguments, walker );
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.hibernate.metamodel.mapping.SqlExpressable;
|
|||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
|
@ -119,7 +119,7 @@ public class SelfRenderingFunctionSqlAstExpression
|
|||
@Override
|
||||
public void renderToSql(
|
||||
SqlAppender sqlAppender,
|
||||
SqlAstWalker walker,
|
||||
SqlAstTranslator<?> walker,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
renderer.render( sqlAppender, sqlAstArguments, walker );
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.query.sqm.produce.function;
|
|||
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
||||
/**
|
||||
|
@ -26,6 +27,7 @@ public class NamedFunctionDescriptorBuilder {
|
|||
|
||||
private boolean useParenthesesWhenNoArgs = true;
|
||||
private String argumentListSignature;
|
||||
private SqlAstNodeRenderingMode argumentRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||
|
||||
public NamedFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String functionName) {
|
||||
this.registry = registry;
|
||||
|
@ -70,6 +72,11 @@ public class NamedFunctionDescriptorBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public NamedFunctionDescriptorBuilder setArgumentRenderingMode(SqlAstNodeRenderingMode argumentRenderingMode) {
|
||||
this.argumentRenderingMode = argumentRenderingMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqmFunctionDescriptor register() {
|
||||
return registry.register( registrationKey, descriptor() );
|
||||
}
|
||||
|
@ -81,7 +88,8 @@ public class NamedFunctionDescriptorBuilder {
|
|||
argumentsValidator,
|
||||
returnTypeResolver,
|
||||
registrationKey,
|
||||
argumentListSignature
|
||||
argumentListSignature,
|
||||
argumentRenderingMode
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.hibernate.query.sqm.function.PatternBasedSqmFunctionDescriptor;
|
|||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
||||
/**
|
||||
|
@ -23,6 +24,7 @@ public class PatternFunctionDescriptorBuilder {
|
|||
|
||||
private ArgumentsValidator argumentsValidator;
|
||||
private FunctionReturnTypeResolver returnTypeResolver;
|
||||
private SqlAstNodeRenderingMode argumentRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||
|
||||
public PatternFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String pattern) {
|
||||
this.registry = registry;
|
||||
|
@ -54,13 +56,18 @@ public class PatternFunctionDescriptorBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public PatternFunctionDescriptorBuilder setArgumentRenderingMode(SqlAstNodeRenderingMode argumentRenderingMode) {
|
||||
this.argumentRenderingMode = argumentRenderingMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqmFunctionDescriptor register() {
|
||||
return registry.register( registrationKey, descriptor() );
|
||||
}
|
||||
|
||||
public SqmFunctionDescriptor descriptor() {
|
||||
return new PatternBasedSqmFunctionDescriptor(
|
||||
new PatternRenderer( pattern ),
|
||||
new PatternRenderer( pattern, argumentRenderingMode ),
|
||||
argumentsValidator,
|
||||
returnTypeResolver,
|
||||
registrationKey,
|
||||
|
|
|
@ -8,7 +8,8 @@ package org.hibernate.query.sqm.produce.function.internal;
|
|||
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
|
@ -29,13 +30,15 @@ public class PatternRenderer {
|
|||
private final int[] paramIndexes;
|
||||
private final int varargParam;
|
||||
private final int maxParamIndex;
|
||||
private final SqlAstNodeRenderingMode argumentRenderingMode;
|
||||
|
||||
/**
|
||||
* Constructs a template renderer
|
||||
*
|
||||
* @param pattern The template
|
||||
* @param argumentRenderingMode The rendering mode for arguments
|
||||
*/
|
||||
public PatternRenderer(String pattern) {
|
||||
public PatternRenderer(String pattern, SqlAstNodeRenderingMode argumentRenderingMode) {
|
||||
final Set<Integer> paramNumbers = new HashSet<>();
|
||||
final List<String> chunkList = new ArrayList<>();
|
||||
final List<Integer> paramList = new ArrayList<>();
|
||||
|
@ -94,14 +97,16 @@ public class PatternRenderer {
|
|||
chunkList.add( chunk.toString() );
|
||||
}
|
||||
|
||||
varargParam = vararg;
|
||||
maxParamIndex = max;
|
||||
this.varargParam = vararg;
|
||||
this.maxParamIndex = max;
|
||||
|
||||
chunks = chunkList.toArray( new String[chunkList.size()] );
|
||||
paramIndexes = new int[paramList.size()];
|
||||
this.chunks = chunkList.toArray( new String[chunkList.size()] );
|
||||
int[] paramIndexes = new int[paramList.size()];
|
||||
for ( i = 0; i < paramIndexes.length; ++i ) {
|
||||
paramIndexes[i] = paramList.get( i );
|
||||
}
|
||||
this.paramIndexes = paramIndexes;
|
||||
this.argumentRenderingMode = argumentRenderingMode;
|
||||
}
|
||||
|
||||
public boolean hasVarargs() {
|
||||
|
@ -115,15 +120,15 @@ public class PatternRenderer {
|
|||
/**
|
||||
* The rendering code.
|
||||
*
|
||||
* @param args The arguments to inject into the template
|
||||
* @param sqlAppender
|
||||
* @param args The arguments to inject into the template
|
||||
* @return The rendered template with replacements
|
||||
*/
|
||||
@SuppressWarnings({ "UnusedDeclaration" })
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> args,
|
||||
SqlAstWalker walker) {
|
||||
SqlAstTranslator<?> walker) {
|
||||
final int numberOfArguments = args.size();
|
||||
if ( numberOfArguments < maxParamIndex ) {
|
||||
LOG.missingArguments( maxParamIndex, numberOfArguments );
|
||||
|
@ -135,7 +140,7 @@ public class PatternRenderer {
|
|||
final SqlAstNode arg = args.get( j );
|
||||
if ( arg != null ) {
|
||||
sqlAppender.appendSql( chunks[i] );
|
||||
arg.accept( walker );
|
||||
walker.render( arg, argumentRenderingMode );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +151,7 @@ public class PatternRenderer {
|
|||
sqlAppender.appendSql( chunks[i] );
|
||||
}
|
||||
if ( arg != null ) {
|
||||
arg.accept( walker );
|
||||
walker.render( arg, argumentRenderingMode );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -2280,13 +2280,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
@Override
|
||||
public Expression visitFunction(SqmFunction sqmFunction) {
|
||||
inferableTypeAccessStack.push( () -> null );
|
||||
shallownessStack.push( Shallowness.FUNCTION );
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return sqmFunction.convertToSqlAst( this );
|
||||
}
|
||||
finally {
|
||||
shallownessStack.pop();
|
||||
inferableTypeAccessStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.sql.ast;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public enum SqlAstNodeRenderingMode {
|
||||
/**
|
||||
* Render node as is.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* Render parameters as literals.
|
||||
*/
|
||||
INLINE_PARAMETERS,
|
||||
|
||||
/**
|
||||
* Don't render plain parameters. Render it as literal or as expression.
|
||||
*/
|
||||
NO_PLAIN_PARAMETER
|
||||
}
|
|
@ -9,6 +9,7 @@ package org.hibernate.sql.ast;
|
|||
import java.util.Set;
|
||||
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
||||
|
@ -16,6 +17,12 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqlAstTranslator<T extends JdbcOperation> extends SqlAstWalker {
|
||||
|
||||
/**
|
||||
* Renders the given SQL AST node with the given rendering mode.
|
||||
*/
|
||||
void render(SqlAstNode sqlAstNode, SqlAstNodeRenderingMode renderingMode);
|
||||
|
||||
/**
|
||||
* Not the best spot for this. Its the table names collected while walking the SQL AST.
|
||||
* Its ok here because the translator is consider a one-time-use. It just needs to be called
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.hibernate.sql.ast.spi;
|
|||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
|
@ -25,13 +27,19 @@ import org.hibernate.metamodel.mapping.ModelPartContainer;
|
|||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.query.Limit;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlTreeCreationException;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
|
@ -54,6 +62,7 @@ import org.hibernate.sql.exec.spi.JdbcSelect;
|
|||
import org.hibernate.sql.exec.spi.JdbcUpdate;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerStandard;
|
||||
import org.hibernate.type.IntegerType;
|
||||
import org.hibernate.type.StringType;
|
||||
|
||||
import static org.hibernate.sql.ast.SqlTreePrinter.logSqlAst;
|
||||
import static org.hibernate.sql.results.graph.DomainResultGraphPrinter.logDomainResultGraph;
|
||||
|
@ -68,6 +77,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation>
|
|||
private final Statement statement;
|
||||
private final Set<String> affectedTableNames = new HashSet<>();
|
||||
|
||||
private boolean inlineParameters;
|
||||
|
||||
private Map<JdbcParameter, JdbcParameterBinding> appliedParameterBindings = Collections.emptyMap();
|
||||
private JdbcParameterBindings jdbcParameterBindings;
|
||||
private LockOptions lockOptions;
|
||||
|
@ -90,6 +101,84 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation>
|
|||
return affectedTableNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(SqlAstNode sqlAstNode, SqlAstNodeRenderingMode renderingMode) {
|
||||
switch ( renderingMode ) {
|
||||
case NO_PLAIN_PARAMETER:
|
||||
if ( sqlAstNode instanceof SqmParameterInterpretation ) {
|
||||
sqlAstNode = ( (SqmParameterInterpretation) sqlAstNode ).getResolvedExpression();
|
||||
}
|
||||
if ( sqlAstNode instanceof JdbcParameter ) {
|
||||
final JdbcMapping jdbcMapping = ( (JdbcParameter) sqlAstNode ).getExpressionType().getJdbcMappings()
|
||||
.get( 0 );
|
||||
// We try to avoid inlining parameters if possible which can be done by wrapping the parameter
|
||||
// in an expression that is semantically unnecessary e.g. numeric + 0 or concat with an empty string
|
||||
switch ( jdbcMapping.getSqlTypeDescriptor().getJdbcTypeCode() ) {
|
||||
case Types.BIT:
|
||||
case Types.SMALLINT:
|
||||
case Types.TINYINT:
|
||||
case Types.INTEGER:
|
||||
case Types.BIGINT:
|
||||
case Types.DOUBLE:
|
||||
case Types.REAL:
|
||||
case Types.FLOAT:
|
||||
case Types.NUMERIC:
|
||||
case Types.DECIMAL:
|
||||
sqlAstNode.accept( this );
|
||||
appendSql( "+0" );
|
||||
break;
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.NCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.LONGNVARCHAR:
|
||||
final SqmFunctionDescriptor sqmFunctionDescriptor = getSessionFactory().getQueryEngine()
|
||||
.getSqmFunctionRegistry()
|
||||
.findFunctionDescriptor( "concat" );
|
||||
if ( sqmFunctionDescriptor instanceof AbstractSqmSelfRenderingFunctionDescriptor ) {
|
||||
final List<SqlAstNode> list = new ArrayList<>( 2 );
|
||||
list.add( sqlAstNode );
|
||||
list.add( new QueryLiteral<>( "", StringType.INSTANCE ) );
|
||||
( (AbstractSqmSelfRenderingFunctionDescriptor) sqmFunctionDescriptor )
|
||||
.render( this, list, this );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
renderExpressionAsLiteral( (Expression) sqlAstNode, jdbcParameterBindings );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sqlAstNode.accept( this );
|
||||
}
|
||||
break;
|
||||
case INLINE_PARAMETERS:
|
||||
boolean inlineParameters = this.inlineParameters;
|
||||
this.inlineParameters = true;
|
||||
try {
|
||||
sqlAstNode.accept( this );
|
||||
}
|
||||
finally {
|
||||
this.inlineParameters = inlineParameters;
|
||||
}
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
sqlAstNode.accept( this );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParameter(JdbcParameter jdbcParameter) {
|
||||
if ( inlineParameters ) {
|
||||
renderExpressionAsLiteral( jdbcParameter, jdbcParameterBindings );
|
||||
}
|
||||
else {
|
||||
super.visitParameter( jdbcParameter );
|
||||
}
|
||||
}
|
||||
|
||||
protected void addAppliedParameterBinding(JdbcParameter parameter, JdbcParameterBinding binding) {
|
||||
if ( appliedParameterBindings.isEmpty() ) {
|
||||
appliedParameterBindings = new IdentityHashMap<>();
|
||||
|
@ -197,6 +286,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation>
|
|||
protected void renderExpressionAsLiteral(Expression expression, JdbcParameterBindings jdbcParameterBindings) {
|
||||
if ( expression instanceof Literal ) {
|
||||
expression.accept( this );
|
||||
return;
|
||||
}
|
||||
else if ( expression instanceof JdbcParameter ) {
|
||||
if ( jdbcParameterBindings == null ) {
|
||||
|
@ -204,6 +294,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation>
|
|||
}
|
||||
final JdbcParameter parameter = (JdbcParameter) expression;
|
||||
renderAsLiteral( parameter, getParameterBindValue( parameter ) );
|
||||
return;
|
||||
}
|
||||
throw new UnsupportedOperationException( "Can't render expression as literal: " + expression );
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
|
|||
import org.hibernate.query.sqm.tree.expression.Conversion;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
@ -2721,12 +2722,20 @@ public abstract class AbstractSqlAstWalker implements SqlAstWalker, SqlAppender
|
|||
@Override
|
||||
public void visitSelfRenderingPredicate(SelfRenderingPredicate selfRenderingPredicate) {
|
||||
// todo (6.0) render boolean expression as comparison predicate if necessary
|
||||
selfRenderingPredicate.getSelfRenderingExpression().renderToSql( this, this, getSessionFactory() );
|
||||
selfRenderingPredicate.getSelfRenderingExpression().renderToSql(
|
||||
this,
|
||||
(SqlAstTranslator<?>) this,
|
||||
getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSelfRenderingExpression(SelfRenderingExpression expression) {
|
||||
expression.renderToSql( this, this, getSessionFactory() );
|
||||
expression.renderToSql(
|
||||
this,
|
||||
(SqlAstTranslator<?>) this,
|
||||
getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.sql.ast.tree.expression;
|
|||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@ public class LiteralAsParameter<T> implements SelfRenderingExpression {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void renderToSql(SqlAppender sqlAppender, SqlAstWalker walker, SessionFactoryImplementor sessionFactory) {
|
||||
public void renderToSql(SqlAppender sqlAppender, SqlAstTranslator<?> walker, SessionFactoryImplementor sessionFactory) {
|
||||
sqlAppender.appendSql( "?" );
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.sql.ast.tree.expression;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
|
||||
|
@ -19,5 +20,5 @@ public interface SelfRenderingExpression extends Expression {
|
|||
sqlTreeWalker.visitSelfRenderingExpression( this );
|
||||
}
|
||||
|
||||
void renderToSql(SqlAppender sqlAppender, SqlAstWalker walker, SessionFactoryImplementor sessionFactory);
|
||||
void renderToSql(SqlAppender sqlAppender, SqlAstTranslator<?> walker, SessionFactoryImplementor sessionFactory);
|
||||
}
|
||||
|
|
|
@ -264,7 +264,6 @@ public class FunctionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support a parameter in the 'length' function or the 'char' function which we render as emulation")
|
||||
public void testOverlayFunctionParameters(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -338,7 +337,6 @@ public class FunctionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support a parameter in the 'length' function or the 'char' function which we render as emulation")
|
||||
public void testPadFunctionParameters(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
|
|
@ -104,6 +104,11 @@ public class PreparedStatementSpyConnectionProvider extends ConnectionProviderDe
|
|||
}
|
||||
Connection connectionSpy = spy( connection, settingsForConnections );
|
||||
try {
|
||||
// Apache Derby is object identity sensitive and calling setAutoCommit on the spy causes issues
|
||||
Mockito.doAnswer( invocation -> {
|
||||
connection.setAutoCommit( invocation.getArgument( 0 ) );
|
||||
return null;
|
||||
}).when( connectionSpy ).setAutoCommit( Mockito.anyBoolean() );
|
||||
Mockito.doAnswer( invocation -> {
|
||||
PreparedStatement statement = (PreparedStatement) invocation.callRealMethod();
|
||||
PreparedStatement statementSpy = spy( statement, settingsForStatements );
|
||||
|
|
Loading…
Reference in New Issue