Issue Details (XML | Word | Printable)

Key: NUCRDBMS-28
Type: Bug Bug
Status: Open Open
Priority: Testcase Required Testcase Required
Assignee: Unassigned
Reporter: Marco Schulze
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
DataNucleus Store RDBMS

Usage of an interface as mapped-by field in a Set leads to missing/wrong elements in the Set

Created: 05/Jun/08 12:53 AM   Updated: 29/Oct/13 11:12 AM
Component/s: None
Affects Version/s: None
Fix Version/s: None

Forum Thread URL: http://www.jpox.org/servlet/forum/viewthread?thread=5118


 Description  « Hide
When using an interface field in the mapped element as mapped-by field, the Set of the element-holder (i.e. the object having the Set field) behaves incorrectly:

* Set.isEmpty() returns true (even though there is an element).
* Set.size() returns 0 (even though there is an element).
* After calling Set.iterator(), isEmpty() returns false (correct), but the Set contains more elements than there should be (Set.size() returned 2 in my test even though there is only 1 element).

Test case: http://www.nightlabs.de/~marco/datanucleus/2008-06-03.00/TestDataNucleusOneDatastore.tar.gz
Log file: http://www.nightlabs.de/~marco/datanucleus/2008-06-03.00/datanucleus.log.gz

Marco Schulze added a comment - 05/Jun/08 01:36 AM
I just digged deeper into the query that returns too many results (i.e. 2 instead of 1):

SELECT
   'org.datanucleus.test.E' AS JPOXMETADATA,
   `THIS`.`EEE_ID`,
   `THIS`.`ORGANISATION_ID`
FROM `E` `THIS`
LEFT OUTER JOIN `F` `SUBELEMENT0`
   ON
   `SUBELEMENT0`.`EEE_ID` = `THIS`.`EEE_ID` AND
   `SUBELEMENT0`.`ORGANISATION_ID` = `THIS`.`ORGANISATION_ID`
WHERE
   `SUBELEMENT0`.`EEE_ID` IS NULL AND
   `SUBELEMENT0`.`ORGANISATION_ID` IS NULL AND
   (
     (
       (
         0 = `THIS`.`ELEMENT_HOLDER_B_BBB_ID_EID` AND
         'nightlabs.org' = `THIS`.`ELEMENT_HOLDER_B_ORGANISATION_ID_EID`
       ) OR
       (
         0 = `THIS`.`ELEMENT_HOLDER_A_AAA_ID_EID` AND
         'nightlabs.org' = `THIS`.`ELEMENT_HOLDER_A_ORGANISATION_ID_EID`
       )
     )
   )
UNION
SELECT
   'org.datanucleus.test.F' AS JPOXMETADATA,
   `THIS`.`EEE_ID`,`THIS`.`ORGANISATION_ID`
FROM `E` `THIS`
INNER JOIN `F` `ELEMENT`
   ON
   `ELEMENT`.`EEE_ID` = `THIS`.`EEE_ID` AND
   `ELEMENT`.`ORGANISATION_ID` = `THIS`.`ORGANISATION_ID`
WHERE
   (
     (
       0 = `THIS`.`ELEMENT_HOLDER_B_BBB_ID_EID` AND
       'nightlabs.org' = `THIS`.`ELEMENT_HOLDER_B_ORGANISATION_ID_EID`
     ) OR
     (
       0 = `THIS`.`ELEMENT_HOLDER_A_AAA_ID_EID` AND
       'nightlabs.org' = `THIS`.`ELEMENT_HOLDER_A_ORGANISATION_ID_EID`
     )
   )

The part before the UNION returns already 2 records. The part after the UNION returns none. Playing a bit around with it, I found out that it seems to be an issue with MySQL's query engine that evaluates this part always to true (even though the field ELEMENT_HOLDER_B_BBB_ID_EID is NULL:

  (
    0 = `THIS`.`ELEMENT_HOLDER_B_BBB_ID_EID` AND
    'nightlabs.org' = `THIS`.`ELEMENT_HOLDER_B_ORGANISATION_ID_EID`
  )

The problem seems to be that 0 is an integer while the field ELEMENT_HOLDER_B_BBB_ID_EID is a VARCHAR. Maybe that's because internally a NULL String is stored as 0. I don't know how other SQL servers behave in this situation.

Even though it's IMHO a bug in MySQL, I think it is not clean to do add this part above the "OR" in the first place: It compares primary key fields of class A with columns of class B. Since the type of the object having the pk values "nightlabs.org" and "0" is known, DataNucleus should only query the corresponding fields - i.e. the A fields (the part under the "OR").

Btw. I'm wondering what will happen, if the number of primary key fields between class A and B differs. Probably an exception ;-)

Andy Jefferson added a comment - 29/Oct/13 11:12 AM
testcase no longer exists on that server. left as guesswork as to whether the set has an interface type or the other end, whether using join table or not, etc.

Andy Jefferson made changes - 29/Oct/13 11:12 AM
Field Original Value New Value
Priority Major [ 3 ] No Testcase [ 6 ]