mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4509c6b1ed | ||
|
|
d32559baf4 | ||
|
|
2639e799c5 | ||
|
|
46c66b7169 | ||
|
|
30ae435f33 | ||
|
|
4f4743807c | ||
|
|
7b7a492241 | ||
|
|
4af8e53315 | ||
|
|
1c6fa575f2 | ||
|
|
2430404e1f | ||
|
|
d433e0ea46 | ||
|
|
42591a5a87 | ||
|
|
65a62bf683 | ||
|
|
3e3f3c35e7 | ||
|
|
f4db7ca0bb | ||
|
|
b0e487cfbd | ||
|
|
23fd29ddf1 | ||
|
|
f21cac5d4f | ||
|
|
c2e5619f70 | ||
|
|
18e0ff7067 | ||
|
|
4119c02f0d | ||
|
|
8985d37aed | ||
|
|
23e035894f | ||
|
|
32b8fd0e26 | ||
|
|
4971db54c8 | ||
|
|
e417b3cde2 | ||
|
|
d23ca31e42 |
@@ -1,6 +1,29 @@
|
||||
[](https://travis-ci.org/ebean-orm/ebean)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
|
||||
|
||||
# Sponsors
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foconis.de/" target="_blank">
|
||||
<img width="222px" src="https://www.foconis.de/templates/yootheme/cache/foconis_logo_322-709da1de.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.payintech.com/" target="_blank">
|
||||
<img width="222px" src="https://www.payintech.com/wp-content/uploads/2015/10/PayinTech-logo-noir.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.premium-minds.com" target="_blank">
|
||||
<img width="222px" src="https://ebean.io/images/logo-premium-minds.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
# Need help?
|
||||
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
|
||||
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.36.3</version>
|
||||
<version>11.37.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.9.5</jackson-core.version>
|
||||
<jackson-core.version>2.9.8</jackson-core.version>
|
||||
<snakeyaml.version>1.21</snakeyaml.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.36.3</tag>
|
||||
<tag>ebean-11.37.1</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -250,7 +250,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>11.27.1</version>
|
||||
<version>11.37.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -330,7 +330,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>11.35.1</version>
|
||||
<version>11.37.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
@@ -109,6 +109,12 @@ public interface DtoQuery<T> {
|
||||
*/
|
||||
DtoQuery<T> setLabel(String label);
|
||||
|
||||
/**
|
||||
* Set the profile location of this query. This is used to relate query execution metrics
|
||||
* back to a location like a specific line of code.
|
||||
*/
|
||||
DtoQuery<T> setProfileLocation(ProfileLocation profileLocation);
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
|
||||
@@ -5,7 +5,7 @@ package io.ebean.config;
|
||||
*/
|
||||
public class AutoTuneConfig {
|
||||
|
||||
private AutoTuneMode mode = AutoTuneMode.DEFAULT_ON;
|
||||
private AutoTuneMode mode = AutoTuneMode.DEFAULT_OFF;
|
||||
|
||||
private String queryTuningFile = "ebean-autotune.xml";
|
||||
|
||||
|
||||
@@ -524,6 +524,10 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean idGeneratorAutomatic = true;
|
||||
|
||||
private boolean dumpMetricsOnShutdown;
|
||||
|
||||
private String dumpMetricsOptions;
|
||||
|
||||
/**
|
||||
* Construct a Database Configuration for programmatically creating an Database.
|
||||
*/
|
||||
@@ -2903,6 +2907,8 @@ public class ServerConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
|
||||
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
|
||||
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
|
||||
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
|
||||
collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans);
|
||||
@@ -3287,6 +3293,36 @@ public class ServerConfig {
|
||||
this.collectQueryPlans = collectQueryPlans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
public boolean isDumpMetricsOnShutdown() {
|
||||
return dumpMetricsOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
public void setDumpMetricsOnShutdown(boolean dumpMetricsOnShutdown) {
|
||||
this.dumpMetricsOnShutdown = dumpMetricsOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the options for dumping metrics.
|
||||
*/
|
||||
public String getDumpMetricsOptions() {
|
||||
return dumpMetricsOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include 'sql' or 'hash' in options such that they are included in the output.
|
||||
*
|
||||
* @param dumpMetricsOptions Example "sql,hash", "sql"
|
||||
*/
|
||||
public void setDumpMetricsOptions(String dumpMetricsOptions) {
|
||||
this.dumpMetricsOptions = dumpMetricsOptions;
|
||||
}
|
||||
|
||||
public enum UuidVersion {
|
||||
VERSION4,
|
||||
VERSION1,
|
||||
|
||||
@@ -49,6 +49,8 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected boolean useExtraTransactionOnIterateSecondaryQueries;
|
||||
|
||||
protected boolean supportsDeleteTableAlias;
|
||||
|
||||
/**
|
||||
* The behaviour used when ending a read only transaction at read committed isolation level.
|
||||
*/
|
||||
@@ -176,10 +178,10 @@ public class DatabasePlatform {
|
||||
* findIterate() and findVisit().
|
||||
*/
|
||||
protected boolean forwardOnlyHintOnFindIterate;
|
||||
|
||||
|
||||
/**
|
||||
* If set then use the CONCUR_UPDATABLE hint when creating ResultSets.
|
||||
*
|
||||
*
|
||||
* This is {@code false} for HANA
|
||||
*/
|
||||
protected boolean supportsResultSetConcurrencyModeUpdatable = true;
|
||||
@@ -306,6 +308,13 @@ public class DatabasePlatform {
|
||||
return supportsNativeIlike;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the platform supports delete statements with table alias.
|
||||
*/
|
||||
public boolean isSupportsDeleteTableAlias() {
|
||||
return supportsDeleteTableAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum table name length.
|
||||
* <p>
|
||||
@@ -524,7 +533,7 @@ public class DatabasePlatform {
|
||||
public void setForwardOnlyHintOnFindIterate(boolean forwardOnlyHintOnFindIterate) {
|
||||
this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the ResultSet CONCUR_UPDATABLE Hint should be used on
|
||||
* createNativeSqlTree() PreparedStatements.
|
||||
@@ -535,7 +544,7 @@ public class DatabasePlatform {
|
||||
public boolean isSupportsResultSetConcurrencyModeUpdatable() {
|
||||
return supportsResultSetConcurrencyModeUpdatable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set to true if the ResultSet CONCUR_UPDATABLE Hint should be used by default on createNativeSqlTree() PreparedStatements.
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.historySupport = new H2HistorySupport();
|
||||
this.nativeUuidType = true;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
public OraclePlatform() {
|
||||
super();
|
||||
this.platform = Platform.ORACLE;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.maxTableNameLength = 30;
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
|
||||
@@ -30,6 +30,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.platform = Platform.POSTGRES;
|
||||
this.supportsNativeIlike = true;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.List;
|
||||
/**
|
||||
* A simple MetricVisitor that can collect the desired metrics into lists.
|
||||
*/
|
||||
public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics {
|
||||
|
||||
private final List<MetaTimedMetric> timed = new ArrayList<>();
|
||||
private final List<MetaQueryMetric> dtoQuery = new ArrayList<>();
|
||||
@@ -29,6 +29,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
/**
|
||||
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaTimedMetric> getTimedMetrics() {
|
||||
return timed;
|
||||
}
|
||||
@@ -36,6 +37,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaQueryMetric> getDtoQueryMetrics() {
|
||||
return dtoQuery;
|
||||
}
|
||||
@@ -43,6 +45,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
@Override
|
||||
public List<MetaOrmQueryMetric> getOrmQueryMetrics() {
|
||||
return ormQuery;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,15 @@ import java.util.List;
|
||||
*/
|
||||
public interface MetaInfoManager {
|
||||
|
||||
/**
|
||||
* Return the metrics for the database instance.
|
||||
* <p>
|
||||
* This will reset the metrics (reset counters back to zero etc) and
|
||||
* will only return the non-empty metrics.
|
||||
* </p>
|
||||
*/
|
||||
ServerMetrics collectMetrics();
|
||||
|
||||
/**
|
||||
* Collect query plans.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -9,11 +7,6 @@ import java.util.List;
|
||||
*/
|
||||
public interface MetaOrmQueryMetric extends MetaQueryMetric {
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Return true if this query plan was tuned by AutoTune.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
/**
|
||||
* Query execution metrics.
|
||||
*/
|
||||
@@ -15,6 +17,11 @@ public interface MetaQueryMetric extends MetaTimedMetric {
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* The actual SQL of the query.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Metrics of the Database instance.
|
||||
*/
|
||||
public interface ServerMetrics {
|
||||
|
||||
/**
|
||||
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
|
||||
*/
|
||||
List<MetaTimedMetric> getTimedMetrics();
|
||||
|
||||
/**
|
||||
* Return the DTO query metrics.
|
||||
*/
|
||||
List<MetaQueryMetric> getDtoQueryMetrics();
|
||||
|
||||
/**
|
||||
* Return the ORM query metrics.
|
||||
*/
|
||||
List<MetaOrmQueryMetric> getOrmQueryMetrics();
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Comparator for timed metrics sorted by name and then count.
|
||||
*/
|
||||
public class SortMetric {
|
||||
|
||||
public static final Comparator<MetaTimedMetric> NAME = new Name();
|
||||
public static final Comparator<MetaTimedMetric> COUNT = new Count();
|
||||
public static final Comparator<MetaTimedMetric> TOTAL = new Total();
|
||||
public static final Comparator<MetaTimedMetric> MEAN = new Mean();
|
||||
public static final Comparator<MetaTimedMetric> MAX = new Max();
|
||||
|
||||
/**
|
||||
* Sort by name.
|
||||
*/
|
||||
public static class Name implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
String name = o1.getName();
|
||||
String name2 = o2.getName();
|
||||
if (name == null) {
|
||||
return name2 == null ? 0 : -1;
|
||||
}
|
||||
if (name2 == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int i = name.compareTo(name2);
|
||||
return i != 0 ? i : Long.compare(o1.getCount(), o2.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by count desc.
|
||||
*/
|
||||
public static class Count implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getCount(), o1.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by total time desc.
|
||||
*/
|
||||
public static class Total implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getTotal(), o1.getTotal());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by mean desc.
|
||||
*/
|
||||
public static class Mean implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getMean(), o1.getMean());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by max desc.
|
||||
*/
|
||||
public static class Max implements Comparator<MetaTimedMetric> {
|
||||
|
||||
@Override
|
||||
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
|
||||
return Long.compare(o2.getMax(), o1.getMax());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean.metric;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetricType;
|
||||
|
||||
/**
|
||||
@@ -27,6 +28,6 @@ public interface MetricFactory {
|
||||
/**
|
||||
* Create a Timed metric.
|
||||
*/
|
||||
QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, String sql);
|
||||
QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, ProfileLocation profileLocation, String sql);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.DtoQuery;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebeaninternal.server.dto.DtoMappingRequest;
|
||||
import io.ebeaninternal.server.dto.DtoQueryPlan;
|
||||
|
||||
@@ -37,9 +38,23 @@ public interface SpiDtoQuery<T> extends DtoQuery<T>, SpiSqlBinding {
|
||||
/**
|
||||
* Return the label for the query.
|
||||
*/
|
||||
@Override
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Return the label with fallback to profile location label.
|
||||
*/
|
||||
String getPlanLabel();
|
||||
|
||||
/**
|
||||
* Obtain the location if necessary.
|
||||
*/
|
||||
void obtainLocation();
|
||||
|
||||
/**
|
||||
* Return the profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Return the associated DTO bean type.
|
||||
*/
|
||||
|
||||
@@ -54,67 +54,69 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
/**
|
||||
* Find by Id or unique returning a single bean.
|
||||
*/
|
||||
BEAN(FIND_ONE),
|
||||
BEAN(FIND_ONE, "byId"),
|
||||
|
||||
/**
|
||||
* Find returning a List.
|
||||
*/
|
||||
LIST(FIND_MANY),
|
||||
LIST(FIND_MANY, "findList"),
|
||||
|
||||
/**
|
||||
* Find returning a Set.
|
||||
*/
|
||||
SET(FIND_MANY),
|
||||
SET(FIND_MANY, "findSet"),
|
||||
|
||||
/**
|
||||
* Find returning a Map.
|
||||
*/
|
||||
MAP(FIND_MANY),
|
||||
MAP(FIND_MANY, "findMap"),
|
||||
|
||||
/**
|
||||
* Find iterate type query - findEach(), findIterate() etc.
|
||||
*/
|
||||
ITERATE(FIND_ITERATE),
|
||||
ITERATE(FIND_ITERATE, "findEach"),
|
||||
|
||||
/**
|
||||
* Find the Id's.
|
||||
*/
|
||||
ID_LIST(FIND_ID_LIST),
|
||||
ID_LIST(FIND_ID_LIST, "findIds"),
|
||||
|
||||
/**
|
||||
* Find single attribute.
|
||||
*/
|
||||
ATTRIBUTE(FIND_ATTRIBUTE),
|
||||
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute"),
|
||||
|
||||
/**
|
||||
* Find rowCount.
|
||||
*/
|
||||
COUNT(FIND_COUNT),
|
||||
COUNT(FIND_COUNT, "findCount"),
|
||||
|
||||
/**
|
||||
* A subquery used as part of a where clause.
|
||||
*/
|
||||
SUBQUERY(FIND_SUBQUERY),
|
||||
SUBQUERY(FIND_SUBQUERY, "subquery"),
|
||||
|
||||
/**
|
||||
* Delete query.
|
||||
*/
|
||||
DELETE(FIND_DELETE, true),
|
||||
DELETE(FIND_DELETE, "delete", true),
|
||||
|
||||
/**
|
||||
* Update query.
|
||||
*/
|
||||
UPDATE(FIND_UPDATE, true);
|
||||
UPDATE(FIND_UPDATE, "update", true);
|
||||
|
||||
boolean update;
|
||||
String profileEventId;
|
||||
private boolean update;
|
||||
private String profileEventId;
|
||||
private String label;
|
||||
|
||||
Type(String profileEventId) {
|
||||
this(profileEventId, false);
|
||||
Type(String profileEventId, String label) {
|
||||
this(profileEventId, label, false);
|
||||
}
|
||||
|
||||
Type(String profileEventId, boolean update) {
|
||||
Type(String profileEventId, String label, boolean update) {
|
||||
this.profileEventId = profileEventId;
|
||||
this.label = label;
|
||||
this.update = update;
|
||||
}
|
||||
|
||||
@@ -128,6 +130,10 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
public String profileEventId() {
|
||||
return profileEventId;
|
||||
}
|
||||
|
||||
public String label() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
enum TemporalMode {
|
||||
|
||||
@@ -69,11 +69,6 @@ public interface SpiTransaction extends Transaction {
|
||||
*/
|
||||
void registerDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
void unregisterDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
|
||||
@@ -183,11 +183,6 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
transaction.registerDeleteBean(hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDeleteBean(Integer hash) {
|
||||
transaction.unregisterDeleteBean(hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegisteredDeleteBean(Integer hash) {
|
||||
return transaction.isRegisteredDeleteBean(hash);
|
||||
|
||||
@@ -262,7 +262,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
DdlBuffer apply = writer.apply();
|
||||
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(tableName).append(" (");
|
||||
writeTableColumns(apply, columns, useIdentity);
|
||||
writeCheckConstraints(apply, createTable);
|
||||
writeUniqueConstraints(apply, createTable);
|
||||
writeCompoundUniqueConstraints(apply, createTable);
|
||||
if (!pk.isEmpty()) {
|
||||
@@ -506,31 +505,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
buffer.appendStatement(platformDdl.dropSequence(sequenceName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all the check constraints.
|
||||
*/
|
||||
protected void writeCheckConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
|
||||
|
||||
for (Column column : createTable.getColumn()) {
|
||||
String checkConstraint = column.getCheckConstraint();
|
||||
if (hasValue(checkConstraint)) {
|
||||
writeCheckConstraint(apply, column, checkConstraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a check constraint.
|
||||
*/
|
||||
protected void writeCheckConstraint(DdlBuffer buffer, Column column, String checkConstraint) throws IOException {
|
||||
|
||||
String ckName = column.getCheckConstraintName();
|
||||
|
||||
buffer.append(",").newLine();
|
||||
buffer.append(" constraint ").append(ckName);
|
||||
buffer.append(" ").append(checkConstraint);
|
||||
}
|
||||
|
||||
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
|
||||
|
||||
boolean inlineUniqueWhenNull = platformDdl.isInlineUniqueWhenNullable();
|
||||
|
||||
@@ -64,6 +64,11 @@ public class ClickHouseDdl extends PlatformDdl {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createCheckConstraint(String ckName, String checkConstraint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeColumnNotNull(DdlBuffer buffer) {
|
||||
// do nothing
|
||||
|
||||
-6
@@ -25,10 +25,4 @@ public class ClickHouseTableDdl extends BaseTableDdl {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void writeCheckConstraints(DdlBuffer apply, CreateTable createTable) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ import java.util.Collection;
|
||||
*/
|
||||
public class MySqlDdl extends PlatformDdl {
|
||||
|
||||
// check constraint support is disabled by default. See https://groups.google.com/forum/#!topic/ebean/luFN-2xBkUw
|
||||
// this flag is for compatibility. Use it with care.
|
||||
private static final boolean USE_CHECK_CONSTRAINT = Boolean.getBoolean("ebean.mysql.useCheckConstraint");
|
||||
|
||||
public MySqlDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.alterColumn = "modify";
|
||||
@@ -48,11 +52,40 @@ public class MySqlDdl extends PlatformDdl {
|
||||
buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')").endOfStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createCheckConstraint(String ckName, String checkConstraint) {
|
||||
if (USE_CHECK_CONSTRAINT) {
|
||||
return super.createCheckConstraint(ckName, checkConstraint);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String alterTableAddCheckConstraint(String tableName, String checkConstraintName, String checkConstraint) {
|
||||
if (USE_CHECK_CONSTRAINT) {
|
||||
return super.alterTableAddCheckConstraint(tableName, checkConstraintName, checkConstraint);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterTableDropConstraint(String tableName, String constraintName) {
|
||||
// drop constraint not supported in MySQL 5.7 and 8.0 but starting with MariaDB 10.2.1 CHECK is evaluated
|
||||
// TODO: Implement for MariaDB >= 10.2.1
|
||||
return null;
|
||||
// drop constraint not supported in MySQL 5.7 and 8.0 but starting with MariaDB
|
||||
// 10.2.1 CHECK is evaluated
|
||||
if (USE_CHECK_CONSTRAINT) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// statement for MySQL >= 8.0.16
|
||||
sb.append("/*!80016 alter table ").append(tableName);
|
||||
sb.append(" drop check ").append(constraintName).append(" */;\n");
|
||||
// statement for MariaDB >= 10.2.1
|
||||
sb.append("/*M!100201 ");
|
||||
sb.append(super.alterTableDropConstraint(tableName, constraintName));
|
||||
sb.append(" */");
|
||||
return sb.toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -213,10 +213,21 @@ public class PlatformDdl {
|
||||
*/
|
||||
public void writeTableColumns(DdlBuffer apply, List<Column> columns, boolean useIdentity) throws IOException {
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
if (i > 0) {
|
||||
apply.append(",");
|
||||
}
|
||||
apply.newLine();
|
||||
writeColumnDefinition(apply, columns.get(i), useIdentity);
|
||||
if (i < columns.size() - 1) {
|
||||
apply.append(",");
|
||||
}
|
||||
|
||||
for (Column column : columns) {
|
||||
String checkConstraint = column.getCheckConstraint();
|
||||
if (hasValue(checkConstraint)) {
|
||||
checkConstraint = createCheckConstraint(maxConstraintName(column.getCheckConstraintName()), checkConstraint);
|
||||
if (hasValue(checkConstraint)) {
|
||||
apply.append(",").newLine();
|
||||
apply.append(checkConstraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,6 +264,13 @@ public class PlatformDdl {
|
||||
buffer.append(" not null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the check constraint.
|
||||
*/
|
||||
public String createCheckConstraint(String ckName, String checkConstraint) {
|
||||
return " constraint " + ckName + " " + checkConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the DB column default literal to platform specific.
|
||||
*/
|
||||
@@ -492,9 +510,10 @@ public class PlatformDdl {
|
||||
|
||||
// check constraints cannot be added in one statement for h2
|
||||
if (!StringHelper.isNull(column.getCheckConstraint())) {
|
||||
String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(),
|
||||
column.getCheckConstraint());
|
||||
buffer.append(ddl).endOfStatement();
|
||||
String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(), column.getCheckConstraint());
|
||||
if (hasValue(ddl)) {
|
||||
buffer.append(ddl).endOfStatement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buffer.append(addColumnSuffix);
|
||||
@@ -580,7 +599,7 @@ public class PlatformDdl {
|
||||
}
|
||||
|
||||
protected void appendWithSpace(String content, StringBuilder buffer) {
|
||||
if (content != null && !content.isEmpty()) {
|
||||
if (hasValue(content)) {
|
||||
buffer.append(" ").append(content);
|
||||
}
|
||||
}
|
||||
@@ -613,6 +632,13 @@ public class PlatformDdl {
|
||||
return updateNullWithDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if null or trimmed string is empty.
|
||||
*/
|
||||
protected boolean hasValue(String value) {
|
||||
return value != null && !value.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Null safe Boolean true test.
|
||||
*/
|
||||
|
||||
@@ -41,7 +41,7 @@ public class BaseQueryTuner {
|
||||
*/
|
||||
private final boolean skipAll;
|
||||
|
||||
public BaseQueryTuner(AutoTuneConfig config, SpiEbeanServer server, ProfilingListener profilingListener) {
|
||||
BaseQueryTuner(AutoTuneConfig config, SpiEbeanServer server, ProfilingListener profilingListener) {
|
||||
this.server = server;
|
||||
this.profilingListener = profilingListener;
|
||||
this.mode = config.getMode();
|
||||
@@ -84,12 +84,17 @@ public class BaseQueryTuner {
|
||||
/**
|
||||
* Auto tune the query and enable profiling.
|
||||
*/
|
||||
public boolean tuneQuery(SpiQuery<?> query) {
|
||||
boolean tuneQuery(SpiQuery<?> query) {
|
||||
|
||||
if (skipAll || !tunableQuery(query)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.getProfilingListener() != null) {
|
||||
// profiling secondary query
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!useTuning(query)) {
|
||||
if (profiling) {
|
||||
profiling(query, server.createCallStack());
|
||||
@@ -138,6 +143,7 @@ public class BaseQueryTuner {
|
||||
switch (type) {
|
||||
case COUNT:
|
||||
case ID_LIST:
|
||||
case UPDATE:
|
||||
case DELETE:
|
||||
case SUBQUERY:
|
||||
return false;
|
||||
|
||||
@@ -103,8 +103,7 @@ public class ProfileManager implements ProfilingListener {
|
||||
|
||||
private ProfileOrigin getProfileOrigin(ObjectGraphOrigin originQueryPoint) {
|
||||
synchronized (monitor) {
|
||||
ProfileOrigin stats = profileMap.computeIfAbsent(originQueryPoint.getKey(), k -> new ProfileOrigin(originQueryPoint, queryTuningAddVersion, profilingBase, profilingRate));
|
||||
return stats;
|
||||
return profileMap.computeIfAbsent(originQueryPoint.getKey(), k -> new ProfileOrigin(originQueryPoint, queryTuningAddVersion, profilingBase, profilingRate));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ public class ProfileOrigin {
|
||||
}
|
||||
}
|
||||
|
||||
private OrmQueryDetail buildDetail(BeanDescriptor<?> rootDesc) {
|
||||
OrmQueryDetail buildDetail(BeanDescriptor<?> rootDesc) {
|
||||
|
||||
PathProperties pathProps = new PathProperties();
|
||||
for (ProfileOriginNodeUsage statsNode : nodeUsageMap.values()) {
|
||||
@@ -107,8 +107,7 @@ public class ProfileOrigin {
|
||||
|
||||
OrmQueryDetail detail = new OrmQueryDetail();
|
||||
|
||||
Collection<Props> pathProperties = pathProps.getPathProps();
|
||||
for (Props props : pathProperties) {
|
||||
for (Props props : pathProps.getPathProps()) {
|
||||
if (!props.isEmpty()) {
|
||||
detail.fetch(props.getPath(), props.getPropertiesAsString(), null);
|
||||
}
|
||||
@@ -151,12 +150,8 @@ public class ProfileOrigin {
|
||||
* Collect the usage information for from a instance for this node.
|
||||
*/
|
||||
public void collectUsageInfo(NodeUsageCollector profile) {
|
||||
|
||||
//logger.info("COLLECT USAGE {}", profile.toString());
|
||||
|
||||
if (!profile.isEmpty()) {
|
||||
ProfileOriginNodeUsage nodeStats = getNodeStats(profile.getNode().getPath());
|
||||
nodeStats.collectUsageInfo(profile);
|
||||
getNodeStats(profile.getNode().getPath()).collectUsageInfo(profile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,23 +55,27 @@ public class ProfileOriginNodeUsage {
|
||||
}
|
||||
}
|
||||
|
||||
BeanProperty toOneIdProperty = null;
|
||||
boolean addedToPath = false;
|
||||
|
||||
for (String propName : aggregateUsed) {
|
||||
BeanProperty beanProp = desc.findPropertyFromPath(propName);
|
||||
if (beanProp == null) {
|
||||
logger.warn("AutoTune: Can't find property[" + propName + "] for " + desc.getName());
|
||||
|
||||
} else {
|
||||
if (beanProp instanceof BeanPropertyAssoc<?>) {
|
||||
BeanPropertyAssoc<?> assocProp = (BeanPropertyAssoc<?>) beanProp;
|
||||
String targetIdProp = assocProp.getTargetIdProperty();
|
||||
String manyPath = SplitName.add(path, assocProp.getName());
|
||||
pathProps.addToPath(manyPath, targetIdProp);
|
||||
if (beanProp.isId()) {
|
||||
// remember and maybe add ToOne property to parent path
|
||||
toOneIdProperty = beanProp;
|
||||
} else if (beanProp instanceof BeanPropertyAssoc<?>) {
|
||||
// intentionally skip
|
||||
} else {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (beanProp.isLob() && !beanProp.isFetchEager()) {
|
||||
// AutoTune will not include Lob's marked FetchLazy
|
||||
// (which is the default for Lob's so typical).
|
||||
} else {
|
||||
addedToPath = true;
|
||||
pathProps.addToPath(path, beanProp.getName());
|
||||
}
|
||||
}
|
||||
@@ -81,9 +85,16 @@ public class ProfileOriginNodeUsage {
|
||||
if ((modified || addVersionProperty) && desc != null) {
|
||||
BeanProperty versionProp = desc.getVersionProperty();
|
||||
if (versionProp != null) {
|
||||
addedToPath = true;
|
||||
pathProps.addToPath(path, versionProp.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (toOneIdProperty != null && !addedToPath) {
|
||||
// add ToOne property to parent path
|
||||
ElPropertyValue assocOne = rootDesc.getElGetValue(path);
|
||||
pathProps.addToPath(SplitName.parent(path), assocOne.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,15 +144,13 @@ public abstract class AbstractSqlQueryRequest {
|
||||
* Prepare and execute the SQL using the Binder.
|
||||
*/
|
||||
public void executeSql(Binder binder, SpiQuery.Type type) throws SQLException {
|
||||
startNano = System.nanoTime();
|
||||
executeAsSql(binder);
|
||||
}
|
||||
|
||||
protected void executeAsSql(Binder binder) throws SQLException {
|
||||
|
||||
startNano = System.nanoTime();
|
||||
|
||||
prepareSql();
|
||||
|
||||
Connection conn = trans.getInternalConnection();
|
||||
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class DefaultCallStackFactory implements CallStackFactory {
|
||||
|
||||
// find the first non-avaje stackElement
|
||||
for (; startIndex < stackTrace.length; startIndex++) {
|
||||
if (!stackTrace[startIndex].getClassName().startsWith(IO_EBEAN)) {
|
||||
if (!ignore(stackTrace[startIndex])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,16 @@ public class DefaultCallStackFactory implements CallStackFactory {
|
||||
return createCallStack(finalTrace);
|
||||
}
|
||||
|
||||
private boolean ignore(StackTraceElement element) {
|
||||
if (element.getClassName().startsWith(IO_EBEAN)) {
|
||||
return true;
|
||||
}
|
||||
if (element.getMethodName().startsWith("_ebean_")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private CallStack createCallStack(StackTraceElement[] finalTrace) {
|
||||
return new CallStack(finalTrace, finalTrace[0].hashCode(), pathHash(finalTrace));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -35,6 +36,11 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
server.visitMetrics(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetrics collectMetrics() {
|
||||
return visitBasic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicMetricVisitor visitBasic() {
|
||||
BasicMetricVisitor basic = new BasicMetricVisitor();
|
||||
|
||||
@@ -505,6 +505,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private void shutdownPlugins() {
|
||||
|
||||
if (serverConfig.isDumpMetricsOnShutdown()) {
|
||||
new DumpMetrics(this, serverConfig.getDumpMetricsOptions()).dump();
|
||||
}
|
||||
|
||||
for (Plugin plugin : serverPlugins) {
|
||||
try {
|
||||
plugin.shutdown();
|
||||
@@ -1234,7 +1238,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(spiQuery, t);
|
||||
request.profileLocationById();
|
||||
if (request.isUseDocStore()) {
|
||||
return docStore().find(request);
|
||||
}
|
||||
@@ -1588,7 +1591,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
private <T> List<T> findList(Query<T> query, Transaction t, boolean findOne) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
request.profileLocationAll();
|
||||
request.resetBeanCacheAutoMode(findOne);
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
|
||||
@@ -37,6 +37,7 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
super(server, query, null);
|
||||
this.queryEngine = engine;
|
||||
this.query = query;
|
||||
query.obtainLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,6 +45,7 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
*/
|
||||
@Override
|
||||
public void executeSql(Binder binder, SpiQuery.Type type) throws SQLException {
|
||||
startNano = System.nanoTime();
|
||||
SpiQuery<?> ormQuery = query.getOrmQuery();
|
||||
if (ormQuery != null) {
|
||||
ormQuery.setType(type);
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import io.ebean.meta.SortMetric;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
class DumpMetrics {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
private final String options;
|
||||
|
||||
private final String nameFormat;
|
||||
private final String nameFormatTimed;
|
||||
|
||||
private boolean dumpHash;
|
||||
private boolean dumpSql;
|
||||
private boolean dumpLoc;
|
||||
|
||||
private Comparator<MetaTimedMetric> sortBy = SortMetric.NAME;
|
||||
|
||||
DumpMetrics(SpiEbeanServer server, String options) {
|
||||
this.server = server;
|
||||
this.options = options;
|
||||
|
||||
int width = 0;
|
||||
|
||||
if (options != null) {
|
||||
dumpLoc = options.contains("loc");
|
||||
dumpSql = options.contains("sql");
|
||||
dumpHash = options.contains("hash");
|
||||
for (int i = 5; i < 10; i++) {
|
||||
width = Math.max(width, optionWidth(i * 10));
|
||||
}
|
||||
for (String option : new String[]{"Total", "Count", "Mean", "Max"}) {
|
||||
sortOption(option);
|
||||
}
|
||||
}
|
||||
if (width == 0) {
|
||||
width = 80;
|
||||
}
|
||||
|
||||
nameFormat = "%1$-" + width + "s";
|
||||
nameFormatTimed = "%1$-" + (width + 6) + "s";
|
||||
}
|
||||
|
||||
private int optionWidth(int check) {
|
||||
return options.contains("w" + check) ? check : 0;
|
||||
}
|
||||
|
||||
private void sortOption(String option) {
|
||||
if (options.contains("sort" + option)) {
|
||||
sortBy = setSortOption(option);
|
||||
}
|
||||
}
|
||||
|
||||
private Comparator<MetaTimedMetric> setSortOption(String option) {
|
||||
switch (option.toUpperCase()) {
|
||||
case "TOTAL":
|
||||
return SortMetric.TOTAL;
|
||||
case "COUNT":
|
||||
return SortMetric.COUNT;
|
||||
case "MEAN":
|
||||
return SortMetric.MEAN;
|
||||
case "MAX":
|
||||
return SortMetric.MAX;
|
||||
}
|
||||
return SortMetric.NAME;
|
||||
}
|
||||
|
||||
void dump() {
|
||||
|
||||
out("-- Dumping metrics for " + server.getName() + " -- ");
|
||||
ServerMetrics serverMetrics = server.getMetaInfoManager().collectMetrics();
|
||||
|
||||
for (MetaTimedMetric metric : serverMetrics.getTimedMetrics()) {
|
||||
log(metric);
|
||||
}
|
||||
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = serverMetrics.getOrmQueryMetrics();
|
||||
if (!ormQueryMetrics.isEmpty()) {
|
||||
out("\n-- ORM queries --");
|
||||
ormQueryMetrics.sort(sortBy);
|
||||
for (MetaOrmQueryMetric metric : ormQueryMetrics) {
|
||||
logQuery(metric);
|
||||
}
|
||||
}
|
||||
|
||||
List<MetaQueryMetric> dtoQueryMetrics = serverMetrics.getDtoQueryMetrics();
|
||||
if (!dtoQueryMetrics.isEmpty()) {
|
||||
out("\n-- DTO queries --");
|
||||
dtoQueryMetrics.sort(sortBy);
|
||||
for (MetaQueryMetric metric : dtoQueryMetrics) {
|
||||
logDtoQuery(metric);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void out(String sb) {
|
||||
System.out.println(sb);
|
||||
}
|
||||
|
||||
private void logQuery(MetaOrmQueryMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
appendQueryName(metric, sb);
|
||||
appendCounters(metric, sb);
|
||||
if (dumpHash) {
|
||||
sb.append("\n hash:").append(metric.getQueryPlanHash());
|
||||
}
|
||||
appendProfileAndSql(metric, sb);
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
|
||||
private void logDtoQuery(MetaQueryMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
appendQueryName(metric, sb);
|
||||
appendCounters(metric, sb);
|
||||
appendProfileAndSql(metric, sb);
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
private void appendQueryName(MetaQueryMetric metric, StringBuilder sb) {
|
||||
sb.append("query:").append(padName(metric.getName())).append(" ");
|
||||
}
|
||||
|
||||
private void appendProfileAndSql(MetaQueryMetric metric, StringBuilder sb) {
|
||||
ProfileLocation profileLocation = metric.getProfileLocation();
|
||||
if (dumpLoc && profileLocation != null) {
|
||||
sb.append("\n loc:").append(profileLocation.shortDescription());
|
||||
}
|
||||
|
||||
if (dumpSql) {
|
||||
sb.append(" \n\n sql:").append(metric.getSql()).append("\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void log(MetaTimedMetric metric) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(padNameTimed(metric.getName())).append(" ");
|
||||
appendCounters(metric, sb);
|
||||
out(sb.toString());
|
||||
}
|
||||
|
||||
private void appendCounters(MetaTimedMetric timedMetric, StringBuilder sb) {
|
||||
sb.append(" count:").append(pad(timedMetric.getCount()))
|
||||
.append(" total:").append(pad(timedMetric.getTotal()))
|
||||
.append(" mean:").append(pad(timedMetric.getMean()))
|
||||
.append(" max:").append(pad(timedMetric.getMax()));
|
||||
}
|
||||
|
||||
private String padName(String name) {
|
||||
return String.format(nameFormat, name);
|
||||
}
|
||||
|
||||
private String padNameTimed(String name) {
|
||||
return String.format(nameFormatTimed, name);
|
||||
}
|
||||
|
||||
private String pad(long value) {
|
||||
return String.format("%1$-8s", value);
|
||||
}
|
||||
}
|
||||
@@ -102,20 +102,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
return queryEngine.translate(this, bindLog, sql, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profileLocationById() {
|
||||
if (query.getProfileLocation() == null) {
|
||||
query.setProfileLocation(beanDescriptor.profileLocationById());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profileLocationAll() {
|
||||
if (query.getProfileLocation() == null && query.isFindAll()) {
|
||||
query.setProfileLocation(beanDescriptor.profileLocationAll());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeleteByStatement() {
|
||||
if (!transaction.isPersistCascade() || beanDescriptor.isDeleteByStatement()) {
|
||||
|
||||
@@ -607,11 +607,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
transaction.registerDeleteBean(hash);
|
||||
}
|
||||
|
||||
public void unregisterDeleteBean() {
|
||||
Integer hash = getBeanHash();
|
||||
transaction.unregisterDeleteBean(hash);
|
||||
}
|
||||
|
||||
public boolean isRegisteredForDeleteBean() {
|
||||
if (transaction == null) {
|
||||
return false;
|
||||
|
||||
@@ -162,16 +162,6 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
|
||||
*/
|
||||
boolean isUseDocStore();
|
||||
|
||||
/**
|
||||
* Set profile location for "find by id" if not set.
|
||||
*/
|
||||
void profileLocationById();
|
||||
|
||||
/**
|
||||
* Set profile location for "find all" if not set.
|
||||
*/
|
||||
void profileLocationAll();
|
||||
|
||||
/**
|
||||
* Return true if delete by statement is allowed for this type given cascade rules etc.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.Transaction;
|
||||
@@ -136,8 +135,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
private final Map<String, String> namedQuery;
|
||||
|
||||
private final short profileBeanId;
|
||||
private final ProfileLocation locationById;
|
||||
private final ProfileLocation locationAll;
|
||||
|
||||
private final boolean multiValueSupported;
|
||||
|
||||
@@ -448,8 +445,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
this.name = InternString.intern(deploy.getName());
|
||||
this.baseTableAlias = "t0";
|
||||
this.fullName = InternString.intern(deploy.getFullName());
|
||||
this.locationById = ProfileLocation.createAt(fullName + ".byId");
|
||||
this.locationAll = ProfileLocation.createAt(fullName + ".all");
|
||||
this.profileBeanId = deploy.getProfileId();
|
||||
this.beanType = deploy.getBeanType();
|
||||
this.rootBeanType = PersistenceContextUtil.root(beanType);
|
||||
@@ -582,20 +577,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a location for "find by id".
|
||||
*/
|
||||
public ProfileLocation profileLocationById() {
|
||||
return locationById;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a location for "find all".
|
||||
*/
|
||||
public ProfileLocation profileLocationAll() {
|
||||
return locationAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id used in profiling to identify the bean type.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import io.ebean.metric.QueryPlanMetric;
|
||||
@@ -14,6 +15,8 @@ public class DtoMappingRequest {
|
||||
|
||||
private final String label;
|
||||
|
||||
private final ProfileLocation profileLocation;
|
||||
|
||||
private final String sql;
|
||||
|
||||
private final boolean relaxedMode;
|
||||
@@ -22,7 +25,8 @@ public class DtoMappingRequest {
|
||||
|
||||
public DtoMappingRequest(SpiDtoQuery query, String sql, DtoColumn[] columnMeta) {
|
||||
this.type = query.getType();
|
||||
this.label = query.getLabel();
|
||||
this.label = query.getPlanLabel();
|
||||
this.profileLocation = query.getProfileLocation();
|
||||
this.sql = sql;
|
||||
this.relaxedMode = query.isRelaxedMode();
|
||||
this.columnMeta = columnMeta;
|
||||
@@ -45,6 +49,6 @@ public class DtoMappingRequest {
|
||||
}
|
||||
|
||||
public QueryPlanMetric createMetric() {
|
||||
return MetricFactory.get().createQueryPlanMetric(MetricType.DTO, type, label, sql);
|
||||
return MetricFactory.get().createQueryPlanMetric(MetricType.DTO, type, label, profileLocation, sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.ebeaninternal.api.LoadSecondaryQuery;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiQuerySecondary;
|
||||
import io.ebeaninternal.server.autotune.ProfilingListener;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -55,9 +56,9 @@ public class DLoadContext implements LoadContext {
|
||||
*/
|
||||
private final String relativePath;
|
||||
private final ObjectGraphOrigin origin;
|
||||
private final boolean useProfiling;
|
||||
private final String planLabel;
|
||||
private final ProfileLocation profileLocation;
|
||||
private final ProfilingListener profilingListener;
|
||||
|
||||
private final Map<String, ObjectGraphNode> nodePathMap = new HashMap<>();
|
||||
|
||||
@@ -88,7 +89,7 @@ public class DLoadContext implements LoadContext {
|
||||
this.relativePath = null;
|
||||
this.planLabel = null;
|
||||
this.profileLocation = null;
|
||||
this.useProfiling = false;
|
||||
this.profilingListener = null;
|
||||
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null);
|
||||
}
|
||||
|
||||
@@ -114,7 +115,7 @@ public class DLoadContext implements LoadContext {
|
||||
this.disableReadAudit = query.isDisableReadAudit();
|
||||
this.disableLazyLoading = query.isDisableLazyLoading();
|
||||
this.useBeanCache = query.getUseBeanCache();
|
||||
this.useProfiling = query.getProfilingListener() != null;
|
||||
this.profilingListener = query.getProfilingListener();
|
||||
this.planLabel = query.getPlanLabel();
|
||||
this.profileLocation = query.getProfileLocation();
|
||||
|
||||
@@ -368,8 +369,8 @@ public class DLoadContext implements LoadContext {
|
||||
if (disableReadAudit) {
|
||||
query.setDisableReadAuditing();
|
||||
}
|
||||
if (useProfiling) {
|
||||
query.setAutoTune(true);
|
||||
if (profilingListener != null) {
|
||||
query.setProfilingListener(profilingListener);
|
||||
}
|
||||
if (tenantId != null) {
|
||||
query.setTenantId(tenantId);
|
||||
|
||||
@@ -882,7 +882,6 @@ public final class DefaultPersister implements Persister {
|
||||
// bean to handle bi-directional cascading
|
||||
request.registerDeleteBean();
|
||||
deleteAssocMany(request);
|
||||
request.unregisterDeleteBean();
|
||||
|
||||
unloadedForeignKeys = getDeleteUnloadedForeignKeys(request);
|
||||
if (unloadedForeignKeys != null) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import io.ebean.metric.QueryPlanMetric;
|
||||
@@ -22,8 +23,8 @@ public class DMetricFactory implements MetricFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, String sql) {
|
||||
return new DQueryPlanMetric(new DQueryPlanMeta(type, label, sql), new DTimedMetric(metricType, label));
|
||||
public QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, ProfileLocation profileLocation, String sql) {
|
||||
return new DQueryPlanMetric(new DQueryPlanMeta(type, label, profileLocation, sql), new DTimedMetric(metricType, label));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,11 +42,12 @@ class DProfileLocation implements ProfileLocation {
|
||||
|
||||
@Override
|
||||
public String obtain() {
|
||||
// atomic assignment so happy with this
|
||||
// atomic assignments so happy enough with this (racing but atomic)
|
||||
if (location == null) {
|
||||
final String loc = create();
|
||||
shortDescription = shortDesc(loc);
|
||||
label = UtilLocation.label(shortDescription);
|
||||
final String shortDesc = shortDesc(loc);
|
||||
label = UtilLocation.label(shortDesc);
|
||||
shortDescription = shortDesc;
|
||||
location = loc;
|
||||
}
|
||||
return location;
|
||||
@@ -63,6 +64,7 @@ class DProfileLocation implements ProfileLocation {
|
||||
}
|
||||
|
||||
private String create() {
|
||||
// relatively expensive but we only do it once per profile location
|
||||
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
for (int i = 3; i < trace.length; i++) {
|
||||
if (!trace[i].getClassName().startsWith(IO_EBEAN)) {
|
||||
|
||||
@@ -1,25 +1,43 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
class DQueryPlanMeta {
|
||||
|
||||
private final Class<?> type;
|
||||
private final String label;
|
||||
private final ProfileLocation profileLocation;
|
||||
private final String name;
|
||||
private final String sql;
|
||||
|
||||
DQueryPlanMeta(Class<?> type, String label, String sql) {
|
||||
DQueryPlanMeta(Class<?> type, String label, ProfileLocation profileLocation, String sql) {
|
||||
this.type = type;
|
||||
this.label = label;
|
||||
this.profileLocation = profileLocation;
|
||||
this.sql = sql;
|
||||
String name = type.getSimpleName();
|
||||
if (label != null) {
|
||||
name += "_" + label;
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return profileLocation;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
@@ -60,6 +61,11 @@ class DQueryPlanMetric implements QueryPlanMetric {
|
||||
return meta.getLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return meta.getProfileLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSql() {
|
||||
return meta.getSql();
|
||||
@@ -67,7 +73,7 @@ class DQueryPlanMetric implements QueryPlanMetric {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return stats.getName();
|
||||
return meta.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,8 +7,19 @@ final class UtilLocation {
|
||||
if (pos == -1) {
|
||||
return shortDescription;
|
||||
} else {
|
||||
return shortDescription.substring(0, pos);
|
||||
return trimInit(shortDescription.substring(0, pos));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim constructor init to be "safe" without greater than or less than chars.
|
||||
*/
|
||||
private static String trimInit(String desc) {
|
||||
if (desc.endsWith("<init>")) {
|
||||
// trim to make a safe label
|
||||
return desc.substring(0, desc.length() - 6) + "init";
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -135,14 +135,22 @@ class CQueryBuilder {
|
||||
|
||||
private <T> String buildDeleteSql(OrmQueryRequest<T> request, String rootTableAlias, CQueryPredicates predicates, SqlTree sqlTree) {
|
||||
|
||||
String alias = alias(rootTableAlias);
|
||||
if (!sqlTree.isIncludeJoins()) {
|
||||
// simple - delete from table ...
|
||||
return aliasStrip(buildSql("delete", request, predicates, sqlTree).getSql());
|
||||
if (dbPlatform.isSupportsDeleteTableAlias()) {
|
||||
// delete from table <alias> ...
|
||||
return aliasReplace(buildSql("delete", request, predicates, sqlTree).getSql(), alias);
|
||||
} else if (dbPlatform.getPlatform() == Platform.MYSQL) {
|
||||
return aliasReplace(buildSql("delete " + alias, request, predicates, sqlTree).getSql(), alias);
|
||||
} else {
|
||||
// simple - delete from table ...
|
||||
return aliasStrip(buildSql("delete", request, predicates, sqlTree).getSql());
|
||||
}
|
||||
}
|
||||
// wrap as - delete from table where id in (select id ...)
|
||||
String sql = buildSql(null, request, predicates, sqlTree).getSql();
|
||||
sql = request.getBeanDescriptor().getDeleteByIdInSql() + "in (" + sql + ")";
|
||||
sql = aliasReplace(sql, alias(rootTableAlias));
|
||||
sql = aliasReplace(sql, alias);
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -425,7 +433,7 @@ class CQueryBuilder {
|
||||
try {
|
||||
// For SqlServer we need either "selectMethod=cursor" in the connection string or fetch explicitly a cursorable
|
||||
// statement here by specifying ResultSet.CONCUR_UPDATABLE
|
||||
PreparedStatement statement = connection.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, dbPlatform.isSupportsResultSetConcurrencyModeUpdatable() ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY);
|
||||
PreparedStatement statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, dbPlatform.isSupportsResultSetConcurrencyModeUpdatable() ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY);
|
||||
predicates.bind(statement, connection);
|
||||
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
@@ -702,21 +710,21 @@ class CQueryBuilder {
|
||||
}
|
||||
|
||||
private String toSql(CountDistinctOrder orderBy) {
|
||||
switch(orderBy) {
|
||||
case ATTR_ASC:
|
||||
return " order by r1.attribute_";
|
||||
case ATTR_DESC:
|
||||
return " order by r1.attribute_ desc";
|
||||
case COUNT_ASC_ATTR_ASC:
|
||||
return " order by count(*), r1.attribute_";
|
||||
case COUNT_ASC_ATTR_DESC:
|
||||
return " order by count(*), r1.attribute_ desc";
|
||||
case COUNT_DESC_ATTR_ASC:
|
||||
return " order by count(*) desc, r1.attribute_";
|
||||
case COUNT_DESC_ATTR_DESC:
|
||||
return " order by count(*) desc, r1.attribute_ desc";
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal enum: "+ orderBy);
|
||||
switch (orderBy) {
|
||||
case ATTR_ASC:
|
||||
return " order by r1.attribute_";
|
||||
case ATTR_DESC:
|
||||
return " order by r1.attribute_ desc";
|
||||
case COUNT_ASC_ATTR_ASC:
|
||||
return " order by count(*), r1.attribute_";
|
||||
case COUNT_ASC_ATTR_DESC:
|
||||
return " order by count(*), r1.attribute_ desc";
|
||||
case COUNT_DESC_ATTR_ASC:
|
||||
return " order by count(*) desc, r1.attribute_";
|
||||
case COUNT_DESC_ATTR_DESC:
|
||||
return " order by count(*) desc, r1.attribute_ desc";
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal enum: " + orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ public class CQueryPlan {
|
||||
|
||||
private final String label;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final CQueryPlanKey planKey;
|
||||
|
||||
private final boolean rawSql;
|
||||
@@ -112,6 +114,7 @@ public class CQueryPlan {
|
||||
SpiQuery<?> query = request.getQuery();
|
||||
this.profileLocation = query.getProfileLocation();
|
||||
this.label = query.getPlanLabel();
|
||||
this.name = deriveName(label, query.getType());
|
||||
this.location = location();
|
||||
this.autoTuned = query.isAutoTuned();
|
||||
this.asOfTableCount = query.getAsOfTableCount();
|
||||
@@ -138,6 +141,7 @@ public class CQueryPlan {
|
||||
SpiQuery<?> query = request.getQuery();
|
||||
this.profileLocation = query.getProfileLocation();
|
||||
this.label = query.getPlanLabel();
|
||||
this.name = deriveName(label, query.getType());
|
||||
this.location = location();
|
||||
this.planKey = buildPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
|
||||
this.autoTuned = false;
|
||||
@@ -154,6 +158,16 @@ public class CQueryPlan {
|
||||
this.bindCapture = initBindCapture(server.getServerConfig(), query);
|
||||
}
|
||||
|
||||
private String deriveName(String label, SpiQuery.Type type) {
|
||||
if (label == null) {
|
||||
return beanType.getSimpleName() + "." + type.label();
|
||||
}
|
||||
if (label.startsWith(beanType.getSimpleName())) {
|
||||
return label;
|
||||
}
|
||||
return beanType.getSimpleName() + "_" + label;
|
||||
}
|
||||
|
||||
private CQueryBindCapture initBindCapture(ServerConfig serverConfig, SpiQuery<?> query) {
|
||||
if (serverConfig.isCollectQueryPlans() && !query.getType().isUpdate()) {
|
||||
return new CQueryBindCapture(this, PlatformQueryPlan.getLogger(serverConfig.getDatabasePlatform().getPlatform()));
|
||||
@@ -192,6 +206,10 @@ public class CQueryPlan {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ public final class CQueryPlanStats {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return queryPlan.getLabel();
|
||||
return queryPlan.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,7 +26,7 @@ public abstract class QueryPlanLogger {
|
||||
}
|
||||
|
||||
protected DQueryPlanOutput createPlan(CQueryPlan plan, String bind, String planString) {
|
||||
return new DQueryPlanOutput(plan.getBeanType(), plan.getLabel(), plan.getSql(), bind, planString);
|
||||
return new DQueryPlanOutput(plan.getBeanType(), plan.getName(), plan.getSql(), bind, planString);
|
||||
}
|
||||
|
||||
DQueryPlanOutput readQueryPlanBasic(CQueryPlan plan, BindCapture bind, ResultSet rset) throws SQLException {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.querydefn;
|
||||
|
||||
import io.ebean.DtoQuery;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.api.SpiDtoQuery;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -39,6 +40,8 @@ public class DefaultDtoQuery<T> implements SpiDtoQuery<T> {
|
||||
|
||||
private String label;
|
||||
|
||||
private ProfileLocation profileLocation;
|
||||
|
||||
/**
|
||||
* Bind parameters when using the query language.
|
||||
*/
|
||||
@@ -52,6 +55,7 @@ public class DefaultDtoQuery<T> implements SpiDtoQuery<T> {
|
||||
this.descriptor = descriptor;
|
||||
this.ormQuery = ormQuery;
|
||||
this.label = ormQuery.getLabel();
|
||||
this.profileLocation = ormQuery.getProfileLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,6 +170,35 @@ public class DefaultDtoQuery<T> implements SpiDtoQuery<T> {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlanLabel() {
|
||||
if (label != null) {
|
||||
return label;
|
||||
}
|
||||
if (profileLocation != null) {
|
||||
return profileLocation.label();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void obtainLocation() {
|
||||
if (profileLocation != null) {
|
||||
profileLocation.obtain();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DtoQuery<T> setProfileLocation(ProfileLocation profileLocation) {
|
||||
this.profileLocation = profileLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileLocation getProfileLocation() {
|
||||
return profileLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstRow() {
|
||||
return firstRow;
|
||||
|
||||
@@ -121,7 +121,10 @@ public class OrmQueryDetail implements Serializable {
|
||||
}
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties join : fetchPaths.values()) {
|
||||
join.append(" fetch ", sb);
|
||||
if (sb.length() > 0) {
|
||||
sb.append(" ");
|
||||
}
|
||||
join.append("fetch ", sb);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -294,7 +294,7 @@ public class OrmQueryProperties implements Serializable {
|
||||
sb.append(path).append(" ");
|
||||
}
|
||||
if (!isEmpty()) {
|
||||
sb.append("(").append(rawProperties).append(") ");
|
||||
sb.append("(").append(rawProperties).append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -194,11 +194,6 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
|
||||
throw new IllegalStateException(notExpectedMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDeleteBean(Integer persistedBean) {
|
||||
throw new IllegalStateException(notExpectedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
|
||||
@@ -436,16 +436,6 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
deletingBeansHash.add(persistingBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
@Override
|
||||
public void unregisterDeleteBean(Integer persistedBean) {
|
||||
if (deletingBeansHash != null) {
|
||||
deletingBeansHash.remove(persistedBean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
|
||||
@@ -123,11 +123,6 @@ class NoTransaction implements SpiTransaction {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDeleteBean(Integer hash) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegisteredDeleteBean(Integer hash) {
|
||||
return false;
|
||||
|
||||
@@ -2,9 +2,9 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
@@ -64,12 +64,12 @@ public abstract class BaseTestCase {
|
||||
server().getMetaInfoManager().resetAllMetrics();
|
||||
}
|
||||
|
||||
protected BasicMetricVisitor visitMetricsBasic() {
|
||||
return server().getMetaInfoManager().visitBasic();
|
||||
protected ServerMetrics collectMetrics() {
|
||||
return server().getMetaInfoManager().collectMetrics();
|
||||
}
|
||||
|
||||
protected List<MetaTimedMetric> visitTimedMetrics() {
|
||||
return visitMetricsBasic().getTimedMetrics();
|
||||
return collectMetrics().getTimedMetrics();
|
||||
}
|
||||
|
||||
protected List<MetaTimedMetric> sqlMetrics() {
|
||||
@@ -170,6 +170,10 @@ public abstract class BaseTestCase {
|
||||
return isH2() || isPostgres();
|
||||
}
|
||||
|
||||
public boolean isPlatformSupportsDeleteTableAlias() {
|
||||
return spiEbeanServer().getDatabasePlatform().isSupportsDeleteTableAlias();
|
||||
}
|
||||
|
||||
public boolean isPersistBatchOnCascade() {
|
||||
return spiEbeanServer().getDatabasePlatform().getPersistBatchOnCascade() != PersistBatch.NONE;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Contact;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
@@ -19,23 +20,25 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
@BeforeClass
|
||||
public static void resetStats() {
|
||||
Ebean.getDefaultServer().getMetaInfoManager().resetAllMetrics();
|
||||
DB.getDefault().getMetaInfoManager().resetAllMetrics();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void reportStats() {
|
||||
BasicMetricVisitor basic = DB.getDefault().getMetaInfoManager().visitBasic();
|
||||
for (MetaQueryMetric metric : basic.getDtoQueryMetrics()) {
|
||||
ServerMetrics metrics = DB.getDefault().getMetaInfoManager().collectMetrics();
|
||||
for (MetaQueryMetric metric : metrics.getDtoQueryMetrics()) {
|
||||
System.out.println(metric);
|
||||
}
|
||||
|
||||
System.out.println("-- transaction metrics --");
|
||||
for (MetaTimedMetric metric : basic.getTimedMetrics()) {
|
||||
for (MetaTimedMetric metric : metrics.getTimedMetrics()) {
|
||||
System.out.println(metric);
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore
|
||||
private static final ProfileLocation loc0 = ProfileLocation.create();
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@Test
|
||||
public void testPlanHits() {
|
||||
|
||||
@@ -43,27 +46,27 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
resetAllMetrics();
|
||||
|
||||
String[] prefix = { "Bl", "B", "Red", "jim" };
|
||||
String[] prefix = {"Bl", "B", "Red", "jim"};
|
||||
|
||||
for (String val : prefix) {
|
||||
List<ContactDto> list = Ebean.find(Contact.class)
|
||||
.select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where()
|
||||
.istartsWith(concat("lastName", ", ", "firstName"), val).orderBy().asc("lastName").setMaxRows(10)
|
||||
.asDto(ContactDto.class).setLabel("prefixLoop").findList();
|
||||
|
||||
System.out.println("List:" + list);
|
||||
DB.find(Contact.class)
|
||||
.setProfileLocation(loc0)
|
||||
.select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where()
|
||||
.istartsWith(concat("lastName", ", ", "firstName"), val).orderBy().asc("lastName").setMaxRows(10)
|
||||
.asDto(ContactDto.class).setLabel("prefixLoop").findList();
|
||||
}
|
||||
|
||||
BasicMetricVisitor basic = visitMetricsBasic();
|
||||
ServerMetrics metrics = collectMetrics();
|
||||
|
||||
List<MetaQueryMetric> stats = basic.getDtoQueryMetrics();
|
||||
List<MetaQueryMetric> stats = metrics.getDtoQueryMetrics();
|
||||
for (MetaQueryMetric stat : stats) {
|
||||
System.out.println(stat);
|
||||
long meanMicros = stat.getMean();
|
||||
assertThat(meanMicros).isLessThan(900_000);
|
||||
assertThat(stat.getProfileLocation()).isSameAs(loc0);
|
||||
}
|
||||
|
||||
assertThat(stats).hasSize(1);
|
||||
assertThat(stats.get(0).getCount()).isEqualTo(3);
|
||||
|
||||
assertThat(stats.get(0).getCount()).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -73,11 +76,11 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
DtoQuery<ContactDto> query = Ebean.find(Contact.class)
|
||||
// we must explicitly add the id property for DTO query (if we want it)
|
||||
.select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class).setLabel("explicitId")
|
||||
.setRelaxedMode();
|
||||
DtoQuery<ContactDto> query = DB.find(Contact.class)
|
||||
// we must explicitly add the id property for DTO query (if we want it)
|
||||
.select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class).setLabel("explicitId")
|
||||
.setRelaxedMode();
|
||||
|
||||
List<ContactDto> dtos = query.findList();
|
||||
|
||||
@@ -86,12 +89,11 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
for (ContactDto dto : dtos) {
|
||||
assertThat(dto.getEmail()).isNotNull();
|
||||
assertThat(dto.getFullName()).isNotNull();
|
||||
System.out.println(dto);
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name")
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,9 +103,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
DtoQuery<ContactDto> query = Ebean.find(Contact.class)
|
||||
.select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class);
|
||||
DtoQuery<ContactDto> query = DB.find(Contact.class)
|
||||
.select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class);
|
||||
|
||||
List<ContactDto> dtos = query.findList();
|
||||
|
||||
@@ -112,12 +114,11 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
for (ContactDto dto : dtos) {
|
||||
assertThat(dto.getEmail()).isNotNull();
|
||||
assertThat(dto.getFullName()).isNotNull();
|
||||
System.out.println(dto);
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("select t0.email, " + concat("t0.last_name", ", ", "t0.first_name")
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -127,27 +128,26 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<ContactDto> contactDtos = Ebean.find(Contact.class).setLabel("emailFullName")
|
||||
.select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList();
|
||||
List<ContactDto> contactDtos = DB.find(Contact.class).setLabel("emailFullName")
|
||||
.select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList();
|
||||
|
||||
assertThat(contactDtos).isNotEmpty();
|
||||
|
||||
for (ContactDto dto : contactDtos) {
|
||||
assertThat(dto.getEmail()).isNotNull();
|
||||
assertThat(dto.getFullName()).isNotNull();
|
||||
System.out.println(dto);
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
if (isSqlServer()) {
|
||||
assertThat(sql.get(0)).contains("select top 10 t0.email, " + concat("t0.last_name", ", ", "t0.first_name")
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("select t0.email, " + concat("t0.last_name", ", ", "t0.first_name")
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,14 +158,13 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<ContactDto> contactDtos = Ebean.find(Contact.class)
|
||||
.select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList();
|
||||
List<ContactDto> contactDtos = DB.find(Contact.class)
|
||||
.select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
|
||||
.isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList();
|
||||
|
||||
assertThat(contactDtos).isNotEmpty();
|
||||
|
||||
for (ContactDto dto : contactDtos) {
|
||||
System.out.println(dto);
|
||||
assertThat(dto.getId()).isNotNull();
|
||||
assertThat(dto.getFullName()).isNotNull();
|
||||
assertThat(dto.getEmail()).isNotNull();
|
||||
@@ -174,11 +173,11 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
if (isSqlServer()) {
|
||||
assertThat(sql.get(0)).contains("select top 10 t0.id, t0.email, "
|
||||
+ concat("t0.last_name", ", ", "t0.first_name")
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
+ concat("t0.last_name", ", ", "t0.first_name")
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name")
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,22 +188,20 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<ContactDto> contactDtos = Ebean.find(Contact.class)
|
||||
.select(concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("lastName").orderBy()
|
||||
.asc("lastName").asDto(ContactDto.class).setFirstRow(2).setMaxRows(5).findList();
|
||||
List<ContactDto> contactDtos = DB.find(Contact.class)
|
||||
.select(concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("lastName").orderBy()
|
||||
.asc("lastName").asDto(ContactDto.class).setFirstRow(2).setMaxRows(5).findList();
|
||||
|
||||
assertThat(contactDtos).isNotEmpty();
|
||||
|
||||
for (ContactDto dto : contactDtos) {
|
||||
System.out.println(dto);
|
||||
assertThat(dto.getFullName()).isNotNull();
|
||||
assertThat(dto.getId()).isNull();
|
||||
assertThat(dto.getEmail()).isNull();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0))
|
||||
.contains("select " + concat("t0.last_name", ", ", "t0.first_name") + " fullName from contact t0 where");
|
||||
assertThat(sql.get(0)).contains("select " + concat("t0.last_name", ", ", "t0.first_name") + " fullName from contact t0 where");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -214,9 +211,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<ContactTotals> contactDtos = Ebean.find(Contact.class).select("lastName, count(*) as totalCount").where()
|
||||
.isNotNull("lastName").having().gt("count(*)", 1).orderBy().desc("count(*)").asDto(ContactTotals.class)
|
||||
.findList();
|
||||
List<ContactTotals> contactDtos = DB.find(Contact.class).select("lastName, count(*) as totalCount").where()
|
||||
.isNotNull("lastName").having().gt("count(*)", 1).orderBy().desc("count(*)").asDto(ContactTotals.class)
|
||||
.findList();
|
||||
|
||||
assertThat(contactDtos).isNotEmpty();
|
||||
|
||||
@@ -226,8 +223,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains(
|
||||
"select t0.last_name, count(*) totalCount from contact t0 where t0.last_name is not null group by t0.last_name having count(*) > ?");
|
||||
assertThat(sql.get(0)).contains("select t0.last_name, count(*) totalCount from contact t0 where t0.last_name is not null group by t0.last_name having count(*) > ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -235,8 +231,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
List<ContactTotals> contactDtos = Ebean.find(Contact.class).select("lastName, count(*) as totalCount").where()
|
||||
.isNotNull("lastName").asDto(ContactTotals.class).findList();
|
||||
List<ContactTotals> contactDtos = DB.find(Contact.class).select("lastName, count(*) as totalCount").where()
|
||||
.isNotNull("lastName").asDto(ContactTotals.class).findList();
|
||||
|
||||
assertThat(contactDtos).isNotEmpty();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaQueryMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
@@ -24,6 +25,7 @@ public class DtoQueryTest extends BaseTestCase {
|
||||
public void dto_findList_constructorMatch() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
resetAllMetrics();
|
||||
|
||||
DtoQuery<DCust> dtoQuery = server().findDto(DCust.class, "select id, name from o_customer");
|
||||
|
||||
@@ -31,6 +33,17 @@ public class DtoQueryTest extends BaseTestCase {
|
||||
|
||||
log.info(list.toString());
|
||||
assertThat(list).isNotEmpty();
|
||||
|
||||
ServerMetrics metrics = collectMetrics();
|
||||
|
||||
List<MetaQueryMetric> stats = metrics.getDtoQueryMetrics();
|
||||
for (MetaQueryMetric stat : stats) {
|
||||
long meanMicros = stat.getMean();
|
||||
assertThat(meanMicros).isLessThan(900_000);
|
||||
}
|
||||
|
||||
assertThat(stats).hasSize(1);
|
||||
assertThat(stats.get(0).getCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -188,7 +201,7 @@ public class DtoQueryTest extends BaseTestCase {
|
||||
MetaQueryMetric queryMetric = stats.get(0);
|
||||
assertThat(queryMetric.getLabel()).isEqualTo("basic");
|
||||
assertThat(queryMetric.getCount()).isEqualTo(3);
|
||||
assertThat(queryMetric.getName()).isEqualTo("basic");
|
||||
assertThat(queryMetric.getName()).isEqualTo("DCust_basic");
|
||||
|
||||
|
||||
server().findDto(DCust.class, "select c4.id, c4.name from o_customer c4 where lower(c4.name) = :name")
|
||||
@@ -196,7 +209,7 @@ public class DtoQueryTest extends BaseTestCase {
|
||||
.setParameter("name", "rob")
|
||||
.findList();
|
||||
|
||||
BasicMetricVisitor metric2 = server().getMetaInfoManager().visitBasic();
|
||||
ServerMetrics metric2 = server().getMetaInfoManager().collectMetrics();
|
||||
|
||||
stats = metric2.getDtoQueryMetrics();
|
||||
assertThat(stats).hasSize(2);
|
||||
|
||||
@@ -127,7 +127,7 @@ public class NamedDtoQueryTest extends BaseTestCase {
|
||||
MetaQueryMetric queryMetric = stats.get(0);
|
||||
assertThat(queryMetric.getLabel()).isEqualTo("basic");
|
||||
assertThat(queryMetric.getCount()).isEqualTo(3);
|
||||
assertThat(queryMetric.getName()).isEqualTo("basic");
|
||||
assertThat(queryMetric.getName()).isEqualTo("DCust_basic");
|
||||
|
||||
|
||||
server().createNamedDtoQuery(DCust.class, "findByName_c4")
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.IgnorePlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Country;
|
||||
@@ -38,8 +38,8 @@ public class UpdateQueryTest extends BaseTestCase {
|
||||
|
||||
assertThat(query.getGeneratedSql()).contains("update o_customer set status=?, updtime=? where status = ? and id > ?");
|
||||
|
||||
BasicMetricVisitor basic = visitMetricsBasic();
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = basic.getOrmQueryMetrics();
|
||||
ServerMetrics metrics = collectMetrics();
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = metrics.getOrmQueryMetrics();
|
||||
assertThat(ormQueryMetrics).hasSize(1);
|
||||
assertThat(ormQueryMetrics.get(0).getType()).isEqualTo(Customer.class);
|
||||
assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateActive");
|
||||
@@ -68,8 +68,8 @@ public class UpdateQueryTest extends BaseTestCase {
|
||||
|
||||
assertThat(sql.get(0)).contains("update o_customer set status = status");
|
||||
|
||||
BasicMetricVisitor basic = visitMetricsBasic();
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = basic.getOrmQueryMetrics();
|
||||
ServerMetrics metrics = collectMetrics();
|
||||
List<MetaOrmQueryMetric> ormQueryMetrics = metrics.getOrmQueryMetrics();
|
||||
assertThat(ormQueryMetrics).hasSize(1);
|
||||
assertThat(ormQueryMetrics.get(0).getType()).isEqualTo(Customer.class);
|
||||
assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateAll");
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package io.ebeaninternal.server.autotune.service;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.bean.NodeUsageCollector;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.ObjectGraphOrigin;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
|
||||
private BeanDescriptor<Order> desc = getBeanDescriptor(Order.class);
|
||||
|
||||
@Test
|
||||
public void buildDetail() {
|
||||
|
||||
NodeUsageCollector c = node("customer");
|
||||
c.addUsed("id");
|
||||
c.addUsed("name");
|
||||
|
||||
ProfileOrigin po = new ProfileOrigin(null, false, 1, 1);
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString().trim()).isEqualTo("fetch customer (name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildDetail_selectFetch() {
|
||||
|
||||
NodeUsageCollector c = node("customer");
|
||||
c.addUsed("id");
|
||||
c.addUsed("name");
|
||||
|
||||
ProfileOrigin po = new ProfileOrigin(null, false, 1, 1);
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
c = node(null);
|
||||
c.addUsed("orderDate");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildDetail_expect_mergeFetchToSelect() {
|
||||
|
||||
NodeUsageCollector c = node("customer");
|
||||
c.addUsed("id");
|
||||
|
||||
ProfileOrigin po = new ProfileOrigin(null, false, 1, 1);
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
c = node(null);
|
||||
c.addUsed("orderDate");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString().trim()).isEqualTo("select (orderDate,customer)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildDetail_expect_mergeFetchToParentFetch() {
|
||||
|
||||
ProfileOrigin po = new ProfileOrigin(null, false, 1, 1);
|
||||
|
||||
NodeUsageCollector c = node(null);
|
||||
c.addUsed("orderDate");
|
||||
c.addUsed("customer");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
c = node("customer");
|
||||
c.addUsed("billingAddress");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
c = node("customer.billingAddress");
|
||||
c.addUsed("id");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (billingAddress)");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void buildDetail_expect_mergeMulit() {
|
||||
|
||||
ProfileOrigin po = new ProfileOrigin(null, false, 1, 1);
|
||||
|
||||
//fetch details (id,orderQty,shipQty,unitPrice)
|
||||
|
||||
NodeUsageCollector c = node(null);
|
||||
c.addUsed("details");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
c = node("details");
|
||||
c.addUsed("id");
|
||||
c.addUsed("orderQty");
|
||||
c.addUsed("shipQty");
|
||||
c.addUsed("unitPrice");
|
||||
c.addUsed("product");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
//fetch details.product (id,name)
|
||||
c = node("details.product");
|
||||
c.addUsed("id");
|
||||
c.addUsed("name");
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
assertThat(detail.asString()).isEqualTo("fetch details (orderQty,shipQty,unitPrice) fetch details.product (name)");
|
||||
}
|
||||
|
||||
private NodeUsageCollector node(String path) {
|
||||
ObjectGraphNode node = new ObjectGraphNode((ObjectGraphOrigin)null, path);
|
||||
return new NodeUsageCollector(node, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueries() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
//DB.createQuery(Order.class, "select (orderDate) fetch customer (billingAddress)").findList();
|
||||
|
||||
// we prefer this first query other the second one
|
||||
DB.createQuery(Order.class, "select (orderDate,customer)").findList();
|
||||
DB.createQuery(Order.class, "select (orderDate) fetch customer (id)").findList();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,14 @@ package io.ebeaninternal.server.expression;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Contact;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.nofk.EUserNoFk;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -26,6 +30,29 @@ public class IsEmptyExpressionQueryTest extends BaseTestCase {
|
||||
assertThat(sqlOf(query)).contains("select t0.id from o_customer t0 where not exists (select 1 from contact x where x.customer_id = t0.id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteQuery_isEmpty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(EUserNoFk.class)
|
||||
.where().isEmpty("files")
|
||||
.delete();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
|
||||
if (isPlatformSupportsDeleteTableAlias()) {
|
||||
assertThat(sql.get(0)).contains("delete from euser_no_fk t0 where not exists (select 1 from efile_no_fk x where x.owner_user_id = t0.user_id)");
|
||||
} else if (isMySql()) {
|
||||
assertThat(sql.get(0)).contains("delete t0 from euser_no_fk t0 where not exists (select 1 from efile_no_fk x where x.owner_user_id = t0.user_id)");
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("delete from euser_no_fk where not exists (select 1 from efile_no_fk x where x.owner_user_id = user_id)");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotEmpty() {
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.SortMetric;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SortMetricTest {
|
||||
|
||||
private Comparator<MetaTimedMetric> sortMetric = SortMetric.NAME;
|
||||
|
||||
@Test
|
||||
public void compare_list() {
|
||||
|
||||
List<DTimeMetricStats> list = new ArrayList<>();
|
||||
list.add(create("d"));
|
||||
list.add(create("b"));
|
||||
list.add(create("c"));
|
||||
list.add(create(null));
|
||||
list.add(create("a"));
|
||||
list.sort(sortMetric);
|
||||
|
||||
String names = list.stream().map(DTimeMetricStats::getName).collect(Collectors.joining());
|
||||
|
||||
assertEquals("nullabcd", names);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compare_when_same() {
|
||||
|
||||
assertEquals(0, sortMetric.compare(create("foo"), create("foo")));
|
||||
assertEquals(0, sortMetric.compare(create(null), create(null)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compare_when_less() {
|
||||
|
||||
assertEquals(-1, sortMetric.compare(create("a"), create("b")));
|
||||
assertEquals(-1, sortMetric.compare(create("foo"), create("goo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compare_when_more() {
|
||||
|
||||
assertEquals(1, sortMetric.compare(create("b"), create("a")));
|
||||
assertEquals(1, sortMetric.compare(create("goo"), create("foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compare_when_nulls() {
|
||||
|
||||
assertEquals(0, sortMetric.compare(create(null), create(null)));
|
||||
assertEquals(1, sortMetric.compare(create("foo"), create(null)));
|
||||
assertEquals(-1, sortMetric.compare(create(null), create("foo")));
|
||||
}
|
||||
|
||||
private DTimeMetricStats create(String name) {
|
||||
return new DTimeMetricStats(MetricType.L2, name, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebeaninternal.server.profile;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class UtilLocationTest {
|
||||
|
||||
@Test
|
||||
public void label() {
|
||||
|
||||
assertThat(UtilLocation.label("foo")).isEqualTo("foo");
|
||||
assertThat(UtilLocation.label("ProfileLocationTest$Other.<init>(ProfileLocationTest.java:47)")).isEqualTo("ProfileLocationTest$Other.init");
|
||||
}
|
||||
}
|
||||
@@ -62,14 +62,14 @@ public class OrmQueryPropertiesTest {
|
||||
public void append_when_someProperties() {
|
||||
|
||||
OrmQueryProperties p1 = new OrmQueryProperties(null, "id,name");
|
||||
assertThat(append("select ", p1)).isEqualTo("select (id,name) ");
|
||||
assertThat(append("select ", p1)).isEqualTo("select (id,name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void append_when_somePropertiesWithOptions() {
|
||||
|
||||
OrmQueryProperties p1 = new OrmQueryProperties(null, "id,name +cache");
|
||||
assertThat(append("select ", p1)).isEqualTo("select (id,name +cache) ");
|
||||
assertThat(append("select ", p1)).isEqualTo("select (id,name +cache)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -83,7 +83,7 @@ public class OrmQueryPropertiesTest {
|
||||
public void append_when_path_and_somePropertiesWithOptions() {
|
||||
|
||||
OrmQueryProperties p1 = new OrmQueryProperties("customer", "id,name +cache");
|
||||
assertThat(append("fetch ", p1)).isEqualTo("fetch customer (id,name +cache) ");
|
||||
assertThat(append("fetch ", p1)).isEqualTo("fetch customer (id,name +cache)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import io.ebean.annotation.IgnorePlatform;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.annotation.Transactional;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
@@ -77,8 +77,8 @@ public class TestBatchInsertFlush extends BaseTestCase {
|
||||
transaction.end();
|
||||
}
|
||||
|
||||
BasicMetricVisitor basic = visitMetricsBasic();
|
||||
List<MetaTimedMetric> txnStats = basic.getTimedMetrics();
|
||||
ServerMetrics metrics = collectMetrics();
|
||||
List<MetaTimedMetric> txnStats = metrics.getTimedMetrics();
|
||||
for (MetaTimedMetric txnMetric : txnStats) {
|
||||
System.out.println(txnMetric);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.tests.cascade;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
public class RelDetail {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@Version
|
||||
int version;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "detail")
|
||||
private List<RelMaster> masterRel;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<RelMaster> getMasterRel() {
|
||||
return masterRel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.tests.cascade;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
public class RelMaster {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@Version
|
||||
int version;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.REMOVE)
|
||||
private RelDetail detail;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public RelDetail getDetail() {
|
||||
return detail;
|
||||
}
|
||||
|
||||
public void setDetail(RelDetail detail) {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.tests.cascade;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Transaction;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestMasterDetailDelete extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testDeleteOneMasterTxn() {
|
||||
try (Transaction txn = server().beginTransaction()) {
|
||||
RelDetail rd = new RelDetail();
|
||||
rd.setName("test1");
|
||||
server().save(rd);
|
||||
|
||||
RelMaster rm = new RelMaster();
|
||||
rm.setDetail(rd);
|
||||
server().save(rm);
|
||||
|
||||
List<RelDetail> lst = server().find(RelDetail.class).where().eq("name", "test1").findList();
|
||||
assertThat(lst).hasSize(1);
|
||||
|
||||
server().find(RelMaster.class).delete();
|
||||
|
||||
lst = server().find(RelDetail.class).where().eq("name", "test1").findList();
|
||||
assertThat(lst).isEmpty();
|
||||
} // no commit
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteMultiMasterTxn() {
|
||||
try (Transaction txn = server().beginTransaction()) {
|
||||
RelDetail rd = new RelDetail();
|
||||
rd.setName("test2");
|
||||
server().save(rd);
|
||||
|
||||
RelMaster rm1 = new RelMaster();
|
||||
rm1.setDetail(rd);
|
||||
server().save(rm1);
|
||||
|
||||
RelMaster rm2 = new RelMaster();
|
||||
rm2.setDetail(rd);
|
||||
server().save(rm2);
|
||||
|
||||
List<RelDetail> lst = server().find(RelDetail.class).where().eq("name", "test2").findList();
|
||||
assertThat(lst).hasSize(1);
|
||||
|
||||
server().find(RelMaster.class).delete();
|
||||
|
||||
lst = server().find(RelDetail.class).where().eq("name", "test2").findList();
|
||||
assertThat(lst).isEmpty();
|
||||
} // no commit
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMultiMasterPlain() {
|
||||
RelDetail rd = new RelDetail();
|
||||
rd.setName("test3");
|
||||
server().save(rd);
|
||||
|
||||
RelMaster rm1 = new RelMaster();
|
||||
rm1.setDetail(rd);
|
||||
server().save(rm1);
|
||||
|
||||
RelMaster rm2 = new RelMaster();
|
||||
rm2.setDetail(rd);
|
||||
server().save(rm2);
|
||||
|
||||
List<RelDetail> lst = server().find(RelDetail.class).where().eq("name", "test3").findList();
|
||||
assertThat(lst).hasSize(1);
|
||||
|
||||
server().find(RelMaster.class).delete();
|
||||
|
||||
lst = server().find(RelDetail.class).where().eq("name", "test3").findList();
|
||||
assertThat(lst).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,13 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
|
||||
loggedSql = LoggedSqlCollector.stop();
|
||||
assertThat(loggedSql).hasSize(1);
|
||||
assertThat(loggedSql.get(0)).contains("delete from bbookmark_user where name =");
|
||||
if (isPlatformSupportsDeleteTableAlias()) {
|
||||
assertThat(loggedSql.get(0)).contains("delete from bbookmark_user t0 where t0.name =");
|
||||
} else if (isMySql()){
|
||||
assertThat(loggedSql.get(0)).contains("delete t0 from bbookmark_user t0 where t0.name =");
|
||||
} else {
|
||||
assertThat(loggedSql.get(0)).contains("delete from bbookmark_user where name =");
|
||||
}
|
||||
|
||||
|
||||
server.find(BBookmarkUser.class).select("id").where().eq("name", "NotARealFirstName").delete();
|
||||
@@ -102,8 +108,13 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
Ebean.find(BBookmarkUser.class).setId(7000).delete();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("delete from bbookmark_user where id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from bbookmark_user where id = ?");
|
||||
if (isPlatformSupportsDeleteTableAlias()) {
|
||||
assertThat(sql.get(0)).contains("delete from bbookmark_user t0 where t0.id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from bbookmark_user t0 where t0.id = ?");
|
||||
} else if (!isMySql()) {
|
||||
assertThat(sql.get(0)).contains("delete from bbookmark_user where id = ?");
|
||||
assertThat(sql.get(1)).contains("delete from bbookmark_user where id = ?");
|
||||
}
|
||||
|
||||
// and note this is the easiest option
|
||||
Ebean.delete(BBookmarkUser.class, 7000);
|
||||
@@ -140,7 +151,11 @@ public class TestDeleteByQuery extends BaseTestCase {
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("delete from contact where id = ?");
|
||||
if (isPlatformSupportsDeleteTableAlias()) {
|
||||
assertThat(sql.get(0)).contains("delete from contact t0 where t0.id = ?");
|
||||
} else if (!isMySql()){
|
||||
assertThat(sql.get(0)).contains("delete from contact where id = ?");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -9,6 +9,8 @@ public class ProfileLocationTest {
|
||||
|
||||
private static ProfileLocation loc = ProfileLocation.create(12, "foo");
|
||||
|
||||
private static ProfileLocation loc2 = ProfileLocation.create();
|
||||
|
||||
private String doIt() {
|
||||
return loc.obtain();
|
||||
}
|
||||
@@ -16,8 +18,8 @@ public class ProfileLocationTest {
|
||||
@Test
|
||||
public void test_obtain() {
|
||||
|
||||
assertThat(doIt()).isEqualTo("org.tests.profile.ProfileLocationTest.doIt(ProfileLocationTest.java:13)");
|
||||
assertThat(loc.shortDescription()).isEqualTo("ProfileLocationTest.doIt(ProfileLocationTest.java:13)");
|
||||
assertThat(doIt()).isEqualTo("org.tests.profile.ProfileLocationTest.doIt(ProfileLocationTest.java:15)");
|
||||
assertThat(loc.shortDescription()).isEqualTo("ProfileLocationTest.doIt(ProfileLocationTest.java:15)");
|
||||
assertThat(loc.label()).isEqualTo("ProfileLocationTest.doIt");
|
||||
}
|
||||
|
||||
@@ -25,4 +27,21 @@ public class ProfileLocationTest {
|
||||
public void test_add() {
|
||||
loc.add(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_constructor() {
|
||||
|
||||
Other other = new Other();
|
||||
other.hashCode();
|
||||
|
||||
assertThat(loc2.label()).isEqualTo("ProfileLocationTest$Other.init");
|
||||
assertThat(loc2.shortDescription()).isEqualTo("ProfileLocationTest$Other.<init>(ProfileLocationTest.java:44)");
|
||||
}
|
||||
|
||||
static class Other {
|
||||
|
||||
Other() {
|
||||
loc2.obtain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package org.tests.query.autotune;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Address;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.OrderDetail;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
@@ -49,16 +49,17 @@ public class TestAutoTuneProfiling extends BaseTestCase {
|
||||
|
||||
|
||||
private void execute() {
|
||||
useOrderDate();
|
||||
useOrderDateCustomerName();
|
||||
useLots();
|
||||
// useOrderDate();
|
||||
// useOrderDateCustomerName();
|
||||
// useLots();
|
||||
useLotUntuned();
|
||||
}
|
||||
|
||||
private Order findById(long id) {
|
||||
return Ebean.find(Order.class)
|
||||
return DB.find(Order.class)
|
||||
.select("status, orderDate, shipDate")
|
||||
.setId(id)
|
||||
.setUseCache(false)
|
||||
.findOne();
|
||||
}
|
||||
|
||||
@@ -99,19 +100,19 @@ public class TestAutoTuneProfiling extends BaseTestCase {
|
||||
detail.getUnitPrice();
|
||||
}
|
||||
|
||||
Customer customer = order.getCustomer();
|
||||
customer.getName();
|
||||
Address billingAddress = customer.getBillingAddress();
|
||||
if (billingAddress != null) {
|
||||
billingAddress.getCity();
|
||||
billingAddress.getLine1();
|
||||
billingAddress.getLine2();
|
||||
}
|
||||
// Customer customer = order.getCustomer();
|
||||
// customer.getName();
|
||||
// Address billingAddress = customer.getBillingAddress();
|
||||
// if (billingAddress != null) {
|
||||
// billingAddress.getCity();
|
||||
// billingAddress.getLine1();
|
||||
// billingAddress.getLine2();
|
||||
// }
|
||||
}
|
||||
|
||||
private static void collectUsage() {
|
||||
|
||||
Ebean.getDefaultServer().getAutoTune().collectProfiling();
|
||||
DB.getDefault().getAutoTune().collectProfiling();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ package org.tests.query.finder;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.meta.BasicMetricVisitor;
|
||||
import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
@@ -153,16 +153,16 @@ public class TestCustomerFinder extends BaseTestCase {
|
||||
Customer.find.updateNames("Junk", 2000);
|
||||
Customer.find.byId(3);
|
||||
|
||||
BasicMetricVisitor basic = server().getMetaInfoManager().visitBasic();
|
||||
ServerMetrics metrics = server().getMetaInfoManager().collectMetrics();
|
||||
|
||||
List<MetaOrmQueryMetric> planStats = basic.getOrmQueryMetrics();
|
||||
List<MetaOrmQueryMetric> planStats = metrics.getOrmQueryMetrics();
|
||||
assertThat(planStats.size()).isGreaterThan(4);
|
||||
|
||||
for (MetaOrmQueryMetric planStat : planStats) {
|
||||
System.out.println(planStat);
|
||||
}
|
||||
|
||||
for (MetaTimedMetric txnTimed : basic.getTimedMetrics()) {
|
||||
for (MetaTimedMetric txnTimed : metrics.getTimedMetrics()) {
|
||||
System.out.println(txnTimed);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ create table migtest_e_basic (
|
||||
indextest5 varchar(127),
|
||||
indextest6 varchar(127),
|
||||
user_id integer not null,
|
||||
constraint ck_migtest_e_basic_status check ( status in ('N','A','I')),
|
||||
constraint ck_mgtst__bsc_stts check ( status in ('N','A','I')),
|
||||
constraint pk_migtest_e_basic primary key (id)
|
||||
);
|
||||
-- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_4aybzy unique (indextest2);
|
||||
@@ -79,7 +79,7 @@ create table migtest_e_basic (
|
||||
create table migtest_e_enum (
|
||||
id integer generated by default as identity not null,
|
||||
test_status varchar(1),
|
||||
constraint ck_migtest_e_enum_test_status check ( test_status in ('N','A','I')),
|
||||
constraint ck_mgtst__n_773sok check ( test_status in ('N','A','I')),
|
||||
constraint pk_migtest_e_enum primary key (id)
|
||||
);
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ create table migtest_e_basic (
|
||||
indextest5 varchar(127),
|
||||
indextest6 varchar(127),
|
||||
user_id integer not null,
|
||||
constraint ck_migtest_e_basic_status check ( status in ('N','A','I')),
|
||||
constraint uq_migtest_e_basic_indextest2 unique (indextest2),
|
||||
constraint uq_migtest_e_basic_indextest6 unique (indextest6),
|
||||
constraint pk_migtest_e_basic primary key (id)
|
||||
@@ -79,7 +78,6 @@ create table migtest_e_basic (
|
||||
create table migtest_e_enum (
|
||||
id integer auto_increment not null,
|
||||
test_status varchar(1),
|
||||
constraint ck_migtest_e_enum_test_status check ( test_status in ('N','A','I')),
|
||||
constraint pk_migtest_e_enum primary key (id)
|
||||
);
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id for
|
||||
update migtest_e_basic set status = 'A' where status is null;
|
||||
alter table migtest_e_basic alter status set default 'A';
|
||||
alter table migtest_e_basic modify status varchar(1) not null;
|
||||
alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I','?'));
|
||||
|
||||
-- rename all collisions;
|
||||
alter table migtest_e_basic add constraint uq_migtest_e_basic_description unique (description);
|
||||
@@ -53,7 +52,6 @@ update migtest_e_basic set new_boolean_field = old_boolean;
|
||||
|
||||
alter table migtest_e_basic add column new_boolean_field2 tinyint(1) default 1 not null;
|
||||
alter table migtest_e_basic add column progress integer default 0 not null;
|
||||
alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2));
|
||||
alter table migtest_e_basic add column new_integer integer default 42 not null;
|
||||
|
||||
alter table migtest_e_basic drop index uq_migtest_e_basic_indextest2;
|
||||
|
||||
@@ -20,7 +20,6 @@ alter table migtest_fk_none_via_join drop foreign key fk_migtest_fk_none_via_joi
|
||||
alter table migtest_fk_set_null drop foreign key fk_migtest_fk_set_null_one_id;
|
||||
alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null;
|
||||
alter table migtest_e_basic alter status drop default;
|
||||
alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I'));
|
||||
alter table migtest_e_basic drop index uq_migtest_e_basic_description;
|
||||
|
||||
update migtest_e_basic set user_id = 23 where user_id is null;
|
||||
@@ -37,7 +36,6 @@ alter table migtest_e_basic drop index uq_migtest_e_basic_indextest4;
|
||||
alter table migtest_e_basic drop index uq_migtest_e_basic_indextest5;
|
||||
alter table migtest_e_basic add constraint uq_migtest_e_basic_indextest2 unique (indextest2);
|
||||
alter table migtest_e_basic add constraint uq_migtest_e_basic_indextest6 unique (indextest6);
|
||||
alter table migtest_e_enum add constraint ck_migtest_e_enum_test_status check ( test_status in ('N','A','I'));
|
||||
alter table migtest_e_history comment = '';
|
||||
alter table migtest_e_history2 alter test_string drop default;
|
||||
alter table migtest_e_history2 add column obsolete_string1 varchar(255);
|
||||
|
||||
@@ -13,6 +13,7 @@ ebean.encryptKeyManager=org.tests.basic.encrypt.BasicEncyptKeyManager
|
||||
|
||||
#ebean.disableL2Cache=true
|
||||
#ebean.autoTune.queryTuning=true
|
||||
#ebean.autoTune.mode=DEFAULT_ON
|
||||
#ebean.autoTune.profiling=true
|
||||
#ebean.autoTune.profilingUpdateFrequency=5
|
||||
|
||||
@@ -22,6 +23,9 @@ ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp}
|
||||
ebean.packages=org.tests
|
||||
datasource.default=h2
|
||||
|
||||
ebean.dumpMetricsOnShutdown=true
|
||||
ebean.dumpMetricsOptions=sql,hash
|
||||
|
||||
ebean.collectQueryPlans=true
|
||||
|
||||
ebean.autoReadOnlyDataSource=true
|
||||
|
||||
@@ -82,9 +82,9 @@
|
||||
<!--<logger name="org.avaje.docker" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.DDL" level="DEBUG"/>-->
|
||||
|
||||
<!--<logger name="io.ebean.SQL" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.TXN" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.SUM" level="TRACE"/>-->
|
||||
<logger name="io.ebean.SQL" level="TRACE"/>
|
||||
<logger name="io.ebean.TXN" level="TRACE"/>
|
||||
<logger name="io.ebean.SUM" level="TRACE"/>
|
||||
|
||||
<!--<logger name="io.ebean.cache.TABLEMOD" level="TRACE"/>-->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user