You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2016/08/24 20:41:26 UTC
olingo-odata2 git commit: [OLINGO-414] Merged fix for ManyTo with
DISTINCT generation
Repository: olingo-odata2
Updated Branches:
refs/heads/OLINGO-JPA-Fixes a1f6d1f5f -> 3ed58899d
[OLINGO-414] Merged fix for ManyTo with DISTINCT generation
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/3ed58899
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/3ed58899
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/3ed58899
Branch: refs/heads/OLINGO-JPA-Fixes
Commit: 3ed58899d76c57ef8a26a3a02098c736f4740856
Parents: a1f6d1f
Author: mibo <mi...@apache.org>
Authored: Wed Aug 24 22:40:03 2016 +0200
Committer: mibo <mi...@apache.org>
Committed: Wed Aug 24 22:40:03 2016 +0200
----------------------------------------------------------------------
.../jpa/processor/api/jpql/JPQLStatement.java | 1 +
.../core/access/data/JPAQueryBuilder.java | 106 ++++++++++++++++---
2 files changed, 93 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/3ed58899/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLStatement.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLStatement.java b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLStatement.java
index 56ea231..57660b0 100644
--- a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLStatement.java
+++ b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLStatement.java
@@ -120,6 +120,7 @@ public class JPQLStatement {
public static final class KEYWORD {
public static final String SELECT = "SELECT";
+ public static final String SELECT_DISTINCT = "SELECT DISTINCT";
public static final String FROM = "FROM";
public static final String WHERE = "WHERE";
public static final String LEFT_OUTER_JOIN = "LEFT OUTER JOIN";
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/3ed58899/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
----------------------------------------------------------------------
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 c5e61a8..bf20832 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,6 +18,11 @@
******************************************************************************/
package org.apache.olingo.odata2.jpa.processor.core.access.data;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import javax.persistence.EntityManager;
import javax.persistence.Query;
@@ -41,14 +46,14 @@ import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmMapping;
public class JPAQueryBuilder {
- public enum UriInfoType {
+ enum UriInfoType {
GetEntitySet,
GetEntity,
GetEntitySetCount,
GetEntityCount,
PutMergePatch,
Delete
- };
+ }
private EntityManager em = null;
private int pageSize = 0;
@@ -82,7 +87,7 @@ public class JPAQueryBuilder {
public Query build(GetEntityUriInfo uriInfo) throws ODataJPARuntimeException {
Query query = null;
try {
- ODataJPAQueryExtensionEntityListener listener = getODataJPAQuertEntityListener((UriInfo) uriInfo);
+ ODataJPAQueryExtensionEntityListener listener = getODataJPAQueryEntityListener((UriInfo) uriInfo);
if (listener != null) {
query = listener.getQuery(uriInfo, em);
}
@@ -99,7 +104,7 @@ public class JPAQueryBuilder {
public Query build(GetEntitySetCountUriInfo uriInfo) throws ODataJPARuntimeException {
Query query = null;
try {
- ODataJPAQueryExtensionEntityListener listener = getODataJPAQuertEntityListener((UriInfo) uriInfo);
+ ODataJPAQueryExtensionEntityListener listener = getODataJPAQueryEntityListener((UriInfo) uriInfo);
if (listener != null) {
query = listener.getQuery(uriInfo, em);
}
@@ -116,7 +121,7 @@ public class JPAQueryBuilder {
public Query build(GetEntityCountUriInfo uriInfo) throws ODataJPARuntimeException {
Query query = null;
try {
- ODataJPAQueryExtensionEntityListener listener = getODataJPAQuertEntityListener((UriInfo) uriInfo);
+ ODataJPAQueryExtensionEntityListener listener = getODataJPAQueryEntityListener((UriInfo) uriInfo);
if (listener != null) {
query = listener.getQuery(uriInfo, em);
}
@@ -133,7 +138,7 @@ public class JPAQueryBuilder {
public Query build(DeleteUriInfo uriInfo) throws ODataJPARuntimeException {
Query query = null;
try {
- ODataJPAQueryExtensionEntityListener listener = getODataJPAQuertEntityListener((UriInfo) uriInfo);
+ ODataJPAQueryExtensionEntityListener listener = getODataJPAQueryEntityListener((UriInfo) uriInfo);
if (listener != null) {
query = listener.getQuery(uriInfo, em);
}
@@ -150,7 +155,7 @@ public class JPAQueryBuilder {
public Query build(PutMergePatchUriInfo uriInfo) throws ODataJPARuntimeException {
Query query = null;
try {
- ODataJPAQueryExtensionEntityListener listener = getODataJPAQuertEntityListener((UriInfo) uriInfo);
+ ODataJPAQueryExtensionEntityListener listener = getODataJPAQueryEntityListener((UriInfo) uriInfo);
if (listener != null) {
query = listener.getQuery(uriInfo, em);
}
@@ -168,17 +173,16 @@ public class JPAQueryBuilder {
throws EdmException,
ODataJPAModelException, ODataJPARuntimeException {
- Query query = null;
JPQLContextType contextType = determineJPQLContextType(uriParserResultView, type);
JPQLContext jpqlContext = buildJPQLContext(contextType, uriParserResultView);
- JPQLStatement jpqlStatement = JPQLStatement.createBuilder(jpqlContext)
- .build();
- query = em.createQuery(jpqlStatement.toString());
+ JPQLStatement jpqlStatement = JPQLStatement.createBuilder(jpqlContext).build();
- return query;
+ return em.createQuery(normalizeMembers(jpqlStatement.toString()));
}
- public ODataJPAQueryExtensionEntityListener getODataJPAQuertEntityListener(UriInfo uriInfo) throws EdmException,
+
+
+ public ODataJPAQueryExtensionEntityListener getODataJPAQueryEntityListener(UriInfo uriInfo) throws EdmException,
InstantiationException, IllegalAccessException {
ODataJPAQueryExtensionEntityListener queryListener = null;
ODataJPATombstoneEntityListener listener = getODataJPATombstoneEntityListener(uriInfo);
@@ -236,7 +240,81 @@ public class JPAQueryBuilder {
return contextType;
}
- public final class JPAQueryInfo {
+ private static final Pattern NORMALIZATION_NEEDED_PATTERN = Pattern.compile(".*[\\s\\(](\\S+\\.\\S+\\.\\S+).*");
+ private static final Pattern JOIN_ALIAS_PATTERN = Pattern.compile(".*\\sJOIN\\s(\\S*\\s\\S*).*");
+
+ private static String normalizeMembers(String jpqlQuery) {
+ // check if normalization is needed (if query contains "x.y.z" elements
+ // starting with space or parenthesis)
+ Matcher normalizationNeededMatcher = NORMALIZATION_NEEDED_PATTERN.matcher(jpqlQuery);
+ if (!normalizationNeededMatcher.find()) {
+ return jpqlQuery;
+ }
+
+ String normalizedJpqlQuery = jpqlQuery;
+ Map<String, String> joinAliases = new HashMap<String, String>();
+
+ // collect information about existing joins/aliases
+ Matcher joinAliasMatcher = JOIN_ALIAS_PATTERN.matcher(normalizedJpqlQuery);
+ if (joinAliasMatcher.find()) {
+ for (int i = 1; i <= joinAliasMatcher.groupCount(); i++) {
+ String[] joinAlias = joinAliasMatcher.group(i).split(String.valueOf(JPQLStatement.DELIMITER.SPACE));
+ joinAliases.put(joinAlias[0], joinAlias[1]);
+ }
+ }
+
+ // normalize query
+ boolean normalizationNeeded = true;
+ while (normalizationNeeded) {
+ String membershipToNormalize = normalizationNeededMatcher.group(1);
+
+ // get member info
+ String memberInfo = membershipToNormalize.substring(0,
+ ordinalIndexOf(membershipToNormalize, JPQLStatement.DELIMITER.PERIOD, 1));
+
+ String alias;
+ if (joinAliases.containsKey(memberInfo)) {
+ // use existing alias
+ alias = joinAliases.get(memberInfo);
+ } else {
+ // create new join/alias
+ alias = "R" + (joinAliases.size() + 1);
+
+ int joinInsertPosition = normalizedJpqlQuery.indexOf(JPQLStatement.KEYWORD.WHERE);
+ if (joinInsertPosition == -1) {
+ joinInsertPosition = normalizedJpqlQuery.indexOf(JPQLStatement.KEYWORD.ORDERBY);
+ }
+ normalizedJpqlQuery = normalizedJpqlQuery.substring(0, joinInsertPosition) + JPQLStatement.KEYWORD.JOIN
+ + JPQLStatement.DELIMITER.SPACE + memberInfo + JPQLStatement.DELIMITER.SPACE + alias
+ + JPQLStatement.DELIMITER.SPACE + normalizedJpqlQuery.substring(joinInsertPosition);
+
+ joinAliases.put(memberInfo, alias);
+ }
+
+ // use alias
+ normalizedJpqlQuery = normalizedJpqlQuery.replaceAll(memberInfo + "\\" + JPQLStatement.DELIMITER.PERIOD,
+ alias + JPQLStatement.DELIMITER.PERIOD);
+
+ // check if further normalization is needed
+ normalizationNeededMatcher = NORMALIZATION_NEEDED_PATTERN.matcher(normalizedJpqlQuery);
+ normalizationNeeded = normalizationNeededMatcher.find();
+ }
+
+ // add distinct to avoid duplicates in result set
+ return normalizedJpqlQuery.replaceFirst(
+ JPQLStatement.KEYWORD.SELECT + JPQLStatement.DELIMITER.SPACE,
+ JPQLStatement.KEYWORD.SELECT_DISTINCT + JPQLStatement.DELIMITER.SPACE);
+ }
+
+ private static int ordinalIndexOf(String str, char s, int n) {
+ int pos = str.indexOf(s, 0);
+ while (n-- > 0 && pos != -1) {
+ pos = str.indexOf(s, pos + 1);
+ }
+ return pos;
+ }
+
+ final class JPAQueryInfo {
private Query query = null;
private boolean isTombstoneQuery = false;