HHH-16260 - JdbcParameterRenderer not called with dynamic filters

HHH-16256 - JdbcParameterRenderer to have an impact on write operations
HHH-16273 - Support for Dialect native JdbcParameterRenderer
This commit is contained in:
Steve Ebersole 2023-03-09 17:59:55 -06:00
parent 274af05b8a
commit 5811c858de
36 changed files with 637 additions and 545 deletions

View File

@ -11,9 +11,6 @@ hibernate.connection.username @jdbc.user@
hibernate.connection.password @jdbc.pass@
hibernate.connection.init_sql @connection.init_sql@
# some Agroal tests fail with native markers. not sure why yet
hibernate.dialect.native_param_markers=false
hibernate.jdbc.batch_size 10
hibernate.connection.provider_class AgroalConnectionProvider

View File

@ -2789,7 +2789,7 @@ public interface AvailableSettings {
String TIMEZONE_DEFAULT_STORAGE = "hibernate.timezone.default_storage";
/**
* Specifies whether to use JDBC parameter markers (`?`) or dialect native markers.
* Controls whether to use JDBC parameter markers (`?`) or dialect native markers.
*
* @implNote By default ({@code true}), dialect native markers are used, if any; disable
* ({@code false}) to use the standard JDBC parameter markers (`?`) instead

View File

@ -117,7 +117,6 @@ import org.hibernate.mapping.Index;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.persister.entity.mutation.EntityMutationTarget;

View File

@ -911,11 +911,18 @@ public class H2Dialect extends Dialect {
@Override
public JdbcParameterRenderer getNativeParameterRenderer() {
return H2Dialect::renderNatively;
return OrdinalParameterRenderer.INSTANCE;
}
private static void renderNatively(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
appender.append( "?" );
appender.appendSql( position );
public static class OrdinalParameterRenderer implements JdbcParameterRenderer {
/**
* Singleton access
*/
public static final OrdinalParameterRenderer INSTANCE = new OrdinalParameterRenderer();
@Override
public String renderJdbcParameter(int position, JdbcType jdbcType) {
return "?" + position;
}
}
}

View File

