HHH-7165 - count() query on classes using EmbeddedId should not use id column tuple on Dialects which dont support non-distinct tuple counts

This commit is contained in:
Steve Ebersole 2012-03-13 12:26:04 -05:00
parent 41dd7079e0
commit c3fc7f3214
5 changed files with 84 additions and 25 deletions

View File

@ -58,10 +58,14 @@ tokens
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, HqlSqlBaseWalker.class.getName());
private int level = 0;
private boolean inSelect = false;
private boolean inFunctionCall = false;
private boolean inCase = false;
private boolean inFrom = false;
private boolean inCount = false;
private boolean inCountDistinct = false;
private int statementType;
private String statementTypeName;
// Note: currentClauseType tracks the current clause within the current
@ -92,6 +96,14 @@ tokens
return inCase;
}
public final boolean isInCount() {
return inCount;
}
public final boolean isInCountDistinct() {
return inCountDistinct;
}
public final int getStatementType() {
return statementType;
}
@ -392,7 +404,10 @@ selectExpr
;
count
: #(COUNT ( DISTINCT | ALL )? ( aggregateExpr | ROW_STAR ) )
: #(COUNT { inCount = true; } ( DISTINCT { inCountDistinct = true; } | ALL )? ( aggregateExpr | ROW_STAR ) ) {
inCount = false;
inCountDistinct = false;
}
;
constructor

View File

@ -41,7 +41,8 @@ public class ComponentJoin extends FromElement {
private final ComponentType componentType;
private final String componentProperty;
private final String columns;
private final String[] columns;
private final String columnsFragment;
public ComponentJoin(
FromClause fromClause,
@ -56,16 +57,16 @@ public class ComponentJoin extends FromElement {
fromClause.addJoinByPathMap( componentPath, this );
initializeComponentJoin( new ComponentFromElementType( this ) );
final String[] cols = origin.getPropertyMapping( "" ).toColumns( getTableAlias(), componentProperty );
this.columns = origin.getPropertyMapping( "" ).toColumns( getTableAlias(), componentProperty );
StringBuilder buf = new StringBuilder();
for ( int j = 0; j < cols.length; j++ ) {
final String column = cols[j];
for ( int j = 0; j < columns.length; j++ ) {
final String column = columns[j];
if ( j > 0 ) {
buf.append( ", " );
}
buf.append( column );
}
this.columns = buf.toString();
this.columnsFragment = buf.toString();
}
public String getComponentPath() {
@ -86,9 +87,6 @@ public class ComponentJoin extends FromElement {
return getComponentType();
}
/**
* {@inheritDoc}
*/
@Override
public String getIdentityColumn() {
// used to "resolve" the IdentNode when our alias is encountered *by itself* in the query; so
@ -96,12 +94,14 @@ public class ComponentJoin extends FromElement {
// NOTE : ^^ is true *except for* when encountered by itself in the SELECT clause. That gets
// routed through org.hibernate.hql.internal.ast.tree.ComponentJoin.ComponentFromElementType.renderScalarIdentifierSelect()
// which we also override to account for
return columnsFragment;
}
@Override
public String[] getIdentityColumns() {
return columns;
}
/**
* {@inheritDoc}
*/
@Override
public String getDisplayText() {
return "ComponentJoin{path=" + getComponentPath() + ", type=" + componentType.getReturnedClass() + "}";

View File

@ -325,13 +325,23 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, Pa
}
public String getIdentityColumn() {
final String[] cols = getIdentityColumns();
if ( cols.length == 1 ) {
return cols[0];
}
else {
return "(" + StringHelper.join( ", ", cols ) + ")";
}
}
public String[] getIdentityColumns() {
checkInitialized();
String table = getTableAlias();
final String table = getTableAlias();
if ( table == null ) {
throw new IllegalStateException( "No table alias for node " + this );
}
String[] cols;
String propertyName;
final String propertyName;
if ( getEntityPersister() != null && getEntityPersister().getEntityMetamodel() != null
&& getEntityPersister().getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
propertyName = getEntityPersister().getIdentifierPropertyName();
@ -339,14 +349,13 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, Pa
else {
propertyName = EntityPersister.ENTITY_ID;
}
if ( getWalker().getStatementType() == HqlSqlTokenTypes.SELECT ) {
cols = getPropertyMapping( propertyName ).toColumns( table, propertyName );
return getPropertyMapping( propertyName ).toColumns( table, propertyName );
}
else {
cols = getPropertyMapping( propertyName ).toColumns( propertyName );
return getPropertyMapping( propertyName ).toColumns( propertyName );
}
String result = StringHelper.join( ", ", cols );
return cols.length == 1 ? result : "(" + result + ")";
}
public void setCollectionJoin(boolean collectionJoin) {

View File

@ -149,11 +149,25 @@ public class IdentNode extends FromReferenceNode implements SelectExpression {
private boolean resolveAsAlias() {
// This is not actually a constant, but a reference to FROM element.
FromElement element = getWalker().getCurrentFromClause().getFromElement(getText());
if (element != null) {
setFromElement(element);
setText(element.getIdentityColumn());
setType(SqlTokenTypes.ALIAS_REF);
FromElement element = getWalker().getCurrentFromClause().getFromElement( getText() );
if ( element != null ) {
setType( SqlTokenTypes.ALIAS_REF );
setFromElement( element );
String[] columnExpressions = element.getIdentityColumns();
final boolean isInNonDistinctCount = getWalker().isInCount() && ! getWalker().isInCountDistinct();
final boolean isCompositePk = columnExpressions.length > 1;
if ( isCompositePk
&& isInNonDistinctCount
&& ! getWalker().getSessionFactoryHelper().getFactory().getDialect().supportsTupleCounts() ) {
setText( columnExpressions[0] );
}
else {
String joinedFragment = StringHelper.join( ", ", columnExpressions );
if ( ! getWalker().isInCount() ) {
joinedFragment = "(" + joinedFragment + ")";
}
setText( joinedFragment );
}
return true;
}
return false;

View File

@ -74,6 +74,27 @@ public class CompositeIdTest extends BaseCoreFunctionalTestCase {
assertEquals( expectCommas, hadCommas );
}
@Test
public void testDistinctCountOfEntityWithCompositeId() {
// today we do not account for Dialects supportsTupleDistinctCounts() is false. though really the only
// "option" there is to throw an error.
final HQLQueryPlan plan = sessionFactory().getQueryPlanCache().getHQLQueryPlan(
"select count(distinct o) from Order o",
false,
Collections.EMPTY_MAP
);
assertEquals( 1, plan.getTranslators().length );
final QueryTranslator translator = plan.getTranslators()[0];
final String generatedSql = translator.getSQLString();
System.out.println( "Generated SQL : " + generatedSql );
final int countExpressionListStart = generatedSql.indexOf( "count(" );
final int countExpressionListEnd = generatedSql.indexOf( ")", countExpressionListStart );
final String countExpressionFragment = generatedSql.substring( countExpressionListStart+6, countExpressionListEnd+1 );
assertTrue( countExpressionFragment.startsWith( "distinct" ) );
assertTrue( countExpressionFragment.contains( "," ) );
}
@Test
public void testQuery() {
Session s = openSession();