Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
private final STreePropertyAssoc assocBeanProperty;
private final SpiQuery.TemporalMode temporalMode;
private final String prefix;
private final boolean manyJoin;
private boolean manyJoin;
private final boolean pathContainsMany;
private List<SqlTreeNode> children;

Expand Down Expand Up @@ -95,6 +95,9 @@ public void addChild(SqlTreeNode child) {
if (children == null) {
children = new ArrayList<>();
}
if (child.hasMany()) {
manyJoin = true;
}
children.add(child);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.tests.basic;

import io.ebean.DB;
import io.ebean.Query;
import io.ebean.xtest.BaseTestCase;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Country;
import org.tests.model.basic.EBasic;
import org.tests.model.basic.OBeanChild;
import org.tests.model.basic.OCachedBean;
import org.tests.model.basic.ResetBasicData;

public class TestManyOnChildOfExtraJoin extends BaseTestCase {


@Test
public void test() {
ResetBasicData.reset();

OCachedBean bean = new OCachedBean();
bean.setName("m2m-with-sq");
bean.getCountries().add(DB.reference(Country.class, "NZ"));
bean.getCountries().add(DB.reference(Country.class, "AU"));
DB.save(bean);

OBeanChild child = new OBeanChild();
child.setCachedBean(bean);
DB.save(child);

EBasic b1 = new EBasic();
b1.setName("Australia");
b1.setStatus(EBasic.Status.ACTIVE);
DB.save(b1);

EBasic b2 = new EBasic();
b2.setName("New Zealand");
b2.setStatus(EBasic.Status.ACTIVE);
DB.save(b2);

Query<OBeanChild> query = DB.find(OBeanChild.class).where()
.eq("cachedBean.name", "m2m-with-sq")
.exists(DB.find(EBasic.class)
.alias("sq1")
.where()
.raw("cachedBean.countries.name = sq1.name")
.eq("status", EBasic.Status.ACTIVE)
.query())
.query();
SoftAssertions softly = new SoftAssertions();
softly.assertThat(query.findList()).hasSize(1);
softly.assertThat(query.getGeneratedSql()).startsWith("select distinct");
softly.assertAll();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void testOrderOnChainedFormulaProperty() {
.orderBy().asc("order.totalAmount");

shipQuery.findList();
assertSql(shipQuery.getGeneratedSql()).isEqualTo("select t0.id "
assertSql(shipQuery.getGeneratedSql()).isEqualTo("select distinct t0.id, z_bt1.total_amount "
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- new SQL (with distinct - and orderby field)
select distinct t0.id, z_bt1.total_amount from or_order_ship t0 
    left join o_order t1 on t1.id = t0.order_id 
    left join (select order_id, count(*) as total_items, sum(order_qty*unit_price) as total_amount
    from o_order_detail group by order_id) z_bt1 on z_bt1.order_id = t1.id
    order by z_bt1.total_amount
-- old SQL (without distinct)
select          t0.id                     from or_order_ship t0 
    left join o_order t1 on t1.id = t0.order_id 
    left join (select order_id, count(*) as total_items, sum(order_qty*unit_price) as total_amount 
    from o_order_detail group by order_id) z_bt1 on z_bt1.order_id = t1.id
    order by z_bt1.total_amount

The problem here is, that totalAmount is a @Formula property with join. And that join could be theoretically a M2M
Ebean generates a SqlTreeNodeFormulaWhereJoin here, which always returns true for hasMany()

+ "from or_order_ship t0 "
+ "left join o_order t1 on t1.id = t0.order_id "
+ "left join (select order_id, count(*) as total_items, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) z_bt1 on z_bt1.order_id = t1.id "
Expand All @@ -99,7 +99,7 @@ public void testWhereOnChainedFormulaProperty() {
.where().isNotNull("order.totalAmount").query();

shipQuery.findList();
assertSql(shipQuery.getGeneratedSql()).isEqualTo("select t0.id "
assertSql(shipQuery.getGeneratedSql()).isEqualTo("select distinct t0.id "
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--- new SQL (with distinct)
select distinct t0.id from or_order_ship t0
    left join o_order t1 on t1.id = t0.order_id
    left join (select order_id, count(*) as total_items, sum(order_qty*unit_price) as total_amount
    from o_order_detail group by order_id) z_bt1 on z_bt1.order_id = t1.id
    where z_bt1.total_amount is not null
-- old SQL (without distinct)
select          t0.id from or_order_ship t0
    left join o_order t1 on t1.id = t0.order_id
    left join (select order_id, count(*) as total_items, sum(order_qty*unit_price) as total_amount 
    from o_order_detail group by order_id) z_bt1 on z_bt1.order_id = t1.id 
    where z_bt1.total_amount is not null

Here is also just a distinct added

+ "from or_order_ship t0 "
+ "left join o_order t1 on t1.id = t0.order_id "
+ "left join (select order_id, count(*) as total_items, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) z_bt1 on z_bt1.order_id = t1.id "
Expand Down Expand Up @@ -313,7 +313,7 @@ public void test_ChildPersonParentFindIds() {
List<String> loggedSql = LoggedSql.stop();
assertEquals(1, loggedSql.size());
assertThat(loggedSql.get(0))
.contains("select t0.identifier from child_person t0")
.contains("select distinct t0.identifier from child_person t0")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- new SQL (with distinct)
select distinct t0.identifier from child_person t0
    left join parent_person t1 on t1.identifier = t0.parent_identifier
    left join (select i2.parent_identifier, count(*) as child_count, sum(i2.age) as child_age
    from child_person i2 group by i2.parent_identifier) f2 on f2.parent_identifier = t1.identifier
    where coalesce(f2.child_age, 0) = ?
-- old SQL (without distinct)
select          t0.identifier from child_person t0
    left join parent_person t1 on t1.identifier = t0.parent_identifier
    left join (select i2.parent_identifier, count(*) as child_count, sum(i2.age) as child_age
    from child_person i2 group by i2.parent_identifier) f2 on f2.parent_identifier = t1.identifier
    where coalesce(f2.child_age, 0) = ?

.contains("left join (select i2.parent_identifier")
.contains("where coalesce(f2.child_age, 0) = ?");
}
Expand All @@ -329,8 +329,8 @@ public void test_ChildPersonParentFindCount() {

List<String> loggedSql = LoggedSql.stop();
assertEquals(1, loggedSql.size());
assertThat(loggedSql.get(0)).contains("select count(*) from child_person t0 left join parent_person t1 on t1.identifier = t0.parent_identifier");
assertThat(loggedSql.get(0)).contains("where coalesce(f2.child_age, 0) = ?");
assertThat(loggedSql.get(0)).contains("select count(*) from ( select distinct t0.identifier from child_person t0 left join parent_person t1 on t1.identifier = t0.parent_identifier");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- new SQL - with subquery & distinct
select count(*) from ( select distinct t0.identifier 
    from child_person t0 
    left join parent_person t1 on t1.identifier = t0.parent_identifier
    left join (select i2.parent_identifier, count(*) as child_count, sum(i2.age) as child_age
    from child_person i2 group by i2.parent_identifier) f2 on f2.parent_identifier = t1.identifier
    where coalesce(f2.child_age, 0) = ?) -- subquery ends here
-- old SQL (same as above, but not wrapped in a subquery
select count(*)                                      from child_person t0
    left join parent_person t1 on t1.identifier = t0.parent_identifier
    left join (select i2.parent_identifier, count(*) as child_count, sum(i2.age) as child_age
    from child_person i2 group by i2.parent_identifier) f2 on f2.parent_identifier = t1.identifier
    where coalesce(f2.child_age, 0) = ?

assertThat(loggedSql.get(0)).contains("where coalesce(f2.child_age, 0) = ?)");
}

@Test
Expand Down