[OLINGO-1192] Parameterizing JPA Queries
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java
index 4187ab0..a2266df 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java
@@ -18,10 +18,15 @@
******************************************************************************/
package org.apache.olingo.odata2.jpa.processor.core;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import org.apache.olingo.odata2.api.edm.EdmException;
import org.apache.olingo.odata2.api.edm.EdmLiteral;
@@ -52,6 +57,7 @@
import org.apache.olingo.odata2.api.uri.expression.UnaryExpression;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
+import org.apache.olingo.odata2.jpa.processor.core.model.JPAEdmMappingImpl;
/**
* This class contains utility methods for parsing the filter expressions built by core library from user OData Query.
@@ -63,7 +69,10 @@
public static final String EMPTY = ""; //$NON-NLS-1$
public static final ThreadLocal<Integer> methodFlag = new ThreadLocal<Integer>();
-
+ public static final Character[] EMPTY_CHARACTER_ARRAY = new Character[0];
+ private static int index = 1;
+ private static Map<Integer, Object> positionalParameters = new HashMap<Integer, Object>();
+
/**
* This method returns the parsed where condition corresponding to the filter input in the user query.
*
@@ -91,6 +100,7 @@
return "-" + operand; //$NON-NLS-1$
}
default:
+ reInitializePositionalParameters();
throw new ODataNotImplementedException();
}
@@ -109,6 +119,7 @@
}
}
final String left = parseToJPAWhereExpression(binaryExpression.getLeftOperand(), tableAlias);
+ index++;
final String right = parseToJPAWhereExpression(binaryExpression.getRightOperand(), tableAlias);
// Special handling for STARTSWITH and ENDSWITH method expression
@@ -116,6 +127,7 @@
if (!binaryExpression.getOperator().equals(BinaryOperator.EQ) &&
!(binaryExpression.getRightOperand() instanceof LiteralExpression) &&
("true".equals(right) || "false".equals(right))) {
+ reInitializePositionalParameters();
throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.OPERATOR_EQ_NE_MISSING
.addContent(binaryExpression.getOperator().toString()), null);
} else if (binaryExpression.getOperator().equals(BinaryOperator.EQ)) {
@@ -167,8 +179,10 @@
+ JPQLStatement.Operator.GE + JPQLStatement.DELIMITER.SPACE + right
+ JPQLStatement.DELIMITER.PARENTHESIS_RIGHT;
case PROPERTY_ACCESS:
+ reInitializePositionalParameters();
throw new ODataNotImplementedException();
default:
+ reInitializePositionalParameters();
throw new ODataNotImplementedException();
}
@@ -200,14 +214,16 @@
final LiteralExpression literal = (LiteralExpression) whereExpression;
final EdmSimpleType literalType = (EdmSimpleType) literal.getEdmType();
EdmLiteral uriLiteral = EdmSimpleTypeKind.parseUriLiteral(literal.getUriLiteral());
- return evaluateComparingExpression(uriLiteral.getLiteral(), literalType);
+ return evaluateComparingExpression(uriLiteral.getLiteral(), literalType, null);
case METHOD:
final MethodExpression methodExpression = (MethodExpression) whereExpression;
String first = parseToJPAWhereExpression(methodExpression.getParameters().get(0), tableAlias);
+ index++;
String second =
methodExpression.getParameterCount() > 1 ? parseToJPAWhereExpression(methodExpression.getParameters().get(1),
tableAlias) : null;
+ index++;
String third =
methodExpression.getParameterCount() > 2 ? parseToJPAWhereExpression(methodExpression.getParameters().get(2),
tableAlias) : null;
@@ -219,12 +235,10 @@
case SUBSTRINGOF:
if (methodFlag.get() != null && methodFlag.get() == 1) {
methodFlag.set(null);
- updateValueIfWildcards(first);
return String.format("(CASE WHEN (%s LIKE CONCAT('%%',CONCAT(%s,'%%')) ESCAPE '\\') "
+ "THEN TRUE ELSE FALSE END)",
second, first);
} else {
- first = updateValueIfWildcards(first);
return String.format("(CASE WHEN (%s LIKE CONCAT('%%',CONCAT(%s,'%%')) ESCAPE '\\') "
+ "THEN TRUE ELSE FALSE END) = true",
second, first);
@@ -232,12 +246,11 @@
case TOLOWER:
return String.format("LOWER(%s)", first);
case STARTSWITH:
- second = updateValueIfWildcards(second);
return String.format("%s LIKE CONCAT(%s,'%%') ESCAPE '\\'", first, second);
case ENDSWITH:
- second = updateValueIfWildcards(second);
return String.format("%s LIKE CONCAT('%%',%s) ESCAPE '\\'", first, second);
default:
+ reInitializePositionalParameters();
throw new ODataNotImplementedException();
}
@@ -245,8 +258,34 @@
throw new ODataNotImplementedException();
}
}
+
+ public static Map<Integer, Object> getPositionalParameters() {
+ return positionalParameters;
+ }
+
+ public static void reInitializePositionalParameters() {
+ index = 1;
+ positionalParameters = new HashMap<Integer, Object>();
+ }
/**
+ * This method converts String to Byte array
+ * @param uriLiteral
+ */
+ public static Byte[] toByteArray(String uriLiteral) {
+ int length = uriLiteral.length();
+ if (length == 0) {
+ return new Byte[0];
+ }
+ byte[] byteValues = uriLiteral.getBytes();
+ final Byte[] result = new Byte[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = new Byte(byteValues[i]);
+ }
+ return result;
+ }
+
+ /**
* This method escapes the wildcards
* @param first
*/
@@ -341,6 +380,7 @@
String literal = null;
String propertyName = null;
EdmSimpleType edmSimpleType = null;
+ Class<?> edmMappedType = null;
StringBuilder keyFilters = new StringBuilder();
int i = 0;
for (KeyPredicate keyPredicate : keyPredicates) {
@@ -352,11 +392,12 @@
try {
propertyName = keyPredicate.getProperty().getMapping().getInternalName();
edmSimpleType = (EdmSimpleType) keyPredicate.getProperty().getType();
+ edmMappedType = ((JPAEdmMappingImpl)keyPredicate.getProperty().getMapping()).getJPAType();
} catch (EdmException e) {
throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL.addContent(e.getMessage()), e);
}
- literal = evaluateComparingExpression(literal, edmSimpleType);
+ literal = evaluateComparingExpression(literal, edmSimpleType, edmMappedType);
if (edmSimpleType == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
|| edmSimpleType == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()) {
@@ -367,12 +408,32 @@
+ JPQLStatement.Operator.EQ + JPQLStatement.DELIMITER.SPACE + literal);
}
if (keyFilters.length() > 0) {
+ Map<String, Map<Integer, Object>> parameterizedExpressionMap =
+ new HashMap<String, Map<Integer,Object>>();
+ parameterizedExpressionMap.put(keyFilters.toString(), ODataExpressionParser.getPositionalParameters());
+ ODataParameterizedWhereExpressionUtil.setParameterizedQueryMap(parameterizedExpressionMap);
return keyFilters.toString();
} else {
return null;
}
}
-
+
+ /**
+ * Convert char array to Character Array
+ * */
+ public static Character[] toCharacterArray(char[] array) {
+ if (array == null) {
+ return null;
+ } else if (array.length == 0) {
+ return EMPTY_CHARACTER_ARRAY;
+ }
+ final Character[] result = new Character[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = new Character(array[i]);
+ }
+ return result;
+ }
+
public static String parseKeyPropertiesToJPAOrderByExpression(
final List<EdmProperty> edmPropertylist, final String tableAlias) throws ODataJPARuntimeException {
String propertyName = null;
@@ -401,16 +462,25 @@
*
* @param uriLiteral
* @param edmSimpleType
+ * @param edmMappedType
* @return the evaluated expression
* @throws ODataJPARuntimeException
*/
- private static String evaluateComparingExpression(String uriLiteral, final EdmSimpleType edmSimpleType)
- throws ODataJPARuntimeException {
+ private static String evaluateComparingExpression(String uriLiteral, final EdmSimpleType edmSimpleType,
+ Class<?> edmMappedType) throws ODataJPARuntimeException {
if (EdmSimpleTypeKind.String.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)
|| EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)) {
uriLiteral = uriLiteral.replaceAll("'", "''");
- uriLiteral = "'" + uriLiteral + "'"; //$NON-NLS-1$ //$NON-NLS-2$
+ uriLiteral = updateValueIfWildcards(uriLiteral);
+ if (!positionalParameters.containsKey(index)) {
+ if(edmMappedType != null){
+ evaluateExpressionForString(uriLiteral, edmMappedType);
+ }else{
+ positionalParameters.put(index, String.valueOf(uriLiteral));
+ }
+ }
+ uriLiteral = "?" + index;
} else if (EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)
|| EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)) {
try {
@@ -418,19 +488,10 @@
(Calendar) edmSimpleType.valueOfString(uriLiteral, EdmLiteralKind.DEFAULT, null, edmSimpleType
.getDefaultType());
- String year = String.format("%04d", datetime.get(Calendar.YEAR));
- String month = String.format("%02d", datetime.get(Calendar.MONTH) + 1);
- String day = String.format("%02d", datetime.get(Calendar.DAY_OF_MONTH));
- String hour = String.format("%02d", datetime.get(Calendar.HOUR_OF_DAY));
- String min = String.format("%02d", datetime.get(Calendar.MINUTE));
- String sec = String.format("%02d", datetime.get(Calendar.SECOND));
-
- uriLiteral =
- JPQLStatement.DELIMITER.LEFT_BRACE + JPQLStatement.KEYWORD.TIMESTAMP + JPQLStatement.DELIMITER.SPACE + "\'"
- + year + JPQLStatement.DELIMITER.HYPHEN + month + JPQLStatement.DELIMITER.HYPHEN + day
- + JPQLStatement.DELIMITER.SPACE + hour + JPQLStatement.DELIMITER.COLON + min
- + JPQLStatement.DELIMITER.COLON + sec + JPQLStatement.KEYWORD.OFFSET + "\'"
- + JPQLStatement.DELIMITER.RIGHT_BRACE;
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, datetime);
+ }
+ uriLiteral = "?" + index;
} catch (EdmSimpleTypeException e) {
throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL.addContent(e.getMessage()), e);
@@ -445,20 +506,94 @@
String hourValue = String.format("%02d", time.get(Calendar.HOUR_OF_DAY));
String minValue = String.format("%02d", time.get(Calendar.MINUTE));
String secValue = String.format("%02d", time.get(Calendar.SECOND));
-
+
uriLiteral =
- "\'" + hourValue + JPQLStatement.DELIMITER.COLON + minValue + JPQLStatement.DELIMITER.COLON + secValue
- + "\'";
+ hourValue + JPQLStatement.DELIMITER.COLON + minValue + JPQLStatement.DELIMITER.COLON + secValue;
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, Time.valueOf(uriLiteral));
+ }
+ uriLiteral = "?" + index;
} catch (EdmSimpleTypeException e) {
throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL.addContent(e.getMessage()), e);
}
- } else if (Long.class.equals(edmSimpleType.getDefaultType())) {
- uriLiteral = uriLiteral + JPQLStatement.DELIMITER.LONG; //$NON-NLS-1$
+ } else {
+ uriLiteral = evaluateExpressionForNumbers(uriLiteral, edmSimpleType, edmMappedType);
}
return uriLiteral;
}
+ private static String evaluateExpressionForNumbers(String uriLiteral, EdmSimpleType edmSimpleType,
+ Class<?> edmMappedType) {
+ Class<? extends Object> type = edmMappedType==null? edmSimpleType.getDefaultType():
+ edmMappedType;
+ if (Long.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, Long.valueOf(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (Double.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, Double.valueOf(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (Integer.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, Integer.valueOf(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (Byte.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, Byte.valueOf(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (Byte[].class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, toByteArray(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (Short.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, Short.valueOf(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (BigDecimal.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, new BigDecimal(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (BigInteger.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, new BigInteger(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ } else if (Float.class.equals(type)) {
+ if (!positionalParameters.containsKey(index)) {
+ positionalParameters.put(index, Float.valueOf(uriLiteral));
+ }
+ uriLiteral = "?" + index;
+ }
+ return uriLiteral;
+ }
+
+ private static void evaluateExpressionForString(String uriLiteral, Class<?> edmMappedType) {
+
+ if(edmMappedType.equals(char[].class)){
+ positionalParameters.put(index, uriLiteral.toCharArray());
+ }else if(edmMappedType.equals(char.class)){
+ positionalParameters.put(index, uriLiteral.charAt(0));
+ }else if(edmMappedType.equals(Character[].class)){
+ char[] charArray = uriLiteral.toCharArray();
+ Character[] charObjectArray =toCharacterArray(charArray);
+ positionalParameters.put(index, charObjectArray);
+ }else if(edmMappedType.equals(Character.class)){
+ positionalParameters.put(index, (Character)uriLiteral.charAt(0));
+ }else {
+ positionalParameters.put(index, String.valueOf(uriLiteral));
+ }
+
+ }
+
private static String getPropertyName(final CommonExpression whereExpression) throws EdmException,
ODataJPARuntimeException {
EdmTyped edmProperty = ((PropertyExpression) whereExpression).getEdmProperty();
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataParameterizedWhereExpressionUtil.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataParameterizedWhereExpressionUtil.java
new file mode 100644
index 0000000..2ba6026
--- /dev/null
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataParameterizedWhereExpressionUtil.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * 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.olingo.odata2.jpa.processor.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ODataParameterizedWhereExpressionUtil {
+ /**
+ * Map includes where expression clause as the key and the
+ * ODataParameterizedWhereExpression as the value
+ */
+ private static Map<String, Map<Integer, Object>> parameterizedQueryMap = new
+ HashMap<String, Map<Integer,Object>>();
+
+ private static String jpqlStatement = null;
+
+ /**
+ * @return the parameterizedQueryMap
+ */
+ public static Map<String, Map<Integer, Object>> getParameterizedQueryMap() {
+ return parameterizedQueryMap;
+ }
+
+ /**
+ * @param parameterizedQueryMap the parameterizedQueryMap to set
+ */
+ public static void setParameterizedQueryMap(Map<String, Map<Integer, Object>> parameterizedQueryMap) {
+ ODataParameterizedWhereExpressionUtil.parameterizedQueryMap = parameterizedQueryMap;
+ }
+
+ public static void setJPQLStatement(String jpqlStatement) {
+ ODataParameterizedWhereExpressionUtil.jpqlStatement = jpqlStatement;
+ }
+
+ public static String getJPQLStatement() {
+ return jpqlStatement;
+ }
+
+}
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java
index 195153b..6920c8f 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java
@@ -21,12 +21,17 @@
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.sql.Time;
+import java.sql.Timestamp;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import javax.persistence.EntityManager;
import javax.persistence.Query;
+import javax.persistence.TemporalType;
import org.apache.olingo.odata2.api.commons.InlineCount;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
@@ -59,6 +64,7 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextType;
import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmMapping;
import org.apache.olingo.odata2.jpa.processor.core.ODataEntityParser;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
import org.apache.olingo.odata2.jpa.processor.core.access.data.JPAPage.JPAPageBuilder;
import org.apache.olingo.odata2.jpa.processor.core.access.data.JPAQueryBuilder.JPAQueryInfo;
@@ -146,6 +152,7 @@
JPAQueryBuilder queryBuilder = new JPAQueryBuilder(oDataJPAContext);
JPAQueryInfo queryInfo = queryBuilder.build(uriParserResultView);
Query query = queryInfo.getQuery();
+ setPositionalParametersToQuery(query);
ODataJPATombstoneEntityListener listener =
queryBuilder.getODataJPATombstoneEntityListener((UriInfo) uriParserResultView);
Map<String, String> customQueryOptions = uriParserResultView.getCustomQueryOptions();
@@ -180,6 +187,33 @@
}
}
+ /**
+ * @param query
+ */
+ private void setPositionalParametersToQuery(Query query) {
+ Map<String, Map<Integer, Object>> parameterizedMap = ODataParameterizedWhereExpressionUtil.
+ getParameterizedQueryMap();
+ if (parameterizedMap != null && parameterizedMap.size() > 0) {
+ for (Entry<String, Map<Integer, Object>> parameterEntry : parameterizedMap.entrySet()) {
+ if (ODataParameterizedWhereExpressionUtil.getJPQLStatement().contains(parameterEntry.getKey())) {
+ Map<Integer, Object> positionalParameters = parameterEntry.getValue();
+ for (Entry<Integer, Object> param : positionalParameters.entrySet()) {
+ if (param.getValue() instanceof Calendar || param.getValue() instanceof Timestamp) {
+ query.setParameter(param.getKey(), (Calendar) param.getValue(), TemporalType.TIMESTAMP);
+ } else if (param.getValue() instanceof Time) {
+ query.setParameter(param.getKey(), (Time) param.getValue(), TemporalType.TIME);
+ } else {
+ query.setParameter(param.getKey(), param.getValue());
+ }
+ }
+ parameterizedMap.remove(parameterEntry.getKey());
+ ODataParameterizedWhereExpressionUtil.setJPQLStatement(null);
+ break;
+ }
+ }
+ }
+ }
+
/* Process Get Entity Request (Read) */
@Override
public <T> Object process(GetEntityUriInfo uriParserResultView)
@@ -194,6 +228,7 @@
JPAQueryBuilder queryBuilder = new JPAQueryBuilder(oDataJPAContext);
Query query = queryBuilder.build(resultsView);
+ setPositionalParametersToQuery(query);
List<?> resultList = query.getResultList();
if (resultList != null && resultList.size() == 1) {
return Long.valueOf(resultList.get(0).toString());
@@ -208,6 +243,7 @@
JPAQueryBuilder queryBuilder = new JPAQueryBuilder(oDataJPAContext);
Query query = queryBuilder.build(resultsView);
+ setPositionalParametersToQuery(query);
List<?> resultList = query.getResultList();
if (resultList != null && resultList.size() == 1) {
return Long.valueOf(resultList.get(0).toString());
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
index 232e90c..3319fc3 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
@@ -18,14 +18,19 @@
******************************************************************************/
package org.apache.olingo.odata2.jpa.processor.core.access.data;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.EntityManager;
import javax.persistence.Query;
+import javax.persistence.TemporalType;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
@@ -46,6 +51,7 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextType;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmMapping;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
public class JPAQueryBuilder {
@@ -180,7 +186,29 @@
JPQLContext jpqlContext = buildJPQLContext(contextType, uriParserResultView);
JPQLStatement jpqlStatement = JPQLStatement.createBuilder(jpqlContext).build();
- return em.createQuery(normalizeMembers(em, jpqlStatement.toString()));
+ Query query = em.createQuery(normalizeMembers(em, jpqlStatement.toString()));
+ Map<String, Map<Integer, Object>> parameterizedMap = ODataParameterizedWhereExpressionUtil.
+ getParameterizedQueryMap();
+ if (parameterizedMap != null && parameterizedMap.size() > 0) {
+ for (Entry<String, Map<Integer, Object>> parameterEntry : parameterizedMap.entrySet()) {
+ if (jpqlStatement.toString().contains(parameterEntry.getKey())) {
+ Map<Integer, Object> positionalParameters = parameterEntry.getValue();
+ for (Entry<Integer, Object> param : positionalParameters.entrySet()) {
+ if (param.getValue() instanceof Calendar || param.getValue() instanceof Timestamp) {
+ query.setParameter(param.getKey(), (Calendar) param.getValue(), TemporalType.TIMESTAMP);
+ } else if (param.getValue() instanceof Time) {
+ query.setParameter(param.getKey(), (Time) param.getValue(), TemporalType.TIME);
+ } else {
+ query.setParameter(param.getKey(), param.getValue());
+ }
+ }
+ parameterizedMap.remove(parameterEntry.getKey());
+ ODataParameterizedWhereExpressionUtil.setJPQLStatement(null);
+ break;
+ }
+ }
+ }
+ return query;
}
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java
index 56b1686..3ebf1c6 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java
@@ -62,7 +62,9 @@
setKeyPredicates(entityView.getKeyPredicates());
setSelectExpression(generateSelectExpression());
-
+
+ ODataExpressionParser.reInitializePositionalParameters();
+
} catch (EdmException e) {
throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL, e);
}
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java
index 4c64855..da66916 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java
@@ -26,6 +26,8 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLJoinSelectSingleContextView;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement.JPQLStatementBuilder;
+import org.apache.olingo.odata2.jpa.processor.core.ODataExpressionParser;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
public class JPQLJoinSelectSingleStatementBuilder extends JPQLStatementBuilder {
@@ -39,6 +41,8 @@
@Override
public JPQLStatement build() throws ODataJPARuntimeException {
jpqlStatement = createStatement(createJPQLQuery());
+ ODataParameterizedWhereExpressionUtil.setJPQLStatement(jpqlStatement.toString());
+ ODataExpressionParser.reInitializePositionalParameters();
return jpqlStatement;
}
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java
index c2e3085..4e87f05 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java
@@ -27,6 +27,8 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLJoinContextView;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement.JPQLStatementBuilder;
+import org.apache.olingo.odata2.jpa.processor.core.ODataExpressionParser;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
public class JPQLJoinStatementBuilder extends JPQLStatementBuilder {
@@ -40,6 +42,8 @@
@Override
public JPQLStatement build() throws ODataJPARuntimeException {
jpqlStatement = createStatement(createJPQLQuery());
+ ODataParameterizedWhereExpressionUtil.setJPQLStatement(jpqlStatement.toString());
+ ODataExpressionParser.reInitializePositionalParameters();
return jpqlStatement;
}
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
index 34f8655..33921f4 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
@@ -18,6 +18,9 @@
******************************************************************************/
package org.apache.olingo.odata2.jpa.processor.core.jpql;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.olingo.odata2.api.edm.EdmEntityType;
import org.apache.olingo.odata2.api.edm.EdmException;
import org.apache.olingo.odata2.api.edm.EdmMapping;
@@ -29,6 +32,7 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextType;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLSelectContextView;
import org.apache.olingo.odata2.jpa.processor.core.ODataExpressionParser;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
public class JPQLSelectContext extends JPQLContext implements JPQLSelectContextView {
@@ -154,10 +158,18 @@
*/
protected String generateWhereExpression() throws ODataException {
if (entitySetView.getFilter() != null) {
- return ODataExpressionParser.parseToJPAWhereExpression(entitySetView.getFilter(), getJPAEntityAlias());
+ String whereExpression = ODataExpressionParser.parseToJPAWhereExpression(
+ entitySetView.getFilter(), getJPAEntityAlias());
+ Map<String, Map<Integer, Object>> parameterizedExpressionMap =
+ new HashMap<String, Map<Integer,Object>>();
+ parameterizedExpressionMap.put(whereExpression, ODataExpressionParser.getPositionalParameters());
+ ODataParameterizedWhereExpressionUtil.setParameterizedQueryMap(parameterizedExpressionMap);
+ ODataExpressionParser.reInitializePositionalParameters();
+ return whereExpression;
}
+ ODataExpressionParser.reInitializePositionalParameters();
return null;
}
}
-}
+}
\ No newline at end of file
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java
index 47e3f42..e1b0910 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java
@@ -24,6 +24,7 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement.JPQLStatementBuilder;
import org.apache.olingo.odata2.jpa.processor.core.ODataExpressionParser;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
public class JPQLSelectSingleStatementBuilder extends JPQLStatementBuilder {
@@ -37,6 +38,8 @@
@Override
public JPQLStatement build() throws ODataJPARuntimeException {
jpqlStatement = createStatement(createJPQLQuery());
+ ODataParameterizedWhereExpressionUtil.setJPQLStatement(jpqlStatement.toString());
+ ODataExpressionParser.reInitializePositionalParameters();
return jpqlStatement;
}
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java
index 49ed28b..1276238 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java
@@ -24,6 +24,8 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLSelectContextView;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement.JPQLStatementBuilder;
+import org.apache.olingo.odata2.jpa.processor.core.ODataExpressionParser;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
public class JPQLSelectStatementBuilder extends JPQLStatementBuilder {
@@ -37,6 +39,8 @@
@Override
public JPQLStatement build() throws ODataJPARuntimeException {
jpqlStatement = createStatement(createJPQLQuery());
+ ODataParameterizedWhereExpressionUtil.setJPQLStatement(jpqlStatement.toString());
+ ODataExpressionParser.reInitializePositionalParameters();
return jpqlStatement;
}
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataFilterExpressionParserTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataFilterExpressionParserTest.java
index c65dced..02baae6 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataFilterExpressionParserTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataFilterExpressionParserTest.java
@@ -23,6 +23,10 @@
import static org.junit.Assert.fail;
import java.io.InputStream;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Map;
+import java.util.Map.Entry;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmException;
@@ -33,6 +37,7 @@
import org.apache.olingo.odata2.api.uri.UriParser;
import org.apache.olingo.odata2.api.uri.expression.ExpressionParserException;
import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
+import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -49,11 +54,11 @@
private static final String[] EXPRESSION_BINARY_AND =
{
"id le '123' and soId eq 123L and not (substringof(id,'123') eq false) eq true",
- "(((E1.id <= '123') AND (E1.soId = 123L)) AND (NOT(((CASE WHEN ('123' LIKE CONCAT('%',CONCAT(E1.id,'%')"
+ "(((E1.id <= '123') AND (E1.soId = 123)) AND (NOT(((CASE WHEN ('123' LIKE CONCAT('%',CONCAT(E1.id,'%')"
+ ") ESCAPE '\\') "
+ "THEN TRUE ELSE FALSE END) = false)) = true))" };
private static final String[] EXPRESSION_BINARY_OR = { "id ge '123' or soId gt 123L",
- "((E1.id >= '123') OR (E1.soId > 123L))" };
+ "((E1.id >= '123') OR (E1.soId > 123))" };
private static final String[] EXPRESSION_MEMBER_OR = { "id lt '123' or oValue/Currency eq 'INR'",
"((E1.id < '123') OR (E1.oValue.Currency = 'INR'))" };
private static final String[] EXPRESSION_STARTS_WITH = { "startswith(oValue/Currency,'INR')",
@@ -94,7 +99,7 @@
"id eq '123' and id ne '123' or (id eq '123' and id ne '123')",
"(((E1.id = '123') AND (E1.id <> '123')) OR ((E1.id = '123') AND (E1.id <> '123')))" };
private static final String[] EXPRESSION_DATETIME = { "date eq datetime'2000-01-01T00:00:00'",
- "(E1.date = {ts '2000-01-01 00:00:00.000'})" };
+ "(E1.date = 2000-01-01 00:00:00.000)" };
private static final String[] EXPRESSION_NULL = { "date eq null", "(E1.date IS null)" };
@@ -140,35 +145,45 @@
@Test
public void testDateTime() {
- assertEquals(EXPRESSION_DATETIME[OUTPUT], parseWhereExpression(
- EXPRESSION_DATETIME[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_DATETIME[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_DATETIME[OUTPUT], whereExpression);
}
@Test
public void testPrecedence() {
- assertEquals(EXPRESSION_PRECEDENCE[OUTPUT], parseWhereExpression(
- EXPRESSION_PRECEDENCE[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_PRECEDENCE[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_PRECEDENCE[OUTPUT], whereExpression);
}
@Test
public void testSubStringOfSQLInjection() {
- assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION1[OUTPUT], parseWhereExpression(
- EXPRESSION_SUBSTRINGOF_INJECTION1[INPUT], false));
- assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION2[OUTPUT], parseWhereExpression(
- EXPRESSION_SUBSTRINGOF_INJECTION2[INPUT], false));
- assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION3[OUTPUT], parseWhereExpression(
- EXPRESSION_SUBSTRINGOF_INJECTION3[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_SUBSTRINGOF_INJECTION1[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION1[OUTPUT], whereExpression);
+
+ whereExpression = parseWhereExpression(EXPRESSION_SUBSTRINGOF_INJECTION2[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION2[OUTPUT], whereExpression);
+
+ whereExpression = parseWhereExpression(EXPRESSION_SUBSTRINGOF_INJECTION3[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION3[OUTPUT], whereExpression);
}
@Test
public void testEndsWithSQLInjection() {
- assertEquals(EXPRESSION_ENDSWITH_INJECTION1[OUTPUT], parseWhereExpression(
- EXPRESSION_ENDSWITH_INJECTION1[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_ENDSWITH_INJECTION1[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_ENDSWITH_INJECTION1[OUTPUT], whereExpression);
}
@Test
public void testSubStringWithAllOperator() {
- assertEquals(EXPRESSION_SUBSTRING_ALL_OP[OUTPUT], parseWhereExpression(EXPRESSION_SUBSTRING_ALL_OP[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_SUBSTRING_ALL_OP[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_SUBSTRING_ALL_OP[OUTPUT], whereExpression);
}
@Test
@@ -178,73 +193,101 @@
@Test
public void testSubStringOf() {
- assertEquals(EXPRESSION_SUBSTRING_OF[OUTPUT], parseWhereExpression(EXPRESSION_SUBSTRING_OF[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_SUBSTRING_OF[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_SUBSTRING_OF[OUTPUT], whereExpression);
}
@Test
public void testStartsWithEqual() {
- assertEquals(EXPRESSION_STARTS_WITH_EQUAL[OUTPUT], parseWhereExpression(EXPRESSION_STARTS_WITH_EQUAL[INPUT],
- false));
+ String whereExpression = parseWhereExpression(EXPRESSION_STARTS_WITH_EQUAL[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTS_WITH_EQUAL[OUTPUT], whereExpression);
}
@Test
public void testEscapeCharacters() {
- assertEquals(EXPRESSION_ESCAPE[OUTPUT], parseWhereExpression(EXPRESSION_ESCAPE[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_ESCAPE[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_ESCAPE[OUTPUT], whereExpression);
}
@Test
public void testNotEndsWithToLowerMethod() {
- assertEquals(EXPRESSION_NOT_ENDS_WITH[OUTPUT], parseWhereExpression(EXPRESSION_NOT_ENDS_WITH[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_NOT_ENDS_WITH[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_NOT_ENDS_WITH[OUTPUT], whereExpression);
}
@Test
public void testNestedMethod() {
- assertEquals(EXPRESSION_NESTED_METHOD[OUTPUT], parseWhereExpression(EXPRESSION_NESTED_METHOD[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_NESTED_METHOD[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_NESTED_METHOD[OUTPUT], whereExpression);
}
@Test
public void testNotStartsWith() {
- assertEquals(EXPRESSION_NOT_STARTS_WITH[OUTPUT], parseWhereExpression(EXPRESSION_NOT_STARTS_WITH[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_NOT_STARTS_WITH[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_NOT_STARTS_WITH[OUTPUT], whereExpression);
}
@Test
public void testStartsWith() {
- assertEquals(EXPRESSION_STARTS_WITH[OUTPUT], parseWhereExpression(EXPRESSION_STARTS_WITH[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_STARTS_WITH[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTS_WITH[OUTPUT], whereExpression);
}
@Test
public void testSimpleEqRelation() {
- assertEquals(EXPRESSION_EQ[OUTPUT], parseWhereExpression(EXPRESSION_EQ[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_EQ[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_EQ[OUTPUT], whereExpression);
+
}
@Test
public void testSimpleNeRelation() {
- assertEquals(EXPRESSION_NE[OUTPUT], parseWhereExpression(EXPRESSION_NE[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_NE[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_NE[OUTPUT], whereExpression);
}
@Test
public void testBinaryAnd() {
- assertEquals(EXPRESSION_BINARY_AND[OUTPUT], parseWhereExpression(EXPRESSION_BINARY_AND[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_BINARY_AND[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_BINARY_AND[OUTPUT], whereExpression);
}
@Test
public void testBinaryOr() {
- assertEquals(EXPRESSION_BINARY_OR[OUTPUT], parseWhereExpression(EXPRESSION_BINARY_OR[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_BINARY_OR[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_BINARY_OR[OUTPUT], whereExpression);
}
@Test
public void testMemberOr() {
- assertEquals(EXPRESSION_MEMBER_OR[OUTPUT], parseWhereExpression(EXPRESSION_MEMBER_OR[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_MEMBER_OR[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_MEMBER_OR[OUTPUT], whereExpression);
}
@Test
public void testNull() {
- assertEquals(EXPRESSION_NULL[OUTPUT], parseWhereExpression(EXPRESSION_NULL[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_NULL[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_NULL[OUTPUT], whereExpression);
}
@Test
public void testNotNull() {
- assertEquals(EXPRESSION_NOT_NULL[OUTPUT], parseWhereExpression(EXPRESSION_NOT_NULL[INPUT], false));
+ String whereExpression = parseWhereExpression(EXPRESSION_NOT_NULL[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_NOT_NULL[OUTPUT], whereExpression);
}
private String parseWhereExpression(final String input, final boolean isExceptionExpected) {
@@ -271,48 +314,106 @@
@Test
public void testStartsWith_BinaryEq() {
- assertEquals(EXPRESSION_STARTSWITH_EQBINARY[OUTPUT], parseWhereExpression(
- EXPRESSION_STARTSWITH_EQBINARY[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_STARTSWITH_EQBINARY[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTSWITH_EQBINARY[OUTPUT], whereExpression);
}
@Test
public void testBinaryEq_StartsWith() {
- assertEquals(EXPRESSION_EQBINARY_STARTSWITH[OUTPUT], parseWhereExpression(
- EXPRESSION_EQBINARY_STARTSWITH[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_EQBINARY_STARTSWITH[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_EQBINARY_STARTSWITH[OUTPUT], whereExpression);
}
public void testStartsWithEq_BinaryEq() {
- assertEquals(EXPRESSION_STARTSWITHEQ_EQBINARY[OUTPUT], parseWhereExpression(
- EXPRESSION_STARTSWITHEQ_EQBINARY[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_STARTSWITHEQ_EQBINARY[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTSWITHEQ_EQBINARY[OUTPUT], whereExpression);
}
@Test
public void testBinaryEq_StartsWithEq() {
- assertEquals(EXPRESSION_EQBINARY_STARTSWITHEQ[OUTPUT], parseWhereExpression(
- EXPRESSION_EQBINARY_STARTSWITHEQ[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_EQBINARY_STARTSWITHEQ[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_EQBINARY_STARTSWITHEQ[OUTPUT], whereExpression);
}
@Test
public void testStartsWith_StartsWith() {
- assertEquals(EXPRESSION_STARTSWITH_STARTSWITH[OUTPUT], parseWhereExpression(
- EXPRESSION_STARTSWITH_STARTSWITH[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_STARTSWITH_STARTSWITH[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTSWITH_STARTSWITH[OUTPUT], whereExpression);
}
@Test
public void testStartsWithEq_StartsWithEq() {
- assertEquals(EXPRESSION_STARTSWITHEQ_STARTSWITHEQ[OUTPUT], parseWhereExpression(
- EXPRESSION_STARTSWITHEQ_STARTSWITHEQ[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_STARTSWITHEQ_STARTSWITHEQ[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTSWITHEQ_STARTSWITHEQ[OUTPUT], whereExpression);
}
@Test
public void testStartsWithEq_AndTrue() {
- assertEquals(EXPRESSION_STARTSWITHEQTRUE_ANDTRUE[OUTPUT], parseWhereExpression(
- EXPRESSION_STARTSWITHEQTRUE_ANDTRUE[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_STARTSWITHEQTRUE_ANDTRUE[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTSWITHEQTRUE_ANDTRUE[OUTPUT], whereExpression);
}
@Test
public void testStarts_AndTrue() {
- assertEquals(EXPRESSION_STARTSWITH_ANDTRUE[OUTPUT], parseWhereExpression(
- EXPRESSION_STARTSWITH_ANDTRUE[INPUT], false));
+ String whereExpression = parseWhereExpression(
+ EXPRESSION_STARTSWITH_ANDTRUE[INPUT], false);
+ whereExpression = replacePositionalParameters(whereExpression);
+ assertEquals(EXPRESSION_STARTSWITH_ANDTRUE[OUTPUT], whereExpression);
}
+
+ private String replacePositionalParameters(String whereExpression) {
+ Map<Integer, Object> positionalParameters = ODataExpressionParser.getPositionalParameters();
+ for (Entry<Integer, Object> param : positionalParameters.entrySet()) {
+ Integer key = param.getKey();
+ if (param.getValue() instanceof String) {
+ whereExpression = whereExpression.replaceAll("\\?" + String.valueOf(key), "\'" + param.getValue() + "\'");
+ } else if (param.getValue() instanceof Timestamp || param.getValue() instanceof Calendar){
+ Calendar datetime = (Calendar) param.getValue();
+ String year = String.format("%04d", datetime.get(Calendar.YEAR));
+ String month = String.format("%02d", datetime.get(Calendar.MONTH) + 1);
+ String day = String.format("%02d", datetime.get(Calendar.DAY_OF_MONTH));
+ String hour = String.format("%02d", datetime.get(Calendar.HOUR_OF_DAY));
+ String min = String.format("%02d", datetime.get(Calendar.MINUTE));
+ String sec = String.format("%02d", datetime.get(Calendar.SECOND));
+ String value =
+ year + JPQLStatement.DELIMITER.HYPHEN + month + JPQLStatement.DELIMITER.HYPHEN + day
+ + JPQLStatement.DELIMITER.SPACE + hour + JPQLStatement.DELIMITER.COLON + min
+ + JPQLStatement.DELIMITER.COLON + sec + JPQLStatement.KEYWORD.OFFSET;
+ whereExpression = whereExpression.replaceAll("\\?" + String.valueOf(key), value);
+ } else if(param.getValue() instanceof Byte[]){
+ byte[] byteValue = convertToByte((Byte[])param.getValue());
+ whereExpression = whereExpression.replaceAll("\\?" + String.valueOf(key), new String(byteValue));
+ }else {
+ whereExpression = whereExpression.replaceAll("\\?" + String.valueOf(key), param.getValue().toString());
+ }
+ }
+ ODataExpressionParser.reInitializePositionalParameters();
+ return whereExpression;
+ }
+
+ private byte[] convertToByte(Byte[] value) {
+ int length = value.length;
+ if (length == 0) {
+ return new byte[0];
+ }
+ final byte[] result = new byte[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = value[i];
+ }
+ return result;
+ }
}
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLBuilderFactoryTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLBuilderFactoryTest.java
index 318c167..5aef018 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLBuilderFactoryTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLBuilderFactoryTest.java
@@ -39,7 +39,6 @@
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmEntityType;
import org.apache.olingo.odata2.api.edm.EdmException;
-import org.apache.olingo.odata2.api.edm.EdmMapping;
import org.apache.olingo.odata2.api.edm.EdmProperty;
import org.apache.olingo.odata2.api.edm.EdmSimpleType;
import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
@@ -61,6 +60,7 @@
import org.apache.olingo.odata2.jpa.processor.core.factory.ODataJPAFactoryImpl;
import org.apache.olingo.odata2.jpa.processor.core.jpql.JPQLSelectContext.JPQLSelectContextBuilder;
import org.apache.olingo.odata2.jpa.processor.core.jpql.JPQLSelectSingleContext.JPQLSelectSingleContextBuilder;
+import org.apache.olingo.odata2.jpa.processor.core.model.JPAEdmMappingImpl;
import org.easymock.EasyMock;
import org.junit.Test;
@@ -181,9 +181,11 @@
KeyPredicate keyPredicate = EasyMock.createMock(KeyPredicate.class);
EdmProperty kpProperty = EasyMock.createMock(EdmProperty.class);
EdmSimpleType edmType = EdmSimpleTypeKind.Int32.getEdmSimpleTypeInstance();
- EdmMapping edmMapping = EasyMock.createMock(EdmMapping.class);
+ JPAEdmMappingImpl edmMapping = EasyMock.createMock(JPAEdmMappingImpl.class);
EasyMock.expect(edmMapping.getInternalName()).andStubReturn("Field1");
EasyMock.expect(keyPredicate.getLiteral()).andStubReturn("1");
+ EasyMock.expect(edmMapping.getJPAType())
+ .andStubReturn(null);
try {
EasyMock.expect(kpProperty.getName()).andStubReturn("Field1");
EasyMock.expect(kpProperty.getType()).andStubReturn(edmType);
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java
index 3c595ae..2fbedef 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java
@@ -44,6 +44,7 @@
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAModelException;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
import org.apache.olingo.odata2.jpa.processor.core.jpql.JPQLJoinSelectContext.JPQLJoinContextBuilder;
+import org.apache.olingo.odata2.jpa.processor.core.model.JPAEdmMappingImpl;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.AfterClass;
@@ -70,6 +71,7 @@
final EdmNavigationProperty navigationProperty = createNavigationProperty("a");
final EdmNavigationProperty navigationProperty1 = createNavigationProperty("b");
final List<KeyPredicate> keyPredicates = createKeyPredicates();
+ EdmProperty kpProperty = EasyMock.createMock(EdmProperty.class);
NavigationSegment navigationSegment = new NavigationSegment() {
@Override
@@ -182,7 +184,9 @@
KeyPredicate keyPredicate = EasyMock.createMock(KeyPredicate.class);
EasyMock.expect(keyPredicate.getLiteral()).andStubReturn("1");
EdmProperty edmProperty = EasyMock.createMock(EdmProperty.class);
- EdmMapping edmMapping = EasyMock.createMock(EdmMapping.class);
+ JPAEdmMappingImpl edmMapping = EasyMock.createMock(JPAEdmMappingImpl.class);
+ EasyMock.expect(edmMapping.getJPAType())
+ .andStubReturn(null);
EasyMock.expect(edmMapping.getInternalName()).andStubReturn("soid");
EasyMock.expect(edmProperty.getMapping()).andStubReturn(edmMapping);
EasyMock.expect(edmProperty.getName()).andStubReturn("soid");
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java
index f16217c..d5684e0 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java
@@ -44,6 +44,7 @@
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAModelException;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
import org.apache.olingo.odata2.jpa.processor.core.jpql.JPQLJoinSelectSingleContext.JPQLJoinSelectSingleContextBuilder;
+import org.apache.olingo.odata2.jpa.processor.core.model.JPAEdmMappingImpl;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.AfterClass;
@@ -195,7 +196,9 @@
KeyPredicate keyPredicate = EasyMock.createMock(KeyPredicate.class);
EasyMock.expect(keyPredicate.getLiteral()).andStubReturn("1");
EdmProperty edmProperty = EasyMock.createMock(EdmProperty.class);
- EdmMapping edmMapping = EasyMock.createMock(EdmMapping.class);
+ JPAEdmMappingImpl edmMapping = EasyMock.createMock(JPAEdmMappingImpl.class);
+ EasyMock.expect(edmMapping.getJPAType())
+ .andStubReturn(null);
EasyMock.expect(edmMapping.getInternalName()).andStubReturn("soid");
EasyMock.expect(edmProperty.getMapping()).andStubReturn(edmMapping);
EasyMock.expect(edmProperty.getName()).andStubReturn("soid");
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java
index 9d47839..63b5948 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java
@@ -23,11 +23,12 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmEntityType;
import org.apache.olingo.odata2.api.edm.EdmException;
-import org.apache.olingo.odata2.api.edm.EdmMapping;
import org.apache.olingo.odata2.api.edm.EdmProperty;
import org.apache.olingo.odata2.api.edm.EdmSimpleType;
import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
@@ -39,6 +40,8 @@
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextType;
+import org.apache.olingo.odata2.jpa.processor.core.ODataParameterizedWhereExpressionUtil;
+import org.apache.olingo.odata2.jpa.processor.core.model.JPAEdmMappingImpl;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
@@ -69,7 +72,9 @@
KeyPredicate keyPredicate = EasyMock.createMock(KeyPredicate.class);
EdmProperty kpProperty = EasyMock.createMock(EdmProperty.class);
EdmSimpleType edmType = EdmSimpleTypeKind.Int32.getEdmSimpleTypeInstance();
- EdmMapping edmMapping = EasyMock.createMock(EdmMapping.class);
+ JPAEdmMappingImpl edmMapping = EasyMock.createMock(JPAEdmMappingImpl.class);
+ EasyMock.expect(edmMapping.getJPAType())
+ .andStubReturn(null);
EasyMock.expect(edmMapping.getInternalName()).andStubReturn("Field1");
EasyMock.expect(keyPredicate.getLiteral()).andStubReturn("1");
try {
@@ -114,11 +119,22 @@
@Test
public void testBuildSimpleQuery() throws EdmException, ODataJPARuntimeException {
+
JPQLSelectSingleContext JPQLSelectSingleContextImpl = createSelectContext();
JPQLSelectSingleStatementBuilder = new JPQLSelectSingleStatementBuilder(JPQLSelectSingleContextImpl);
- assertEquals("SELECT E1 FROM SalesOrderHeader E1 WHERE E1.Field1 = 1", JPQLSelectSingleStatementBuilder.build()
- .toString());
+ String query = JPQLSelectSingleStatementBuilder.build().toString();
+ query = query.substring(0, query.indexOf("?"));
+ Map<String, Map<Integer, Object>> positionalParameters =
+ ODataParameterizedWhereExpressionUtil.getParameterizedQueryMap();
+ for (Entry<String, Map<Integer, Object>> param : positionalParameters.entrySet()) {
+ for (Entry<Integer, Object> postionalParam : param.getValue().entrySet()) {
+ query += postionalParam.getValue();
+ }
+ }
+
+ assertEquals("SELECT E1 FROM SalesOrderHeader E1 WHERE E1.Field1 = 1", query);
+
}
}
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
index cb59b6f..c218bfb 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
@@ -76,7 +76,9 @@
Query jpqlquery = EasyMock.createMock(Query.class);
Capture<String> capturedArgument = new Capture<String>();
EasyMock.expect(em.createQuery(EasyMock.capture(capturedArgument))).andReturn(jpqlquery);
- EasyMock.replay(em,mm);
+ EasyMock.expect(jpqlquery.setParameter(EasyMock.anyInt(), EasyMock.anyObject()))
+ .andReturn(jpqlquery).anyTimes();
+ EasyMock.replay(em,mm,jpqlquery);
return em;
}