I filed: http://issues.apache.org/jira/browse/OPENJPA-1227

In investigating further I also found that a field from the subclass must
also be selected to trigger the error (such that the variable seld in
JDBCStoreManager.selectBaseMappings() is set to 1). In the issue I attached
a patch which forces a join to the superclass table only in the
circumstances in which I am seeing the bug, so hopefully that will help
someone track it down and figure out a better fix.

On Tue, Aug 4, 2009 at 8:59 AM, David Minor <[email protected]> wrote:

> Hi Kevin,
>
> I'm using 1.2.1. If the DataCache is turned on, then the problem surfaces,
> otherwise it does not. Both the QueryCache and QuerySQLCache are turned off.
> The problem is exhibited every time the DataCacheStoreManager's load method
> is called with a set of fields that includes the to-many field in the
> superclass (but no other fields in the superclass).
>
> The code in selectBaseMapping() doesn't add a join to the superclass table
> because there are no other fields requested aside from the to-many field.
> But later in eagerToMany.selectEagerJoin(), there is no superclass join
> created either (only the join from the superclass table to the to-many
> table). From what I can tell from stepping through the code, the Join
> created in eagerToMany.selectEagerJoin() wraps the SelectImpl from
> selectBaseMapping(), and the final sql join is based on that, so the
> superclass join never gets created.
>
> This entity is being fetched with different fetch groups at various points
> in the code, so I am guessing that it is first ending up in the cache
> without the to-many field, and then being requested with the to-many field
> in a fetch group.
>
> In testing the change from my first email it appears that it does get
> applied too broadly.
>
> The gist of the class structure is this:
>
> @Entity
> @Table(name = AbstractCategoryImpl.TABLE_NAME)
> @Inheritance(strategy = InheritanceType.JOINED)
> @DiscriminatorColumn(name = "TYPE", discriminatorType =
> DiscriminatorType.STRING, length = 255 )
> public abstract class AbstractCategoryImpl {
>
>     public static final String TABLE_NAME = "TCATEGORY";
>
>     private Set<Category> children = new TreeSet<Category>();
>     private Category parent;
>     private long uidPk;
>
>     @Id
>     @Column(name = "UIDPK")
>     @GeneratedValue(strategy = GenerationType.TABLE, generator =
> AbstractCategoryImpl.TABLE_NAME)
>     @TableGenerator(name = AbstractCategoryImpl.TABLE_NAME, table =
> "JPA_GENERATED_KEYS",
>             pkColumnName = "ID", valueColumnName = "LAST_VALUE",
> pkColumnValue AbstractCategoryImpl.TABLE_NAME)
>     public long getUidPk() {
>         return this.uidPk;
>     }
>
>     public void setUidPk(final long uidPk) {
>         this.uidPk = uidPk;
>     }
>
>     @OneToMany(targetEntity = AbstractCategoryImpl.class, mappedBy =
> "parentInternal", cascade = { CascadeType.ALL })
>     public Set<Category> getChildren() {
>         return this.children;
>     }
>
>     public void setChildren(final Set<Category> children) {
>         this.children = children;
>     }
>
>
>     @ManyToOne(targetEntity = AbstractCategoryImpl.class, cascade = {
> CascadeType.MERGE, CascadeType.REFRESH })
>     @JoinColumn(name = "PARENT_CATEGORY_UID")
>     @ForeignKey
>     protected Category getParentInternal() {
>         return this.parent;
>     }
>
>     protected void setParentInternal(final Category newParent) {
>         this.parent = newParent;
>     }
> }
>
> @Entity
> @Table(name = CategoryImpl.TABLE_NAME, uniqueConstraints =
> @UniqueConstraint(columnNames = "CODE"))
> @PrimaryKeyJoinColumn(name = "UIDPK", referencedColumnName = "UIDPK")
> @DiscriminatorValue("masterCategory")
> public class CategoryImpl extends AbstractCategoryImpl {
>
>     public static final String TABLE_NAME = "TMASTERCATEGORY";
> }
>
> And the gist of persistence.xml is this:
>
> <property name="openjpa.ConnectionFactoryProperties"
> value="PrettyPrint=true, PrettyPrintLineLength=120"/>
> <property name="openjpa.jdbc.EagerFetchMode" value="parallel"/>
> <property name="openjpa.jdbc.SubclassFetchMode" value="parallel"/>
> <property name="openjpa.QueryCompilationCache" value="false"/>
> <property name="openjpa.DetachState"
> value="loaded(DetachedStateField=true)"/>
> <property name="openjpa.Multithreaded" value="true"/>
>
>
> <property name="openjpa.DataCache" value="true(CacheSize=1000,
> SoftReferenceSize=0)"/>
> <property name="openjpa.RemoteCommitProvider" value="sjvm"/>
>
> <property name="openjpa.QueryCache" value="false"/>
> <property name="openjpa.jdbc.QuerySQLCache" value="false"/>
>
> Hopefully that helps.
>
>
>
>>
>> -----Original Message-----
>> From: Kevin Sutter [mailto:[email protected]]
>> Sent: Tuesday, August 04, 2009 6:26 AM
>> To: [email protected]
>> Subject: Re: SQL generation error
>>
>> Hi David,
>> More questions than answers...  Can you provide a concrete example of
>> this failure?  For example, the Entity and Superclass definitions would
>> be helpful.  The persistence.xml would also be helpful.  So, you are
>> indicating that if turn on the openjpa.DataCache property, then the
>> problem surfaces?
>> But, if you remove this property, then everything works as expected?
>> The DataCache property automatically turns on the QueryCache, have your
>> tried setting the openjpa.QueryCache to "false" while leaving the
>> openjpa.DataCache set to "true"?
>>
>> Is this particular SQL generated incorrectly all the time?  That is, if
>> you have the proper settings to reproduce the problem (DataCache,
>> whatever), does your application always generate the wrong SQL?  Or, is
>> it sometimes correct?  (The reason I am asking this question is whether
>> the QuerySQLCache is affecting this scenario or not.  You could quickly
>> test this out by setting openjpa.jdbc.QuerySQLCache to "false".)
>>
>> Oh yeah, and what version of OpenJPA are you using?
>>
>> The concern with the change you suggested below is that we might be
>> generating or re-generating SQL too often with the proposed change.
>> But, I haven't studied it in great depth due to the questions I had
>> above.  If you have made the change below, how does the rest of the
>> OpenJPA test bucket fare?  Any regressions introduced when you run the
>> whole bucket?
>>
>> Thanks,
>> Kevin
>>
>> On Mon, Aug 3, 2009 at 2:36 PM, David Minor <[email protected]> wrote:
>>
>> > I've encountered a SQL generation bug where a join to a superclass
>> > seems to be missing. The problem only occurs when the datacache is in
>> > use, and seems to occur when the superclass is loading a single field
>> > which is to-many (I'm using parallel eager select, which may be
>> > affecting this as well). The field is a collection of the same type as
>>
>> > the superclass.
>> >
>> > I believe the problem is in the select generated by the
>> > eagerToMany.selectEagerJoin() call in JDBCStoreManager.select().
>> > However, I've found that in JDBCStoreManager.selectBaseMappings(), if
>> > I change the
>> > line:
>> >
>> >            if (fms[i] == eagerToMany)
>> >                continue;
>> >
>> > to:
>> >
>> >            if (fms[i] == eagerToMany) {
>> >                seld = 0;
>> >                continue;
>> >            }
>> >
>> > to indicate that the select is required, the problem goes away.
>> > However, I don't know the ramifications on other SQL generation.
>> >
>> > If anyone who is more familiar with the SQL generation code could
>> > comment, it would be much appreciated.
>> >
>> > --
>> > _____________
>> > David Minor
>> >
>>
>>
>>
>>
>
>
> --
> _____________
> David Minor
>



-- 
_____________
David Minor

Reply via email to