mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-09-20 11:17:36 +00:00
Compare commits
2
Commits
18.4.0
...
feature/3848
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56894400f4 | ||
|
|
32931d6db0 |
@@ -162,6 +162,18 @@ public class DatabasePlatform {
|
||||
protected boolean selectCountWithAlias;
|
||||
protected boolean selectCountWithColumnAlias;
|
||||
|
||||
/**
|
||||
* Set true for platforms where {@code exists(...)} can only be used as a predicate
|
||||
* and not as a directly selectable scalar boolean expression (e.g. SQL Server, Oracle).
|
||||
*/
|
||||
protected boolean existsWithCaseWhen;
|
||||
|
||||
/**
|
||||
* Clause appended after the {@code case when exists(...) then 1 else 0 end} exists query
|
||||
* for platforms that require a FROM clause on every select (e.g. {@code from dual} on Oracle).
|
||||
*/
|
||||
protected String existsFromClause = "";
|
||||
|
||||
/**
|
||||
* If set then use the FORWARD ONLY hint when creating ResultSets for
|
||||
* findIterate() and findVisit().
|
||||
@@ -660,6 +672,21 @@ public class DatabasePlatform {
|
||||
return selectCountWithColumnAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a scalar boolean {@code exists(...)} expression is not supported
|
||||
* as a select expression and needs to be wrapped as {@code case when exists(...) then 1 else 0 end}.
|
||||
*/
|
||||
public boolean existsWithCaseWhen() {
|
||||
return existsWithCaseWhen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the clause to append after the exists case-when wrapping (e.g. {@code from dual} on Oracle).
|
||||
*/
|
||||
public String existsFromClause() {
|
||||
return existsFromClause;
|
||||
}
|
||||
|
||||
|
||||
public String completeSql(String sql, Query<?> query) {
|
||||
if (query.isForUpdate()) {
|
||||
|
||||
@@ -336,7 +336,10 @@ final class CQueryBuilder {
|
||||
return sql;
|
||||
}
|
||||
|
||||
private String wrapSelectExists(String sql) {
|
||||
static String wrapSelectExists(String sql, boolean existsWithCaseWhen, String existsFromClause) {
|
||||
if (existsWithCaseWhen) {
|
||||
return "select case when exists(" + sql + ") then 1 else 0 end" + existsFromClause;
|
||||
}
|
||||
return "select exists(" + sql + ")";
|
||||
}
|
||||
|
||||
@@ -366,7 +369,7 @@ final class CQueryBuilder {
|
||||
}
|
||||
|
||||
SqlLimitResponse s = buildSql("select 1", request, predicates, sqlTree);
|
||||
String sql = wrapSelectExists(s.getSql());
|
||||
String sql = wrapSelectExists(s.getSql(), dbPlatform.existsWithCaseWhen(), dbPlatform.existsFromClause());
|
||||
|
||||
queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.logWhereSql());
|
||||
request.putQueryPlan(queryPlan);
|
||||
|
||||
@@ -117,6 +117,31 @@ class CQueryBuilderTest {
|
||||
assertThat(countSql).isEqualTo("select count(*) from ( select t0.id from ad t0) as c");
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrapSelectExists_default_usesScalarExists() {
|
||||
String sql = CQueryBuilder.wrapSelectExists("select 1 from o_order t0 where t0.id > ?", false, "");
|
||||
assertThat(sql).isEqualTo("select exists(select 1 from o_order t0 where t0.id > ?)");
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Server does not support exists(...) as a directly selectable scalar
|
||||
* boolean expression - see https://github.com/ebean-orm/ebean/issues/3848
|
||||
*/
|
||||
@Test
|
||||
void wrapSelectExists_existsWithCaseWhen_wrapsAsCaseWhen() {
|
||||
String sql = CQueryBuilder.wrapSelectExists("select 1 from o_order t0 where t0.id > ?", true, "");
|
||||
assertThat(sql).isEqualTo("select case when exists(select 1 from o_order t0 where t0.id > ?) then 1 else 0 end");
|
||||
}
|
||||
|
||||
/**
|
||||
* Oracle also requires a FROM clause on every select (from dual) - see https://github.com/ebean-orm/ebean/issues/3848
|
||||
*/
|
||||
@Test
|
||||
void wrapSelectExists_existsWithCaseWhenAndFromClause_appendsFromClause() {
|
||||
String sql = CQueryBuilder.wrapSelectExists("select 1 from o_order t0 where t0.id > ?", true, " from dual");
|
||||
assertThat(sql).isEqualTo("select case when exists(select 1 from o_order t0 where t0.id > ?) then 1 else 0 end from dual");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineSqlCommentLabel_rootExplicitLabel_prefixesBeanType() {
|
||||
String label = CQueryBuilder.inlineSqlCommentLabel("fetchMachineFleets", null, false, "COrganisationMachine");
|
||||
|
||||
@@ -112,7 +112,9 @@ public class TestInsertCheckUnique extends BaseTestCase {
|
||||
assertThat(DB.checkUniqueness(doc2).toString()).contains("title");
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from document t0 where t0.title = ?)");
|
||||
if (isH2() || isPostgresCompatible()) {
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from document t0 where t0.title = ?)");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -135,8 +137,10 @@ public class TestInsertCheckUnique extends BaseTestCase {
|
||||
assertThat(DB.getDefault().checkUniqueness(basic, null, true, false)).isEmpty();
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from e_basicverucon t0 where t0.name = ?)");
|
||||
assertThat(sql.get(1)).contains("select exists(select 1 from e_basicverucon t0 where t0.other = ? and t0.other_one = ?)");
|
||||
if (isH2() || isPostgresCompatible()) {
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from e_basicverucon t0 where t0.name = ?)");
|
||||
assertThat(sql.get(1)).contains("select exists(select 1 from e_basicverucon t0 where t0.other = ? and t0.other_one = ?)");
|
||||
}
|
||||
DB.save(basic);
|
||||
try {
|
||||
// reload from database
|
||||
@@ -147,8 +151,10 @@ public class TestInsertCheckUnique extends BaseTestCase {
|
||||
assertThat(DB.getDefault().checkUniqueness(basic, null, true, false)).isEmpty();
|
||||
sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from e_basicverucon t0 where t0.id <> ? and t0.name = ?)");
|
||||
assertThat(sql.get(1)).contains("select exists(select 1 from e_basicverucon t0 where t0.id <> ? and t0.other = ? and t0.other_one = ?)");
|
||||
if (isH2() || isPostgresCompatible()) {
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from e_basicverucon t0 where t0.id <> ? and t0.name = ?)");
|
||||
assertThat(sql.get(1)).contains("select exists(select 1 from e_basicverucon t0 where t0.id <> ? and t0.other = ? and t0.other_one = ?)");
|
||||
}
|
||||
|
||||
// and check again - expect to hit query cache
|
||||
LoggedSql.start();
|
||||
@@ -187,8 +193,10 @@ public class TestInsertCheckUnique extends BaseTestCase {
|
||||
assertThat(DB.getDefault().checkUniqueness(basic, null, false, true)).isEmpty();
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from e_basicverucon t0 where t0.name = ?)");
|
||||
assertThat(sql.get(1)).contains("select exists(select 1 from e_basicverucon t0 where t0.other = ? and t0.other_one = ?)");
|
||||
if (isH2() || isPostgresCompatible()) {
|
||||
assertThat(sql.get(0)).contains("select exists(select 1 from e_basicverucon t0 where t0.name = ?)");
|
||||
assertThat(sql.get(1)).contains("select exists(select 1 from e_basicverucon t0 where t0.other = ? and t0.other_one = ?)");
|
||||
}
|
||||
DB.save(basic);
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
// reload from database
|
||||
|
||||
@@ -33,6 +33,8 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.dbDefaultValue.setTrue("1");
|
||||
this.dbDefaultValue.setNow("current_timestamp");
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.existsWithCaseWhen = true;
|
||||
this.existsFromClause = " from dual";
|
||||
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
|
||||
@@ -45,4 +45,11 @@ class OraclePlatformTest {
|
||||
DbPlatformType dbType = platform.dbTypeMap().get(DbPlatformType.UUID);
|
||||
assertThat(dbType.renderType(0, 0)).isEqualTo("raw(16)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsWithCaseWhen_trueForOracle() {
|
||||
OraclePlatform platform = new OraclePlatform();
|
||||
assertThat(platform.existsWithCaseWhen()).isTrue();
|
||||
assertThat(platform.existsFromClause()).isEqualTo(" from dual");
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
|
||||
this.idInExpandedForm = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.selectCountWithColumnAlias = true;
|
||||
this.existsWithCaseWhen = true;
|
||||
this.sqlLimiter = new SqlServerSqlLimiter();
|
||||
this.basicSqlLimiter = new SqlServerBasicSqlLimiter();
|
||||
this.historySupport = new SqlServerHistorySupport();
|
||||
|
||||
+6
@@ -40,6 +40,12 @@ class SqlServerPlatformTest {
|
||||
assertEquals(dbPlatform.unQuote("[firstName]"), "firstName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void existsWithCaseWhen_trueForSqlServer() {
|
||||
SqlServer17Platform dbPlatform = new SqlServer17Platform();
|
||||
assertEquals(dbPlatform.existsWithCaseWhen(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultTypesForDecimalAndVarchar() {
|
||||
DatabasePlatform dbPlatform = new DatabasePlatform();
|
||||
|
||||
Reference in New Issue
Block a user