re-enable tests

re-organize some tests
continuing with o.h.test.hql - order-by
add Expression#unwrap to help account for SqlSelectionExpression
This commit is contained in:
Steve Ebersole 2021-04-02 07:30:08 -05:00
parent 51074eb9a0
commit 159135ea89
9 changed files with 160 additions and 151 deletions

View File

@ -219,7 +219,7 @@ public class EmbeddedAttributeMapping
)
);
columnReferences.add( (ColumnReference) columnReference );
columnReferences.add( columnReference.unwrap( ColumnReference.class ) );
}
);

View File

@ -1,108 +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.query.results;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import org.hibernate.Internal;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
*/
@Internal
public class SqlAstProcessingStateImpl implements SqlAstProcessingState, SqlExpressionResolver {
private final FromClauseAccessImpl fromClauseAccess;
private final Map<String, SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
private final Consumer<SqlSelection> sqlSelectionConsumer;
private final SqlAstCreationState sqlAstCreationState;
public SqlAstProcessingStateImpl(
FromClauseAccessImpl fromClauseAccess,
Consumer<SqlSelection> sqlSelectionConsumer,
SqlAstCreationState sqlAstCreationState) {
this.fromClauseAccess = fromClauseAccess;
this.sqlSelectionConsumer = sqlSelectionConsumer;
this.sqlAstCreationState = sqlAstCreationState;
}
@Override
public SqlAstProcessingState getParentState() {
// none
return null;
}
@Override
public SqlExpressionResolver getSqlExpressionResolver() {
return this;
}
@Override
public SqlAstCreationState getSqlAstCreationState() {
return sqlAstCreationState;
}
public int getNumberOfProcessedSelections() {
return sqlSelectionMap.size();
}
@Override
public Expression resolveSqlExpression(
String key,
Function<SqlAstProcessingState, Expression> creator) {
final SqlSelectionImpl existing = sqlSelectionMap.get( key );
if ( existing != null ) {
return existing;
}
final Expression created = creator.apply( this );
if ( created instanceof SqlSelectionImpl ) {
sqlSelectionMap.put( key, (SqlSelectionImpl) created );
sqlSelectionConsumer.accept( (SqlSelectionImpl) created );
}
else if ( created instanceof ColumnReference ) {
final ColumnReference columnReference = (ColumnReference) created;
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl(
sqlSelectionMap.size() + 1,
columnReference.getJdbcMapping()
);
sqlSelectionMap.put( key, sqlSelection );
sqlSelectionConsumer.accept( sqlSelection );
}
return created;
}
@Override
public SqlSelection resolveSqlSelection(
Expression expression,
JavaTypeDescriptor javaTypeDescriptor,
TypeConfiguration typeConfiguration) {
assert expression instanceof SqlSelectionImpl;
return (SqlSelection) expression;
}
public FromClauseAccess getFromClauseAccess() {
return fromClauseAccess;
}
}

View File

@ -86,6 +86,7 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
final List<ColumnReference> columnReferences = new ArrayList<>();
// todo (6.0) : "polymorphize" this
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
if ( mapping instanceof ToOneAttributeMapping ) {
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) mapping;
final ModelPart modelPart = getModelPart( sqlAstCreationState, toOne );
@ -99,21 +100,19 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
toOne,
selection.getContainingTableExpression()
);
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey(
tableReference,
selection.getSelectionExpression()
),
sqlAstProcessingState -> new ColumnReference(
tableReference.getIdentificationVariable(),
selection,
sqlAstCreationState.getCreationContext().getSessionFactory()
)
);
final Expression columnReference = sqlAstCreationState.getSqlExpressionResolver()
.resolveSqlExpression(
createColumnReferenceKey(
tableReference,
selection.getSelectionExpression()
),
sqlAstProcessingState -> new ColumnReference(
tableReference.getIdentificationVariable(),
selection,
sqlAstCreationState.getCreationContext().getSessionFactory()
)
);
columnReferences.add( (ColumnReference) columnReference );
columnReferences.add( columnReference.unwrap( ColumnReference.class ) );
}
);
}
@ -151,7 +150,7 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
(index, selectable) -> {
final TableReference tableReference = mapTableGroup.resolveTableReference( selectable.getContainingTableExpression() );
final SqlExpressionResolver expressionResolver = sqlAstCreationState.getSqlExpressionResolver();
final SqlExpressionResolver expressionResolver = sqlExpressionResolver;
columnReferences.add(
(ColumnReference) expressionResolver.resolveSqlExpression(

View File

@ -25,6 +25,10 @@ public interface Expression extends SqlAstNode, SqlSelectionProducer {
*/
MappingModelExpressable getExpressionType();
default <T> T unwrap(Class<T> target) {
return (T) this;
}
@Override
default SqlSelection createSqlSelection(
int jdbcPosition,

View File

@ -29,6 +29,28 @@ public class SqlSelectionExpression implements Expression {
return theSelection;
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> target) {
if ( target.isInstance( this ) ) {
return (T) this;
}
if ( target.isInstance( theSelection ) ) {
return (T) theSelection;
}
if ( target.isInstance( theSelection.getExpression() ) ) {
return (T) theSelection.getExpression();
}
if ( target.isInstance( theSelection.getExpressionType() ) ) {
return (T) theSelection.getExpressionType();
}
return theSelection.getExpression().unwrap( target );
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitSqlSelectionExpression( this );

View File

@ -9,6 +9,7 @@ package org.hibernate.sql.results.jdbc.internal;
import java.sql.SQLException;
import org.hibernate.CacheMode;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.QueryKey;
import org.hibernate.cache.spi.QueryResultsCache;
import org.hibernate.query.spi.QueryOptions;
@ -248,11 +249,19 @@ public class JdbcValuesResultSetImpl extends AbstractJdbcValues {
private void readCurrentRowValues() throws SQLException {
for ( final SqlSelection sqlSelection : sqlSelections ) {
currentRowJdbcValues[ sqlSelection.getValuesArrayPosition() ] = sqlSelection.getJdbcValueExtractor().extract(
resultSetAccess.getResultSet(),
sqlSelection.getJdbcResultSetIndex(),
executionContext.getSession()
);
try {
currentRowJdbcValues[ sqlSelection.getValuesArrayPosition() ] = sqlSelection.getJdbcValueExtractor().extract(
resultSetAccess.getResultSet(),
sqlSelection.getJdbcResultSetIndex(),
executionContext.getSession()
);
}
catch (Exception e) {
throw new HibernateException(
"Unable to extract JDBC value for position `" + sqlSelection.getJdbcResultSetIndex() + "`",
e
);
}
}
}

View File

@ -55,7 +55,6 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
super.configure( cfg );
cfg.setProperty( Environment.USE_QUERY_CACHE, "false" );
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
cfg.setProperty( Environment.SEMANTIC_QUERY_PRODUCER, HqlTranslator.class.getName() );
}
private void createData() {
@ -68,6 +67,7 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
address1.setStreet( "1313 Mockingbird Lane" );
address1.setCity( "Anywhere" );
address1.setStateProvince( stateProvince );
address1.setPostalCode( "12345" );
address1.setCountry( "USA" );
zoo1.setAddress( address1 );
zoo1Mammal1 = new Mammal();
@ -84,6 +84,7 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
Address address2 = new Address();
address2.setStreet( "1313 Mockingbird Lane" );
address2.setCity( "Anywhere" );
address2.setPostalCode( "12345" );
address2.setStateProvince( stateProvince );
address2.setCountry( "USA" );
zoo2.setAddress( address2 );
@ -100,6 +101,7 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
address3.setStreet( "1312 Mockingbird Lane" );
address3.setCity( "Anywhere" );
address3.setStateProvince( stateProvince );
address3.setPostalCode( "12345" );
address3.setCountry( "USA" );
zoo3.setAddress( address3 );
@ -109,6 +111,7 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
address4.setStreet( "1312 Mockingbird Lane" );
address4.setCity( "Nowhere" );
address4.setStateProvince( stateProvince );
address4.setPostalCode( "12345" );
address4.setCountry( "USA" );
zoo4.setAddress( address4 );
@ -241,17 +244,58 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// NOTE (6.0) : the above illustration is based on 5.x code. but the outcome
// is ultimately based on the order in which we render the attributes of
// the Address component. In 6.0 this has been made consistent and easily
// explainable, whereas that was not previously the case.
// checkTestOrderByResults(
// s.createQuery(
// "select z.name, z.address from Zoo z order by z.address, z.name"
// ).list(),
// zoo3, zoo4, zoo2, zoo1, null
// );
// NOTE (6.0) - continued : this is functionally equivalent to the 5.x case
checkTestOrderByResults(
s.createQuery(
"select z.name, z.address " +
"from Zoo z " +
"order by z.address.street," +
" z.address.city," +
" z.address.postalCode, " +
" z.address.country," +
" z.name"
).list(),
zoo3, zoo4, zoo2, zoo1, null
);
// NOTE (6.0) - continued 2 : this is the 6.x functionally
// ordered by address, name:
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
checkTestOrderByResults(
s.createQuery(
"select z.name, z.address from Zoo z order by z.address, z.name"
).list(),
zoo3, zoo4, zoo2, zoo1, null
zoo3, zoo2, zoo1, zoo4, null
);
// NOTE (6.0) - continued 3 : and the functionally equiv "full ordering"
checkTestOrderByResults(
s.createQuery(
"select z.name, z.address from Zoo z order by z.address.city, z.address.country, z.address.stateProvince, z.address.street, z.name"
).list(),
zoo3, zoo2, zoo1, zoo4, null
);
checkTestOrderByResults(
s.createQuery(
"select name, address from Zoo order by address, name"
).list(),
zoo3, zoo4, zoo2, zoo1, null
zoo3, zoo2, zoo1, zoo4, null
);
// ordered by address:
@ -260,15 +304,24 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
// unordered:
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
//
// NOTE 6.0 : these results are not well defined. Because we primarily order
// based on city zoo1, zoo2 and zoo3 are all sorted "above" zoo4. however
// the order between zoo1 and zoo2 is completely undefined because they
// have the same address
//
// and honestly, not even sure what this assertion is even trying to test.
// but changed the query to what you'd need to get those results - which I guess
// is the order used by 5.x
checkTestOrderByResults(
s.createQuery(
"select z.name, z.address from Zoo z order by z.address"
"select z.name, z.address from Zoo z order by z.address.street, z.address.city"
).list(),
zoo3, zoo4, null, null, zoosWithSameAddress
);
checkTestOrderByResults(
s.createQuery(
"select name, address from Zoo order by address"
"select name, address from Zoo order by address.street, address.city"
).list(),
zoo3, zoo4, null, null, zoosWithSameAddress
);
@ -406,30 +459,37 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
//
// NOTE (6.0) : another case of different handling for the component attributes
// causing a "failure"
// zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA
checkTestOrderByResults(
s.createQuery(
"select z.name as address, z.address as name from Zoo z order by name, address"
).list(),
zoo3, zoo4, zoo2, zoo1, null
zoo3, zoo2, zoo1, zoo4, null
);
checkTestOrderByResults(
s.createQuery(
"select z.name, z.address as name from Zoo z order by name, z.name"
).list(),
zoo3, zoo4, zoo2, zoo1, null
zoo3, zoo2, zoo1, zoo4, null
);
// using ASC
checkTestOrderByResults(
s.createQuery(
"select z.name as address, z.address as name from Zoo z order by name ASC, address ASC"
).list(),
zoo3, zoo4, zoo2, zoo1, null
zoo3, zoo2, zoo1, zoo4, null
);
checkTestOrderByResults(
s.createQuery(
"select z.name, z.address as name from Zoo z order by name ASC, z.name ASC"
).list(),
zoo3, zoo4, zoo2, zoo1, null
zoo3, zoo2, zoo1, zoo4, null
);
// ordered by address:
@ -438,19 +498,22 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
// unordered:
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
// zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA
checkTestOrderByResults(
s.createQuery(
"select z.name as zooName, z.address as zooAddress from Zoo z order by zooAddress"
).list(),
zoo3, zoo4, null, null, zoosWithSameAddress
);
//
// NOTE (6.0) : another one where the result order would be undefined
// checkTestOrderByResults(
// s.createQuery(
// "select z.name as zooName, z.address as zooAddress from Zoo z order by zooAddress"
// ).list(),
// zoo3, zoo4, null, null, zoosWithSameAddress
// );
checkTestOrderByResults(
s.createQuery(
"select z.name as zooName, z.address as name from Zoo z order by name"
).list(),
zoo3, zoo4, null, null, zoosWithSameAddress
);
// NOTE (6.0) : another undefined case
// checkTestOrderByResults(
// s.createQuery(
// "select z.name as zooName, z.address as name from Zoo z order by name"
// ).list(),
// zoo3, zoo4, null, null, zoosWithSameAddress
// );
// ordered by name:
// zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA
@ -679,8 +742,8 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
assertTrue( zoosUnordered.remove( zooResult ) );
}
else {
assertEquals( zooExpected.getName(), ( ( Object[] ) result )[ 0 ] );
assertEquals( zooExpected.getAddress(), ( ( Object[] ) result )[ 1 ] );
assertEquals( zooExpected.getName(), ( ( Object[] ) result )[ 0 ] );
}
}
}

View File

@ -100,4 +100,15 @@ public class Address {
result = 31 * result + ( stateProvince != null ? stateProvince.hashCode() : 0 );
return result;
}
@Override
public String toString() {
return "Address{" +
"street='" + street + '\'' +
", city='" + city + '\'' +
", postalCode='" + postalCode + '\'' +
", country='" + country + '\'' +
", stateProvince=" + stateProvince +
'}';
}
}

View File

@ -70,4 +70,13 @@ public class StateProvince {
result = 31 * result + ( isoCode != null ? isoCode.hashCode() : 0 );
return result;
}
@Override
public String toString() {
return "StateProvince{" +
"id=" + id +
", name='" + name + '\'' +
", isoCode='" + isoCode + '\'' +
'}';
}
}