diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 43396fab9..93d91a94c 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -75,6 +75,11 @@ public class DatabasePlatform { protected boolean caseSensitiveCollation = true; + /** + * Set true if the Database support LIMIT clause on sql update. + */ + protected boolean inlineSqlUpdateLimit; + /** * For limit/offset, row_number etc limiting of SQL queries. */ @@ -171,7 +176,7 @@ public class DatabasePlatform { /** * Characters escaped for startsWith, endsWith and contains. */ - protected char[] likeSpecialCharacters = { '%', '_', '|' }; + protected char[] likeSpecialCharacters = {'%', '_', '|'}; protected DbEncrypt dbEncrypt; @@ -187,7 +192,7 @@ public class DatabasePlatform { /** * If set then use the CONCUR_UPDATABLE hint when creating ResultSets. - * + *

* This is {@code false} for HANA */ protected boolean supportsResultSetConcurrencyModeUpdatable = true; @@ -339,6 +344,13 @@ public class DatabasePlatform { return supportsSavepointId; } + /** + * Return true if the platform supports LIMIT with sql update. + */ + public boolean isInlineSqlUpdateLimit() { + return inlineSqlUpdateLimit; + } + /** * Return the maximum table name length. *

@@ -370,11 +382,11 @@ public class DatabasePlatform { /** * Return a DB Sequence based IdGenerator. * - * @param be the BackgroundExecutor that can be used to load the sequence if - * desired - * @param ds the DataSource - * @param stepSize the sequence allocation size as defined by mapping (defaults to 50) - * @param seqName the name of the sequence + * @param be the BackgroundExecutor that can be used to load the sequence if + * desired + * @param ds the DataSource + * @param stepSize the sequence allocation size as defined by mapping (defaults to 50) + * @param seqName the name of the sequence */ public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { return null; @@ -659,7 +671,7 @@ public class DatabasePlatform { if (dbName != null && !dbName.isEmpty()) { if (dbName.startsWith(openQuote)) { // trim off the open and close quotes - return dbName.substring(1, dbName.length()-1); + return dbName.substring(1, dbName.length() - 1); } } return dbName; @@ -786,7 +798,7 @@ public class DatabasePlatform { for (int i = 0; i < value.length(); i++) { char ch = value.charAt(i); boolean escaped = false; - for (char escapeChar: likeSpecialCharacters) { + for (char escapeChar : likeSpecialCharacters) { if (ch == escapeChar) { if (sb == null) { sb = new StringBuilder(value.substring(0, i)); diff --git a/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java b/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java index b7a3b1660..dd0cfde1a 100644 --- a/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java +++ b/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java @@ -24,6 +24,7 @@ public class H2Platform extends DatabasePlatform { this.historySupport = new H2HistorySupport(); this.nativeUuidType = true; this.supportsDeleteTableAlias = true; + this.inlineSqlUpdateLimit = true; this.dbDefaultValue.setNow("now()"); this.columnAliasPrefix = null; this.exceptionTranslator = diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java index 07698f832..dd9017816 100644 --- a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java @@ -28,6 +28,7 @@ public class MySqlPlatform extends DatabasePlatform { this.useExtraTransactionOnIterateSecondaryQueries = true; this.selectCountWithAlias = true; this.supportsSavepointId = false; + this.inlineSqlUpdateLimit = true; this.dbEncrypt = new MySqlDbEncrypt(); this.historySupport = new MySqlHistorySupport(); this.columnAliasPrefix = null; diff --git a/src/main/java/io/ebeaninternal/api/SpiQuery.java b/src/main/java/io/ebeaninternal/api/SpiQuery.java index fd8c7ce28..9130ac67c 100644 --- a/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -458,7 +458,7 @@ public interface SpiQuery extends Query, TxnProfileEventCodes { /** * Set the query to be a delete query. */ - void setDelete(); + void setupForDeleteOrUpdate(boolean deleteRequest); /** * Set the query to be delete by ids due to cascading delete. diff --git a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index fab12b976..7394065dc 100644 --- a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -795,4 +795,11 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery dependentTables.addAll(tables); } } + + /** + * Return true if no MaxRows or use LIMIT in SQL update. + */ + public boolean isInlineSqlUpdateLimit() { + return query.getMaxRows() < 1 || ebeanServer.getDatabasePlatform().isInlineSqlUpdateLimit(); + } } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 557499fe7..552d3d03c 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -47,24 +47,19 @@ class CQueryBuilder { final String columnAliasPrefix; private final SqlLimiter sqlLimiter; - private final CQueryBuilderRawSql rawSqlHandler; - private final Binder binder; private final boolean selectCountWithAlias; private final CQueryHistorySupport historySupport; - private final CQueryDraftSupport draftSupport; - private final DatabasePlatform dbPlatform; /** * Create the SqlGenSelect. */ CQueryBuilder(DatabasePlatform dbPlatform, Binder binder, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { - this.dbPlatform = dbPlatform; this.binder = binder; this.draftSupport = draftSupport; @@ -102,7 +97,7 @@ class CQueryBuilder { SpiQuery query = request.getQuery(); String rootTableAlias = query.getAlias(); - query.setDelete(); + query.setupForDeleteOrUpdate(deleteRequest); CQueryPredicates predicates = new CQueryPredicates(binder, request); CQueryPlan queryPlan = request.getQueryPlan(); @@ -135,16 +130,16 @@ class CQueryBuilder { if (sqlTree.noJoins()) { if (dbPlatform.isSupportsDeleteTableAlias()) { // delete from table ... - return aliasReplace(buildSql("delete", request, predicates, sqlTree).getSql(), alias); + return aliasReplace(buildSqlDelete("delete", request, predicates, sqlTree).getSql(), alias); } else if (isMySql(dbPlatform.getPlatform())) { - return aliasReplace(buildSql("delete " + alias, request, predicates, sqlTree).getSql(), alias); + return aliasReplace(buildSqlDelete("delete " + alias, request, predicates, sqlTree).getSql(), alias); } else { // simple - delete from table ... - return aliasStrip(buildSql("delete", request, predicates, sqlTree).getSql()); + return aliasStrip(buildSqlDelete("delete", request, predicates, sqlTree).getSql()); } } // wrap as - delete from table where id in (select id ...) - String sql = buildSql(null, request, predicates, sqlTree).getSql(); + String sql = buildSqlDelete(null, request, predicates, sqlTree).getSql(); sql = request.getBeanDescriptor().getDeleteByIdInSql() + "in (" + sql + ")"; sql = aliasReplace(sql, alias); return sql; @@ -168,7 +163,7 @@ class CQueryBuilder { sb.append(" set ").append(predicates.getDbUpdateClause()); String updateClause = sb.toString(); - if (sqlTree.noJoins()) { + if (sqlTree.noJoins() && request.isInlineSqlUpdateLimit()) { // simple - update table set ... where ... return aliasStrip(buildSqlUpdate(updateClause, request, predicates, sqlTree).getSql()); } @@ -547,137 +542,156 @@ class CQueryBuilder { * Return the SQL response with row limiting (when not an update statement). */ private SqlLimitResponse buildSql(String selectClause, OrmQueryRequest request, CQueryPredicates predicates, SqlTree select) { - return buildSql(selectClause, request, predicates, select, false); - } - - /** - * Return the SQL response for update statement (stripping table alias for find by id expression). - */ - private SqlLimitResponse buildSqlUpdate(String selectClause, OrmQueryRequest request, CQueryPredicates predicates, SqlTree select) { - return buildSql(selectClause, request, predicates, select, true); - } - - private SqlLimitResponse buildSql(String selectClause, OrmQueryRequest request, CQueryPredicates predicates, SqlTree select, boolean stripAlias) { - SpiQuery query = request.getQuery(); - if (query.isNativeSql()) { return new SqlLimitResponse(query.getGeneratedSql(), false); } if (query.isRawSql()) { return rawSqlHandler.buildSql(request, predicates, query.getRawSql().getSql()); } + return new BuildReq(selectClause, request, predicates, select).buildSql(); + } - boolean distinct = query.isDistinct() || select.isSqlDistinct(); - boolean useSqlLimiter = false; - StringBuilder sb = new StringBuilder(500); - String dbOrderBy = predicates.getDbOrderBy(); + private SqlLimitResponse buildSqlDelete(String selectClause, OrmQueryRequest request, CQueryPredicates predicates, SqlTree select) { + return new BuildReq(selectClause, request, predicates, select).buildSql(); + } - if (selectClause != null) { - sb.append(selectClause); + private SqlLimitResponse buildSqlUpdate(String selectClause, OrmQueryRequest request, CQueryPredicates predicates, SqlTree select) { + return new BuildReq(selectClause, request, predicates, select, true).buildSql(); + } - } else { - useSqlLimiter = (query.hasMaxRowsOrFirstRow() && select.getManyProperty() == null); + private class BuildReq { + private final StringBuilder sb = new StringBuilder(500); + private final String selectClause; + private final OrmQueryRequest request; + private final SpiQuery query; + private final CQueryPredicates predicates; + private final SqlTree select; + private final boolean updateStatement; - if (!useSqlLimiter) { - sb.append("select "); - if (distinct) { - if (request.isInlineCountDistinct()) { - sb.append("count("); - } - sb.append("distinct "); - String distinctOn = select.getDistinctOn(); - if (distinctOn != null) { - sb.append("on ("); - sb.append(distinctOn).append(") "); + private final boolean distinct; + private final String dbOrderBy; + private boolean useSqlLimiter; + private boolean hasWhere; + + private BuildReq(String selectClause, OrmQueryRequest request, CQueryPredicates predicates, SqlTree select) { + this(selectClause, request, predicates, select, false); + } + + private BuildReq(String selectClause, OrmQueryRequest request, CQueryPredicates predicates, SqlTree select, boolean updateStatement) { + this.selectClause = selectClause; + this.request = request; + this.query = request.getQuery(); + this.predicates = predicates; + this.select = select; + this.updateStatement = updateStatement; + this.distinct = query.isDistinct() || select.isSqlDistinct(); + this.dbOrderBy = predicates.getDbOrderBy(); + } + + private void appendSelect() { + if (selectClause != null) { + sb.append(selectClause); + + } else { + useSqlLimiter = (query.hasMaxRowsOrFirstRow() && select.getManyProperty() == null); + if (!useSqlLimiter) { + appendSelectDistinct(); + } + if (query.isCountDistinct() && query.isSingleAttribute()) { + sb.append("r1.attribute_, count(*) from (select ").append(select.getSelectSql()).append(" as attribute_"); + } else { + sb.append(select.getSelectSql()); + } + if (request.isInlineCountDistinct()) { + sb.append(")"); + } + if (distinct && dbOrderBy != null && !query.isSingleAttribute()) { + // add the orderBy columns to the select clause (due to distinct) + final OrderBy orderBy = query.getOrderBy(); + if (orderBy != null && orderBy.supportsSelect()) { + sb.append(", ").append(DbOrderByTrim.trim(dbOrderBy)); } } } - if (query.isCountDistinct() && query.isSingleAttribute()) { - sb.append("r1.attribute_, count(*) from (select "); - sb.append(select.getSelectSql()); - sb.append(" as attribute_"); - } else { - sb.append(select.getSelectSql()); - } - if (request.isInlineCountDistinct()) { - sb.append(")"); - } - if (distinct && dbOrderBy != null && !query.isSingleAttribute()) { - // add the orderBy columns to the select clause (due to distinct) - final OrderBy orderBy = query.getOrderBy(); - if (orderBy != null && orderBy.supportsSelect()) { - sb.append(", ").append(DbOrderByTrim.trim(dbOrderBy)); + } + + private void appendSelectDistinct() { + sb.append("select "); + if (distinct) { + if (request.isInlineCountDistinct()) { + sb.append("count("); + } + sb.append("distinct "); + String distinctOn = select.getDistinctOn(); + if (distinctOn != null) { + sb.append("on (").append(distinctOn).append(") "); } } } - if (selectClause == null || !selectClause.startsWith("update")) { - sb.append(" from "); - sb.append(select.getFromSql()); - } - - String inheritanceWhere = select.getInheritanceWhereSql(); - - boolean hasWhere = false; - if (!inheritanceWhere.isEmpty()) { - sb.append(" where"); - sb.append(inheritanceWhere); - hasWhere = true; - } - - if (query.isAsOfBaseTable() && !historySupport.isStandardsBased()) { - hasWhere = appendWhere(hasWhere, sb); - sb.append(historySupport.getAsOfPredicate(request.getBaseTableAlias())); - } - - if (request.isFindById() || query.getId() != null) { - appendWhere(hasWhere, sb); - - BeanDescriptor desc = request.getBeanDescriptor(); - String idSql = desc.getIdBinderIdSql(query.getAlias()); - if (idSql.isEmpty()) { - throw new IllegalStateException("Executing FindById query on entity bean " + desc.getName() - + " that doesn't have an @Id property??"); + private void appendFrom() { + if (selectClause == null || !selectClause.startsWith("update")) { + sb.append(" from "); + sb.append(select.getFromSql()); } - if (stripAlias) { - // strip the table alias for use in update statement - idSql = StringHelper.replaceString(idSql, "t0.", ""); - } - sb.append(idSql).append(" "); - hasWhere = true; } - String dbWhere = predicates.getDbWhere(); - if (hasValue(dbWhere)) { - if (!hasWhere) { - hasWhere = true; - sb.append(" where "); - } else { + private void appendAndOrWhere() { + if (hasWhere) { sb.append(" and "); - } - sb.append(dbWhere); - } - - String dbFilterMany = predicates.getDbFilterMany(); - if (hasValue(dbFilterMany)) { - if (!hasWhere) { - hasWhere = true; - sb.append(" where "); } else { - sb.append("and "); + sb.append(" where "); + hasWhere = true; } - sb.append(dbFilterMany); } - if (!query.isIncludeSoftDeletes()) { + private void appendInheritanceWhere() { + String inheritanceWhere = select.getInheritanceWhereSql(); + if (!inheritanceWhere.isEmpty()) { + sb.append(" where"); + sb.append(inheritanceWhere); + hasWhere = true; + } + } + + private void appendHistoryAsOfPredicate() { + if (query.isAsOfBaseTable() && !historySupport.isStandardsBased()) { + appendAndOrWhere(); + sb.append(historySupport.getAsOfPredicate(request.getBaseTableAlias())); + } + } + + private void appendFindId() { + if (request.isFindById() || query.getId() != null) { + appendAndOrWhere(); + + BeanDescriptor desc = request.getBeanDescriptor(); + String idSql = desc.getIdBinderIdSql(query.getAlias()); + if (idSql.isEmpty()) { + throw new IllegalStateException("Executing FindById query on entity bean " + desc.getName() + + " that doesn't have an @Id property??"); + } + if (updateStatement) { + // strip the table alias for use in update statement + idSql = StringHelper.replaceString(idSql, "t0.", ""); + } + sb.append(idSql).append(" "); + hasWhere = true; + } + } + + private void appendToWhere(String predicate) { + if (hasValue(predicate)) { + appendAndOrWhere(); + sb.append(predicate); + } + } + + private void appendSoftDelete() { List softDeletePredicates = query.getSoftDeletePredicates(); if (softDeletePredicates != null) { - if (!hasWhere) { - sb.append(" where "); - } else { - sb.append(" and "); - } + appendAndOrWhere(); for (int i = 0; i < softDeletePredicates.size(); i++) { if (i > 0) { sb.append(" and "); @@ -687,69 +701,75 @@ class CQueryBuilder { } } - String groupBy = select.getGroupBy(); - if (groupBy != null) { - sb.append(" group by ").append(groupBy); + private SqlLimitResponse buildSql() { + appendSelect(); + appendFrom(); + appendInheritanceWhere(); + appendHistoryAsOfPredicate(); + appendFindId(); + appendToWhere(predicates.getDbWhere()); + appendToWhere(predicates.getDbFilterMany()); + if (!query.isIncludeSoftDeletes()) { + appendSoftDelete(); + } + + String groupBy = select.getGroupBy(); + if (groupBy != null) { + sb.append(" group by ").append(groupBy); + } + + String dbHaving = predicates.getDbHaving(); + if (hasValue(dbHaving)) { + sb.append(" having ").append(dbHaving); + } + + if (dbOrderBy != null && !query.isCountDistinct()) { + sb.append(" order by ").append(dbOrderBy); + } + + if (query.isCountDistinct() && query.isSingleAttribute()) { + sb.append(") r1 group by r1.attribute_"); + sb.append(toSql(query.getCountDistinctOrder())); + } + + if (useSqlLimiter) { + // use LIMIT/OFFSET, ROW_NUMBER() or rownum type SQL query limitation + SqlLimitRequest r = new OrmQueryLimitRequest(sb.toString(), dbOrderBy, query, dbPlatform, distinct); + return sqlLimiter.limit(r); + } else { + if (updateStatement) { + final int maxRows = query.getMaxRows(); + if (maxRows > 0) { + // limit on update statement only support on platforms with supportsMaxRowsOnUpdate + sb.append(" limit ").append(maxRows); + } + } + return new SqlLimitResponse(dbPlatform.completeSql(sb.toString(), query), false); + } } - String dbHaving = predicates.getDbHaving(); - if (hasValue(dbHaving)) { - sb.append(" having ").append(dbHaving); + 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); + } } - if (dbOrderBy != null && !query.isCountDistinct()) { - sb.append(" order by ").append(dbOrderBy); + private boolean hasValue(String s) { + return s != null && !s.isEmpty(); } - - if (query.isCountDistinct() && query.isSingleAttribute()) { - sb.append(") r1 group by r1.attribute_"); - sb.append(toSql(query.getCountDistinctOrder())); - } - - if (useSqlLimiter) { - // use LIMIT/OFFSET, ROW_NUMBER() or rownum type SQL query limitation - SqlLimitRequest r = new OrmQueryLimitRequest(sb.toString(), dbOrderBy, query, dbPlatform, distinct); - return sqlLimiter.limit(r); - - } else { - return new SqlLimitResponse(dbPlatform.completeSql(sb.toString(), query), false); - } - - } - - 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); - } - } - - /** - * Append where or and based on the hasWhere flag. - */ - private boolean appendWhere(boolean hasWhere, StringBuilder sb) { - if (hasWhere) { - sb.append(" and "); - } else { - sb.append(" where "); - } - return true; - } - - private boolean hasValue(String s) { - return s != null && !s.isEmpty(); } boolean isPlatformDistinctOn() { @@ -759,7 +779,7 @@ class CQueryBuilder { /** * Return the 'for update' FROM hint (sql server). */ - public String fromForUpdate(SpiQuery query) { + String fromForUpdate(SpiQuery query) { Query.ForUpdate mode = query.getForUpdateMode(); if (mode == null) { return null; diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 61bd4513f..ab0824901 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -692,13 +692,15 @@ public class DefaultOrmQuery implements SpiQuery { } /** - * Setup to be a delete query. + * Setup to be a delete or update query. */ @Override - public void setDelete() { + public void setupForDeleteOrUpdate(boolean deleteRequest) { // unset any paging and select on the id in the case where the query // includes joins and we use - delete ... where id in (...) - maxRows = 0; + if (deleteRequest) { + maxRows = 0; + } firstRow = 0; forUpdate = null; rootTableAlias = "${RTA}"; // alias we remove later diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java index cfbdb02f6..7e945a2d5 100644 --- a/src/test/java/io/ebean/UpdateQueryTest.java +++ b/src/test/java/io/ebean/UpdateQueryTest.java @@ -1,5 +1,6 @@ package io.ebean; +import io.ebean.annotation.ForPlatform; import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.Platform; import io.ebean.meta.MetaOrmQueryMetric; @@ -16,7 +17,6 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; - public class UpdateQueryTest extends BaseTestCase { @Test @@ -143,12 +143,10 @@ public class UpdateQueryTest extends BaseTestCase { assertThat(query.getGeneratedSql()).contains("update o_customer cust set status=?, updtime=? where id > ?"); } + @IgnorePlatform(Platform.MYSQL) @Test public void withJoin() { - if (isMySql()) { - return; - } EbeanServer server = server(); Country nz = server.getReference(Country.class, "NZ"); @@ -169,6 +167,51 @@ public class UpdateQueryTest extends BaseTestCase { assertThat(sqlOf(query)).contains("update o_customer set status=?, updtime=? where id in (select t0.id from o_customer t0 left join o_address t1 on t1.id = t0.billing_address_id where t0.status = ? and t1.country_code = ? and t0.id > ?)"); } + @ForPlatform({Platform.H2, Platform.POSTGRES}) + @Test + public void withJoinAndLimit() { + + EbeanServer server = server(); + + Country nz = server.getReference(Country.class, "NZ"); + + LoggedSqlCollector.start(); + + server.update(Customer.class) + .set("status", Customer.Status.ACTIVE) + .where() + .eq("billingAddress.country", nz) + .gt("id", 1000) + .setMaxRows(100) + .update(); + + final List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("update o_customer set status=? where id in (select t0.id from o_customer t0 left join o_address t1 on t1.id = t0.billing_address_id where t1.country_code = ? and t0.id > ? limit 100)"); + } + + @ForPlatform({Platform.H2, Platform.POSTGRES, Platform.MYSQL}) + @Test + public void simpleWithLimit() { + + EbeanServer server = server(); + + LoggedSqlCollector.start(); + + server.update(Customer.class) + .set("status", Customer.Status.ACTIVE) + .where() + .gt("id", 1000) + .setMaxRows(100) + .update(); + + final List sql = LoggedSqlCollector.stop(); + if (isMySql() || isH2()) { + assertThat(sql.get(0)).contains("update o_customer set status=? where id > ? limit 100"); + } else { + assertThat(sql.get(0)).contains("update o_customer set status=? where id in (select t0.id from o_customer t0 where t0.id > ? limit 100)"); + } + } + @Test public void whereIsEmpty() { diff --git a/src/test/java/org/tests/basic/TestCreateEntityBean.java b/src/test/java/org/tests/basic/TestCreateEntityBean.java index 6f544db53..af15e5380 100644 --- a/src/test/java/org/tests/basic/TestCreateEntityBean.java +++ b/src/test/java/org/tests/basic/TestCreateEntityBean.java @@ -3,6 +3,8 @@ package org.tests.basic; import io.ebean.BaseTestCase; import io.ebean.DB; import io.ebean.Ebean; +import io.ebean.annotation.IgnorePlatform; +import io.ebean.annotation.Platform; import org.junit.Test; import org.tests.model.basic.EDefaultProp; @@ -11,6 +13,7 @@ import static org.junit.Assert.assertNotNull; public class TestCreateEntityBean extends BaseTestCase { + @IgnorePlatform(Platform.SQLSERVER) @Test public void testDefaultRelation() { diff --git a/src/test/java/org/tests/query/TestQueryFilterMany.java b/src/test/java/org/tests/query/TestQueryFilterMany.java index 2dff48308..fcc734a98 100644 --- a/src/test/java/org/tests/query/TestQueryFilterMany.java +++ b/src/test/java/org/tests/query/TestQueryFilterMany.java @@ -193,6 +193,6 @@ public class TestQueryFilterMany extends BaseTestCase { assertThat(sql).hasSize(2); assertThat(sql.get(0)).contains(" from o_customer t0"); assertThat(sql.get(1)).contains("from contact t0 where "); - assertThat(sql.get(1)).contains("and (t0.first_name is not null and lower(t0.email) like ? escape'|' )"); + assertThat(sql.get(1)).contains("and (t0.first_name is not null and lower(t0.email) like ?"); } }