Skip to content

Commit 566873d

Browse files
authored
Merge pull request #643 from swarmbox/CAY-2917
CAY-2917 Add Qualifier Joins Before Depenent Table Joins
2 parents 3b7139e + 8df4331 commit 566873d

4 files changed

Lines changed: 107 additions & 29 deletions

File tree

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ CAY-2897 Add no-op default implementations to the GraphChangeHandler interface
2121
CAY-2905 Upgrade Gradle to 8.14
2222
CAY-2908 Review and upgrade dependencies
2323
CAY-2916 SelectById: unify logic for null/empty values
24+
CAY-2917 Add Qualifier Joins Before Depenent Table Joins
2425

2526
Bug Fixes:
2627

cayenne/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@
3838
public class DefaultSelectTranslator implements SelectTranslator {
3939

4040
private static final TranslationStage[] TRANSLATION_STAGES = {
41+
new QualifierTranslationStage(),
4142
new ColumnExtractorStage(),
4243
new PrefetchNodeStage(),
4344
new OrderingStage(),
44-
new QualifierTranslationStage(),
4545
new HavingTranslationStage(),
4646
new OrderingGroupByStage(),
4747
new GroupByStage(),

cayenne/src/test/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorIT.java

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -615,50 +615,50 @@ public void testCreateSqlStringWithQuoteSqlIdentifiers3() throws Exception {
615615
assertTrue(s, artistId > 0 && artistId < iFrom);
616616
int dateOfBirth = s.indexOf(charStart + "t0" + charEnd + "." + charStart + "DATE_OF_BIRTH" + charEnd);
617617
assertTrue(s, dateOfBirth > 0 && dateOfBirth < iFrom);
618-
int estimatedPrice = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "ESTIMATED_PRICE" + charEnd);
618+
int estimatedPrice = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "ESTIMATED_PRICE" + charEnd);
619619
assertTrue(s, estimatedPrice > 0 && estimatedPrice < iFrom);
620-
int paintingDescription = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "PAINTING_DESCRIPTION"
620+
int paintingDescription = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "PAINTING_DESCRIPTION"
621621
+ charEnd);
622622
assertTrue(s, paintingDescription > 0 && paintingDescription < iFrom);
623-
int paintingTitle = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "PAINTING_TITLE" + charEnd);
623+
int paintingTitle = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "PAINTING_TITLE" + charEnd);
624624
assertTrue(s, paintingTitle > 0 && paintingTitle < iFrom);
625-
int artistIdT1 = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "ARTIST_ID" + charEnd);
626-
assertTrue(s, artistIdT1 > 0 && artistIdT1 < iFrom);
627-
int galleryId = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "GALLERY_ID" + charEnd);
625+
int artistIdT2 = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "ARTIST_ID" + charEnd);
626+
assertTrue(s, artistIdT2 > 0 && artistIdT2 < iFrom);
627+
int galleryId = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "GALLERY_ID" + charEnd);
628628
assertTrue(s, galleryId > 0 && galleryId < iFrom);
629-
int paintingId = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "PAINTING_ID" + charEnd);
629+
int paintingId = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "PAINTING_ID" + charEnd);
630630
assertTrue(s, paintingId > 0 && paintingId < iFrom);
631631
int iArtist = s.indexOf(charStart + "ARTIST" + charEnd + " " + charStart + "t0" + charEnd);
632632
assertTrue(s, iArtist > iFrom);
633-
int iLeftJoin = s.indexOf("LEFT JOIN");
634-
assertTrue(s, iLeftJoin > iFrom);
635-
int iPainting = s.indexOf(charStart + "PAINTING" + charEnd + " " + charStart + "t1" + charEnd);
636-
assertTrue(s, iPainting > iLeftJoin);
637-
int iOn = s.indexOf(" ON ");
638-
assertTrue(s, iOn > iLeftJoin);
639-
int iArtistId = s.indexOf(charStart + "t0" + charEnd + "." + charStart + "ARTIST_ID" + charEnd, iLeftJoin);
640-
assertTrue(s, iArtistId > iOn);
641-
int iArtistIdT1 = s
642-
.indexOf(charStart + "t1" + charEnd + "." + charStart + "ARTIST_ID" + charEnd, iLeftJoin);
643-
assertTrue(s, iArtistIdT1 > iOn);
644-
int i = s.indexOf("=", iLeftJoin);
645-
assertTrue(s, iArtistIdT1 > i || iArtistId > i);
646633
int iJoin = s.indexOf("JOIN");
647-
assertTrue(s, iJoin > iLeftJoin);
648-
int iPainting2 = s.indexOf(charStart + "PAINTING" + charEnd + " " + charStart + "t2" + charEnd);
634+
assertTrue(s, iJoin > iFrom);
635+
int iPainting2 = s.indexOf(charStart + "PAINTING" + charEnd + " " + charStart + "t1" + charEnd);
649636
assertTrue(s, iPainting2 > iJoin);
650-
int iOn2 = s.indexOf(" ON ");
637+
int iOn2 = s.indexOf(" ON ", iJoin);
651638
assertTrue(s, iOn2 > iJoin);
652639
int iArtistId2 = s.indexOf(charStart + "t0" + charEnd + "." + charStart + "ARTIST_ID" + charEnd, iJoin);
653640
assertTrue(s, iArtistId2 > iOn2);
654-
int iArtistId2T2 = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "ARTIST_ID" + charEnd, iJoin);
655-
assertTrue(s, iArtistId2T2 > iOn2);
641+
int iArtistId2T1 = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "ARTIST_ID" + charEnd, iJoin);
642+
assertTrue(s, iArtistId2T1 > iOn2);
656643
int i2 = s.indexOf("=", iJoin);
657-
assertTrue(s, iArtistId2T2 > i2 || iArtistId2 > i2);
644+
assertTrue(s, iArtistId2T1 > i2 || iArtistId2 > i2);
645+
int iLeftJoin = s.indexOf("LEFT JOIN");
646+
assertTrue(s, iLeftJoin > iJoin);
647+
int iPainting = s.indexOf(charStart + "PAINTING" + charEnd + " " + charStart + "t2" + charEnd);
648+
assertTrue(s, iPainting > iLeftJoin);
649+
int iOn = s.indexOf(" ON ", iLeftJoin);
650+
assertTrue(s, iOn > iLeftJoin);
651+
int iArtistId = s.indexOf(charStart + "t0" + charEnd + "." + charStart + "ARTIST_ID" + charEnd, iLeftJoin);
652+
assertTrue(s, iArtistId > iOn);
653+
int iArtistIdT2 = s
654+
.indexOf(charStart + "t2" + charEnd + "." + charStart + "ARTIST_ID" + charEnd, iLeftJoin);
655+
assertTrue(s, iArtistIdT2 > iOn);
656+
int i = s.indexOf("=", iLeftJoin);
657+
assertTrue(s, iArtistIdT2 > i || iArtistId > i);
658658
int iWhere = s.indexOf(" WHERE ");
659-
assertTrue(s, iWhere > iJoin);
659+
assertTrue(s, iWhere > iLeftJoin);
660660

