HHH-16284 - Rename JdbcParameterRender to ParameterMarkerStrategy
This commit is contained in:
parent
f45dcf4c2f
commit
b276128f56
|
@ -19,7 +19,8 @@ ext {
|
||||||
'jdbc.user' : 'sa',
|
'jdbc.user' : 'sa',
|
||||||
'jdbc.pass' : '',
|
'jdbc.pass' : '',
|
||||||
'jdbc.url' : 'jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=10000',
|
'jdbc.url' : 'jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=10000',
|
||||||
'connection.init_sql' : ''
|
'connection.init_sql' : '',
|
||||||
|
'hibernate.dialect.native_param_markers' : 'true'
|
||||||
],
|
],
|
||||||
hsqldb : [
|
hsqldb : [
|
||||||
'db.dialect' : 'org.hibernate.dialect.HSQLDialect',
|
'db.dialect' : 'org.hibernate.dialect.HSQLDialect',
|
||||||
|
@ -250,4 +251,4 @@ if ( processTestResourcesTask != null ) {
|
||||||
// processTestResourcesTask.inputs.property( "gradle.libs.versions.hsqldb", project.getProperty( "gradle.libs.versions.hsqldb", "2.7.1" ) )
|
// processTestResourcesTask.inputs.property( "gradle.libs.versions.hsqldb", project.getProperty( "gradle.libs.versions.hsqldb", "2.7.1" ) )
|
||||||
// processTestResourcesTask.inputs.property( "gradle.libs.versions.derby", project.getProperty( "gradle.libs.versions.derby", "10.15.2.0" ) )
|
// processTestResourcesTask.inputs.property( "gradle.libs.versions.derby", project.getProperty( "gradle.libs.versions.derby", "10.15.2.0" ) )
|
||||||
processTestResourcesTask.filter( ReplaceTokens, tokens: dbBundle[db] )
|
processTestResourcesTask.filter( ReplaceTokens, tokens: dbBundle[db] )
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableSt
|
||||||
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy;
|
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy;
|
||||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||||
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.CriteriaDelete;
|
import jakarta.persistence.criteria.CriteriaDelete;
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
@ -2789,13 +2790,15 @@ public interface AvailableSettings {
|
||||||
String TIMEZONE_DEFAULT_STORAGE = "hibernate.timezone.default_storage";
|
String TIMEZONE_DEFAULT_STORAGE = "hibernate.timezone.default_storage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls whether to use JDBC parameter markers (`?`) or dialect native markers.
|
* Controls whether to use JDBC markers (`?`) or dialect native markers for parameters
|
||||||
|
* within {@linkplain java.sql.PreparedStatement preparable} SQL statements.
|
||||||
*
|
*
|
||||||
* @implNote By default ({@code true}), dialect native markers are used, if any; disable
|
* @implNote {@code False} by default, indicating standard JDBC parameter markers (`?`)
|
||||||
* ({@code false}) to use the standard JDBC parameter markers (`?`) instead
|
* are used. Set to {@code true} to use the Dialect's native markers, if any. For
|
||||||
|
* Dialects without native markers, the standard JDBC strategy is used.
|
||||||
*
|
*
|
||||||
* @see org.hibernate.sql.ast.spi.JdbcParameterRenderer
|
* @see ParameterMarkerStrategy
|
||||||
* @see org.hibernate.dialect.Dialect#getNativeParameterRenderer()
|
* @see org.hibernate.dialect.Dialect#getNativeParameterMarkerStrategy()
|
||||||
*
|
*
|
||||||
* @since 6.2
|
* @since 6.2
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -144,8 +144,8 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||||
import org.hibernate.sql.ForUpdateFragment;
|
import org.hibernate.sql.ForUpdateFragment;
|
||||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.internal.JdbcParameterRendererStandard;
|
import org.hibernate.sql.ast.internal.ParameterMarkerStrategyStandard;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
||||||
import org.hibernate.sql.model.MutationOperation;
|
import org.hibernate.sql.model.MutationOperation;
|
||||||
|
@ -4815,10 +4815,15 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for native parameter rendering
|
* Support for native parameter markers.
|
||||||
|
* <p/>
|
||||||
|
* This is generally dependent on both the database and the driver.
|
||||||
|
*
|
||||||
|
* @return May return {@code null} to indicate that the JDBC
|
||||||
|
* {@linkplain ParameterMarkerStrategyStandard standard} strategy should be used
|
||||||
*/
|
*/
|
||||||
public JdbcParameterRenderer getNativeParameterRenderer() {
|
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||||
return JdbcParameterRendererStandard.INSTANCE;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,7 +75,7 @@ import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
import org.hibernate.sql.model.MutationOperation;
|
import org.hibernate.sql.model.MutationOperation;
|
||||||
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
||||||
|
@ -193,8 +193,8 @@ public class DialectDelegateWrapper extends Dialect {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JdbcParameterRenderer getNativeParameterRenderer() {
|
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||||
return wrapped.getNativeParameterRenderer();
|
return wrapped.getNativeParameterMarkerStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -57,7 +57,7 @@ import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.tree.Statement;
|
import org.hibernate.sql.ast.tree.Statement;
|
||||||
|
@ -910,18 +910,18 @@ public class H2Dialect extends Dialect {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JdbcParameterRenderer getNativeParameterRenderer() {
|
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||||
return OrdinalParameterRenderer.INSTANCE;
|
return OrdinalParameterMarkerStrategy.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class OrdinalParameterRenderer implements JdbcParameterRenderer {
|
public static class OrdinalParameterMarkerStrategy implements ParameterMarkerStrategy {
|
||||||
/**
|
/**
|
||||||
* Singleton access
|
* Singleton access
|
||||||
*/
|
*/
|
||||||
public static final OrdinalParameterRenderer INSTANCE = new OrdinalParameterRenderer();
|
public static final OrdinalParameterMarkerStrategy INSTANCE = new OrdinalParameterMarkerStrategy();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String renderJdbcParameter(int position, JdbcType jdbcType) {
|
public String createMarker(int position, JdbcType jdbcType) {
|
||||||
return "?" + position;
|
return "?" + position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.tree.Statement;
|
import org.hibernate.sql.ast.tree.Statement;
|
||||||
|
@ -145,7 +145,7 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
|
|
||||||
protected final PostgreSQLDriverKind driverKind;
|
protected final PostgreSQLDriverKind driverKind;
|
||||||
private final OptionalTableUpdateStrategy optionalTableUpdateStrategy;
|
private final OptionalTableUpdateStrategy optionalTableUpdateStrategy;
|
||||||
private final JdbcParameterRenderer parameterRenderer;
|
private final ParameterMarkerStrategy parameterRenderer;
|
||||||
|
|
||||||
public PostgreSQLDialect() {
|
public PostgreSQLDialect() {
|
||||||
this( MINIMUM_VERSION );
|
this( MINIMUM_VERSION );
|
||||||
|
@ -166,7 +166,7 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
this.optionalTableUpdateStrategy = determineOptionalTableUpdateStrategy( version );
|
this.optionalTableUpdateStrategy = determineOptionalTableUpdateStrategy( version );
|
||||||
this.parameterRenderer = driverKind == PostgreSQLDriverKind.VERT_X
|
this.parameterRenderer = driverKind == PostgreSQLDriverKind.VERT_X
|
||||||
? NativeParameterMarkers.INSTANCE
|
? NativeParameterMarkers.INSTANCE
|
||||||
: super.getNativeParameterRenderer();
|
: super.getNativeParameterMarkerStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OptionalTableUpdateStrategy determineOptionalTableUpdateStrategy(DatabaseVersion version) {
|
private static OptionalTableUpdateStrategy determineOptionalTableUpdateStrategy(DatabaseVersion version) {
|
||||||
|
@ -1433,18 +1433,18 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JdbcParameterRenderer getNativeParameterRenderer() {
|
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||||
return parameterRenderer;
|
return parameterRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NativeParameterMarkers implements JdbcParameterRenderer {
|
private static class NativeParameterMarkers implements ParameterMarkerStrategy {
|
||||||
/**
|
/**
|
||||||
* Singleton access
|
* Singleton access
|
||||||
*/
|
*/
|
||||||
public static final NativeParameterMarkers INSTANCE = new NativeParameterMarkers();
|
public static final NativeParameterMarkers INSTANCE = new NativeParameterMarkers();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String renderJdbcParameter(int position, JdbcType jdbcType) {
|
public String createMarker(int position, JdbcType jdbcType) {
|
||||||
return "$" + position;
|
return "$" + position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6129,7 +6129,7 @@ public abstract class AbstractEntityPersister
|
||||||
delete.addColumnRestriction( propertyColumnNames[k] );
|
delete.addColumnRestriction( propertyColumnNames[k] );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
delete.addColumnNullnessRestriction( propertyColumnNames[k] );
|
delete.addColumnIsNullRestriction( propertyColumnNames[k] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,7 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
jdbcParameterBindings = new JdbcParameterBindingsImpl(
|
||||||
|
|
||||||
jdbcParameterBindings.registerNativeQueryParameters(
|
|
||||||
queryParameterBindings,
|
queryParameterBindings,
|
||||||
parameterList,
|
parameterList,
|
||||||
jdbcParameterBinders,
|
jdbcParameterBinders,
|
||||||
|
|
|
@ -79,9 +79,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
jdbcParameterBindings = new JdbcParameterBindingsImpl(
|
||||||
|
|
||||||
jdbcParameterBindings.registerNativeQueryParameters(
|
|
||||||
queryParameterBindings,
|
queryParameterBindings,
|
||||||
parameterList,
|
parameterList,
|
||||||
jdbcParameterBinders,
|
jdbcParameterBinders,
|
||||||
|
@ -95,8 +93,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
sql,
|
sql,
|
||||||
jdbcParameterBinders,
|
jdbcParameterBinders,
|
||||||
resultSetMapping,
|
resultSetMapping,
|
||||||
affectedTableNames,
|
affectedTableNames
|
||||||
Collections.emptySet()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||||
|
@ -116,6 +113,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
@Override
|
@Override
|
||||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, DomainQueryExecutionContext executionContext) {
|
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, DomainQueryExecutionContext executionContext) {
|
||||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||||
|
//noinspection unchecked
|
||||||
return EmptyScrollableResults.INSTANCE;
|
return EmptyScrollableResults.INSTANCE;
|
||||||
}
|
}
|
||||||
final List<JdbcParameterBinder> jdbcParameterBinders;
|
final List<JdbcParameterBinder> jdbcParameterBinders;
|
||||||
|
@ -128,9 +126,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
jdbcParameterBindings = new JdbcParameterBindingsImpl(
|
||||||
|
|
||||||
jdbcParameterBindings.registerNativeQueryParameters(
|
|
||||||
queryParameterBindings,
|
queryParameterBindings,
|
||||||
parameterList,
|
parameterList,
|
||||||
jdbcParameterBinders,
|
jdbcParameterBinders,
|
||||||
|
@ -142,8 +138,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
sql,
|
sql,
|
||||||
jdbcParameterBinders,
|
jdbcParameterBinders,
|
||||||
resultSetMapping,
|
resultSetMapping,
|
||||||
affectedTableNames,
|
affectedTableNames
|
||||||
Collections.emptySet()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return executionContext.getSession().getJdbcServices().getJdbcSelectExecutor().scroll(
|
return executionContext.getSession().getJdbcServices().getJdbcSelectExecutor().scroll(
|
||||||
|
|
|
@ -38,7 +38,7 @@ import org.hibernate.query.sqm.mutation.internal.SqmMultiTableMutationStrategyPr
|
||||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistryInitiator;
|
import org.hibernate.resource.beans.spi.ManagedBeanRegistryInitiator;
|
||||||
import org.hibernate.resource.transaction.internal.TransactionCoordinatorBuilderInitiator;
|
import org.hibernate.resource.transaction.internal.TransactionCoordinatorBuilderInitiator;
|
||||||
import org.hibernate.service.internal.SessionFactoryServiceRegistryFactoryInitiator;
|
import org.hibernate.service.internal.SessionFactoryServiceRegistryFactoryInitiator;
|
||||||
import org.hibernate.sql.ast.internal.JdbcParameterRendererInitiator;
|
import org.hibernate.sql.ast.internal.ParameterMarkerStrategyInitiator;
|
||||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerProviderInitiator;
|
import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerProviderInitiator;
|
||||||
import org.hibernate.tool.schema.internal.SchemaManagementToolInitiator;
|
import org.hibernate.tool.schema.internal.SchemaManagementToolInitiator;
|
||||||
import org.hibernate.tool.schema.internal.script.SqlScriptExtractorInitiator;
|
import org.hibernate.tool.schema.internal.script.SqlScriptExtractorInitiator;
|
||||||
|
@ -152,8 +152,8 @@ public final class StandardServiceInitiators {
|
||||||
// SqmMultiTableMutationStrategyProvider
|
// SqmMultiTableMutationStrategyProvider
|
||||||
serviceInitiators.add( SqmMultiTableMutationStrategyProviderInitiator.INSTANCE );
|
serviceInitiators.add( SqmMultiTableMutationStrategyProviderInitiator.INSTANCE );
|
||||||
|
|
||||||
// JdbcParameterRenderer
|
// ParameterMarkerStrategy
|
||||||
serviceInitiators.add( JdbcParameterRendererInitiator.INSTANCE );
|
serviceInitiators.add( ParameterMarkerStrategyInitiator.INSTANCE );
|
||||||
|
|
||||||
serviceInitiators.trimToSize();
|
serviceInitiators.trimToSize();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.hibernate.Internal;
|
||||||
@Internal
|
@Internal
|
||||||
public class ComparisonRestriction implements Restriction {
|
public class ComparisonRestriction implements Restriction {
|
||||||
private final String lhs;
|
private final String lhs;
|
||||||
private final String operator;
|
private final Operator operator;
|
||||||
private final String rhs;
|
private final String rhs;
|
||||||
|
|
||||||
public ComparisonRestriction(String lhs) {
|
public ComparisonRestriction(String lhs) {
|
||||||
|
@ -24,10 +24,10 @@ public class ComparisonRestriction implements Restriction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComparisonRestriction(String lhs, String rhs) {
|
public ComparisonRestriction(String lhs, String rhs) {
|
||||||
this( lhs, "=", rhs );
|
this( lhs, Operator.EQ, rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComparisonRestriction(String lhs, String operator, String rhs) {
|
public ComparisonRestriction(String lhs, Operator operator, String rhs) {
|
||||||
this.lhs = lhs;
|
this.lhs = lhs;
|
||||||
this.operator = operator;
|
this.operator = operator;
|
||||||
this.rhs = rhs;
|
this.rhs = rhs;
|
||||||
|
@ -36,7 +36,7 @@ public class ComparisonRestriction implements Restriction {
|
||||||
@Override
|
@Override
|
||||||
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
|
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
|
||||||
sqlBuffer.append( lhs );
|
sqlBuffer.append( lhs );
|
||||||
sqlBuffer.append( operator );
|
sqlBuffer.append( operator.getSqlText() );
|
||||||
|
|
||||||
if ( "?".equals( rhs ) ) {
|
if ( "?".equals( rhs ) ) {
|
||||||
sqlBuffer.append( context.makeParameterMarker() );
|
sqlBuffer.append( context.makeParameterMarker() );
|
||||||
|
@ -45,4 +45,20 @@ public class ComparisonRestriction implements Restriction {
|
||||||
sqlBuffer.append( rhs );
|
sqlBuffer.append( rhs );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Operator {
|
||||||
|
EQ( "=" ),
|
||||||
|
NE( "<>" )
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String sqlText;
|
||||||
|
|
||||||
|
Operator(String sqlText) {
|
||||||
|
this.sqlText = sqlText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSqlText() {
|
||||||
|
return sqlText;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,14 @@
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql;
|
package org.hibernate.sql;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.hibernate.Internal;
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A SQL {@code DELETE} statement.
|
* A SQL {@code DELETE} statement.
|
||||||
|
@ -22,24 +20,20 @@ import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public class Delete {
|
public class Delete implements RestrictionRenderingContext {
|
||||||
|
|
||||||
protected String tableName;
|
protected String tableName;
|
||||||
protected String comment;
|
protected String comment;
|
||||||
|
protected final List<Restriction> restrictions = new ArrayList<>();
|
||||||
|
|
||||||
protected final List<String> whereFragments = new ArrayList<>();
|
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||||
|
|
||||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
|
||||||
private final boolean standardParamRendering;
|
|
||||||
private int parameterCount;
|
private int parameterCount;
|
||||||
|
|
||||||
public Delete(SessionFactoryImplementor factory) {
|
public Delete(SessionFactoryImplementor factory) {
|
||||||
this( factory.getServiceRegistry().getService( JdbcParameterRenderer.class ) );
|
this( factory.getServiceRegistry().getService( ParameterMarkerStrategy.class ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Delete(JdbcParameterRenderer jdbcParameterRenderer) {
|
public Delete(ParameterMarkerStrategy parameterMarkerStrategy) {
|
||||||
this.jdbcParameterRenderer = jdbcParameterRenderer;
|
this.parameterMarkerStrategy = parameterMarkerStrategy;
|
||||||
this.standardParamRendering = JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Delete setTableName(String tableName) {
|
public Delete setTableName(String tableName) {
|
||||||
|
@ -54,8 +48,7 @@ public class Delete {
|
||||||
|
|
||||||
@SuppressWarnings("UnusedReturnValue")
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
public Delete addColumnRestriction(String columnName) {
|
public Delete addColumnRestriction(String columnName) {
|
||||||
final String paramMarker = jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null );
|
restrictions.add( new ComparisonRestriction( columnName ) );
|
||||||
this.whereFragments.add( columnName + "=" + paramMarker );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,17 +64,14 @@ public class Delete {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UnusedReturnValue")
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
public Delete addColumnNullnessRestriction(String columnName) {
|
public Delete addColumnIsNullRestriction(String columnName) {
|
||||||
addColumnNullnessRestriction( columnName, false );
|
restrictions.add( new NullnessRestriction( columnName ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UnusedReturnValue")
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
public Delete addColumnNullnessRestriction(String columnName, boolean negate) {
|
public Delete addColumnIsNotNullRestriction(String columnName) {
|
||||||
final String fragment = negate
|
restrictions.add( new NullnessRestriction( columnName, false ) );
|
||||||
? columnName + " is not null"
|
|
||||||
: columnName + " is null";
|
|
||||||
whereFragments.add( fragment );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,25 +92,29 @@ public class Delete {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyRestrictions(StringBuilder buf) {
|
|
||||||
if ( whereFragments.isEmpty() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.append( " where " );
|
|
||||||
|
|
||||||
for ( int i = 0; i < whereFragments.size(); i++ ) {
|
|
||||||
if ( i > 0 ) {
|
|
||||||
buf.append( " and " );
|
|
||||||
}
|
|
||||||
buf.append( whereFragments.get(i) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyComment(StringBuilder buf) {
|
private void applyComment(StringBuilder buf) {
|
||||||
if ( comment != null ) {
|
if ( comment != null ) {
|
||||||
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
|
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyRestrictions(StringBuilder buf) {
|
||||||
|
if ( restrictions.isEmpty() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.append( " where " );
|
||||||
|
|
||||||
|
for ( int i = 0; i < restrictions.size(); i++ ) {
|
||||||
|
if ( i > 0 ) {
|
||||||
|
buf.append( " and " );
|
||||||
|
}
|
||||||
|
restrictions.get( i ).render( buf, this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String makeParameterMarker() {
|
||||||
|
return parameterMarkerStrategy.createMarker( ++parameterCount, null );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,8 @@ import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.generator.OnExecutionGenerator;
|
import org.hibernate.generator.OnExecutionGenerator;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
|
||||||
import static org.hibernate.sql.ast.spi.JdbcParameterRenderer.isStandardRenderer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A SQL {@code INSERT} statement.
|
* A SQL {@code INSERT} statement.
|
||||||
|
@ -34,21 +33,19 @@ public class Insert {
|
||||||
protected Map<String,String> columns = new LinkedHashMap<>();
|
protected Map<String,String> columns = new LinkedHashMap<>();
|
||||||
|
|
||||||
private final Dialect dialect;
|
private final Dialect dialect;
|
||||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||||
private final boolean standardParamRendering;
|
|
||||||
private int parameterCount;
|
private int parameterCount;
|
||||||
|
|
||||||
public Insert(SessionFactoryImplementor sessionFactory) {
|
public Insert(SessionFactoryImplementor sessionFactory) {
|
||||||
this(
|
this(
|
||||||
sessionFactory.getJdbcServices().getDialect(),
|
sessionFactory.getJdbcServices().getDialect(),
|
||||||
sessionFactory.getServiceRegistry().getService( JdbcParameterRenderer.class )
|
sessionFactory.getServiceRegistry().getService( ParameterMarkerStrategy.class )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Insert(Dialect dialect, JdbcParameterRenderer jdbcParameterRenderer) {
|
public Insert(Dialect dialect, ParameterMarkerStrategy parameterMarkerStrategy) {
|
||||||
this.dialect = dialect;
|
this.dialect = dialect;
|
||||||
this.jdbcParameterRenderer = jdbcParameterRenderer;
|
this.parameterMarkerStrategy = parameterMarkerStrategy;
|
||||||
this.standardParamRendering = isStandardRenderer( jdbcParameterRenderer );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Dialect getDialect() {
|
protected Dialect getDialect() {
|
||||||
|
@ -179,8 +176,8 @@ public class Insert {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String normalizeExpressionFragment(String rhs) {
|
private String normalizeExpressionFragment(String rhs) {
|
||||||
return rhs.equals( "?" ) && !standardParamRendering
|
return rhs.equals( "?" )
|
||||||
? jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null )
|
? parameterMarkerStrategy.createMarker( ++parameterCount, null )
|
||||||
: rhs;
|
: rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,32 +9,32 @@ package org.hibernate.sql;
|
||||||
import org.hibernate.Internal;
|
import org.hibernate.Internal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nullness restriction - is [not] null
|
* Nullness restriction - IS (NOT)? NULL
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public class NullnessRestriction implements Restriction {
|
public class NullnessRestriction implements Restriction {
|
||||||
private final String columnName;
|
private final String columnName;
|
||||||
private final boolean negated;
|
private final boolean affirmative;
|
||||||
|
|
||||||
public NullnessRestriction(String columnName) {
|
public NullnessRestriction(String columnName) {
|
||||||
this( columnName, false );
|
this( columnName, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
public NullnessRestriction(String columnName, boolean negated) {
|
public NullnessRestriction(String columnName, boolean affirmative) {
|
||||||
this.columnName = columnName;
|
this.columnName = columnName;
|
||||||
this.negated = negated;
|
this.affirmative = affirmative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
|
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
|
||||||
sqlBuffer.append( columnName );
|
sqlBuffer.append( columnName );
|
||||||
if ( negated ) {
|
if ( affirmative ) {
|
||||||
sqlBuffer.append( " is not null" );
|
sqlBuffer.append( " is null" );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sqlBuffer.append( " is null" );
|
sqlBuffer.append( " is not null" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A SQL {@code SELECT} statement with no table joins.
|
* A SQL {@code SELECT} statement with no table joins.
|
||||||
|
@ -37,20 +37,18 @@ public class SimpleSelect implements RestrictionRenderingContext {
|
||||||
|
|
||||||
protected LockOptions lockOptions = new LockOptions( LockMode.READ );
|
protected LockOptions lockOptions = new LockOptions( LockMode.READ );
|
||||||
|
|
||||||
private final SessionFactoryImplementor factory;
|
|
||||||
private final Dialect dialect;
|
private final Dialect dialect;
|
||||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||||
private int parameterCount;
|
private int parameterCount;
|
||||||
|
|
||||||
public SimpleSelect(SessionFactoryImplementor factory) {
|
public SimpleSelect(SessionFactoryImplementor factory) {
|
||||||
this.factory = factory;
|
|
||||||
this.dialect = factory.getJdbcServices().getDialect();
|
this.dialect = factory.getJdbcServices().getDialect();
|
||||||
this.jdbcParameterRenderer = factory.getServiceRegistry().getService( JdbcParameterRenderer.class );
|
this.parameterMarkerStrategy = factory.getServiceRegistry().getService( ParameterMarkerStrategy.class );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String makeParameterMarker() {
|
public String makeParameterMarker() {
|
||||||
return jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null );
|
return parameterMarkerStrategy.createMarker( ++parameterCount, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,7 +102,7 @@ public class SimpleSelect implements RestrictionRenderingContext {
|
||||||
/**
|
/**
|
||||||
* Appends a restriction comparing the {@code columnName} for equality with a parameter
|
* Appends a restriction comparing the {@code columnName} for equality with a parameter
|
||||||
*
|
*
|
||||||
* @see #addRestriction(String, String, String)
|
* @see #addRestriction(String, ComparisonRestriction.Operator, String)
|
||||||
*/
|
*/
|
||||||
public SimpleSelect addRestriction(String columnName) {
|
public SimpleSelect addRestriction(String columnName) {
|
||||||
restrictions.add( new ComparisonRestriction( columnName ) );
|
restrictions.add( new ComparisonRestriction( columnName ) );
|
||||||
|
@ -114,10 +112,10 @@ public class SimpleSelect implements RestrictionRenderingContext {
|
||||||
/**
|
/**
|
||||||
* Appends a restriction based on the comparison between {@code lhs} and {@code rhs}.
|
* Appends a restriction based on the comparison between {@code lhs} and {@code rhs}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The {@code rhs} is checked for parameter marker and processed via {@link JdbcParameterRenderer}
|
* The {@code rhs} is checked for parameter marker and processed via {@link ParameterMarkerStrategy}
|
||||||
* if needed.
|
* if needed.
|
||||||
*/
|
*/
|
||||||
public SimpleSelect addRestriction(String lhs, String op, String rhs) {
|
public SimpleSelect addRestriction(String lhs, ComparisonRestriction.Operator op, String rhs) {
|
||||||
restrictions.add( new ComparisonRestriction( lhs, op, rhs ) );
|
restrictions.add( new ComparisonRestriction( lhs, op, rhs ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import java.util.Map;
|
||||||
import org.hibernate.Internal;
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A SQL {@code UPDATE} statement.
|
* A SQL {@code UPDATE} statement.
|
||||||
|
@ -28,17 +28,15 @@ public class Update implements RestrictionRenderingContext {
|
||||||
protected Map<String,String> assignments = new LinkedHashMap<>();
|
protected Map<String,String> assignments = new LinkedHashMap<>();
|
||||||
protected List<Restriction> restrictions = new ArrayList<>();
|
protected List<Restriction> restrictions = new ArrayList<>();
|
||||||
|
|
||||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||||
private final boolean standardParamRendering;
|
|
||||||
private int parameterCount;
|
private int parameterCount;
|
||||||
|
|
||||||
public Update(SessionFactoryImplementor factory) {
|
public Update(SessionFactoryImplementor factory) {
|
||||||
this( factory.getServiceRegistry().getService( JdbcParameterRenderer.class ) );
|
this( factory.getServiceRegistry().getService( ParameterMarkerStrategy.class ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Update(JdbcParameterRenderer jdbcParameterRenderer) {
|
public Update(ParameterMarkerStrategy parameterMarkerStrategy) {
|
||||||
this.jdbcParameterRenderer = jdbcParameterRenderer;
|
this.parameterMarkerStrategy = parameterMarkerStrategy;
|
||||||
this.standardParamRendering = JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTableName() {
|
public String getTableName() {
|
||||||
|
@ -91,19 +89,26 @@ public class Update implements RestrictionRenderingContext {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Update addRestriction(String column, String op, String value) {
|
public Update addRestriction(String column, ComparisonRestriction.Operator op, String value) {
|
||||||
restrictions.add( new ComparisonRestriction( column, op, value ) );
|
restrictions.add( new ComparisonRestriction( column, op, value ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String normalizeExpressionFragment(String rhs) {
|
private String normalizeExpressionFragment(String rhs) {
|
||||||
return rhs.equals( "?" ) && !standardParamRendering
|
return rhs.equals( "?" )
|
||||||
? jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null )
|
? parameterMarkerStrategy.createMarker( ++parameterCount, null )
|
||||||
: rhs;
|
: rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Update addNullnessRestriction(String column) {
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
restrictions.add( new NullnessRestriction( column ) );
|
public Update addColumnIsNullRestriction(String columnName) {
|
||||||
|
restrictions.add( new NullnessRestriction( columnName ) );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
|
public Update addColumnIsNotNullRestriction(String columnName) {
|
||||||
|
restrictions.add( new NullnessRestriction( columnName, false ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +163,6 @@ public class Update implements RestrictionRenderingContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String makeParameterMarker() {
|
public String makeParameterMarker() {
|
||||||
return jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null );
|
return parameterMarkerStrategy.createMarker( ++parameterCount, null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +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.sql.ast.internal;
|
|
||||||
|
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
|
||||||
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 String renderJdbcParameter(int position, JdbcType jdbcType) {
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,35 +14,39 @@ import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class JdbcParameterRendererInitiator implements StandardServiceInitiator<JdbcParameterRenderer> {
|
public class ParameterMarkerStrategyInitiator implements StandardServiceInitiator<ParameterMarkerStrategy> {
|
||||||
/**
|
/**
|
||||||
* Singleton access
|
* Singleton access
|
||||||
*/
|
*/
|
||||||
public static final JdbcParameterRendererInitiator INSTANCE = new JdbcParameterRendererInitiator();
|
public static final ParameterMarkerStrategyInitiator INSTANCE = new ParameterMarkerStrategyInitiator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JdbcParameterRenderer initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
public ParameterMarkerStrategy initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||||
final boolean useNativeMarkers = ConfigurationHelper.getBoolean(
|
final boolean useNativeMarkers = ConfigurationHelper.getBoolean(
|
||||||
AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS,
|
AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS,
|
||||||
configurationValues,
|
configurationValues,
|
||||||
true
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( useNativeMarkers ) {
|
if ( useNativeMarkers ) {
|
||||||
final Dialect dialect = registry.getService( JdbcServices.class ).getDialect();
|
final Dialect dialect = registry.getService( JdbcServices.class ).getDialect();
|
||||||
return dialect.getNativeParameterRenderer();
|
final ParameterMarkerStrategy nativeParameterMarkerStrategy = dialect.getNativeParameterMarkerStrategy();
|
||||||
|
// the Dialect may return `null`, indicating falling-through to the standard strategy
|
||||||
|
if ( nativeParameterMarkerStrategy != null ) {
|
||||||
|
return nativeParameterMarkerStrategy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return JdbcParameterRendererStandard.INSTANCE;
|
return ParameterMarkerStrategyStandard.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<JdbcParameterRenderer> getServiceInitiated() {
|
public Class<ParameterMarkerStrategy> getServiceInitiated() {
|
||||||
return JdbcParameterRenderer.class;
|
return ParameterMarkerStrategy.class;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The standard ParameterMarkerStrategy based on the standard JDBC {@code ?} marker
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ParameterMarkerStrategyStandard implements ParameterMarkerStrategy {
|
||||||
|
/**
|
||||||
|
* Singleton access
|
||||||
|
*/
|
||||||
|
public static final ParameterMarkerStrategyStandard INSTANCE = new ParameterMarkerStrategyStandard();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createMarker(int position, JdbcType jdbcType) {
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStandardRenderer(ParameterMarkerStrategy check) {
|
||||||
|
return check == null || ParameterMarkerStrategyStandard.class.equals( check.getClass() );
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,7 @@ import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||||
import org.hibernate.sql.ast.SqlTreeCreationException;
|
import org.hibernate.sql.ast.SqlTreeCreationException;
|
||||||
|
import org.hibernate.sql.ast.internal.ParameterMarkerStrategyStandard;
|
||||||
import org.hibernate.sql.ast.tree.MutationStatement;
|
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||||
import org.hibernate.sql.ast.tree.Statement;
|
import org.hibernate.sql.ast.tree.Statement;
|
||||||
|
@ -273,7 +274,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
||||||
private JdbcParameterBindings jdbcParameterBindings;
|
private JdbcParameterBindings jdbcParameterBindings;
|
||||||
private Map<JdbcParameter, JdbcParameterBinding> appliedParameterBindings = Collections.emptyMap();
|
private Map<JdbcParameter, JdbcParameterBinding> appliedParameterBindings = Collections.emptyMap();
|
||||||
private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||||
|
|
||||||
|
|
||||||
private final Stack<Clause> clauseStack = new StandardStack<>( Clause.class );
|
private final Stack<Clause> clauseStack = new StandardStack<>( Clause.class );
|
||||||
|
@ -317,7 +318,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
||||||
this.sessionFactory = sessionFactory;
|
this.sessionFactory = sessionFactory;
|
||||||
this.dialect = sessionFactory.getJdbcServices().getDialect();
|
this.dialect = sessionFactory.getJdbcServices().getDialect();
|
||||||
this.statementStack.push( statement );
|
this.statementStack.push( statement );
|
||||||
this.jdbcParameterRenderer = sessionFactory.getServiceRegistry().getService( JdbcParameterRenderer.class );
|
this.parameterMarkerStrategy = sessionFactory.getServiceRegistry().getService( ParameterMarkerStrategy.class );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Clause matchWithClause(Clause clause) {
|
private static Clause matchWithClause(Clause clause) {
|
||||||
|
@ -5073,8 +5074,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
||||||
// If we encounter a plain literal in the select clause which has no literal formatter, we must render it as parameter
|
// If we encounter a plain literal in the select clause which has no literal formatter, we must render it as parameter
|
||||||
if ( literalFormatter == null ) {
|
if ( literalFormatter == null ) {
|
||||||
parameterBinders.add( literal );
|
parameterBinders.add( literal );
|
||||||
|
final String marker = parameterMarkerStrategy.createMarker( parameterBinders.size(), literal.getJdbcMapping().getJdbcType() );
|
||||||
final LiteralAsParameter<Object> jdbcParameter = new LiteralAsParameter<>( literal );
|
final LiteralAsParameter<Object> jdbcParameter = new LiteralAsParameter<>( literal, marker );
|
||||||
if ( castParameter ) {
|
if ( castParameter ) {
|
||||||
renderCasted( jdbcParameter );
|
renderCasted( jdbcParameter );
|
||||||
}
|
}
|
||||||
|
@ -6187,14 +6188,21 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
||||||
jdbcParameters.addParameter( jdbcParameter );
|
jdbcParameters.addParameter( jdbcParameter );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void renderParameterAsParameter(JdbcParameter jdbcParameter) {
|
protected final void renderParameterAsParameter(JdbcParameter jdbcParameter) {
|
||||||
renderParameterAsParameter( jdbcParameter, parameterBinders.size() + 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void renderParameterAsParameter(JdbcParameter jdbcParameter, int position) {
|
|
||||||
final JdbcType jdbcType = jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType();
|
final JdbcType jdbcType = jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType();
|
||||||
assert jdbcType != null;
|
assert jdbcType != null;
|
||||||
final String parameterMarker = jdbcParameterRenderer.renderJdbcParameter( position, jdbcType );
|
renderParameterAsParameter( parameterBinders.size() + 1, jdbcParameter );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a parameter marker for the given position
|
||||||
|
* @param jdbcParameter
|
||||||
|
* @param position
|
||||||
|
*/
|
||||||
|
protected void renderParameterAsParameter(int position, JdbcParameter jdbcParameter) {
|
||||||
|
final JdbcType jdbcType = jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType();
|
||||||
|
assert jdbcType != null;
|
||||||
|
final String parameterMarker = parameterMarkerStrategy.createMarker( position, jdbcType );
|
||||||
jdbcType.appendWriteExpression( parameterMarker, this, dialect );
|
jdbcType.appendWriteExpression( parameterMarker, this, dialect );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8018,7 +8026,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
||||||
// if there are no parameters or if we are using the standard parameter renderer
|
// if there are no parameters or if we are using the standard parameter renderer
|
||||||
// - the rendering is pretty simple
|
// - the rendering is pretty simple
|
||||||
if ( CollectionHelper.isEmpty( columnWriteFragment.getParameters() )
|
if ( CollectionHelper.isEmpty( columnWriteFragment.getParameters() )
|
||||||
|| JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer ) ) {
|
|| ParameterMarkerStrategyStandard.isStandardRenderer( parameterMarkerStrategy ) ) {
|
||||||
simpleColumnWriteFragmentRendering( columnWriteFragment );
|
simpleColumnWriteFragmentRendering( columnWriteFragment );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -8034,7 +8042,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
||||||
// to the index of the parameter marker
|
// to the index of the parameter marker
|
||||||
appendSql( sqlFragment.substring( lastEnd, markerStart ) );
|
appendSql( sqlFragment.substring( lastEnd, markerStart ) );
|
||||||
|
|
||||||
// render the parameter marker and register it
|
// render the parameter marker and register the parameter handling
|
||||||
visitParameterAsParameter( parameter );
|
visitParameterAsParameter( parameter );
|
||||||
|
|
||||||
lastEnd = markerStart + 1;
|
lastEnd = markerStart + 1;
|
||||||
|
|
|
@ -1,39 +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.sql.ast.spi;
|
|
||||||
|
|
||||||
import org.hibernate.service.Service;
|
|
||||||
import org.hibernate.sql.ast.internal.JdbcParameterRendererStandard;
|
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension point for rendering parameter markers.
|
|
||||||
* <p/>
|
|
||||||
* Generally Hibernate will use the JDBC standard marker - {@code ?}. Many
|
|
||||||
* databases support alternative marker syntax, often numbered.
|
|
||||||
* <p/>
|
|
||||||
* Originally developed as an extension point for use from Hibernate Reactive
|
|
||||||
* to handle the fact that some Vert.X drivers (ok, their PGSQL driver) only
|
|
||||||
* support native parameter marker syntax instead of the JDBC standard
|
|
||||||
*
|
|
||||||
* @see org.hibernate.cfg.AvailableSettings#DIALECT_NATIVE_PARAM_MARKERS
|
|
||||||
*
|
|
||||||
* @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, if known
|
|
||||||
*/
|
|
||||||
String renderJdbcParameter(int position, JdbcType jdbcType);
|
|
||||||
|
|
||||||
static boolean isStandardRenderer(JdbcParameterRenderer check) {
|
|
||||||
return check == null || JdbcParameterRendererStandard.class.equals( check.getClass() );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.spi;
|
||||||
|
|
||||||
|
import org.hibernate.service.Service;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strategy for generating parameter markers used in {@linkplain java.sql.PreparedStatement preparable} SQL strings.
|
||||||
|
* <p/>
|
||||||
|
* Generally Hibernate will use the JDBC standard marker - {@code ?}. Many JDBC drivers support the
|
||||||
|
* use of the "native" marker syntax of the underlying database - e.g. {@code $n}, {@code ?n}, ...
|
||||||
|
*
|
||||||
|
* @implNote Originally developed as an extension point for use from Hibernate Reactive
|
||||||
|
* for Vert.X PostgreSQL drivers which only support the native {@code $n} syntax.
|
||||||
|
*
|
||||||
|
* @see org.hibernate.cfg.AvailableSettings#DIALECT_NATIVE_PARAM_MARKERS
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface ParameterMarkerStrategy extends Service {
|
||||||
|
/**
|
||||||
|
* Create a parameter marker
|
||||||
|
*
|
||||||
|
* @param position The 1-based position of the parameter.
|
||||||
|
* @param jdbcType The type of the parameter, if known - may be {@code null}.
|
||||||
|
*/
|
||||||
|
String createMarker(int position, JdbcType jdbcType);
|
||||||
|
}
|
|
@ -19,16 +19,17 @@ import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
* @author Christian Beikov
|
* @author Christian Beikov
|
||||||
*/
|
*/
|
||||||
public class LiteralAsParameter<T> implements SelfRenderingExpression {
|
public class LiteralAsParameter<T> implements SelfRenderingExpression {
|
||||||
|
|
||||||
private final Literal literal;
|
private final Literal literal;
|
||||||
|
private final String parameterMarker;
|
||||||
|
|
||||||
public LiteralAsParameter(Literal literal) {
|
public LiteralAsParameter(Literal literal, String parameterMarker) {
|
||||||
this.literal = literal;
|
this.literal = literal;
|
||||||
|
this.parameterMarker = parameterMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderToSql(SqlAppender sqlAppender, SqlAstTranslator<?> walker, SessionFactoryImplementor sessionFactory) {
|
public void renderToSql(SqlAppender sqlAppender, SqlAstTranslator<?> walker, SessionFactoryImplementor sessionFactory) {
|
||||||
sqlAppender.appendSql( "?" );
|
sqlAppender.append( parameterMarker );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,12 +9,25 @@ package org.hibernate.sql.exec.internal;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
import org.hibernate.query.BindableType;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
|
import org.hibernate.query.sql.internal.NativeQueryImpl;
|
||||||
|
import org.hibernate.query.sql.spi.ParameterOccurrence;
|
||||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||||
|
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||||
|
import org.hibernate.type.BasicTypeReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard implementation of JdbcParameterBindings
|
* Standard implementation of JdbcParameterBindings
|
||||||
|
@ -30,6 +43,83 @@ public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JdbcParameterBindingsImpl(
|
||||||
|
QueryParameterBindings queryParameterBindings,
|
||||||
|
List<ParameterOccurrence> parameterOccurrences,
|
||||||
|
List<JdbcParameterBinder> jdbcParameterBinders,
|
||||||
|
SessionFactoryImplementor factory) {
|
||||||
|
if ( !parameterOccurrences.isEmpty() ) {
|
||||||
|
bindingMap = new IdentityHashMap<>( parameterOccurrences.size() );
|
||||||
|
|
||||||
|
final Dialect dialect = factory.getJdbcServices().getDialect();
|
||||||
|
final boolean paddingEnabled = factory.getSessionFactoryOptions().inClauseParameterPaddingEnabled();
|
||||||
|
final int inExprLimit = dialect.getInExpressionCountLimit();
|
||||||
|
|
||||||
|
for ( ParameterOccurrence occurrence : parameterOccurrences ) {
|
||||||
|
final QueryParameterImplementor<?> param = occurrence.getParameter();
|
||||||
|
final QueryParameterBinding<?> binding = queryParameterBindings.getBinding( param );
|
||||||
|
|
||||||
|
final JdbcMapping jdbcMapping;
|
||||||
|
|
||||||
|
final BindableType<?> type = determineParamType( param, binding );
|
||||||
|
if ( type == null ) {
|
||||||
|
jdbcMapping = factory.getTypeConfiguration().getBasicTypeForJavaType( Object.class );
|
||||||
|
}
|
||||||
|
else if ( type instanceof BasicTypeReference ) {
|
||||||
|
jdbcMapping = factory.getTypeConfiguration()
|
||||||
|
.getBasicTypeRegistry()
|
||||||
|
.resolve( ( (BasicTypeReference<?>) type ) );
|
||||||
|
}
|
||||||
|
else if ( type instanceof BasicValuedMapping ) {
|
||||||
|
jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException( "Could not resolve NativeQuery parameter type : `" + param + "`");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( binding.isMultiValued() ) {
|
||||||
|
final Collection<?> bindValues = binding.getBindValues();
|
||||||
|
final int bindValueCount = bindValues.size();
|
||||||
|
Object lastBindValue = null;
|
||||||
|
for ( Object bindValue : bindValues ) {
|
||||||
|
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||||
|
jdbcParameterBinders.add( jdbcParameter );
|
||||||
|
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, bindValue ) );
|
||||||
|
lastBindValue = bindValue;
|
||||||
|
}
|
||||||
|
final int bindValueMaxCount = NativeQueryImpl.determineBindValueMaxCount(
|
||||||
|
paddingEnabled,
|
||||||
|
inExprLimit,
|
||||||
|
bindValueCount
|
||||||
|
);
|
||||||
|
if ( bindValueMaxCount != bindValueCount ) {
|
||||||
|
for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) {
|
||||||
|
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||||
|
jdbcParameterBinders.add( jdbcParameter );
|
||||||
|
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||||
|
jdbcParameterBinders.add( jdbcParameter );
|
||||||
|
addBinding(
|
||||||
|
jdbcParameter,
|
||||||
|
new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BindableType<?> determineParamType(QueryParameterImplementor<?> param, QueryParameterBinding<?> binding) {
|
||||||
|
BindableType<?> type = binding.getBindType();
|
||||||
|
if ( type == null ) {
|
||||||
|
type = param.getHibernateType();
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBinding(JdbcParameter parameter, JdbcParameterBinding binding) {
|
public void addBinding(JdbcParameter parameter, JdbcParameterBinding binding) {
|
||||||
if ( bindingMap == null ) {
|
if ( bindingMap == null ) {
|
||||||
|
@ -47,7 +137,6 @@ public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
|
||||||
@Override
|
@Override
|
||||||
public JdbcParameterBinding getBinding(JdbcParameter parameter) {
|
public JdbcParameterBinding getBinding(JdbcParameter parameter) {
|
||||||
if ( bindingMap == null ) {
|
if ( bindingMap == null ) {
|
||||||
// no bindings
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return bindingMap.get( parameter );
|
return bindingMap.get( parameter );
|
||||||
|
@ -55,6 +144,9 @@ public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBindings(BiConsumer<JdbcParameter, JdbcParameterBinding> action) {
|
public void visitBindings(BiConsumer<JdbcParameter, JdbcParameterBinding> action) {
|
||||||
|
if ( bindingMap == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for ( Map.Entry<JdbcParameter, JdbcParameterBinding> entry : bindingMap.entrySet() ) {
|
for ( Map.Entry<JdbcParameter, JdbcParameterBinding> entry : bindingMap.entrySet() ) {
|
||||||
action.accept( entry.getKey(), entry.getValue() );
|
action.accept( entry.getKey(), entry.getValue() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,34 +11,24 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.Bindable;
|
import org.hibernate.metamodel.mapping.Bindable;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.query.BindableType;
|
|
||||||
import org.hibernate.query.internal.BindingTypeHelper;
|
import org.hibernate.query.internal.BindingTypeHelper;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
|
||||||
import org.hibernate.query.sql.internal.NativeQueryImpl;
|
|
||||||
import org.hibernate.query.sql.spi.ParameterOccurrence;
|
|
||||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
||||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
import org.hibernate.type.BasicTypeReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to all of the externalized JDBC parameter bindings
|
* Access to all the externalized JDBC parameter bindings
|
||||||
*
|
*
|
||||||
* @apiNote "Externalized" because some JDBC parameter values are
|
* @apiNote "Externalized" because some JDBC parameter values are
|
||||||
* intrinsically part of the parameter itself and we do not need to
|
* intrinsically part of the parameter itself, and we do not need to
|
||||||
* locate a JdbcParameterBinding. E.g., consider a
|
* locate a JdbcParameterBinding. E.g., consider a
|
||||||
* {@link org.hibernate.sql.ast.tree.expression.LiteralAsParameter}
|
* {@link org.hibernate.sql.ast.tree.expression.LiteralAsParameter}
|
||||||
* which actually encapsulates the actually literal value inside
|
* which encapsulates the literal value inside itself - to create the
|
||||||
* itself - to create the binder and actually perform the binding
|
* binder and actually perform the binding is only dependent on the
|
||||||
* is only dependent on the LiteralParameter
|
* LiteralParameter
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@ -90,94 +80,27 @@ public interface JdbcParameterBindings {
|
||||||
offset,
|
offset,
|
||||||
jdbcParameters,
|
jdbcParameters,
|
||||||
session.getFactory().getTypeConfiguration(),
|
session.getFactory().getTypeConfiguration(),
|
||||||
(selectionIndex, params, typeConfiguration, jdbcValue, type) -> {
|
this::createAndAddBinding,
|
||||||
addBinding(
|
|
||||||
params.get( selectionIndex ),
|
|
||||||
new JdbcParameterBindingImpl(
|
|
||||||
BindingTypeHelper.INSTANCE.resolveBindType(
|
|
||||||
jdbcValue,
|
|
||||||
type,
|
|
||||||
typeConfiguration
|
|
||||||
),
|
|
||||||
jdbcValue
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
,
|
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
default void registerNativeQueryParameters(
|
private void createAndAddBinding(
|
||||||
QueryParameterBindings queryParameterBindings,
|
int selectionIndex,
|
||||||
List<ParameterOccurrence> parameterOccurrences,
|
List<JdbcParameter> params,
|
||||||
List<JdbcParameterBinder> jdbcParameterBinders,
|
TypeConfiguration typeConfiguration,
|
||||||
SessionFactoryImplementor factory) {
|
Object jdbcValue,
|
||||||
final Dialect dialect = factory.getJdbcServices().getDialect();
|
JdbcMapping type) {
|
||||||
final boolean paddingEnabled = factory.getSessionFactoryOptions().inClauseParameterPaddingEnabled();
|
addBinding(
|
||||||
final int inExprLimit = dialect.getInExpressionCountLimit();
|
params.get( selectionIndex ),
|
||||||
|
new JdbcParameterBindingImpl(
|
||||||
for ( ParameterOccurrence occurrence : parameterOccurrences ) {
|
BindingTypeHelper.INSTANCE.resolveBindType(
|
||||||
final QueryParameterImplementor<?> param = occurrence.getParameter();
|
jdbcValue,
|
||||||
final QueryParameterBinding<?> binding = queryParameterBindings.getBinding( param );
|
type,
|
||||||
|
typeConfiguration
|
||||||
final JdbcMapping jdbcMapping;
|
),
|
||||||
|
jdbcValue
|
||||||
final BindableType<?> type = determineParamType( param, binding );
|
)
|
||||||
if ( type == null ) {
|
);
|
||||||
jdbcMapping = factory.getTypeConfiguration().getBasicTypeForJavaType( Object.class );
|
|
||||||
}
|
|
||||||
else if ( type instanceof BasicTypeReference ) {
|
|
||||||
jdbcMapping = factory.getTypeConfiguration()
|
|
||||||
.getBasicTypeRegistry()
|
|
||||||
.resolve( ( (BasicTypeReference<?>) type ) );
|
|
||||||
}
|
|
||||||
else if ( type instanceof BasicValuedMapping ) {
|
|
||||||
jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException( "Could not resolve NativeQuery parameter type : `" + param + "`");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( binding.isMultiValued() ) {
|
|
||||||
final Collection<?> bindValues = binding.getBindValues();
|
|
||||||
final int bindValueCount = bindValues.size();
|
|
||||||
Object lastBindValue = null;
|
|
||||||
for ( Object bindValue : bindValues ) {
|
|
||||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
|
||||||
jdbcParameterBinders.add( jdbcParameter );
|
|
||||||
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, bindValue ) );
|
|
||||||
lastBindValue = bindValue;
|
|
||||||
}
|
|
||||||
final int bindValueMaxCount = NativeQueryImpl.determineBindValueMaxCount(
|
|
||||||
paddingEnabled,
|
|
||||||
inExprLimit,
|
|
||||||
bindValueCount
|
|
||||||
);
|
|
||||||
if ( bindValueMaxCount != bindValueCount ) {
|
|
||||||
for ( int i = bindValueCount; i < bindValueMaxCount; i++ ) {
|
|
||||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
|
||||||
jdbcParameterBinders.add( jdbcParameter );
|
|
||||||
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
|
||||||
jdbcParameterBinders.add( jdbcParameter );
|
|
||||||
addBinding(
|
|
||||||
jdbcParameter,
|
|
||||||
new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BindableType<?> determineParamType(QueryParameterImplementor<?> param, QueryParameterBinding<?> binding) {
|
|
||||||
BindableType<?> type = binding.getBindType();
|
|
||||||
if ( type == null ) {
|
|
||||||
type = param.getHibernateType();
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
|
import org.hibernate.sql.ComparisonRestriction;
|
||||||
import org.hibernate.sql.SimpleSelect;
|
import org.hibernate.sql.SimpleSelect;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
@ -76,7 +77,7 @@ public class PersistentListTest {
|
||||||
.setTableName( queryableCollection.getTableName() )
|
.setTableName( queryableCollection.getTableName() )
|
||||||
.addColumn( "NAME" )
|
.addColumn( "NAME" )
|
||||||
.addColumn( "LIST_INDEX" )
|
.addColumn( "LIST_INDEX" )
|
||||||
.addRestriction( "NAME", "<>", "?" );
|
.addRestriction( "NAME", ComparisonRestriction.Operator.NE, "?" );
|
||||||
PreparedStatement preparedStatement = ( (SessionImplementor) session2 ).getJdbcCoordinator()
|
PreparedStatement preparedStatement = ( (SessionImplementor) session2 ).getJdbcCoordinator()
|
||||||
.getStatementPreparer()
|
.getStatementPreparer()
|
||||||
.prepareStatement( select.toStatementString() );
|
.prepareStatement( select.toStatementString() );
|
||||||
|
|
|
@ -1,163 +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.orm.test.sql.ast;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.Filter;
|
|
||||||
import org.hibernate.annotations.FilterDef;
|
|
||||||
import org.hibernate.annotations.ParamDef;
|
|
||||||
import org.hibernate.dialect.Dialect;
|
|
||||||
import org.hibernate.dialect.H2Dialect;
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
|
||||||
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 jakarta.persistence.Basic;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
|
|
||||||
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, JdbcParameterRendererTests.EntityWithFilters.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" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFilters(SessionFactoryScope scope) {
|
|
||||||
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
|
||||||
statementInspector.clear();
|
|
||||||
|
|
||||||
scope.inTransaction( (session) -> {
|
|
||||||
session.enableFilter( "region" ).setParameter( "region", "NA" );
|
|
||||||
session.createSelectionQuery( "from EntityWithFilters", EntityWithFilters.class ).list();
|
|
||||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
|
||||||
final String sql = statementInspector.getSqlQueries().get( 0 );
|
|
||||||
assertThat( sql ).contains( "?1" );
|
|
||||||
} );
|
|
||||||
|
|
||||||
statementInspector.clear();
|
|
||||||
scope.inTransaction( (session) -> {
|
|
||||||
final EntityWithFilters it = new EntityWithFilters( 1, "It", "EMEA" );
|
|
||||||
session.persist( it );
|
|
||||||
} );
|
|
||||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
|
||||||
assertThat( StringHelper.count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 3 );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?2" );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?3" );
|
|
||||||
|
|
||||||
scope.inTransaction( (session) -> {
|
|
||||||
final EntityWithFilters it = session.find( EntityWithFilters.class, 1 );
|
|
||||||
statementInspector.clear();
|
|
||||||
it.setName( "It 2" );
|
|
||||||
} );
|
|
||||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
|
||||||
assertThat( StringHelper.count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 3 );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?2" );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?3" );
|
|
||||||
|
|
||||||
scope.inTransaction( (session) -> {
|
|
||||||
final EntityWithFilters it = session.find( EntityWithFilters.class, 1 );
|
|
||||||
statementInspector.clear();
|
|
||||||
session.remove( it );
|
|
||||||
} );
|
|
||||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
|
||||||
assertThat( StringHelper.count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 1 );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JdbcParameterRendererImpl implements JdbcParameterRenderer {
|
|
||||||
@Override
|
|
||||||
public String renderJdbcParameter(int position, JdbcType jdbcType) {
|
|
||||||
return "?" + position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity( name = "EntityWithFilters" )
|
|
||||||
@Table( name = "filtered_entity" )
|
|
||||||
@FilterDef(
|
|
||||||
name = "region",
|
|
||||||
defaultCondition = "region = :region",
|
|
||||||
parameters = @ParamDef(name = "region", type = String.class)
|
|
||||||
)
|
|
||||||
@Filter( name = "region" )
|
|
||||||
public static class EntityWithFilters {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
@Basic
|
|
||||||
private String name;
|
|
||||||
@Basic
|
|
||||||
private String region;
|
|
||||||
|
|
||||||
protected EntityWithFilters() {
|
|
||||||
// for use by Hibernate
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityWithFilters(Integer id, String name, String region) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.region = region;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRegion() {
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRegion(String region) {
|
|
||||||
this.region = region;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
* 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 java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.annotations.Filter;
|
||||||
|
import org.hibernate.annotations.FilterDef;
|
||||||
|
import org.hibernate.annotations.ParamDef;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
|
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.FailureExpected;
|
||||||
|
import org.hibernate.testing.orm.junit.Jira;
|
||||||
|
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.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Version;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hibernate.internal.util.StringHelper.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 = ParameterMarkerStrategy.class,
|
||||||
|
impl = ParameterMarkerStrategyTests.ParameterMarkerStrategyImpl.class
|
||||||
|
) )
|
||||||
|
@DomainModel( annotatedClasses = {
|
||||||
|
EntityOfBasics.class,
|
||||||
|
ParameterMarkerStrategyTests.EntityWithFilters.class,
|
||||||
|
ParameterMarkerStrategyTests.EntityWithVersion.class
|
||||||
|
} )
|
||||||
|
@SessionFactory( useCollectingStatementInspector = true )
|
||||||
|
@RequiresDialect( H2Dialect.class )
|
||||||
|
public class ParameterMarkerStrategyTests {
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16229" )
|
||||||
|
public void testQueryParams(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" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16260" )
|
||||||
|
public void testFilters(SessionFactoryScope scope) {
|
||||||
|
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||||
|
statementInspector.clear();
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.enableFilter( "region" ).setParameter( "region", "NA" );
|
||||||
|
session.createSelectionQuery( "from EntityWithFilters", EntityWithFilters.class ).list();
|
||||||
|
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||||
|
final String sql = statementInspector.getSqlQueries().get( 0 );
|
||||||
|
assertThat( sql ).contains( "?1" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16256" )
|
||||||
|
public void testMutations(SessionFactoryScope scope) {
|
||||||
|
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||||
|
statementInspector.clear();
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityWithFilters it = new EntityWithFilters( 1, "It", "EMEA" );
|
||||||
|
session.persist( it );
|
||||||
|
session.flush();
|
||||||
|
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||||
|
assertThat( count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 3 );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?2" );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?3" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityWithFilters it = session.find( EntityWithFilters.class, 1 );
|
||||||
|
statementInspector.clear();
|
||||||
|
it.setName( "It 2" );
|
||||||
|
session.flush();
|
||||||
|
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||||
|
assertThat( count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 3 );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?2" );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?3" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityWithFilters it = session.find( EntityWithFilters.class, 1 );
|
||||||
|
statementInspector.clear();
|
||||||
|
session.remove( it );
|
||||||
|
session.flush();
|
||||||
|
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||||
|
assertThat( count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 1 );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16229" )
|
||||||
|
public void testLocking(SessionFactoryScope scope) {
|
||||||
|
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||||
|
|
||||||
|
final EntityWithVersion created = scope.fromTransaction( (session) -> {
|
||||||
|
final EntityWithVersion entity = new EntityWithVersion( 1, "Entity Prime" );
|
||||||
|
session.persist( entity );
|
||||||
|
return entity;
|
||||||
|
} );
|
||||||
|
|
||||||
|
statementInspector.clear();
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.lock( created, LockMode.PESSIMISTIC_FORCE_INCREMENT );
|
||||||
|
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?2" );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?3" );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).matches( (sql) -> count( sql, "?" ) == 3 );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@FailureExpected
|
||||||
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16283" )
|
||||||
|
public void testNativeQuery(SessionFactoryScope scope) {
|
||||||
|
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||||
|
|
||||||
|
statementInspector.clear();
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.createNativeQuery( "select count(1) from filtered_entity e where e.region = :region" )
|
||||||
|
.setParameter( "region", "ABC" )
|
||||||
|
.uniqueResult();
|
||||||
|
|
||||||
|
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||||
|
assertThat( count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 1 );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
statementInspector.clear();
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.createNativeQuery( "select count(1) from filtered_entity e where e.region in (:region)" )
|
||||||
|
.setParameterList( "region", List.of( "ABC", "DEF" ) )
|
||||||
|
.uniqueResult();
|
||||||
|
|
||||||
|
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||||
|
assertThat( count( statementInspector.getSqlQueries().get( 0 ), "?" ) ).isEqualTo( 1 );
|
||||||
|
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanUpTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete EntityOfBasics" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete EntityWithFilters" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete EntityWithVersion" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ParameterMarkerStrategyImpl implements ParameterMarkerStrategy {
|
||||||
|
@Override
|
||||||
|
public String createMarker(int position, JdbcType jdbcType) {
|
||||||
|
return "?" + position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "EntityWithFilters" )
|
||||||
|
@Table( name = "filtered_entity" )
|
||||||
|
@FilterDef(
|
||||||
|
name = "region",
|
||||||
|
defaultCondition = "region = :region",
|
||||||
|
parameters = @ParamDef(name = "region", type = String.class)
|
||||||
|
)
|
||||||
|
@Filter( name = "region" )
|
||||||
|
public static class EntityWithFilters {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
@Basic
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
protected EntityWithFilters() {
|
||||||
|
// for use by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityWithFilters(Integer id, String name, String region) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.region = region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegion() {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegion(String region) {
|
||||||
|
this.region = region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "EntityWithVersion" )
|
||||||
|
@Table( name = "versioned_entity" )
|
||||||
|
public static class EntityWithVersion {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
@Version
|
||||||
|
private int version;
|
||||||
|
|
||||||
|
private EntityWithVersion() {
|
||||||
|
// for use by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityWithVersion(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
|
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
|
||||||
import org.hibernate.property.access.spi.Getter;
|
import org.hibernate.property.access.spi.Getter;
|
||||||
|
import org.hibernate.sql.ComparisonRestriction;
|
||||||
import org.hibernate.sql.Update;
|
import org.hibernate.sql.Update;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
|
@ -580,11 +581,11 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
||||||
// Apply "AND REV <> ?"
|
// Apply "AND REV <> ?"
|
||||||
// todo (PropertyMapping) : need to be able to handle paths
|
// todo (PropertyMapping) : need to be able to handle paths
|
||||||
final String path = configuration.getRevisionNumberPath();
|
final String path = configuration.getRevisionNumberPath();
|
||||||
context.addRestriction( rootAuditEntity.toColumns( path )[ 0 ], "<>", "?" );
|
context.addRestriction( rootAuditEntity.toColumns( path )[ 0 ], ComparisonRestriction.Operator.NE, "?" );
|
||||||
context.bind( revisionNumber, rootAuditEntity.getPropertyType( path ) );
|
context.bind( revisionNumber, rootAuditEntity.getPropertyType( path ) );
|
||||||
|
|
||||||
// Apply "AND REVEND is null"
|
// Apply "AND REVEND is null"
|
||||||
context.addNullnessRestriction( revEndColumnName );
|
context.addColumnIsNullRestriction( revEndColumnName );
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -635,11 +636,11 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
||||||
|
|
||||||
// Apply "AND REV <> ?"
|
// Apply "AND REV <> ?"
|
||||||
// todo (PropertyMapping) : need to be able to handle paths
|
// todo (PropertyMapping) : need to be able to handle paths
|
||||||
context.addRestriction( configuration.getRevisionFieldName(), "<>", "?" );
|
context.addRestriction( configuration.getRevisionFieldName(), ComparisonRestriction.Operator.NE, "?" );
|
||||||
context.bind( revisionNumber, auditEntity.getPropertyType( configuration.getRevisionNumberPath() ) );
|
context.bind( revisionNumber, auditEntity.getPropertyType( configuration.getRevisionNumberPath() ) );
|
||||||
|
|
||||||
// Apply "AND REVEND_TSTMP is null"
|
// Apply "AND REVEND_TSTMP is null"
|
||||||
context.addNullnessRestriction( revEndTimestampColumnName );
|
context.addColumnIsNullRestriction( revEndTimestampColumnName );
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue