Compare commits

...
Author SHA1 Message Date
rob bygrave 4509c6b1ed [maven-release-plugin] prepare release ebean-11.37.1 2019-04-12 13:38:41 +12:00
rob bygrave d32559baf4 #1674 - For ProfileLocation use in constructors trim label <init> to init .... (for safe label) 2019-04-12 02:25:05 +12:00
rob bygrave 2639e799c5 #1673 - ENH: Support ProfileLocation on DtoQuery including via orm query.asDto() 2019-04-12 02:01:01 +12:00
rob bygrave 46c66b7169 #1672 - ENH: Add ebean.dumpMetricsOnShutdown=true ... for dumping metrics 2019-04-12 00:55:39 +12:00
rob bygrave 30ae435f33 #1672 - ENH: Add ebean.dumpMetricsOnShutdown=true ... for dumping metrics 2019-04-12 00:45:00 +12:00
rob bygrave 4f4743807c #1671 - Use table alias with delete query for Postgres, Oracle, MySql 2019-04-10 01:25:43 +12:00
rob bygrave 7b7a492241 Bump to 11.37.1 2019-04-09 23:04:34 +12:00
rob bygrave 4af8e53315 #1670 - Expose metrics as ServerMetrics interface (improvement over existing BasicMetricVisitor use) 2019-04-09 22:54:16 +12:00
rob bygrave 1c6fa575f2 #1669 - When deleting complex object graphs, entities are deleted multiple times
Fix by not unregistering the deleted bean hash in the transaction so that
the skip occurs on other root level bean traversals (the delete of the
2nd master bean)
2019-04-09 20:30:17 +12:00
rob bygrave 2430404e1f Merge branch 'FOCONIS-bug-delete-with-version' 2019-04-09 20:27:23 +12:00
rob bygrave d433e0ea46 Merge branch 'bug-delete-with-version' of https://github.com/FOCONIS/ebean into FOCONIS-bug-delete-with-version 2019-04-09 20:06:12 +12:00
rob bygrave 42591a5a87 No effective change - reformat line 2019-04-09 20:05:22 +12:00
Roland PramlandRob Bygrave 65a62bf683 Fix check constraint support for MariaDB >= 10.2.1 (#1668)
* fixed the check constraint support for mysql/mariadb

* update migration scripts
2019-04-09 19:38:57 +12:00
Roland Praml 3e3f3c35e7 add test case to show delete with version 2019-04-08 17:21:23 +02:00
Rob BygraveandGitHub f4db7ca0bb Update sponsors in README 2019-04-08 20:49:28 +12:00
rob bygrave b0e487cfbd Add sponsor payintech.com 2019-04-03 23:24:13 +13:00
rob bygrave 23fd29ddf1 #1659 - CVE-2018-12022 - Bump Jackson version from 2.9.5 to 2.9.8 2019-04-01 23:23:02 +13:00
rob bygrave f21cac5d4f [maven-release-plugin] prepare for next development iteration 2019-04-01 23:13:07 +13:00
rob bygrave c2e5619f70 [maven-release-plugin] prepare release ebean-11.36.4 2019-04-01 23:12:53 +13:00
rob bygrave 18e0ff7067 #1665 - Incorrect query execution metrics for ORM query converted to DTO query via asDto() 2019-04-01 23:11:16 +13:00
rob bygrave 4119c02f0d #1663 Additionally trim the OrmQueryDetail.asString() output removing extra whitespace 2019-04-01 23:09:58 +13:00
rob bygrave 8985d37aed Merge branch 'master' of github.com:ebean-orm/ebean 2019-04-01 22:25:24 +13:00
Rob BygraveandGitHub 23e035894f Add foconis.de as sponsor to readme 2019-04-01 22:24:50 +13:00
rob bygrave 32b8fd0e26 #1663 Additionally trim the OrmQueryDetail.asString() output removing extra whitespace 2019-03-29 00:43:32 +13:00
rob bygrave 4971db54c8 #1663 - AutoTune - merge profiling such that "select (orderDate) fetch customer (id)" instead merges to "select (orderDate,customer)" 2019-03-29 00:19:21 +13:00
rob bygrave e417b3cde2 #1661 - AutoTune - callstack filters _ebean_ methods 2019-03-28 20:47:34 +13:00
rob bygrave d23ca31e42 [maven-release-plugin] prepare for next development iteration 2019-03-27 16:44:00 +13:00
81 changed files with 1279 additions and 330 deletions
+23
View File
@@ -1,6 +1,29 @@
[![Build Status](https://travis-ci.org/ebean-orm/ebean.svg?branch=master)](https://travis-ci.org/ebean-orm/ebean)
[![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](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
+5 -5
View File
@@ -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>
+6
View File
@@ -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
@@ -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;
+8 -4
View File
@@ -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;
}
+53 -57
View File
@@ -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();
}
+15 -2
View File
@@ -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")
+5 -5
View File
@@ -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);
+4
View File
@@ -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
+3 -3
View File
@@ -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"/>-->