Open Source Repository

Home /hibernate/hibernate-3.2.7.ga | Repository Home


org/hibernate/hql/ast/util/SyntheticAndFactory.java
// $Id: SyntheticAndFactory.java 15759 2009-01-09 05:40:48Z [email protected] $
package org.hibernate.hql.ast.util;

import java.util.Map;

import org.hibernate.hql.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.ast.tree.FromElement;
import org.hibernate.hql.ast.tree.QueryNode;
import org.hibernate.hql.ast.tree.RestrictableStatement;
import org.hibernate.hql.ast.tree.SqlFragment;
import org.hibernate.hql.ast.tree.Node;
import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.util.StringHelper;
import org.hibernate.type.Type;
import org.hibernate.param.CollectionFilterKeyParameterSpecification;

import antlr.collections.AST;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Creates synthetic and nodes based on the where fragment part of a JoinSequence.
 *
 @author josh Dec 5, 2004 12:25:20 PM
 */
public class SyntheticAndFactory implements HqlSqlTokenTypes {
  private static final Log log = LogFactory.getLogSyntheticAndFactory.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 ASTUtil.createhqlSqlWalker.getASTFactory(), 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.isEmptywhereFragment ) ) {
      return;
    }

    // Forcefully remove leading ands from where fragments; the grammar will
    // handle adding them
    if whereFragment.startsWith"and" ) ) {
      whereFragment = whereFragment.substring);
    }

    if log.isDebugEnabled() ) {
      log.debug"Using unprocessed WHERE-fragment [" + whereFragment + "]");
    }

    SqlFragment fragment = SqlFragment createSQL_TOKEN, whereFragment );
    fragment.setJoinFragmentjoinFragment );
    fragment.setFromElementfromElement );

    if fromElement.getIndexCollectionSelectorParamSpec() != null ) {
      fragment.addEmbeddedParameterfromElement.getIndexCollectionSelectorParamSpec() );
      fromElement.setIndexCollectionSelectorParamSpecnull );
    }

    if hqlSqlWalker.isFilter() ) {
      if whereFragment.indexOf'?' >= ) {
        Type collectionFilterKeyType = hqlSqlWalker.getSessionFactoryHelper()
            .requireQueryableCollectionhqlSqlWalker.getCollectionFilterRole() )
            .getKeyType();
        CollectionFilterKeyParameterSpecification paramSpec = new CollectionFilterKeyParameterSpecification(
            hqlSqlWalker.getCollectionFilterRole(),
            collectionFilterKeyType,
            0
        );
        fragment.addEmbeddedParameterparamSpec );
      }
    }

    JoinProcessor.processDynamicFilterParameters(
        whereFragment,
        fragment,
        hqlSqlWalker
    );

    log.debug"Using processed WHERE-fragment [" + 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 = createFILTERS, "{filter conditions}" );
        // Put the FILTERS node before the HQL condition and theta joins
        ASTUtil.insertChildwhere, filters );
      }

      // add the current fragment to the FILTERS node
      filters.addChildfragment );
    }
    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 = createTHETA_JOINS, "{theta joins}" );
        // Put the THETA_JOINS node before the HQL condition, after the filters.
        if (filters==null) {
          ASTUtil.insertChildwhere, thetaJoins );
        }
        else {
          ASTUtil.insertSiblingthetaJoins, 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.filterFragmentalias, enabledFilters ).trim();
    if "".equalswhereFragment ) ) {
      return;
    }
    if whereFragment.startsWith"and" ) ) {
      whereFragment = whereFragment.substring);
    }

    // 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.replacewhereFragment, persister.generateFilterConditionAliasalias ".""" );

    // 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 createSQL_TOKEN, whereFragment );

    JoinProcessor.processDynamicFilterParameters(
        whereFragment,
        discrimNode,
        hqlSqlWalker
    );

    if statement.getWhereClause().getNumberOfChildren() == ) {
      statement.getWhereClause().setFirstChilddiscrimNode );
    }
    else {
      AST and = createAND, "{and}" );
      AST currentFirstChild = statement.getWhereClause().getFirstChild();
      and.setFirstChilddiscrimNode );
      and.addChildcurrentFirstChild );
      statement.getWhereClause().setFirstChildand );
    }
  }
}