HHH-16229 - Consider pluggability for rendering "JDBC" parameters
This commit is contained in:
parent
6ed48ffff5
commit
4cc8f04b73
|
@ -38,6 +38,7 @@ import org.hibernate.query.sqm.mutation.internal.SqmMultiTableMutationStrategyPr
|
|||
import org.hibernate.resource.beans.spi.ManagedBeanRegistryInitiator;
|
||||
import org.hibernate.resource.transaction.internal.TransactionCoordinatorBuilderInitiator;
|
||||
import org.hibernate.service.internal.SessionFactoryServiceRegistryFactoryInitiator;
|
||||
import org.hibernate.sql.ast.internal.JdbcParameterRendererInitiator;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerProviderInitiator;
|
||||
import org.hibernate.tool.schema.internal.SchemaManagementToolInitiator;
|
||||
import org.hibernate.tool.schema.internal.script.SqlScriptExtractorInitiator;
|
||||
|
@ -99,6 +100,7 @@ public final class StandardServiceInitiators {
|
|||
|
||||
serviceInitiators.add( JdbcValuesMappingProducerProviderInitiator.INSTANCE );
|
||||
serviceInitiators.add( SqmMultiTableMutationStrategyProviderInitiator.INSTANCE );
|
||||
serviceInitiators.add( JdbcParameterRendererInitiator.INSTANCE );
|
||||
|
||||
serviceInitiators.trimToSize();
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.internal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcParameterRendererInitiator implements StandardServiceInitiator<JdbcParameterRenderer> {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final JdbcParameterRendererInitiator INSTANCE = new JdbcParameterRendererInitiator();
|
||||
|
||||
@Override
|
||||
public JdbcParameterRenderer initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||
return JdbcParameterRendererStandard.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<JdbcParameterRenderer> getServiceInitiated() {
|
||||
return JdbcParameterRenderer.class;
|
||||
}
|
||||
}
|
|
@ -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.internal;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcParameterRendererStandard implements JdbcParameterRenderer {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final JdbcParameterRendererStandard INSTANCE = new JdbcParameterRendererStandard();
|
||||
|
||||
@Override
|
||||
public void renderJdbcParameter(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
|
||||
jdbcType.appendWriteExpression( "?", appender, dialect );
|
||||
}
|
||||
}
|
|
@ -95,6 +95,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement;
|
|||
import org.hibernate.sql.ast.tree.cte.CteTableGroup;
|
||||
import org.hibernate.sql.ast.tree.cte.SearchClauseSpecification;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.AggregateColumnWriteExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Any;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||
|
@ -102,7 +103,6 @@ import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
|||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.Collation;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.AggregateColumnWriteExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Distinct;
|
||||
import org.hibernate.sql.ast.tree.expression.Duration;
|
||||
import org.hibernate.sql.ast.tree.expression.DurationUnit;
|
||||
|
@ -192,7 +192,6 @@ import org.hibernate.sql.model.internal.TableInsertStandard;
|
|||
import org.hibernate.sql.model.internal.TableUpdateCustomSql;
|
||||
import org.hibernate.sql.model.internal.TableUpdateStandard;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerStandard;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducerProvider;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
|
@ -268,6 +267,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
|
||||
private final List<JdbcParameterBinder> parameterBinders = new ArrayList<>();
|
||||
private final JdbcParametersImpl jdbcParameters = new JdbcParametersImpl();
|
||||
private JdbcParameterBindings jdbcParameterBindings;
|
||||
private Map<JdbcParameter, JdbcParameterBinding> appliedParameterBindings = Collections.emptyMap();
|
||||
private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
||||
|
||||
|
||||
|
||||
private final Set<FilterJdbcParameter> filterJdbcParameters = new HashSet<>();
|
||||
|
||||
|
@ -302,16 +307,19 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
private transient BasicType<String> stringType;
|
||||
private transient BasicType<Boolean> booleanType;
|
||||
|
||||
private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||
|
||||
private Map<JdbcParameter, JdbcParameterBinding> appliedParameterBindings = Collections.emptyMap();
|
||||
private JdbcParameterBindings jdbcParameterBindings;
|
||||
private LockOptions lockOptions;
|
||||
private Limit limit;
|
||||
private JdbcParameter offsetParameter;
|
||||
private JdbcParameter limitParameter;
|
||||
private ForUpdateClause forUpdate;
|
||||
|
||||
protected AbstractSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.dialect = sessionFactory.getJdbcServices().getDialect();
|
||||
this.statementStack.push( statement );
|
||||
this.jdbcParameterRenderer = sessionFactory.getServiceRegistry().getService( JdbcParameterRenderer.class );
|
||||
}
|
||||
|
||||
private static Clause matchWithClause(Clause clause) {
|
||||
if ( clause == Clause.WITH ) {
|
||||
return Clause.WITH;
|
||||
|
@ -323,12 +331,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
return dialect;
|
||||
}
|
||||
|
||||
protected AbstractSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.dialect = sessionFactory.getJdbcServices().getDialect();
|
||||
this.statementStack.push( statement );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory;
|
||||
|
@ -499,7 +501,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
|
||||
@Override
|
||||
public boolean supportsFilterClause() {
|
||||
// By default we report false because not many dialects support this
|
||||
// By default, we report false because not many dialects support this
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6178,27 +6180,38 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
public void visitParameter(JdbcParameter jdbcParameter) {
|
||||
switch ( getParameterRenderingMode() ) {
|
||||
case NO_UNTYPED:
|
||||
case NO_PLAIN_PARAMETER:
|
||||
case NO_PLAIN_PARAMETER: {
|
||||
renderCasted( jdbcParameter );
|
||||
break;
|
||||
}
|
||||
case INLINE_PARAMETERS:
|
||||
case INLINE_ALL_PARAMETERS:
|
||||
case INLINE_ALL_PARAMETERS: {
|
||||
renderExpressionAsLiteral( jdbcParameter, jdbcParameterBindings );
|
||||
break;
|
||||
}
|
||||
case DEFAULT:
|
||||
default:
|
||||
jdbcParameter.getExpressionType()
|
||||
.getJdbcMappings()
|
||||
.get( 0 )
|
||||
.getJdbcType()
|
||||
.appendWriteExpression( "?", this, getDialect() );
|
||||
|
||||
parameterBinders.add( jdbcParameter.getParameterBinder() );
|
||||
jdbcParameters.addParameter( jdbcParameter );
|
||||
default: {
|
||||
visitParameterAsParameter( jdbcParameter );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void visitParameterAsParameter(JdbcParameter jdbcParameter) {
|
||||
renderParameterAsParameter( jdbcParameter );
|
||||
parameterBinders.add( jdbcParameter.getParameterBinder() );
|
||||
jdbcParameters.addParameter( jdbcParameter );
|
||||
}
|
||||
|
||||
protected void renderParameterAsParameter(JdbcParameter jdbcParameter) {
|
||||
jdbcParameterRenderer.renderJdbcParameter(
|
||||
parameterBinders.size() + 1,
|
||||
jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType(),
|
||||
this,
|
||||
getDialect()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(SqlAstNode sqlAstNode, SqlAstNodeRenderingMode renderingMode) {
|
||||
SqlAstNodeRenderingMode original = this.parameterRenderingMode;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.spi;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.service.Service;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
/**
|
||||
* Extension point, intended for use from Hibernate Reactive, to render JDBC
|
||||
* parameter placeholders into the SQL query string being generated.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JdbcParameterRenderer extends Service {
|
||||
/**
|
||||
* Render the parameter for the given position
|
||||
*
|
||||
* @param position The 1-based position of the parameter.
|
||||
* @param jdbcType The type of the parameter
|
||||
* @param appender The appender where the parameter should be rendered
|
||||
* @param dialect The Dialect in use within the SessionFactory
|
||||
*/
|
||||
void renderJdbcParameter(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect);
|
||||
}
|
|
@ -9,6 +9,7 @@ package org.hibernate.orm.test.dialect.function;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
|
@ -30,90 +31,95 @@ import org.hibernate.type.descriptor.jdbc.CharJdbcType;
|
|||
import org.hibernate.type.internal.BasicTypeImpl;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@ServiceRegistry
|
||||
public class AnsiTrimEmulationFunctionTest {
|
||||
private static final String trimSource = "a.column";
|
||||
|
||||
@Test
|
||||
public void testBasicSqlServerProcessing() {
|
||||
public void testBasicSqlServerProcessing(ServiceRegistryScope scope) {
|
||||
Dialect dialect = new SQLServerDialect();
|
||||
TrimFunction function = new TrimFunction( dialect, new TypeConfiguration() );
|
||||
|
||||
performBasicSpaceTrimmingTests( dialect, function );
|
||||
performBasicSpaceTrimmingTests( dialect, scope.getRegistry(), function );
|
||||
|
||||
final String expectedTrimPrep = "replace(replace(a.column,' ','#%#%'),'-',' ')";
|
||||
final String expectedPostTrimPrefix = "replace(replace(";
|
||||
final String expectedPostTrimSuffix = ",' ','-'),'#%#%',' ')";
|
||||
|
||||
// -> trim(LEADING '-' FROM a.column)
|
||||
String rendered = render( dialect, function, TrimSpec.LEADING, '-', trimSource );
|
||||
String rendered = render( dialect, scope.getRegistry(), function, TrimSpec.LEADING, '-', trimSource );
|
||||
String expected = expectedPostTrimPrefix + "ltrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(TRAILING '-' FROM a.column)
|
||||
rendered = render( dialect, function, TrimSpec.TRAILING, '-', trimSource );
|
||||
rendered = render( dialect, scope.getRegistry(), function, TrimSpec.TRAILING, '-', trimSource );
|
||||
expected = expectedPostTrimPrefix + "rtrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(BOTH '-' FROM a.column)
|
||||
rendered = render( dialect, function, TrimSpec.BOTH, '-', trimSource );
|
||||
rendered = render( dialect, scope.getRegistry(), function, TrimSpec.BOTH, '-', trimSource );
|
||||
expected = expectedPostTrimPrefix + "ltrim(rtrim(" + expectedTrimPrep + "))" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicSybaseProcessing() {
|
||||
public void testBasicSybaseProcessing(ServiceRegistryScope scope) {
|
||||
Dialect dialect = new SybaseDialect();
|
||||
TrimFunction function = new TrimFunction( dialect, new TypeConfiguration() );
|
||||
|
||||
performBasicSpaceTrimmingTests( dialect, function );
|
||||
performBasicSpaceTrimmingTests( dialect, scope.getRegistry(), function );
|
||||
|
||||
final String expectedTrimPrep = "str_replace(str_replace(a.column,' ','#%#%'),'-',' ')";
|
||||
final String expectedPostTrimPrefix = "str_replace(str_replace(";
|
||||
final String expectedPostTrimSuffix = ",' ','-'),'#%#%',' ')";
|
||||
|
||||
// -> trim(LEADING '-' FROM a.column)
|
||||
String rendered = render( dialect, function, TrimSpec.LEADING, '-', trimSource );
|
||||
String rendered = render( dialect, scope.getRegistry(), function, TrimSpec.LEADING, '-', trimSource );
|
||||
String expected = expectedPostTrimPrefix + "ltrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(TRAILING '-' FROM a.column)
|
||||
rendered = render( dialect, function, TrimSpec.TRAILING, '-', trimSource );
|
||||
rendered = render( dialect, scope.getRegistry(), function, TrimSpec.TRAILING, '-', trimSource );
|
||||
expected = expectedPostTrimPrefix + "rtrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(BOTH '-' FROM a.column)
|
||||
rendered = render( dialect, function, TrimSpec.BOTH, '-', trimSource );
|
||||
rendered = render( dialect, scope.getRegistry(), function, TrimSpec.BOTH, '-', trimSource );
|
||||
expected = expectedPostTrimPrefix + "ltrim(rtrim(" + expectedTrimPrep + "))" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
}
|
||||
|
||||
private void performBasicSpaceTrimmingTests(Dialect dialect, TrimFunction function) {
|
||||
private void performBasicSpaceTrimmingTests(Dialect dialect, StandardServiceRegistry registry, TrimFunction function) {
|
||||
// -> trim(a.column)
|
||||
String rendered = render( dialect, function, TrimSpec.BOTH, ' ', trimSource );
|
||||
String rendered = render( dialect, registry, function, TrimSpec.BOTH, ' ', trimSource );
|
||||
assertEquals( "ltrim(rtrim(a.column))", rendered );
|
||||
|
||||
// -> trim(LEADING FROM a.column)
|
||||
rendered = render( dialect, function, TrimSpec.LEADING, ' ', trimSource );
|
||||
rendered = render( dialect, registry, function, TrimSpec.LEADING, ' ', trimSource );
|
||||
assertEquals( "ltrim(a.column)", rendered );
|
||||
|
||||
// -> trim(TRAILING FROM a.column)
|
||||
rendered = render( dialect, function, TrimSpec.TRAILING, ' ', trimSource );
|
||||
rendered = render( dialect, registry, function, TrimSpec.TRAILING, ' ', trimSource );
|
||||
assertEquals( "rtrim(a.column)", rendered );
|
||||
}
|
||||
|
||||
private String render(
|
||||
Dialect dialect,
|
||||
StandardServiceRegistry registry,
|
||||
TrimFunction function,
|
||||
TrimSpec trimSpec,
|
||||
char trimCharacter,
|
||||
|
@ -121,6 +127,7 @@ public class AnsiTrimEmulationFunctionTest {
|
|||
SessionFactoryImplementor factory = Mockito.mock( SessionFactoryImplementor.class );
|
||||
JdbcServices jdbcServices = Mockito.mock( JdbcServices.class );
|
||||
Mockito.doReturn( jdbcServices ).when( factory ).getJdbcServices();
|
||||
Mockito.doReturn( registry ).when( factory ).getServiceRegistry();
|
||||
Mockito.doReturn( dialect ).when( jdbcServices ).getDialect();
|
||||
StandardSqlAstTranslator<JdbcOperation> walker = new StandardSqlAstTranslator<>(
|
||||
factory,
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.orm.test.sql.ast;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @implNote Restricted to H2 as there is nothing intrinsically Dialect specific here,
|
||||
* though each database has specific syntax for labelled parameters
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@ServiceRegistry( services = @ServiceRegistry.Service(
|
||||
role = JdbcParameterRenderer.class,
|
||||
impl = JdbcParameterRendererTests.JdbcParameterRendererImpl.class
|
||||
) )
|
||||
@DomainModel( annotatedClasses = EntityOfBasics.class )
|
||||
@SessionFactory( useCollectingStatementInspector = true )
|
||||
@RequiresDialect( H2Dialect.class )
|
||||
public class JdbcParameterRendererTests {
|
||||
@Test
|
||||
public void basicTest(SessionFactoryScope scope) {
|
||||
final String queryString = "select e from EntityOfBasics e where e.id = :id";
|
||||
|
||||
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createSelectionQuery( queryString, EntityOfBasics.class ).setParameter( "id", 1 ).list();
|
||||
} );
|
||||
|
||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||
final String sql = statementInspector.getSqlQueries().get( 0 );
|
||||
assertThat( sql ).contains( "?1" );
|
||||
}
|
||||
|
||||
public static class JdbcParameterRendererImpl implements JdbcParameterRenderer {
|
||||
@Override
|
||||
public void renderJdbcParameter(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
|
||||
jdbcType.appendWriteExpression( "?" + position, appender, dialect );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -71,62 +71,46 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
public class SmokeTests {
|
||||
@Test
|
||||
public void testSimpleHqlInterpretation(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final QueryImplementor<String> query = session.createQuery(
|
||||
"select e.name from SimpleEntity e",
|
||||
String.class
|
||||
);
|
||||
final SqmQueryImplementor<String> hqlQuery = (SqmQueryImplementor<String>) query;
|
||||
final SqmSelectStatement<String> sqmStatement = (SqmSelectStatement<String>) hqlQuery.getSqmStatement();
|
||||
scope.inTransaction( (session) -> {
|
||||
final SelectStatement sqlAst = SqlAstHelper.translateHqlSelectQuery(
|
||||
"select e.name from SimpleEntity e",
|
||||
String.class,
|
||||
session
|
||||
);
|
||||
|
||||
final StandardSqmTranslator<SelectStatement> sqmConverter = new StandardSqmTranslator<>(
|
||||
sqmStatement,
|
||||
hqlQuery.getQueryOptions(),
|
||||
( (QuerySqmImpl<?>) hqlQuery ).getDomainParameterXref(),
|
||||
query.getParameterBindings(),
|
||||
session.getLoadQueryInfluencers(),
|
||||
scope.getSessionFactory(),
|
||||
true
|
||||
);
|
||||
final FromClause fromClause = sqlAst.getQuerySpec().getFromClause();
|
||||
assertThat( fromClause.getRoots().size(), is( 1 ) );
|
||||
|
||||
final SqmTranslation<SelectStatement> sqmInterpretation = sqmConverter.translate();
|
||||
final SelectStatement sqlAst = sqmInterpretation.getSqlAst();
|
||||
final TableGroup rootTableGroup = fromClause.getRoots().get( 0 );
|
||||
assertThat( rootTableGroup.getPrimaryTableReference(), notNullValue() );
|
||||
assertThat( rootTableGroup.getPrimaryTableReference().getTableId(), is( "mapping_simple_entity" ) );
|
||||
|
||||
final FromClause fromClause = sqlAst.getQuerySpec().getFromClause();
|
||||
assertThat( fromClause.getRoots().size(), is( 1 ) );
|
||||
assertThat( rootTableGroup.getTableReferenceJoins().size(), is( 0 ) );
|
||||
|
||||
final TableGroup rootTableGroup = fromClause.getRoots().get( 0 );
|
||||
assertThat( rootTableGroup.getPrimaryTableReference(), notNullValue() );
|
||||
assertThat( rootTableGroup.getPrimaryTableReference().getTableId(), is( "mapping_simple_entity" ) );
|
||||
|
||||
assertThat( rootTableGroup.getTableReferenceJoins().size(), is( 0 ) );
|
||||
|
||||
assertThat( rootTableGroup.getTableGroupJoins().isEmpty(), is( true ) );
|
||||
assertThat( rootTableGroup.getTableGroupJoins().isEmpty(), is( true ) );
|
||||
|
||||
|
||||
// `s` is the "alias stem" for `SimpleEntity` and as it is the first entity with that stem in
|
||||
// the query the base becomes `s1`. The primary table reference is always suffixed as `_0`
|
||||
assertThat( rootTableGroup.getPrimaryTableReference().getIdentificationVariable(), is( "s1_0" ) );
|
||||
// `s` is the "alias stem" for `SimpleEntity` and as it is the first entity with that stem in
|
||||
// the query the base becomes `s1`. The primary table reference is always suffixed as `_0`
|
||||
assertThat( rootTableGroup.getPrimaryTableReference().getIdentificationVariable(), is( "s1_0" ) );
|
||||
|
||||
final SelectClause selectClause = sqlAst.getQuerySpec().getSelectClause();
|
||||
assertThat( selectClause.getSqlSelections().size(), is( 1 ) ) ;
|
||||
final SqlSelection sqlSelection = selectClause.getSqlSelections().get( 0 );
|
||||
assertThat( sqlSelection.getJdbcResultSetIndex(), is( 1 ) );
|
||||
assertThat( sqlSelection.getValuesArrayPosition(), is( 0 ) );
|
||||
assertThat( sqlSelection.getJdbcValueExtractor(), notNullValue() );
|
||||
final SelectClause selectClause = sqlAst.getQuerySpec().getSelectClause();
|
||||
assertThat( selectClause.getSqlSelections().size(), is( 1 ) ) ;
|
||||
final SqlSelection sqlSelection = selectClause.getSqlSelections().get( 0 );
|
||||
assertThat( sqlSelection.getJdbcResultSetIndex(), is( 1 ) );
|
||||
assertThat( sqlSelection.getValuesArrayPosition(), is( 0 ) );
|
||||
assertThat( sqlSelection.getJdbcValueExtractor(), notNullValue() );
|
||||
|
||||
final JdbcOperationQuerySelect jdbcSelectOperation = new StandardSqlAstTranslator<JdbcOperationQuerySelect>(
|
||||
session.getSessionFactory(),
|
||||
sqlAst
|
||||
).translate( null, QueryOptions.NONE );
|
||||
final JdbcOperationQuerySelect jdbcSelectOperation = new StandardSqlAstTranslator<JdbcOperationQuerySelect>(
|
||||
session.getSessionFactory(),
|
||||
sqlAst
|
||||
).translate( null, QueryOptions.NONE );
|
||||
|
||||
assertThat(
|
||||
jdbcSelectOperation.getSqlString(),
|
||||
is( "select s1_0.name from mapping_simple_entity s1_0" )
|
||||
);
|
||||
}
|
||||
);
|
||||
assertThat(
|
||||
jdbcSelectOperation.getSqlString(),
|
||||
is( "select s1_0.name from mapping_simple_entity s1_0" )
|
||||
);
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.orm.test.sql.ast;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.query.hql.spi.SqmQueryImplementor;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
import org.hibernate.query.sqm.internal.QuerySqmImpl;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslation;
|
||||
import org.hibernate.query.sqm.sql.internal.StandardSqmTranslator;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqlAstHelper {
|
||||
public static SelectStatement translateHqlSelectQuery(String hql, Class<?> returnType, SessionImplementor session) {
|
||||
final QueryImplementor<?> query = session.createQuery( hql, returnType );
|
||||
final QuerySqmImpl<?> hqlQuery = (QuerySqmImpl<?>) query;
|
||||
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) hqlQuery.getSqmStatement();
|
||||
|
||||
final StandardSqmTranslator<SelectStatement> sqmConverter = new StandardSqmTranslator<>(
|
||||
sqmStatement,
|
||||
hqlQuery.getQueryOptions(),
|
||||
hqlQuery.getDomainParameterXref(),
|
||||
query.getParameterBindings(),
|
||||
session.getLoadQueryInfluencers(),
|
||||
session.getFactory(),
|
||||
true
|
||||
);
|
||||
|
||||
final SqmTranslation<SelectStatement> sqmInterpretation = sqmConverter.translate();
|
||||
return sqmInterpretation.getSqlAst();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue