mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Merge pull request #3372 from ebean-orm/feature/1857-SlowQueryBindCapture
#1857 Add bind values capture for SlowQueryEvent / SlowQueryListener
This commit is contained in:
@@ -1,50 +1,29 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Slow query event.
|
||||
* The data for the slow query.
|
||||
*/
|
||||
public class SlowQueryEvent {
|
||||
|
||||
private final String sql;
|
||||
|
||||
private final long timeMillis;
|
||||
|
||||
private final int rowCount;
|
||||
|
||||
private final ObjectGraphNode originNode;
|
||||
|
||||
/**
|
||||
* Construct with the SQL and execution time in millis.
|
||||
*/
|
||||
public SlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode) {
|
||||
this.sql = sql;
|
||||
this.timeMillis = timeMillis;
|
||||
this.rowCount = rowCount;
|
||||
this.originNode = originNode;
|
||||
}
|
||||
public interface SlowQueryEvent {
|
||||
|
||||
/**
|
||||
* Return the SQL for the slow query.
|
||||
*/
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Return the execution time in millis.
|
||||
*/
|
||||
public long getTimeMillis() {
|
||||
return timeMillis;
|
||||
}
|
||||
long getTimeMillis();
|
||||
|
||||
/**
|
||||
* Return the total row count associated with the query.
|
||||
*/
|
||||
public int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
int getRowCount();
|
||||
|
||||
/**
|
||||
* Return the origin point for the root query.
|
||||
@@ -53,7 +32,20 @@ public class SlowQueryEvent {
|
||||
* shows the code that invoked the query.
|
||||
* </p>
|
||||
*/
|
||||
public ObjectGraphNode getOriginNode() {
|
||||
return originNode;
|
||||
}
|
||||
ObjectGraphNode getOriginNode();
|
||||
|
||||
/**
|
||||
* Return the bind parameters.
|
||||
*/
|
||||
List<Object> getBindParams();
|
||||
|
||||
/**
|
||||
* Return the label.
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public interface SpiExpression extends Expression {
|
||||
*
|
||||
* @param request the associated request.
|
||||
*/
|
||||
void addBindValues(SpiExpressionRequest request);
|
||||
void addBindValues(SpiExpressionBind request);
|
||||
|
||||
/**
|
||||
* Validate all the properties/paths associated with this expression.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* Expression bind values capture.
|
||||
*/
|
||||
public interface SpiExpressionBind {
|
||||
|
||||
/**
|
||||
* Return the bean descriptor for the root type.
|
||||
*/
|
||||
BeanDescriptor<?> descriptor();
|
||||
|
||||
/**
|
||||
* Add an encryption key to bind to this request.
|
||||
*/
|
||||
void addBindEncryptKey(Object encryptKey);
|
||||
|
||||
/**
|
||||
* Add a bind value to this request.
|
||||
*/
|
||||
void addBindValue(Object bindValue);
|
||||
|
||||
/**
|
||||
* Escapes a string to use it as exact match in Like clause.
|
||||
*/
|
||||
String escapeLikeString(String value);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionRequest;
|
||||
|
||||
@@ -10,7 +9,7 @@ import java.util.List;
|
||||
/**
|
||||
* Request object used for gathering expression sql and bind values.
|
||||
*/
|
||||
public interface SpiExpressionRequest extends DbExpressionRequest {
|
||||
public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionRequest {
|
||||
|
||||
/**
|
||||
* Return the DB specific handler for JSON and ARRAY expressions.
|
||||
@@ -22,11 +21,6 @@ public interface SpiExpressionRequest extends DbExpressionRequest {
|
||||
*/
|
||||
String parseDeploy(String logicalProp);
|
||||
|
||||
/**
|
||||
* Return the bean descriptor for the root type.
|
||||
*/
|
||||
BeanDescriptor<?> descriptor();
|
||||
|
||||
/**
|
||||
* Return the associated QueryRequest.
|
||||
*/
|
||||
@@ -58,16 +52,6 @@ public interface SpiExpressionRequest extends DbExpressionRequest {
|
||||
*/
|
||||
SpiExpressionRequest parse(String expression);
|
||||
|
||||
/**
|
||||
* Add an encryption key to bind to this request.
|
||||
*/
|
||||
void addBindEncryptKey(Object encryptKey);
|
||||
|
||||
/**
|
||||
* Add a bind value to this request.
|
||||
*/
|
||||
void addBindValue(Object bindValue);
|
||||
|
||||
/**
|
||||
* Return the accumulated expression sql for all expressions in this request.
|
||||
*/
|
||||
@@ -88,11 +72,6 @@ public interface SpiExpressionRequest extends DbExpressionRequest {
|
||||
*/
|
||||
void appendLike(boolean rawLikeExpression);
|
||||
|
||||
/**
|
||||
* Escapes a string to use it as exact match in Like clause.
|
||||
*/
|
||||
String escapeLikeString(String value);
|
||||
|
||||
/**
|
||||
* Append IN expression taking into account platform and type support for Multi-value.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.SlowQueryEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Slow query event.
|
||||
*/
|
||||
final class DSlowQueryEvent implements SlowQueryEvent {
|
||||
|
||||
private final String sql;
|
||||
private final long timeMillis;
|
||||
private final int rowCount;
|
||||
private final ObjectGraphNode originNode;
|
||||
private final List<Object> bindParams;
|
||||
private final String label;
|
||||
private final ProfileLocation profileLocation;
|
||||
|
||||
/**
|
||||
* Construct with the SQL and execution time in millis.
|
||||
*/
|
||||
DSlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode,
|
||||
List<Object> bindParams, String label, ProfileLocation profileLocation) {
|
||||
this.sql = sql;
|
||||
this.timeMillis = timeMillis;
|
||||
this.rowCount = rowCount;
|
||||
this.originNode = originNode;
|
||||
this.bindParams = bindParams;
|
||||
this.profileLocation = profileLocation;
|
||||
this.label = label != null ? label : profileLocation == null ? null : profileLocation.label();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeMillis() {
|
||||
return timeMillis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getOriginNode() {
|
||||
return originNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getBindParams() {
|
||||
return bindParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return profileLocation;
|
||||
}
|
||||
}
|
||||
@@ -2184,7 +2184,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
@Override
|
||||
public void slowQueryCheck(long timeMicros, int rowCount, SpiQuery<?> query) {
|
||||
if (timeMicros > slowQueryMicros && slowQueryListener != null) {
|
||||
slowQueryListener.process(new SlowQueryEvent(query.getGeneratedSql(), timeMicros / 1000L, rowCount, query.parentNode()));
|
||||
List<Object> bindParams = new SlowQueryBindCapture(query).capture();
|
||||
slowQueryListener.process(new DSlowQueryEvent(query.getGeneratedSql(), timeMicros / 1000L, rowCount,
|
||||
query.parentNode(), bindParams, query.label(), query.profileLocation()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.avaje.applog.AppLog;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.config.SlowQueryEvent;
|
||||
import io.ebean.config.SlowQueryListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.System.Logger.Level.WARNING;
|
||||
|
||||
/**
|
||||
@@ -16,11 +18,10 @@ final class DefaultSlowQueryListener implements SlowQueryListener {
|
||||
|
||||
@Override
|
||||
public void process(SlowQueryEvent event) {
|
||||
String firstStack = "";
|
||||
ObjectGraphNode node = event.getOriginNode();
|
||||
if (node != null) {
|
||||
firstStack = node.origin().top();
|
||||
}
|
||||
log.log(WARNING, "Slow query warning - millis:{0} rows:{1} caller[{2}] sql[{3}]", event.getTimeMillis(), event.getRowCount(), firstStack, event.getSql());
|
||||
ProfileLocation profileLocation = event.getProfileLocation();
|
||||
String loc = profileLocation == null ? "" : profileLocation.fullLocation();
|
||||
List<Object> bindParams = event.getBindParams();
|
||||
log.log(WARNING, "Slow query warning - millis:{0} rows:{1} location:{2} sql[{3}] params{4}",
|
||||
event.getTimeMillis(), event.getRowCount(), loc, event.getSql(), bindParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionList;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.persist.MultiValueWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
final class SlowQueryBindCapture implements SpiExpressionBind {
|
||||
|
||||
private final SpiQuery<?> query;
|
||||
private final List<Object> bindParams = new ArrayList<>();
|
||||
|
||||
SlowQueryBindCapture(SpiQuery<?> query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
List<Object> capture() {
|
||||
var params = query.bindParams();
|
||||
if (params != null) {
|
||||
var positionedParameters = params.positionedParameters();
|
||||
for (BindParams.Param param : positionedParameters) {
|
||||
if (param.isInParam()) {
|
||||
add(param.inValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
Object id = query.getId();
|
||||
if (id != null) {
|
||||
add(id);
|
||||
}
|
||||
SpiExpressionList<?> spiExpressionList = query.whereExpressions();
|
||||
if (spiExpressionList != null) {
|
||||
spiExpressionList.addBindValues(this);
|
||||
}
|
||||
return bindParams;
|
||||
}
|
||||
|
||||
private void add(Object value) {
|
||||
if (value instanceof MultiValueWrapper) {
|
||||
var mvw = (MultiValueWrapper) value;
|
||||
bindParams.add(mvw.getValues());
|
||||
} else {
|
||||
bindParams.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor<?> descriptor() {
|
||||
return query.descriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValue(Object bindValue) {
|
||||
add(bindValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindEncryptKey(Object encryptKey) {
|
||||
bindParams.add("*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escapeLikeString(String value) {
|
||||
return query.descriptor().ebeanServer().databasePlatform().escapeLikeString(value);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.deploy.id;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -143,7 +144,7 @@ public interface IdBinder {
|
||||
/**
|
||||
* Binds multiple id value to a request.
|
||||
*/
|
||||
void addBindValues(SpiExpressionRequest request, Collection<?> ids);
|
||||
void addBindValues(SpiExpressionBind request, Collection<?> ids);
|
||||
|
||||
/**
|
||||
* Return the sql for binding the id using an IN clause.
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy.id;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
@@ -269,7 +270,7 @@ public final class IdBinderEmbedded implements IdBinder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request, Collection<?> values) {
|
||||
public void addBindValues(SpiExpressionBind request, Collection<?> values) {
|
||||
for (Object value : values) {
|
||||
final EntityBean bean = (EntityBean) value;
|
||||
for (BeanProperty prop : props) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.deploy.id;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.bind.DataBind;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
@@ -130,7 +131,7 @@ final class IdBinderEmpty implements IdBinder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request, Collection<?> ids) {
|
||||
public void addBindValues(SpiExpressionBind request, Collection<?> ids) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy.id;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import io.ebeaninternal.server.core.InternString;
|
||||
@@ -143,7 +144,7 @@ public final class IdBinderSimple implements IdBinder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request, Collection<?> values) {
|
||||
public void addBindValues(SpiExpressionBind request, Collection<?> values) {
|
||||
List<Object> copy = new ArrayList<>(values);
|
||||
copy.replaceAll(idValue -> convertSetId(idValue, null));
|
||||
request.addBindValue(new MultiValueWrapper(copy));
|
||||
|
||||
@@ -97,7 +97,7 @@ abstract class AbstractExpression implements SpiExpression {
|
||||
validation.validate(propName);
|
||||
}
|
||||
|
||||
protected final ElPropertyValue getElProp(SpiExpressionRequest request) {
|
||||
protected final ElPropertyValue getElProp(SpiExpressionBind request) {
|
||||
return request.descriptor().elGetValue(propName);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
/**
|
||||
@@ -28,7 +29,7 @@ abstract class AbstractTextExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
// do nothing, only execute against document store
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ final class AllEqualsExpression extends NonPrepareExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
if (propMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -72,7 +73,7 @@ final class ArrayContainsExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (Object value : values) {
|
||||
request.addBindValue(value);
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -49,7 +50,7 @@ final class ArrayIsEmptyExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
// nothing to bind
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -34,7 +35,7 @@ final class BetweenExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && prop.isDbEncrypted()) {
|
||||
// bind the key as well as the value
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
request.addBindValue(val());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,7 @@ final class BitwiseExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
request.addBindValue(flags);
|
||||
request.addBindValue(match);
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -33,7 +34,7 @@ final class CaseInsensitiveEqualExpression extends AbstractValueExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && prop.isDbEncrypted()) {
|
||||
// bind the key as well as the value
|
||||
|
||||
+2
-8
@@ -5,12 +5,7 @@ import io.ebean.LikeType;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.SpiExpressionValidation;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
@@ -194,8 +189,7 @@ final class DefaultExampleExpression implements SpiExpression, ExampleExpression
|
||||
* Adds bind values to the request.
|
||||
*/
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (SpiExpression item : list) {
|
||||
item.addBindValues(request);
|
||||
}
|
||||
|
||||
+1
-1
@@ -591,7 +591,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (SpiExpression expr : list) {
|
||||
expr.addBindValues(request);
|
||||
}
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ final class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreE
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (Object bindParam : bindParams) {
|
||||
request.addBindValue(bindParam);
|
||||
}
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ final class ExistsSqlQueryExpression implements SpiExpression, UnsupportedDocSto
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (Object bindParam : bindParams) {
|
||||
request.addBindValue(bindParam);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ final class IdExpression extends NonPrepareExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
// 'flatten' EmbeddedId and multiple ID cases
|
||||
// into an array of the underlying scalar field values
|
||||
for (Object bindIdValue : request.descriptor().bindIdValues(value)) {
|
||||
|
||||
@@ -61,7 +61,7 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
if (idCollection.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.persist.MultiValueWrapper;
|
||||
|
||||
@@ -103,7 +100,7 @@ public final class InExpression extends AbstractExpression implements IdInCommon
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@ package io.ebeaninternal.server.expression;
|
||||
import io.ebean.Pairs;
|
||||
import io.ebean.Pairs.Entry;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.persist.MultiValueWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -58,8 +55,7 @@ final class InPairsExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
// Note at this point entries may have been removed when used with l2 caching
|
||||
// ... for each l2 cache hit an entry was removed
|
||||
this.concatBindValues = new ArrayList<>(entries.size());
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -32,7 +33,7 @@ final class InRangeExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && prop.isDbEncrypted()) {
|
||||
// bind the key twice, for both values
|
||||
|
||||
@@ -2,10 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.InTuples;
|
||||
import io.ebean.service.SpiInTuples;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -37,7 +34,7 @@ final class InTuplesExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (Object[] entry : entries) {
|
||||
for (Object value : entry) {
|
||||
requireNonNull(value);
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -53,7 +50,7 @@ final class IsEmptyExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
// no bind values
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -102,7 +103,7 @@ final class JsonPathExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
if (value != null) {
|
||||
// value is null for EXISTS/NOT EXISTS
|
||||
request.addBindValue(value);
|
||||
|
||||
@@ -141,7 +141,7 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (SpiExpression expr : exprList.internalList()) {
|
||||
expr.addBindValues(request);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.expression;
|
||||
import io.ebean.LikeType;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -25,7 +26,7 @@ final class LikeExpression extends AbstractValueExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && prop.isDbEncrypted()) {
|
||||
// bind the key as well as the value
|
||||
@@ -78,7 +79,7 @@ final class LikeExpression extends AbstractValueExpression {
|
||||
return strValue().equals(that.strValue());
|
||||
}
|
||||
|
||||
private static String getValue(String value, boolean caseInsensitive, LikeType type, SpiExpressionRequest request) {
|
||||
private static String getValue(String value, boolean caseInsensitive, LikeType type, SpiExpressionBind request) {
|
||||
if (caseInsensitive) {
|
||||
value = value.toLowerCase();
|
||||
}
|
||||
|
||||
@@ -3,12 +3,7 @@ package io.ebeaninternal.server.expression;
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.Junction;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.SpiExpressionValidation;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -133,7 +128,7 @@ abstract class LogicExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
expOne.addBindValues(request);
|
||||
expTwo.addBindValues(request);
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.expression;
|
||||
import io.ebean.LikeType;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -23,8 +24,7 @@ final class NativeILikeExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && prop.isDbEncrypted()) {
|
||||
// bind the key as well as the value
|
||||
|
||||
+2
-7
@@ -1,13 +1,8 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.SpiExpressionValidation;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -94,7 +89,7 @@ final class NestedPathWrapperExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
delegate.addBindValues(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ final class NoopExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.SpiExpressionValidation;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -73,7 +68,7 @@ final class NotExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
exp.addBindValues(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -51,7 +48,7 @@ final class NullExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ final class RawExpression extends NonPrepareExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
if (values != null) {
|
||||
for (Object value : values) {
|
||||
if (value instanceof Collection<?>) {
|
||||
|
||||
@@ -2,10 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.plugin.ExpressionPath;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -68,8 +65,7 @@ public final class SimpleExpression extends AbstractValueExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null) {
|
||||
if (prop.isAssocId()) {
|
||||
|
||||
@@ -79,7 +79,7 @@ final class SubQueryExpression extends AbstractExpression implements Unsupported
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (Object bindParam : bindParams) {
|
||||
request.addBindValue(bindParam);
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionBind;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -47,7 +48,7 @@ final class SubQueryRawExpression extends AbstractExpression implements Unsuppor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
public void addBindValues(SpiExpressionBind request) {
|
||||
for (Object bindParam : bindParams) {
|
||||
request.addBindValue(bindParam);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.Query;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SlowQueryBindCaptureTest {
|
||||
|
||||
static Database db;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
db = DB.getDefault();
|
||||
db.script().run("/h2-init.sql");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindParams_capture() {
|
||||
String sql = "select * from o_customer p where p.status = ?";
|
||||
Query<Customer> query = db.findNative(Customer.class, sql)
|
||||
.setParameter("N");
|
||||
query.findList();
|
||||
|
||||
var sbc = new SlowQueryBindCapture((SpiQuery<?>) query);
|
||||
List<Object> bindParams = sbc.capture();
|
||||
assertThat(bindParams).hasSize(1);
|
||||
assertThat(bindParams.get(0)).isEqualTo("N");
|
||||
}
|
||||
|
||||
@Test
|
||||
void expressionsCapture() {
|
||||
Query<Customer> query = db.find(Customer.class)
|
||||
.where()
|
||||
.startsWith("name", "rob")
|
||||
.eq("status", "N")
|
||||
.query();
|
||||
|
||||
query.findList();
|
||||
|
||||
var sbc = new SlowQueryBindCapture((SpiQuery<?>) query);
|
||||
List<Object> bindParams = sbc.capture();
|
||||
assertThat(bindParams).hasSize(2);
|
||||
assertThat(bindParams.get(0)).isEqualTo("rob%");
|
||||
assertThat(bindParams.get(1)).isEqualTo("N");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void multiValueCapture() {
|
||||
Query<Customer> query = db.find(Customer.class)
|
||||
.where()
|
||||
.in("id", List.of(1, 2, 3, 4))
|
||||
.query();
|
||||
|
||||
query.findList();
|
||||
|
||||
var sbc = new SlowQueryBindCapture((SpiQuery<?>) query);
|
||||
List<Object> bindParams = sbc.capture();
|
||||
assertThat(bindParams).hasSize(1);
|
||||
Object bindParam0 = bindParams.get(0);
|
||||
assertThat(bindParam0).isInstanceOf(ArrayList.class);
|
||||
var values = (ArrayList<Object>) bindParam0;
|
||||
assertThat(values).contains(1, 2, 3, 4);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
create table animal (
|
||||
create table if not exists animal (
|
||||
species varchar(255) not null,
|
||||
id bigint generated by default as identity not null,
|
||||
shelter_id bigint,
|
||||
@@ -11,14 +11,14 @@ create table animal (
|
||||
constraint pk_animal primary key (id)
|
||||
);
|
||||
|
||||
create table animal_shelter (
|
||||
create table if not exists animal_shelter (
|
||||
id bigint generated by default as identity not null,
|
||||
name varchar(255),
|
||||
version bigint not null,
|
||||
constraint pk_animal_shelter primary key (id)
|
||||
);
|
||||
|
||||
create table o_customer (
|
||||
create table if not exists o_customer (
|
||||
id integer generated by default as identity not null,
|
||||
status varchar(1),
|
||||
name varchar(40) not null,
|
||||
|
||||
@@ -4,6 +4,7 @@ ebean.ddl.initSql=init-db.sql
|
||||
ebean.dumpMetricsOnShutdown=true
|
||||
ebean.dumpMetricsOptions=sql,hash,loc
|
||||
ebean.includeLabelInSql=true
|
||||
ebean.slowQueryMillis=1
|
||||
|
||||
datasource.default=h2
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ ebean.encryptKeyManager=org.tests.basic.encrypt.BasicEncyptKeyManager
|
||||
#ebean.autoTune.profilingUpdateFrequency=5
|
||||
ebean.includeLabelInSql=true
|
||||
|
||||
ebean.slowQueryMillis=4
|
||||
ebean.ddl.generate=true
|
||||
ebean.ddl.run=true
|
||||
ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp}
|
||||
|
||||
Reference in New Issue
Block a user