Open Source Repository

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


org/hibernate/hql/classic/SelectParser.java
//$Id: SelectParser.java 9915 2006-05-09 09:38:15Z [email protected] $
package org.hibernate.hql.classic;

import org.hibernate.Hibernate;
import org.hibernate.QueryException;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.hql.QuerySplitter;
import org.hibernate.type.Type;
import org.hibernate.util.ReflectHelper;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * Parsers the select clause of a Hibernate query.
 *
 @author Gavin King, David Channon
 */
public class SelectParser implements Parser {

  //TODO: arithmetic expressions, multiple new Foo(...)

  private static final Set COUNT_MODIFIERS = new HashSet();

  static {
    COUNT_MODIFIERS.add"distinct" );
    COUNT_MODIFIERS.add"all" );
    COUNT_MODIFIERS.add"*" );
  }

  private LinkedList aggregateFuncTokenList = new LinkedList();

  private boolean ready;
  private boolean aggregate;
  private boolean first;
  private boolean afterNew;
  private boolean insideNew;
  private boolean aggregateAddSelectScalar;
  private Class holderClass;

  private final SelectPathExpressionParser pathExpressionParser;
  private final PathExpressionParser aggregatePathExpressionParser;

  {
    pathExpressionParser = new SelectPathExpressionParser();
    aggregatePathExpressionParser = new PathExpressionParser();
    //TODO: would be nice to use false, but issues with MS SQL
    pathExpressionParser.setUseThetaStyleJointrue );
    aggregatePathExpressionParser.setUseThetaStyleJointrue );
  }

  public void token(String token, QueryTranslatorImpl qthrows QueryException {

    String lctoken = token.toLowerCase();

    if first ) {
      first = false;
      if "distinct".equalslctoken ) ) {
        q.setDistincttrue );
        return;
      }
      else if "all".equalslctoken ) ) {
        q.setDistinctfalse );
        return;
      }
    }

    if afterNew ) {
      afterNew = false;
      try {
        holderClass = ReflectHelper.classForNameQuerySplitter.getImportedClasstoken, q.getFactory() ) );
      }
      catch ClassNotFoundException cnfe ) {
        throw new QueryExceptioncnfe );
      }
      if holderClass == null throw new QueryException"class not found: " + token );
      q.setHolderClassholderClass );
      insideNew = true;
    }
    else if token.equals"," ) ) {
      if !aggregate && ready throw new QueryException"alias or expression expected in SELECT" );
      q.appendScalarSelectToken", " );
      ready = true;
    }
    else if "new".equalslctoken ) ) {
      afterNew = true;
      ready = false;
    }
    else if "(".equalstoken ) ) {
      if insideNew && !aggregate && !ready ) {
        //opening paren in new Foo ( ... )
        ready = true;
      }
      else if aggregate ) {
        q.appendScalarSelectTokentoken );
      }
      else {
        throw new QueryException"aggregate function expected before ( in SELECT" );
      }
      ready = true;
    }
    else if ")".equalstoken ) ) {
      if insideNew && !aggregate && !ready ) {
        //if we are inside a new Result(), but not inside a nested function
        insideNew = false;
      }
      else if aggregate && ready ) {
        q.appendScalarSelectTokentoken );
        aggregateFuncTokenList.removeLast();
        if aggregateFuncTokenList.size() ) {
          aggregate = false;
          ready = false;
        }
      }
      else {
        throw new QueryException"( expected before ) in select" );
      }
    }
    else if COUNT_MODIFIERS.containslctoken ) ) {
      if !ready || !aggregate throw new QueryExceptiontoken + " only allowed inside aggregate function in SELECT" );
      q.appendScalarSelectTokentoken );
      if "*".equalstoken ) ) q.addSelectScalargetFunction"count", q ).getReturnTypeHibernate.LONG, q.getFactory() ) )//special case
    }
    else if getFunctionlctoken, q != null && token.equalsq.unaliastoken ) ) ) {
      // the name of an SQL function
      if !ready throw new QueryException", expected before aggregate function in SELECT: " + token );
      aggregate = true;
      aggregateAddSelectScalar = true;
      aggregateFuncTokenList.addlctoken );
      ready = false;
      q.appendScalarSelectTokentoken );
      if !aggregateHasArgslctoken, q ) ) {
        q.addSelectScalaraggregateTypeaggregateFuncTokenList, null, q ) );
        if !aggregateFuncNoArgsHasParenthesislctoken, q ) ) {
          aggregateFuncTokenList.removeLast();
          if aggregateFuncTokenList.size() ) {
            aggregate = false;
            ready = false;
          }
          else {
            ready = true;
          }
        }
      }
    }
    else if aggregate ) {
      boolean constantToken = false;
      if !ready throw new QueryException"( expected after aggregate function in SELECT" );
      try {
        ParserHelper.parseaggregatePathExpressionParser, q.unaliastoken ), ParserHelper.PATH_SEPARATORS, q );
      }
      catch QueryException qex ) {
        constantToken = true;
      }

      if constantToken ) {
        q.appendScalarSelectTokentoken );
      }
      else {
        if aggregatePathExpressionParser.isCollectionValued() ) {
          q.addCollectionaggregatePathExpressionParser.getCollectionName(),
              aggregatePathExpressionParser.getCollectionRole() );
        }
        q.appendScalarSelectTokenaggregatePathExpressionParser.getWhereColumn() );
        if aggregateAddSelectScalar ) {
          q.addSelectScalaraggregateTypeaggregateFuncTokenList, aggregatePathExpressionParser.getWhereColumnType(), q ) );
          aggregateAddSelectScalar = false;
        }
        aggregatePathExpressionParser.addAssociation);
      }
    }
    else {
      if !ready throw new QueryException", expected in SELECT" );
      ParserHelper.parsepathExpressionParser, q.unaliastoken ), ParserHelper.PATH_SEPARATORS, q );
      if pathExpressionParser.isCollectionValued() ) {
        q.addCollectionpathExpressionParser.getCollectionName(),
            pathExpressionParser.getCollectionRole() );
      }
      else if pathExpressionParser.getWhereColumnType().isEntityType() ) {
        q.addSelectClasspathExpressionParser.getSelectName() );
      }
      q.appendScalarSelectTokenspathExpressionParser.getWhereColumns() );
      q.addSelectScalarpathExpressionParser.getWhereColumnType() );
      pathExpressionParser.addAssociation);

      ready = false;
    }
  }

  public boolean aggregateHasArgs(String funcToken, QueryTranslatorImpl q) {
    return getFunctionfuncToken, q ).hasArguments();
  }

  public boolean aggregateFuncNoArgsHasParenthesis(String funcToken, QueryTranslatorImpl q) {
    return getFunctionfuncToken, q ).hasParenthesesIfNoArguments();
  }

  public Type aggregateType(List funcTokenList, Type type, QueryTranslatorImpl qthrows QueryException {
    Type retType = type;
    Type argType;
    for int i = funcTokenList.size() 1; i >= 0; i-- ) {
      argType = retType;
      String funcToken = String funcTokenList.get);
      retType = getFunctionfuncToken, q ).getReturnTypeargType, q.getFactory() );
    }
    return retType;
  }

  private SQLFunction getFunction(String name, QueryTranslatorImpl q) {
    return q.getFactory().getSqlFunctionRegistry().findSQLFunctionname );
  }

  public void start(QueryTranslatorImpl q) {
    ready = true;
    first = true;
    aggregate = false;
    afterNew = false;
    insideNew = false;
    holderClass = null;
    aggregateFuncTokenList.clear();
  }

  public void end(QueryTranslatorImpl q) {
  }

}