661-
int paintingTitle2 = s.indexOf(charStart + "t2" + charEnd + "." + charStart + "PAINTING_TITLE" + charEnd + " = ?");
661+
int paintingTitle2 = s.indexOf(charStart + "t1" + charEnd + "." + charStart + "PAINTING_TITLE" + charEnd + " = ?");
662662
assertTrue(s, paintingTitle2 > iWhere);
663663

664664
} finally {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
****************************************************************/
19+
20+
package org.apache.cayenne.access.translator.select;
21+
22+
import org.apache.cayenne.access.DataNode;
23+
import org.apache.cayenne.dba.DbAdapter;
24+
import org.apache.cayenne.di.Inject;
25+
import org.apache.cayenne.map.EntityResolver;
26+
import org.apache.cayenne.query.ObjectSelect;
27+
import org.apache.cayenne.testdo.inheritance_vertical.IvBase;
28+
import org.apache.cayenne.testdo.inheritance_vertical.IvOther;
29+
import org.apache.cayenne.unit.di.runtime.CayenneProjects;
30+
import org.apache.cayenne.unit.di.runtime.RuntimeCase;
31+
import org.apache.cayenne.unit.di.runtime.UseCayenneRuntime;
32+
import org.junit.Test;
33+
34+
import static org.junit.Assert.*;
35+
36+
/**
37+
* @since 5.0
38+
*/
39+
@UseCayenneRuntime(CayenneProjects.INHERITANCE_VERTICAL_PROJECT)
40+
public class VerticalInheritanceJoinOrderIT extends RuntimeCase {
41+
42+
@Inject
43+
private DataNode dataNode;
44+
45+
/**
46+
* Tests that INNER joins from WHERE clause relationships are added before
47+
* LEFT OUTER joins from vertical inheritance child tables in the generated SQL.
48+
*/
49+
@Test
50+
public void testQualifierJoinsBeforeDependentTableLeftJoins() {
51+
ObjectSelect<IvBase> q = ObjectSelect.query(IvBase.class)
52+
.where(IvBase.OTHERS.dot(IvOther.NAME).eq("test"))
53+
.and(IvBase.OTHERS.dot(IvOther.BASE).dot(IvBase.NAME).eq("test2"));
54+
55+
String sql = translateToSql(q);
56+
57+
assertTrue("Expected INNER JOIN to IV_OTHER, got: " + sql, sql.contains("JOIN IV_OTHER"));
58+
assertTrue("Expected LEFT JOIN to IV_IMPL, got: " + sql, sql.contains("LEFT JOIN IV_IMPL"));
59+
60+
int iLeftJoin = sql.indexOf("LEFT JOIN IV_IMPL");
61+
int iInnerJoinOther = sql.indexOf("JOIN IV_OTHER");
62+
assertTrue("INNER JOIN to IV_OTHER should precede LEFT JOIN, got: " + sql,
63+
iInnerJoinOther < iLeftJoin);
64+
65+
int iInnerJoinBase = sql.indexOf("JOIN IV_BASE", iInnerJoinOther);
66+
if (iInnerJoinBase > 0) {
67+
assertTrue("INNER JOIN to IV_BASE should precede LEFT JOIN, got: " + sql,
68+
iInnerJoinBase < iLeftJoin);
69+
}
70+
}
71+
72+
private String translateToSql(ObjectSelect<?> query) {
73+
DbAdapter adapter = dataNode.getAdapter();
74+
EntityResolver resolver = dataNode.getEntityResolver();
75+
return new DefaultSelectTranslator(query, adapter, resolver).getSql();
76+
}
77+
}

0 commit comments

Comments
 (0)