1 package org.hibernate.hql.classic; 3 4 import java.util.HashMap ; 5 import java.util.HashSet ; 6 import java.util.LinkedList ; 7 import java.util.Map ; 8 import java.util.Set ; 9 import java.util.StringTokenizer ; 10 11 import org.hibernate.MappingException; 12 import org.hibernate.QueryException; 13 import org.hibernate.engine.JoinSequence; 14 import org.hibernate.hql.QueryTranslator; 15 import org.hibernate.persister.collection.CollectionPropertyNames; 16 import org.hibernate.persister.entity.Queryable; 17 import org.hibernate.sql.InFragment; 18 import org.hibernate.type.EntityType; 19 import org.hibernate.type.LiteralType; 20 import org.hibernate.type.Type; 21 import org.hibernate.type.TypeFactory; 22 import org.hibernate.util.ReflectHelper; 23 import org.hibernate.util.StringHelper; 24 25 29 30 34 40 public class WhereParser implements Parser { 41 42 private final PathExpressionParser pathExpressionParser; 43 44 { 45 pathExpressionParser = new PathExpressionParser(); 46 pathExpressionParser.setUseThetaStyleJoin( true ); } 48 49 private static final Set EXPRESSION_TERMINATORS = new HashSet (); private static final Set EXPRESSION_OPENERS = new HashSet (); private static final Set BOOLEAN_OPERATORS = new HashSet (); private static final Map NEGATIONS = new HashMap (); 53 54 static { 55 EXPRESSION_TERMINATORS.add( "and" ); 56 EXPRESSION_TERMINATORS.add( "or" ); 57 EXPRESSION_TERMINATORS.add( ")" ); 58 60 EXPRESSION_OPENERS.add( "and" ); 61 EXPRESSION_OPENERS.add( "or" ); 62 EXPRESSION_OPENERS.add( "(" ); 63 65 BOOLEAN_OPERATORS.add( "<" ); 66 BOOLEAN_OPERATORS.add( "=" ); 67 BOOLEAN_OPERATORS.add( ">" ); 68 BOOLEAN_OPERATORS.add( "#" ); 69 BOOLEAN_OPERATORS.add( "~" ); 70 BOOLEAN_OPERATORS.add( "like" ); 71 BOOLEAN_OPERATORS.add( "ilike" ); 72 BOOLEAN_OPERATORS.add( "regexp" ); 73 BOOLEAN_OPERATORS.add( "rlike" ); 74 BOOLEAN_OPERATORS.add( "is" ); 75 BOOLEAN_OPERATORS.add( "in" ); 76 BOOLEAN_OPERATORS.add( "any" ); 77 BOOLEAN_OPERATORS.add( "some" ); 78 BOOLEAN_OPERATORS.add( "all" ); 79 BOOLEAN_OPERATORS.add( "exists" ); 80 BOOLEAN_OPERATORS.add( "between" ); 81 BOOLEAN_OPERATORS.add( "<=" ); 82 BOOLEAN_OPERATORS.add( ">=" ); 83 BOOLEAN_OPERATORS.add( "=>" ); 84 BOOLEAN_OPERATORS.add( "=<" ); 85 BOOLEAN_OPERATORS.add( "!=" ); 86 BOOLEAN_OPERATORS.add( "<>" ); 87 BOOLEAN_OPERATORS.add( "!#" ); 88 BOOLEAN_OPERATORS.add( "!~" ); 89 BOOLEAN_OPERATORS.add( "!<" ); 90 BOOLEAN_OPERATORS.add( "!>" ); 91 BOOLEAN_OPERATORS.add( "is not" ); 92 BOOLEAN_OPERATORS.add( "not like" ); 93 BOOLEAN_OPERATORS.add( "not ilike" ); 94 BOOLEAN_OPERATORS.add( "not regexp" ); 95 BOOLEAN_OPERATORS.add( "not rlike" ); 96 BOOLEAN_OPERATORS.add( "not in" ); 97 BOOLEAN_OPERATORS.add( "not between" ); 98 BOOLEAN_OPERATORS.add( "not exists" ); 99 100 NEGATIONS.put( "and", "or" ); 101 NEGATIONS.put( "or", "and" ); 102 NEGATIONS.put( "<", ">=" ); 103 NEGATIONS.put( "=", "<>" ); 104 NEGATIONS.put( ">", "<=" ); 105 NEGATIONS.put( "#", "!#" ); 106 NEGATIONS.put( "~", "!~" ); 107 NEGATIONS.put( "like", "not like" ); 108 NEGATIONS.put( "ilike", "not ilike" ); 109 NEGATIONS.put( "regexp", "not regexp" ); 110 NEGATIONS.put( "rlike", "not rlike" ); 111 NEGATIONS.put( "is", "is not" ); 112 NEGATIONS.put( "in", "not in" ); 113 NEGATIONS.put( "exists", "not exists" ); 114 NEGATIONS.put( "between", "not between" ); 115 NEGATIONS.put( "<=", ">" ); 116 NEGATIONS.put( ">=", "<" ); 117 NEGATIONS.put( "=>", "<" ); 118 NEGATIONS.put( "=<", ">" ); 119 NEGATIONS.put( "!=", "=" ); 120 NEGATIONS.put( "<>", "=" ); 121 NEGATIONS.put( "!#", "#" ); 122 NEGATIONS.put( "!~", "~" ); 123 NEGATIONS.put( "!<", "<" ); 124 NEGATIONS.put( "!>", ">" ); 125 NEGATIONS.put( "is not", "is" ); 126 NEGATIONS.put( "not like", "like" ); 127 NEGATIONS.put( "not ilike", "ilike" ); 128 NEGATIONS.put( "not regexp", "regexp" ); 129 NEGATIONS.put( "not rlike", "rlike" ); 130 NEGATIONS.put( "not in", "in" ); 131 NEGATIONS.put( "not between", "between" ); 132 NEGATIONS.put( "not exists", "exists" ); 133 134 } 135 154 private boolean betweenSpecialCase = false; private boolean negated = false; 156 157 private boolean inSubselect = false; 158 private int bracketsSinceSelect = 0; 159 private StringBuffer subselect; 160 161 private boolean expectingPathContinuation = false; 162 private int expectingIndex = 0; 163 164 167 private LinkedList nots = new LinkedList (); private LinkedList joins = new LinkedList (); private LinkedList booleanTests = new LinkedList (); 171 private String getElementName(PathExpressionParser.CollectionElement element, QueryTranslatorImpl q) throws QueryException { 172 String name; 173 if ( element.isOneToMany ) { 174 name = element.alias; 175 } 176 else { 177 Type type = element.elementType; 178 if ( type.isEntityType() ) { String entityName = ( ( EntityType ) type ).getAssociatedEntityName(); 180 name = pathExpressionParser.continueFromManyToMany( entityName, element.elementColumns, q ); 181 } 182 else { 183 throw new QueryException( "illegally dereferenced collection element" ); 184 } 185 } 186 return name; 187 } 188 189 public void token(String token, QueryTranslatorImpl q) throws QueryException { 190 191 String lcToken = token.toLowerCase(); 192 193 if ( token.equals( "[" ) && !expectingPathContinuation ) { 195 expectingPathContinuation = false; 196 if ( expectingIndex == 0 ) throw new QueryException( "unexpected [" ); 197 return; 198 } 199 else if ( token.equals( "]" ) ) { 200 expectingIndex--; 201 expectingPathContinuation = true; 202 return; 203 } 204 205 if ( expectingPathContinuation ) { 207 boolean pathExpressionContinuesFurther = continuePathExpression( token, q ); 208 if ( pathExpressionContinuesFurther ) return; } 210 211 if ( !inSubselect && ( lcToken.equals( "select" ) || lcToken.equals( "from" ) ) ) { 213 inSubselect = true; 214 subselect = new StringBuffer ( 20 ); 215 } 216 if ( inSubselect && token.equals( ")" ) ) { 217 bracketsSinceSelect--; 218 219 if ( bracketsSinceSelect == -1 ) { 220 QueryTranslatorImpl subq = new QueryTranslatorImpl( 221 subselect.toString(), 222 q.getEnabledFilters(), 223 q.getFactory() 224 ); 225 try { 226 subq.compile( q ); 227 } 228 catch ( MappingException me ) { 229 throw new QueryException( "MappingException occurred compiling subquery", me ); 230 } 231 appendToken( q, subq.getSQLString() ); 232 inSubselect = false; 233 bracketsSinceSelect = 0; 234 } 235 } 236 if ( inSubselect ) { 237 if ( token.equals( "(" ) ) bracketsSinceSelect++; 238 subselect.append( token ).append( ' ' ); 239 return; 240 } 241 242 specialCasesBefore( lcToken ); 244 245 if ( !betweenSpecialCase && EXPRESSION_TERMINATORS.contains( lcToken ) ) { 247 closeExpression( q, lcToken ); 248 } 249 250 if ( BOOLEAN_OPERATORS.contains( lcToken ) ) { 252 booleanTests.removeLast(); 253 booleanTests.addLast( Boolean.TRUE ); 254 } 255 256 if ( lcToken.equals( "not" ) ) { 257 nots.addLast( new Boolean ( !( ( Boolean ) nots.removeLast() ).booleanValue() ) ); 258 negated = !negated; 259 return; } 261 262 doToken( token, q ); 264 265 if ( !betweenSpecialCase && EXPRESSION_OPENERS.contains( lcToken ) ) { 267 openExpression( q, lcToken ); 268 } 269 270 specialCasesAfter( lcToken ); 272 273 } 274 275 public void start(QueryTranslatorImpl q) throws QueryException { 276 token( "(", q ); 277 } 278 279 public void end(QueryTranslatorImpl q) throws QueryException { 280 if ( expectingPathContinuation ) { 281 expectingPathContinuation = false; 282 PathExpressionParser.CollectionElement element = pathExpressionParser.lastCollectionElement(); 283 if ( element.elementColumns.length != 1 ) throw new QueryException( "path expression ended in composite collection element" ); 284 appendToken( q, element.elementColumns[0] ); 285 addToCurrentJoin( element ); 286 } 287 token( ")", q ); 288 } 289 290 private void closeExpression(QueryTranslatorImpl q, String lcToken) { 291 if ( ( ( Boolean ) booleanTests.removeLast() ).booleanValue() ) { 293 if ( booleanTests.size() > 0 ) { 294 booleanTests.removeLast(); 296 booleanTests.addLast( Boolean.TRUE ); 297 } 298 299 appendToken( q, ( joins.removeLast() ).toString() ); 301 302 } 303 else { 304 StringBuffer join = ( StringBuffer ) joins.removeLast(); 305 ( ( StringBuffer ) joins.getLast() ).append( join.toString() ); 306 } 307 308 if ( ( ( Boolean ) nots.removeLast() ).booleanValue() ) negated = !negated; 309 310 if ( !")".equals( lcToken ) ) appendToken( q, ")" ); 311 } 312 313 private void openExpression(QueryTranslatorImpl q, String lcToken) { 314 nots.addLast( Boolean.FALSE ); 315 booleanTests.addLast( Boolean.FALSE ); 316 joins.addLast( new StringBuffer () ); 317 if ( !"(".equals( lcToken ) ) appendToken( q, "(" ); 318 } 319 320 private void preprocess(String token, QueryTranslatorImpl q) throws QueryException { 321 String [] tokens = StringHelper.split( ".", token, true ); 324 if ( 325 tokens.length > 5 && 326 ( CollectionPropertyNames.COLLECTION_ELEMENTS.equals( tokens[tokens.length - 1] ) 327 || CollectionPropertyNames.COLLECTION_INDICES.equals( tokens[tokens.length - 1] ) ) 328 ) { 329 pathExpressionParser.start( q ); 330 for ( int i = 0; i < tokens.length - 3; i++ ) { 331 pathExpressionParser.token( tokens[i], q ); 332 } 333 pathExpressionParser.token( null, q ); 334 pathExpressionParser.end( q ); 335 addJoin( pathExpressionParser.getWhereJoin(), q ); 336 pathExpressionParser.ignoreInitialJoin(); 337 } 338 } 339 340 private void doPathExpression(String token, QueryTranslatorImpl q) throws QueryException { 341 342 preprocess( token, q ); 343 344 StringTokenizer tokens = new StringTokenizer ( token, ".", true ); 345 pathExpressionParser.start( q ); 346 while ( tokens.hasMoreTokens() ) { 347 pathExpressionParser.token( tokens.nextToken(), q ); 348 } 349 pathExpressionParser.end( q ); 350 if ( pathExpressionParser.isCollectionValued() ) { 351 openExpression( q, "" ); 352 appendToken( q, pathExpressionParser.getCollectionSubquery( q.getEnabledFilters() ) ); 353 closeExpression( q, "" ); 354 q.addQuerySpaces( q.getCollectionPersister( pathExpressionParser.getCollectionRole() ).getCollectionSpaces() ); 356 } 357 else { 358 if ( pathExpressionParser.isExpectingCollectionIndex() ) { 359 expectingIndex++; 360 } 361 else { 362 addJoin( pathExpressionParser.getWhereJoin(), q ); 363 appendToken( q, pathExpressionParser.getWhereColumn() ); 364 } 365 } 366 } 367 368 private void addJoin(JoinSequence joinSequence, QueryTranslatorImpl q) throws QueryException { 369 q.addFromJoinOnly( pathExpressionParser.getName(), joinSequence ); 372 try { 373 addToCurrentJoin( joinSequence.toJoinFragment( q.getEnabledFilters(), true ).toWhereFragmentString() ); 374 } 375 catch ( MappingException me ) { 376 throw new QueryException( me ); 377 } 378 } 379 380 private void doToken(String token, QueryTranslatorImpl q) throws QueryException { 381 if ( q.isName( StringHelper.root( token ) ) ) { doPathExpression( q.unalias( token ), q ); 383 } 384 else if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) { q.addNamedParameter( token.substring( 1 ) ); 386 appendToken( q, "?" ); 387 } 388 else { 389 Queryable persister = q.getEntityPersisterUsingImports( token ); 390 if ( persister != null ) { final String discrim = persister.getDiscriminatorSQLValue(); 392 if ( InFragment.NULL.equals(discrim) || InFragment.NOT_NULL.equals(discrim) ) { 393 throw new QueryException( "subclass test not allowed for null or not null discriminator" ); 394 } 395 else { 396 appendToken( q, discrim ); 397 } 398 } 399 else { 400 Object constant; 401 if ( 402 token.indexOf( '.' ) > -1 && 403 ( constant = ReflectHelper.getConstantValue( token ) ) != null 404 ) { 405 Type type; 406 try { 407 type = TypeFactory.heuristicType( constant.getClass().getName() ); 408 } 409 catch ( MappingException me ) { 410 throw new QueryException( me ); 411 } 412 if ( type == null ) throw new QueryException( QueryTranslator.ERROR_CANNOT_DETERMINE_TYPE + token ); 413 try { 414 appendToken( q, ( ( LiteralType ) type ).objectToSQLString( constant ) ); 415 } 416 catch ( Exception e ) { 417 throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + token, e ); 418 } 419 } 420 else { 422 String negatedToken = negated ? ( String ) NEGATIONS.get( token.toLowerCase() ) : null; 423 if ( negatedToken != null && ( !betweenSpecialCase || !"or".equals( negatedToken ) ) ) { 424 appendToken( q, negatedToken ); 425 } 426 else { 427 appendToken( q, token ); 428 } 429 } 430 } 431 } 432 } 433 434 private void addToCurrentJoin(String sql) { 435 ( ( StringBuffer ) joins.getLast() ).append( sql ); 436 } 437 438 private void addToCurrentJoin(PathExpressionParser.CollectionElement ce) 439 throws QueryException { 440 try { 441 addToCurrentJoin( ce.joinSequence.toJoinFragment().toWhereFragmentString() + ce.indexValue.toString() ); 442 } 443 catch ( MappingException me ) { 444 throw new QueryException( me ); 445 } 446 } 447 448 private void specialCasesBefore(String lcToken) { 449 if ( lcToken.equals( "between" ) || lcToken.equals( "not between" ) ) { 450 betweenSpecialCase = true; 451 } 452 } 453 454 private void specialCasesAfter(String lcToken) { 455 if ( betweenSpecialCase && lcToken.equals( "and" ) ) { 456 betweenSpecialCase = false; 457 } 458 } 459 460 void appendToken(QueryTranslatorImpl q, String token) { 461 if ( expectingIndex > 0 ) { 462 pathExpressionParser.setLastCollectionElementIndexValue( token ); 463 } 464 else { 465 q.appendWhereToken( token ); 466 } 467 } 468 469 private boolean continuePathExpression(String token, QueryTranslatorImpl q) throws QueryException { 470 471 expectingPathContinuation = false; 472 473 PathExpressionParser.CollectionElement element = pathExpressionParser.lastCollectionElement(); 474 475 if ( token.startsWith( "." ) ) { 477 doPathExpression( getElementName( element, q ) + token, q ); 479 addToCurrentJoin( element ); 480 return true; 482 } 483 484 else { if ( element.elementColumns.length != 1 ) { 486 throw new QueryException( "path expression ended in composite collection element" ); 487 } 488 appendToken( q, element.elementColumns[0] ); 489 addToCurrentJoin( element ); 490 return false; 491 } 492 } 493 } 494 | Popular Tags |