Issue #1417: [ObjectDB 2.5.5_03] Unexpected exception (Error 990)

Type: Bug ReoprtPriority: NormalStatus: FixedReplies: 9
#1

Hello!

When I run this query

SELECT t FROM Unit t
WHERE t.lastGeocodedPosition IS NULL OR
      t.lastGeocodedPosition.receiveTime < :lastGeocodedPosition.receiveTime

I get the following exception:

[ObjectDB 2.5.5_03] Unexpected exception (Error 990)
  Generated by Java HotSpot(TM) 64-Bit Server VM 1.7.0_55 (on Linux 3.13.0-27-generic).
Please report this error on http://www.objectdb.com/database/issue/new
com.objectdb.o.InternalException: null
com.objectdb.o.InternalException
at com.objectdb.o.QNF.C(QNF.java:920)
at com.objectdb.o.QNF.z(QNF.java:789)
at com.objectdb.o.QNF.k(QNF.java:258)
at com.objectdb.o.QNF.q(QNF.java:524)
at com.objectdb.o.QNF.k(QNF.java:189)
at com.objectdb.o.QNF.t(QNF.java:611)
at com.objectdb.o.QNF.t(QNF.java:605)
at com.objectdb.o.QNF.k(QNF.java:218)
at com.objectdb.o.QNF.t(QNF.java:611)
at com.objectdb.o.QNF.t(QNF.java:605)
at com.objectdb.o.QNF.k(QNF.java:224)
at com.objectdb.o.QNF.j(QNF.java:135)
at com.objectdb.o.QRC.B(QRC.java:340)
at com.objectdb.o.QRC.x(QRC.java:231)
at com.objectdb.jpa.JpaQuery.analyzeQuery(JpaQuery.java:683)
at com.objectdb.jpa.JpaQuery.getHints(JpaQuery.java:275)
at com.objectdb.o.QRP.L(QRP.java:195)
at com.objectdb.o.QRP.T(QRP.java:723)
at com.objectdb.o.QRP.actionPerformed(QRP.java:686)

Am I doing something wrong?

Regards

Ralph

#2

Maybe the type of the parameter (:lastGeocodedPosition) is unknown, so ObjectDB cannot search for field receiveTime in that object (although a better error message is required of course).

Try the following query:

SELECT t FROM Unit t
WHERE t.lastGeocodedPosition IS NULL OR
      t.lastGeocodedPosition.receiveTime < :receiveTime

and send time rather than an entity as a parameter.

ObjectDB Support
#3

You are absolutely right. This query works. Actually I passed a date parameter before but my WHERE clause generator simply took the filed name as parameter name. Normally some random characters are appended to the parameter name. A real world query looks like this:

SELECT t FROM Unit t WHERE (t.lastGeocodedPosition IS NULL OR t.lastGeocodedPosition.receiveTime < :lastGeocodedPosition.receiveTime1u6kopqt6zmjo)

Then a date is set on ":lastGeocodedPosition.receiveTime1u6kopqt6zmjo".

Obviously ObjectDB only takes ":lastGeocodedPosition" as parameter name and tries to get receiveTime1u6kopqt6zmjo from the not set parameter.

I'll change my WHERE clause generator to remove dots from parameter names. Then it should also work with nested fields.

Maybe you should implement a better exception for trying to retrieve a field of a not set parameter.

Thanks for your help

Ralph

#4

I now did some more tests. It's strange.

I think the two attached screenshots show it pretty well. All lastGeocodedPosition fields are null  BTW.

Should I open a forum thread or another issue for this problem or is it related to the other error?

#5

It seems that the expression in the WHERE clause fails with NPE for all the objects, and therefore no objects are returned from the query.

If it was a Java expression you wouldn't have NPE, because OR is evaluated from left to right.

I am not sure if this should be the case with queries (in JPQL or SQL) because expressions are reordered as part of the query optimization.

ObjectDB Support
#6

I did some research on this topic. The NULL handling of JPQL or SQL queries is well defined.

Have a look at the Persistence 2.0 specification: https://download.oracle.com/otndocs/jcp/persistence-2.0-fr-eval-oth-JSpec/
T
he chapter dealing with null handling starts on page 168. It's derived from SQL99 to which most RDBMS claim to be compatible.

Let's analyze my query:
Page 168 states: • Comparison or arithmetic operations with a NULL value always yield an unknown value.
Hence t.lastGeocodedPosition.receiveTime < :receiveTime with a NULL value evaluates to UNKNOWN.

The OR table on page 169 states that TRUE AND UNKNOWN = TRUE
t.lastGeocodedPosition IS NULL evaluates to TRUE hence the WHERE clause should be TRUE.

#7

NULL < :receiveTime is UNKNOWN, because it is comparison with NULL.

But t.lastGeocodedPosition.receiveTime is not NULL but NPE so you do not compare null.

Accessing fields through a null expression is very different from comparison and arithmetic operations.

I think that according to the JPA specification, your query is equivalent to:

SELECT t
FROM Unit t INNER JOIN t.lastGeocodedPosition l
WHERE l IS NULL OR l.receiveTime < :last

and since there is no t.lastGeocodedPosition there are no results.

Maybe you should try:

SELECT t
FROM Unit t LEFT OUTER JOIN t.lastGeocodedPosition l
WHERE l.receiveTime < :last

See also this paragraph in the manual.

ObjectDB Support
#8

I overlooked the NULL navigation thing. Sorry.

Your suggested query doesn't work but I modified it a little bit and now it does:

SELECT t
FROM Unit t LEFT OUTER JOIN t.lastGeocodedPosition l WHERE
l.receiveTime < :last OR l IS NULL

The question is why. l IS NULL clearly evaluates to true on every record currently in my DB  but l.receiveTime should again lead to a NPE or am I wrong?

#9

You are right, and actually NPE is not really defined in the JPA spec. I think that accessing a value field using a NULL reference is evaluated to either NULL or UNKNOWN,  Accessing an entity is a different story because it implicitly defines an INNER JOIN, i.e. an internal loop, and if the the internal loop is empty for a specific Unit, that Unit is ignored. So there is a difference between NPE as a result of accessing a value field and NPE as a result of accessing a relationship.

We implemented a better error message for the exception in your original post (will be released in a new build shortly), so this issue can be closed now.

ObjectDB Support
#10
ObjectDB Support

Reply