1 package org.hibernate.hql.classic; 3 4 import org.hibernate.Hibernate; 5 import org.hibernate.QueryException; 6 import org.hibernate.dialect.function.SQLFunction; 7 import org.hibernate.hql.QuerySplitter; 8 import org.hibernate.type.Type; 9 import org.hibernate.util.ReflectHelper; 10 11 import java.util.HashSet ; 12 import java.util.LinkedList ; 13 import java.util.List ; 14 import java.util.Set ; 15 16 21 public class SelectParser implements Parser { 22 23 25 private static final Set COUNT_MODIFIERS = new HashSet (); 26 27 static { 28 COUNT_MODIFIERS.add( "distinct" ); 29 COUNT_MODIFIERS.add( "all" ); 30 COUNT_MODIFIERS.add( "*" ); 31 } 32 33 private LinkedList aggregateFuncTokenList = new LinkedList (); 34 35 private boolean ready; 36 private boolean aggregate; 37 private boolean first; 38 private boolean afterNew; 39 private boolean insideNew; 40 private boolean aggregateAddSelectScalar; 41 private Class holderClass; 42 43 private final SelectPathExpressionParser pathExpressionParser; 44 private final PathExpressionParser aggregatePathExpressionParser; 45 46 { 47 pathExpressionParser = new SelectPathExpressionParser(); 48 aggregatePathExpressionParser = new PathExpressionParser(); 49 pathExpressionParser.setUseThetaStyleJoin( true ); 51 aggregatePathExpressionParser.setUseThetaStyleJoin( true ); 52 } 53 54 public void token(String token, QueryTranslatorImpl q) throws QueryException { 55 56 String lctoken = token.toLowerCase(); 57 58 if ( first ) { 59 first = false; 60 if ( "distinct".equals( lctoken ) ) { 61 q.setDistinct( true ); 62 return; 63 } 64 else if ( "all".equals( lctoken ) ) { 65 q.setDistinct( false ); 66 return; 67 } 68 } 69 70 if ( afterNew ) { 71 afterNew = false; 72 try { 73 holderClass = ReflectHelper.classForName( QuerySplitter.getImportedClass( token, q.getFactory() ) ); 74 } 75 catch ( ClassNotFoundException cnfe ) { 76 throw new QueryException( cnfe ); 77 } 78 if ( holderClass == null ) throw new QueryException( "class not found: " + token ); 79 q.setHolderClass( holderClass ); 80 insideNew = true; 81 } 82 else if ( token.equals( "," ) ) { 83 if ( !aggregate && ready ) throw new QueryException( "alias or expression expected in SELECT" ); 84 q.appendScalarSelectToken( ", " ); 85 ready = true; 86 } 87 else if ( "new".equals( lctoken ) ) { 88 afterNew = true; 89 ready = false; 90 } 91 else if ( "(".equals( token ) ) { 92 if ( insideNew && !aggregate && !ready ) { 93 ready = true; 95 } 96 else if ( aggregate ) { 97 q.appendScalarSelectToken( token ); 98 } 99 else { 100 throw new QueryException( "aggregate function expected before ( in SELECT" ); 101 } 102 ready = true; 103 } 104 else if ( ")".equals( token ) ) { 105 if ( insideNew && !aggregate && !ready ) { 106 insideNew = false; 108 } 109 else if ( aggregate && ready ) { 110 q.appendScalarSelectToken( token ); 111 aggregateFuncTokenList.removeLast(); 112 if ( aggregateFuncTokenList.size() < 1 ) { 113 aggregate = false; 114 ready = false; 115 } 116 } 117 else { 118 throw new QueryException( "( expected before ) in select" ); 119 } 120 } 121 else if ( COUNT_MODIFIERS.contains( lctoken ) ) { 122 if ( !ready || !aggregate ) throw new QueryException( token + " only allowed inside aggregate function in SELECT" ); 123 q.appendScalarSelectToken( token ); 124 if ( "*".equals( token ) ) q.addSelectScalar( Hibernate.INTEGER ); } 126 else if ( getFunction( lctoken, q ) != null && token.equals( q.unalias( token ) ) ) { 127 if ( !ready ) throw new QueryException( ", expected before aggregate function in SELECT: " + token ); 129 aggregate = true; 130 aggregateAddSelectScalar = true; 131 aggregateFuncTokenList.add( lctoken ); 132 ready = false; 133 q.appendScalarSelectToken( token ); 134 if ( !aggregateHasArgs( lctoken, q ) ) { 135 q.addSelectScalar( aggregateType( aggregateFuncTokenList, null, q ) ); 136 if ( !aggregateFuncNoArgsHasParenthesis( lctoken, q ) ) { 137 aggregateFuncTokenList.removeLast(); 138 if ( aggregateFuncTokenList.size() < 1 ) { 139 aggregate = false; 140 ready = false; 141 } 142 else { 143 ready = true; 144 } 145 } 146 } 147 } 148 else if ( aggregate ) { 149 boolean constantToken = false; 150 if ( !ready ) throw new QueryException( "( expected after aggregate function in SELECT" ); 151 try { 152 ParserHelper.parse( aggregatePathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q ); 153 } 154 catch ( QueryException qex ) { 155 constantToken = true; 156 } 157 158 if ( constantToken ) { 159 q.appendScalarSelectToken( token ); 160 } 161 else { 162 if ( aggregatePathExpressionParser.isCollectionValued() ) { 163 q.addCollection( aggregatePathExpressionParser.getCollectionName(), 164 aggregatePathExpressionParser.getCollectionRole() ); 165 } 166 q.appendScalarSelectToken( aggregatePathExpressionParser.getWhereColumn() ); 167 if ( aggregateAddSelectScalar ) { 168 q.addSelectScalar( aggregateType( aggregateFuncTokenList, aggregatePathExpressionParser.getWhereColumnType(), q ) ); 169 aggregateAddSelectScalar = false; 170 } 171 aggregatePathExpressionParser.addAssociation( q ); 172 } 173 } 174 else { 175 if ( !ready ) throw new QueryException( ", expected in SELECT" ); 176 ParserHelper.parse( pathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q ); 177 if ( pathExpressionParser.isCollectionValued() ) { 178 q.addCollection( pathExpressionParser.getCollectionName(), 179 pathExpressionParser.getCollectionRole() ); 180 } 181 else if ( pathExpressionParser.getWhereColumnType().isEntityType() ) { 182 q.addSelectClass( pathExpressionParser.getSelectName() ); 183 } 184 q.appendScalarSelectTokens( pathExpressionParser.getWhereColumns() ); 185 q.addSelectScalar( pathExpressionParser.getWhereColumnType() ); 186 pathExpressionParser.addAssociation( q ); 187 188 ready = false; 189 } 190 } 191 192 public boolean aggregateHasArgs(String funcToken, QueryTranslatorImpl q) { 193 return getFunction( funcToken, q ).hasArguments(); 194 } 195 196 public boolean aggregateFuncNoArgsHasParenthesis(String funcToken, QueryTranslatorImpl q) { 197 return getFunction( funcToken, q ).hasParenthesesIfNoArguments(); 198 } 199 200 public Type aggregateType(List funcTokenList, Type type, QueryTranslatorImpl q) throws QueryException { 201 Type retType = type; 202 Type argType; 203 for ( int i = funcTokenList.size() - 1; i >= 0; i-- ) { 204 argType = retType; 205 String funcToken = ( String ) funcTokenList.get( i ); 206 retType = getFunction( funcToken, q ).getReturnType( argType, q.getFactory() ); 207 } 208 return retType; 209 } 210 211 private SQLFunction getFunction(String name, QueryTranslatorImpl q) { 212 return ( SQLFunction ) q.getFactory().getDialect().getFunctions().get( name ); 213 } 214 215 public void start(QueryTranslatorImpl q) { 216 ready = true; 217 first = true; 218 aggregate = false; 219 afterNew = false; 220 insideNew = false; 221 holderClass = null; 222 aggregateFuncTokenList.clear(); 223 } 224 225 public void end(QueryTranslatorImpl q) { 226 } 227 228 } 229 | Popular Tags |