OraclePlatform update (ANSI row limiting with OFFSET), Oracle11Platform for old behaviour (#1951)

* #1947 - Oracle change to use concat operator rather than function

* #1947 - setMaxRows(1).findIds() under Oracle returns wrong result

* #1950 - Change OraclePlatform to use ANSI row limiting - OFFSET and NEXT ROWS, old platform as Oracle11Platform

* Revert test default to H2

* #1947 - Oracle & Oracle11 platform
This commit is contained in:
Rob Bygrave
2020-02-22 09:28:34 +13:00
committed by GitHub
parent 2db95f909d
commit 907d36123d
35 changed files with 252 additions and 224 deletions
+3 -3
View File
@@ -175,7 +175,7 @@ public abstract class BaseTestCase {
* so tests that do this need to be skipped for SQL Server.
*/
public boolean isSqlServer() {
return Platform.SQLSERVER == platform().base();
return Platform.SQLSERVER == platform();
}
public boolean isH2() {
@@ -203,7 +203,7 @@ public abstract class BaseTestCase {
}
public boolean isMySql() {
return Platform.MYSQL == platform().base();
return Platform.MYSQL == platform();
}
public boolean isHana() {
@@ -242,7 +242,7 @@ public abstract class BaseTestCase {
}
protected Platform platform() {
return spiEbeanServer().getDatabasePlatform().getPlatform();
return spiEbeanServer().getDatabasePlatform().getPlatform().base();
}
protected IdType idType() {
@@ -27,7 +27,7 @@ public class EbeanServer_eqlTest extends BaseTestCase {
assertSql(query).startsWith("select top 100 ");
assertSql(query).endsWith("order by t0.id");
} else if (isOracle()) {
assertSql(query).contains("where rownum <= 100");
assertSql(query).contains(" fetch next 100 rows only");
} else {
assertSql(query).endsWith("order by t0.id limit 100");
}
@@ -45,7 +45,7 @@ public class EbeanServer_eqlTest extends BaseTestCase {
assertSql(query).startsWith("select top 10 ");
assertSql(query).endsWith("order by t0.id");
} else if (isOracle()) {
assertSql(query).contains("where rownum <= 10");
assertSql(query).contains(" fetch next 10 rows only");
} else {
assertSql(query).endsWith("order by t0.id limit 10");
}
@@ -62,8 +62,7 @@ public class EbeanServer_eqlTest extends BaseTestCase {
if (isSqlServer()) {
assertSql(query).endsWith("order by t0.id offset 3 rows fetch next 10 rows only");
} else if (isOracle()) {
assertSql(query).contains("where rownum <= 13");
assertSql(query).contains("where rn_ > 3");
assertSql(query).contains("offset 3 rows fetch next 10 rows only");
} else {
assertSql(query).endsWith("order by t0.id limit 10 offset 3");
}
@@ -83,8 +82,7 @@ public class EbeanServer_eqlTest extends BaseTestCase {
if (isSqlServer()) {
assertSql(query).endsWith("order by t0.name offset 3 rows fetch next 10 rows only");
} else if (isOracle()) {
assertSql(query).contains("where rownum <= 13");
assertSql(query).contains("where rn_ > 3");
assertSql(query).contains("offset 3 rows fetch next 10 rows only");
} else {
assertSql(query).endsWith("order by t0.name limit 10 offset 3");
}
@@ -110,8 +108,7 @@ public class EbeanServer_eqlTest extends BaseTestCase {
if (isSqlServer()) {
assertSql(query).endsWith("order by t0.name, t0.id offset 3 rows fetch next 10 rows only");
} else if (isOracle()) {
assertSql(query).contains("where rownum <= 13");
assertSql(query).contains("where rn_ > 3");
assertSql(query).contains("offset 3 rows fetch next 10 rows only");
} else {
assertSql(query).endsWith("order by t0.name, t0.id limit 10 offset 3");
}
@@ -140,8 +137,7 @@ public class EbeanServer_eqlTest extends BaseTestCase {
if (isSqlServer()) {
assertSql(query).endsWith("from o_customer t0 order by t0.id offset 3 rows fetch next 10 rows only");
} else if (isOracle()) {
assertSql(query).contains("where rownum <= 13");
assertSql(query).contains("where rn_ > 3");
assertSql(query).contains("offset 3 rows fetch next 10 rows only");
} else {
assertSql(query).endsWith("from o_customer t0 limit 10 offset 3");
}
@@ -159,7 +155,7 @@ public class EbeanServer_eqlTest extends BaseTestCase {
if (isSqlServer()) {
assertSql(query).startsWith("select top 10 ");
} else if (isOracle()) {
assertSql(query).contains(" a where rownum <= 10");
assertSql(query).contains("fetch next 10 rows only");
} else {
assertSql(query).endsWith("limit 10");
}
@@ -0,0 +1,18 @@
package io.ebeaninternal.server.expression.platform;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class H2DbExpressionTest {
H2DbExpression expression = new H2DbExpression();
@Test
public void concat() {
assertThat(expression.concat("p0", ",", "q1", "suffix")).isEqualTo("concat(p0,',',q1,'suffix')");
assertThat(expression.concat("p0", ",", "q1", null)).isEqualTo("concat(p0,',',q1)");
assertThat(expression.concat("p0", ",", "q1", "")).isEqualTo("concat(p0,',',q1)");
}
}
@@ -0,0 +1,18 @@
package io.ebeaninternal.server.expression.platform;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class OracleDbExpressionTest {
OracleDbExpression expression = new OracleDbExpression();
@Test
public void concat() {
assertThat(expression.concat("p0", ",", "q1", "suffix")).isEqualTo("(p0||','||q1||'suffix')");
assertThat(expression.concat("p0", ",", "q1", null)).isEqualTo("(p0||','||q1)");
assertThat(expression.concat("p0", ",", "q1", "")).isEqualTo("(p0||','||q1)");
}
}
@@ -0,0 +1,17 @@
package io.ebeaninternal.server.expression.platform;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class PostgresDbExpressionTest {
PostgresDbExpression expression = new PostgresDbExpression();
@Test
public void concat() {
assertThat(expression.concat("p0", ",", "p1", "suffix")).isEqualTo("(p0||','||p1||'suffix')");
assertThat(expression.concat("p0", ",", "p1", null)).isEqualTo("(p0||','||p1)");
assertThat(expression.concat("p0", ",", "p1", "")).isEqualTo("(p0||','||p1)");
}
}
+1 -2
View File
@@ -8,10 +8,9 @@ public class StartOracle {
public static void main(String[] args) {
OracleConfig config = new OracleConfig();
// config.setImage("quillbuilduser/oracle-18-xe:latest");
config.setUser("test_ebean");
OracleContainer container = new OracleContainer(config);
container.start();//WithDropCreate();
container.startWithDropCreate();
}
}
@@ -205,7 +205,7 @@ public class TestBatchInsertFlush extends BaseTestCase {
}
@Test
@IgnorePlatform(Platform.SQLSERVER)
@IgnorePlatform({Platform.SQLSERVER, Platform.ORACLE})
public void noflushWhenIdIsLoaded() {
EbeanServer server = Ebean.getDefaultServer();
@@ -21,7 +21,7 @@ public class MainEntity {
@SoftDelete
@Formula(select = "${ta}.id is null")
@Formula(select = "CASE WHEN ${ta}.id is null THEN 1 ELSE 0 END", platforms = Platform.SQLSERVER17)
@Formula(select = "CASE WHEN ${ta}.id is null THEN 1 ELSE 0 END", platforms = {Platform.SQLSERVER17, Platform.ORACLE})
// evaluates to true in a left join if bean has been deleted.
boolean deleted;
@@ -57,14 +57,14 @@ public class TestLazyForeignKeys extends BaseTestCase {
assertFalse(rel1.getEntity1().isDeleted());
assertTrue(rel1.getEntity2().isDeleted());
List<String> loggedSql = LoggedSqlCollector.stop();
assertThat(loggedSql).hasSize(3);
assertThat(loggedSql.get(0)).contains("select t0.id, t0.attr1, t0.id1, t0.id2 from main_entity_relation");
if (isSqlServer()) {
assertThat(loggedSql.get(1)).contains("select t0.id, t0.attr1, t0.attr2, CASE WHEN t0.id is null THEN 1 ELSE 0 END from main_entity t0");
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(3);
assertSql(sql.get(0)).contains("select t0.id, t0.attr1, t0.id1, t0.id2 from main_entity_relation");
if (isSqlServer() || isOracle()) {
assertSql(sql.get(1)).contains("select t0.id, t0.attr1, t0.attr2, CASE WHEN t0.id is null THEN 1 ELSE 0 END from main_entity t0");
} else {
assertThat(loggedSql.get(1)).contains("select t0.id, t0.attr1, t0.attr2, t0.id is null from main_entity t0");
assertThat(loggedSql.get(2)).contains("select t0.id, t0.attr1, t0.attr2, t0.id is null from main_entity t0");
assertSql(sql.get(1)).contains("select t0.id, t0.attr1, t0.attr2, t0.id is null from main_entity t0");
assertSql(sql.get(2)).contains("select t0.id, t0.attr1, t0.attr2, t0.id is null from main_entity t0");
}
}
@@ -370,7 +370,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase {
if (isH2()) {
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code) in (?,?) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})");
} else if (isPostgres()) {
} else if (isPostgres() || isOracle()) {
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code)");
} else if (isHana()) {
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, '-'||t0.code)");
@@ -413,7 +413,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase {
if (isH2()) {
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo') in (?,?) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})");
} else if (isPostgres()){
} else if (isPostgres() || isOracle()){
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo')");
} else if (isHana()){
assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, ':'||t0.code||'-foo')");
@@ -2,6 +2,8 @@ package org.tests.model.history;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.annotation.IgnorePlatform;
import io.ebean.annotation.Platform;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
@@ -12,6 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class TestHistoryOneToMany extends BaseTestCase {
@IgnorePlatform(Platform.ORACLE)
@Test
public void test() {
@@ -19,7 +19,7 @@ public class EUserNoFkSoftDel {
@SoftDelete
@Formula(select = "${ta}.user_id is null")
@Formula(select = "CASE WHEN ${ta}.user_id is null THEN 1 ELSE 0 END", platforms = Platform.SQLSERVER17)
@Formula(select = "CASE WHEN ${ta}.user_id is null THEN 1 ELSE 0 END", platforms = {Platform.SQLSERVER17, Platform.ORACLE})
// evaluates to true in a left join if bean has been deleted.
boolean deleted;
@@ -27,8 +27,9 @@ public class TestNoFk extends BaseTestCase {
Ebean.find(EUserNoFk.class).delete();
Ebean.find(EUserNoFkSoftDel.class).delete();
Ebean.createSqlUpdate("delete from efile_no_fk_euser_no_fk").execute();
Ebean.createSqlUpdate("delete from efile_no_fk_euser_no_fk_soft_del").execute();
DB.sqlUpdate("delete from efile_no_fk_euser_no_fk").execute();
String tabName = isOracle() ? "efile_no_fk_euser_no_fk_soft_d" : "efile_no_fk_euser_no_fk_soft_del";
DB.sqlUpdate("delete from " + tabName).execute();
// There are two user accounts persisted in our database
EUserNoFk root = new EUserNoFk();
@@ -39,7 +39,7 @@ public class TestOneToOneOrphanRemove extends BaseTestCase {
assertSqlBind(sql.get(1));
assertSql(sql.get(2)).contains("update oto_cust set version=? where cid=? and version=?");
assertThat(sql.get(3)).contains("insert into oto_cust_address ");
assertThat(sql.get(4)).contains("-- bind(other1");
assertThat(sql.get(4)).contains("-- bind(");
jack.setAddress(null);
Ebean.save(jack);
@@ -22,7 +22,7 @@ public class TestQueryOrderById extends BaseTestCase {
query.findList();
if (isSqlServer()) {
assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id offset 1 rows fetch next 5 rows only");
} else {
} else if (!isOracle()) {
assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id limit 5 offset 1");
}
}
@@ -39,7 +39,7 @@ public class TestQueryOrderById extends BaseTestCase {
query.findList();
if (isSqlServer()) {
assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id offset 1 rows fetch next 5 rows only");
} else {
} else if (!isOracle()) {
assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id limit 5 offset 1");
}
}
@@ -229,8 +229,10 @@ public class TestCustomerFinder extends BaseTestCase {
assertThat(metricsJson).contains("\"name\":\"txn.main\"");
assertThat(metricsJson).contains("\"name\":\"orm.Customer.findList\"");
assertThat(metricsJson).contains("\"loc\":\"CustomerFinder.byNameStatus(CustomerFinder.java:44)\"");
assertThat(metricsJson).contains("\"hash\":\"cc20eb930403cfd418db2d0475c6e26a\"");
assertThat(metricsJson).contains("\"sql\":\"select t0.id, t0.status,");
if (!isOracle()) {
assertThat(metricsJson).contains("\"hash\":\"cc20eb930403cfd418db2d0475c6e26a\"");
assertThat(metricsJson).contains("\"sql\":\"select t0.id, t0.status,");
}
}
@Test
@@ -191,8 +191,7 @@ public class TestQuerySingleAttribute extends BaseTestCase {
if (isSqlServer()) {
assertThat(sqlOf(query)).contains("select distinct top 100 t0.id from o_customer t0");
} else if (isOracle()) {
assertThat(sqlOf(query)).contains("from ( select distinct t0.id from o_customer t0");
assertThat(sqlOf(query)).contains("where rownum <= 100");
assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 fetch next 100 rows only");
} else {
assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 limit 100");
}
@@ -271,7 +270,7 @@ public class TestQuerySingleAttribute extends BaseTestCase {
if (isSqlServer()) {
assertThat(sqlOf(query)).contains("select top 100 t0.id from o_customer t0");
} else if (isOracle()) {
assertThat(sqlOf(query)).contains("where rownum <= 100");
assertThat(sqlOf(query)).contains("fetch next 100 rows only");
} else {
assertThat(sqlOf(query)).contains("select t0.id from o_customer t0 limit 100");
}
@@ -583,16 +582,23 @@ public class TestQuerySingleAttribute extends BaseTestCase {
.where().isNotNull("customer.billingAddress.line1").query()
.setCountDistinct(CountDistinctOrder.ATTR_DESC)
.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*) from ("
+ "select t2.line_1 as attribute_ from contact t0 "
+ "join o_customer t1 on t1.id = t0.customer_id "
+ "left join o_address t2 on t2.id = t1.billing_address_id "
+ "where t2.line_1 is not null"
+ ") r1 group by r1.attribute_ order by r1.attribute_ desc ");
if (isOracle()) {
assertSql(query).contains("select r1.attribute_, count(*) from (select t2.line_1 as attribute_ from contact t0 join o_customer t1 on t1.id = t0.customer_id left join o_address t2 on t2.id = t1.billing_address_id where t2.line_1 is not null) r1 group by r1.attribute_ order by r1.attribute_ desc offset 1 rows fetch next 2 rows only");
} else {
assertSql(query).contains("select r1.attribute_, count(*) from ("
+ "select t2.line_1 as attribute_ from contact t0 "
+ "join o_customer t1 on t1.id = t0.customer_id "
+ "left join o_address t2 on t2.id = t1.billing_address_id "
+ "where t2.line_1 is not null"
+ ") r1 group by r1.attribute_ order by r1.attribute_ desc ");
}
if (isSqlServer()) {
assertThat(sqlOf(query)).endsWith(" fetch next 2 rows only");
} else if (isDb2()) {
assertSql(query).endsWith("FETCH FIRST 2 ROWS ONLY");
} else if (isOracle()) {
assertSql(query).contains(" offset 1 rows fetch next 2 rows only");
} else {
assertThat(sqlOf(query)).endsWith(" limit 2 offset 1");
}
@@ -219,7 +219,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase {
assertSql(query).contains("top 100 ");
assertSql(query).contains("order by o.ship_date desc");
} else if (isOracle()) {
assertSql(query).contains("a where rownum <= 100 )");
assertSql(query).contains("fetch next 100 rows only");
} else {
assertSql(query).contains("order by o.ship_date desc limit 100");
}
@@ -254,7 +254,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase {
assertSql(query).contains("top 100 ");
assertSql(query).contains("order by o.ship_date desc, o.id");
} else if (isOracle()) {
assertSql(query).contains("a where rownum <= 100 )");
assertSql(query).contains("fetch next 100 rows only");
} else {
assertSql(query).contains("order by o.ship_date desc, o.id limit 100");
}
@@ -356,7 +356,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase {
assertThat(sqlOf(query)).contains("select top 100 ");
assertThat(sqlOf(query)).contains("order by o.id desc");
} else if (isOracle()) {
assertThat(sqlOf(query)).contains("a where rownum <= 100 )");
assertThat(sqlOf(query)).contains("fetch next 100 rows only");
} else {
assertThat(sqlOf(query)).contains("order by o.id desc limit 100");
}
@@ -65,7 +65,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
}
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA})
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA, Platform.ORACLE})
@Test
public void nestedUseSavepoint_doubleNested_rollbackCommit() {
@@ -102,7 +102,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
}
}
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA})
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA, Platform.ORACLE})
@Test
public void nestedUseSavepoint_doubleNested_commitRollback() {
@@ -139,7 +139,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
}
}
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA})
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA, Platform.ORACLE})
@Test
public void nestedUseSavepoint_nested_RequiresNew() {
@@ -175,7 +175,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
assertNull(after);
}
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA})
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA, Platform.ORACLE})
@Test
public void nestedUseSavepoint() {