Author: hthomann Date: Fri Jun 24 03:43:49 2016 New Revision: 1750039 URL: http://svn.apache.org/viewvc?rev=1750039&view=rev Log: OPENJPA-2631: Fix for CriteriaBuilder issue with an @EmbeddedId that contains more than one field. Ported 2.1.x commit to 2.2.1
Added: openjpa/branches/2.2.1.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/ - copied from r1750036, openjpa/branches/2.1.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/ Modified: openjpa/branches/2.2.1.x/ (props changed) openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java Propchange: openjpa/branches/2.2.1.x/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Fri Jun 24 03:43:49 2016 @@ -1,5 +1,5 @@ /openjpa/branches/1.0.x:736493 /openjpa/branches/2.0.x:1419659,1484136,1484287,1504611 -/openjpa/branches/2.1.x:1415379,1415398,1436150,1469090,1469949,1484300,1484313,1485010,1505837,1513249,1517838,1529241,1530146,1533218,1533280,1539188,1569528,1575444,1591536,1614935,1636464,1648430,1655218,1662610,1673300,1673491,1686894,1709201,1709309 +/openjpa/branches/2.1.x:1415379,1415398,1436150,1469090,1469949,1484300,1484313,1485010,1505837,1513249,1517838,1529241,1530146,1533218,1533280,1539188,1569528,1575444,1591536,1614935,1636464,1648430,1655218,1662610,1673300,1673491,1686894,1709201,1709309,1750036 /openjpa/branches/2.2.x:1580898,1580939,1591681,1641906,1642555,1702143 /openjpa/trunk:1416742,1420324,1430117,1431649,1436957,1436960,1448662,1448796,1451369,1456574,1456614,1459091,1461833,1469646,1469649,1469652,1504282,1564989,1600757,1603251 Modified: openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java URL: http://svn.apache.org/viewvc/openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java?rev=1750039&r1=1750038&r2=1750039&view=diff ============================================================================== --- openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java (original) +++ openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java Fri Jun 24 03:43:49 2016 @@ -18,6 +18,10 @@ */ package org.apache.openjpa.jdbc.kernel.exps; +import java.util.List; + +import org.apache.openjpa.jdbc.meta.ClassMapping; +import org.apache.openjpa.jdbc.meta.FieldMapping; import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.Select; @@ -62,8 +66,31 @@ class EqualExpression new FilterValueImpl(sel, ctx, bstate.state1, val1), new FilterValueImpl(sel, ctx, bstate.state2, val2)); } else { - int len = java.lang.Math.min(val1.length(sel, ctx, - bstate.state1), val2.length(sel, ctx, bstate.state2)); + int lenVal1 = val1.length(sel, ctx, bstate.state1); + int lenVal2 = val2.length(sel, ctx, bstate.state2); + int len = java.lang.Math.min(lenVal1, lenVal2); + + // OPENJPA-2631: Detect and handle slightly differently the + // case where a composite PK is in use. When an equals comparison + // is created by CriteriaBuilder, and the comparison is done against + // an entity with a composite PK, 'val2' can be either a: + // 1) Lit - in this case a Lit is hard coded to return a length of 1. + // 2) Param - in this case the metadata is null so length will return 1. + // Given this, first look to see if lenVal1 is greater than lenVal2. + if (lenVal1 > lenVal2) { + // If here, lets get the metadata from val1 and see if its PK + // is an embeddable. If so, the length (val1Len) will be the + // size of the number of colunns in the PK. Use this length + // in order to create an equal expression with the right number + // of 'AND' statementes. + ClassMapping cm = (ClassMapping) val1.getMetaData(); + FieldMapping[] fmsPK = cm.getPrimaryKeyFieldMappings(); + + if (fmsPK[0].isEmbedded()) { + len = lenVal1; + } + } + for (int i = 0; i < len; i++) { if (i > 0) buf.append(" AND "); Modified: openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java URL: http://svn.apache.org/viewvc/openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java?rev=1750039&r1=1750038&r2=1750039&view=diff ============================================================================== --- openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java (original) +++ openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java Fri Jun 24 03:43:49 2016 @@ -116,10 +116,11 @@ public class Lit public void appendTo(Select sel, ExpContext ctx, ExpState state, SQLBuffer sql, int index) { LitExpState lstate = (LitExpState) state; - if (lstate.otherLength > 1) - sql.appendValue(((Object[]) lstate.sqlValue)[index], - lstate.getColumn(index)); - else if (_isRaw) { + if (lstate.otherLength > 1) { + sql.appendValue(((Object[]) lstate.sqlValue)[index], lstate.getColumn(index)); + // OPENJPA-2631: Return so as not to go into sql.appendValue a second time below. + return; + } else if (_isRaw) { int parseType = getParseType(); if (parseType == Literal.TYPE_ENUM) { StringBuilder value = new StringBuilder(); Modified: openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java URL: http://svn.apache.org/viewvc/openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java?rev=1750039&r1=1750038&r2=1750039&view=diff ============================================================================== --- openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java (original) +++ openjpa/branches/2.2.1.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java Fri Jun 24 03:43:49 2016 @@ -253,6 +253,32 @@ public class ClassMapping sm = (OpenJPAStateManager) pc.pcGetStateManager(); if (sm == null) { ret = getValueFromUnmanagedInstance(obj, cols, true); + + // OPENJPA-2631 start + // Check to see if we are dealing with a Embeddable pk. If the PK is an Embeddable, AND IFF the + // columns in the Embeddable are greater than 1, we are dealing with a composite primary + // key, and as such 'ret' will be an instance of the embeddable, NOT the individual PK values. + // Given this, we need to dig deeper and get the individual values of the embeddable key. + // On the other hand, if the embeddable only contains one column, 'ret' will be the value of + // that column and as such no further digging is necessary. + FieldMapping[] fmsPK = this.getPrimaryKeyFieldMappings(); + List<FieldMapping> fms = getFieldMappings(cols, true); + + // Note that if we are dealing with an embeddable that is an EmbeddableId, the fms.size will + // always be 1 (since an EmbeddableId is slightly opaque, we don't have an fms for each field). + // If on the other hand we are dealing with an embeddable that is an @IdClass, fms.size will be the + // number columns in the @IdClass. Furthermore, when dealing with @IdClass, 'ret' will already + // properly contain the column values, therefore no further processing is needed. + if (fmsPK[0].isEmbedded() && cols.length > 1 && fms.size() == 1) { + // OK, we know this PK is an embeddable. So get the individual field values. + Object[] tmpRet = new Object[cols.length]; + for (int i = 0; i < cols.length; i++) { + Joinable join = this.assertJoinable(cols[i]); + tmpRet[i] = join.getJoinValue(ret, cols[i], store); + } + ret = tmpRet; + } + // OPENJPA-2631 end } else if (sm.isDetached()) { obj = store.getContext().find(sm.getObjectId(), false, null); sm = store.getContext().getStateManager(obj);