In our Hibernate application, we're making use of the 3.0-style discriminator-subclass mapping with <joined-subclass> mappings. In a new query that we've written, we're getting a problem with the mapping of the .class property: it appears that what's happening is that in the LiteralProcessor it's adding single-quotation characters, and then adding additional ones in the FromReferenceNode it's adding additional single-quotation characters. This means that MySQL gets "exchangeTrades BondTradeBean" in two single-quotation characters in the WHERE clause, which causes a parse exception because it's not valid.
In our case we can easily rewrite the query to do an explicit join between TradeAssignmentBean and BondTradeBean, but I expected that doing an inner join would be more efficient.
In addition, I find it interesting that in our case, although we've explictly specified the subclass of TradeBean (the reference in TradeAssignmentBean is to TradeBean, which is a superclass of BondTradeBean), the generated SQL isn't being smart enough to prune out the unnecessary tables from the join: although assignment.trade could be an instance of any other subclass of TradeBean, the restriction on assignment.trade.class means that it only actually has to join against exchange_trades (the <subclass><join table> for BondTradeBean).
That might be an enhancement that could be done in a future release I suppose, for us it's inefficient enough that I'm going to rewrite the query to resolve both issues at once.
Hibernate version: 3.0RC1
HQL Statement:
select distinct assignment.trade
from com.lmsystems.trade.model.TradeAssignmentBean as assignment
inner join assignment.trade
where assignment.assignmentDate = :date
and assignment.trade.class = com.lmsystems.trade.model.BondTradeBean
Name and version of the database you are using: MySQL 4.1.10
The generated SQL (show_sql=true):
select distinct tradebean1_.id as id, tradebean1_.source_trade_id as source3_18_, tradebean1_.counterparty_id as counterp4_18_, tradebean1_.first_appearance as first5_18_, tradebean1_.user_description as user6_18_, tradebean1_.is_aggregate as is7_18_, tradebean1_1_.trade_type as trade2_19_, tradebean1_1_.code as code19_, tradebean1_1_.position as position19_, tradebean1_2_.unique_id_name as unique5_19_, tradebean1_3_.currency as currency20_, tradebean1_3_.start_date as start3_20_, tradebean1_3_.end_date as end4_20_, tradebean1_3_.fixing_date as fixing5_20_, tradebean1_3_.position as position20_, tradebean1_3_.fixed_rate as fixed7_20_, tradebean1_3_.ref_rate as ref8_20_, tradebean1_3_.yield_basis as yield9_20_, tradebean1_3_.is_pay_fixed as is10_20_, tradebean1_4_.exchange_date as exchange2_21_, tradebean1_4_.pay_amount as pay3_21_, tradebean1_4_.pay_currency as pay4_21_, tradebean1_4_.rcv_amount as rcv5_21_, tradebean1_4_.rcv_currency as rcv6_21_, tradebean1_5_.exchange_date as exchange2_22_, tradebean1_5_.pay_amount as pay3_22_, tradebean1_5_.pay_currency as pay4_22_, tradebean1_5_.rcv_amount as rcv5_22_, tradebean1_5_.rcv_currency as rcv6_22_, tradebean1_5_.expiry as expiry22_, tradebean1_5_.is_long as is8_22_, tradebean1_6_.currency as currency23_, tradebean1_6_.start_date as start3_23_, tradebean1_6_.end_date as end4_23_, tradebean1_6_.fixed_rate as fixed5_23_, tradebean1_6_.pay_fixed as pay6_23_, tradebean1_6_.position as position23_, tradebean1_7_.currency as currency24_, tradebean1_7_.start_date as start3_24_, tradebean1_7_.end_date as end4_24_, tradebean1_7_.fixed_rate as fixed5_24_, tradebean1_7_.pay_fixed as pay6_24_, tradebean1_7_.position as position24_, tradebean1_7_.expiry as expiry24_, tradebean1_7_.is_long as is9_24_, tradebean1_.discriminator as discrimi2_ from trade_assignments tradeassig0_, trades tradebean1_ left outer join exchange_trades tradebean1_1_ on tradebean1_.id=tradebean1_1_.trade_id left outer join exchange_trades tradebean1_2_ on tradebean1_.id=tradebean1_2_.trade_id left outer join fra_trades tradebean1_3_ on tradebean1_.id=tradebean1_3_.trade_id left outer join fx_trades tradebean1_4_ on tradebean1_.id=tradebean1_4_.trade_id left outer join fxoption_trades tradebean1_5_ on tradebean1_.id=tradebean1_5_.trade_id left outer join swap_trades tradebean1_6_ on tradebean1_.id=tradebean1_6_.trade_id left outer join swaption_trades tradebean1_7_ on tradebean1_.id=tradebean1_7_.trade_id, trades tradebean3_ where (tradeassig0_.assignment_date=? and tradebean3_.discriminator=''exchange_trades BondTradeBean'' and tradeassig0_.trade_id=tradebean1_.id and tradeassig0_.trade_id=tradebean3_.id)
Debug level Hibernate log excerpt:
[DEBUG] SessionFactoryImpl - -Checking named query: TradeBean.bond.byDate
[DEBUG] QueryTranslatorImpl - -parse() - HQL:
select distinct assignment.trade
from com.lmsystems.trade.model.TradeAssignmentBean as assignment
inner join assignment.trade
where assignment.assignmentDate = :date
and assignment.trade.class = com.lmsystems.trade.model.BondTradeBean
[DEBUG] AST - ---- HQL AST ---
\-[QUERY] CommonAST: 'query'
+-[SELECT_FROM] CommonAST: 'SELECT_FROM'
| +-[FROM] CommonAST: 'from'
| | +-[DOT] CommonAST: '.'
| | | +-[DOT] CommonAST: '.'
| | | | +-[DOT] CommonAST: '.'
| | | | | +-[DOT] CommonAST: '.'
| | | | | | +-[IDENT] CommonAST: 'com'
| | | | | | \-[IDENT] CommonAST: 'lmsystems'
| | | | | \-[IDENT] CommonAST: 'trade'
| | | | \-[IDENT] CommonAST: 'model'
| | | \-[IDENT] CommonAST: 'TradeAssignmentBean'
| | +-[ALIAS] CommonAST: 'assignment'
| | \-[JOIN] CommonAST: 'join'
| | +-[INNER] CommonAST: 'inner'
| | \-[DOT] CommonAST: '.'
| | +-[IDENT] CommonAST: 'assignment'
| | \-[IDENT] CommonAST: 'trade'
| \-[SELECT] CommonAST: 'select'
| +-[DISTINCT] CommonAST: 'distinct'
| \-[DOT] CommonAST: '.'
| +-[IDENT] CommonAST: 'assignment'
| \-[IDENT] CommonAST: 'trade'
\-[WHERE] CommonAST: 'where'
\-[AND] CommonAST: 'and'
+-[EQ] CommonAST: '='
| +-[DOT] CommonAST: '.'
| | +-[IDENT] CommonAST: 'assignment'
| | \-[IDENT] CommonAST: 'assignmentDate'
| \-[COLON] CommonAST: ':'
| \-[IDENT] CommonAST: 'date'
\-[EQ] CommonAST: '='
+-[DOT] CommonAST: '.'
| +-[DOT] CommonAST: '.'
| | +-[IDENT] CommonAST: 'assignment'
| | \-[IDENT] CommonAST: 'trade'
| \-[CLASS] CommonAST: 'class'
\-[DOT] CommonAST: '.'
+-[DOT] CommonAST: '.'
| +-[DOT] CommonAST: '.'
| | +-[DOT] CommonAST: '.'
| | | +-[IDENT] CommonAST: 'com'
| | | \-[IDENT] CommonAST: 'lmsystems'
| | \-[IDENT] CommonAST: 'trade'
| \-[IDENT] CommonAST: 'model'
\-[IDENT] CommonAST: 'BondTradeBean'
[DEBUG] parser - -throwQueryException() : no errors
[DEBUG] HqlSqlBaseWalker - -query() << begin, level = 1
[DEBUG] FromElement - -com.lmsystems.trade.model.TradeAssignmentBean (assignment) -> tradeassig0_
[DEBUG] FromReferenceNode - -Resolved : assignment -> tradeassig0_.id
[DEBUG] DotNode - -getDataType() : trade -> org.hibernate.type.ManyToOneType(com.lmsystems.trade.model.TradeBean)
[DEBUG] DotNode - -dereferenceEntityJoin() : generating join for trade in com.lmsystems.trade.model.TradeAssignmentBean {no alias} parent = [ {null} ]
[DEBUG] FromElement - -com.lmsystems.trade.model.TradeBean (no alias) -> tradebean1_
[DEBUG] FromClause - -addJoinByPathMap() : assignment.trade (explicit) -> trades tradebean1_
[DEBUG] FromReferenceNode - -Resolved : assignment.trade -> tradeassig0_.trade_id
[DEBUG] HqlSqlWalker - -createFromJoinElement() : -- join tree --
\-[JOIN_FRAGMENT] FromElement: 'trades tradebean1_' FromElement{explicit,not a collection join,classAlias=null,role=null,tableName=trades,tableAlias=tradebean1_,colums={tradeassig0_.trade_id ,className=com.lmsystems.trade.model.TradeBean}}
[DEBUG] FromReferenceNode - -Resolved : assignment -> tradeassig0_.id
[DEBUG] DotNode - -getDataType() : trade -> org.hibernate.type.ManyToOneType(com.lmsystems.trade.model.TradeBean)
[DEBUG] DotNode - -dereferenceEntityJoin() : generating join for trade in com.lmsystems.trade.model.TradeAssignmentBean {no alias} parent = [ {null} ]
[DEBUG] FromReferenceNode - -Resolved : assignment.trade -> tradeassig0_.trade_id
[DEBUG] FromReferenceNode - -Resolved : assignment -> tradeassig0_.id
[DEBUG] DotNode - -getDataType() : assignmentDate -> org.hibernate.type.TimestampType@8046f4
[DEBUG] FromReferenceNode - -Resolved : assignment.assignmentDate -> tradeassig0_.assignment_date
[DEBUG] FromReferenceNode - -Resolved : assignment -> tradeassig0_.id
[DEBUG] DotNode - -getDataType() : trade -> org.hibernate.type.ManyToOneType(com.lmsystems.trade.model.TradeBean)
[DEBUG] DotNode - -dereferenceEntityJoin() : generating join for trade in com.lmsystems.trade.model.TradeAssignmentBean {no alias} parent = [ ( . ( . tradeassig0_.id trade ) class ) ]
[DEBUG] FromElement - -com.lmsystems.trade.model.TradeBean (no alias) -> tradebean3_
[DEBUG] FromClause - -addJoinByPathMap() : assignment.trade (implied) -> trades tradebean3_
[DEBUG] FromReferenceNode - -Resolved : assignment.trade -> tradeassig0_.trade_id
[DEBUG] DotNode - -getDataType() : class -> org.hibernate.type.StringType@9505f
[DEBUG] FromReferenceNode - -Resolved : assignment.trade.class -> tradebean3_.discriminator
[DEBUG] FromReferenceNode - -Resolved : com -> com
[DEBUG] LiteralProcessor - -setConstantValue() com.lmsystems.trade.model.BondTradeBean -> 'exchange_trades BondTradeBean' java.lang.String
[DEBUG] FromReferenceNode - -Resolved : com.lmsystems.trade.model.BondTradeBean -> ''exchange_trades BondTradeBean''
[DEBUG] HqlSqlBaseWalker - -query() : finishing up...
[DEBUG] SyntheticAndFactory - -addWhereFragment() : {tradeassig0_.trade_id=tradebean3_.id}
[DEBUG] JoinProcessor - -Using FROM fragment [trades tradebean1_ left outer join exchange_trades tradebean1_1_ on tradebean1_.id=tradebean1_1_.trade_id left outer join exchange_trades tradebean1_2_ on tradebean1_.id=tradebean1_2_.trade_id left outer join fra_trades tradebean1_3_ on tradebean1_.id=tradebean1_3_.trade_id left outer join fx_trades tradebean1_4_ on tradebean1_.id=tradebean1_4_.trade_id left outer join fxoption_trades tradebean1_5_ on tradebean1_.id=tradebean1_5_.trade_id left outer join swap_trades tradebean1_6_ on tradebean1_.id=tradebean1_6_.trade_id left outer join swaption_trades tradebean1_7_ on tradebean1_.id=tradebean1_7_.trade_id]
[DEBUG] SyntheticAndFactory - -addWhereFragment() : {tradeassig0_.trade_id=tradebean1_.id}
[DEBUG] JoinProcessor - -Using FROM fragment [trade_assignments tradeassig0_]
|