Community
Participate
Working Groups
Build Identifier: Eclipse Memory Analyzer Version 1.1.0 development version As reported in Eclipse Forum entry http://www.eclipse.org/forums/index.php/mv/tree/220664/#page_top entering a query with an invalid WHERE clause such as : SELECT getName() as name FROM java.lang.Class WHERE name.startsWith("com.myco") gives a NullPointerException with stack trace: Executed Query: /* Press F1 for help */ SELECT getName() as name FROM java.lang.Class WHERE name.startsWith("com.myco") java.lang.NullPointerException at org.eclipse.mat.parser.internal.oql.OQLQueryImpl.accept(OQLQueryImpl.java:1037) at org.eclipse.mat.parser.internal.oql.OQLQueryImpl.accept(OQLQueryImpl.java:1025) at org.eclipse.mat.parser.internal.oql.OQLQueryImpl.filterClasses(OQLQueryImpl.java:1007) at org.eclipse.mat.parser.internal.oql.OQLQueryImpl.doFromItem(OQLQueryImpl.java:853) at org.eclipse.mat.parser.internal.oql.OQLQueryImpl.internalExecute(OQLQueryImpl.java:650) at org.eclipse.mat.parser.internal.oql.OQLQueryImpl.execute(OQLQueryImpl.java:627) at org.eclipse.mat.inspections.OQLQuery.execute(OQLQuery.java:50) at org.eclipse.mat.inspections.OQLQuery.execute(OQLQuery.java:1) at org.eclipse.mat.query.registry.ArgumentSet.execute(ArgumentSet.java:129) at org.eclipse.mat.ui.snapshot.panes.OQLPane$OQLJob.doRun(OQLPane.java:267) at org.eclipse.mat.ui.editor.AbstractPaneJob.run(AbstractPaneJob.java:34) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54) In this instance the reason is that the variable "name" is not bound to a valid value, so the evaluation of the WHERE clause fails. This error should be handled more gracefully with an appropriate error message rather than a NullPointerException. Reproducible: Always Steps to Reproduce: 1. Start Memory Analyzer 2. Open a heap dump 3. Execute the OQL query given in the bug details.
Thanks for the bug report. In this case "name" in the WHERE clause is treaded as a field name of the selected objects, on which the comparison is done. Considering the behavior in other queries, the proper behavior should be to just ignore the objects where the field is not defined. In this case the query above will return nothing instead of throwing a NullPointerException. Does this sound as a reasonable solution?
Rather than just quietly returning nothing, would it be possible/reasonable to issue a warning message that the field name is not defined for the specified object type? This could help a user in the case of typos etc.
With this query it would make sense. However, I could also execute a broader query printing the value of "name" in all objects where such a field exists, by something like: SELECT * FROM INSTANCEOF java.lang.Object WHERE name != null This will silently ignore all objects that do not qualify... Hmm... this example doesn't seem very useful I guess. Here another one: SELECT * FROM INSTANCEOF java.util.AbstractMap WHERE size = 0 Although AbstractMap does not define "size" attribute, many of the classes inheriting it do have "size". It could be useful to get the list of classes where such field didn't exist, but depending on the query these could be hundreds. Do these examples justify my proposal to silently ignore?
I agree with Krum - I thought of the example: select * from ".*" where value != null which finds String and Double, Float, Integer etc. However select * from ".*" where value = null also finds objects where the value field is not defined. Perhaps if the field is not defined it should return a NotAThing or Undefined value which is not even equal to itself (like NaN for floating point). You could then do select * from ".*" where value = value to find objects with a value field and select * from ".*" where value != value to find objects without a value field. (Though it might also find fields containing NaN.) Is there an OQL standard we follow? Would this proposal be understood by regular users? Is the original example valid in another version of OQL or SQL? Is expecting the 'as' output column name to also be a variable a sensible thing to do? Normally the select part is not evaluated until the where clause succeeds.
Yes, with these examples it seems reasonable to adopt your original proposal, thanks.
I submitted change 1165 which adds just a simple null check to avoid the NPE. However, I'd like I noticed another strange thing - in the SELECT clause getName() works just fine, but if I trie to use something like clazz.getName() in the where clause this doesn't work. There I can use only the methods defined in IObject, e.g. getTechnicalName() which makes the query look like: SELECT getName() AS name FROM java.lang.Class c WHERE c.getTechnicalName().startsWith("class java.lang") I'd like to look at this in more details.
The problem with getName() not working is because some of the objects returned are not ClassImpl but ObjectImpl. See this comment from the help: SELECT * FROM ( SELECT * FROM java.lang.Class c WHERE c implements org.eclipse.mat.snapshot.model.IClass )The statement returns all objects in the heap. The implements check is necessary, as the heap dump can contain java.lang.Class instances caused by proxy classes. The same effect has the following query, which calls a method directly on the ISnapshot object: SELECT * FROM ${snapshot}.getClasses() You could do: SELECT * FROM java.lang.Class c where c implements org.eclipse.mat.snapshot.model.IClass and c.getName().startsWith("java.lang")
The null pointer exception no longer occurs. If we want to do something special for field names etc. which do not exist then we should deal with this under a new item.