You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2019/01/11 14:10:00 UTC

cayenne git commit: Regression in join logic in SelectTranslator

Repository: cayenne
Updated Branches:
  refs/heads/master 835d1d451 -> 6bb83bbee


Regression in join logic in SelectTranslator


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/6bb83bbe
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/6bb83bbe
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/6bb83bbe

Branch: refs/heads/master
Commit: 6bb83bbee58254caaa0749c677a673ed84ef85ab
Parents: 835d1d4
Author: Nikita Timofeev <st...@gmail.com>
Authored: Fri Jan 11 17:09:52 2019 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Fri Jan 11 17:09:52 2019 +0300

----------------------------------------------------------------------
 .../translator/select/DbPathProcessor.java      | 28 +++++++++++++-------
 .../select/DescriptorColumnExtractor.java       |  3 ++-
 .../translator/select/ObjPathProcessor.java     | 19 +++++++------
 .../access/translator/select/PathProcessor.java |  6 ++++-
 .../translator/select/PathTranslator.java       |  8 ++++--
 .../cayenne/exp/property/PathAliasesIT.java     |  4 +--
 .../apache/cayenne/query/ColumnSelectIT.java    | 12 ++++-----
 7 files changed, 51 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/6bb83bbe/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
index cccea12..383e1f9 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
@@ -30,14 +30,22 @@ import org.apache.cayenne.map.JoinType;
  */
 class DbPathProcessor extends PathProcessor<DbEntity> {
 
-    DbPathProcessor(TranslatorContext context, DbEntity entity, String parentPath) {
+    private boolean flattenedPath;
+
+    DbPathProcessor(TranslatorContext context, DbEntity entity, String parentPath, boolean flattenedPath) {
         super(context, entity);
+        this.flattenedPath = flattenedPath;
         if(parentPath != null) {
             currentDbPath.append(parentPath);
         }
     }
 
     @Override
+    public boolean isOuterJoin() {
+        return super.isOuterJoin() || flattenedPath;
+    }
+
+    @Override
     protected void processNormalAttribute(String next) {
         DbAttribute dbAttribute = entity.getAttribute(next);
         if(dbAttribute != null) {
@@ -76,7 +84,8 @@ class DbPathProcessor extends PathProcessor<DbEntity> {
             processRelTermination(relationship);
         } else {
             appendCurrentPath(relationship.getName());
-            context.getTableTree().addJoinTable(currentDbPath.toString(), relationship, JoinType.LEFT_OUTER);
+            context.getTableTree().addJoinTable(currentDbPath.toString(), relationship, isOuterJoin()
+                    ? JoinType.LEFT_OUTER : JoinType.INNER);
             if(!relationship.isToMany()) {
                 String path = currentDbPath.toString();
                 for (DbAttribute attribute : relationship.getTargetEntity().getPrimaryKeys()) {
@@ -86,20 +95,21 @@ class DbPathProcessor extends PathProcessor<DbEntity> {
         }
     }
 
-    protected void processRelTermination(DbRelationship rel) {
-        this.relationship = rel;
+    protected void processRelTermination(DbRelationship relationship) {
+        this.relationship = relationship;
         String path = currentDbPath.toString();
-        appendCurrentPath(rel.getName());
+        appendCurrentPath(relationship.getName());
 
-        if (rel.isToMany() || !rel.isToPK()) {
+        if (relationship.isToMany() || !relationship.isToPK()) {
             // match on target PK
-            context.getTableTree().addJoinTable(currentDbPath.toString(), rel, JoinType.LEFT_OUTER);
+            context.getTableTree().addJoinTable(currentDbPath.toString(), relationship, isOuterJoin()
+                    ? JoinType.LEFT_OUTER : JoinType.INNER);
             path = currentDbPath.toString();
-            for(DbAttribute attribute : rel.getTargetEntity().getPrimaryKeys()) {
+            for(DbAttribute attribute : relationship.getTargetEntity().getPrimaryKeys()) {
                 addAttribute(path, attribute);
             }
         } else {
-            for(DbJoin join : rel.getJoins()) {
+            for(DbJoin join : relationship.getJoins()) {
                 addAttribute(path, join.getSource());
             }
         }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/6bb83bbe/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
index 5bcff0f..43f521e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
@@ -99,7 +99,8 @@ class DescriptorColumnExtractor extends BaseColumnExtractor implements PropertyV
     @Override
     public boolean visitToOne(ToOneProperty property) {
         ObjRelationship rel = property.getRelationship();
-        PathTranslationResult result = pathTranslator.translatePath(rel.getSourceEntity(), property.getName(), prefix);
+        // outer join should be used for to-one relationships
+        PathTranslationResult result = pathTranslator.translatePath(rel.getSourceEntity(), property.getName() + '+', prefix);
 
         int count = result.getDbAttributes().size();
         for(int i=0; i<count; i++) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/6bb83bbe/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/ObjPathProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/ObjPathProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/ObjPathProcessor.java
index 111bfc4..9bf98db 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/ObjPathProcessor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/ObjPathProcessor.java
@@ -89,8 +89,10 @@ class ObjPathProcessor extends PathProcessor<ObjEntity> {
             return;
         }
 
-        PathTranslationResult result = context.getPathTranslator()
-                .translatePath(entity.getDbEntity(), attribute.getDbAttributePath(), currentDbPath.toString());
+        PathTranslationResult result = context.getPathTranslator().translatePath(entity.getDbEntity()
+                , attribute.getDbAttributePath()
+                , currentDbPath.toString()
+                , attribute.isFlattened());
         attributes.addAll(result.getDbAttributes());
         attributePaths.addAll(result.getAttributePaths());
         relationship = result.getDbRelationship().orElse(relationship);
@@ -109,22 +111,23 @@ class ObjPathProcessor extends PathProcessor<ObjEntity> {
             for (int i=0; i<count; i++) {
                 DbRelationship dbRel = relationship.getDbRelationships().get(i);
                 appendCurrentPath(dbRel.getName());
+                boolean leftJoin = isOuterJoin() || count > 1;
                 context.getTableTree().addJoinTable(currentDbPath.toString(), dbRel,
-                        isOuterJoin ? JoinType.LEFT_OUTER : JoinType.INNER);
+                        leftJoin ? JoinType.LEFT_OUTER : JoinType.INNER);
             }
         }
     }
 
-    protected void processRelTermination(ObjRelationship rel) {
-        String path = currentAlias != null ? currentAlias : rel.getDbRelationshipPath();
-        if(isOuterJoin) {
+    protected void processRelTermination(ObjRelationship relationship) {
+        String path = currentAlias != null ? currentAlias : relationship.getDbRelationshipPath();
+        if(isOuterJoin()) {
             path += OUTER_JOIN_INDICATOR;
         }
         PathTranslationResult result = context.getPathTranslator()
-                .translatePath(entity.getDbEntity(), path, currentDbPath.toString());
+                .translatePath(entity.getDbEntity(), path, currentDbPath.toString(), relationship.isFlattened());
         attributes.addAll(result.getDbAttributes());
         attributePaths.addAll(result.getAttributePaths());
-        relationship = result.getDbRelationship().orElse(relationship);
+        this.relationship = result.getDbRelationship().orElse(this.relationship);
         currentDbPath.delete(0, currentDbPath.length());
         currentDbPath.append(result.getFinalPath());
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/6bb83bbe/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathProcessor.java
index b330608..bb9f1d2 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathProcessor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathProcessor.java
@@ -44,7 +44,7 @@ abstract class PathProcessor<T extends Entity> implements PathTranslationResult
     protected final StringBuilder currentDbPath;
 
     protected boolean lastComponent;
-    protected boolean isOuterJoin;
+    private boolean isOuterJoin;
     protected T entity;
     protected DbRelationship relationship;
     protected String currentAlias;
@@ -126,4 +126,8 @@ abstract class PathProcessor<T extends Entity> implements PathTranslationResult
             currentDbPath.append(OUTER_JOIN_INDICATOR);
         }
     }
+
+    public boolean isOuterJoin() {
+        return isOuterJoin;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/6bb83bbe/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathTranslator.java
index c3dd57f..dfaf8ce 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/PathTranslator.java
@@ -48,9 +48,13 @@ class PathTranslator {
         return translatePath(entity, path, null);
     }
 
-    PathTranslationResult translatePath(DbEntity entity, String path, String parentPath) {
+    PathTranslationResult translatePath(DbEntity entity, String path, String parentPath, boolean flattenedPath) {
         return dbResultCache.computeIfAbsent(parentPath + '.' + entity.getName() + '.' + path,
-                (k) -> new DbPathProcessor(context, entity, parentPath).process(path));
+                (k) -> new DbPathProcessor(context, entity, parentPath, flattenedPath).process(path));
+    }
+
+    PathTranslationResult translatePath(DbEntity entity, String path, String parentPath) {
+        return translatePath(entity, path, parentPath, false);
     }
 
     PathTranslationResult translatePath(DbEntity entity, String path) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/6bb83bbe/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
index 93a68f2..b182dc5 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
@@ -167,7 +167,7 @@ public class PathAliasesIT extends ServerCase {
         List<Object[]> artistAndPaintingCount = ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.PAINTING_ARRAY.count())
                 .having(Artist.PAINTING_ARRAY.alias("p1").count().lt(5L))
                 .select(context);
-        assertEquals(19, artistAndPaintingCount.size());
+        assertEquals(4, artistAndPaintingCount.size());
         assertTrue((Long)artistAndPaintingCount.get(0)[1] < 5);
     }
 
@@ -298,7 +298,7 @@ public class PathAliasesIT extends ServerCase {
         List<Object[]> artistAndPaintingCount = ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.PAINTING_ARRAY.count())
                 .having(PropertyFactory.createBase(e1, Number.class).count().lt(5L))
                 .select(context);
-        assertEquals(19, artistAndPaintingCount.size());
+        assertEquals(4, artistAndPaintingCount.size());
         assertTrue((Long)artistAndPaintingCount.get(0)[1] < 5);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/6bb83bbe/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
index cbd2e03..a7086ec 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ColumnSelectIT.java
@@ -609,7 +609,7 @@ public class ColumnSelectIT extends ServerCase {
                 .pageSize(10)
                 .select(context);
         assertNotNull(a);
-        assertEquals(20, a.size());
+        assertEquals(5, a.size());
         int idx = 0;
         for(Object[] next : a) {
             assertNotNull(next);
@@ -657,7 +657,7 @@ public class ColumnSelectIT extends ServerCase {
                 .pageSize(10)
                 .select(context);
         assertNotNull(a);
-        assertEquals(20, a.size());
+        assertEquals(5, a.size());
         int idx = 0;
         for(Object[] next : a) {
             assertNotNull(next);
@@ -677,7 +677,7 @@ public class ColumnSelectIT extends ServerCase {
                 .select(context);
 
         assertNotNull(a);
-        assertEquals(36, a.size());
+        assertEquals(21, a.size());
         int idx = 0;
         for(Object[] next : a) {
             assertNotNull(next);
@@ -782,7 +782,7 @@ public class ColumnSelectIT extends ServerCase {
     }
 
     private void checkAggregatePrefetchResults(List<Object[]> result) {
-        assertEquals(20, result.size());
+        assertEquals(5, result.size());
         for(Object[] next : result) {
             assertTrue(next[0] instanceof Artist);
             assertTrue(next[1] instanceof Long);
@@ -852,7 +852,7 @@ public class ColumnSelectIT extends ServerCase {
         List<Object[]> result = ObjectSelect.query(Artist.class)
                 .columns(artistProperty, Artist.ARTIST_NAME, Artist.PAINTING_ARRAY.count())
                 .select(context);
-        assertEquals(20, result.size());
+        assertEquals(5, result.size());
 
         for(Object[] next : result) {
             assertTrue(next[0] instanceof Artist);
@@ -903,7 +903,7 @@ public class ColumnSelectIT extends ServerCase {
         List<Object[]> result = ObjectSelect.query(Artist.class)
                 .columns(artistProperty, Artist.PAINTING_ARRAY.flat(), Artist.PAINTING_ARRAY.dot(Painting.TO_GALLERY))
                 .select(context);
-        assertEquals(36, result.size());
+        assertEquals(21, result.size());
 
         for(Object[] next : result) {
             assertTrue(next[0] instanceof Artist);