org.hibernate.hql.internal.ast.util.SyntheticAndFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* 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 .
*/
package org.hibernate.hql.internal.ast.util;
import java.util.Map;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.HqlSqlWalker;
import org.hibernate.hql.internal.ast.tree.FromElement;
import org.hibernate.hql.internal.ast.tree.Node;
import org.hibernate.hql.internal.ast.tree.QueryNode;
import org.hibernate.hql.internal.ast.tree.RestrictableStatement;
import org.hibernate.hql.internal.ast.tree.SqlFragment;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.type.Type;
import antlr.collections.AST;
/**
* Creates synthetic and nodes based on the where fragment part of a JoinSequence.
*
* @author josh
*/
public class SyntheticAndFactory implements HqlSqlTokenTypes {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SyntheticAndFactory.class );
private HqlSqlWalker hqlSqlWalker;
private AST thetaJoins;
private AST filters;
public SyntheticAndFactory(HqlSqlWalker hqlSqlWalker) {
this.hqlSqlWalker = hqlSqlWalker;
}
private Node create(int tokenType, String text) {
return (Node) hqlSqlWalker.getASTFactory().create( tokenType, text );
}
public void addWhereFragment(
JoinFragment joinFragment,
String whereFragment,
QueryNode query,
FromElement fromElement,
HqlSqlWalker hqlSqlWalker) {
if ( whereFragment == null ) {
return;
}
if ( !fromElement.useWhereFragment() && !joinFragment.hasThetaJoins() ) {
return;
}
whereFragment = whereFragment.trim();
if ( StringHelper.isEmpty( whereFragment ) ) {
return;
}
// Forcefully remove leading ands from where fragments; the grammar will
// handle adding them
if ( whereFragment.startsWith( "and" ) ) {
whereFragment = whereFragment.substring( 4 );
}
LOG.debugf( "Using unprocessed WHERE-fragment [%s]", whereFragment );
SqlFragment fragment = (SqlFragment) create( SQL_TOKEN, whereFragment );
fragment.setJoinFragment( joinFragment );
fragment.setFromElement( fromElement );
if ( fromElement.getIndexCollectionSelectorParamSpec() != null ) {
fragment.addEmbeddedParameter( fromElement.getIndexCollectionSelectorParamSpec() );
fromElement.setIndexCollectionSelectorParamSpec( null );
}
if ( hqlSqlWalker.isFilter() ) {
if ( whereFragment.indexOf( '?' ) >= 0 ) {
Type collectionFilterKeyType = hqlSqlWalker.getSessionFactoryHelper()
.requireQueryableCollection( hqlSqlWalker.getCollectionFilterRole() )
.getKeyType();
CollectionFilterKeyParameterSpecification paramSpec = new CollectionFilterKeyParameterSpecification(
hqlSqlWalker.getCollectionFilterRole(),
collectionFilterKeyType
);
fragment.addEmbeddedParameter( paramSpec );
}
}
JoinProcessor.processDynamicFilterParameters(
whereFragment,
fragment,
hqlSqlWalker
);
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Using processed WHERE-fragment [%s]", fragment.getText() );
}
// Filter conditions need to be inserted before the HQL where condition and the
// theta join node. This is because org.hibernate.loader.Loader binds the filter parameters first,
// then it binds all the HQL query parameters, see org.hibernate.loader.Loader.processFilterParameters().
if ( fragment.getFromElement().isFilter() || fragment.hasFilterCondition() ) {
if ( filters == null ) {
// Find or create the WHERE clause
AST where = query.getWhereClause();
// Create a new FILTERS node as a parent of all filters
filters = create( FILTERS, "{filter conditions}" );
// Put the FILTERS node before the HQL condition and theta joins
ASTUtil.insertChild( where, filters );
}
// add the current fragment to the FILTERS node
filters.addChild( fragment );
}
else {
if ( thetaJoins == null ) {
// Find or create the WHERE clause
AST where = query.getWhereClause();
// Create a new THETA_JOINS node as a parent of all filters
thetaJoins = create( THETA_JOINS, "{theta joins}" );
// Put the THETA_JOINS node before the HQL condition, after the filters.
if ( filters == null ) {
ASTUtil.insertChild( where, thetaJoins );
}
else {
ASTUtil.insertSibling( thetaJoins, filters );
}
}
// add the current fragment to the THETA_JOINS node
thetaJoins.addChild( fragment );
}
}
public void addDiscriminatorWhereFragment(
RestrictableStatement statement,
Queryable persister,
Map enabledFilters,
String alias) {
String whereFragment = persister.filterFragment( alias, enabledFilters ).trim();
if ( "".equals( whereFragment ) ) {
return;
}
if ( whereFragment.startsWith( "and" ) ) {
whereFragment = whereFragment.substring( 4 );
}
// Need to parse off the column qualifiers; this is assuming (which is true as of now)
// that this is only used from update and delete HQL statement parsing
whereFragment = StringHelper.replace(
whereFragment,
persister.generateFilterConditionAlias( alias ) + ".",
""
);
// Note: this simply constructs a "raw" SQL_TOKEN representing the
// where fragment and injects this into the tree. This "works";
// however it is probably not the best long-term solution.
//
// At some point we probably want to apply an additional grammar to
// properly tokenize this where fragment into constituent parts
// focused on the operators embedded within the fragment.
SqlFragment discrimNode = (SqlFragment) create( SQL_TOKEN, whereFragment );
JoinProcessor.processDynamicFilterParameters(
whereFragment,
discrimNode,
hqlSqlWalker
);
if ( statement.getWhereClause().getNumberOfChildren() == 0 ) {
statement.getWhereClause().setFirstChild( discrimNode );
}
else {
AST and = create( AND, "{and}" );
AST currentFirstChild = statement.getWhereClause().getFirstChild();
and.setFirstChild( discrimNode );
and.addChild( currentFirstChild );
statement.getWhereClause().setFirstChild( and );
}
}
}