Author: mtylenda
Date: Sun Jul  3 12:32:03 2011
New Revision: 1142426

URL: http://svn.apache.org/viewvc?rev=1142426&view=rev
Log:
OPENJPA-487: Simplify generated SQL for SUBSTRING and LOCATE JPQL functions by 
switching from JDO style to JPA style in expressions. SUBSTRING parameters are 
still inlined to support grouping by SUBSTRING.

Added:
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestLocate.java
   (with props)
Modified:
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Substring.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractSQLServerDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/FirebirdDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/HSQLDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/IngresDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JDataStoreDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PointbaseDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/IndexOf.java
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Substring.java
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestSubstring.java
    
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Substring.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Substring.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Substring.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Substring.java
 Sun Jul  3 12:32:03 2011
@@ -127,16 +127,16 @@ public class Substring
         BinaryOpExpState bstate = (BinaryOpExpState) state;
         FilterValue str = new FilterValueImpl(sel, ctx, bstate.state1, _val1);
         FilterValue start;
-        FilterValue end = null;
+        FilterValue length = null;
         if (_val2 instanceof Args) {
             FilterValue[] filts = ((Args) _val2).newFilterValues(sel, ctx, 
                 bstate.state2);
             start = filts[0];
-            end = filts[1];
+            length = filts[1];
         } else
             start = new FilterValueImpl(sel, ctx, bstate.state2, _val2);
 
-        ctx.store.getDBDictionary().substring(sql, str, start, end);
+        ctx.store.getDBDictionary().substring(sql, str, start, length);
     }
 
     public void acceptVisit(ExpressionVisitor visitor) {

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java
 Sun Jul  3 12:32:03 2011
@@ -73,7 +73,7 @@ public abstract class AbstractDB2Diction
 
     public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
         FilterValue start) {
-        buf.append("(LOCATE(CAST((");
+        buf.append("LOCATE(CAST((");
         find.appendTo(buf);
         buf.append(") AS VARCHAR(").append(Integer.toString(varcharCastLength))
             .append(")), CAST((");
@@ -83,37 +83,32 @@ public abstract class AbstractDB2Diction
         if (start != null) {
             buf.append(", CAST((");
             start.appendTo(buf);
-            buf.append(") AS INTEGER) + 1");
+            buf.append(") AS INTEGER)");
         }
-        buf.append(") - 1)");
+        buf.append(")");
     }
 
