18
18
import java .util .Map ;
19
19
import java .util .Set ;
20
20
21
- import org .hibernate .HibernateException ;
22
21
import org .hibernate .QueryException ;
23
22
import org .hibernate .engine .internal .JoinSequence ;
24
23
import org .hibernate .engine .internal .ParameterBinder ;
34
33
import org .hibernate .hql .internal .ast .tree .ConstructorNode ;
35
34
import org .hibernate .hql .internal .ast .tree .DeleteStatement ;
36
35
import org .hibernate .hql .internal .ast .tree .DotNode ;
36
+ import org .hibernate .hql .internal .ast .tree .EntityJoinFromElement ;
37
37
import org .hibernate .hql .internal .ast .tree .FromClause ;
38
38
import org .hibernate .hql .internal .ast .tree .FromElement ;
39
39
import org .hibernate .hql .internal .ast .tree .FromElementFactory ;
74
74
import org .hibernate .param .PositionalParameterSpecification ;
75
75
import org .hibernate .param .VersionTypeSeedParameterSpecification ;
76
76
import org .hibernate .persister .collection .QueryableCollection ;
77
+ import org .hibernate .persister .entity .EntityPersister ;
77
78
import org .hibernate .persister .entity .Queryable ;
78
79
import org .hibernate .sql .JoinType ;
79
80
import org .hibernate .type .AssociationType ;
80
- import org .hibernate .type .ComponentType ;
81
81
import org .hibernate .type .CompositeType ;
82
82
import org .hibernate .type .DbTimestampType ;
83
83
import org .hibernate .type .Type ;
@@ -363,50 +363,121 @@ protected void createFromJoinElement(
363
363
if ( fetch && isSubQuery () ) {
364
364
throw new QueryException ( "fetch not allowed in subquery from-elements" );
365
365
}
366
- // The path AST should be a DotNode, and it should have been evaluated already.
367
- if ( path .getType () != SqlTokenTypes .DOT ) {
368
- throw new SemanticException ( "Path expected for join!" );
369
- }
370
- DotNode dot = (DotNode ) path ;
371
- JoinType hibernateJoinType = JoinProcessor .toHibernateJoinType ( joinType );
372
- dot .setJoinType ( hibernateJoinType ); // Tell the dot node about the join type.
373
- dot .setFetch ( fetch );
374
- // Generate an explicit join for the root dot node. The implied joins will be collected and passed up
375
- // to the root dot node.
376
- dot .resolve ( true , false , alias == null ? null : alias .getText () );
377
-
378
- final FromElement fromElement ;
379
- if ( dot .getDataType () != null && dot .getDataType ().isComponentType () ) {
380
- if ( dot .getDataType ().isAnyType () ) {
381
- throw new SemanticException ( "An AnyType attribute cannot be join fetched" );
382
- // ^^ because the discriminator (aka, the "meta columns") must be known to the SQL in
383
- // a non-parameterized way.
384
- }
385
- FromElementFactory factory = new FromElementFactory (
386
- getCurrentFromClause (),
387
- dot .getLhs ().getFromElement (),
388
- dot .getPropertyPath (),
389
- alias == null ? null : alias .getText (),
390
- null ,
391
- false
366
+
367
+
368
+ // the incoming "path" can be either:
369
+ // 1) an implicit join path (join p.address.city)
370
+ // 2) an entity-join (join com.acme.User)
371
+ //
372
+ // so make the proper interpretation here...
373
+
374
+ final EntityPersister entityJoinReferencedPersister = resolveEntityJoinReferencedPersister ( path );
375
+ if ( entityJoinReferencedPersister != null ) {
376
+ // `path` referenced an entity
377
+ final EntityJoinFromElement join = createEntityJoin (
378
+ entityJoinReferencedPersister ,
379
+ alias ,
380
+ joinType ,
381
+ propertyFetch ,
382
+ with
392
383
);
393
- fromElement = factory .createComponentJoin ( (CompositeType ) dot .getDataType () );
384
+
385
+ ( (FromReferenceNode ) path ).setFromElement ( join );
394
386
}
395
387
else {
396
- fromElement = dot .getImpliedJoin ();
397
- fromElement .setAllPropertyFetch ( propertyFetch != null );
388
+ if ( path .getType () != SqlTokenTypes .DOT ) {
389
+ throw new SemanticException ( "Path expected for join!" );
390
+ }
398
391
399
- if ( with != null ) {
400
- if ( fetch ) {
401
- throw new SemanticException ( "with-clause not allowed on fetched associations; use filters" );
392
+ DotNode dot = (DotNode ) path ;
393
+ JoinType hibernateJoinType = JoinProcessor .toHibernateJoinType ( joinType );
394
+ dot .setJoinType ( hibernateJoinType ); // Tell the dot node about the join type.
395
+ dot .setFetch ( fetch );
396
+ // Generate an explicit join for the root dot node. The implied joins will be collected and passed up
397
+ // to the root dot node.
398
+ dot .resolve ( true , false , alias == null ? null : alias .getText () );
399
+
400
+ final FromElement fromElement ;
401
+ if ( dot .getDataType () != null && dot .getDataType ().isComponentType () ) {
402
+ if ( dot .getDataType ().isAnyType () ) {
403
+ throw new SemanticException ( "An AnyType attribute cannot be join fetched" );
404
+ // ^^ because the discriminator (aka, the "meta columns") must be known to the SQL in
405
+ // a non-parameterized way.
402
406
}
403
- handleWithFragment ( fromElement , with );
407
+ FromElementFactory factory = new FromElementFactory (
408
+ getCurrentFromClause (),
409
+ dot .getLhs ().getFromElement (),
410
+ dot .getPropertyPath (),
411
+ alias == null ? null : alias .getText (),
412
+ null ,
413
+ false
414
+ );
415
+ fromElement = factory .createComponentJoin ( (CompositeType ) dot .getDataType () );
416
+ }
417
+ else {
418
+ fromElement = dot .getImpliedJoin ();
419
+ fromElement .setAllPropertyFetch ( propertyFetch != null );
420
+
421
+ if ( with != null ) {
422
+ if ( fetch ) {
423
+ throw new SemanticException ( "with-clause not allowed on fetched associations; use filters" );
424
+ }
425
+ handleWithFragment ( fromElement , with );
426
+ }
427
+ }
428
+
429
+ if ( LOG .isDebugEnabled () ) {
430
+ LOG .debug (
431
+ "createFromJoinElement() : "
432
+ + getASTPrinter ().showAsString ( fromElement , "-- join tree --" )
433
+ );
404
434
}
405
435
}
436
+ }
406
437
407
- if ( LOG .isDebugEnabled () ) {
408
- LOG .debug ( "createFromJoinElement() : " + getASTPrinter ().showAsString ( fromElement , "-- join tree --" ) );
438
+ private EntityPersister resolveEntityJoinReferencedPersister (AST path ) {
439
+ if ( path .getType () == IDENT ) {
440
+ final IdentNode pathIdentNode = (IdentNode ) path ;
441
+ String name = path .getText ();
442
+ if ( name == null ) {
443
+ name = pathIdentNode .getOriginalText ();
444
+ }
445
+ return sessionFactoryHelper .findEntityPersisterByName ( name );
446
+ }
447
+ else if ( path .getType () == DOT ) {
448
+ final String pathText = ASTUtil .getPathText ( path );
449
+ return sessionFactoryHelper .findEntityPersisterByName ( pathText );
409
450
}
451
+ return null ;
452
+ }
453
+
454
+ @ Override
455
+ protected void finishFromClause (AST fromClause ) throws SemanticException {
456
+ ( (FromClause ) fromClause ).finishInit ();
457
+ }
458
+
459
+ private EntityJoinFromElement createEntityJoin (
460
+ EntityPersister entityPersister ,
461
+ AST aliasNode ,
462
+ int joinType ,
463
+ AST propertyFetch ,
464
+ AST with ) throws SemanticException {
465
+ final String alias = aliasNode == null ? null : aliasNode .getText ();
466
+ LOG .debugf ( "Creating entity-join FromElement [%s -> %s]" , alias , entityPersister .getEntityName () );
467
+ EntityJoinFromElement join = new EntityJoinFromElement (
468
+ this ,
469
+ getCurrentFromClause (),
470
+ entityPersister ,
471
+ JoinProcessor .toHibernateJoinType ( joinType ),
472
+ propertyFetch != null ,
473
+ alias
474
+ );
475
+
476
+ if ( with != null ) {
477
+ handleWithFragment ( join , with );
478
+ }
479
+
480
+ return join ;
410
481
}
411
482
412
483
private void handleWithFragment (FromElement fromElement , AST hqlWithNode ) throws SemanticException {
@@ -429,16 +500,16 @@ private void handleWithFragment(FromElement fromElement, AST hqlWithNode) throws
429
500
if ( withClauseJoinAlias == null ) {
430
501
withClauseJoinAlias = fromElement .getCollectionTableAlias ();
431
502
}
432
- else {
433
- FromElement referencedFromElement = visitor .getReferencedFromElement ();
434
- if ( referencedFromElement != fromElement ) {
435
- LOG .warnf (
436
- "with-clause expressions do not reference the from-clause element to which the " +
437
- "with-clause was associated. The query may not work as expected [%s]" ,
438
- queryTranslatorImpl .getQueryString ()
439
- );
440
- }
441
- }
503
+ // else {
504
+ // FromElement referencedFromElement = visitor.getReferencedFromElement();
505
+ // if ( referencedFromElement != fromElement ) {
506
+ // LOG.warnf(
507
+ // "with-clause expressions do not reference the from-clause element to which the " +
508
+ // "with-clause was associated. The query may not work as expected [%s]",
509
+ // queryTranslatorImpl.getQueryString()
510
+ // );
511
+ // }
512
+ // }
442
513
443
514
SqlGenerator sql = new SqlGenerator ( getSessionFactoryHelper ().getFactory () );
444
515
sql .whereExpr ( hqlSqlWithNode .getFirstChild () );
@@ -483,9 +554,9 @@ public void visit(AST node) {
483
554
DotNode dotNode = (DotNode ) node ;
484
555
FromElement fromElement = dotNode .getFromElement ();
485
556
if ( referencedFromElement != null ) {
486
- if ( fromElement != referencedFromElement ) {
487
- throw new HibernateException ( "with-clause referenced two different from-clause elements" );
488
- }
557
+ // if ( fromElement != referencedFromElement ) {
558
+ // throw new HibernateException( "with-clause referenced two different from-clause elements" );
559
+ // }
489
560
}
490
561
else {
491
562
referencedFromElement = fromElement ;
0 commit comments