//
//
//
//
// $Revision$
//
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace ICSharpCode.Profiler.Controller.Data.Linq
{
///
/// The SingleCall class is never instanciated; it only used to represent database rows
/// inside expression trees.
///
abstract class SingleCall
{
// Warning CS0649: Field is never assigned to, and will always have its default value 0
#pragma warning disable 649
public int ID;
public int ParentID;
public int DataSetID;
#pragma warning restore 649
public static readonly FieldInfo IDField = typeof(SingleCall).GetField("ID");
public static readonly FieldInfo ParentIDField = typeof(SingleCall).GetField("ParentID");
public static readonly FieldInfo DataSetIdField = typeof(SingleCall).GetField("DataSetID");
}
///
/// Base class for nodes in the Query AST.
///
abstract class QueryNode : Expression
{
public enum SqlStatementKind
{
Select,
SelectWhere,
SelectGroupBy,
SelectGroupByHaving,
SelectOrderBy,
SelectLimit
}
public readonly QueryNode Target;
protected QueryNode(QueryNode target)
{
this.Target = target;
}
protected override ExpressionType NodeTypeImpl()
{
return ExpressionType.Extension;
}
protected override Type TypeImpl()
{
return typeof(IQueryable);
}
protected abstract override Expression VisitChildren(Func visitor);
///
/// SQL construction documentation see SQLiteQueryProvider documentation.
///
public abstract SqlStatementKind BuildSql(StringBuilder b, SqlQueryContext context);
///
/// Wraps the current SQL statement into an inner select, allowing to continue with "WHERE" queries
/// even after ORDER BY or LIMIT.
///
protected static void WrapSqlIntoNestedStatement(StringBuilder b, SqlQueryContext context)
{
CallTreeNodeSqlNameSet oldNames = context.CurrentNameSet;
CallTreeNodeSqlNameSet newNames = new CallTreeNodeSqlNameSet(context);
string query = "SELECT "
+ SqlAs(oldNames.NameID, newNames.NameID) + ", "
+ SqlAs(oldNames.CpuCyclesSpent, newNames.CpuCyclesSpent) + ", "
+ SqlAs(oldNames.CallCount, newNames.CallCount) + ", "
+ SqlAs(oldNames.HasChildren, newNames.HasChildren) + ", "
+ SqlAs(oldNames.ActiveCallCount, newNames.ActiveCallCount);
if (context.HasIDList) {
query += ", " + SqlAs(oldNames.ID, newNames.ID);
}
query += Environment.NewLine + "FROM (" + Environment.NewLine;
b.Insert(0, query);
b.AppendLine(")");
context.SetCurrent(newNames, SqlTableType.None, context.HasIDList);
}
///
/// Helper function that builds the text 'expression AS newName'
///
protected static string SqlAs(string expression, string newName)
{
if (expression == newName)
return newName;
else
return expression + " AS " + newName;
}
public IQueryable Execute(SQLiteQueryProvider provider, QueryExecutionOptions options)
{
StringBuilder b = new StringBuilder();
SqlQueryContext context = new SqlQueryContext(provider);
BuildSql(b, context);
if (options.HasLoggers)
options.WriteLogLine(b.ToString());
Stopwatch w = Stopwatch.StartNew();
IList result = provider.RunSQLNodeList(b.ToString(), context.HasIDList);
w.Stop();
if (options.HasLoggers) {
options.WriteLogLine("Query returned " + result.Count + " rows in " + w.Elapsed);
}
return result.AsQueryable();
}
}
}