HHH-16260 - JdbcParameterRenderer not called with dynamic filters

HHH-16256 - JdbcParameterRenderer to have an impact on write operations
HHH-16273 - Support for Dialect native JdbcParameterRenderer
This commit is contained in:
Steve Ebersole 2023-03-08 21:30:21 -06:00
parent 9b83362b88
commit 55691a0c27
21 changed files with 121 additions and 3 deletions

View File

@ -2788,6 +2788,21 @@ public interface AvailableSettings {
*/
String TIMEZONE_DEFAULT_STORAGE = "hibernate.timezone.default_storage";
/**
* Specifies whether to use JDBC parameter markers (`?`) or dialect native markers.
*
* @implNote By default ({@code true}), dialect native markers are used, if any; disable
* ({@code false}) to use the standard JDBC parameter markers (`?`) instead
*
* @see org.hibernate.sql.ast.spi.JdbcParameterRenderer
* @see org.hibernate.dialect.Dialect#getNativeParameterRenderer()
*
* @since 6.2
*/
@Incubating
String DIALECT_NATIVE_PARAM_MARKERS = "hibernate.dialect.native_param_markers";
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Java (javax) Persistence defined settings
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -145,6 +145,8 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.sql.ForUpdateFragment;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.internal.JdbcParameterRendererStandard;
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
import org.hibernate.sql.model.MutationOperation;
@ -4813,6 +4815,13 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
return "truncate table " + tableName;
}
/**
* Support for native parameter rendering
*/
public JdbcParameterRenderer getNativeParameterRenderer() {
return JdbcParameterRendererStandard.INSTANCE;
}
/**
* Pluggable strategy for determining the {@link Size} to use for
* columns of a given SQL type.

View File

@ -57,6 +57,7 @@ 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.JdbcParameterRenderer;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
@ -907,4 +908,14 @@ public class H2Dialect extends Dialect {
SessionFactoryImplementor factory) {
return new OptionalTableUpdateOperation( mutationTarget, optionalTableUpdate, factory );
}
@Override
public JdbcParameterRenderer getNativeParameterRenderer() {
return H2Dialect::renderNatively;
}
private static void renderNatively(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
appender.append( "?" );
appender.appendSql( position );
}
}

View File

@ -66,6 +66,7 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
@ -1429,4 +1430,14 @@ public class PostgreSQLDialect extends Dialect {
SessionFactoryImplementor factory) {
return new OptionalTableUpdateOperation( mutationTarget, optionalTableUpdate, factory );
}
@Override
public JdbcParameterRenderer getNativeParameterRenderer() {
return PostgreSQLDialect::renderNatively;
}
private static void renderNatively(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
appender.append( "$" );
appender.appendSql( position );
}
}

View File

@ -9,6 +9,10 @@ package org.hibernate.sql.ast.internal;
import java.util.Map;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
@ -23,6 +27,17 @@ public class JdbcParameterRendererInitiator implements StandardServiceInitiator<
@Override
public JdbcParameterRenderer initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
final boolean useNativeMarkers = ConfigurationHelper.getBoolean(
AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS,
configurationValues,
true
);
if ( useNativeMarkers ) {
final Dialect dialect = registry.getService( JdbcServices.class ).getDialect();
return dialect.getNativeParameterRenderer();
}
return JdbcParameterRendererStandard.INSTANCE;
}

View File

@ -6187,8 +6187,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
protected void renderParameterAsParameter(JdbcParameter jdbcParameter) {
renderParameterAsParameter( jdbcParameter, parameterBinders.size() + 1 );
}
protected void renderParameterAsParameter(JdbcParameter jdbcParameter, int position) {
jdbcParameterRenderer.renderJdbcParameter(
parameterBinders.size() + 1,
position,
jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType(),
this,
getDialect()

View File

@ -11,6 +11,7 @@ package org.hibernate.sql.ast.spi;
*
* @author Steve Ebersole
*/
@FunctionalInterface
public interface SqlAppender extends Appendable {
String NO_SEPARATOR = "";
String COMA_SEPARATOR = ",";

View File

@ -8,12 +8,15 @@ import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.annotations.BatchSize;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -32,6 +35,11 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ServiceRegistry(
settings = {
@Setting( name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false" )
}
)
@DomainModel(
annotatedClasses = {
BatchAndClassIdAndLazyCollectionTest.Child.class,

View File

@ -8,12 +8,15 @@ import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.annotations.BatchSize;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -31,6 +34,11 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ServiceRegistry(
settings = {
@Setting( name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false" )
}
)
@DomainModel(
annotatedClasses = {
BatchAndClassIdTest.Child.class,

View File

@ -8,12 +8,15 @@ import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.annotations.BatchSize;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -32,6 +35,11 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ServiceRegistry(
settings = {
@Setting( name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false" )
}
)
@DomainModel(
annotatedClasses = {
BatchAndEmbeddedIdId2Test.Child.class,

View File

@ -9,12 +9,15 @@ import java.util.Set;
import org.hibernate.DuplicateMappingException;
import org.hibernate.Hibernate;
import org.hibernate.annotations.BatchSize;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -34,6 +37,11 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ServiceRegistry(
settings = {
@Setting( name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false" )
}
)
@DomainModel(
annotatedClasses = {
BatchAndEmbeddedIdIdAndLazyCollectionTest.Child.class,

View File

@ -8,12 +8,15 @@ import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.annotations.BatchSize;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -32,6 +35,11 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ServiceRegistry(
settings = {
@Setting( name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false" )
}
)
@DomainModel(
annotatedClasses = {
BatchAndEmbeddedIdIdTest.Child.class,

View File

@ -48,6 +48,7 @@ public class BatchOptimisticLockingTest extends
@Override
protected void addSettings(Map<String,Object> settings) {
settings.put( AvailableSettings.STATEMENT_BATCH_SIZE, String.valueOf( 2 ) );
settings.put( AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, Boolean.FALSE );
}
@Test

View File

@ -48,6 +48,7 @@ abstract class BaseInsertOrderingTest extends BaseSessionFactoryFunctionalTest {
.get( AvailableSettings.CONNECTION_PROVIDER );
this.connectionProvider.setConnectionProvider( connectionProvider );
builer.applySetting( AvailableSettings.CONNECTION_PROVIDER, this.connectionProvider );
builer.applySetting( AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, false );
builer.applySetting( AvailableSettings.DEFAULT_LIST_SEMANTICS, CollectionClassification.BAG );
}

View File

@ -38,6 +38,7 @@ public class SessionJdbcBatchTest
@Override
protected void addSettings(Map<String,Object> settings) {
settings.put( AvailableSettings.STATEMENT_BATCH_SIZE, 2 );
settings.put( AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, Boolean.FALSE );
connectionProvider.setConnectionProvider( (ConnectionProvider) settings.get( AvailableSettings.CONNECTION_PROVIDER ) );
settings.put(
AvailableSettings.CONNECTION_PROVIDER,

View File

@ -14,6 +14,7 @@ import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
import org.hibernate.query.sqm.CastType;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
@ -40,6 +41,7 @@ public abstract class AbstractCriteriaLiteralHandlingModeTest extends BaseEntity
@Override
protected void addConfigOptions(Map options) {
sqlStatementInterceptor = new SQLStatementInterceptor( options );
options.put( AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, Boolean.FALSE );
}
@Override

View File

@ -23,6 +23,7 @@ import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.ListJoin;
import jakarta.persistence.criteria.Root;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.exception.SQLGrammarException;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
@ -32,6 +33,7 @@ import org.hibernate.testing.jdbc.SQLStatementInterceptor;
import org.junit.Before;
import org.junit.Test;
import static java.lang.Boolean.FALSE;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -49,6 +51,7 @@ public class CriteriaLiteralsTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected void addConfigOptions(Map options) {
sqlStatementInterceptor = new SQLStatementInterceptor( options );
options.put( AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, FALSE );
}
@Override

View File

@ -41,7 +41,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
@Jpa(
annotatedClasses = { NamedQueryCommentTest.Game.class },
integrationSettings = {
@Setting( name = AvailableSettings.USE_SQL_COMMENTS, value = "true" )
@Setting( name = AvailableSettings.USE_SQL_COMMENTS, value = "true" ),
@Setting( name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false" )
},
useCollectingStatementInspector = true
)

View File

@ -39,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
integrationSettings = {
@Setting(name = AvailableSettings.USE_SQL_COMMENTS, value = "true"),
@Setting(name = AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, value = "true"),
@Setting(name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false"),
},
useCollectingStatementInspector = true
)

View File

@ -32,7 +32,8 @@ import static org.junit.Assert.assertTrue;
annotatedClasses = { InClauseParameterPaddingTest.Person.class },
integrationSettings = {
@Setting(name = AvailableSettings.USE_SQL_COMMENTS, value = "true"),
@Setting(name = AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, value = "true")
@Setting(name = AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, value = "true"),
@Setting(name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false")
},
useCollectingStatementInspector = true
)

View File

@ -37,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
integrationSettings = {
@Setting(name = AvailableSettings.USE_SQL_COMMENTS, value = "true"),
@Setting(name = AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, value = "true"),
@Setting(name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false"),
},
settingProviders ={
@SettingProvider(