+    @Override
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-        FilterValue end) {
+        FilterValue length) {
         buf.append("SUBSTR(CAST((");
         str.appendTo(buf);
         buf.append(") AS VARCHAR(").append(Integer.toString(varcharCastLength))
             .append(")), ");
         if (start.getValue() instanceof Number) {
-            long startLong = toLong(start);
-            buf.append(Long.toString(startLong + 1));
+            buf.append(Long.toString(toLong(start)));
         } else {
             buf.append("CAST((");
             start.appendTo(buf);
-            buf.append(") AS INTEGER) + 1");
+            buf.append(") AS INTEGER)");
         }
-        if (end != null) {
+        if (length != null) {
             buf.append(", ");
-            if (start.getValue() instanceof Number
-                && end.getValue() instanceof Number) {
-                long startLong = toLong(start);
-                long endLong = toLong(end);
-                buf.append(Long.toString(endLong - startLong));
+            if (length.getValue() instanceof Number) {
+                buf.append(Long.toString(toLong(length)));
             } else {
                 buf.append("CAST((");
-                end.appendTo(buf);
-                buf.append(") AS INTEGER) - CAST((");
-                start.appendTo(buf);
+                length.appendTo(buf);
                 buf.append(") AS INTEGER)");
             }
         }

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractSQLServerDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractSQLServerDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractSQLServerDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractSQLServerDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -120,23 +120,20 @@ public abstract class AbstractSQLServerD
     }
 
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-        FilterValue end) {
-        if (end != null)
-            super.substring(buf, str, start, end);
+        FilterValue length) {
+        if (length != null)
+            super.substring(buf, str, start, length);
         else {
-            // ### it would be good to change this logic as in DBDictionary to
-            // ### simplify the generated SQL
             buf.append("SUBSTRING(");
             str.appendTo(buf);
             buf.append(", ");
             start.appendTo(buf);
-            buf.append(" + 1, ");
-            buf.append("LEN(");
+            buf.append(", LEN(");
             str.appendTo(buf);
             buf.append(")");
             buf.append(" - (");
             start.appendTo(buf);
-            buf.append("))");
+            buf.append(" - 1))");
         }
     }
 
@@ -149,9 +146,9 @@ public abstract class AbstractSQLServerD
             substring(buf, str, start, null);
         else
             str.appendTo(buf);
-        buf.append(") - 1");
+        buf.append(")");
         if (start != null) {
-            buf.append(" + ");
+            buf.append(" - 1 + ");
             start.appendTo(buf);
         }
         buf.append(")");

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
 Sun Jul  3 12:32:03 2011
@@ -829,12 +829,12 @@ public class DB2Dictionary
     public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
             FilterValue start) {
         if (find.getValue() != null) { // non constants
-            buf.append("(LOCATE(CAST((");
+            buf.append("LOCATE(CAST((");
             find.appendTo(buf);
             buf.append(") AS VARCHAR(1000)), ");
         } else {
             // this is a constant
-            buf.append("(LOCATE(");
+            buf.append("LOCATE(");
             find.appendTo(buf);
             buf.append(", ");
         }
@@ -846,16 +846,16 @@ public class DB2Dictionary
             str.appendTo(buf);
         }
         if (start != null) {
-            if (start.getValue() == null) {
+            if (start.getValue() != null) {
                 buf.append(", CAST((");
                 start.appendTo(buf);
-                buf.append(") AS INTEGER) + 1");
+                buf.append(") AS INTEGER)");
             } else {
                 buf.append(", ");
                 start.appendTo(buf);
             }
         }
-        buf.append(") - 1)");
+        buf.append(")");
     }
     
     /** 

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -2745,37 +2745,30 @@ public class DBDictionary
 
     /**
      * Invoke this database's substring function.
+     * Numeric parameters are inlined if possible. This is to handle grouping 
by SUBSTRING -
+     * most databases do not allow parameter binding in this case.
      *
      * @param buf the SQL buffer to write the substring invocation to
      * @param str a query value representing the target string
      * @param start a query value representing the start index
-     * @param end a query value representing the end index, or null for none
+     * @param length a query value representing the length of substring, or 
null for none
      */
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-        FilterValue end) {
+        FilterValue length) {
         buf.append(substringFunctionName).append("(");
         str.appendTo(buf);
         buf.append(", ");
         if (start.getValue() instanceof Number) {
-            long startLong = toLong(start);
-            buf.append(Long.toString(startLong + 1));
+            buf.append(Long.toString(toLong(start)));
         } else {
-            buf.append("(");
             start.appendTo(buf);
-            buf.append(" + 1)");
         }
-        if (end != null) {
+        if (length != null) {
             buf.append(", ");
-            if (start.getValue() instanceof Number
-                && end.getValue() instanceof Number) {
-                long startLong = toLong(start);
-                long endLong = toLong(end);
-                buf.append(Long.toString(endLong - startLong));
+            if (length.getValue() instanceof Number) {
+                buf.append(Long.toString(toLong(length)));
             } else {
-                end.appendTo(buf);
-                buf.append(" - (");
-                start.appendTo(buf);
-                buf.append(")");
+                length.appendTo(buf);
             }
         }
         buf.append(")");
@@ -2803,9 +2796,9 @@ public class DBDictionary
             str.appendTo(buf);
         buf.append("), (");
         find.appendTo(buf);
-        buf.append(")) - 1");
+        buf.append("))");
         if (start != null) {
-            buf.append(" + ");
+            buf.append(" - 1  + ");
             start.appendTo(buf);
         }
         buf.append(")");

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/FirebirdDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/FirebirdDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/FirebirdDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/FirebirdDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -402,28 +402,26 @@ public class FirebirdDictionary
      * Parameters are inlined because neither parameter binding nor expressions
      * are accepted by Firebird here. As a result, an
      * {@link UnsupportedException} is thrown when something else than a
-     * constant is used in <code>start</code> or <code>end</code>.
+     * constant is used in <code>start</code> or <code>length</code>.
      */
     @Override
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-        FilterValue end) {
+        FilterValue length) {
         buf.append(substringFunctionName).append("(");
         str.appendTo(buf);
         buf.append(" FROM ");
         if (start.getValue() instanceof Number) {
             long startLong = toLong(start);
-            buf.append(Long.toString(startLong + 1));
+            buf.append(Long.toString(startLong));
         } else {
             throw new UnsupportedException(_loc.get("function-not-supported",
                 getClass(), substringFunctionName + " with non-constants"));
         }
-        if (end != null) {
+        if (length != null) {
             buf.append(" FOR ");
-            if (start.getValue() instanceof Number
-                && end.getValue() instanceof Number) {
-                long startLong = toLong(start);
-                long endLong = toLong(end);
-                buf.append(Long.toString(endLong - startLong));
+            if (length.getValue() instanceof Number) {
+                long lengthLong = toLong(length);
+                buf.append(Long.toString(lengthLong));
             } else {
                 throw new UnsupportedException(_loc.get(
                     "function-not-supported", getClass(), substringFunctionName

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java
 Sun Jul  3 12:32:03 2011
@@ -232,9 +232,9 @@ public class H2Dictionary extends DBDict
             substring(buf, str, start, null);
         else
             str.appendTo(buf);
-        buf.append(") - 1");
+        buf.append(")");
         if (start != null) {
-            buf.append(" + ");
+            buf.append(" - 1 + ");
             start.appendTo(buf);
         }
         buf.append(")");

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/HSQLDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/HSQLDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/HSQLDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/HSQLDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -345,16 +345,15 @@ public class HSQLDictionary extends DBDi
     @Override
     public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
         FilterValue start) {
-        buf.append("(LOCATE(");
+        buf.append("LOCATE(");
         find.appendTo(buf);
         buf.append(", ");
         str.appendTo(buf);
         if (start != null) {
-            buf.append(", (");
+            buf.append(", ");
             start.appendTo(buf);
-            buf.append(" + 1)");
         }
-        buf.append(") - 1)");
+        buf.append(")");
     }
 
     @Override

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/IngresDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/IngresDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/IngresDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/IngresDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -260,7 +260,6 @@ public class IngresDictionary extends DB
      *            - a query value representing the start index, or null to 
      *            start at the beginning
      */
-
     @Override
     public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
         FilterValue start) {
@@ -273,10 +272,10 @@ public class IngresDictionary extends DB
         else
             str.appendTo(buf);
         
-        buf.append(")) - 1");
+        buf.append("))");
 
         if (start != null) {
-            buf.append(" + ");
+            buf.append(" - 1 + ");
             start.appendTo(buf);
         }
         buf.append(")");
@@ -291,30 +290,24 @@ public class IngresDictionary extends DB
      */
     @Override
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-        FilterValue end) {
+        FilterValue length) {
         buf.append(substringFunctionName).append("(");
         str.appendTo(buf);
         buf.append(", ");
         if (start.getValue() instanceof Number) {
-            long startLong = toLong(start);
-            buf.append(Long.toString(startLong + 1));
+            buf.append(Long.toString(toLong(start)));
         } else {
             buf.append("(CAST ((");
             start.appendTo(buf);
-            buf.append(" + 1) AS INTEGER))");
+            buf.append(") AS INTEGER))");
         }
-        if (end != null) {
+        if (length != null) {
             buf.append(", ");
-            if (start.getValue() instanceof Number
-                && end.getValue() instanceof Number) {
-                long startLong = toLong(start);
-                long endLong = toLong(end);
-                buf.append(Long.toString(endLong - startLong));
+            if (length.getValue() instanceof Number) {
+                buf.append(Long.toString(toLong(length)));
             } else {
-                buf.append("(CAST (");
-                end.appendTo(buf);
-                buf.append(" - (");
-                start.appendTo(buf);
+                buf.append("(CAST ((");
+                length.appendTo(buf);
                 buf.append(") AS INTEGER))");
             }
         }

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JDataStoreDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JDataStoreDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JDataStoreDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JDataStoreDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -69,21 +69,21 @@ public class JDataStoreDictionary
 
     @Override
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-        FilterValue end) {
+        FilterValue length) {
         buf.append("SUBSTRING(");
         str.appendTo(buf);
         buf.append(" FROM (");
         start.appendTo(buf);
-        buf.append(" + 1) FOR (");
-        if (end == null) {
+        buf.append(") FOR (");
+        if (length == null) {
             buf.append("CHAR_LENGTH(");
             str.appendTo(buf);
             buf.append(")");
         } else
-            end.appendTo(buf);
+            length.appendTo(buf);
         buf.append(" - (");
         start.appendTo(buf);
-        buf.append(")))");
+        buf.append(" - 1)))");
     }
 
     @Override
@@ -96,9 +96,9 @@ public class JDataStoreDictionary
             substring(buf, str, start, null);
         else
             str.appendTo(buf);
-        buf.append(") - 1");
+        buf.append(")");
         if (start != null) {
-            buf.append(" + ");
+            buf.append(" - 1 + ");
             start.appendTo(buf);
         }
         buf.append(")");

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PointbaseDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PointbaseDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PointbaseDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PointbaseDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -103,20 +103,16 @@ public class PointbaseDictionary
     }
 
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-        FilterValue end) {
+        FilterValue length) {
         // SUBSTRING in Pointbase is of the form:
         // SELECT SUBSTRING(SOME_COLUMN FROM 1 FOR 5)
         buf.append("SUBSTRING(");
         str.appendTo(buf);
         buf.append(" FROM ");
         start.appendTo(buf);
-        buf.append(" + 1");
-        if (end != null) {
+        if (length != null) {
             buf.append(" FOR ");
-            end.appendTo(buf);
-            buf.append(" - (");
-            start.appendTo(buf);
-            buf.append(")");
+            length.appendTo(buf);
         }
         buf.append(")");
     }
@@ -130,9 +126,9 @@ public class PointbaseDictionary
             substring(buf, str, start, null);
         else
             str.appendTo(buf);
-        buf.append(") - 1");
+        buf.append(")");
         if (start != null) {
-            buf.append(" + ");
+            buf.append(" - 1 + ");
             start.appendTo(buf);
         }
         buf.append(")");

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -352,9 +352,9 @@ public class PostgresDictionary
             substring(buf, str, start, null);
         else
             str.appendTo(buf);
-        buf.append(") - 1");
+        buf.append(")");
         if (start != null) {
-            buf.append(" + ");
+            buf.append(" - 1 + ");
             start.appendTo(buf);
         }
         buf.append(")");

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java
 Sun Jul  3 12:32:03 2011
@@ -317,20 +317,17 @@ public class SolidDBDictionary
     
     @Override
     public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
-            FilterValue end) {
-        if (end != null) {
-            super.substring(buf, str, start, end);
+            FilterValue length) {
+        if (length != null) {
+            super.substring(buf, str, start, length);
         } else {
             buf.append(substringFunctionName).append("(");
             str.appendTo(buf);
             buf.append(", ");
             if (start.getValue() instanceof Number) {
-                long startLong = toLong(start);
-                buf.append(Long.toString(startLong + 1));
+                buf.append(Long.toString(toLong(start)));
             } else {
-                buf.append("(");
                 start.appendTo(buf);
-                buf.append(" + 1)");
             }
             buf.append(", ");
             if (start.getValue() instanceof Number) {
@@ -350,22 +347,15 @@ public class SolidDBDictionary
     @Override
     public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
         FilterValue start) {
-        buf.append("(LOCATE(");
+        buf.append("LOCATE(");
         find.appendTo(buf);
         buf.append(", ");
         str.appendTo(buf);
         if (start != null) {
             buf.append(", ");
-            if (start.getValue() instanceof Number) {
-                long startLong = toLong(start);
-                buf.append(Long.toString(startLong + 1));
-            } else {
-                buf.append("(");
-                start.appendTo(buf);
-                buf.append(" + 1)");
-            }
+            start.appendTo(buf);
         }
-        buf.append(") - 1)");
+        buf.append(")");
     }
    
     @Override

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
 Sun Jul  3 12:32:03 2011
@@ -18,8 +18,6 @@
  */
 package org.apache.openjpa.kernel.exps;
 
-import java.sql.Time;
-import java.sql.Timestamp;
 import java.util.Date;
 
 import org.apache.openjpa.meta.ClassMetaData;
@@ -332,8 +330,9 @@ public interface ExpressionFactory {
     public Value abs(Value num);
 
     /**
-     * Return a value representing the {@link String#indexOf} function on
+     * Return a value representing the indexOf (LOCATE in JPQL) function on
      * the given target with the given args.
+     * The optional second argument is one-based.
      */
     public Value indexOf(Value str, Value args);
 
@@ -349,9 +348,9 @@ public interface ExpressionFactory {
     public Value sqrt(Value num);
 
     /**
-     * Return a value representing the {@link String#substring} function on
-     * the given target with the given args. As with {@link String#substring},
-     * the start index is zero-based, and the second argument is the end index.
+     * Return a value representing the substring function on
+     * the given target with the given args. Unlike as with {@link 
String#substring},
+     * the start index is one-based, and the second argument is the length.
      */
     public Value substring(Value str, Value args);
 

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/IndexOf.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/IndexOf.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/IndexOf.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/IndexOf.java
 Sun Jul  3 12:32:03 2011
@@ -22,6 +22,7 @@ import org.apache.openjpa.kernel.StoreCo
 
 /**
  * Find the index of one string within another.
+ * Index is 1-based.
  *
  * @author Abe White
  */
@@ -55,9 +56,9 @@ class IndexOf
         if (arg instanceof Object[]) {
             Object[] args = (Object[]) arg;
             idx = str.toString().indexOf(args[0].toString(),
-                ((Number) args[1]).intValue());
+                ((Number) args[1]).intValue() - 1) + 1;
         } else
-            idx = str.toString().indexOf(arg.toString());
+            idx = str.toString().indexOf(arg.toString()) + 1;
         return idx;
     }
 

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Substring.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Substring.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Substring.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Substring.java
 Sun Jul  3 12:32:03 2011
@@ -53,12 +53,12 @@ class Substring
         Object arg = _args.eval(candidate, orig, ctx, params);
         if (arg instanceof Object[]) {
             Object[] args = (Object[]) arg;
-            int start = ((Number) args[0]).intValue();
-            int end = ((Number) args[1]).intValue();
+            int start = ((Number) args[0]).intValue() - 1;
+            int length = ((Number) args[1]).intValue();
             String string = str == null ? "" : str.toString();
-            return string.substring(start, Math.min(end, string.length()));
+            return string.substring(start, Math.min(start + length, 
string.length()));
         }
-        return str.toString().substring(((Number) arg).intValue());
+        return str.toString().substring(((Number) arg).intValue() - 1);
     }
 
     public void acceptVisit(ExpressionVisitor visitor) {

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
 Sun Jul  3 12:32:03 2011
@@ -1304,18 +1304,22 @@ public class JPQLExpressionBuilder
                 return factory.concat(val1, val2);
 
             case JJTSUBSTRING:
-                if (node.children.length == 3) {
-                    val1 = getValue(child(node, 0, 3));
-                    val2 = getValue(child(node, 1, 3));
-                    JPQLNode child3 = child(node, 2, 3);
-                    if (child3.id == JJTINTEGERLITERAL)
+                // Literals are forced to be Integers because PostgreSQL 
rejects Longs in SUBSTRING parameters.
+                // This however does not help if an expression like 1+1 is 
passed as parameter.
+                val1 = getValue(firstChild(node));
+                JPQLNode child2 = secondChild(node);
+                if (child2.id == JJTINTEGERLITERAL) {
+                    val2 = getIntegerValue(child2);
+                } else {
+                    val2 = getValue(child2);
+                }
+                if (node.getChildCount() == 3) {
+                    JPQLNode child3 = thirdChild(node);
+                    if (child3.id == JJTINTEGERLITERAL) {
                         val3 = getIntegerValue(child3);
-                    else
+                    } else {
                         val3 = getValue(child3);
-                    
-                } else if (node.children.length == 2) {
-                    val1 = getValue(child(node, 0, 2));
-                    val2 = getValue(child(node, 1, 2));
+                    }
                 }
                 setImplicitType(val1, TYPE_STRING);
                 setImplicitType(val2, Integer.TYPE);
@@ -1325,12 +1329,11 @@ public class JPQLExpressionBuilder
                 return convertSubstringArguments(factory, val1, val2, val3);
 
             case JJTLOCATE:
-                // as with SUBSTRING (above), the semantics for LOCATE differ
-                // from ExpressionFactory.indexOf in that LOCATE uses a
-                // 0-based index, and indexOf uses a 1-based index
                 Value locatePath = getValue(firstChild(node));
                 Value locateSearch = getValue(secondChild(node));
                 Value locateFromIndex = null;
+                // Literals are forced to be Integers because PostgreSQL 
rejects Longs in POSITION parameters.
+                // This however does not help if an expression like 1+1 is 
passed as parameter.
                 if (node.getChildCount() > 2) { // optional start index arg
                     JPQLNode child3 = thirdChild(node);
                     if (child3.id == JJTINTEGERLITERAL) {
@@ -1342,16 +1345,11 @@ public class JPQLExpressionBuilder
                 setImplicitType(locateSearch, TYPE_STRING);
 
                 if (locateFromIndex != null)
-                    setImplicitType(locateFromIndex, TYPE_STRING);
+                    setImplicitType(locateFromIndex, Integer.TYPE);
 
-                return factory.add(factory.indexOf(locateSearch,
+                return factory.indexOf(locateSearch,
                     locateFromIndex == null ? locatePath
-                        : factory.newArgumentList(locatePath,
-                        factory.subtract(locateFromIndex,
-                            factory.newLiteral(1,
-                                Literal.TYPE_NUMBER)))),
-                    factory.newLiteral(1,
-                        Literal.TYPE_NUMBER));
+                        : factory.newArgumentList(locatePath, 
locateFromIndex));
 
             case JJTAGGREGATE:
                 // simply pass-through while asserting a single child
@@ -1461,14 +1459,6 @@ public class JPQLExpressionBuilder
      * Converts JPQL substring() function to OpenJPA ExpressionFactory 
      * substring() arguments.
      * 
-     * The semantics of the JPQL substring() function are that arg2 is the 
-     * 1-based start index, and arg3 is the length of the string to be return.
-     * This is different than the semantics of the ExpressionFactory's 
-     * substring(), which matches the Java language (0-based start index,
-     * arg2 is the end index): we perform the translation by adding one to the 
-     * first argument, and then adding the first argument to the second  
-     * argument to get the endIndex.
-     * 
      * @param val1 the original String
      * @param val2 the 1-based start index as per JPQL substring() semantics
      * @param val3 the length of the returned string as per JPQL semantics
@@ -1476,35 +1466,10 @@ public class JPQLExpressionBuilder
      */
     public static Value convertSubstringArguments(ExpressionFactory factory, 
                Value val1, Value val2, Value val3) {
-        Value start = null;
-        Value end = null;
-        if (val2 instanceof Literal && 
-            (val3 == null || val3 instanceof Literal)) {
-            // optimize SQL for the common case of two literals
-            long jpqlStart = ((Number) ((Literal) val2).getValue())
-                .longValue();
-            start = factory.newLiteral(Long.valueOf(jpqlStart - 1),
-                Literal.TYPE_NUMBER);
-            if (val3 != null) {
-               long length = ((Number) ((Literal) val3).getValue())
-                    .longValue();
-            long endIndex = length + (jpqlStart - 1);
-            end = factory.newLiteral(Long.valueOf(endIndex),
-                Literal.TYPE_NUMBER);
-            }
-        } else {
-            start = factory.subtract(val2, factory.newLiteral
-                (1, Literal.TYPE_NUMBER));
-            if (val3 != null)
-            end = factory.add(val3,
-                (factory.subtract(val2, factory.newLiteral
-                    (1, Literal.TYPE_NUMBER))));
-        }
         if (val3 != null)
-            return factory.substring(val1, factory.newArgumentList(start, 
end));
+            return factory.substring(val1, factory.newArgumentList(val2, 
val3));
         else
-            return factory.substring(val1, start);
-       
+            return factory.substring(val1, val2);
     }
     private void assertQueryExtensions(String clause) {
         OpenJPAConfiguration conf = resolver.getConfiguration();

Modified: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
 (original)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
 Sun Jul  3 12:32:03 2011
@@ -107,7 +107,7 @@ public class TestEJBQLFunction extends A
         em.refresh(user);
 
         assertNotNull("the user is null", user);
-        assertEquals("the users name is not AblahumSeet", "Ablahumeeth",
+        assertEquals("the users name is not Ablahumeeth", "Ablahumeeth",
             user.getName());
 
         query = "UPDATE CompUser e SET e.name = " +
@@ -121,8 +121,23 @@ public class TestEJBQLFunction extends A
         em.refresh(user);
 
         assertNotNull("the user is null", user);
-        assertEquals("the users name is not Ablahumeeth", "XYZeeth",
+        assertEquals("the users name is not XYZeeth", "XYZeeth",
             user.getName());
+
+        query = "UPDATE CompUser e SET e.name = " +
+            "CONCAT('CAD', SUBSTRING(e.name, LOCATE('e', e.name, 5))) " +
+            "WHERE e.name='XYZeeth'";
+        result = em.createQuery(query).executeUpdate();
+    
+        assertEquals("the result is not 1", 1, result);
+
+        user = em.find(CompUser.class, userid1);
+        em.refresh(user);
+
+        assertNotNull("the user is null", user);
+        assertEquals("the users name is not CADeth", "CADeth",
+            user.getName());
+
         endTx(em);
         endEm(em);
     }

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestLocate.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestLocate.java?rev=1142426&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestLocate.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestLocate.java
 Sun Jul  3 12:32:03 2011
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.query;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.apache.openjpa.persistence.test.SingleEMTestCase;
+
+/**
+ * Test for JPQL LOCATE function.
+ */
+public class TestLocate extends SingleEMTestCase {
+
+    public void setUp() {
+        super.setUp(SimpleEntity.class, CLEAR_TABLES);
+
+        EntityManager em1 = emf.createEntityManager();
+        em1.getTransaction().begin();
+        em1.persist(new SimpleEntity("foo", "bar"));
+        em1.getTransaction().commit();
+        em1.close();
+    }
+
+    public void testLocate() {
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where LOCATE('bar', o.value) = 1").getSingleResult());
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where LOCATE('ar', o.value) = 2").getSingleResult());
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where LOCATE('zzz', o.value) = 0").getSingleResult());
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where LOCATE('ar', o.value, 1) = 2").getSingleResult());
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where LOCATE('ar', o.value, 2) = 2").getSingleResult());
+    }
+
+    public void testLocateInMemory() {
+        List<SimpleEntity> allEntities = em.createQuery("select o from simple 
o", SimpleEntity.class).getResultList();
+        Object inMemoryResult = em.createQuery("select LOCATE('bar', o.value) 
from simple o")
+            .setCandidateCollection(allEntities).getSingleResult();
+        assertEquals(1, inMemoryResult);
+        inMemoryResult = em.createQuery("select LOCATE('ar', o.value, 2) from 
simple o")
+            .setCandidateCollection(allEntities).getSingleResult();
+        assertEquals(2, inMemoryResult);
+    }
+}

Propchange: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestLocate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestSubstring.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestSubstring.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestSubstring.java
 (original)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestSubstring.java
 Sun Jul  3 12:32:03 2011
@@ -18,8 +18,11 @@
  */
 package org.apache.openjpa.persistence.query;
 
+import java.util.List;
+
 import javax.persistence.EntityManager;
 
+import org.apache.openjpa.jdbc.sql.PostgresDictionary;
 import org.apache.openjpa.persistence.test.SingleEMTestCase;
 
 public class TestSubstring extends SingleEMTestCase {
@@ -28,6 +31,18 @@ public class TestSubstring extends Singl
         super.setUp(SimpleEntity.class, CLEAR_TABLES,
             "openjpa.Compatibility", "JPQL=extended");
 
+        // Expressions as substring parameters fail on PostgreSQL.
+        // The same problem exists with LOCATE.
+        // Possible fix: use CAST to integer as we do with DB2.
+        if ("testSubstringWithExpressionsInWhere".equals(getName())) {
+            setUnsupportedDatabases(PostgresDictionary.class);
+            if (isTestsDisabled()) {
+                getLog().trace(getName() +
+                    " - Skipping test - Expressions as substring parameters 
fail on PostgreSQL.");
+                return;
+            }
+        }
+
         EntityManager em = emf.createEntityManager();
         em.getTransaction().begin();
         em.persist(new SimpleEntity("foo", "bar"));
@@ -49,6 +64,12 @@ public class TestSubstring extends Singl
             "where substring(o.value, 1, 2) = 'ba'").getSingleResult());
         assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
             "where substring(o.value, 2, 2) = 'ar'").getSingleResult());
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where substring(o.value, 1) = 'bar'").getSingleResult());
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where substring(o.value, 2) = 'ar'").getSingleResult());
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where substring(o.value, 3) = 'r'").getSingleResult());
     }
 
     public void testSubstringInSelect() {
@@ -58,5 +79,22 @@ public class TestSubstring extends Singl
             "from simple o").getSingleResult());
         assertEquals("r", em.createQuery("select substring(o.value, 3, 1) " +
             "from simple o").getSingleResult());
+        assertEquals("ar", em.createQuery("select substring(o.value, 2) " +
+            "from simple o").getSingleResult());
+    }
+
+    public void testSubstringInMemory() {
+        List<SimpleEntity> allEntities = em.createQuery("select o from simple 
o", SimpleEntity.class).getResultList();
+        Object inMemoryResult = em.createQuery("select substring(o.value, 1, 
1) from simple o")
+            .setCandidateCollection(allEntities).getSingleResult();
+        assertEquals("b", inMemoryResult);
+        inMemoryResult = em.createQuery("select substring(o.value, 2) from 
simple o")
+            .setCandidateCollection(allEntities).getSingleResult();
+        assertEquals("ar", inMemoryResult);
+    }
+    
+    public void testSubstringWithExpressionsInWhere() {
+        assertEquals((long) 1, em.createQuery("select count(o) from simple o " 
+
+            "where substring(o.value, 1+1, 1+1) = 'ar'").getSingleResult());
     }
 }

Modified: 
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java?rev=1142426&r1=1142425&r2=1142426&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
 (original)
+++ 
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
 Sun Jul  3 12:32:03 2011
@@ -570,13 +570,10 @@ class Expressions {
             Value locateSearch = path.toValue(factory, q);
             Value locateFromIndex = (from == null ? null : 
Expressions.toValue(from, factory, q));
             Value locatePath = Expressions.toValue(pattern, factory, q);
-            
-            return factory.add(factory.indexOf(locateSearch,
-                    locateFromIndex == null ? locatePath
-                        : factory.newArgumentList(locatePath,
-                            factory.subtract(locateFromIndex, 
-                                             
factory.newLiteral(Integer.valueOf(1), Literal.TYPE_NUMBER)))),
-                                             
factory.newLiteral(Integer.valueOf(1), Literal.TYPE_NUMBER));
+
+            return factory.indexOf(locateSearch,
+                locateFromIndex == null ? locatePath
+                    : factory.newArgumentList(locatePath, locateFromIndex));
         }
         
         public void acceptVisit(CriteriaExpressionVisitor visitor) {


Reply via email to