diff options
| author | Andrew Johnson | 2019-11-09 21:37:37 +0000 |
|---|---|---|
| committer | Andrew Johnson | 2019-11-09 21:48:44 +0000 |
| commit | f4f97ad2226c0e8f7e714f786b99a422e52ac79c (patch) | |
| tree | a747b75ab61593202ac9c10cb31e1ef9fc1f7b94 | |
| parent | b717cc5add67f0f0010ebfeb313574a2a7a4332b (diff) | |
| download | org.eclipse.mat-f4f97ad2226c0e8f7e714f786b99a422e52ac79c.tar.gz org.eclipse.mat-f4f97ad2226c0e8f7e714f786b99a422e52ac79c.tar.xz org.eclipse.mat-f4f97ad2226c0e8f7e714f786b99a422e52ac79c.zip | |
552879: OQL enhancements for sub-selects, maps, context providers etc.
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=552879
Change-Id: I52e78ef8c3f679cb3d294c70eea329cbd2913eaf
14 files changed, 799 insertions, 83 deletions
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/collectionextract/IMapExtractor.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/collectionextract/IMapExtractor.java index 34421c64..eeb91b4e 100644 --- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/collectionextract/IMapExtractor.java +++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/collectionextract/IMapExtractor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2015 SAP AG, IBM Corporation and others + * Copyright (c) 2008, 2019 SAP AG, IBM Corporation and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -150,5 +150,10 @@ public interface IMapExtractor extends ICollectionExtractor { throw new IllegalArgumentException(); } + + public String toString() + { + return getKey().getDisplayName()+ "=" +getValue().getDisplayName(); //$NON-NLS-1$ + } } } diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/snapshot/OQL.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/snapshot/OQL.java index bbdde926..2552dc2f 100644 --- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/snapshot/OQL.java +++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/snapshot/OQL.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2009 SAP AG.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@ *
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson (IBM Corporation) - unions
*******************************************************************************/
package org.eclipse.mat.snapshot;
@@ -89,19 +90,29 @@ public final class OQL return "SELECT * FROM " + classId; //$NON-NLS-1$
}
- private static CharSequence lastId(CharSequence query)
+ /**
+ * Find the last identifier of the query
+ * @param query
+ * @return the identifier, including a space
+ */
+ private static CharSequence lastId(CharSequence query, int end)
{
- int end = query.length();
int j = end - 1;
while (j >= 0 && Character.isJavaIdentifierPart(query.charAt(j))) --j;
if (j < end - 1 && Character.isJavaIdentifierStart(query.charAt(j + 1)))
- {
+ {
if (isSpace(query, j))
- return query.subSequence(j, query.length());
+ return query.subSequence(j, end);
}
return ""; //$NON-NLS-1$
}
+ /**
+ * Extract out digits, spaces and commas going backward
+ * @param s
+ * @param e start position
+ * @return the sequence of digits, spaces, commas
+ */
private static CharSequence matchObjs(CharSequence s, int e) {
int i = e - 1;
while (isSpace(s, i))
@@ -145,30 +156,28 @@ public final class OQL * select s.a,s.b,s.c from 123 s
* combine to
* select s.a,s.b,s.c from 1,173,123 s
+ *
+ * Also split off UNION clauses to see if the new clause can
+ * be merged into an existing UNION clause.
*/
public static void union(StringBuilder query, String other)
{
if ((query.length() > 0))
{
-
- CharSequence id1 = lastId(query.toString());
- CharSequence id2 = lastId(other);
- if (id1.equals(id2))
+ int end = query.length();
+ while (query.charAt(end - 1) == ')')
{
- CharSequence num1 = matchObjs(query, query.length() - id1.length());
- CharSequence num2 = matchObjs(other, other.length() - id2.length());
- int s1 = query.length() - id1.length() - num1.length();
- int s2 = other.length() - id2.length() - num2.length();
- if (num1.length() > 0 && num2.length() > 0 &&
- query.subSequence(0, s1).equals(
- other.subSequence(0, s2)))
- {
- int j = 0;
- while (isSpace(num2, j)) ++j;
- query.insert(s1 + num1.length(), ","+num2.subSequence(j, num2.length())); //$NON-NLS-1$
+ int start = query.lastIndexOf(" UNION ("); //$NON-NLS-1$
+ if (start == -1)
+ break;
+ if (union(query, start + 8, end - 1, other))
return;
- }
+ if (start < 1)
+ break;
+ end = start;
}
+ if (union(query, 0, end, other))
+ return;
// Default
query.append(" UNION (").append(other).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
}
@@ -176,6 +185,31 @@ public final class OQL query.append(other);
}
+ private static boolean union(StringBuilder query, int start, int end, String other)
+ {
+ // Strip off last identifier
+ CharSequence id1 = lastId(query, end);
+ CharSequence id2 = lastId(other, other.length());
+ if (id1.equals(id2))
+ {
+ // Find the object identifiers
+ CharSequence num1 = matchObjs(query, end - id1.length());
+ CharSequence num2 = matchObjs(other, other.length() - id2.length());
+ int s1 = end - id1.length() - num1.length();
+ int s2 = other.length() - id2.length() - num2.length();
+ if (num1.length() > 0 && num2.length() > 0 &&
+ query.subSequence(start, s1).equals(
+ other.subSequence(0, s2)))
+ {
+ int j = 0;
+ while (isSpace(num2, j)) ++j;
+ query.insert(s1 + num1.length(), ","+num2.subSequence(j, num2.length())); //$NON-NLS-1$
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Return all instances of classes matching a given regular expression.
*/
@@ -212,7 +246,7 @@ public final class OQL /**
* Returns an OQL query string to select all objects loaded by the given
* class loader.
- *
+ *
* <pre>
* select *
* from
@@ -224,7 +258,7 @@ public final class OQL * and c.@classLoaderId = {0}
* )
* </pre>
- *
+ *
* @param classLoaderId
* the object id of the class loader
* @return an OQL query selecting all objects loaded by the class loader
@@ -241,7 +275,7 @@ public final class OQL /**
* Returns an OQL query string to select all classes loaded by the given
* class loader.
- *
+ *
* <pre>
* select *
* from java.lang.Class c
@@ -249,7 +283,7 @@ public final class OQL * c implements org.eclipse.mat.snapshot.model.IClass
* and c.@classLoaderId = {0}
* </pre>
- *
+ *
* @param classLoaderId
* the object id of the class loader
* @return an OQL query selecting all classes loaded by the class loader
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/OQLQueryImpl.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/OQLQueryImpl.java index 30be010b..9a9f443b 100644 --- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/OQLQueryImpl.java +++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/OQLQueryImpl.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG and IBM Corporation.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,17 +7,20 @@ *
* Contributors:
* SAP AG - initial API and implementation
- * IBM Corporation - bug fixes for instanceof
+ * IBM Corporation - bug fixes for instanceof, big changes for tables
*******************************************************************************/
package org.eclipse.mat.parser.internal.oql;
import java.io.StringReader;
import java.lang.reflect.Array;
+import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -33,14 +36,18 @@ import org.eclipse.mat.parser.internal.oql.compiler.CompilerImpl; import org.eclipse.mat.parser.internal.oql.compiler.EvaluationContext;
import org.eclipse.mat.parser.internal.oql.compiler.Expression;
import org.eclipse.mat.parser.internal.oql.compiler.Query;
+import org.eclipse.mat.parser.internal.oql.compiler.Query.FromClause;
import org.eclipse.mat.parser.internal.oql.compiler.Query.SelectItem;
import org.eclipse.mat.parser.internal.oql.parser.OQLParser;
import org.eclipse.mat.parser.internal.oql.parser.ParseException;
import org.eclipse.mat.parser.internal.oql.parser.TokenMgrError;
import org.eclipse.mat.query.Column;
+import org.eclipse.mat.query.ContextProvider;
import org.eclipse.mat.query.IContextObject;
import org.eclipse.mat.query.IContextObjectSet;
import org.eclipse.mat.query.IResultTable;
+import org.eclipse.mat.query.IResultTree;
+import org.eclipse.mat.query.IStructuredResult;
import org.eclipse.mat.query.ResultMetaData;
import org.eclipse.mat.snapshot.IOQLQuery;
import org.eclipse.mat.snapshot.ISnapshot;
@@ -51,6 +58,7 @@ import org.eclipse.mat.snapshot.model.IObject; import org.eclipse.mat.util.IProgressListener;
import org.eclipse.mat.util.MessageUtil;
import org.eclipse.mat.util.PatternUtil;
+import org.eclipse.mat.util.SilentProgressListener;
import org.eclipse.mat.util.SimpleMonitor;
import org.eclipse.mat.util.VoidProgressListener;
@@ -63,13 +71,208 @@ public class OQLQueryImpl implements IOQLQuery // result set implementations
// //////////////////////////////////////////////////////////////
- private interface CustomTableResultSet extends IOQLQuery.Result, IResultTable
+ private interface CustomTableResultSet extends IOQLQuery.Result, IResultTable, List<Object>
{}
/**
+ * Get more details for a table.
+ * Allows extra menu options for columns holding objects.
+ * @param rt
+ * @param columns
+ * @param source
+ * @return
+ */
+ private static ResultMetaData getResultMetaData(IResultTable rt, Query query)
+ {
+ Column columns[] = rt.getColumns();
+ ResultMetaData.Builder builder = new ResultMetaData.Builder();
+ int prov = 0;
+ for (int ii = 0; ii < columns.length; ++ii)
+ {
+ // Find an example object for each column
+ Object sample = rt.getColumnValue(rt.getRow(0), ii);
+ // See if it is one or more objects from the dump
+ if (sample instanceof IObject || sample instanceof Iterable<?> && ((Iterable<?>)sample).iterator().hasNext() && ((Iterable<?>)sample).iterator().next() instanceof IObject)
+ {
+ // Also add the underlying row
+ if (prov == 0 && rt.getContext(rt.getRow(0)) != null)
+ {
+ String label;
+ FromClause fc = query.getFromClause();
+ if (fc != null)
+ {
+ String alias = fc.getAlias();
+ if (alias != null)
+ label = alias;
+ else
+ label = fc.toString();
+ }
+ else
+ {
+ label = query.toString();
+ }
+ builder.addContext(new ContextProvider(label) {
+ @Override
+ public IContextObject getContext(Object row)
+ {
+ return rt.getContext(row);
+ }
+ });
+ ++prov;
+ };
+ int columnIndex = ii;
+ builder.addContext(new ContextProvider(columns[ii].getLabel()) {
+
+ @Override
+ public IContextObject getContext(Object row)
+ {
+ Object o = rt.getColumnValue(row, columnIndex);
+ if (o instanceof IObject)
+ {
+ IObject io = (IObject)o;
+ return new IContextObjectSet() {
+
+ @Override
+ public int getObjectId()
+ {
+
+ return io.getObjectId();
+ }
+
+ @Override
+ public int[] getObjectIds()
+ {
+
+ return new int[] {io.getObjectId()};
+ }
+
+ @Override
+ public String getOQL()
+ {
+ String alias = query.getFromClause().getAlias();
+ String alias2;
+ if (alias == null)
+ alias2 = ""; //$NON-NLS-1$
+ else
+ alias2 = " "+alias; //$NON-NLS-1$
+ Query.SelectItem column = query.getSelectClause().getSelectList().get(columnIndex);
+ return "SELECT "+column.toString()+" FROM OBJECTS " + getObjectId()+alias2; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ };
+ }
+ else if (o instanceof Iterable<?>)
+ {
+ Iterable<?>l = (Iterable<?>)o;
+ return new IContextObjectSet() {
+
+ @Override
+ public int getObjectId()
+ {
+
+ return rt.getContext(row).getObjectId();
+ }
+
+ @Override
+ public int[] getObjectIds()
+ {
+ ArrayInt ai = new ArrayInt();
+ for (Object o : l)
+ {
+ if (o instanceof IObject)
+ {
+ ai.add(((IObject)o).getObjectId());
+ }
+ }
+ return ai.toArray();
+ }
+
+ @Override
+ public String getOQL()
+ {
+ String alias = query.getFromClause().getAlias();
+ String alias2;
+ if (alias == null)
+ alias2 = ""; //$NON-NLS-1$
+ else
+ alias2 = " "+alias; //$NON-NLS-1$
+ Query.SelectItem column = query.getSelectClause().getSelectList().get(columnIndex);
+ return "SELECT "+column.toString()+" FROM OBJECTS " + getObjectId()+alias2; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ };
+ }
+ return null;
+ }
+
+ });
+ ++prov;
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Find the distinct rows in the table.
+ * @param table
+ * @return an array of unique rows
+ */
+ private static ArrayInt distinctList(IResultTable table)
+ {
+ LinkedHashSet<Object> hs = new LinkedHashSet<Object>();
+ ArrayInt newrows = new ArrayInt();
+ Column columns[] = table.getColumns();
+ for (int i = 0; i < table.getRowCount(); ++i)
+ {
+ List<Object>rowo = new ArrayList<Object>();
+ Object row = table.getRow(i);
+ for (int j = 0; j < columns.length; ++j)
+ {
+ rowo.add(table.getColumnValue(row, j));
+ }
+ if (hs.add(rowo))
+ {
+ newrows.add(i);
+ }
+ }
+ hs.clear();
+ return newrows;
+ }
+
+ private static abstract class AbstractCustomTableResultSet extends AbstractList<Object> implements CustomTableResultSet
+ {
+ @Override
+ public Object get(int index)
+ {
+ int cols = getColumns().length;
+ if (cols == 1)
+ return getColumnValue(getRow(index), 0);
+ // Delay resolving columns until needed
+ List<Object>l = new AbstractList<Object>() {
+ @Override
+ public Object get(int col)
+ {
+ return getColumnValue(getRow(index), col);
+ }
+
+ @Override
+ public int size()
+ {
+ return cols;
+ }
+ };
+ return l;
+ }
+
+ @Override
+ public int size()
+ {
+ return getRowCount();
+ }
+ }
+
+ /**
* Result from a select with select list where the from clause returned a list or array of objects.
*/
- private static class ObjectResultSet implements CustomTableResultSet
+ private static class ObjectResultSet extends AbstractCustomTableResultSet implements CustomTableResultSet
{
private static final Object NULL_VALUE = new Object();
@@ -106,7 +309,7 @@ public class OQLQueryImpl implements IOQLQuery try
{
for (int ii = 0; ii < columns.length; ii++)
- columns[ii] = buildColumn(selectList.get(ii), getColumnValue(0, ii));
+ columns[ii] = buildColumn(selectList.get(ii), getColumnValue(getRow(0), ii));
}
catch (RuntimeException e)
{
@@ -116,7 +319,7 @@ public class OQLQueryImpl implements IOQLQuery public ResultMetaData getResultMetaData()
{
- return null;
+ return OQLQueryImpl.getResultMetaData(this, source.query);
}
public Column[] getColumns()
@@ -214,7 +417,7 @@ public class OQLQueryImpl implements IOQLQuery /**
* Result from a select with select list where the from clause returned an array of object IDs.
*/
- private static class ResultSet implements CustomTableResultSet
+ private static class ResultSet extends AbstractCustomTableResultSet implements CustomTableResultSet
{
private static final Object NULL_VALUE = new Object();
@@ -245,7 +448,7 @@ public class OQLQueryImpl implements IOQLQuery try
{
for (int ii = 0; ii < columns.length; ii++)
- columns[ii] = buildColumn(selectList.get(ii), getColumnValue(0, ii));
+ columns[ii] = buildColumn(selectList.get(ii), getColumnValue(getRow(0), ii));
}
catch (RuntimeException e)
{
@@ -256,7 +459,7 @@ public class OQLQueryImpl implements IOQLQuery public ResultMetaData getResultMetaData()
{
- return null;
+ return OQLQueryImpl.getResultMetaData(this, source.query);
}
public int getRowCount()
@@ -351,15 +554,17 @@ public class OQLQueryImpl implements IOQLQuery return new Column(name, type).noTotals();
}
- private static class UnionResultSet implements Result, IResultTable
+ private static class UnionResultSet extends AbstractCustomTableResultSet implements Result, IResultTable
{
private static class ValueHolder
{
+ Query query;
IResultTable source;
Object row;
- public ValueHolder(IResultTable source, Object row)
+ public ValueHolder(Query query, IResultTable source, Object row)
{
+ this.query = query;
this.source = source;
this.row = row;
}
@@ -367,19 +572,160 @@ public class OQLQueryImpl implements IOQLQuery }
int size = 0;
+ List<Query> queries = new ArrayList<Query>();
List<CustomTableResultSet> resultSets = new ArrayList<CustomTableResultSet>();
ArrayInt sizes = new ArrayInt(5);
- public void addResultSet(CustomTableResultSet resultSet)
+ public void addResultSet(Query query, CustomTableResultSet resultSet)
{
+ queries.add(query);
sizes.add(size);
size += resultSet.getRowCount();
resultSets.add(resultSet);
}
+ /**
+ * Metadata for object columns for UNION queries
+ */
public ResultMetaData getResultMetaData()
{
- return null;
+ Column columns[] = getColumns();
+ ResultMetaData.Builder builder = new ResultMetaData.Builder();
+ int prov = 0;
+ for (int ii = 0; ii < columns.length; ++ii)
+ {
+ // Find an example object for each column
+ Object sample = null;
+ IContextObject sampleContext = null;
+ // Look in each table in case single columns have blanks
+ for (IResultTable tab : resultSets)
+ {
+ Object o = tab.getColumnValue(tab.getRow(0), ii);
+ if (o != null)
+ {
+ sample = o;
+ if (prov == 0)
+ sampleContext = tab.getContext(tab.getRow(0));
+ break;
+ }
+ }
+ // See if it is one or more objects from the dump
+ if (sample instanceof IObject || sample instanceof Iterable<?> && ((Iterable<?>)sample).iterator().hasNext() && ((Iterable<?>)sample).iterator().next() instanceof IObject)
+ {
+ // Also add the underlying row
+ if (prov == 0 && sampleContext != null)
+ {
+ String label;
+ FromClause fc = queries.get(0).getFromClause();
+ if (fc != null)
+ {
+ String alias = fc.getAlias();
+ if (alias != null)
+ label = alias;
+ else
+ label = fc.toString();
+ }
+ else
+ {
+ label = queries.get(0).toString();
+ }
+ builder.addContext(new ContextProvider(label) {
+ @Override
+ public IContextObject getContext(Object row)
+ {
+ return UnionResultSet.this.getContext(row);
+ }
+ });
+ ++prov;
+ };
+ int columnIndex = ii;
+ builder.addContext(new ContextProvider(columns[ii].getLabel()) {
+
+ @Override
+ public IContextObject getContext(Object row)
+ {
+ Object o = getColumnValue(row, columnIndex);
+ if (o instanceof IObject)
+ {
+ IObject io = (IObject)o;
+ return new IContextObjectSet() {
+
+ @Override
+ public int getObjectId()
+ {
+
+ return io.getObjectId();
+ }
+
+ @Override
+ public int[] getObjectIds()
+ {
+
+ return new int[] {io.getObjectId()};
+ }
+
+ @Override
+ public String getOQL()
+ {
+ String alias = ((ValueHolder)row).query.getFromClause().getAlias();
+ String alias2;
+ if (alias == null)
+ alias2 = ""; //$NON-NLS-1$
+ else
+ alias2 = " "+alias; //$NON-NLS-1$
+ Query.SelectItem column = ((ValueHolder)row).query.getSelectClause().getSelectList().get(columnIndex);
+ return "SELECT "+column.toString()+" FROM OBJECTS " + getObjectId()+alias2; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ };
+ }
+ else if (o instanceof Iterable<?>)
+ {
+ Iterable<?>l = (Iterable<?>)o;
+ return new IContextObjectSet() {
+
+ @Override
+ public int getObjectId()
+ {
+
+ return UnionResultSet.this.getContext(row).getObjectId();
+ }
+
+ @Override
+ public int[] getObjectIds()
+ {
+ ArrayInt ai = new ArrayInt();
+ for (Object o : l)
+ {
+ if (o instanceof IObject)
+ {
+ ai.add(((IObject)o).getObjectId());
+ }
+ }
+ return ai.toArray();
+ }
+
+ @Override
+ public String getOQL()
+ {
+ String alias = ((ValueHolder)row).query.getFromClause().getAlias();
+ String alias2;
+ if (alias == null)
+ alias2 = ""; //$NON-NLS-1$
+ else
+ alias2 = " "+alias; //$NON-NLS-1$
+ Query.SelectItem column = ((ValueHolder)row).query.getSelectClause().getSelectList().get(columnIndex);
+ return "SELECT "+column.toString()+" FROM OBJECTS " + getObjectId()+alias2; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ };
+ }
+ return null;
+ }
+
+ });
+ ++prov;
+ }
+ }
+ return builder.build();
}
public Column[] getColumns()
@@ -395,9 +741,10 @@ public class OQLQueryImpl implements IOQLQuery public Object getRow(int index)
{
int ii = findPageFor(index);
+ Query query = queries.get(ii);
IResultTable rs = resultSets.get(ii);
Object value = rs.getRow(index - sizes.get(ii));
- return new ValueHolder(rs, value);
+ return new ValueHolder(query, rs, value);
}
public Object getColumnValue(Object row, int columnIndex)
@@ -708,7 +1055,7 @@ public class OQLQueryImpl implements IOQLQuery if (result instanceof CustomTableResultSet)
{
unionResultSet = new UnionResultSet();
- unionResultSet.addResultSet((CustomTableResultSet) result);
+ unionResultSet.addResultSet(query, (CustomTableResultSet) result);
}
else if (result instanceof IntResult)
{
@@ -740,7 +1087,7 @@ public class OQLQueryImpl implements IOQLQuery {
if (unionResultSet != null)
{
- unionResultSet.addResultSet((CustomTableResultSet) unionResult);
+ unionResultSet.addResultSet(q, (CustomTableResultSet) unionResult);
}
else if (unionIntResult != null)
{
@@ -755,7 +1102,7 @@ public class OQLQueryImpl implements IOQLQuery else
{
unionResultSet = new UnionResultSet();
- unionResultSet.addResultSet((CustomTableResultSet) unionResult);
+ unionResultSet.addResultSet(q, (CustomTableResultSet) unionResult);
}
}
}
@@ -768,6 +1115,14 @@ public class OQLQueryImpl implements IOQLQuery OQLQueryImpl subQuery = new OQLQueryImpl(this.ctx, query.getFromClause().getSubSelect());
Object result = subQuery.internalExecute(monitor);
+ if (result instanceof IResultTable || result instanceof IResultTree)
+ {
+ if (query.getFromClause().includeObjects() && !query.getFromClause().includeSubClasses())
+ {
+ return filterAndSelect((IStructuredResult)result, monitor);
+ }
+ }
+
if (!(result instanceof IntResult))
throw new SnapshotException(MessageUtil.format(Messages.OQLQueryImpl_Error_MustReturnObjectList,
new Object[] { query.getFromClause().getSubSelect() }));
@@ -944,7 +1299,10 @@ public class OQLQueryImpl implements IOQLQuery {
Expression method = query.getFromClause().getCall();
this.ctx.setSubject(this.ctx.getSnapshot());
+ this.ctx.setProgressListener(listener);
+ IProgressListener old = ctx.getProgressListener();
Object result = method.compute(this.ctx);
+ this.ctx.setProgressListener(old);
if (query.getFromClause().includeObjects() && !query.getFromClause().includeSubClasses())
{
@@ -958,7 +1316,7 @@ public class OQLQueryImpl implements IOQLQuery for (Object obj : (Iterable<?>) result)
{
- if (accept(obj))
+ if (accept(obj, listener))
r.add(obj);
}
@@ -972,15 +1330,19 @@ public class OQLQueryImpl implements IOQLQuery for (int ii = 0; ii < length; ii++)
{
Object obj = Array.get(result, ii);
- if (accept(obj))
+ if (accept(obj, listener))
r.add(obj);
}
return r.isEmpty() ? null : select(r, listener);
}
+ else if (result instanceof IResultTable || result instanceof IResultTree)
+ {
+ return filterAndSelect((IStructuredResult)result, listener);
+ }
else
{
- return accept(result) ? select(result, listener) : null;
+ return accept(result, listener) ? select(result, listener) : null;
}
}
else
@@ -1107,7 +1469,7 @@ public class OQLQueryImpl implements IOQLQuery IntResult filteredSet = createIntResult(classes.size());
for (IClass clasz : classes)
{
- if (accept(clasz.getObjectId()))
+ if (accept(clasz.getObjectId(), listener))
filteredSet.add(clasz.getObjectId());
if (listener.isCanceled())
@@ -1119,7 +1481,24 @@ public class OQLQueryImpl implements IOQLQuery }
else
{
- listener.beginTask(Messages.OQLQueryImpl_CollectingObjects, classes.size());
+ // Keep track of progress via classes or objects
+ int work = classes.size();
+ boolean countObjs = work < 1000;
+ if (countObjs)
+ {
+ for (IClass clasz : classes)
+ {
+ work += clasz.getNumberOfObjects();
+ }
+ if (work < classes.size())
+ {
+ // Original way
+ countObjs = false;
+ work = classes.size();
+ }
+ }
+
+ listener.beginTask(Messages.OQLQueryImpl_CollectingObjects, work);
IntResult filteredSet = createIntResult(classes.size() * 100);
for (IClass clasz : classes)
@@ -1130,36 +1509,47 @@ public class OQLQueryImpl implements IOQLQuery int[] ids = clasz.getObjectIds();
for (int id : ids)
{
- if (accept(id))
+ if (accept(id, listener))
filteredSet.add(id);
+
+ if (countObjs)
+ listener.worked(1);
+ if (listener.isCanceled())
+ throw new IProgressListener.OperationCanceledException();
}
if (listener.isCanceled())
throw new IProgressListener.OperationCanceledException();
- listener.worked(1);
+ if (!countObjs)
+ listener.worked(1);
}
return filteredSet.isEmpty() ? null : select(filteredSet, listener);
}
}
- private boolean accept(int objectId) throws SnapshotException
+ private boolean accept(int objectId, IProgressListener mon) throws SnapshotException
{
if (query.getWhereClause() == null)
return true;
- return accept(ctx.getSnapshot().getObject(objectId));
+ return accept(ctx.getSnapshot().getObject(objectId), mon);
}
- private boolean accept(Object object) throws SnapshotException
+ private boolean accept(Object object, IProgressListener mon) throws SnapshotException
{
if (query.getWhereClause() == null)
return true;
ctx.setSubject(object);
+ // We don't track work for the WHERE clause
+ IProgressListener old = ctx.getProgressListener();
+ ctx.setProgressListener(new SilentProgressListener(mon));
Boolean result = (Boolean) query.getWhereClause().compute(ctx);
+ ctx.setProgressListener(old);
+
return result == null ? false : result.booleanValue();
}
@@ -1173,7 +1563,7 @@ public class OQLQueryImpl implements IOQLQuery throw new IProgressListener.OperationCanceledException();
int id = iter.nextInt();
- if (accept(id))
+ if (accept(id, listener))
filteredSet.add(id);
}
@@ -1203,7 +1593,22 @@ public class OQLQueryImpl implements IOQLQuery }
else
{
- return new ResultSet(getSelectQuery(), objectIds.toArray());
+ if (select.isDistinct())
+ {
+ int ids[] = objectIds.toArray();
+ ResultSet r1 = new ResultSet(getSelectQuery(), ids);
+ ArrayInt aa = distinctList(r1);
+ // Reuse the array from remapping list to the list of object ids
+ for (int i = 0; i < aa.size(); ++i)
+ {
+ aa.set(i, ids[aa.get(i)]);
+ }
+ return new ResultSet(getSelectQuery(), aa.toArray());
+ }
+ else
+ {
+ return new ResultSet(getSelectQuery(), objectIds.toArray());
+ }
}
}
@@ -1227,10 +1632,75 @@ public class OQLQueryImpl implements IOQLQuery }
else
{
- return new ObjectResultSet(getSelectQuery(), objects);
+ if (select.isDistinct())
+ {
+ // Prefilter the list, we also make distinct on column values
+ Set<Object>so = new LinkedHashSet<Object>(objects);
+ Object objs[] = so.toArray(new Object[so.size()]);
+ so.clear();
+ ObjectResultSet s1 = new ObjectResultSet(getSelectQuery(), objs);
+ ArrayInt aa = distinctList(s1);
+ Object objs2[] = new Object[aa.size()];
+ for (int i = 0; i < aa.size(); ++i)
+ {
+ objs2[i] = objs[aa.get(i)];
+ }
+ return new ObjectResultSet(getSelectQuery(), objs2);
+ }
+ else
+ {
+ return new ObjectResultSet(getSelectQuery(), objects);
+ }
}
}
+ private Object filterAndSelect(IStructuredResult result, IProgressListener listener) throws SnapshotException
+ {
+ List<Object> r = new ArrayList<Object>();
+ IStructuredResult irt = (IStructuredResult)result;
+ Column cols[] = irt.getColumns();
+ int colCount = cols.length;
+ List<?>elements = irt instanceof IResultTree ? ((IResultTree)irt).getElements() : null;
+ int count = irt instanceof IResultTable ? ((IResultTable)irt).getRowCount() : elements.size();
+ for (int ii = 0; ii < count; ii++)
+ {
+ if (listener.isCanceled())
+ throw new IProgressListener.OperationCanceledException();
+ Object row = irt instanceof IResultTable ? ((IResultTable)irt).getRow(ii) : elements.get(ii);
+ Object rowobj;
+ // Should single select items be wrapped?
+ if (colCount > 1)
+ {
+ // Delay resolving columns until needed
+ List<Object>l = new AbstractList<Object>() {
+ @Override
+ public Object get(int index)
+ {
+ return irt.getColumnValue(row, index);
+ }
+
+ @Override
+ public int size()
+ {
+ return colCount;
+ }
+ };
+ rowobj = l;
+ }
+ else
+ {
+ rowobj = irt.getColumnValue(row, 0);
+ }
+ // Don't use any context object for the select
+ //IContextObject ic = irt.getContext(row);
+ //IObject o = ctx.getSnapshot().getObject(ic.getObjectId());
+ if (accept(rowobj, listener))
+ r.add(rowobj);
+ }
+
+ return r.isEmpty() ? null : select(r, listener);
+ }
+
private Object select(Object object, IProgressListener listener) throws SnapshotException
{
Query.SelectClause select = query.getSelectClause();
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/ArrayIndexExpression.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/ArrayIndexExpression.java index 0cf78cd0..1a2cb793 100644 --- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/ArrayIndexExpression.java +++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/ArrayIndexExpression.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2012, 2017 IBM Corporation.
+ * Copyright (c) 2012, 2019 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,12 +13,15 @@ package org.eclipse.mat.parser.internal.oql.compiler; import java.lang.ref.SoftReference;
import java.lang.reflect.Array;
import java.util.AbstractList;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.inspections.collectionextract.CollectionExtractionUtils;
import org.eclipse.mat.inspections.collectionextract.ExtractedCollection;
+import org.eclipse.mat.inspections.collectionextract.ExtractedMap;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.snapshot.model.IObjectArray;
@@ -178,7 +181,63 @@ class ArrayIndexExpression extends Expression }
}
-
+
+ private static class MapObjectSubList extends AbstractList<Entry<IObject,IObject>>
+ {
+ private final ExtractedMap coll;
+ private final int i1;
+ private final int i2;
+ /** Cache extraction of the objects in the collection */
+ SoftReference<List<Entry<IObject,IObject>>> sr = null;
+ /** Lazy fill of the list */
+ Iterator<Entry<IObject,IObject>> it;
+
+ public MapObjectSubList(ExtractedMap map, int i1, int i2)
+ {
+ this.coll = map;
+ this.i1 = i1;
+ this.i2 = i2;
+ }
+
+ @Override
+ public Entry<IObject,IObject> get(int index)
+ {
+ if (index < 0 || index >= size())
+ throw new IndexOutOfBoundsException(Integer.toString(index));
+ List<Entry<IObject,IObject>> objs;
+ if (!(sr != null && (objs = sr.get()) != null))
+ {
+ objs = new ArrayList<Entry<IObject,IObject>>();
+ it = coll.iterator();
+ sr = new SoftReference<List<Entry<IObject,IObject>>>(objs);
+ }
+ if (i1 + index >= i2)
+ {
+ throw new IllegalArgumentException(index + " >= " + (i2 - i1) +" " + coll.getTechnicalName()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ // Fill array to required point
+ for (int i = objs.size(); it.hasNext() && i < i1 + index + 1; ++i)
+ {
+ objs.add(it.next());
+ }
+ if (i1 + index >= objs.size())
+ {
+ /*
+ * Currently the CollectionsExtractor only returns non-null entries, so the number of entries
+ * can be less than the size, so pad at the end with nulls.
+ */
+ return null;
+ }
+ return objs.get(i1 + index);
+ }
+
+ @Override
+ public int size()
+ {
+ return i2 - i1;
+ }
+ }
+
List<Expression> parameters;
public ArrayIndexExpression(List<Expression> parameters)
@@ -270,6 +329,25 @@ class ArrayIndexExpression extends Expression else if (subject instanceof IObject)
{
IObject obj = (IObject) subject;
+ ExtractedMap map = CollectionExtractionUtils.extractMap(obj);
+ if (map != null)
+ {
+ Object objlen = map.size();
+ if (objlen != null)
+ {
+ int len = (Integer)objlen;
+ if (range)
+ {
+ final int i1 = normalize(index, len, 0), i2 = normalize(index2, len, 1);
+ return new MapObjectSubList(map, i1, i2);
+ }
+ if (index >= len)
+ return null;
+ if (index < 0)
+ return null;
+ return (new MapObjectSubList(map, index, index+1)).get(0);
+ }
+ }
ExtractedCollection coll = CollectionExtractionUtils.extractList(obj);
if (coll != null && coll.hasExtractableContents())
{
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/EvaluationContext.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/EvaluationContext.java index bb76dcd8..525a8881 100644 --- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/EvaluationContext.java +++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/EvaluationContext.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,10 +7,12 @@ *
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson (IBM Corporation) - progress listener
*******************************************************************************/
package org.eclipse.mat.parser.internal.oql.compiler;
import org.eclipse.mat.snapshot.ISnapshot;
+import org.eclipse.mat.util.IProgressListener;
public class EvaluationContext
{
@@ -18,6 +20,7 @@ public class EvaluationContext ISnapshot snapshot;
Object subject;
+ IProgressListener listener;
String alias;
@@ -25,6 +28,7 @@ public class EvaluationContext {
this.parent = parent;
this.snapshot = parent != null ? parent.snapshot : null;
+ this.listener = parent != null ? parent.listener : null;
}
public ISnapshot getSnapshot()
@@ -37,6 +41,16 @@ public class EvaluationContext this.snapshot = snapshot;
}
+ public IProgressListener getProgressListener()
+ {
+ return listener != null ? listener : parent != null ? parent.getProgressListener() : null;
+ }
+
+ public void setProgressListener(IProgressListener listener)
+ {
+ this.listener = listener;
+ }
+
public Object getSubject()
{
return subject;
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/Query.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/Query.java index f4c7f7c9..33e619a5 100644 --- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/Query.java +++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/Query.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG and others.
+ * Copyright (c) 2008, 2019 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -282,8 +282,9 @@ public class Query /*
* Ensure that a non-env var or constant has parentheses
* so it isn't confused with a FROM classname
- * No parentheses
- * select * from objects ${snapshot}
+ * Add parentheses for select wrapped as a call expression,
+ * otherwise will be reparsed just as a subselect
+ * ( select * from objects ${snapshot} )
* Add parentheses for this:
* select * from objects (1)
* Add parentheses for this:
@@ -293,7 +294,8 @@ public class Query */
String cl = String.valueOf(call);
boolean eval = call instanceof PathExpression && !cl.startsWith("$")//$NON-NLS-1$
- || call instanceof CompilerImpl.ConstantExpression;
+ || call instanceof CompilerImpl.ConstantExpression
+ || call instanceof QueryExpression;
if (eval) buf.append("( ");//$NON-NLS-1$
buf.append(call);
if (eval) buf.append(" )");//$NON-NLS-1$
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/QueryExpression.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/QueryExpression.java index 2607f912..2f5c9ecf 100644 --- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/QueryExpression.java +++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/QueryExpression.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@ *
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson (IBM Corporation) - progress listener
*******************************************************************************/
package org.eclipse.mat.parser.internal.oql.compiler;
@@ -38,14 +39,14 @@ public class QueryExpression extends Expression if (!isQueryContextDependent)
{
OQLQueryImpl q = new OQLQueryImpl(ctx, query);
- queryResult = q.execute(ctx.getSnapshot(), null);
+ queryResult = q.execute(ctx.getSnapshot(), ctx.getProgressListener());
}
}
if (isQueryContextDependent)
{
OQLQueryImpl q = new OQLQueryImpl(ctx, query);
- return q.execute(ctx.getSnapshot(), null);
+ return q.execute(ctx.getSnapshot(), ctx.getProgressListener());
}
else
{
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/ContextDerivedData.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/ContextDerivedData.java index 37d15d33..15ab5ec4 100644 --- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/ContextDerivedData.java +++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/ContextDerivedData.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2018 SAP AG and IBM Corporation.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -163,7 +163,7 @@ public abstract class ContextDerivedData return column;
}
- throw new RuntimeException(MessageUtil.format(Messages.ContextDerivedData_Error_OperationNotFound, operation
+ throw new IllegalArgumentException(MessageUtil.format(Messages.ContextDerivedData_Error_OperationNotFound, operation
.getLabel(), this.getClass().getName()));
}
}
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/registry/QueryResult.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/registry/QueryResult.java index 6b184378..927c3cd8 100644 --- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/registry/QueryResult.java +++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/query/registry/QueryResult.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@ *
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson (IBM Corporation) - remove newlines in titles
*******************************************************************************/
package org.eclipse.mat.query.registry;
@@ -85,12 +86,12 @@ public class QueryResult public String getTitle()
{
- return command;
+ return command.replaceAll("[\\r\\n]", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
public String getTitleToolTip()
{
- return command;
+ return command.replaceAll("[\\r\\n]", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
public ContextProvider getDefaultContextProvider()
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/util/SimpleMonitor.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/util/SimpleMonitor.java index 0d03114a..530db1aa 100644 --- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/util/SimpleMonitor.java +++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/util/SimpleMonitor.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@ *
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson (IBM Corporation) - nested SimpleMonitor
*******************************************************************************/
package org.eclipse.mat.util;
@@ -29,6 +30,29 @@ public class SimpleMonitor public IProgressListener nextMonitor()
{
+
+ // Subcall to simple monitor
+ if (delegate instanceof Listener)
+ {
+ /*
+ * Scale by remaining.
+ * E.g. first monitor has [100,50,100]
+ * total of 250
+ * After second monitor has been used (10), 40 remaining
+ * Now second SimpleMonitor [100,100,100,100] created.
+ * All the percentages need to be scaled by 1/10
+ */
+ Listener l = (Listener)delegate;
+ int togo = l.majorUnits - l.unitsReported;
+ int todo = 0;
+ for (int i = currentMonitor; i < percentages.length; ++i)
+ {
+ todo += percentages[i];
+ }
+ if (currentMonitor == 0)
+ delegate.beginTask(task, togo);
+ return new Listener((int)((long)percentages[currentMonitor++] * togo / todo));
+ }
if (currentMonitor == 0)
{
int total = 0;
@@ -64,7 +88,21 @@ public class SimpleMonitor if (totalWork == 0)
return;
- isSmaller = totalWork < majorUnits;
+ if (workDone > 0)
+ {
+ // Already had a beginTask, so use up the remaining
+ if (unitsReported < majorUnits)
+ {
+ majorUnits -= unitsReported;
+ }
+ else
+ {
+ majorUnits = 0;
+ }
+ workDone = 0;
+ }
+
+ isSmaller = totalWork < majorUnits || majorUnits == 0;
workPerUnit = isSmaller ? majorUnits / totalWork : totalWork / majorUnits;
unitsReported = 0;
}
@@ -92,7 +130,7 @@ public class SimpleMonitor public void totalWorkDone(long work)
{
- if (workDone == work)
+ if (workDone >= work)
return;
if (workPerUnit == 0)
@@ -100,6 +138,8 @@ public class SimpleMonitor workDone = work;
int unitsWorked = isSmaller ? (int) (work * workPerUnit) : (int) (work / workPerUnit);
+ // Avoid exceeding work
+ unitsWorked = Math.min(unitsWorked, majorUnits);
int unitsToReport = unitsWorked - unitsReported;
if (unitsToReport > 0)
diff --git a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java index 655ccc89..35e6108c 100644 --- a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java +++ b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2018 SAP AG and IBM Corporation.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -868,6 +868,17 @@ public class OQLTest assertEquals("select s from 1,2,3 s UNION (select s from 17,23 t)", sb.toString());
}
+ @Test
+ public void testOQLunion6() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("select s from 1 s");
+ OQL.union(sb, "select s from 2 s");
+ OQL.union(sb, "select t from 17 t");
+ OQL.union(sb, "select t from 23 t");
+ OQL.union(sb, "select s from 3 s");
+ assertEquals("select s from 1,2,3 s UNION (select t from 17,23 t)", sb.toString());
+ }
+
/**
* Complex test to check that the second FROM clause is reevaluated.
* @throws SnapshotException
@@ -891,6 +902,60 @@ public class OQLTest }
/**
+ * Complex test to check that the second and third FROM clause
+ * is not reevaluated each time - otherwise this will take a long time.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testComplex3() throws SnapshotException {
+ int res[] = (int[])execute("SELECT OBJECTS r from OBJECTS ${snapshot}.@GCRoots r "
+ + "WHERE (SELECT s FROM INSTANCEOF java.lang.Object s "
+ + "WHERE (SELECT t FROM INSTANCEOF java.lang.String t) != null) != null");
+ assertEquals(354, res.length);
+ }
+
+ @Test
+ public void testComplex4() throws SnapshotException {
+ IResultTable irt = (IResultTable)execute("SELECT s AS HashMap, eval((SELECT t, t.getKey(), t.getValue() "
+ + "FROM OBJECTS ( s[0:-1] ) t "
+ + "WHERE (toString(t.getKey()) = \"META-INF\")))[0][2] AS \"Value for META-INF\" "
+ + "FROM java.util.HashMap s "
+ + "WHERE "
+ + "((SELECT t FROM OBJECTS ( s[0:-1] ) t "
+ + "WHERE (toString(t.getKey()) = \"META-INF\")) != null)");
+ assertEquals(3, irt.getRowCount());
+ // 0 is the whole row, 1 is column 0, 2 is column 1
+ assertEquals("Value for META-INF", irt.getResultMetaData().getContextProviders().get(2).getLabel());
+ int id = irt.getResultMetaData().getContextProviders().get(1).getContext(irt.getRow(0)).getObjectId();
+ assertTrue(id >= 0);
+ }
+
+ @Test
+ public void testComplex5() throws SnapshotException {
+ IResultTable irt = (IResultTable)execute("SELECT v[0], v[1][0].getKey() "
+ + "FROM OBJECTS ( "
+ + "SELECT t, t[0:-1] "
+ + "FROM java.util.HashSet t "
+ + "UNION "
+ + "( SELECT s, s[0:-1] "
+ + "FROM java.util.Hashtable s ) ) v ");
+ assertEquals(11, irt.getRowCount());
+ }
+
+ @Test
+ public void testComplex6() throws SnapshotException {
+ IResultTable irt = (IResultTable)execute("SELECT toString(v[0].getKey()) AS Key "
+ + "FROM OBJECTS "
+ + "( SELECT * "
+ + "FROM java.util.HashSet t "
+ + "UNION "
+ + "( SELECT * "
+ + "FROM java.util.Hashtable s ) ) v ");
+ assertEquals(11, irt.getRowCount());
+ assertEquals("META-INF", irt.getColumnValue(irt.getRow(1), 0));
+ }
+
+ /**
* Test that null objects from a from clause don't cause problems
*/
@Test
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/panes/QueryResultPane.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/panes/QueryResultPane.java index 37fb8edb..e37289e5 100644 --- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/panes/QueryResultPane.java +++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/panes/QueryResultPane.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@ *
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson (IBM Corporation) - tooltip
*******************************************************************************/
package org.eclipse.mat.ui.internal.panes;
@@ -114,6 +115,12 @@ public class QueryResultPane extends AbstractEditorPane implements ISelectionPro }
@Override
+ public String getTitleToolTip()
+ {
+ return viewer != null ? viewer.getQueryResult().getTitleToolTip() : null;
+ }
+
+ @Override
public void setFocus()
{
if (viewer != null)
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/snapshot/panes/OQLPane.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/snapshot/panes/OQLPane.java index 372ebdda..09c53707 100644 --- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/snapshot/panes/OQLPane.java +++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/snapshot/panes/OQLPane.java @@ -1,5 +1,5 @@ /*******************************************************************************
- * Copyright (c) 2008, 2014 SAP AG., IBM Corporation and others
+ * Copyright (c) 2008, 2019 SAP AG., IBM Corporation and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -451,7 +451,7 @@ public class OQLPane extends CompositeHeapEditorPane public OQLJob(AbstractEditorPane pane, String queryString, PaneState state)
{
- super(queryString, pane);
+ super(queryString.trim(), pane);
this.queryString = queryString;
this.state = state;
this.setUser(true);
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java index e7e9e89b..f3c2f23f 100644 --- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java +++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/util/QueryContextMenu.java @@ -131,9 +131,6 @@ public class QueryContextMenu }
}
- if (menuContext.isEmpty())
- continue;
-
PopupMenu menu = manager;
String menuLabel = p.getLabel();
@@ -157,11 +154,13 @@ public class QueryContextMenu label = getLabel(selection);
}
- queryMenu(menu, menuContext, label);
+ if (!menuContext.isEmpty())
+ queryMenu(menu, menuContext, label);
systemMenu(menu, control);
- customMenu(menu, menuContext, p, label);
+ if (!menuContext.isEmpty())
+ customMenu(menu, menuContext, p, label);
}
}
|
