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 2018/03/21 13:28:36 UTC
[2/4] cayenne git commit: CAY-2412 test case + warning about limit
with joint prefetch
CAY-2412 test case + warning about limit with joint prefetch
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/26330d4c
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/26330d4c
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/26330d4c
Branch: refs/heads/STABLE-4.0
Commit: 26330d4cb1edfa66f2c02e32462c85b5101edd6b
Parents: a16d7c4
Author: Nikita Timofeev <st...@gmail.com>
Authored: Tue Mar 6 17:38:54 2018 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Tue Mar 6 17:38:54 2018 +0300
----------------------------------------------------------------------
.../select/DefaultSelectTranslator.java | 68 ++++++++++++
.../test/java/org/apache/cayenne/Cay2412IT.java | 110 +++++++++++++++++++
2 files changed, 178 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/26330d4c/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
index e455901..d933a39 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
@@ -42,6 +42,7 @@ import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.map.PathComponent;
+import org.apache.cayenne.query.PrefetchProcessor;
import org.apache.cayenne.query.PrefetchSelectQuery;
import org.apache.cayenne.query.PrefetchTreeNode;
import org.apache.cayenne.query.Query;
@@ -55,6 +56,8 @@ import org.apache.cayenne.reflect.ToOneProperty;
import org.apache.cayenne.util.CayenneMapEntry;
import org.apache.cayenne.util.EqualsBuilder;
import org.apache.cayenne.util.HashCodeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.sql.Types;
import java.util.ArrayList;
@@ -72,6 +75,8 @@ import java.util.Set;
*/
public class DefaultSelectTranslator extends QueryAssembler implements SelectTranslator {
+ private static final Logger logger = LoggerFactory.getLogger(SelectTranslator.class);
+
protected static final int[] UNSUPPORTED_DISTINCT_TYPES = { Types.BLOB, Types.CLOB, Types.NCLOB,
Types.LONGVARBINARY, Types.LONGVARCHAR, Types.LONGNVARCHAR };
@@ -110,6 +115,8 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
*/
AddJoinListener joinListener;
+ JointPrefetchChecker jointPrefetchChecker = new JointPrefetchChecker();
+
public DefaultSelectTranslator(Query query, DbAdapter adapter, EntityResolver entityResolver) {
super(query, adapter, entityResolver);
@@ -129,6 +136,8 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
@Override
protected void doTranslate() {
+ checkLimitAndJointPrefetch();
+
DataMap dataMap = queryMetadata.getDataMap();
JoinStack joins = getJoinStack();
@@ -249,6 +258,22 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
}
/**
+ * Warn user in case query uses both limit and joint prefetch, as we don't support this combination.
+ */
+ private void checkLimitAndJointPrefetch() {
+ if(queryMetadata.getFetchLimit() == 0 && queryMetadata.getFetchOffset() == 0) {
+ return;
+ }
+
+ if(!jointPrefetchChecker.haveJointNode(queryMetadata.getPrefetchTree())) {
+ return;
+ }
+
+ logger.warn("Query uses both limit and joint prefetch, this most probably will lead to incorrect result. " +
+ "Either use disjointById prefetch or get full result set.");
+ }
+
+ /**
* Allows subclasses to insert their own dialect of DISTINCT statement to
* improve performance.
*
@@ -925,4 +950,47 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
interface AddJoinListener {
void joinAdded();
}
+
+ private static class JointPrefetchChecker implements PrefetchProcessor {
+ private boolean haveJointNode;
+
+ public JointPrefetchChecker() {
+ }
+
+ public boolean haveJointNode(PrefetchTreeNode prefetchTree) {
+ haveJointNode = false;
+ prefetchTree.traverse(this);
+ return haveJointNode;
+ }
+
+ @Override
+ public boolean startPhantomPrefetch(PrefetchTreeNode node) {
+ return true;
+ }
+
+ @Override
+ public boolean startDisjointPrefetch(PrefetchTreeNode node) {
+ return true;
+ }
+
+ @Override
+ public boolean startDisjointByIdPrefetch(PrefetchTreeNode prefetchTreeNode) {
+ return true;
+ }
+
+ @Override
+ public boolean startJointPrefetch(PrefetchTreeNode node) {
+ haveJointNode = true;
+ return false;
+ }
+
+ @Override
+ public boolean startUnknownPrefetch(PrefetchTreeNode node) {
+ return true;
+ }
+
+ @Override
+ public void finishPrefetch(PrefetchTreeNode node) {
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/26330d4c/cayenne-server/src/test/java/org/apache/cayenne/Cay2412IT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/Cay2412IT.java b/cayenne-server/src/test/java/org/apache/cayenne/Cay2412IT.java
new file mode 100644
index 0000000..26b6049
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/Cay2412IT.java
@@ -0,0 +1,110 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne;
+
+import java.sql.Types;
+
+import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.1
+ */
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class Cay2412IT extends ServerCase {
+
+ @Inject
+ DataContext context;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Before
+ public void prepareData() throws Exception {
+ TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
+ tArtist.setColumnTypes(Types.INTEGER, Types.VARCHAR, Types.DATE);
+ tArtist.insert(1, "artist1", new java.sql.Date(System.currentTimeMillis()));
+
+ TableHelper tGallery = new TableHelper(dbHelper, "GALLERY");
+ tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+ tGallery.insert(1, "tate modern");
+
+ TableHelper tPaintings = new TableHelper(dbHelper, "PAINTING");
+ tPaintings.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "GALLERY_ID", "ESTIMATED_PRICE");
+ for (int i = 1; i <= 3; i++) {
+ tPaintings.insert(i, "painting" + i, 1, 1, 22 - i);
+ }
+ }
+
+ @Ignore("selectFirst() call corrupts object state in context, and because of cache it's also returned for unrelated query")
+ @Test
+ public void testJoinPrefetchWithLimitBeforeFullSelect() {
+ Artist artist0 = ObjectSelect.query(Artist.class)
+ .prefetch(Artist.PAINTING_ARRAY.joint())
+ .localCache("test")
+ .selectOne(context);
+ assertEquals(3, artist0.getPaintingArray().size());
+
+ Artist artist1 = ObjectSelect.query(Artist.class)
+ .prefetch(Artist.PAINTING_ARRAY.joint())
+ .selectFirst(context);
+ assertEquals(1, artist1.getPaintingArray().size()); // <-- wrong assertion, but expected
+
+ Artist artist2 = ObjectSelect.query(Artist.class)
+ .prefetch(Artist.PAINTING_ARRAY.joint())
+ .localCache("test")
+ .selectOne(context);
+ assertEquals(3, artist2.getPaintingArray().size()); // <-- assertion failure here, got 1 instead of 3
+ }
+
+ @Test
+ public void testDisjointByIdPrefetchWithLimitBeforeFullSelect() {
+ Artist artist0 = ObjectSelect.query(Artist.class)
+ .prefetch(Artist.PAINTING_ARRAY.disjointById())
+ .localCache("test")
+ .selectOne(context);
+ assertEquals(3, artist0.getPaintingArray().size());
+
+ Artist artist1 = ObjectSelect.query(Artist.class)
+ .prefetch(Artist.PAINTING_ARRAY.disjointById())
+ .selectFirst(context);
+ assertEquals(3, artist1.getPaintingArray().size());
+
+ Artist artist2 = ObjectSelect.query(Artist.class)
+ .prefetch(Artist.PAINTING_ARRAY.disjointById())
+ .localCache("test")
+ .selectOne(context);
+ assertEquals(3, artist2.getPaintingArray().size());
+ }
+
+}