Browse Source

- implemented ORDER BY DESC

- updated documentation
- implemented StartsWith for all valid strings

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5033 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Siegfried Pammer 17 years ago
parent
commit
1027bf45dc
  1. 2
      src/AddIns/Misc/Profiler/Controller/Data/Linq/ExpressionSqlWriter.cs
  2. 2
      src/AddIns/Misc/Profiler/Controller/Data/Linq/KnownMembers.cs
  3. 73
      src/AddIns/Misc/Profiler/Controller/Data/Linq/SQLiteQueryProvider.cs
  4. 2
      src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerView.xaml

2
src/AddIns/Misc/Profiler/Controller/Data/Linq/ExpressionSqlWriter.cs

@ -116,7 +116,7 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
} else if (me.Member == SingleCall.ParentIDField) { } else if (me.Member == SingleCall.ParentIDField) {
w.Write("parentid"); w.Write("parentid");
} else if (me.Member == KnownMembers.CallTreeNode_CallCount) { } else if (me.Member == KnownMembers.CallTreeNode_CallCount) {
w.Write(nameSet.CallCount); w.Write("(" + nameSet.CallCount + " + " + nameSet.ActiveCallCount + ")");
} else if (me.Member == KnownMembers.CallTreeNode_CpuCyclesSpent) { } else if (me.Member == KnownMembers.CallTreeNode_CpuCyclesSpent) {
w.Write(nameSet.CpuCyclesSpent); w.Write(nameSet.CpuCyclesSpent);
} else { } else {

2
src/AddIns/Misc/Profiler/Controller/Data/Linq/KnownMembers.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
public static readonly MethodInfo QueryableOfCallTreeNode_Where = MethodOf((IQueryable<CallTreeNode> q) => q.Where(x => true)); public static readonly MethodInfo QueryableOfCallTreeNode_Where = MethodOf((IQueryable<CallTreeNode> q) => q.Where(x => true));
public static readonly MethodInfo QueryableOfCallTreeNode_Take = MethodOf((IQueryable<CallTreeNode> q) => q.Take(1)); public static readonly MethodInfo QueryableOfCallTreeNode_Take = MethodOf((IQueryable<CallTreeNode> q) => q.Take(1));
public static readonly MethodInfo Queryable_OrderBy = MethodOf((IQueryable<CallTreeNode> q) => q.OrderBy(x => x)).GetGenericMethodDefinition(); public static readonly MethodInfo Queryable_OrderBy = MethodOf((IQueryable<CallTreeNode> q) => q.OrderBy(x => x)).GetGenericMethodDefinition();
public static readonly MethodInfo QueryableOfCallTreeNode_OrderByDesc = MethodOf((IOrderedQueryable<CallTreeNode> q) => q.OrderByDescending(x => default(int))); public static readonly MethodInfo Queryable_OrderByDesc = MethodOf((IQueryable<CallTreeNode> q) => q.OrderByDescending(x => x)).GetGenericMethodDefinition();
public static readonly MethodInfo String_StartsWith = MethodOf((string s) => s.StartsWith(s, default(StringComparison))); public static readonly MethodInfo String_StartsWith = MethodOf((string s) => s.StartsWith(s, default(StringComparison)));
public static readonly MethodInfo Queryable_Merge = MethodOf((IQueryable<CallTreeNode> q) => q.Merge()); public static readonly MethodInfo Queryable_Merge = MethodOf((IQueryable<CallTreeNode> q) => q.Merge());

73
src/AddIns/Misc/Profiler/Controller/Data/Linq/SQLiteQueryProvider.cs

@ -52,6 +52,10 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
- if c is the lambda parameter, then these expressions are valid: - if c is the lambda parameter, then these expressions are valid:
c.NameMapping.ID c.NameMapping.ID
c.NameMapping.Name c.NameMapping.Name
c.CallCount
c.CpuCyclesSpent
c.IsThread
c.IsUserCode
Additionally, field references on a lambda parameter of type SingleCall are valid inside Additionally, field references on a lambda parameter of type SingleCall are valid inside
filters that operate directly on "AllCalls" (e.g. AllCalls.Filter()). filters that operate directly on "AllCalls" (e.g. AllCalls.Filter()).
@ -81,6 +85,14 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
input.Select(x => x) -> input input.Select(x => x) -> input
This rule is necessary to remove degenerate selects so that the parts of the query continuing after the select This rule is necessary to remove degenerate selects so that the parts of the query continuing after the select
can also be represented as QueryNodes. can also be represented as QueryNodes.
input.Take(count) -> input.Limit(0, count)
Note: Skip/Take combinations are not combined (Skip is not supported).
input.OrderBy(x => x.SomeField) -> input.Sort({ [x.SomeField, ascending] })
Note: ThenBy is not supported.
input.OrderByDescending(x => x.SomeField) -> input.Sort({ [x.SomeField, descending] })
Translation rules for expression importer: Translation rules for expression importer:
Any valid expressions (as defined in 'valid expressions in QueryAst nodes') are copied over directly. Any valid expressions (as defined in 'valid expressions in QueryAst nodes') are copied over directly.
@ -237,6 +249,13 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
return base.VisitExtension(node); return base.VisitExtension(node);
} }
bool IsGenericMethodInfoOfCallTreeNode(MethodCallExpression node, MethodInfo info)
{
return node.Method.IsGenericMethod &&
node.Method.GetGenericMethodDefinition() == info &&
node.Method.GetGenericArguments()[0] == typeof(CallTreeNode);
}
protected override Expression VisitMethodCall(MethodCallExpression node) protected override Expression VisitMethodCall(MethodCallExpression node)
{ {
if (node.Method == KnownMembers.QueryableOfCallTreeNode_Select && node.Arguments[1].NodeType == ExpressionType.Quote) { if (node.Method == KnownMembers.QueryableOfCallTreeNode_Select && node.Arguments[1].NodeType == ExpressionType.Quote) {
@ -277,9 +296,10 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
return new Limit(target, 0, (int)ce.Value); return new Limit(target, 0, (int)ce.Value);
} }
} }
} else if (node.Method.IsGenericMethod && node.Method.GetGenericMethodDefinition() == KnownMembers.Queryable_OrderBy && } else if ((IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderBy) ||
node.Method.GetGenericArguments()[0] == typeof(CallTreeNode) && IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc)) &&
node.Arguments[1].NodeType == ExpressionType.Quote) { node.Arguments[1].NodeType == ExpressionType.Quote) {
UnaryExpression quote = (UnaryExpression)node.Arguments[1]; UnaryExpression quote = (UnaryExpression)node.Arguments[1];
if (quote.Operand.NodeType == ExpressionType.Lambda) { if (quote.Operand.NodeType == ExpressionType.Lambda) {
LambdaExpression lambda = (LambdaExpression)quote.Operand; LambdaExpression lambda = (LambdaExpression)quote.Operand;
@ -287,20 +307,12 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
QueryNode target = Visit(node.Arguments[0]) as QueryNode; QueryNode target = Visit(node.Arguments[0]) as QueryNode;
if (target != null) { if (target != null) {
SafeExpressionImporter importer = new SafeExpressionImporter(lambda.Parameters[0]); SafeExpressionImporter importer = new SafeExpressionImporter(lambda.Parameters[0]);
var imported = importer.Import(lambda.Body); Expression imported = importer.Import(lambda.Body);
if (imported != null) if (imported != null)
return new Sort(target, Expression.Lambda(imported, lambda.Parameters[0]), false); return new Sort(target, Expression.Lambda(imported, lambda.Parameters[0]), IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc));
} }
} }
} }
} else if (node.Method == KnownMembers.QueryableOfCallTreeNode_OrderByDesc && node.Arguments[1].NodeType == ExpressionType.Quote) {
ConstantExpression ce = (ConstantExpression)node.Arguments[1];
if (ce.Type == typeof(int)) {
QueryNode target = Visit(node.Arguments[0]) as QueryNode;
if (target != null) {
return new Limit(target, 0, (int)ce.Value);
}
}
} }
return base.VisitMethodCall(node); return base.VisitMethodCall(node);
} }
@ -387,6 +399,8 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
} else if (IsNameMappingOnParameter(me.Expression)) { } else if (IsNameMappingOnParameter(me.Expression)) {
if (me.Member == KnownMembers.NameMapping_ID) if (me.Member == KnownMembers.NameMapping_ID)
return me; return me;
if (me.Member == KnownMembers.NameMapping_Name)
return me;
} }
} }
return null; return null;
@ -394,23 +408,8 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
{ {
MethodCallExpression mc = (MethodCallExpression)expr; MethodCallExpression mc = (MethodCallExpression)expr;
// TODO: accept StartsWith on any object (not only NameMapping.Name) if (mc.Method == KnownMembers.String_StartsWith)
// accept NameMapping.Name also in other contexts return CreateCall(mc, (pattern, wildcard) => pattern + wildcard);
if (IsMemberOnNameMappingOnParameter(mc.Object, KnownMembers.NameMapping_Name)) {
if (mc.Arguments[0].NodeType == ExpressionType.Constant && mc.Arguments[1].NodeType == ExpressionType.Constant) {
StringComparison cmp = (StringComparison)GetConstantValue(mc.Arguments[1]);
string pattern = (string)GetConstantValue(mc.Arguments[0]);
if (mc.Method == KnownMembers.String_StartsWith) {
if (cmp == StringComparison.Ordinal && pattern.IndexOfAny(forbiddenGlobChars) == -1)
return Expression.Call(KnownMembers.Glob, mc.Object, Expression.Constant(pattern + "*"));
else if (cmp == StringComparison.OrdinalIgnoreCase)
return Expression.Call(KnownMembers.Like, mc.Object, Expression.Constant(EscapeLikeExpr(pattern, "\\") + "%"));
else
return null;
}
}
}
return null; return null;
} }
@ -442,6 +441,22 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
return null; return null;
} }
} }
Expression CreateCall(MethodCallExpression mc, Func<string, string, string> expressionOf)
{
Expression imported = Import(mc.Object);
if (imported != null && mc.Arguments[0].NodeType == ExpressionType.Constant && mc.Arguments[1].NodeType == ExpressionType.Constant) {
StringComparison cmp = (StringComparison)GetConstantValue(mc.Arguments[1]);
string pattern = (string)GetConstantValue(mc.Arguments[0]);
if (cmp == StringComparison.Ordinal && pattern.IndexOfAny(forbiddenGlobChars) == -1)
return Expression.Call(KnownMembers.Glob, imported, Expression.Constant(expressionOf(pattern, "*")));
else if (cmp == StringComparison.OrdinalIgnoreCase)
return Expression.Call(KnownMembers.Like, imported, Expression.Constant(expressionOf(EscapeLikeExpr(pattern, "\\"), "%")));
}
return null;
}
static string EscapeLikeExpr(string expression, string escape) static string EscapeLikeExpr(string expression, string escape)
{ {

2
src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerView.xaml

@ -41,7 +41,7 @@
<y:QueryView x:Name="treeView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowQueryItems="False" CurrentQuery="from t in Threads select t" IsQueryModifiable="False" /> <y:QueryView x:Name="treeView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowQueryItems="False" CurrentQuery="from t in Threads select t" IsQueryModifiable="False" />
</TabItem> </TabItem>
<TabItem Header="{sd:Localize AddIns.Profiler.ProfilingView.Top20TabText}"> <TabItem Header="{sd:Localize AddIns.Profiler.ProfilingView.Top20TabText}">
<y:QueryView x:Name="top20View" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowQueryItems="False" CurrentQuery="(from f in Functions where f.IsUserCode orderby f.CpuCyclesSpent select f).Take(20)" IsQueryModifiable="False" /> <y:QueryView x:Name="top20View" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowQueryItems="False" CurrentQuery="(from f in Functions where f.IsUserCode orderby f.CpuCyclesSpent descending select f).Take(20)" IsQueryModifiable="False" />
</TabItem> </TabItem>
<TabItem x:Name="dummyTab" /> <TabItem x:Name="dummyTab" />
</TabControl> </TabControl>

Loading…
Cancel
Save