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

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

@ -29,7 +29,7 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq @@ -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_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 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 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 @@ -52,6 +52,10 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
- if c is the lambda parameter, then these expressions are valid:
c.NameMapping.ID
c.NameMapping.Name
c.CallCount
c.CpuCyclesSpent
c.IsThread
c.IsUserCode
Additionally, field references on a lambda parameter of type SingleCall are valid inside
filters that operate directly on "AllCalls" (e.g. AllCalls.Filter()).
@ -81,6 +85,14 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq @@ -81,6 +85,14 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
input.Select(x => x) -> input
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.
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:
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 @@ -237,6 +249,13 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
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)
{
if (node.Method == KnownMembers.QueryableOfCallTreeNode_Select && node.Arguments[1].NodeType == ExpressionType.Quote) {
@ -277,9 +296,10 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq @@ -277,9 +296,10 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
return new Limit(target, 0, (int)ce.Value);
}
}
} else if (node.Method.IsGenericMethod && node.Method.GetGenericMethodDefinition() == KnownMembers.Queryable_OrderBy &&
node.Method.GetGenericArguments()[0] == typeof(CallTreeNode) &&
} else if ((IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderBy) ||
IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc)) &&
node.Arguments[1].NodeType == ExpressionType.Quote) {
UnaryExpression quote = (UnaryExpression)node.Arguments[1];
if (quote.Operand.NodeType == ExpressionType.Lambda) {
LambdaExpression lambda = (LambdaExpression)quote.Operand;
@ -287,20 +307,12 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq @@ -287,20 +307,12 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
QueryNode target = Visit(node.Arguments[0]) as QueryNode;
if (target != null) {
SafeExpressionImporter importer = new SafeExpressionImporter(lambda.Parameters[0]);
var imported = importer.Import(lambda.Body);
Expression imported = importer.Import(lambda.Body);
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);
}
@ -387,6 +399,8 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq @@ -387,6 +399,8 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
} else if (IsNameMappingOnParameter(me.Expression)) {
if (me.Member == KnownMembers.NameMapping_ID)
return me;
if (me.Member == KnownMembers.NameMapping_Name)
return me;
}
}
return null;
@ -394,23 +408,8 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq @@ -394,23 +408,8 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
{
MethodCallExpression mc = (MethodCallExpression)expr;
// TODO: accept StartsWith on any object (not only NameMapping.Name)
// accept NameMapping.Name also in other contexts
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;
}
}
}
if (mc.Method == KnownMembers.String_StartsWith)
return CreateCall(mc, (pattern, wildcard) => pattern + wildcard);
return null;
}
@ -442,6 +441,22 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq @@ -442,6 +441,22 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq
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)
{

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

@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
<y:QueryView x:Name="treeView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ShowQueryItems="False" CurrentQuery="from t in Threads select t" IsQueryModifiable="False" />
</TabItem>
<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 x:Name="dummyTab" />
</TabControl>

Loading…
Cancel
Save