HHH-16284 - Rename JdbcParameterRender to ParameterMarkerStrategy
This commit is contained in:
parent
f45dcf4c2f
commit
b276128f56
|
@ -19,7 +19,8 @@ ext {
|
|||
'jdbc.user' : 'sa',
|
||||
'jdbc.pass' : '',
|
||||
'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 : [
|
||||
'db.dialect' : 'org.hibernate.dialect.HSQLDialect',
|
||||
|
|
|
@ -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.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaDelete;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
@ -2789,13 +2790,15 @@ public interface AvailableSettings {
|
|||
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
|
||||
* ({@code false}) to use the standard JDBC parameter markers (`?`) instead
|
||||
* @implNote {@code False} by default, indicating standard JDBC parameter markers (`?`)
|
||||
* 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 org.hibernate.dialect.Dialect#getNativeParameterRenderer()
|
||||
* @see ParameterMarkerStrategy
|
||||
* @see org.hibernate.dialect.Dialect#getNativeParameterMarkerStrategy()
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
|
|
|
@ -144,8 +144,8 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
|
|||
import org.hibernate.sql.ForUpdateFragment;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.internal.JdbcParameterRendererStandard;
|
||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||
import org.hibernate.sql.ast.internal.ParameterMarkerStrategyStandard;
|
||||
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
||||
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() {
|
||||
return JdbcParameterRendererStandard.INSTANCE;
|
||||
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,7 +75,7 @@ import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
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.model.MutationOperation;
|
||||
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
||||
|
@ -193,8 +193,8 @@ public class DialectDelegateWrapper extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JdbcParameterRenderer getNativeParameterRenderer() {
|
||||
return wrapped.getNativeParameterRenderer();
|
||||
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||
return wrapped.getNativeParameterMarkerStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -57,7 +57,7 @@ import org.hibernate.service.ServiceRegistry;
|
|||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
|
@ -910,18 +910,18 @@ public class H2Dialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JdbcParameterRenderer getNativeParameterRenderer() {
|
||||
return OrdinalParameterRenderer.INSTANCE;
|
||||
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||
return OrdinalParameterMarkerStrategy.INSTANCE;
|
||||
}
|
||||
|
||||
public static class OrdinalParameterRenderer implements JdbcParameterRenderer {
|
||||
public static class OrdinalParameterMarkerStrategy implements ParameterMarkerStrategy {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final OrdinalParameterRenderer INSTANCE = new OrdinalParameterRenderer();
|
||||
public static final OrdinalParameterMarkerStrategy INSTANCE = new OrdinalParameterMarkerStrategy();
|
||||
|
||||
@Override
|
||||
public String renderJdbcParameter(int position, JdbcType jdbcType) {
|
||||
public String createMarker(int position, JdbcType jdbcType) {
|
||||
return "?" + position;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
|
@ -145,7 +145,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
|
||||
protected final PostgreSQLDriverKind driverKind;
|
||||
private final OptionalTableUpdateStrategy optionalTableUpdateStrategy;
|
||||
private final JdbcParameterRenderer parameterRenderer;
|
||||
private final ParameterMarkerStrategy parameterRenderer;
|
||||
|
||||
public PostgreSQLDialect() {
|
||||
this( MINIMUM_VERSION );
|
||||
|
@ -166,7 +166,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
this.optionalTableUpdateStrategy = determineOptionalTableUpdateStrategy( version );
|
||||
this.parameterRenderer = driverKind == PostgreSQLDriverKind.VERT_X
|
||||
? NativeParameterMarkers.INSTANCE
|
||||
: super.getNativeParameterRenderer();
|
||||
: super.getNativeParameterMarkerStrategy();
|
||||
}
|
||||
|
||||
private static OptionalTableUpdateStrategy determineOptionalTableUpdateStrategy(DatabaseVersion version) {
|
||||
|
@ -1433,18 +1433,18 @@ public class PostgreSQLDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JdbcParameterRenderer getNativeParameterRenderer() {
|
||||
public ParameterMarkerStrategy getNativeParameterMarkerStrategy() {
|
||||
return parameterRenderer;
|
||||
}
|
||||
|
||||
private static class NativeParameterMarkers implements JdbcParameterRenderer {
|
||||
private static class NativeParameterMarkers implements ParameterMarkerStrategy {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final NativeParameterMarkers INSTANCE = new NativeParameterMarkers();
|
||||
|
||||
@Override
|
||||
public String renderJdbcParameter(int position, JdbcType jdbcType) {
|
||||
public String createMarker(int position, JdbcType jdbcType) {
|
||||
return "$" + position;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6129,7 +6129,7 @@ public abstract class AbstractEntityPersister
|
|||
delete.addColumnRestriction( propertyColumnNames[k] );
|
||||
}
|
||||
else {
|
||||
delete.addColumnNullnessRestriction( propertyColumnNames[k] );
|
||||
delete.addColumnIsNullRestriction( propertyColumnNames[k] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,9 +57,7 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
|
|||
}
|
||||
else {
|
||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
||||
|
||||
jdbcParameterBindings.registerNativeQueryParameters(
|
||||
jdbcParameterBindings = new JdbcParameterBindingsImpl(
|
||||
queryParameterBindings,
|
||||
parameterList,
|
||||
jdbcParameterBinders,
|
||||
|
|
|
@ -79,9 +79,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
}
|
||||
else {
|
||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
||||
|
||||
jdbcParameterBindings.registerNativeQueryParameters(
|
||||
jdbcParameterBindings = new JdbcParameterBindingsImpl(
|
||||
queryParameterBindings,
|
||||
parameterList,
|
||||
jdbcParameterBinders,
|
||||
|
@ -95,8 +93,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
sql,
|
||||
jdbcParameterBinders,
|
||||
resultSetMapping,
|
||||
affectedTableNames,
|
||||
Collections.emptySet()
|
||||
affectedTableNames
|
||||
);
|
||||
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
|
@ -116,6 +113,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
@Override
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, DomainQueryExecutionContext executionContext) {
|
||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||
//noinspection unchecked
|
||||
return EmptyScrollableResults.INSTANCE;
|
||||
}
|
||||
final List<JdbcParameterBinder> jdbcParameterBinders;
|
||||
|
@ -128,9 +126,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
}
|
||||
else {
|
||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
||||
|
||||
jdbcParameterBindings.registerNativeQueryParameters(
|
||||
jdbcParameterBindings = new JdbcParameterBindingsImpl(
|
||||
queryParameterBindings,
|
||||
parameterList,
|
||||
jdbcParameterBinders,
|
||||
|
@ -142,8 +138,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
sql,
|
||||
jdbcParameterBinders,
|
||||
resultSetMapping,
|
||||
affectedTableNames,
|
||||
Collections.emptySet()
|
||||
affectedTableNames
|
||||
);
|
||||
|
||||
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.transaction.internal.TransactionCoordinatorBuilderInitiator;
|
||||
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.tool.schema.internal.SchemaManagementToolInitiator;
|
||||
import org.hibernate.tool.schema.internal.script.SqlScriptExtractorInitiator;
|
||||
|
@ -152,8 +152,8 @@ public final class StandardServiceInitiators {
|
|||
// SqmMultiTableMutationStrategyProvider
|
||||
serviceInitiators.add( SqmMultiTableMutationStrategyProviderInitiator.INSTANCE );
|
||||
|
||||
// JdbcParameterRenderer
|
||||
serviceInitiators.add( JdbcParameterRendererInitiator.INSTANCE );
|
||||
// ParameterMarkerStrategy
|
||||
serviceInitiators.add( ParameterMarkerStrategyInitiator.INSTANCE );
|
||||
|
||||
serviceInitiators.trimToSize();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.hibernate.Internal;
|
|||
@Internal
|
||||
public class ComparisonRestriction implements Restriction {
|
||||
private final String lhs;
|
||||
private final String operator;
|
||||
private final Operator operator;
|
||||
private final String rhs;
|
||||
|
||||
public ComparisonRestriction(String lhs) {
|
||||
|
@ -24,10 +24,10 @@ public class ComparisonRestriction implements Restriction {
|
|||
}
|
||||
|
||||
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.operator = operator;
|
||||
this.rhs = rhs;
|
||||
|
@ -36,7 +36,7 @@ public class ComparisonRestriction implements Restriction {
|
|||
@Override
|
||||
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
|
||||
sqlBuffer.append( lhs );
|
||||
sqlBuffer.append( operator );
|
||||
sqlBuffer.append( operator.getSqlText() );
|
||||
|
||||
if ( "?".equals( rhs ) ) {
|
||||
sqlBuffer.append( context.makeParameterMarker() );
|
||||
|
@ -45,4 +45,20 @@ public class ComparisonRestriction implements Restriction {
|
|||
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>.
|
||||
*/
|
||||
package org.hibernate.sql;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
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.
|
||||
|
@ -22,24 +20,20 @@ import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
|||
* @author Gavin King
|
||||
*/
|
||||
@Internal
|
||||
public class Delete {
|
||||
|
||||
public class Delete implements RestrictionRenderingContext {
|
||||
protected String tableName;
|
||||
protected String comment;
|
||||
protected final List<Restriction> restrictions = new ArrayList<>();
|
||||
|
||||
protected final List<String> whereFragments = new ArrayList<>();
|
||||
|
||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
||||
private final boolean standardParamRendering;
|
||||
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||
private int parameterCount;
|
||||
|
||||
public Delete(SessionFactoryImplementor factory) {
|
||||
this( factory.getServiceRegistry().getService( JdbcParameterRenderer.class ) );
|
||||
this( factory.getServiceRegistry().getService( ParameterMarkerStrategy.class ) );
|
||||
}
|
||||
|
||||
public Delete(JdbcParameterRenderer jdbcParameterRenderer) {
|
||||
this.jdbcParameterRenderer = jdbcParameterRenderer;
|
||||
this.standardParamRendering = JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer );
|
||||
public Delete(ParameterMarkerStrategy parameterMarkerStrategy) {
|
||||
this.parameterMarkerStrategy = parameterMarkerStrategy;
|
||||
}
|
||||
|
||||
public Delete setTableName(String tableName) {
|
||||
|
@ -54,8 +48,7 @@ public class Delete {
|
|||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Delete addColumnRestriction(String columnName) {
|
||||
final String paramMarker = jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null );
|
||||
this.whereFragments.add( columnName + "=" + paramMarker );
|
||||
restrictions.add( new ComparisonRestriction( columnName ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -71,17 +64,14 @@ public class Delete {
|
|||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Delete addColumnNullnessRestriction(String columnName) {
|
||||
addColumnNullnessRestriction( columnName, false );
|
||||
public Delete addColumnIsNullRestriction(String columnName) {
|
||||
restrictions.add( new NullnessRestriction( columnName ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Delete addColumnNullnessRestriction(String columnName, boolean negate) {
|
||||
final String fragment = negate
|
||||
? columnName + " is not null"
|
||||
: columnName + " is null";
|
||||
whereFragments.add( fragment );
|
||||
public Delete addColumnIsNotNullRestriction(String columnName) {
|
||||
restrictions.add( new NullnessRestriction( columnName, false ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -102,25 +92,29 @@ public class Delete {
|
|||
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) {
|
||||
if ( comment != null ) {
|
||||
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.engine.spi.SessionFactoryImplementor;
|
||||
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.
|
||||
|
@ -34,21 +33,19 @@ public class Insert {
|
|||
protected Map<String,String> columns = new LinkedHashMap<>();
|
||||
|
||||
private final Dialect dialect;
|
||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
||||
private final boolean standardParamRendering;
|
||||
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||
private int parameterCount;
|
||||
|
||||
public Insert(SessionFactoryImplementor sessionFactory) {
|
||||
this(
|
||||
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.jdbcParameterRenderer = jdbcParameterRenderer;
|
||||
this.standardParamRendering = isStandardRenderer( jdbcParameterRenderer );
|
||||
this.parameterMarkerStrategy = parameterMarkerStrategy;
|
||||
}
|
||||
|
||||
protected Dialect getDialect() {
|
||||
|
@ -179,8 +176,8 @@ public class Insert {
|
|||
}
|
||||
|
||||
private String normalizeExpressionFragment(String rhs) {
|
||||
return rhs.equals( "?" ) && !standardParamRendering
|
||||
? jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null )
|
||||
return rhs.equals( "?" )
|
||||
? parameterMarkerStrategy.createMarker( ++parameterCount, null )
|
||||
: rhs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,32 +9,32 @@ package org.hibernate.sql;
|
|||
import org.hibernate.Internal;
|
||||
|
||||
/**
|
||||
* Nullness restriction - is [not] null
|
||||
* Nullness restriction - IS (NOT)? NULL
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public class NullnessRestriction implements Restriction {
|
||||
private final String columnName;
|
||||
private final boolean negated;
|
||||
private final boolean affirmative;
|
||||
|
||||
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.negated = negated;
|
||||
this.affirmative = affirmative;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
|
||||
sqlBuffer.append( columnName );
|
||||
if ( negated ) {
|
||||
sqlBuffer.append( " is not null" );
|
||||
}
|
||||
else {
|
||||
if ( affirmative ) {
|
||||
sqlBuffer.append( " is null" );
|
||||
}
|
||||
else {
|
||||
sqlBuffer.append( " is not null" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
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.
|
||||
|
@ -37,20 +37,18 @@ public class SimpleSelect implements RestrictionRenderingContext {
|
|||
|
||||
protected LockOptions lockOptions = new LockOptions( LockMode.READ );
|
||||
|
||||
private final SessionFactoryImplementor factory;
|
||||
private final Dialect dialect;
|
||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
||||
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||
private int parameterCount;
|
||||
|
||||
public SimpleSelect(SessionFactoryImplementor factory) {
|
||||
this.factory = factory;
|
||||
this.dialect = factory.getJdbcServices().getDialect();
|
||||
this.jdbcParameterRenderer = factory.getServiceRegistry().getService( JdbcParameterRenderer.class );
|
||||
this.parameterMarkerStrategy = factory.getServiceRegistry().getService( ParameterMarkerStrategy.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
*
|
||||
* @see #addRestriction(String, String, String)
|
||||
* @see #addRestriction(String, ComparisonRestriction.Operator, String)
|
||||
*/
|
||||
public SimpleSelect addRestriction(String 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}.
|
||||
* <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.
|
||||
*/
|
||||
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 ) );
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.util.Map;
|
|||
import org.hibernate.Internal;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
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.
|
||||
|
@ -28,17 +28,15 @@ public class Update implements RestrictionRenderingContext {
|
|||
protected Map<String,String> assignments = new LinkedHashMap<>();
|
||||
protected List<Restriction> restrictions = new ArrayList<>();
|
||||
|
||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
||||
private final boolean standardParamRendering;
|
||||
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||
private int parameterCount;
|
||||
|
||||
public Update(SessionFactoryImplementor factory) {
|
||||
this( factory.getServiceRegistry().getService( JdbcParameterRenderer.class ) );
|
||||
this( factory.getServiceRegistry().getService( ParameterMarkerStrategy.class ) );
|
||||
}
|
||||
|
||||
public Update(JdbcParameterRenderer jdbcParameterRenderer) {
|
||||
this.jdbcParameterRenderer = jdbcParameterRenderer;
|
||||
this.standardParamRendering = JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer );
|
||||
public Update(ParameterMarkerStrategy parameterMarkerStrategy) {
|
||||
this.parameterMarkerStrategy = parameterMarkerStrategy;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
|
@ -91,19 +89,26 @@ public class Update implements RestrictionRenderingContext {
|
|||
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 ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
private String normalizeExpressionFragment(String rhs) {
|
||||
return rhs.equals( "?" ) && !standardParamRendering
|
||||
? jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null )
|
||||
return rhs.equals( "?" )
|
||||
? parameterMarkerStrategy.createMarker( ++parameterCount, null )
|
||||
: rhs;
|
||||
}
|
||||
|
||||
public Update addNullnessRestriction(String column) {
|
||||
restrictions.add( new NullnessRestriction( column ) );
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -158,6 +163,6 @@ public class Update implements RestrictionRenderingContext {
|
|||
|
||||
@Override
|
||||
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.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
|
||||
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcParameterRendererInitiator implements StandardServiceInitiator<JdbcParameterRenderer> {
|
||||
public class ParameterMarkerStrategyInitiator implements StandardServiceInitiator<ParameterMarkerStrategy> {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final JdbcParameterRendererInitiator INSTANCE = new JdbcParameterRendererInitiator();
|
||||
public static final ParameterMarkerStrategyInitiator INSTANCE = new ParameterMarkerStrategyInitiator();
|
||||
|
||||
@Override
|
||||
public JdbcParameterRenderer initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||
public ParameterMarkerStrategy initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||
final boolean useNativeMarkers = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS,
|
||||
configurationValues,
|
||||
true
|
||||
false
|
||||
);
|
||||
|
||||
if ( useNativeMarkers ) {
|
||||
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
|
||||
public Class<JdbcParameterRenderer> getServiceInitiated() {
|
||||
return JdbcParameterRenderer.class;
|
||||
public Class<ParameterMarkerStrategy> getServiceInitiated() {
|
||||
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.SqlAstTranslator;
|
||||
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.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
|
@ -273,7 +274,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
private JdbcParameterBindings jdbcParameterBindings;
|
||||
private Map<JdbcParameter, JdbcParameterBinding> appliedParameterBindings = Collections.emptyMap();
|
||||
private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||
private final JdbcParameterRenderer jdbcParameterRenderer;
|
||||
private final ParameterMarkerStrategy parameterMarkerStrategy;
|
||||
|
||||
|
||||
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.dialect = sessionFactory.getJdbcServices().getDialect();
|
||||
this.statementStack.push( statement );
|
||||
this.jdbcParameterRenderer = sessionFactory.getServiceRegistry().getService( JdbcParameterRenderer.class );
|
||||
this.parameterMarkerStrategy = sessionFactory.getServiceRegistry().getService( ParameterMarkerStrategy.class );
|
||||
}
|
||||
|
||||
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 ( literalFormatter == null ) {
|
||||
parameterBinders.add( literal );
|
||||
|
||||
final LiteralAsParameter<Object> jdbcParameter = new LiteralAsParameter<>( literal );
|
||||
final String marker = parameterMarkerStrategy.createMarker( parameterBinders.size(), literal.getJdbcMapping().getJdbcType() );
|
||||
final LiteralAsParameter<Object> jdbcParameter = new LiteralAsParameter<>( literal, marker );
|
||||
if ( castParameter ) {
|
||||
renderCasted( jdbcParameter );
|
||||
}
|
||||
|
@ -6187,14 +6188,21 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
jdbcParameters.addParameter( jdbcParameter );
|
||||
}
|
||||
|
||||
protected void renderParameterAsParameter(JdbcParameter jdbcParameter) {
|
||||
renderParameterAsParameter( jdbcParameter, parameterBinders.size() + 1 );
|
||||
}
|
||||
|
||||
protected void renderParameterAsParameter(JdbcParameter jdbcParameter, int position) {
|
||||
protected final void renderParameterAsParameter(JdbcParameter jdbcParameter) {
|
||||
final JdbcType jdbcType = jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType();
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// - the rendering is pretty simple
|
||||
if ( CollectionHelper.isEmpty( columnWriteFragment.getParameters() )
|
||||
|| JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer ) ) {
|
||||
|| ParameterMarkerStrategyStandard.isStandardRenderer( parameterMarkerStrategy ) ) {
|
||||
simpleColumnWriteFragmentRendering( columnWriteFragment );
|
||||
return;
|
||||
}
|
||||
|
@ -8034,7 +8042,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
// to the index of the parameter marker
|
||||
appendSql( sqlFragment.substring( lastEnd, markerStart ) );
|
||||
|
||||
// render the parameter marker and register it
|
||||
// render the parameter marker and register the parameter handling
|
||||
visitParameterAsParameter( parameter );
|
||||
|
||||
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
|
||||
*/
|
||||
public class LiteralAsParameter<T> implements SelfRenderingExpression {
|
||||
|
||||
private final Literal literal;
|
||||
private final String parameterMarker;
|
||||
|
||||
public LiteralAsParameter(Literal literal) {
|
||||
public LiteralAsParameter(Literal literal, String parameterMarker) {
|
||||
this.literal = literal;
|
||||
this.parameterMarker = parameterMarker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderToSql(SqlAppender sqlAppender, SqlAstTranslator<?> walker, SessionFactoryImplementor sessionFactory) {
|
||||
sqlAppender.appendSql( "?" );
|
||||
sqlAppender.append( parameterMarker );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,12 +9,25 @@ package org.hibernate.sql.exec.internal;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.type.BasicTypeReference;
|
||||
|
||||
/**
|
||||
* 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
|
||||
public void addBinding(JdbcParameter parameter, JdbcParameterBinding binding) {
|
||||
if ( bindingMap == null ) {
|
||||
|
@ -47,7 +137,6 @@ public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
|
|||
@Override
|
||||
public JdbcParameterBinding getBinding(JdbcParameter parameter) {
|
||||
if ( bindingMap == null ) {
|
||||
// no bindings
|
||||
return null;
|
||||
}
|
||||
return bindingMap.get( parameter );
|
||||
|
@ -55,6 +144,9 @@ public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
|
|||
|
||||
@Override
|
||||
public void visitBindings(BiConsumer<JdbcParameter, JdbcParameterBinding> action) {
|
||||
if ( bindingMap == null ) {
|
||||
return;
|
||||
}
|
||||
for ( Map.Entry<JdbcParameter, JdbcParameterBinding> entry : bindingMap.entrySet() ) {
|
||||
action.accept( entry.getKey(), entry.getValue() );
|
||||
}
|
||||
|
|
|
@ -11,34 +11,24 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
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.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.Bindable;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.BindableType;
|
||||
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.exec.internal.JdbcParameterBindingImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||
import org.hibernate.type.BasicTypeReference;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* {@link org.hibernate.sql.ast.tree.expression.LiteralAsParameter}
|
||||
* which actually encapsulates the actually literal value inside
|
||||
* itself - to create the binder and actually perform the binding
|
||||
* is only dependent on the LiteralParameter
|
||||
* which encapsulates the literal value inside itself - to create the
|
||||
* binder and actually perform the binding is only dependent on the
|
||||
* LiteralParameter
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -90,7 +80,17 @@ public interface JdbcParameterBindings {
|
|||
offset,
|
||||
jdbcParameters,
|
||||
session.getFactory().getTypeConfiguration(),
|
||||
(selectionIndex, params, typeConfiguration, jdbcValue, type) -> {
|
||||
this::createAndAddBinding,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
private void createAndAddBinding(
|
||||
int selectionIndex,
|
||||
List<JdbcParameter> params,
|
||||
TypeConfiguration typeConfiguration,
|
||||
Object jdbcValue,
|
||||
JdbcMapping type) {
|
||||
addBinding(
|
||||
params.get( selectionIndex ),
|
||||
new JdbcParameterBindingImpl(
|
||||
|
@ -103,81 +103,4 @@ public interface JdbcParameterBindings {
|
|||
)
|
||||
);
|
||||
}
|
||||
,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
default void registerNativeQueryParameters(
|
||||
QueryParameterBindings queryParameterBindings,
|
||||
List<ParameterOccurrence> parameterOccurrences,
|
||||
List<JdbcParameterBinder> jdbcParameterBinders,
|
||||
SessionFactoryImplementor factory) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.sql.ComparisonRestriction;
|
||||
import org.hibernate.sql.SimpleSelect;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
|
@ -76,7 +77,7 @@ public class PersistentListTest {
|
|||
.setTableName( queryableCollection.getTableName() )
|
||||
.addColumn( "NAME" )
|
||||
.addColumn( "LIST_INDEX" )
|
||||
.addRestriction( "NAME", "<>", "?" );
|
||||
.addRestriction( "NAME", ComparisonRestriction.Operator.NE, "?" );
|
||||
PreparedStatement preparedStatement = ( (SessionImplementor) session2 ).getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.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.UnionSubclassEntityPersister;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.sql.ComparisonRestriction;
|
||||
import org.hibernate.sql.Update;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.CollectionType;
|
||||
|
@ -580,11 +581,11 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
|||
// Apply "AND REV <> ?"
|
||||
// todo (PropertyMapping) : need to be able to handle paths
|
||||
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 ) );
|
||||
|
||||
// Apply "AND REVEND is null"
|
||||
context.addNullnessRestriction( revEndColumnName );
|
||||
context.addColumnIsNullRestriction( revEndColumnName );
|
||||
|
||||
return context;
|
||||
}
|
||||
|
@ -635,11 +636,11 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
|||
|
||||
// Apply "AND REV <> ?"
|
||||
// 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() ) );
|
||||
|
||||
// Apply "AND REVEND_TSTMP is null"
|
||||
context.addNullnessRestriction( revEndTimestampColumnName );
|
||||
context.addColumnIsNullRestriction( revEndTimestampColumnName );
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue