HHH-13619 - Support for JPA's `size` function as a select expression
- code cleanup
This commit is contained in:
parent
692f19c83f
commit
336c3b9e30
|
@ -84,7 +84,6 @@ import org.hibernate.param.VersionTypeSeedParameterSpecification;
|
||||||
import org.hibernate.persister.collection.CollectionPropertyNames;
|
import org.hibernate.persister.collection.CollectionPropertyNames;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.PropertyMapping;
|
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.sql.JoinType;
|
import org.hibernate.sql.JoinType;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
|
@ -645,8 +644,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
||||||
@Override
|
@Override
|
||||||
protected AST createCollectionSizeFunction(AST collectionPath, boolean inSelect) throws SemanticException {
|
protected AST createCollectionSizeFunction(AST collectionPath, boolean inSelect) throws SemanticException {
|
||||||
assert collectionPath instanceof CollectionPathNode;
|
assert collectionPath instanceof CollectionPathNode;
|
||||||
|
return new CollectionSizeNode( (CollectionPathNode) collectionPath );
|
||||||
return new CollectionSizeNode( (CollectionPathNode) collectionPath, this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -423,9 +423,9 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String renderOrderByElement(String expression, String order, String nulls) {
|
protected String renderOrderByElement(String expression, String order, String nulls) {
|
||||||
final NullPrecedence nullPrecedence = NullPrecedence.parse( nulls,
|
final NullPrecedence nullPrecedence = NullPrecedence.parse(
|
||||||
sessionFactory.getSettings()
|
nulls,
|
||||||
.getDefaultNullPrecedence()
|
sessionFactory.getSettings().getDefaultNullPrecedence()
|
||||||
);
|
);
|
||||||
return sessionFactory.getDialect().renderOrderByElement( expression, null, order, nullPrecedence );
|
return sessionFactory.getDialect().renderOrderByElement( expression, null, order, nullPrecedence );
|
||||||
}
|
}
|
||||||
|
@ -436,11 +436,13 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
|
||||||
|
|
||||||
final CollectionSizeNode collectionSizeNode = (CollectionSizeNode) ast;
|
final CollectionSizeNode collectionSizeNode = (CollectionSizeNode) ast;
|
||||||
|
|
||||||
// todo : or `#getStringBuilder()` directly?
|
|
||||||
try {
|
try {
|
||||||
writer.clause( collectionSizeNode.toSqlExpression() );
|
writer.clause( collectionSizeNode.toSqlExpression() );
|
||||||
}
|
}
|
||||||
catch (SemanticException e) {
|
catch (QueryException qe) {
|
||||||
|
throw qe;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
throw new QueryException( "Unable to render collection-size node" );
|
throw new QueryException( "Unable to render collection-size node" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,11 @@ import java.util.List;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
||||||
import org.hibernate.hql.internal.ast.SqlASTFactory;
|
import org.hibernate.hql.internal.ast.SqlASTFactory;
|
||||||
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.entity.Joinable;
|
||||||
import org.hibernate.persister.entity.PropertyMapping;
|
import org.hibernate.persister.entity.PropertyMapping;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
@ -38,6 +40,7 @@ public class CollectionPathNode extends SqlNode {
|
||||||
private final String collectionPropertyPath;
|
private final String collectionPropertyPath;
|
||||||
private final String collectionQueryPath;
|
private final String collectionQueryPath;
|
||||||
|
|
||||||
|
private final HqlSqlWalker walker;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,12 +53,16 @@ public class CollectionPathNode extends SqlNode {
|
||||||
CollectionPersister collectionDescriptor,
|
CollectionPersister collectionDescriptor,
|
||||||
String collectionPropertyName,
|
String collectionPropertyName,
|
||||||
String collectionQueryPath,
|
String collectionQueryPath,
|
||||||
String collectionPropertyPath) {
|
String collectionPropertyPath,
|
||||||
|
HqlSqlWalker walker) {
|
||||||
this.ownerFromElement = ownerFromElement;
|
this.ownerFromElement = ownerFromElement;
|
||||||
this.collectionDescriptor = collectionDescriptor;
|
this.collectionDescriptor = collectionDescriptor;
|
||||||
this.collectionPropertyName = collectionPropertyName;
|
this.collectionPropertyName = collectionPropertyName;
|
||||||
this.collectionQueryPath = collectionQueryPath;
|
this.collectionQueryPath = collectionQueryPath;
|
||||||
this.collectionPropertyPath = collectionPropertyPath;
|
this.collectionPropertyPath = collectionPropertyPath;
|
||||||
|
this.walker = walker;
|
||||||
|
|
||||||
|
walker.addQuerySpaces( collectionDescriptor.getCollectionSpaces() );
|
||||||
|
|
||||||
super.setType( SqlASTFactory.COLL_PATH );
|
super.setType( SqlASTFactory.COLL_PATH );
|
||||||
super.setDataType( collectionDescriptor.getCollectionType() );
|
super.setDataType( collectionDescriptor.getCollectionType() );
|
||||||
|
@ -99,7 +106,8 @@ public class CollectionPathNode extends SqlNode {
|
||||||
collectionDescriptor,
|
collectionDescriptor,
|
||||||
referenceName,
|
referenceName,
|
||||||
referencePath,
|
referencePath,
|
||||||
referenceName
|
referenceName,
|
||||||
|
walker
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -126,7 +134,8 @@ public class CollectionPathNode extends SqlNode {
|
||||||
walker.getSessionFactoryHelper().requireQueryableCollection( collectionType.getRole() ),
|
walker.getSessionFactoryHelper().requireQueryableCollection( collectionType.getRole() ),
|
||||||
referenceName,
|
referenceName,
|
||||||
referencePath,
|
referencePath,
|
||||||
referenceName
|
referenceName,
|
||||||
|
walker
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -171,7 +180,8 @@ public class CollectionPathNode extends SqlNode {
|
||||||
walker.getSessionFactoryHelper().requireQueryableCollection( collectionType.getRole() ),
|
walker.getSessionFactoryHelper().requireQueryableCollection( collectionType.getRole() ),
|
||||||
referenceName,
|
referenceName,
|
||||||
referencePath,
|
referencePath,
|
||||||
referenceName
|
referenceName,
|
||||||
|
walker
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,12 +231,13 @@ public class CollectionPathNode extends SqlNode {
|
||||||
walker.getSessionFactoryHelper().requireQueryableCollection( collectionType.getRole() ),
|
walker.getSessionFactoryHelper().requireQueryableCollection( collectionType.getRole() ),
|
||||||
referenceName,
|
referenceName,
|
||||||
referencePath,
|
referencePath,
|
||||||
mappedPath
|
mappedPath,
|
||||||
|
walker
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FromElement getCollectionOwnerRef() {
|
public FromElement getCollectionOwnerFromElement() {
|
||||||
return ownerFromElement;
|
return ownerFromElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,4 +256,26 @@ public class CollectionPathNode extends SqlNode {
|
||||||
public String getCollectionQueryPath() {
|
public String getCollectionQueryPath() {
|
||||||
return collectionQueryPath;
|
return collectionQueryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] resolveOwnerKeyColumnExpressions() {
|
||||||
|
final AST ast = walker.getAST();
|
||||||
|
final String ownerTableAlias;
|
||||||
|
if ( ast instanceof DeleteStatement || ast instanceof UpdateStatement ) {
|
||||||
|
ownerTableAlias = ownerFromElement.getTableName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ownerTableAlias = ownerFromElement.getTableAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String lhsPropertyName = collectionDescriptor.getCollectionType().getLHSPropertyName();
|
||||||
|
if ( lhsPropertyName == null ) {
|
||||||
|
return StringHelper.qualify(
|
||||||
|
ownerTableAlias,
|
||||||
|
( (Joinable) collectionDescriptor.getOwnerEntityPersister() ).getKeyColumnNames()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ownerFromElement.toColumns( ownerTableAlias, lhsPropertyName, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,14 @@ package org.hibernate.hql.internal.ast.tree;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.hql.internal.NameGenerator;
|
import org.hibernate.hql.internal.NameGenerator;
|
||||||
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
|
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
|
||||||
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.persister.collection.CollectionPropertyMapping;
|
import org.hibernate.persister.collection.CollectionPropertyMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPropertyNames;
|
import org.hibernate.persister.collection.CollectionPropertyNames;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.Joinable;
|
|
||||||
import org.hibernate.type.StandardBasicTypes;
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import antlr.SemanticException;
|
|
||||||
import antlr.collections.AST;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@ -31,13 +26,10 @@ public class CollectionSizeNode extends SqlNode implements SelectExpression {
|
||||||
private final CollectionPathNode collectionPathNode;
|
private final CollectionPathNode collectionPathNode;
|
||||||
private final CollectionPropertyMapping collectionPropertyMapping;
|
private final CollectionPropertyMapping collectionPropertyMapping;
|
||||||
|
|
||||||
private final HqlSqlWalker walker;
|
|
||||||
private String alias;
|
private String alias;
|
||||||
|
|
||||||
public CollectionSizeNode(CollectionPathNode collectionPathNode, HqlSqlWalker walker) {
|
public CollectionSizeNode(CollectionPathNode collectionPathNode) {
|
||||||
this.collectionPathNode = collectionPathNode;
|
this.collectionPathNode = collectionPathNode;
|
||||||
this.walker = walker;
|
|
||||||
|
|
||||||
this.collectionPropertyMapping = new CollectionPropertyMapping( (QueryableCollection) collectionPathNode.getCollectionDescriptor() );
|
this.collectionPropertyMapping = new CollectionPropertyMapping( (QueryableCollection) collectionPathNode.getCollectionDescriptor() );
|
||||||
|
|
||||||
setType( HqlSqlTokenTypes.COLL_SIZE );
|
setType( HqlSqlTokenTypes.COLL_SIZE );
|
||||||
|
@ -45,15 +37,12 @@ public class CollectionSizeNode extends SqlNode implements SelectExpression {
|
||||||
setText( "collection-size" );
|
setText( "collection-size" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public CollectionPathNode getCollectionPathNode() {
|
public CollectionPathNode getCollectionPathNode() {
|
||||||
return collectionPathNode;
|
return collectionPathNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HqlSqlWalker getWalker() {
|
public String toSqlExpression() {
|
||||||
return walker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toSqlExpression() throws SemanticException {
|
|
||||||
// generate subquery in the form:
|
// generate subquery in the form:
|
||||||
//
|
//
|
||||||
// select count( alias_.<collection-size-columns> )
|
// select count( alias_.<collection-size-columns> )
|
||||||
|
@ -67,36 +56,10 @@ public class CollectionSizeNode extends SqlNode implements SelectExpression {
|
||||||
// <owner-key-column> => ???
|
// <owner-key-column> => ???
|
||||||
|
|
||||||
|
|
||||||
final FromElement collectionOwnerFromElement = collectionPathNode.getCollectionOwnerRef();
|
final String[] ownerKeyColumns = collectionPathNode.resolveOwnerKeyColumnExpressions();
|
||||||
|
|
||||||
|
final FromElement collectionOwnerFromElement = collectionPathNode.getCollectionOwnerFromElement();
|
||||||
final QueryableCollection collectionDescriptor = (QueryableCollection) collectionPathNode.getCollectionDescriptor();
|
final QueryableCollection collectionDescriptor = (QueryableCollection) collectionPathNode.getCollectionDescriptor();
|
||||||
final String collectionPropertyName = collectionPathNode.getCollectionPropertyName();
|
|
||||||
|
|
||||||
getWalker().addQuerySpaces( collectionDescriptor.getCollectionSpaces() );
|
|
||||||
|
|
||||||
// silly : need to prime `SessionFactoryHelper#collectionPropertyMappingByRole`
|
|
||||||
walker.getSessionFactoryHelper().requireQueryableCollection( collectionDescriptor.getRole() );
|
|
||||||
|
|
||||||
// owner-key
|
|
||||||
final String[] ownerKeyColumns;
|
|
||||||
final AST ast = walker.getAST();
|
|
||||||
final String ownerTableAlias;
|
|
||||||
if ( ast instanceof DeleteStatement || ast instanceof UpdateStatement ) {
|
|
||||||
ownerTableAlias = collectionOwnerFromElement.getTableName();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ownerTableAlias = collectionOwnerFromElement.getTableAlias();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String lhsPropertyName = collectionDescriptor.getCollectionType().getLHSPropertyName();
|
|
||||||
if ( lhsPropertyName == null ) {
|
|
||||||
ownerKeyColumns = StringHelper.qualify(
|
|
||||||
ownerTableAlias,
|
|
||||||
( (Joinable) collectionDescriptor.getOwnerEntityPersister() ).getKeyColumnNames()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ownerKeyColumns = collectionOwnerFromElement.toColumns( ownerTableAlias, lhsPropertyName, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
// collection-key
|
// collection-key
|
||||||
final String collectionTableAlias = collectionOwnerFromElement.getFromClause()
|
final String collectionTableAlias = collectionOwnerFromElement.getFromClause()
|
||||||
|
@ -104,15 +67,10 @@ public class CollectionSizeNode extends SqlNode implements SelectExpression {
|
||||||
.createName( collectionPathNode.getCollectionPropertyName() );
|
.createName( collectionPathNode.getCollectionPropertyName() );
|
||||||
final String[] collectionKeyColumns = StringHelper.qualify( collectionTableAlias, collectionDescriptor.getKeyColumnNames() );
|
final String[] collectionKeyColumns = StringHelper.qualify( collectionTableAlias, collectionDescriptor.getKeyColumnNames() );
|
||||||
|
|
||||||
|
|
||||||
if ( collectionKeyColumns.length != ownerKeyColumns.length ) {
|
if ( collectionKeyColumns.length != ownerKeyColumns.length ) {
|
||||||
throw new AssertionFailure( "Mismatch between collection key columns" );
|
throw new AssertionFailure( "Mismatch between collection key columns" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// PropertyMapping(c).toColumns(customers)
|
|
||||||
// PropertyMapping(c.customers).toColumns(SIZE)
|
|
||||||
|
|
||||||
// size expression (the count function)
|
|
||||||
final String[] sizeColumns = this.collectionPropertyMapping.toColumns(
|
final String[] sizeColumns = this.collectionPropertyMapping.toColumns(
|
||||||
collectionTableAlias,
|
collectionTableAlias,
|
||||||
CollectionPropertyNames.COLLECTION_SIZE
|
CollectionPropertyNames.COLLECTION_SIZE
|
||||||
|
@ -159,13 +117,13 @@ public class CollectionSizeNode extends SqlNode implements SelectExpression {
|
||||||
// SelectExpression
|
// SelectExpression
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setScalarColumnText(int i) throws SemanticException {
|
public void setScalarColumnText(int i) {
|
||||||
log.debugf( "setScalarColumnText(%s)", i );
|
log.debugf( "setScalarColumnText(%s)", i );
|
||||||
scalarName = NameGenerator.scalarName( i, 0 );
|
scalarName = NameGenerator.scalarName( i, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setScalarColumn(int i) throws SemanticException {
|
public void setScalarColumn(int i) {
|
||||||
log.debugf( "setScalarColumn(%s)", i );
|
log.debugf( "setScalarColumn(%s)", i );
|
||||||
setScalarColumnText( i );
|
setScalarColumnText( i );
|
||||||
}
|
}
|
||||||
|
@ -186,12 +144,12 @@ public class CollectionSizeNode extends SqlNode implements SelectExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReturnableEntity() throws SemanticException {
|
public boolean isReturnableEntity() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isScalar() throws SemanticException {
|
public boolean isScalar() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue