diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 73c8d8274..6ae16cf34 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -175,7 +175,7 @@ public class DatabasePlatform { protected SqlExceptionTranslator exceptionTranslator = new SqlCodeTranslator(); - protected char[] specialLikeCharacters = { '%', '_' }; + protected char[] specialLikeCharacters = { '%', '_', '\\' }; /** * Instantiates a new database platform. diff --git a/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java b/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java index 0c9558cc4..ccc9b9fc6 100644 --- a/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java +++ b/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java @@ -26,7 +26,10 @@ public class DB2Platform extends DatabasePlatform { this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsSequence(true); - + + this.likeClause = "like ? escape '|'"; + this.specialLikeCharacters = new char[] { '%', '_', '|' }; + this.exceptionTranslator = new SqlErrorCodes() .addAcquireLock("40001","57033") // key -911/-913 @@ -46,6 +49,10 @@ public class DB2Platform extends DatabasePlatform { persistBatchOnCascade = PersistBatch.NONE; } + @Override + protected void escapeLikeCharacter(char ch, StringBuilder sb) { + sb.append('|').append(ch); + } /** * Return a DB2 specific sequence IdGenerator that supports batch fetching * sequence values. 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 93b82d389..ee37d0c37 100644 --- a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java @@ -48,6 +48,9 @@ public class MySqlPlatform extends DatabasePlatform { this.openQuote = "`"; this.closeQuote = "`"; + // use pipe for escaping as it depends if mysql runs in no_backslash_escapes or not. + this.likeClause = "like binary ? escape '|'"; + this.specialLikeCharacters = new char[] { '%', '_', '|' }; this.forwardOnlyHintOnFindIterate = true; this.booleanDbType = Types.BIT; @@ -76,4 +79,9 @@ public class MySqlPlatform extends DatabasePlatform { // NOWAIT and SKIP LOCKED currently not supported with MySQL return sql + " for update"; } + + @Override + protected void escapeLikeCharacter(char ch, StringBuilder sb) { + sb.append('|').append(ch); + } } diff --git a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java index 57bebab7d..b8c3c6a4a 100644 --- a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java @@ -37,6 +37,9 @@ public class OraclePlatform extends DatabasePlatform { this.treatEmptyStringsAsNull = true; + this.likeClause = "like ? escape '|'"; + this.specialLikeCharacters = new char[] { '%', '_', '|' }; + this.openQuote = "\""; this.closeQuote = "\""; @@ -78,4 +81,9 @@ public class OraclePlatform extends DatabasePlatform { return sql + " for update"; } } + + @Override + protected void escapeLikeCharacter(char ch, StringBuilder sb) { + sb.append('|').append(ch); + } } diff --git a/src/test/java/io/ebean/EbeanServer_eqlTest.java b/src/test/java/io/ebean/EbeanServer_eqlTest.java index eaf7c4482..360b3e941 100644 --- a/src/test/java/io/ebean/EbeanServer_eqlTest.java +++ b/src/test/java/io/ebean/EbeanServer_eqlTest.java @@ -135,7 +135,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { query.setParameter("name", "Ro"); query.findList(); - assertThat(query.getGeneratedSql()).contains("where t0.name like ? "); + assertThat(query.getGeneratedSql()).contains("where t0.name like "); } @Test(expected = PersistenceException.class) diff --git a/src/test/java/io/ebeaninternal/server/expression/DefaultExampleExpressionTest.java b/src/test/java/io/ebeaninternal/server/expression/DefaultExampleExpressionTest.java index 29736f21a..00ba20dc2 100644 --- a/src/test/java/io/ebeaninternal/server/expression/DefaultExampleExpressionTest.java +++ b/src/test/java/io/ebeaninternal/server/expression/DefaultExampleExpressionTest.java @@ -86,8 +86,8 @@ public class DefaultExampleExpressionTest extends BaseExpressionTest { query1.findList(); - assertThat(query1.getGeneratedSql()).contains("(t0.name like ? "); - assertThat(query1.getGeneratedSql()).contains(" and t1.city like ? "); + assertThat(query1.getGeneratedSql()).contains("(t0.name like "); + assertThat(query1.getGeneratedSql()).contains(" and t1.city like "); } diff --git a/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java b/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java index 395680f48..03f043a8c 100644 --- a/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java +++ b/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java @@ -123,7 +123,7 @@ public class EqlParserTest extends BaseTestCase { query.setParameter("name", "Rob"); query.findList(); - assertThat(query.getGeneratedSql()).contains("where t0.name like ?"); + assertThat(query.getGeneratedSql()).contains("where t0.name like "); } @Test diff --git a/src/test/java/org/tests/batchload/TestBatchLazyWithCacheHits.java b/src/test/java/org/tests/batchload/TestBatchLazyWithCacheHits.java index c92149168..6246e4212 100644 --- a/src/test/java/org/tests/batchload/TestBatchLazyWithCacheHits.java +++ b/src/test/java/org/tests/batchload/TestBatchLazyWithCacheHits.java @@ -78,7 +78,7 @@ public class TestBatchLazyWithCacheHits extends BaseTestCase { // batch lazy loading into cache assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("from uuone t0 where t0.name like ?"); + assertThat(sql.get(0)).contains("from uuone t0 where t0.name like "); assertThat(sql.get(1)).contains("from uuone t0 where t0.id in (?,"); statistics = beanCache.getStatistics(true); diff --git a/src/test/java/org/tests/query/TestExprNestedDisjunction.java b/src/test/java/org/tests/query/TestExprNestedDisjunction.java index c6df4fd0d..02125bc64 100644 --- a/src/test/java/org/tests/query/TestExprNestedDisjunction.java +++ b/src/test/java/org/tests/query/TestExprNestedDisjunction.java @@ -27,7 +27,7 @@ public class TestExprNestedDisjunction extends BaseTestCase { q.findList(); String s = q.getGeneratedSql(); - assertThat(s).contains("(t0.name like ? "); + assertThat(s).contains("(t0.name like "); assertThat(s).contains(" and t0.anniversary = ? ) or (t0.status = ? and t0.id > ? )"); } @@ -51,7 +51,7 @@ public class TestExprNestedDisjunction extends BaseTestCase { q.findList(); String s = q.getGeneratedSql(); - assertThat(s).contains("(t0.name like ? "); + assertThat(s).contains("(t0.name like "); assertThat(s).contains(" and t0.anniversary = ? ) or (t0.status = ? and t0.id > ? )"); } diff --git a/src/test/java/org/tests/query/TestQueryFetchManyTwoDeep.java b/src/test/java/org/tests/query/TestQueryFetchManyTwoDeep.java index bf667c46e..de846ef20 100644 --- a/src/test/java/org/tests/query/TestQueryFetchManyTwoDeep.java +++ b/src/test/java/org/tests/query/TestQueryFetchManyTwoDeep.java @@ -154,7 +154,7 @@ public class TestQueryFetchManyTwoDeep extends BaseTestCase { Assert.assertTrue(generatedSql.contains("from contact t0 ")); Assert.assertTrue(generatedSql.contains("join o_customer t1 on t1.id = t0.customer_id")); - Assert.assertTrue(generatedSql.contains("where lower(t1.name) like ?")); + Assert.assertTrue(generatedSql.contains("where lower(t1.name) like ")); } diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 8b837b105..12d05c37b 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -82,7 +82,7 @@ public class TestAggregationCount extends BaseTestCase { String sql = sqlOf(query2, 5); assertThat(sql).contains("select t0.id, t0.name, count(u1.id), sum(u1.units), sum(u1.units * u1.amount) from tevent_one t0"); assertThat(sql).contains("from tevent_one t0 join tevent_many u1 on u1.event_id = t0.id "); - assertThat(sql).contains("where u1.description like ? "); + assertThat(sql).contains("where u1.description like "); assertThat(sql).contains(" group by t0.id, t0.name having count(u1.id) >= ? order by t0.name"); // invoke lazy loading diff --git a/src/test/java/org/tests/query/joins/TestQueryManyToOneWhereClauseJoin.java b/src/test/java/org/tests/query/joins/TestQueryManyToOneWhereClauseJoin.java index 4516d2dbe..abb33a17a 100644 --- a/src/test/java/org/tests/query/joins/TestQueryManyToOneWhereClauseJoin.java +++ b/src/test/java/org/tests/query/joins/TestQueryManyToOneWhereClauseJoin.java @@ -26,7 +26,7 @@ public class TestQueryManyToOneWhereClauseJoin extends BaseTestCase { query.findList(); //select t0.id c0, t0.status c1, t0.order_date c2, t0.ship_date c3, t1.name c4, t0.cretime c5, t0.updtime c6, t0.kcustomer_id c7 - String expectedSql = "from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where lower(t1.name) like ? "; + String expectedSql = "from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where lower(t1.name) like "; Assert.assertTrue(query.getGeneratedSql().contains(expectedSql)); // select t0.id c0, t0.status c1, t0.order_date c2, t0.ship_date c3, t1.name c4, t0.cretime c5, t0.updtime c6, t0.kcustomer_id c7 @@ -50,7 +50,7 @@ public class TestQueryManyToOneWhereClauseJoin extends BaseTestCase { query.findList(); //select t0.id c0, t0.status c1, t0.order_date c2, t0.ship_date c3, t1.name c4, t0.cretime c5, t0.updtime c6, t0.kcustomer_id c7 - String expectedSql = "from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where (lower(t1.name) like ? "; + String expectedSql = "from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where (lower(t1.name) like "; Assert.assertTrue(query.getGeneratedSql().contains(expectedSql)); // select t0.id c0, t0.status c1, t0.order_date c2, t0.ship_date c3, t1.name c4, t0.cretime c5, t0.updtime c6, t0.kcustomer_id c7 @@ -80,7 +80,7 @@ public class TestQueryManyToOneWhereClauseJoin extends BaseTestCase { String generatedSql = query.getGeneratedSql(); Assert.assertTrue(generatedSql.contains("from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id")); Assert.assertTrue(generatedSql.contains("left join contact t2 on t2.customer_id = t1.id")); - Assert.assertTrue(generatedSql.contains("where lower(t1.name) like ?")); + Assert.assertTrue(generatedSql.contains("where lower(t1.name) like ")); // select t0.id c0, t0.status c1, t0.order_date c2, t0.ship_date c3, t1.name c4, t0.cretime c5, t0.updtime c6, // t1.id c7, t1.status c8, t1.name c9, t1.smallnote c10, t1.anniversary c11, t1.cretime c12, t1.updtime c13, t1.billing_address_id c14, t1.shipping_address_id c15, diff --git a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java index c80be3698..0f0123d0d 100644 --- a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java +++ b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinctTake2.java @@ -46,7 +46,7 @@ public class TestOrderByWithDistinctTake2 extends BaseTestCase { } assertThat(generatedSql).contains("order by t0.name desc"); assertThat(generatedSql).contains("from o_customer t0 join contact u1 on u1.customer_id = t0.id"); - assertThat(generatedSql).contains("where lower(u1.first_name) like ?"); + assertThat(generatedSql).contains("where lower(u1.first_name) like "); } @Test @@ -68,7 +68,7 @@ public class TestOrderByWithDistinctTake2 extends BaseTestCase { } assertThat(generatedSql).contains("order by t0.name, t0.id desc"); assertThat(generatedSql).contains("from o_customer t0 join contact u1 on u1.customer_id = t0.id"); - assertThat(generatedSql).contains("where lower(u1.first_name) like ?"); + assertThat(generatedSql).contains("where lower(u1.first_name) like "); } } diff --git a/src/test/java/org/tests/query/other/TestLikeEscaping.java b/src/test/java/org/tests/query/other/TestLikeEscaping.java index a9fbc5fe9..341348cca 100644 --- a/src/test/java/org/tests/query/other/TestLikeEscaping.java +++ b/src/test/java/org/tests/query/other/TestLikeEscaping.java @@ -22,11 +22,19 @@ public class TestLikeEscaping extends BaseTestCase { Ebean.save(ResetBasicData.createCustomer("Paul %% Doublepercentage", "|Pipeway", "[other]", 1, null)); Ebean.save(ResetBasicData.createCustomer("_Udo Underscore", "|Pipeway", "[other]", 1, null)); + Ebean.save(ResetBasicData.createCustomer("Bodo \\ backslash", "\\BS", "[other]", 1, null)); assertThat(Ebean.find(Customer.class) .where().contains("name", "Paul %%").findCount() ).isEqualTo(1); + assertThat(Ebean.find(Customer.class) + .where().contains("name", "o \\ b").findCount() + ).isEqualTo(1); + + assertThat(Ebean.find(Customer.class) + .where().contains("name", "o \\\\ b").findCount() + ).isEqualTo(0); assertThat(Ebean.find(Customer.class) .where().startsWith("name", "_").findCount() @@ -48,10 +56,13 @@ public class TestLikeEscaping extends BaseTestCase { .where().startsWith("shippingAddress.line1", "|P").findCount() ).isEqualTo(2); - + assertThat(Ebean.find(Customer.class) + .where().startsWith("shippingAddress.line1", "\\B").findCount() + ).isEqualTo(1); + assertThat(Ebean.find(Customer.class) .where().endsWith("billingAddress.line1", "]").findCount() - ).isEqualTo(4); + ).isEqualTo(5); assertThat(Ebean.find(Customer.class) .where().endsWith("billingAddress.line1", "[none]").findCount() diff --git a/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java b/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java index 2bc51aa76..b02a53c2f 100644 --- a/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java +++ b/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java @@ -112,7 +112,7 @@ public class TestQuerySingleAttribute extends BaseTestCase { List names = query.findSingleAttributeList(); - assertThat(sqlOf(query)).contains("select distinct t0.name from o_customer t0 left join o_address t1 on t1.id = t0.billing_address_id where t0.status = ? and lower(t1.city) like ?"); + assertThat(sqlOf(query)).contains("select distinct t0.name from o_customer t0 left join o_address t1 on t1.id = t0.billing_address_id where t0.status = ? and lower(t1.city) like "); assertThat(names).isNotNull(); }