DtoQuery initiate the bind capture

This commit is contained in:
robin.bygrave
2026-06-08 23:24:13 +12:00
parent 8c37b53bad
commit a081d08621
5 changed files with 51 additions and 13 deletions
@@ -2276,7 +2276,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (initRequest.isAll()) {
queryPlanManager.setDefaultThreshold(initRequest.thresholdMicros());
}
return descriptorManager.queryPlanInit(initRequest);
List<MetaQueryPlan> list = descriptorManager.queryPlanInit(initRequest);
dtoBeanManager.queryPlanInit(initRequest, list);
return list;
}
List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request) {
@@ -1,7 +1,10 @@
package io.ebeaninternal.server.dto;
import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.MetricVisitor;
import io.ebean.meta.QueryPlanInit;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -43,6 +46,18 @@ public final class DtoBeanDescriptor<T> {
}
}
/**
* Arm bind capture for matching (native SQL) DTO query plans.
*/
public void queryPlanInit(QueryPlanInit request, List<MetaQueryPlan> list) {
for (DtoQueryPlan plan : plans.values()) {
if (request.includeHash(plan.hash())) {
plan.queryPlanInit(request.thresholdMicros(plan.hash()));
list.add(plan.createMeta(null, null));
}
}
}
/**
* Return the named RawSql query.
*/
@@ -1,9 +1,12 @@
package io.ebeaninternal.server.dto;
import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.MetricVisitor;
import io.ebean.meta.QueryPlanInit;
import io.ebeaninternal.server.type.TypeManager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -51,4 +54,14 @@ public final class DtoBeanManager {
value.visit(visitor);
}
}
/**
* Arm bind capture for matching (native SQL) DTO query plans.
*/
@SuppressWarnings("unchecked")
public void queryPlanInit(QueryPlanInit request, List<MetaQueryPlan> list) {
for (DtoBeanDescriptor value : descriptorMap.values()) {
value.queryPlanInit(request, list);
}
}
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.dto;
import io.ebean.core.type.DataReader;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.SpiQueryPlan;
import io.ebeaninternal.server.bind.capture.BindCapture;
import java.sql.SQLException;
@@ -9,7 +10,7 @@ import java.sql.SQLException;
/**
* Knows how to read and map rows into a Bean.
*/
public interface DtoQueryPlan {
public interface DtoQueryPlan extends SpiQueryPlan {
/**
* Read the row data and return the DTO bean.
@@ -30,25 +30,32 @@ class DtoQueryPlanCaptureTest extends BaseTestCase {
}
}
private List<DCustPlanCapture> runQuery() {
return DB.getDefault()
.findDto(DCustPlanCapture.class, "select id, name from o_customer where id > ?")
.setParameter(0)
.setLabel("custDtoPlan")
.findList();
}
@Test
void nativeDtoQuery_capturesQueryPlan() {
ResetBasicData.reset();
// arm bind capture with a very low threshold so new (DTO) plans capture
// build the DTO plan first (default threshold -> no capture yet)
assertThat(runQuery()).isNotEmpty();
// arming an already-built DTO plan should return its meta
QueryPlanInit init = new QueryPlanInit();
init.setAll(true);
init.thresholdMicros(1);
DB.getDefault().metaInfo().queryPlanInit(init);
List<MetaQueryPlan> armed = DB.getDefault().metaInfo().queryPlanInit(init);
assertThat(armed)
.as("queryPlanInit includes the (already built) DTO plan")
.anyMatch(p -> "dto.DCustPlanCapture.custDtoPlan".equals(p.label()));
// native SQL DtoQuery - creates the DTO plan with the low threshold and captures bind values
for (int i = 0; i < 3; i++) {
List<DCustPlanCapture> list = DB.getDefault()
.findDto(DCustPlanCapture.class, "select id, name from o_customer where id > ?")
.setParameter(0)
.setLabel("custDtoPlan")
.findList();
assertThat(list).isNotEmpty();
}
// run again now that the plan is armed -> bind values captured
assertThat(runQuery()).isNotEmpty();
QueryPlanRequest request = new QueryPlanRequest();
request.maxCount(1000);