@ -145,15 +145,28 @@ public class PostgreSQLDialect extends Dialect {
protected final PostgreSQLDriverKind driverKind;
private final OptionalTableUpdateStrategy optionalTableUpdateStrategy;
private final JdbcParameterRenderer parameterRenderer;
public PostgreSQLDialect() {
this( MINIMUM_VERSION );
}
public PostgreSQLDialect(DialectResolutionInfo info) {
super(info);
driverKind = PostgreSQLDriverKind.determineKind( info );
optionalTableUpdateStrategy = determineOptionalTableUpdateStrategy( info );
this( info, PostgreSQLDriverKind.determineKind( info ) );
}
public PostgreSQLDialect(DatabaseVersion version) {
this( version, PostgreSQLDriverKind.PG_JDBC );
}
public PostgreSQLDialect(DatabaseVersion version, PostgreSQLDriverKind driverKind) {
super( version );
this.driverKind = driverKind;
this.optionalTableUpdateStrategy = determineOptionalTableUpdateStrategy( version );
this.parameterRenderer = driverKind == PostgreSQLDriverKind.VERT_X
? NativeParameterMarkers.INSTANCE
: super.getNativeParameterRenderer();
}
private static OptionalTableUpdateStrategy determineOptionalTableUpdateStrategy(DatabaseVersion version) {
@ -162,18 +175,6 @@ public class PostgreSQLDialect extends Dialect {
: PostgreSQLDialect::withoutMerge;
}
public PostgreSQLDialect(DatabaseVersion version) {
super(version);
driverKind = PostgreSQLDriverKind.PG_JDBC;
optionalTableUpdateStrategy = determineOptionalTableUpdateStrategy( version );
}
public PostgreSQLDialect(DatabaseVersion version, PostgreSQLDriverKind driverKind) {
super(version);
this.driverKind = driverKind;
optionalTableUpdateStrategy = determineOptionalTableUpdateStrategy( version );
}
@Override
protected DatabaseVersion getMinimumSupportedVersion() {
return MINIMUM_VERSION;
@ -1433,11 +1434,18 @@ public class PostgreSQLDialect extends Dialect {
@Override
public JdbcParameterRenderer getNativeParameterRenderer() {
return PostgreSQLDialect::renderNatively;
return parameterRenderer;
}
private static void renderNatively(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
appender.append( "$" );
appender.appendSql( position );
private static class NativeParameterMarkers implements JdbcParameterRenderer {
/**
* Singleton access
*/
public static final NativeParameterMarkers INSTANCE = new NativeParameterMarkers();
@Override
public String renderJdbcParameter(int position, JdbcType jdbcType) {
return "$" + position;
}
}
}

View File

@ -14,6 +14,7 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
*/
public enum PostgreSQLDriverKind {
PG_JDBC,
VERT_X,
OTHER;
public static PostgreSQLDriverKind determineKind(DialectResolutionInfo dialectResolutionInfo) {

View File

@ -104,13 +104,13 @@ public class PessimisticReadSelectLockingStrategy extends AbstractSelectLockingS
final SessionFactoryImplementor factory = getLockable().getFactory();
final LockOptions lockOptions = new LockOptions( getLockMode() );
lockOptions.setTimeOut( lockTimeout );
final SimpleSelect select = new SimpleSelect( factory.getJdbcServices().getDialect() )
final SimpleSelect select = new SimpleSelect( factory )
.setLockOptions( lockOptions )
.setTableName( getLockable().getRootTableName() )
.addColumn( getLockable().getRootTableIdentifierColumnNames()[0] )
.addCondition( getLockable().getRootTableIdentifierColumnNames(), "=?" );
.addRestriction( getLockable().getRootTableIdentifierColumnNames() );
if ( getLockable().isVersioned() ) {
select.addCondition( getLockable().getVersionColumnName(), "=?" );
select.addRestriction( getLockable().getVersionColumnName() );
}
if ( factory.getSessionFactoryOptions().isCommentsEnabled() ) {
select.setComment( getLockMode() + " lock " + getLockable().getEntityName() );

View File

@ -122,11 +122,11 @@ public class PessimisticReadUpdateLockingStrategy implements LockingStrategy {
protected String generateLockString() {
final SessionFactoryImplementor factory = lockable.getFactory();
final Update update = new Update( factory.getJdbcServices().getDialect() );
final Update update = new Update( factory );
update.setTableName( lockable.getRootTableName() );
update.addPrimaryKeyColumns( lockable.getRootTableIdentifierColumnNames() );
update.setVersionColumnName( lockable.getVersionColumnName() );
update.addColumn( lockable.getVersionColumnName() );
update.addAssignment( lockable.getVersionColumnName() );
update.addRestriction( lockable.getRootTableIdentifierColumnNames() );
update.addRestriction( lockable.getVersionColumnName() );
if ( factory.getSessionFactoryOptions().isCommentsEnabled() ) {
update.setComment( lockMode + " lock " + lockable.getEntityName() );
}

View File

@ -107,13 +107,13 @@ public class PessimisticWriteSelectLockingStrategy extends AbstractSelectLocking
final SessionFactoryImplementor factory = getLockable().getFactory();
final LockOptions lockOptions = new LockOptions( getLockMode() );
lockOptions.setTimeOut( lockTimeout );
final SimpleSelect select = new SimpleSelect( factory.getJdbcServices().getDialect() )
final SimpleSelect select = new SimpleSelect( factory )
.setLockOptions( lockOptions )
.setTableName( getLockable().getRootTableName() )
.addColumn( getLockable().getRootTableIdentifierColumnNames()[0] )
.addCondition( getLockable().getRootTableIdentifierColumnNames(), "=?" );
.addRestriction( getLockable().getRootTableIdentifierColumnNames() );
if ( getLockable().isVersioned() ) {
select.addCondition( getLockable().getVersionColumnName(), "=?" );
select.addRestriction( getLockable().getVersionColumnName() );
}
if ( factory.getSessionFactoryOptions().isCommentsEnabled() ) {
select.setComment( getLockMode() + " lock " + getLockable().getEntityName() );

View File

@ -120,11 +120,11 @@ public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy {
protected String generateLockString() {
final SessionFactoryImplementor factory = lockable.getFactory();
final Update update = new Update( factory.getJdbcServices().getDialect() );
final Update update = new Update( factory );
update.setTableName( lockable.getRootTableName() );
update.addPrimaryKeyColumns( lockable.getRootTableIdentifierColumnNames() );
update.setVersionColumnName( lockable.getVersionColumnName() );
update.addColumn( lockable.getVersionColumnName() );
update.addAssignment( lockable.getVersionColumnName() );
update.addRestriction( lockable.getRootTableIdentifierColumnNames() );
update.addRestriction( lockable.getVersionColumnName() );
if ( factory.getSessionFactoryOptions().isCommentsEnabled() ) {
update.setComment( lockMode + " lock " + lockable.getEntityName() );
}

View File

@ -102,13 +102,13 @@ public class SelectLockingStrategy extends AbstractSelectLockingStrategy {
final SessionFactoryImplementor factory = getLockable().getFactory();
final LockOptions lockOptions = new LockOptions( getLockMode() );
lockOptions.setTimeOut( timeout );
final SimpleSelect select = new SimpleSelect( factory.getJdbcServices().getDialect() )
final SimpleSelect select = new SimpleSelect( factory )
.setLockOptions( lockOptions )
.setTableName( getLockable().getRootTableName() )
.addColumn( getLockable().getRootTableIdentifierColumnNames()[0] )
.addCondition( getLockable().getRootTableIdentifierColumnNames(), "=?" );
.addRestriction( getLockable().getRootTableIdentifierColumnNames() );
if ( getLockable().isVersioned() ) {
select.addCondition( getLockable().getVersionColumnName(), "=?" );
select.addRestriction( getLockable().getVersionColumnName() );
}
if ( factory.getSessionFactoryOptions().isCommentsEnabled() ) {
select.setComment( getLockMode() + " lock " + getLockable().getEntityName() );

View File

@ -123,11 +123,11 @@ public class UpdateLockingStrategy implements LockingStrategy {
protected String generateLockString() {
final SessionFactoryImplementor factory = lockable.getFactory();
final Update update = new Update( factory.getJdbcServices().getDialect() );
final Update update = new Update( factory );
update.setTableName( lockable.getRootTableName() );
update.addPrimaryKeyColumns( lockable.getRootTableIdentifierColumnNames() );
update.setVersionColumnName( lockable.getVersionColumnName() );
update.addColumn( lockable.getVersionColumnName() );
update.addAssignment( lockable.getVersionColumnName() );
update.addRestriction( lockable.getRootTableIdentifierColumnNames() );
update.addRestriction( lockable.getVersionColumnName() );
if ( factory.getSessionFactoryOptions().isCommentsEnabled() ) {
update.setComment( lockMode + " lock " + lockable.getEntityName() );
}

View File

@ -33,7 +33,7 @@ public class BasicSelectingDelegate extends AbstractSelectingDelegate {
@Override @Deprecated
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( persister.getFactory() );
insert.addGeneratedColumns( persister.getRootTableKeyColumnNames(), (OnExecutionGenerator) persister.getGenerator() );
return insert;
}

View File

@ -51,7 +51,7 @@ public class GetGeneratedKeysDelegate extends AbstractReturningDelegate {
@Override @Deprecated
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( persister.getFactory() );
insert.addGeneratedColumns( persister.getRootTableKeyColumnNames(), (OnExecutionGenerator) persister.getGenerator() );
return insert;
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.id.insert;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.Insert;
/**
@ -16,7 +17,7 @@ import org.hibernate.sql.Insert;
* @author Steve Ebersole
*/
public class IdentifierGeneratingInsert extends Insert {
public IdentifierGeneratingInsert(Dialect dialect) {
super( dialect );
public IdentifierGeneratingInsert(SessionFactoryImplementor sessionFactory) {
super( sessionFactory );
}
}

View File

@ -45,7 +45,7 @@ public class InsertReturningDelegate extends AbstractReturningDelegate {
@Override @Deprecated
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
InsertSelectIdentityInsert insert = new InsertSelectIdentityInsert( dialect );
InsertSelectIdentityInsert insert = new InsertSelectIdentityInsert( persister.getFactory() );
insert.addGeneratedColumns( persister.getRootTableKeyColumnNames(), (OnExecutionGenerator) persister.getGenerator() );
return insert;
}

View File

@ -7,6 +7,7 @@
package org.hibernate.id.insert;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.Insert;
import org.hibernate.generator.OnExecutionGenerator;
@ -20,6 +21,10 @@ import org.hibernate.generator.OnExecutionGenerator;
public class InsertSelectIdentityInsert extends IdentifierGeneratingInsert {
protected String identityColumnName;
public InsertSelectIdentityInsert(SessionFactoryImplementor sessionFactory) {
super( sessionFactory );
}
public Insert addIdentityColumn(String columnName) {
identityColumnName = columnName;
return super.addIdentityColumn( columnName );
@ -36,10 +41,6 @@ public class InsertSelectIdentityInsert extends IdentifierGeneratingInsert {
return super.addGeneratedColumns( columnNames, generator );
}
public InsertSelectIdentityInsert(Dialect dialect) {
super( dialect );
}
public String toStatementString() {
return getDialect().getIdentityColumnSupport()
.appendIdentitySelectToInsert( identityColumnName, super.toStatementString() );

View File

@ -54,7 +54,7 @@ public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
@Override @Deprecated
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
return new IdentifierGeneratingInsert( dialect );
return new IdentifierGeneratingInsert( persister.getFactory() );
}
@Override

View File

@ -128,7 +128,6 @@ import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
@ -1023,7 +1022,7 @@ public abstract class AbstractCollectionPersister
"count(" + getElementColumnNames()[0] + ")"; // sets, maps, bags
return new SimpleSelect( getFactory() )
.setTableName( getTableName() )
.addCondition( getKeyColumnNames(), "=?" )
.addRestriction( getKeyColumnNames() )
.addWhereToken( sqlWhereString )
.addColumn( selectValue )
.toStatementString();
@ -1035,9 +1034,9 @@ public abstract class AbstractCollectionPersister
}
return new SimpleSelect( getFactory() )
.setTableName( getTableName() )
.addCondition( getKeyColumnNames(), "=?" )
.addCondition( getIndexColumnNames(), "=?" )
.addCondition( indexFormulas, "=?" )
.addRestriction( getKeyColumnNames() )
.addRestriction( getIndexColumnNames() )
.addRestriction( indexFormulas )
.addWhereToken( sqlWhereString )
.addColumn( "1" )
.toStatementString();
@ -1047,9 +1046,9 @@ public abstract class AbstractCollectionPersister
protected String generateDetectRowByElementString() {
return new SimpleSelect( getFactory() )
.setTableName( getTableName() )
.addCondition( getKeyColumnNames(), "=?" )
.addCondition( getElementColumnNames(), "=?" )
.addCondition( elementFormulas, "=?" )
.addRestriction( getKeyColumnNames() )
.addRestriction( getElementColumnNames() )
.addRestriction( elementFormulas )
.addWhereToken( sqlWhereString )
.addColumn( "1" )
.toStatementString();

View File

@ -1880,8 +1880,7 @@ public abstract class AbstractEntityPersister
* Generate the SQL that selects the version number by id
*/
public String generateSelectVersionString() {
final SimpleSelect select = new SimpleSelect( getFactory().getJdbcServices().getDialect() )
.setTableName( getVersionedTableName() );
final SimpleSelect select = new SimpleSelect( getFactory() ).setTableName( getVersionedTableName() );
if ( isVersioned() ) {
select.addColumn( getVersionColumnName(), VERSION_COLUMN_ALIAS );
}
@ -1891,7 +1890,7 @@ public abstract class AbstractEntityPersister
if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
select.setComment( "get version " + getEntityName() );
}
return select.addCondition( rootTableKeyColumnNames, "=?" ).toStatementString();
return select.addRestriction( rootTableKeyColumnNames ).toStatementString();
}
private GeneratedValuesProcessor createGeneratedValuesProcessor(EventType timing) {
@ -2711,12 +2710,11 @@ public abstract class AbstractEntityPersister
@Override
public String getSelectByUniqueKeyString(String[] propertyNames) {
final SimpleSelect select =
new SimpleSelect( getFactory().getJdbcServices().getDialect() )
.setTableName( getTableName(0) )
.addColumns( getKeyColumns(0) );
final SimpleSelect select = new SimpleSelect( getFactory() )
.setTableName( getTableName(0) )
.addColumns( getKeyColumns(0) );
for ( int i = 0; i < propertyNames.length; i++ ) {
select.addCondition( getPropertyColumnNames( propertyNames[i] ), "= ?" );
select.addRestriction( getPropertyColumnNames( propertyNames[i] ) );
}
return select.toStatementString();
}
@ -6010,9 +6008,9 @@ public abstract class AbstractEntityPersister
@Deprecated(forRemoval = true)
@Remove
public String generateDeleteString(int j) {
final Delete delete = new Delete()
final Delete delete = new Delete( getFactory() )
.setTableName( getTableName( j ) )
.addPrimaryKeyColumns( getKeyColumns( j ) );
.addColumnRestriction( getKeyColumns( j ) );
if ( j == 0 ) {
delete.setVersionColumnName( getVersionColumnName() );
}
@ -6108,9 +6106,9 @@ public abstract class AbstractEntityPersister
int span = getTableSpan();
String[] deleteStrings = new String[span];
for ( int j = span - 1; j >= 0; j-- ) {
final Delete delete = new Delete()
final Delete delete = new Delete( getFactory() )
.setTableName( getTableName( j ) )
.addPrimaryKeyColumns( getKeyColumns( j ) );
.addColumnRestriction( getKeyColumns( j ) );
if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
delete.setComment( "delete " + getEntityName() + " [" + j + "]" );
}
@ -6125,10 +6123,10 @@ public abstract class AbstractEntityPersister
boolean[] propertyNullness = types[i].toColumnNullness( loadedState[i], getFactory() );
for ( int k = 0; k < propertyNullness.length; k++ ) {
if ( propertyNullness[k] ) {
delete.addWhereFragment( propertyColumnNames[k] + " = ?" );
delete.addColumnRestriction( propertyColumnNames[k] );
}
else {
delete.addWhereFragment( propertyColumnNames[k] + " is null" );
delete.addColumnNullnessRestriction( propertyColumnNames[k] );
}
}
}

View File

@ -0,0 +1,48 @@
/*
* 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;
import org.hibernate.Internal;
/**
* A binary-comparison restriction
*
* @author Steve Ebersole
*/
@Internal
public class ComparisonRestriction implements Restriction {
private final String lhs;
private final String operator;
private final String rhs;
public ComparisonRestriction(String lhs) {
this( lhs, "?" );
}
public ComparisonRestriction(String lhs, String rhs) {
this( lhs, "=", rhs );
}
public ComparisonRestriction(String lhs, String operator, String rhs) {
this.lhs = lhs;
this.operator = operator;
this.rhs = rhs;
}
@Override
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
sqlBuffer.append( lhs );
sqlBuffer.append( operator );
if ( "?".equals( rhs ) ) {
sqlBuffer.append( context.makeParameterMarker() );
}
else {
sqlBuffer.append( rhs );
}
}
}

View File

@ -0,0 +1,28 @@
/*
* 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;
import org.hibernate.Internal;
/**
* For a complete predicate. E.g. {@link org.hibernate.annotations.Where}
*
* @author Steve Ebersole
*/
@Internal
public class CompleteRestriction implements Restriction {
private final String predicate;
public CompleteRestriction(String predicate) {
this.predicate = predicate;
}
@Override
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
sqlBuffer.append( predicate );
}
}

View File

@ -5,12 +5,16 @@
* 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;
/**
* A SQL {@code DELETE} statement.
@ -21,15 +25,21 @@ import org.hibernate.dialect.Dialect;
public class Delete {
protected String tableName;
protected String versionColumnName;
protected String where;
protected String comment;
protected Map<String,String> primaryKeyColumns = new LinkedHashMap<>();
protected final List<String> whereFragments = new ArrayList<>();
public Delete setComment(String comment) {
this.comment = comment;
return this;
private final JdbcParameterRenderer jdbcParameterRenderer;
private final boolean standardParamRendering;
private int parameterCount;
public Delete(SessionFactoryImplementor factory) {
this( factory.getServiceRegistry().getService( JdbcParameterRenderer.class ) );
}
public Delete(JdbcParameterRenderer jdbcParameterRenderer) {
this.jdbcParameterRenderer = jdbcParameterRenderer;
this.standardParamRendering = JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer );
}
public Delete setTableName(String tableName) {
@ -37,93 +47,80 @@ public class Delete {
return this;
}
public String toStatementString() {
StringBuilder buf = new StringBuilder( tableName.length() + 10 );
if ( comment!=null ) {
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
}
buf.append( "delete from " ).append(tableName);
if ( where != null || !primaryKeyColumns.isEmpty() || versionColumnName != null ) {
buf.append( " where " );
}
boolean conditionsAppended = false;
Iterator<Map.Entry<String,String>> iter = primaryKeyColumns.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry<String,String> e = iter.next();
buf.append( e.getKey() ).append( '=' ).append( e.getValue() );
if ( iter.hasNext() ) {
buf.append( " and " );
public Delete setComment(String comment) {
this.comment = comment;
return this;
}
@SuppressWarnings("UnusedReturnValue")
public Delete addColumnRestriction(String columnName) {
final String paramMarker = jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null );
this.whereFragments.add( columnName + "=" + paramMarker );
return this;
}
@SuppressWarnings("UnusedReturnValue")
public Delete addColumnRestriction(String... columnNames) {
for ( int i = 0; i < columnNames.length; i++ ) {
if ( columnNames[i] == null ) {
continue;
}
conditionsAppended = true;
}
if ( where!=null ) {
if ( conditionsAppended ) {
buf.append( " and " );
}
buf.append( where );
conditionsAppended = true;
}
if ( versionColumnName!=null ) {
if ( conditionsAppended ) {
buf.append( " and " );
}
buf.append( versionColumnName ).append( "=?" );
}
return buf.toString();
}
public Delete setWhere(String where) {
this.where=where;
return this;
}
public Delete addWhereFragment(String fragment) {
if ( where == null ) {
where = fragment;
}
else {
where += ( " and " + fragment );
addColumnRestriction( columnNames[i] );
}
return this;
}
public Delete setPrimaryKeyColumnNames(String[] columnNames) {
this.primaryKeyColumns.clear();
addPrimaryKeyColumns(columnNames);
@SuppressWarnings("UnusedReturnValue")
public Delete addColumnNullnessRestriction(String columnName) {
addColumnNullnessRestriction( columnName, false );
return this;
}
public Delete addPrimaryKeyColumns(String[] columnNames) {
for ( String columnName : columnNames ) {
addPrimaryKeyColumn( columnName, "?" );
}
return this;
}
public Delete addPrimaryKeyColumns(String[] columnNames, boolean[] includeColumns, String[] valueExpressions) {
for ( int i=0; i<columnNames.length; i++ ) {
if( includeColumns[i] ) {
addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
}
}
return this;
}
public Delete addPrimaryKeyColumns(String[] columnNames, String[] valueExpressions) {
for ( int i=0; i<columnNames.length; i++ ) {
addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
}
return this;
}
public Delete addPrimaryKeyColumn(String columnName, String valueExpression) {
this.primaryKeyColumns.put(columnName, valueExpression);
@SuppressWarnings("UnusedReturnValue")
public Delete addColumnNullnessRestriction(String columnName, boolean negate) {
final String fragment = negate
? columnName + " is not null"
: columnName + " is null";
whereFragments.add( fragment );
return this;
}
public Delete setVersionColumnName(String versionColumnName) {
this.versionColumnName = versionColumnName;
if ( versionColumnName != null ) {
addColumnRestriction( versionColumnName );
}
return this;
}
public String toStatementString() {
final StringBuilder buf = new StringBuilder( tableName.length() + 10 );
applyComment( buf );
buf.append( "delete from " ).append( tableName );
applyRestrictions( buf );
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( " */ " );
}
}
}

View File

@ -5,7 +5,7 @@
* 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.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@ -14,7 +14,11 @@ import org.hibernate.Internal;
import org.hibernate.MappingException;
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 static org.hibernate.sql.ast.spi.JdbcParameterRenderer.isStandardRenderer;
/**
* A SQL {@code INSERT} statement.
@ -23,16 +27,28 @@ import org.hibernate.generator.OnExecutionGenerator;
*/
@Internal
public class Insert {
private final Dialect dialect;
protected String tableName;
protected String comment;
protected Map<String,String> columns = new LinkedHashMap<>();
protected Map<String,String> lobColumns;
public Insert(Dialect dialect) {
private final Dialect dialect;
private final JdbcParameterRenderer jdbcParameterRenderer;
private final boolean standardParamRendering;
private int parameterCount;
public Insert(SessionFactoryImplementor sessionFactory) {
this(
sessionFactory.getJdbcServices().getDialect(),
sessionFactory.getServiceRegistry().getService( JdbcParameterRenderer.class )
);
}
public Insert(Dialect dialect, JdbcParameterRenderer jdbcParameterRenderer) {
this.dialect = dialect;
this.jdbcParameterRenderer = jdbcParameterRenderer;
this.standardParamRendering = isStandardRenderer( jdbcParameterRenderer );
}
protected Dialect getDialect() {
@ -82,14 +98,6 @@ public class Insert {
return this;
}
public void addLobColumn(String columnName, String valueExpression) {
assert dialect.forceLobAsLastValue();
if ( lobColumns == null ) {
lobColumns = new HashMap<>();
}
lobColumns.put( columnName, valueExpression );
}
public Insert addIdentityColumn(String columnName) {
final IdentityColumnSupport identityColumnSupport = dialect.getIdentityColumnSupport();
if ( identityColumnSupport.hasIdentityInsertKeyword() ) {
@ -117,14 +125,15 @@ public class Insert {
}
public String toStatementString() {
StringBuilder buf = new StringBuilder( columns.size()*15 + tableName.length() + 10 );
final StringBuilder buf = new StringBuilder( columns.size()*15 + tableName.length() + 10 );
if ( comment != null ) {
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
}
buf.append("insert into ").append(tableName);
buf.append( "insert into " ).append( tableName );
if ( columns.size()==0 && lobColumns == null ) {
if ( columns.isEmpty() ) {
if ( dialect.supportsNoColumnsInsert() ) {
buf.append( ' ' ).append( dialect.getNoColumnsInsertString() );
}
@ -140,51 +149,38 @@ public class Insert {
}
else {
buf.append( " (" );
renderColumnsClause( buf );
renderInsertionSpec( buf );
buf.append( ") values (" );
renderValuesClause( buf );
buf.append(')');
renderRowValues( buf );
buf.append( ')' );
}
return buf.toString();
}
private void renderColumnsClause(StringBuilder buf) {
private void renderInsertionSpec(StringBuilder buf) {
final Iterator<String> itr = columns.keySet().iterator();
while ( itr.hasNext() ) {
buf.append( itr.next() );
if ( itr.hasNext() || lobColumns != null ) {
if ( itr.hasNext() ) {
buf.append( ", " );
}
}
if ( lobColumns != null ) {
final Iterator<String> columnsAtEndItr = lobColumns.keySet().iterator();
while ( columnsAtEndItr.hasNext() ) {
buf.append( columnsAtEndItr.next() );
if ( columnsAtEndItr.hasNext() ) {
buf.append( ", " );
}
}
}
}
private void renderValuesClause(StringBuilder buf) {
private void renderRowValues(StringBuilder buf) {
final Iterator<String> itr = columns.values().iterator();
while ( itr.hasNext() ) {
buf.append( itr.next() );
if ( itr.hasNext() || lobColumns != null ) {
buf.append( normalizeExpressionFragment( itr.next() ) );
if ( itr.hasNext() ) {
buf.append( ", " );
}
}
}
if ( lobColumns != null ) {
final Iterator<String> columnsAtEndItr = lobColumns.values().iterator();
while ( columnsAtEndItr.hasNext() ) {
buf.append( columnsAtEndItr.next() );
if ( columnsAtEndItr.hasNext() ) {
buf.append( ", " );
}
}
}
private String normalizeExpressionFragment(String rhs) {
return rhs.equals( "?" ) && !standardParamRendering
? jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null )
: rhs;
}
}

View File

@ -0,0 +1,40 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.sql;
import org.hibernate.Internal;
/**
* Nullness restriction - is [not] null
*
* @author Steve Ebersole
*/
@Internal
public class NullnessRestriction implements Restriction {
private final String columnName;
private final boolean negated;
public NullnessRestriction(String columnName) {
this( columnName, false );
}
public NullnessRestriction(String columnName, boolean negated) {
this.columnName = columnName;
this.negated = negated;
}
@Override
public void render(StringBuilder sqlBuffer, RestrictionRenderingContext context) {
sqlBuffer.append( columnName );
if ( negated ) {
sqlBuffer.append( " is not null" );
}
else {
sqlBuffer.append( " is null" );
}
}
}

View File

@ -0,0 +1,22 @@
/*
* 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;
import org.hibernate.Internal;
/**
* A restriction (predicate) to be applied to a query
*
* @author Steve Ebersole
*/
@Internal
public interface Restriction {
/**
* Render the restriction into the SQL buffer
*/
void render(StringBuilder sqlBuffer, RestrictionRenderingContext context);
}

View File

@ -0,0 +1,17 @@
/*
* 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;
import org.hibernate.Internal;
/**
* @author Steve Ebersole
*/
@Internal
public interface RestrictionRenderingContext {
String makeParameterMarker();
}

View File

@ -9,7 +9,6 @@ package org.hibernate.sql;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -27,47 +26,44 @@ import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
* @author Gavin King
*/
@Internal
public class SimpleSelect {
public class SimpleSelect implements RestrictionRenderingContext {
protected String tableName;
protected String orderBy;
protected String comment;
protected List<String> columns = new ArrayList<>();
protected Map<String, String> aliases = new HashMap<>();
protected List<String> whereTokens = new ArrayList<>();
protected List<Restriction> restrictions = new ArrayList<>();
protected LockOptions lockOptions = new LockOptions( LockMode.READ );
private final SessionFactoryImplementor factory;
private final Dialect dialect;
private JdbcParameterRenderer _jdbcParameterRenderer;
private final JdbcParameterRenderer jdbcParameterRenderer;
private int parameterCount;
public SimpleSelect(SessionFactoryImplementor factory) {
this.factory = factory;
this.dialect = factory.getJdbcServices().getDialect();
this.jdbcParameterRenderer = factory.getServiceRegistry().getService( JdbcParameterRenderer.class );
}
//private static final Alias DEFAULT_ALIAS = new Alias(10, null);
@Override
public String makeParameterMarker() {
return jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null );
}
public SimpleSelect addColumns(String[] columnNames, String[] columnAliases) {
for ( int i = 0; i < columnNames.length; i++ ) {
if ( columnNames[i] != null ) {
addColumn( columnNames[i], columnAliases[i] );
}
}
return this;
}
public SimpleSelect addColumns(String[] columns, String[] aliases, boolean[] ignore) {
for ( int i = 0; i < ignore.length; i++ ) {
if ( !ignore[i] && columns[i] != null ) {
addColumn( columns[i], aliases[i] );
}
}
/**
* Sets the name of the table we are selecting from
*/
public SimpleSelect setTableName(String tableName) {
this.tableName = tableName;
return this;
}
/**
* Adds selections
*/
public SimpleSelect addColumns(String[] columnNames) {
for ( String columnName : columnNames ) {
if ( columnName != null ) {
@ -77,20 +73,66 @@ public class SimpleSelect {
return this;
}
/**
* Adds a selection
*/
public SimpleSelect addColumn(String columnName) {
columns.add( columnName );
//aliases.put( columnName, DEFAULT_ALIAS.toAliasString(columnName) );
return this;
}
/**
* Adds a selection, with an alias
*/
public SimpleSelect addColumn(String columnName, String alias) {
columns.add( columnName );
aliases.put( columnName, alias );
return this;
}
public SimpleSelect setTableName(String tableName) {
this.tableName = tableName;
/**
* Appends a complete {@linkplain org.hibernate.annotations.Where where} condition.
* The {@code condition} is added as-is.
*/
public SimpleSelect addWhereToken(String condition) {
if ( condition != null ) {
restrictions.add( new CompleteRestriction( condition ) );
}
return this;
}
/**
* Appends a restriction comparing the {@code columnName} for equality with a parameter
*
* @see #addRestriction(String, String, String)
*/
public SimpleSelect addRestriction(String columnName) {
restrictions.add( new ComparisonRestriction( columnName ) );
return this;
}
/**
* 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}
* if needed.
*/
public SimpleSelect addRestriction(String lhs, String op, String rhs) {
restrictions.add( new ComparisonRestriction( lhs, op, rhs ) );
return this;
}
/**
* Appends a restriction comparing each name in {@code columnNames} for equality with a parameter
*
* @see #addRestriction(String)
*/
public SimpleSelect addRestriction(String... columnNames) {
for ( int i = 0; i < columnNames.length; i++ ) {
if ( columnNames[i] != null ) {
addRestriction( columnNames[i] );
}
}
return this;
}
@ -104,114 +146,6 @@ public class SimpleSelect {
return this;
}
/**
* Appends a complete {@linkplain org.hibernate.annotations.Where where} fragment. The {@code token} is added as-is
*/
public SimpleSelect addWhereToken(String token) {
if (token != null ) {
and();
whereTokens.add( token );
}
return this;
}
private void and() {
if ( !whereTokens.isEmpty() ) {
whereTokens.add( "and" );
}
}
private JdbcParameterRenderer jdbcParameterRenderer() {
if ( _jdbcParameterRenderer == null ) {
_jdbcParameterRenderer = factory.getServiceRegistry().getService( JdbcParameterRenderer.class );
}
return _jdbcParameterRenderer;
}
public SimpleSelect addCondition(String lhs, String op, String rhs) {
and();
whereTokens.add( lhs + ' ' + op + ' ' + rhs );
return this;
}
public SimpleSelect addCondition(String lhs, String condition) {
and();
whereTokens.add( lhs + ' ' + condition );
return this;
}
public SimpleSelect addCondition(String[] lhs, String condition) {
for ( String lh : lhs ) {
if ( lh != null ) {
addCondition( lh, condition );
}
}
return this;
}
public String toStatementString() {
StringBuilder buf = new StringBuilder(
columns.size() * 10 +
tableName.length() +
whereTokens.size() * 10 +
10
);
if ( comment != null ) {
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
}
buf.append( "select " );
Set<String> uniqueColumns = new HashSet<>();
Iterator<String> iter = columns.iterator();
boolean appendComma = false;
while ( iter.hasNext() ) {
String col = iter.next();
String alias = aliases.get( col );
if ( uniqueColumns.add( alias == null ? col : alias ) ) {
if ( appendComma ) {
buf.append( ", " );
}
buf.append( col );
if ( alias != null && !alias.equals( col ) ) {
buf.append( " as " )
.append( alias );
}
appendComma = true;
}
}
buf.append( " from " )
.append( dialect.appendLockHint( lockOptions, tableName ) );
if ( whereTokens.size() > 0 ) {
buf.append( " where " )
.append( toWhereClause() );
}
if ( orderBy != null ) {
buf.append( orderBy );
}
if ( lockOptions != null ) {
buf = new StringBuilder( dialect.applyLocksToSql( buf.toString(), lockOptions, null ) );
}
return dialect.transformSelectString( buf.toString() );
}
public String toWhereClause() {
StringBuilder buf = new StringBuilder( whereTokens.size() * 5 );
Iterator<String> iter = whereTokens.iterator();
while ( iter.hasNext() ) {
buf.append( iter.next() );
if ( iter.hasNext() ) {
buf.append( ' ' );
}
}
return buf.toString();
}
public SimpleSelect setOrderBy(String orderBy) {
this.orderBy = orderBy;
return this;
@ -222,4 +156,80 @@ public class SimpleSelect {
return this;
}
public String toStatementString() {
final StringBuilder buf = new StringBuilder(
columns.size() * 10 +
tableName.length() +
restrictions.size() * 10 +
10
);
applyComment( buf );
applySelectClause( buf );
applyFromClause( buf );
applyWhereClause( buf );
applyOrderBy( buf );
final String selectString = (lockOptions != null)
? dialect.applyLocksToSql( buf.toString(), lockOptions, null )
: buf.toString();
return dialect.transformSelectString( selectString );
}
private void applyComment(StringBuilder buf) {
if ( comment != null ) {
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
}
}
private void applySelectClause(StringBuilder buf) {
buf.append( "select " );
boolean appendComma = false;
final Set<String> uniqueColumns = new HashSet<>();
for ( int i = 0; i < columns.size(); i++ ) {
final String col = columns.get( i );
final String alias = aliases.get( col );
if ( uniqueColumns.add( alias == null ? col : alias ) ) {
if ( appendComma ) {
buf.append( ", " );
}
buf.append( col );
if ( alias != null && !alias.equals( col ) ) {
buf.append( " as " ).append( alias );
}
appendComma = true;
}
}
}
private void applyFromClause(StringBuilder buf) {
buf.append( " from " ).append( dialect.appendLockHint( lockOptions, tableName ) );
}
private void applyWhereClause(StringBuilder buf) {
if ( restrictions.isEmpty() ) {
return;
}
buf.append( " where " );
for ( int i = 0; i < restrictions.size(); i++ ) {
if ( i > 0 ) {
buf.append( " and " );
}
final Restriction restriction = restrictions.get( i );
restriction.render( buf, this );
}
}
private void applyOrderBy(StringBuilder buf) {
if ( orderBy != null ) {
buf.append( ' ' ).append( orderBy );
}
}
}

View File

@ -5,14 +5,16 @@
* 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.HashMap;
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.metamodel.mapping.ModelPart;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
/**
* A SQL {@code UPDATE} statement.
@ -20,223 +22,142 @@ import org.hibernate.metamodel.mapping.ModelPart;
* @author Gavin King
*/
@Internal
public class Update {
public class Update implements RestrictionRenderingContext {
protected String tableName;
protected String versionColumnName;
protected String where;
protected String assignments;
protected String comment;
protected Map<String,String> assignments = new LinkedHashMap<>();
protected List<Restriction> restrictions = new ArrayList<>();
protected Map<String,String> primaryKeyColumns = new LinkedHashMap<>();
protected Map<String,String> columns = new LinkedHashMap<>();
protected Map<String,String> lobColumns;
protected Map<String,String> whereColumns = new LinkedHashMap<>();
private final JdbcParameterRenderer jdbcParameterRenderer;
private final boolean standardParamRendering;
private int parameterCount;
private Dialect dialect;
public Update(SessionFactoryImplementor factory) {
this( factory.getServiceRegistry().getService( JdbcParameterRenderer.class ) );
}
public Update(Dialect dialect) {
this.dialect = dialect;
public Update(JdbcParameterRenderer jdbcParameterRenderer) {
this.jdbcParameterRenderer = jdbcParameterRenderer;
this.standardParamRendering = JdbcParameterRenderer.isStandardRenderer( jdbcParameterRenderer );
}
public String getTableName() {
return tableName;
}
public Update appendAssignmentFragment(String fragment) {
if ( assignments == null ) {
assignments = fragment;
}
else {
assignments += ", " + fragment;
}
return this;
}
public Update setTableName(String tableName) {
this.tableName = tableName;
return this;
}
public Update setPrimaryKeyColumnNames(String[] columnNames) {
this.primaryKeyColumns.clear();
addPrimaryKeyColumns(columnNames);
return this;
}
public Update addPrimaryKeyColumns(String[] columnNames) {
for ( String columnName : columnNames ) {
addPrimaryKeyColumn( columnName, "?" );
}
return this;
}
public Update addPrimaryKeyColumns(ModelPart keyPart) {
keyPart.forEachSelectable( (selectionIndex, selectableMapping) -> {
addPrimaryKeyColumn( selectableMapping.getSelectionExpression(), "?" );
} );
return this;
}
public Update addPrimaryKeyColumns(String[] columnNames, boolean[] includeColumns, String[] valueExpressions) {
for ( int i=0; i<columnNames.length; i++ ) {
if( includeColumns[i] ) {
addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
}
}
return this;
}
public Update addPrimaryKeyColumns(String[] columnNames, String[] valueExpressions) {
for ( int i=0; i<columnNames.length; i++ ) {
addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
}
return this;
}
public Update addPrimaryKeyColumn(String columnName, String valueExpression) {
this.primaryKeyColumns.put(columnName, valueExpression);
return this;
}
public Update setVersionColumnName(String versionColumnName) {
this.versionColumnName = versionColumnName;
return this;
}
public Update setComment(String comment) {
this.comment = comment;
return this;
}
public Update addColumns(String[] columnNames) {
public Update addAssignments(String... columnNames) {
for ( String columnName : columnNames ) {
addColumn( columnName );
addAssignment( columnName );
}
return this;
}
public Update addColumns(String[] columnNames, boolean[] updateable, String[] valueExpressions) {
for ( int i=0; i<columnNames.length; i++ ) {
if ( updateable[i] ) {
addColumn( columnNames[i], valueExpressions[i] );
public Update addAssignment(String columnName) {
return addAssignment( columnName, "?" );
}
public Update addAssignment(String columnName, String valueExpression) {
assignments.put( columnName, valueExpression );
return this;
}
public Update addRestriction(String column) {
restrictions.add( new ComparisonRestriction( column ) );
return this;
}
public Update addRestriction(String... columns) {
for ( int i = 0; i < columns.length; i++ ) {
final String columnName = columns[ i ];
if ( columnName != null ) {
addRestriction( columnName );
}
}
return this;
}
public Update addColumns(String[] columnNames, String valueExpression) {
for ( String columnName : columnNames ) {
addColumn( columnName, valueExpression );
}
public Update addRestriction(String column, String value) {
restrictions.add( new ComparisonRestriction( column, value ) );
return this;
}
public Update addColumn(String columnName) {
return addColumn(columnName, "?");
}
public Update addColumn(String columnName, String valueExpression) {
columns.put(columnName, valueExpression);
public Update addRestriction(String column, String op, String value) {
restrictions.add( new ComparisonRestriction( column, op, value ) );
return this;
}
public void addLobColumn(String columnName, String valueExpression) {
assert dialect.forceLobAsLastValue();
if ( lobColumns == null ) {
lobColumns = new HashMap<>();
}
lobColumns.put( columnName, valueExpression );
private String normalizeExpressionFragment(String rhs) {
return rhs.equals( "?" ) && !standardParamRendering
? jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null )
: rhs;
}
public Update addWhereColumns(String[] columnNames) {
for ( String columnName : columnNames ) {
addWhereColumn( columnName );
}
return this;
}
public Update addWhereColumns(String[] columnNames, String valueExpression) {
for ( String columnName : columnNames ) {
addWhereColumn( columnName, valueExpression );
}
return this;
}
public Update addWhereColumn(String columnName) {
return addWhereColumn(columnName, "=?");
}
public Update addWhereColumn(String columnName, String valueExpression) {
whereColumns.put(columnName, valueExpression);
return this;
}
public Update setWhere(String where) {
this.where=where;
public Update addNullnessRestriction(String column) {
restrictions.add( new NullnessRestriction( column ) );
return this;
}
public String toStatementString() {
StringBuilder buf = new StringBuilder( (columns.size() * 15) + tableName.length() + 10 );
if ( comment!=null ) {
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
}
buf.append( "update " ).append( tableName ).append( " set " );
boolean assignmentsAppended = false;
Iterator<Map.Entry<String,String>> iter = columns.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry<String,String> e = iter.next();
buf.append( e.getKey() ).append( '=' ).append( e.getValue() );
if ( iter.hasNext() ) {
buf.append( ", " );
}
assignmentsAppended = true;
}
if ( assignments != null ) {
if ( assignmentsAppended ) {
buf.append( ", " );
}
buf.append( assignments );
}
final StringBuilder buf = new StringBuilder( ( assignments.size() * 15) + tableName.length() + 10 );
boolean conditionsAppended = false;
if ( !primaryKeyColumns.isEmpty() || where != null || !whereColumns.isEmpty() || versionColumnName != null ) {
buf.append( " where " );
}
iter = primaryKeyColumns.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry<String,String> e = iter.next();
buf.append( e.getKey() ).append( '=' ).append( e.getValue() );
if ( iter.hasNext() ) {
buf.append( " and " );
}
conditionsAppended = true;
}
if ( where != null ) {
if ( conditionsAppended ) {
buf.append( " and " );
}
buf.append( where );
conditionsAppended = true;
}
iter = whereColumns.entrySet().iterator();
while ( iter.hasNext() ) {
final Map.Entry<String,String> e = iter.next();
if ( conditionsAppended ) {
buf.append( " and " );
}
buf.append( e.getKey() ).append( e.getValue() );
conditionsAppended = true;
}
if ( versionColumnName != null ) {
if ( conditionsAppended ) {
buf.append( " and " );
}
buf.append( versionColumnName ).append( "=?" );
}
applyComment( buf );
buf.append( "update " ).append( tableName );
applyAssignments( buf );
applyRestrictions( buf );
return buf.toString();
}
private void applyComment(StringBuilder buf) {
if ( comment != null ) {
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
}
}
private void applyAssignments(StringBuilder buf) {
buf.append( " set " );
final Iterator<Map.Entry<String,String>> entries = assignments.entrySet().iterator();
while ( entries.hasNext() ) {
final Map.Entry<String,String> entry = entries.next();
buf.append( entry.getKey() )
.append( '=' )
.append( normalizeExpressionFragment( entry.getValue() ) );
if ( entries.hasNext() ) {
buf.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 " );
}
final Restriction restriction = restrictions.get( i );
restriction.render( buf, this );
}
}
@Override
public String makeParameterMarker() {
return jdbcParameterRenderer.renderJdbcParameter( ++parameterCount, null );
}
}

View File

@ -6,9 +6,7 @@
*/
package org.hibernate.sql.ast.internal;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.JdbcParameterRenderer;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.jdbc.JdbcType;
/**
@ -21,7 +19,7 @@ public class JdbcParameterRendererStandard implements JdbcParameterRenderer {
public static final JdbcParameterRendererStandard INSTANCE = new JdbcParameterRendererStandard();
@Override
public void renderJdbcParameter(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
jdbcType.appendWriteExpression( "?", appender, dialect );
public String renderJdbcParameter(int position, JdbcType jdbcType) {
return "?";
}
}

View File

@ -203,6 +203,7 @@ import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.sql.DdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
@ -6191,12 +6192,10 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
protected void renderParameterAsParameter(JdbcParameter jdbcParameter, int position) {
jdbcParameterRenderer.renderJdbcParameter(
position,
jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType(),
this,
getDialect()
);
final JdbcType jdbcType = jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType();
assert jdbcType != null;
final String parameterMarker = jdbcParameterRenderer.renderJdbcParameter( position, jdbcType );
jdbcType.appendWriteExpression( parameterMarker, this, dialect );
}
@Override

View File

@ -6,14 +6,21 @@
*/
package org.hibernate.sql.ast.spi;
import org.hibernate.dialect.Dialect;
import org.hibernate.service.Service;
import org.hibernate.sql.ast.internal.JdbcParameterRendererStandard;
import org.hibernate.type.descriptor.jdbc.JdbcType;
/**
* Extension point, intended for use from Hibernate Reactive, to render JDBC
* parameter placeholders into the SQL query string being generated.
* 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
*/
@ -22,11 +29,9 @@ public interface JdbcParameterRenderer extends Service {
* Render the parameter for the given position
*
* @param position The 1-based position of the parameter.
* @param jdbcType The type of the parameter
* @param appender The appender where the parameter should be rendered
* @param dialect The Dialect in use within the SessionFactory
* @param jdbcType The type of the parameter, if known
*/
void renderJdbcParameter(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect);
String renderJdbcParameter(int position, JdbcType jdbcType);
static boolean isStandardRenderer(JdbcParameterRenderer check) {
return check == null || JdbcParameterRendererStandard.class.equals( check.getClass() );

View File

@ -297,7 +297,7 @@ public class OrderByTest extends BaseCoreFunctionalTestCase {
try {
final QueryableCollection queryableCollection = (QueryableCollection) transactionsPersister;
SimpleSelect select = new SimpleSelect( sessionFactory().getJdbcServices().getDialect() )
SimpleSelect select = new SimpleSelect( sessionFactory() )
.setTableName( queryableCollection.getTableName() )
.addColumn( "code" )
.addColumn( "transactions_index" );

View File

@ -72,11 +72,11 @@ public class PersistentListTest {
session2.doWork(
connection -> {
final QueryableCollection queryableCollection = (QueryableCollection) collectionPersister;
SimpleSelect select = new SimpleSelect( sessionFactory.getJdbcServices().getDialect() )
SimpleSelect select = new SimpleSelect( sessionFactory )
.setTableName( queryableCollection.getTableName() )
.addColumn( "NAME" )
.addColumn( "LIST_INDEX" )
.addCondition( "NAME", "<>", "?" );
.addRestriction( "NAME", "<>", "?" );
PreparedStatement preparedStatement = ( (SessionImplementor) session2 ).getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( select.toStatementString() );
@ -133,7 +133,7 @@ public class PersistentListTest {
session2.doWork(
connection -> {
final QueryableCollection queryableCollection = (QueryableCollection) collectionPersister;
SimpleSelect select = new SimpleSelect( sessionFactory.getJdbcServices().getDialect() )
SimpleSelect select = new SimpleSelect( sessionFactory )
.setTableName( queryableCollection.getTableName() )
.addColumn( "order_id" )
.addColumn( "INDX" )

View File

@ -109,8 +109,8 @@ public class JdbcParameterRendererTests {
public static class JdbcParameterRendererImpl implements JdbcParameterRenderer {
@Override
public void renderJdbcParameter(int position, JdbcType jdbcType, SqlAppender appender, Dialect dialect) {
jdbcType.appendWriteExpression( "?" + position, appender, dialect );
public String renderJdbcParameter(int position, JdbcType jdbcType) {
return "?" + position;
}
}

View File

@ -561,7 +561,7 @@ public class ValidityAuditStrategy implements AuditStrategy {
final String revEndColumnName = rootAuditEntity.findAttributeMapping( revEndAttributeName )
.getSelectable( 0 )
.getSelectionExpression();
context.addColumn( revEndColumnName );
context.addAssignment( revEndColumnName );
context.bind( revisionNumber, revisionEntity.getIdentifierMapping() );
if ( configuration.isRevisionEndTimestampEnabled() ) {
@ -569,22 +569,22 @@ public class ValidityAuditStrategy implements AuditStrategy {
final String revEndTimestampAttributeName = configuration.getRevisionEndTimestampFieldName();
final AttributeMapping revEndTimestampAttributeMapping = rootAuditEntity.findAttributeMapping( revEndTimestampAttributeName );
// Apply optional "[, REVEND_TSTMP = ?]" portion of the SQL
context.addColumn( revEndTimestampAttributeMapping.getSelectable( 0 ).getSelectionExpression() );
context.addAssignment( revEndTimestampAttributeMapping.getSelectable( 0 ).getSelectionExpression() );
context.bind( getRevEndTimestampValue( configuration, revisionTimestamp ), revEndTimestampAttributeMapping );
}
// Apply "WHERE (entity_id) = ?"
context.addPrimaryKeyColumns( rootEntity.getIdentifierColumnNames() );
context.addRestriction( rootEntity.getIdentifierColumnNames() );
context.bind( id, rootEntity.getIdentifierMapping() );
// Apply "AND REV <> ?"
// todo (PropertyMapping) : need to be able to handle paths
final String path = configuration.getRevisionNumberPath();
context.addWhereColumn( rootAuditEntity.toColumns( path )[ 0 ], " <> ?" );
context.addRestriction( rootAuditEntity.toColumns( path )[ 0 ], "<>", "?" );
context.bind( revisionNumber, rootAuditEntity.getPropertyType( path ) );
// Apply "AND REVEND is null"
context.addWhereColumn( revEndColumnName, " is null" );
context.addNullnessRestriction( revEndColumnName );
return context;
}
@ -623,23 +623,23 @@ public class ValidityAuditStrategy implements AuditStrategy {
final String revEndTimestampAttributeName = configuration.getRevisionEndTimestampFieldName();
final AttributeMapping revEndTimestampAttributeMapping = auditEntity.findAttributeMapping( revEndTimestampAttributeName );
final String revEndTimestampColumnName = revEndTimestampAttributeMapping.getSelectable( 0 ).getSelectionExpression();
context.addColumn( revEndTimestampColumnName );
context.addAssignment( revEndTimestampColumnName );
context.bind( getRevEndTimestampValue( configuration, revisionTimestamp ), revEndTimestampAttributeMapping );
// Apply "WHERE (entity_id) = ? AND REV <> ?" portion of the SQL
final Number revisionNumber = getRevisionNumber( configuration, revision );
// Apply "WHERE (entity_id) = ?"
context.addPrimaryKeyColumns( entity.getIdentifierColumnNames() );
context.addRestriction( entity.getIdentifierColumnNames() );
context.bind( id, entity.getIdentifierType() );
// Apply "AND REV <> ?"
// todo (PropertyMapping) : need to be able to handle paths
context.addWhereColumn( configuration.getRevisionFieldName(), " <> ?" );
context.addRestriction( configuration.getRevisionFieldName(), "<>", "?" );
context.bind( revisionNumber, auditEntity.getPropertyType( configuration.getRevisionNumberPath() ) );
// Apply "AND REVEND_TSTMP is null"
context.addWhereColumn( revEndTimestampColumnName, " is null" );
context.addNullnessRestriction( revEndTimestampColumnName );
return context;
}
@ -664,7 +664,7 @@ public class ValidityAuditStrategy implements AuditStrategy {
private final List<QueryParameterBinding> bindings = new ArrayList<>( 0 );
public UpdateContext(SessionFactoryImplementor sessionFactory) {
super ( sessionFactory.getJdbcServices().getDialect() );
super ( sessionFactory );
}
public List<QueryParameterBinding> getBindings() {