1 package org.hibernate.hql.ast.tree; 3 4 import org.hibernate.engine.JoinSequence; 5 import org.hibernate.hql.antlr.SqlTokenTypes; 6 import org.hibernate.hql.ast.util.ASTUtil; 7 import org.hibernate.hql.ast.util.AliasGenerator; 8 import org.hibernate.hql.ast.util.PathHelper; 9 import org.hibernate.hql.ast.util.SessionFactoryHelper; 10 import org.hibernate.persister.collection.QueryableCollection; 11 import org.hibernate.persister.entity.EntityPersister; 12 import org.hibernate.persister.entity.Joinable; 13 import org.hibernate.persister.entity.Queryable; 14 import org.hibernate.sql.JoinFragment; 15 import org.hibernate.type.AssociationType; 16 import org.hibernate.type.CollectionType; 17 import org.hibernate.type.EntityType; 18 import org.hibernate.type.Type; 19 20 import antlr.ASTFactory; 21 import antlr.SemanticException; 22 import antlr.collections.AST; 23 24 import org.apache.commons.logging.Log; 25 import org.apache.commons.logging.LogFactory; 26 27 32 class FromElementFactory implements SqlTokenTypes { 33 34 private static final Log log = LogFactory.getLog( FromElementFactory.class ); 35 36 private FromClause fromClause; 37 private FromElement origin; 38 private String path; 39 40 private String classAlias; 41 private String [] columns; 42 private boolean implied; 43 private boolean inElementsFunction; 44 private boolean collection; 45 private QueryableCollection queryableCollection; 46 private CollectionType collectionType; 47 48 51 public FromElementFactory(FromClause fromClause, FromElement origin, String path) { 52 this.fromClause = fromClause; 53 this.origin = origin; 54 this.path = path; 55 collection = false; 56 } 57 58 61 public FromElementFactory( 62 FromClause fromClause, 63 FromElement origin, 64 String path, 65 String classAlias, 66 String [] columns, 67 boolean implied) { 68 this( fromClause, origin, path ); 69 this.classAlias = classAlias; 70 this.columns = columns; 71 this.implied = implied; 72 collection = true; 73 } 74 75 FromElement addFromElement() throws SemanticException { 76 FromClause parentFromClause = fromClause.getParentFromClause(); 77 if ( parentFromClause != null ) { 78 String pathAlias = PathHelper.getAlias( path ); 80 FromElement parentFromElement = parentFromClause.getFromElement( pathAlias ); 81 if ( parentFromElement != null ) { 82 return createFromElementInSubselect( path, pathAlias, parentFromElement, classAlias ); 83 } 84 } 85 86 EntityPersister entityPersister = fromClause.getSessionFactoryHelper().requireClassPersister( path ); 87 88 FromElement elem = createAndAddFromElement( path, 89 classAlias, 90 entityPersister, 91 ( EntityType ) ( ( Queryable ) entityPersister ).getType(), 92 null ); 93 94 fromClause.getWalker().addQuerySpaces( entityPersister.getQuerySpaces() ); 96 97 return elem; 98 } 99 100 private FromElement createFromElementInSubselect( 101 String path, 102 String pathAlias, 103 FromElement parentFromElement, 104 String classAlias) throws SemanticException { 105 if ( log.isDebugEnabled() ) { 106 log.debug( "createFromElementInSubselect() : path = " + path ); 107 } 108 FromElement fromElement = evaluateFromElementPath( path, classAlias ); 110 EntityPersister entityPersister = fromElement.getEntityPersister(); 111 112 String tableAlias = null; 116 boolean correlatedSubselect = pathAlias.equals( parentFromElement.getClassAlias() ); 117 if ( correlatedSubselect ) { 118 tableAlias = fromElement.getTableAlias(); 119 } 120 else { 121 tableAlias = null; 122 } 123 124 if ( fromElement.getFromClause() != fromClause ) { 126 if ( log.isDebugEnabled() ) { 127 log.debug( "createFromElementInSubselect() : creating a new FROM element..." ); 128 } 129 fromElement = createFromElement( entityPersister ); 130 initializeAndAddFromElement( fromElement, 131 path, 132 classAlias, 133 entityPersister, 134 ( EntityType ) ( ( Queryable ) entityPersister ).getType(), 135 tableAlias 136 ); 137 } 138 if ( log.isDebugEnabled() ) { 139 log.debug( "createFromElementInSubselect() : " + path + " -> " + fromElement ); 140 } 141 return fromElement; 142 } 143 144 private FromElement evaluateFromElementPath(String path, String classAlias) throws SemanticException { 145 ASTFactory factory = fromClause.getASTFactory(); 146 FromReferenceNode pathNode = ( FromReferenceNode ) PathHelper.parsePath( path, factory ); 147 pathNode.recursiveResolve( FromReferenceNode.ROOT_LEVEL, false, classAlias, 150 null 151 ); 152 if ( pathNode.getImpliedJoin() != null ) { 153 return pathNode.getImpliedJoin(); 154 } 155 else { 156 return pathNode.getFromElement(); 157 } 158 } 159 160 FromElement createCollectionElementsJoin( 161 QueryableCollection queryableCollection, 162 String collectionName) throws SemanticException { 163 JoinSequence collectionJoinSequence = fromClause.getSessionFactoryHelper() 164 .createCollectionJoinSequence( queryableCollection, collectionName ); 165 this.queryableCollection = queryableCollection; 166 return createCollectionJoin( collectionJoinSequence, null ); 167 } 168 169 FromElement createCollection( 170 QueryableCollection queryableCollection, 171 String role, 172 int joinType, 173 boolean fetchFlag, 174 boolean indexed) 175 throws SemanticException { 176 if ( !collection ) { 177 throw new IllegalStateException ( "FromElementFactory not initialized for collections!" ); 178 } 179 this.inElementsFunction = indexed; 180 FromElement elem; 181 this.queryableCollection = queryableCollection; 182 collectionType = queryableCollection.getCollectionType(); 183 String roleAlias = fromClause.getAliasGenerator().createName( role ); 184 185 boolean explicitSubqueryFromElement = fromClause.isSubQuery() && !implied; 189 if ( explicitSubqueryFromElement ) { 190 implied = true; 191 } 192 193 Type elementType = queryableCollection.getElementType(); 194 if ( elementType.isEntityType() ) { elem = createEntityAssociation( role, roleAlias, joinType ); 196 } 197 else if ( elementType.isComponentType() ) { JoinSequence joinSequence = createJoinSequence( roleAlias, joinType ); 199 elem = createCollectionJoin( joinSequence, roleAlias ); 200 } 201 else { JoinSequence joinSequence = createJoinSequence( roleAlias, joinType ); 203 elem = createCollectionJoin( joinSequence, roleAlias ); 204 } 205 206 elem.setRole( role ); 207 elem.setQueryableCollection( queryableCollection ); 208 if ( implied ) { 210 elem.setIncludeSubclasses( false ); 211 } 212 213 if ( explicitSubqueryFromElement ) { 214 elem.setInProjectionList( true ); } 216 217 if ( fetchFlag ) { 218 elem.setFetch( true ); 219 } 220 return elem; 221 } 222 223 FromElement createEntityJoin( 224 String entityClass, 225 String tableAlias, 226 JoinSequence joinSequence, 227 boolean fetchFlag, 228 boolean inFrom, 229 EntityType type) throws SemanticException { 230 FromElement elem = createJoin( entityClass, tableAlias, joinSequence, type, false ); 231 elem.setFetch( fetchFlag ); 232 EntityPersister entityPersister = elem.getEntityPersister(); 233 int numberOfTables = entityPersister.getQuerySpaces().length; 234 if ( numberOfTables > 1 && implied && !elem.useFromFragment() ) { 235 if ( log.isDebugEnabled() ) { 236 log.debug( "createEntityJoin() : Implied multi-table entity join" ); 237 } 238 elem.setUseFromFragment( true ); 239 } 240 241 if ( implied && inFrom ) { 244 joinSequence.setUseThetaStyle( false ); 245 elem.setUseFromFragment( true ); 246 elem.setImpliedInFromClause( true ); 247 } 248 if ( elem.getWalker().isSubQuery() ) { 249 if ( elem.getFromClause() != elem.getOrigin().getFromClause() || 254 DotNode.useThetaStyleImplicitJoins ) { 256 elem.setType( FROM_FRAGMENT ); 258 joinSequence.setUseThetaStyle( true ); 259 elem.setUseFromFragment( false ); 260 } 261 } 262 263 return elem; 264 } 265 266 FromElement createElementJoin(QueryableCollection queryableCollection) throws SemanticException { 267 FromElement elem; 268 269 implied = true; inElementsFunction = true; 271 Type elementType = queryableCollection.getElementType(); 272 if ( !elementType.isEntityType() ) { 273 throw new IllegalArgumentException ( "Cannot create element join for a collection of non-entities!" ); 274 } 275 this.queryableCollection = queryableCollection; 276 SessionFactoryHelper sfh = fromClause.getSessionFactoryHelper(); 277 FromElement destination = null; 278 String tableAlias = null; 279 EntityPersister entityPersister = queryableCollection.getElementPersister(); 280 tableAlias = fromClause.getAliasGenerator().createName( entityPersister.getEntityName() ); 281 String associatedEntityName = entityPersister.getEntityName(); 282 EntityPersister targetEntityPersister = sfh.requireClassPersister( associatedEntityName ); 283 destination = createAndAddFromElement( associatedEntityName, 285 classAlias, 286 targetEntityPersister, 287 ( EntityType ) queryableCollection.getElementType(), 288 tableAlias 289 ); 290 if ( implied ) { 292 destination.setIncludeSubclasses( false ); 293 } 294 fromClause.addCollectionJoinFromElementByPath( path, destination ); 295 fromClause.getWalker().addQuerySpaces( entityPersister.getQuerySpaces() ); 298 299 CollectionType type = queryableCollection.getCollectionType(); 300 String role = type.getRole(); 301 String roleAlias = origin.getTableAlias(); 302 303 String [] targetColumns = sfh.getCollectionElementColumns( role, roleAlias ); 304 AssociationType elementAssociationType = sfh.getElementAssociationType( type ); 305 306 int joinType = JoinFragment.INNER_JOIN; 308 JoinSequence joinSequence = sfh.createJoinSequence( implied, elementAssociationType, tableAlias, joinType, targetColumns ); 309 elem = initializeJoin( path, destination, joinSequence, targetColumns, origin, false ); 310 elem.setUseFromFragment( true ); elem.setCollectionTableAlias( roleAlias ); return elem; 313 } 314 315 private FromElement createCollectionJoin(JoinSequence collectionJoinSequence, String tableAlias) throws SemanticException { 316 String text = queryableCollection.getTableName(); 317 AST ast = createFromElement( text ); 318 FromElement destination = ( FromElement ) ast; 319 Type elementType = queryableCollection.getElementType(); 320 if ( elementType.isCollectionType() ) { 321 throw new SemanticException( "Collections of collections are not supported!" ); 322 } 323 destination.initializeCollection( fromClause, classAlias, tableAlias ); 324 destination.setType( JOIN_FRAGMENT ); destination.setIncludeSubclasses( false ); destination.setCollectionJoin( true ); destination.setJoinSequence( collectionJoinSequence ); 328 destination.setOrigin( origin, false ); 329 origin.setText( "" ); origin.setCollectionJoin( true ); fromClause.addCollectionJoinFromElementByPath( path, destination ); 335 fromClause.getWalker().addQuerySpaces( queryableCollection.getCollectionSpaces() ); 336 return destination; 337 } 338 339 private FromElement createEntityAssociation( 340 String role, 341 String roleAlias, 342 int joinType) throws SemanticException { 343 FromElement elem; 344 Queryable entityPersister = ( Queryable ) queryableCollection.getElementPersister(); 345 String associatedEntityName = entityPersister.getEntityName(); 346 if ( queryableCollection.isOneToMany() ) { 348 if ( log.isDebugEnabled() ) { 349 log.debug( "createEntityAssociation() : One to many - path = " + path + " role = " + role + " associatedEntityName = " + associatedEntityName ); 350 } 351 JoinSequence joinSequence = createJoinSequence( roleAlias, joinType ); 352 353 elem = createJoin( associatedEntityName, roleAlias, joinSequence, ( EntityType ) queryableCollection.getElementType(), false ); 354 } 355 else { 356 if ( log.isDebugEnabled() ) { 357 log.debug( "createManyToMany() : path = " + path + " role = " + role + " associatedEntityName = " + associatedEntityName ); 358 } 359 elem = createManyToMany( role, associatedEntityName, 360 roleAlias, entityPersister, ( EntityType ) queryableCollection.getElementType(), joinType ); 361 fromClause.getWalker().addQuerySpaces( queryableCollection.getCollectionSpaces() ); 362 } 363 elem.setCollectionTableAlias( roleAlias ); 364 return elem; 365 } 366 367 private FromElement createJoin( 368 String entityClass, 369 String tableAlias, 370 JoinSequence joinSequence, 371 EntityType type, 372 boolean manyToMany) throws SemanticException { 373 EntityPersister entityPersister = fromClause.getSessionFactoryHelper().requireClassPersister( entityClass ); 375 FromElement destination = createAndAddFromElement( entityClass, 376 classAlias, 377 entityPersister, 378 type, 379 tableAlias ); 380 return initializeJoin( path, destination, joinSequence, getColumns(), origin, manyToMany ); 381 } 382 383 private FromElement createManyToMany( 384 String role, 385 String associatedEntityName, 386 String roleAlias, 387 Queryable entityPersister, 388 EntityType type, 389 int joinType) throws SemanticException { 390 FromElement elem; 391 SessionFactoryHelper sfh = fromClause.getSessionFactoryHelper(); 392 if ( inElementsFunction ) { 393 JoinSequence joinSequence = createJoinSequence( roleAlias, joinType ); 395 elem = createJoin( associatedEntityName, roleAlias, joinSequence, type, true ); 396 } 397 else { 398 String tableAlias = fromClause.getAliasGenerator().createName( entityPersister.getEntityName() ); 402 String [] secondJoinColumns = sfh.getCollectionElementColumns( role, roleAlias ); 403 JoinSequence joinSequence = createJoinSequence( roleAlias, joinType ); 405 joinSequence.addJoin( sfh.getElementAssociationType( collectionType ), tableAlias, joinType, secondJoinColumns ); 406 elem = createJoin( associatedEntityName, tableAlias, joinSequence, type, false ); 407 elem.setUseFromFragment( true ); 408 } 409 return elem; 410 } 411 412 private JoinSequence createJoinSequence(String roleAlias, int joinType) { 413 SessionFactoryHelper sessionFactoryHelper = fromClause.getSessionFactoryHelper(); 414 String [] joinColumns = getColumns(); 415 if ( collectionType == null ) { 416 throw new IllegalStateException ( "collectionType is null!" ); 417 } 418 return sessionFactoryHelper.createJoinSequence( implied, collectionType, roleAlias, joinType, joinColumns ); 419 } 420 421 private FromElement createAndAddFromElement( 422 String className, 423 String classAlias, 424 EntityPersister entityPersister, 425 EntityType type, 426 String tableAlias) { 427 if ( !( entityPersister instanceof Joinable ) ) { 428 throw new IllegalArgumentException ( "EntityPersister " + entityPersister + " does not implement Joinable!" ); 429 } 430 FromElement element = createFromElement( entityPersister ); 431 initializeAndAddFromElement( element, className, classAlias, entityPersister, type, tableAlias ); 432 return element; 433 } 434 435 private void initializeAndAddFromElement( 436 FromElement element, 437 String className, 438 String classAlias, 439 EntityPersister entityPersister, 440 EntityType type, 441 String tableAlias) { 442 if ( tableAlias == null ) { 443 AliasGenerator aliasGenerator = fromClause.getAliasGenerator(); 444 tableAlias = aliasGenerator.createName( entityPersister.getEntityName() ); 445 } 446 element.initializeEntity( fromClause, className, entityPersister, type, classAlias, tableAlias ); 447 } 448 449 private FromElement createFromElement(EntityPersister entityPersister) { 450 Joinable joinable = ( Joinable ) entityPersister; 451 String text = joinable.getTableName(); 452 AST ast = createFromElement( text ); 453 FromElement element = ( FromElement ) ast; 454 return element; 455 } 456 457 private AST createFromElement(String text) { 458 AST ast = ASTUtil.create( fromClause.getASTFactory(), 459 implied ? IMPLIED_FROM : FROM_FRAGMENT, text ); 461 ast.setType( FROM_FRAGMENT ); 465 return ast; 466 } 467 468 private FromElement initializeJoin( 469 String path, 470 FromElement destination, 471 JoinSequence joinSequence, 472 String [] columns, 473 FromElement origin, 474 boolean manyToMany) { 475 destination.setType( JOIN_FRAGMENT ); 476 destination.setJoinSequence( joinSequence ); 477 destination.setColumns( columns ); 478 destination.setOrigin( origin, manyToMany ); 479 fromClause.addJoinByPathMap( path, destination ); 480 return destination; 481 } 482 483 private String [] getColumns() { 484 if ( columns == null ) { 485 throw new IllegalStateException ( "No foriegn key columns were supplied!" ); 486 } 487 return columns; 488 } 489 } 490 | Popular Tags |