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:
parent
41dd7079e0
commit
c3fc7f3214
|
@ -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,8 +404,11 @@ selectExpr
|
|||
;
|
||||
|
||||
count
|
||||
: #(COUNT ( DISTINCT | ALL )? ( aggregateExpr | ROW_STAR ) )
|
||||
;
|
||||
: #(COUNT { inCount = true; } ( DISTINCT { inCountDistinct = true; } | ALL )? ( aggregateExpr | ROW_STAR ) ) {
|
||||
inCount = false;
|
||||
inCountDistinct = false;
|
||||
}
|
||||
;
|
||||
|
||||
constructor
|
||||
{ String className = null; }
|
||||
|
|
|
@ -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() + "}";
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue