[hibernate-issues] [Hibernate-JIRA] Created: (HHH-5860) Sql Join clauses generated in incorrect order when implied joins are created from the select clause

Mike Q (JIRA) noreply at atlassian.com
Fri Jan 21 07:06:05 EST 2011


Sql Join clauses generated in incorrect order when implied joins are created from the select clause
---------------------------------------------------------------------------------------------------

                 Key: HHH-5860
                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-5860
             Project: Hibernate Core
          Issue Type: Bug
          Components: core
    Affects Versions: 3.6.0
            Reporter: Mike Q
            Priority: Critical


I have the following object model

object TimeSeriesPeriod
  has many-to-one to TimeSeriesQuality
  has many-to-one to MeterPointTimeSeries

object TimeSeriesQuality

object MeterPointTimeSeries
  has many-to-one to MeterPoint

object MeterPoint


Writing the following HQL generates incorrect SQL.

has many-to-one to TimeSeriesQuality

{noformat} 
select
t.meterPointTimeSeries.meterPoint,
t.timeSeriesQuality
from TimeSeriesPeriod t
{noformat} 

The SQL AST generated is as follows.

{noformat} 
 \-[SELECT] QueryNode: 'SELECT'  querySpaces (MeterPoint,TimeSeriesQuality,MeterPointTimeSeries,TimeSeriesPeriod)
    +-[SELECT_CLAUSE] SelectClause: '{select clause}'
    |  +-[DOT] DotNode: 'meterpoint2_.id as id222_0_' {propertyName=meterPoint,dereferenceType=EOF,propertyPath=meterPoint,path=t.meterPointTimeSeries.meterPoint,tableAlias=meterpoint2_,className=com.junifer.thor.database.hibernate.objects.MeterPoint,classAlias=null}
    |  |  +-[DOT] DotNode: 'timeseries0_.meterPointTimeSeriesFk' {propertyName=meterPointTimeSeries,dereferenceType=EOF,propertyPath=meterPointTimeSeries,path=t.meterPointTimeSeries,tableAlias=meterpoint1_,className=com.junifer.thor.database.hibernate.objects.MeterPointTimeSeries,classAlias=null}
    |  |  |  +-[ALIAS_REF] IdentNode: 'timeseries0_.id' {alias=t, className=com.junifer.thor.database.hibernate.objects.TimeSeriesPeriod, tableAlias=timeseries0_}
    |  |  |  \-[IDENT] IdentNode: 'meterPointTimeSeries' {originalText=meterPointTimeSeries}
    |  |  \-[IDENT] IdentNode: 'meterPoint' {originalText=meterPoint}
    |  +-[DOT] DotNode: 'timeseries3_.id as id438_1_' {propertyName=timeSeriesQuality,dereferenceType=EOF,propertyPath=timeSeriesQuality,path=t.timeSeriesQuality,tableAlias=timeseries3_,className=com.junifer.thor.database.hibernate.objects.TimeSeriesQuality,classAlias=null}
    |  |  +-[ALIAS_REF] IdentNode: 'timeseries0_.id' {alias=t, className=com.junifer.thor.database.hibernate.objects.TimeSeriesPeriod, tableAlias=timeseries0_}
    |  |  \-[IDENT] IdentNode: 'timeSeriesQuality' {originalText=timeSeriesQuality}
    |  +-[SQL_TOKEN] SqlFragment: 'meterpoint2_.assetFk as assetFk222_0_, meterpoint2_.deleteFl as deleteFl222_0_, meterpoint2_.measurand as measurand222_0_, meterpoint2_.meterTypeFk as meterTyp7_222_0_, meterpoint2_.partitionId as partitio4_222_0_, meterpoint2_.versionNo as versionNo222_0_'
    |  \-[SQL_TOKEN] SqlFragment: 'timeseries3_.code as code438_1_, timeseries3_.deleteFl as deleteFl438_1_, timeseries3_.iconTblFk as iconTblFk438_1_, timeseries3_.internalKey as internal4_438_1_, timeseries3_.languageKey as language5_438_1_, timeseries3_.orderNo as orderNo438_1_, timeseries3_.partitionId as partitio7_438_1_, timeseries3_.versionNo as versionNo438_1_'
    +-[FROM] FromClause: 'from' FromClause{level=1, fromElementCounter=4, fromElements=4, fromElementByClassAlias=[t], fromElementByTableAlias=[meterpoint1_, meterpoint2_, timeseries3_, timeseries0_], fromElementsByPath=[t.timeSeriesQuality, t.meterPointTimeSeries.meterPoint, t.meterPointTimeSeries], collectionJoinFromElementsByPath=[], impliedElements=[]}
    |  \-[FROM_FRAGMENT] FromElement: 'TimeSeriesPeriod timeseries0_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=t,role=null,tableName=TimeSeriesPeriod,tableAlias=timeseries0_,origin=null,columns={,className=com.junifer.thor.database.hibernate.objects.TimeSeriesPeriod}}
    |     +-[FROM_FRAGMENT] ImpliedFromElement: 'MeterPointTimeSeries meterpoint1_' ImpliedFromElement{implied,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=MeterPointTimeSeries,tableAlias=meterpoint1_,origin=TimeSeriesPeriod timeseries0_,columns={timeseries0_.meterPointTimeSeriesFk ,className=com.junifer.thor.database.hibernate.objects.MeterPointTimeSeries}}
    |     |  \-[JOIN_FRAGMENT] FromElement: 'inner join MeterPoint meterpoint2_ on meterpoint1_.meterPointFk=meterpoint2_.id' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=MeterPoint,tableAlias=meterpoint2_,origin=MeterPointTimeSeries meterpoint1_,columns={meterpoint1_.meterPointFk ,className=com.junifer.thor.database.hibernate.objects.MeterPoint}}
    |     \-[JOIN_FRAGMENT] FromElement: 'inner join TimeSeriesQuality timeseries3_ on timeseries0_.timeSeriesQualityFk=timeseries3_.id' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=TimeSeriesQuality,tableAlias=timeseries3_,origin=TimeSeriesPeriod timeseries0_,columns={timeseries0_.timeSeriesQualityFk ,className=com.junifer.thor.database.hibernate.objects.TimeSeriesQuality}}
    \-[WHERE] SqlNode: 'WHERE'
       \-[THETA_JOINS] SqlNode: '{theta joins}'
          \-[SQL_TOKEN] SqlFragment: 'timeseries0_.meterPointTimeSeriesFk=meterpoint1_.id'
{noformat}

The SQL generated is as follows

{noformat}
select 
 meterpoint2_.id as id222_0_,
 timeseries3_.id as id438_1_,
 meterpoint2_.assetFk as assetFk222_0_,
 meterpoint2_.deleteFl as deleteFl222_0_,
 meterpoint2_.measurand as measurand222_0_,
 meterpoint2_.meterTypeFk as meterTyp7_222_0_,
 meterpoint2_.partitionId as partitio4_222_0_,
 meterpoint2_.versionNo as versionNo222_0_,
 timeseries3_.code as code438_1_,
 timeseries3_.deleteFl as deleteFl438_1_,
 timeseries3_.iconTblFk as iconTblFk438_1_,
 timeseries3_.internalKey as internal4_438_1_,
 timeseries3_.languageKey as language5_438_1_,
 timeseries3_.orderNo as orderNo438_1_,
 timeseries3_.partitionId as partitio7_438_1_,
 timeseries3_.versionNo as versionNo438_1_
from 
 TimeSeriesPeriod timeseries0_,
 MeterPointTimeSeries meterpoint1_ 
   inner join MeterPoint meterpoint2_ on meterpoint1_.meterPointFk=meterpoint2_.id
   inner join TimeSeriesQuality timeseries3_ on timeseries0_.timeSeriesQualityFk=timeseries3_.id
where timeseries0_.meterPointTimeSeriesFk=meterpoint1_.id
{noformat}

And the error produced is

{noformat}
The multi-part identifier "timeseries0_.timeSeriesQualityFk" could not be bound.
{noformat}

The SQL above is wrong because the second inner join should be appearing after the first from statement rather than the second one.

Looking at the AST fragment around the joins (some content removed for clarity

{noformat}
    +-[FROM] FromClause: 'from' FromClause{level=1, fromElementCounter=4, fromElements=4, fromElementByClassAlias=[t], fromElementByTableAlias=[meterpoint1_, meterpoint2_, timeseries3_, timeseries0_], fromElementsByPath=[t.timeSeriesQuality, t.meterPointTimeSeries.meterPoint, t.meterPointTimeSeries], collectionJoinFromElementsByPath=[], impliedElements=[]}
    |  \-[FROM_FRAGMENT] FromElement: 'TimeSeriesPeriod timeseries0_'
    |     +-[FROM_FRAGMENT] ImpliedFromElement: 'MeterPointTimeSeries meterpoint1_' 
    |     |  \-[JOIN_FRAGMENT] FromElement: 'inner join MeterPoint meterpoint2_ on meterpoint1_.meterPointFk=meterpoint2_.id'
    |     \-[JOIN_FRAGMENT] FromElement: 'inner join TimeSeriesQuality timeseries3_ on timeseries0_.timeSeriesQualityFk=timeseries3_.id'
{noformat}

Note the second join fragement appears last but is the child of the first from fragment.  This looks to be correct.  However when the SQL is rendered I'm guessing these nodes are rendered in their order as they appear here rather than rendering the second join fragment under the first from.

The tree does look a bit odd as one from fragment is the child of the other but there are unrelated, I would expect both to be children of the main FromClause with one join fragment child each.

Reversing the order of the select clause elements works correctly.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list