org.hibernate.hql.classic.SelectParser Maven / Gradle / Ivy
//$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.setUseThetaStyleJoin( true );
aggregatePathExpressionParser.setUseThetaStyleJoin( true );
}
public void token(String token, QueryTranslatorImpl q) throws QueryException {
String lctoken = token.toLowerCase();
if ( first ) {
first = false;
if ( "distinct".equals( lctoken ) ) {
q.setDistinct( true );
return;
}
else if ( "all".equals( lctoken ) ) {
q.setDistinct( false );
return;
}
}
if ( afterNew ) {
afterNew = false;
try {
holderClass = ReflectHelper.classForName( QuerySplitter.getImportedClass( token, q.getFactory() ) );
}
catch ( ClassNotFoundException cnfe ) {
throw new QueryException( cnfe );
}
if ( holderClass == null ) throw new QueryException( "class not found: " + token );
q.setHolderClass( holderClass );
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".equals( lctoken ) ) {
afterNew = true;
ready = false;
}
else if ( "(".equals( token ) ) {
if ( insideNew && !aggregate && !ready ) {
//opening paren in new Foo ( ... )
ready = true;
}
else if ( aggregate ) {
q.appendScalarSelectToken( token );
}
else {
throw new QueryException( "aggregate function expected before ( in SELECT" );
}
ready = true;
}
else if ( ")".equals( token ) ) {
if ( insideNew && !aggregate && !ready ) {
//if we are inside a new Result(), but not inside a nested function
insideNew = false;
}
else if ( aggregate && ready ) {
q.appendScalarSelectToken( token );
aggregateFuncTokenList.removeLast();
if ( aggregateFuncTokenList.size() < 1 ) {
aggregate = false;
ready = false;
}
}
else {
throw new QueryException( "( expected before ) in select" );
}
}
else if ( COUNT_MODIFIERS.contains( lctoken ) ) {
if ( !ready || !aggregate ) throw new QueryException( token + " only allowed inside aggregate function in SELECT" );
q.appendScalarSelectToken( token );
if ( "*".equals( token ) ) q.addSelectScalar( getFunction( "count", q ).getReturnType( Hibernate.LONG, q.getFactory() ) ); //special case
}
else if ( getFunction( lctoken, q ) != null && token.equals( q.unalias( token ) ) ) {
// the name of an SQL function
if ( !ready ) throw new QueryException( ", expected before aggregate function in SELECT: " + token );
aggregate = true;
aggregateAddSelectScalar = true;
aggregateFuncTokenList.add( lctoken );
ready = false;
q.appendScalarSelectToken( token );
if ( !aggregateHasArgs( lctoken, q ) ) {
q.addSelectScalar( aggregateType( aggregateFuncTokenList, null, q ) );
if ( !aggregateFuncNoArgsHasParenthesis( lctoken, q ) ) {
aggregateFuncTokenList.removeLast();
if ( aggregateFuncTokenList.size() < 1 ) {
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.parse( aggregatePathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
}
catch ( QueryException qex ) {
constantToken = true;
}
if ( constantToken ) {
q.appendScalarSelectToken( token );
}
else {
if ( aggregatePathExpressionParser.isCollectionValued() ) {
q.addCollection( aggregatePathExpressionParser.getCollectionName(),
aggregatePathExpressionParser.getCollectionRole() );
}
q.appendScalarSelectToken( aggregatePathExpressionParser.getWhereColumn() );
if ( aggregateAddSelectScalar ) {
q.addSelectScalar( aggregateType( aggregateFuncTokenList, aggregatePathExpressionParser.getWhereColumnType(), q ) );
aggregateAddSelectScalar = false;
}
aggregatePathExpressionParser.addAssociation( q );
}
}
else {
if ( !ready ) throw new QueryException( ", expected in SELECT" );
ParserHelper.parse( pathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
if ( pathExpressionParser.isCollectionValued() ) {
q.addCollection( pathExpressionParser.getCollectionName(),
pathExpressionParser.getCollectionRole() );
}
else if ( pathExpressionParser.getWhereColumnType().isEntityType() ) {
q.addSelectClass( pathExpressionParser.getSelectName() );
}
q.appendScalarSelectTokens( pathExpressionParser.getWhereColumns() );
q.addSelectScalar( pathExpressionParser.getWhereColumnType() );
pathExpressionParser.addAssociation( q );
ready = false;
}
}
public boolean aggregateHasArgs(String funcToken, QueryTranslatorImpl q) {
return getFunction( funcToken, q ).hasArguments();
}
public boolean aggregateFuncNoArgsHasParenthesis(String funcToken, QueryTranslatorImpl q) {
return getFunction( funcToken, q ).hasParenthesesIfNoArguments();
}
public Type aggregateType(List funcTokenList, Type type, QueryTranslatorImpl q) throws QueryException {
Type retType = type;
Type argType;
for ( int i = funcTokenList.size() - 1; i >= 0; i-- ) {
argType = retType;
String funcToken = ( String ) funcTokenList.get( i );
retType = getFunction( funcToken, q ).getReturnType( argType, q.getFactory() );
}
return retType;
}
private SQLFunction getFunction(String name, QueryTranslatorImpl q) {
return q.getFactory().getSqlFunctionRegistry().findSQLFunction( name );
}
public void start(QueryTranslatorImpl q) {
ready = true;
first = true;
aggregate = false;
afterNew = false;
insideNew = false;
holderClass = null;
aggregateFuncTokenList.clear();
}
public void end(QueryTranslatorImpl q) {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy