HHH-13763 : Update all load-by-key handling to use SQL AST
SingleUniqueKeyEntityLoader
This commit is contained in:
parent
0a41ac8466
commit
e112d9631e
|
@ -6,17 +6,38 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.ast.internal;
|
package org.hibernate.loader.ast.internal;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.loader.ast.spi.SingleUniqueKeyEntityLoader;
|
import org.hibernate.loader.ast.spi.SingleUniqueKeyEntityLoader;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||||
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
|
import org.hibernate.sql.ast.Clause;
|
||||||
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||||
|
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||||
|
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||||
|
import org.hibernate.sql.exec.spi.Callback;
|
||||||
|
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
|
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
||||||
|
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||||
|
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SingleUniqueKeyEntityLoaderStandard implements SingleUniqueKeyEntityLoader {
|
public class SingleUniqueKeyEntityLoaderStandard<T> implements SingleUniqueKeyEntityLoader<T> {
|
||||||
private final EntityMappingType entityDescriptor;
|
private final EntityMappingType entityDescriptor;
|
||||||
private final SingularAttributeMapping uniqueKeyAttribute;
|
private final SingularAttributeMapping uniqueKeyAttribute;
|
||||||
|
|
||||||
|
@ -33,10 +54,172 @@ public class SingleUniqueKeyEntityLoaderStandard implements SingleUniqueKeyEntit
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object load(
|
public T load(
|
||||||
Object ukValue,
|
Object ukValue,
|
||||||
LockOptions lockOptions,
|
LockOptions lockOptions,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||||
|
|
||||||
|
// todo (6.0) : cache the SQL AST and JdbcParameters
|
||||||
|
final List<JdbcParameter> jdbcParameters = new ArrayList<>();
|
||||||
|
final SelectStatement sqlAst = LoaderSelectBuilder.createSelect(
|
||||||
|
entityDescriptor,
|
||||||
|
Collections.emptyList(),
|
||||||
|
uniqueKeyAttribute,
|
||||||
|
null,
|
||||||
|
1,
|
||||||
|
LoadQueryInfluencers.NONE,
|
||||||
|
LockOptions.READ,
|
||||||
|
jdbcParameters::add,
|
||||||
|
sessionFactory
|
||||||
|
);
|
||||||
|
|
||||||
|
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||||
|
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||||
|
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||||
|
|
||||||
|
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAst );
|
||||||
|
|
||||||
|
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( jdbcParameters.size() );
|
||||||
|
final Iterator<JdbcParameter> jdbcParamItr = jdbcParameters.iterator();
|
||||||
|
uniqueKeyAttribute.visitJdbcValues(
|
||||||
|
ukValue,
|
||||||
|
Clause.WHERE,
|
||||||
|
(jdbcValue, jdbcMapping) -> {
|
||||||
|
assert jdbcParamItr.hasNext();
|
||||||
|
final JdbcParameter jdbcParameter = jdbcParamItr.next();
|
||||||
|
jdbcParameterBindings.addBinding(
|
||||||
|
jdbcParameter,
|
||||||
|
new JdbcParameterBinding() {
|
||||||
|
@Override
|
||||||
|
public JdbcMapping getBindType() {
|
||||||
|
return jdbcMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBindValue() {
|
||||||
|
return jdbcValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
session
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Object> list = sessionFactory.getJdbcServices().getJdbcSelectExecutor().list(
|
||||||
|
jdbcSelect,
|
||||||
|
jdbcParameterBindings,
|
||||||
|
new ExecutionContext() {
|
||||||
|
@Override
|
||||||
|
public SharedSessionContractImplementor getSession() {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryOptions getQueryOptions() {
|
||||||
|
return QueryOptions.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryParameterBindings getQueryParameterBindings() {
|
||||||
|
return QueryParameterBindings.NO_PARAM_BINDINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Callback getCallback() {
|
||||||
|
return afterLoadAction -> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
row -> row[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert list.size() == 1;
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) list.get( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolveId(Object ukValue, SharedSessionContractImplementor session) {
|
||||||
|
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||||
|
|
||||||
|
// todo (6.0) : cache the SQL AST and JdbcParameters
|
||||||
|
final List<JdbcParameter> jdbcParameters = new ArrayList<>();
|
||||||
|
final SelectStatement sqlAst = LoaderSelectBuilder.createSelect(
|
||||||
|
entityDescriptor,
|
||||||
|
Collections.singletonList( entityDescriptor.getIdentifierMapping() ),
|
||||||
|
uniqueKeyAttribute,
|
||||||
|
null,
|
||||||
|
1,
|
||||||
|
LoadQueryInfluencers.NONE,
|
||||||
|
LockOptions.READ,
|
||||||
|
jdbcParameters::add,
|
||||||
|
sessionFactory
|
||||||
|
);
|
||||||
|
|
||||||
|
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||||
|
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||||
|
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||||
|
|
||||||
|
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAst );
|
||||||
|
|
||||||
|
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( jdbcParameters.size() );
|
||||||
|
final Iterator<JdbcParameter> jdbcParamItr = jdbcParameters.iterator();
|
||||||
|
uniqueKeyAttribute.visitJdbcValues(
|
||||||
|
ukValue,
|
||||||
|
Clause.WHERE,
|
||||||
|
(jdbcValue, jdbcMapping) -> {
|
||||||
|
assert jdbcParamItr.hasNext();
|
||||||
|
final JdbcParameter jdbcParameter = jdbcParamItr.next();
|
||||||
|
jdbcParameterBindings.addBinding(
|
||||||
|
jdbcParameter,
|
||||||
|
new JdbcParameterBinding() {
|
||||||
|
@Override
|
||||||
|
public JdbcMapping getBindType() {
|
||||||
|
return jdbcMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBindValue() {
|
||||||
|
return jdbcValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
session
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Object> list = sessionFactory.getJdbcServices().getJdbcSelectExecutor().list(
|
||||||
|
jdbcSelect,
|
||||||
|
jdbcParameterBindings,
|
||||||
|
new ExecutionContext() {
|
||||||
|
@Override
|
||||||
|
public SharedSessionContractImplementor getSession() {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryOptions getQueryOptions() {
|
||||||
|
return QueryOptions.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryParameterBindings getQueryParameterBindings() {
|
||||||
|
return QueryParameterBindings.NO_PARAM_BINDINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Callback getCallback() {
|
||||||
|
return afterLoadAction -> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
row -> row[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert list.size() == 1;
|
||||||
|
|
||||||
|
return list.get( 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,4 +20,9 @@ public interface SingleUniqueKeyEntityLoader<T> extends SingleEntityLoader {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
T load(Object ukValue, LockOptions lockOptions, SharedSessionContractImplementor session);
|
T load(Object ukValue, LockOptions lockOptions, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the matching id
|
||||||
|
*/
|
||||||
|
Object resolveId(Object key, SharedSessionContractImplementor session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1255,19 +1255,6 @@ public abstract class AbstractEntityPersister
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resolveTableReferenceJoins(
|
|
||||||
TableReference rootTableReference,
|
|
||||||
SqlAliasBase sqlAliasBase,
|
|
||||||
org.hibernate.sql.ast.JoinType joinType,
|
|
||||||
Consumer<TableReferenceJoin> collector,
|
|
||||||
SqlExpressionResolver sqlExpressionResolver) {
|
|
||||||
for ( int i = 1; i < getSubclassTableSpan(); i++ ) {
|
|
||||||
collector.accept(
|
|
||||||
createTableReferenceJoin( i, rootTableReference, joinType, sqlAliasBase, sqlExpressionResolver )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyTableReferences(
|
public void applyTableReferences(
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
|
@ -1817,8 +1804,7 @@ public abstract class AbstractEntityPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getIdByUniqueKey(Object key, String uniquePropertyName, SharedSessionContractImplementor session)
|
public Object getIdByUniqueKey(Object key, String uniquePropertyName, SharedSessionContractImplementor session) {
|
||||||
throws HibernateException {
|
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.tracef(
|
LOG.tracef(
|
||||||
"resolving unique key [%s] to identifier for entity [%s]",
|
"resolving unique key [%s] to identifier for entity [%s]",
|
||||||
|
@ -1827,103 +1813,7 @@ public abstract class AbstractEntityPersister
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int propertyIndex = getSubclassPropertyIndex( uniquePropertyName );
|
return getUniqueKeyLoader( uniquePropertyName ).resolveId( key, session );
|
||||||
if ( propertyIndex < 0 ) {
|
|
||||||
throw new HibernateException(
|
|
||||||
"Could not determine Type for property [" + uniquePropertyName + "] on entity [" + getEntityName() + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Type propertyType = getSubclassPropertyType( propertyIndex );
|
|
||||||
|
|
||||||
try {
|
|
||||||
PreparedStatement ps = session
|
|
||||||
.getJdbcCoordinator()
|
|
||||||
.getStatementPreparer()
|
|
||||||
.prepareStatement( generateIdByUniqueKeySelectString( uniquePropertyName ) );
|
|
||||||
try {
|
|
||||||
propertyType.nullSafeSet( ps, key, 1, session );
|
|
||||||
ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( ps );
|
|
||||||
try {
|
|
||||||
//if there is no resulting row, return null
|
|
||||||
if ( !rs.next() ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (Serializable) getIdentifierType().nullSafeGet( rs, getIdentifierAliases(), session, null );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( rs, ps );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( ps );
|
|
||||||
session.getJdbcCoordinator().afterStatementExecution();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
|
||||||
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
|
||||||
e,
|
|
||||||
String.format(
|
|
||||||
"could not resolve unique property [%s] to identifier for entity [%s]",
|
|
||||||
uniquePropertyName,
|
|
||||||
getEntityName()
|
|
||||||
),
|
|
||||||
getSQLSnapshotSelectString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String generateIdByUniqueKeySelectString(String uniquePropertyName) {
|
|
||||||
Select select = new Select( getFactory().getDialect() );
|
|
||||||
|
|
||||||
if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
|
|
||||||
select.setComment( "resolve id by unique property [" + getEntityName() + "." + uniquePropertyName + "]" );
|
|
||||||
}
|
|
||||||
|
|
||||||
final String rooAlias = getRootAlias();
|
|
||||||
|
|
||||||
select.setFromClause( fromTableFragment( rooAlias ) + fromJoinFragment( rooAlias, true, false ) );
|
|
||||||
|
|
||||||
SelectFragment selectFragment = new SelectFragment();
|
|
||||||
selectFragment.addColumns( rooAlias, getIdentifierColumnNames(), getIdentifierAliases() );
|
|
||||||
select.setSelectClause( selectFragment );
|
|
||||||
|
|
||||||
StringBuilder whereClauseBuffer = new StringBuilder();
|
|
||||||
final int uniquePropertyIndex = getSubclassPropertyIndex( uniquePropertyName );
|
|
||||||
final String uniquePropertyTableAlias = generateTableAlias(
|
|
||||||
rooAlias,
|
|
||||||
getSubclassPropertyTableNumber( uniquePropertyIndex )
|
|
||||||
);
|
|
||||||
String sep = "";
|
|
||||||
for ( String columnTemplate : getSubclassPropertyColumnReaderTemplateClosure()[uniquePropertyIndex] ) {
|
|
||||||
if ( columnTemplate == null ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final String columnReference = StringHelper.replace(
|
|
||||||
columnTemplate,
|
|
||||||
Template.TEMPLATE,
|
|
||||||
uniquePropertyTableAlias
|
|
||||||
);
|
|
||||||
whereClauseBuffer.append( sep ).append( columnReference ).append( "=?" );
|
|
||||||
sep = " and ";
|
|
||||||
}
|
|
||||||
for ( String formulaTemplate : getSubclassPropertyFormulaTemplateClosure()[uniquePropertyIndex] ) {
|
|
||||||
if ( formulaTemplate == null ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final String formulaReference = StringHelper.replace(
|
|
||||||
formulaTemplate,
|
|
||||||
Template.TEMPLATE,
|
|
||||||
uniquePropertyTableAlias
|
|
||||||
);
|
|
||||||
whereClauseBuffer.append( sep ).append( formulaReference ).append( "=?" );
|
|
||||||
sep = " and ";
|
|
||||||
}
|
|
||||||
whereClauseBuffer.append( whereJoinFragment( rooAlias, true, false ) );
|
|
||||||
|
|
||||||
select.setWhereClause( whereClauseBuffer.toString() );
|
|
||||||
|
|
||||||
return select.setOuterJoins( "", "" ).toStatementString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2644,13 +2534,18 @@ public abstract class AbstractEntityPersister
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<SingularAttributeMapping, SingleUniqueKeyEntityLoader<?>> uniqueKeyLoadersNew;
|
|
||||||
|
|
||||||
public Object loadByUniqueKey(
|
public Object loadByUniqueKey(
|
||||||
String propertyName,
|
String propertyName,
|
||||||
Object uniqueKey,
|
Object uniqueKey,
|
||||||
SharedSessionContractImplementor session) throws HibernateException {
|
SharedSessionContractImplementor session) throws HibernateException {
|
||||||
final SingularAttributeMapping attribute = (SingularAttributeMapping) findSubPart( propertyName );
|
return getUniqueKeyLoader( propertyName ).load( uniqueKey, LockOptions.READ, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<SingularAttributeMapping, SingleUniqueKeyEntityLoader<?>> uniqueKeyLoadersNew;
|
||||||
|
|
||||||
|
protected SingleUniqueKeyEntityLoader getUniqueKeyLoader(String attributeName) {
|
||||||
|
final SingularAttributeMapping attribute = (SingularAttributeMapping) findSubPart( attributeName );
|
||||||
final SingleUniqueKeyEntityLoader<?> existing;
|
final SingleUniqueKeyEntityLoader<?> existing;
|
||||||
if ( uniqueKeyLoadersNew == null ) {
|
if ( uniqueKeyLoadersNew == null ) {
|
||||||
uniqueKeyLoadersNew = new IdentityHashMap<>();
|
uniqueKeyLoadersNew = new IdentityHashMap<>();
|
||||||
|
@ -2666,6 +2561,7 @@ public abstract class AbstractEntityPersister
|
||||||
|
|
||||||
final SingleUniqueKeyEntityLoader loader = new SingleUniqueKeyEntityLoaderStandard( this, attribute );
|
final SingleUniqueKeyEntityLoader loader = new SingleUniqueKeyEntityLoaderStandard( this, attribute );
|
||||||
uniqueKeyLoadersNew.put( attribute, loader );
|
uniqueKeyLoadersNew.put( attribute, loader );
|
||||||
|
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@ import org.hibernate.dialect.Dialect;
|
||||||
* Implementation of InsertSelect.
|
* Implementation of InsertSelect.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
*
|
||||||
|
* @deprecated (since 6.0) Use {@link org.hibernate.sql.ast.tree.insert.InsertSelectStatement} instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class InsertSelect {
|
public class InsertSelect {
|
||||||
private String tableName;
|
private String tableName;
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
|
@ -1,18 +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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO : javadoc
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public interface SelectExpression {
|
|
||||||
public String getExpression();
|
|
||||||
public String getAlias();
|
|
||||||
}
|
|
|
@ -1,103 +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;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Models a SELECT values lists. Eventually, rather than Strings, pass in the Column/Formula representations (something
|
|
||||||
* like {@link org.hibernate.sql.ordering.antlr.ColumnReference}/{@link org.hibernate.sql.ordering.antlr.FormulaReference}
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class SelectValues {
|
|
||||||
private static final Logger log = Logger.getLogger( SelectValues.class );
|
|
||||||
|
|
||||||
private static class SelectValue {
|
|
||||||
private final String qualifier;
|
|
||||||
private final String value;
|
|
||||||
private final String alias;
|
|
||||||
|
|
||||||
private SelectValue(String qualifier, String value, String alias) {
|
|
||||||
this.qualifier = qualifier;
|
|
||||||
this.value = value;
|
|
||||||
this.alias = alias;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Dialect dialect;
|
|
||||||
private final ArrayList<SelectValue> selectValueList = new ArrayList<SelectValue>();
|
|
||||||
|
|
||||||
public SelectValues(Dialect dialect) {
|
|
||||||
this.dialect = dialect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SelectValues addColumns(String qualifier, String[] columnNames, String[] columnAliases) {
|
|
||||||
for ( int i = 0; i < columnNames.length; i++ ) {
|
|
||||||
if ( columnNames[i] != null ) {
|
|
||||||
addColumn( qualifier, columnNames[i], columnAliases[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SelectValues addColumn(String qualifier, String columnName, String columnAlias) {
|
|
||||||
selectValueList.add( new SelectValue( qualifier, columnName, columnAlias ) );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SelectValues addParameter(int jdbcTypeCode, int length) {
|
|
||||||
final String selectExpression = dialect.requiresCastingOfParametersInSelectClause()
|
|
||||||
? dialect.cast( "?", jdbcTypeCode, length )
|
|
||||||
: "?";
|
|
||||||
selectValueList.add( new SelectValue( null, selectExpression, null ) );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SelectValues addParameter(int jdbcTypeCode, int precision, int scale) {
|
|
||||||
final String selectExpression = dialect.requiresCastingOfParametersInSelectClause()
|
|
||||||
? dialect.cast( "?", jdbcTypeCode, precision, scale )
|
|
||||||
: "?";
|
|
||||||
selectValueList.add( new SelectValue( null, selectExpression, null ) );
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String render() {
|
|
||||||
final StringBuilder buf = new StringBuilder( selectValueList.size() * 10 );
|
|
||||||
final HashSet<String> uniqueAliases = new HashSet<String>();
|
|
||||||
boolean firstExpression = true;
|
|
||||||
for ( SelectValue selectValue : selectValueList ) {
|
|
||||||
if ( selectValue.alias != null ) {
|
|
||||||
if ( ! uniqueAliases.add( selectValue.alias ) ) {
|
|
||||||
log.debug( "Skipping select-value with non-unique alias" );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( firstExpression ) {
|
|
||||||
firstExpression = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buf.append( ", " );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( selectValue.qualifier != null ) {
|
|
||||||
buf.append( selectValue.qualifier ).append( '.' );
|
|
||||||
}
|
|
||||||
buf.append( selectValue.value );
|
|
||||||
if ( selectValue.alias != null ) {
|
|
||||||
buf.append( " as " ).append( selectValue.alias );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue