cayenne-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrus Adamchik <and...@objectstyle.org>
Subject Re: Problem with joint prefetch and flattened attributes
Date Wed, 06 Aug 2014 06:34:19 GMT
> This is clearly a bug. Should I create a JIRA issue?

Hi Erlend,

Yes, please Jira it. Sounds like a bug.

Thanks,
Andrus


On Aug 5, 2014, at 2:07 PM, Erlend Birkenes <eb@dataloy.com> wrote:

> Hi
> 
> I discovered a problem with joint prefetch and flattened attributes. This
> is in 3.1B2 which is the version we use at the moment. Not sure if this is
> the lates or not..
> 
> If I have a entity A with a normal relationship to an entity B, and B has
> flattened attributes from C via toCdbrel.SOME_PROPERTY.
> This works fine normally. But when using joint prefetch the table aliases
> in the query will be wrong. (Querying A and prefetching B).
> If there are multiple flattened attributes, C will also be joined in
> multiple times.
> 
> The problem is in SelectTranslator#appendQueryColumns.
> This section adds columns from the target entity of a joint prefetch,
> including relationships for flattened attributes:
> 
> while (targetObjAttrs.hasNext()) {
>        ObjAttribute oa = targetObjAttrs.next();
>        Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
>        while (dbPathIterator.hasNext()) {
>                Object pathPart = dbPathIterator.next();
> 
>                if (pathPart == null) {
>                        throw new CayenneRuntimeException(
>                                        "ObjAttribute has no component: " +
> oa.getName());
>                }
>                else if (pathPart instanceof DbRelationship) {
>                        DbRelationship rel = (DbRelationship) pathPart;
>                        dbRelationshipAdded(rel, JoinType.INNER, null);
> //PROBLEM
>                }
>                else if (pathPart instanceof DbAttribute) {
>                        DbAttribute attribute = (DbAttribute) pathPart;
> 
>                        appendColumn(columns, oa, attribute, attributes,
> labelPrefix
>                                        + '.'
>                                        + attribute.getName());
>                }
>        }
> }
> 
> The problem is that dbRelationshipAdded sets the topNode of the JoinStack
> to the new node when a relationship is added and this is never reset in
> this case. So every time a relationship is added in this loop it will add a
> node to the previously added node. This will increase the tableAlias by 1
> for every relationship, and also cause any attributes directly on B to
> belong to the wrong node and therefore get the wrong tableAlias. It will
> also cause an additional join, but joined to the wrong table.
> 
> The topNode of the JoinStack needs to be reset to the correct value after
> handing each attribute, or more presisely: after the "while
> (dbPathIterator.hasNext())" loop the topNode needs to be the same as it was
> before the loop, because we are still processing attributes on the same
> entity (B in this case).
> 
> Storing the current topNode, and resetting it after processing each
> attribute fixed the problem for me. Like this:
> 
> while (targetObjAttrs.hasNext()) {
>                    JoinTreeNode topNode = getJoinStack().topNode;  // FIX
>                    ObjAttribute oa = targetObjAttrs.next();
>                    Iterator<CayenneMapEntry> dbPathIterator =
> oa.getDbPathIterator();
>                    while (dbPathIterator.hasNext()) {
>                        Object pathPart = dbPathIterator.next();
> 
>                        if (pathPart == null) {
>                            throw new CayenneRuntimeException(
>                                    "ObjAttribute has no component: " +
> oa.getName());
>                        }
>                        else if (pathPart instanceof DbRelationship) {
>                            DbRelationship rel = (DbRelationship) pathPart;
>                            dbRelationshipAdded(rel, JoinType.INNER, null);
>                        }
>                        else if (pathPart instanceof DbAttribute) {
>                            DbAttribute attribute = (DbAttribute) pathPart;
> 
>                            appendColumn(columns, oa, attribute,
> attributes, labelPrefix
>                                    + '.'
>                                    + attribute.getName());
>                        }
>                    }
>                    getJoinStack().topNode = topNode; // FIX
>                }
> 
> resetJoinStack() can't be used in this case, since we don't want the
> rootNode.
> 
> I've run the Cayenne tests after this change with no errors, but I've only
> done limited testing in our own app so far.
> 
> This is clearly a bug. Should I create a JIRA issue?
> 
> 
> –
> Erlend <http://www.dataloy-systems.com>


Mime
View raw message