diff --git a/src/main/java/io/ebeaninternal/server/util/BindParamsParser.java b/src/main/java/io/ebeaninternal/server/util/BindParamsParser.java index 55b5b7d69..89b344700 100644 --- a/src/main/java/io/ebeaninternal/server/util/BindParamsParser.java +++ b/src/main/java/io/ebeaninternal/server/util/BindParamsParser.java @@ -105,7 +105,7 @@ public class BindParamsParser { // search for quotes and named params... in order... int beginQuotePos = sql.indexOf(quote, startPos); - int nameParamStart = sql.indexOf(colon, startPos); + int nameParamStart = findNameStart(sql, startPos); if (beginQuotePos > 0 && beginQuotePos < nameParamStart) { // the quote precedes the named parameter... // find and add up to the end quote @@ -180,6 +180,23 @@ public class BindParamsParser { } } + /** + * Find the next named parameter start position (based on colon). + */ + static int findNameStart(String sql, int startPos) { + int colonPos = sql.indexOf(colon, startPos); + if (colonPos > -1) { + // validate the next character after the colon (ignore postgres cast) + char c = sql.charAt(colonPos + 1); + if (c == '_' || Character.isLetterOrDigit(c)) { + return colonPos; + } else { + return findNameStart(sql, colonPos + 2); + } + } + return -1; + } + /** * Add an encryption key bind parameter. */ diff --git a/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java b/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java index 47c74ebd7..c24d47b6d 100644 --- a/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java +++ b/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java @@ -160,4 +160,26 @@ public class TestRawSqlColumnParsing extends TestCase { } + public void test_doubleColon() { + + ColumnMapping columnMapping = DRawSqlColumnsParser.parse("a,MD5(id::text) as b,c"); + Map mapping = columnMapping.mapping(); + Column c = mapping.get("a"); + + assertEquals("a", c.getDbColumn()); + assertEquals(0, c.getIndexPos()); + assertEquals("a", c.getPropertyName()); + + c = mapping.get("b"); + assertEquals("MD5(id::text)", c.getDbColumn()); + assertEquals(1, c.getIndexPos()); + assertEquals("b", c.getPropertyName()); + + c = mapping.get("c"); + assertEquals("c", c.getDbColumn()); + assertEquals(2, c.getIndexPos()); + assertEquals("c", c.getPropertyName()); + + } + } diff --git a/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlParsing.java b/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlParsing.java index 3d59d2033..570509646 100644 --- a/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlParsing.java +++ b/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlParsing.java @@ -1,12 +1,24 @@ package io.ebeaninternal.server.rawsql; +import io.ebean.BaseTestCase; +import io.ebean.Ebean; import io.ebean.RawSql; -import io.ebeaninternal.server.rawsql.SpiRawSql.Sql; import io.ebean.RawSqlBuilder; -import junit.framework.TestCase; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; +import io.ebeaninternal.server.rawsql.SpiRawSql.Sql; +import org.junit.Test; +import org.tests.model.basic.Customer; +import org.tests.model.basic.ResetBasicData; -public class TestRawSqlParsing extends TestCase { +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; + +public class TestRawSqlParsing extends BaseTestCase { + + @Test public void test() { String sql @@ -24,6 +36,25 @@ public class TestRawSqlParsing extends TestCase { String s = rs.toString(); assertTrue(s, s.contains("[order_id, sum")); + } + @Test + @ForPlatform(Platform.POSTGRES) + public void testDoubleColon() { + + ResetBasicData.reset(); + + String sql = "select id, name from o_customer where name=:name and MD5(id::text) BETWEEN '00000000000000000000000000000000' AND 'ffffffffffffffffffffffffffffffff'"; + + RawSql rawSql = RawSqlBuilder + .parse(sql) + .create(); + + List list = Ebean.createQuery(Customer.class) + .setRawSql(rawSql) + .setParameter("name", "Rob") + .findList(); + + assertThat(list).isNotEmpty(); } } diff --git a/src/test/java/io/ebeaninternal/server/util/BindParamsParserTest.java b/src/test/java/io/ebeaninternal/server/util/BindParamsParserTest.java index 6b57334f4..0b874aa8f 100644 --- a/src/test/java/io/ebeaninternal/server/util/BindParamsParserTest.java +++ b/src/test/java/io/ebeaninternal/server/util/BindParamsParserTest.java @@ -32,4 +32,19 @@ public class BindParamsParserTest { assertEquals("delete from foo where id in (?,?,?,?)", sql1); } + + @Test + public void findNameStart() { + assertEquals(5, BindParamsParser.findNameStart("some :name = ?", 0)); + } + + @Test + public void findNameStart_doubleColon() { + assertEquals(-1, BindParamsParser.findNameStart("some ::name = ?", 0)); + } + + @Test + public void findNameStart_doubleColonSkip() { + assertEquals(10, BindParamsParser.findNameStart("some ::na :a = ?", 0)); + } }