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

Reply via email to