Files
Umbraco-CMS/src/Umbraco.Core/Persistence/DatabaseDebugHelper.cs

180 lines
7.8 KiB
C#
Raw Normal View History

2016-12-02 17:04:51 +01:00
#if DEBUG_DATABASES
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
2018-05-30 16:40:25 +02:00
using System.Data.SqlServerCe;
2016-12-02 17:04:51 +01:00
using System.Linq;
using System.Reflection;
using System.Text;
2018-05-30 16:40:25 +02:00
using Umbraco.Core.Persistence.FaultHandling;
2016-12-02 17:04:51 +01:00
namespace Umbraco.Core.Persistence
{
internal static class DatabaseDebugHelper
{
private const int CommandsSize = 100;
private static readonly Queue<Tuple<string, WeakReference<IDbCommand>>> Commands = new Queue<Tuple<string, WeakReference<IDbCommand>>>();
public static void SetCommand(IDbCommand command, string context)
{
2016-12-14 14:06:30 +01:00
command = command.UnwrapUmbraco();
2016-12-02 17:04:51 +01:00
lock (Commands)
{
Commands.Enqueue(Tuple.Create(context, new WeakReference<IDbCommand>(command)));
while (Commands.Count > CommandsSize) Commands.Dequeue();
}
}
public static string GetCommandContext(IDbCommand command)
{
lock (Commands)
{
2018-05-30 16:40:25 +02:00
var tuple = Commands.FirstOrDefault(x => x.Item2.TryGetTarget(out var c) && c == command);
2016-12-02 17:04:51 +01:00
return tuple == null ? "?" : tuple.Item1;
}
}
public static string GetReferencedObjects(IDbConnection con)
{
2016-12-14 14:06:30 +01:00
con = con.UnwrapUmbraco();
2018-05-30 16:40:25 +02:00
if (con is SqlCeConnection) return null; // "NotSupported: SqlCE";
2016-12-14 14:06:30 +01:00
2018-05-30 16:40:25 +02:00
return con is DbConnection dbCon
? GetReferencedObjects(dbCon)
: "NotSupported: " + con.GetType();
2016-12-02 17:04:51 +01:00
}
public static string GetReferencedObjects(DbConnection con)
{
2018-05-30 16:40:25 +02:00
if (con.UnwrapUmbraco() is DbConnection ucon && !(ucon is SqlCeConnection))
con = ucon;
else
return "NotSupported: " + con.GetType();
2016-12-02 17:04:51 +01:00
2018-05-30 16:40:25 +02:00
var t = con.GetType();
2016-12-02 17:04:51 +01:00
var field = t.GetField("_innerConnection", BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null) throw new Exception("panic: _innerConnection (" + t + ").");
var innerConnection = field.GetValue(con);
2018-05-30 16:40:25 +02:00
var tin = innerConnection.GetType();
2016-12-02 17:04:51 +01:00
var fi = con is System.Data.SqlClient.SqlConnection
2018-05-30 16:40:25 +02:00
? tin.BaseType?.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic)
: tin.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic);
2016-12-02 17:04:51 +01:00
if (fi == null)
//return "";
throw new Exception("panic: referenceCollection.");
var rc = fi.GetValue(innerConnection);
if (rc == null)
//return "";
throw new Exception("panic: innerCollection.");
2018-05-30 16:40:25 +02:00
field = rc.GetType().BaseType?.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic);
2016-12-02 17:04:51 +01:00
if (field == null) throw new Exception("panic: items.");
var items = field.GetValue(rc);
var prop = items.GetType().GetProperty("Length", BindingFlags.Instance | BindingFlags.Public);
if (prop == null) throw new Exception("panic: Length.");
var count = Convert.ToInt32(prop.GetValue(items, null));
var miGetValue = items.GetType().GetMethod("GetValue", new[] { typeof(int) });
if (miGetValue == null) throw new Exception("panic: GetValue.");
if (count == 0) return null;
StringBuilder result = null;
var hasb = false;
for (var i = 0; i < count; i++)
{
var referencedObj = miGetValue.Invoke(items, new object[] { i });
var hasTargetProp = referencedObj.GetType().GetProperty("HasTarget");
if (hasTargetProp == null) throw new Exception("panic: HasTarget");
var hasTarget = Convert.ToBoolean(hasTargetProp.GetValue(referencedObj, null));
if (hasTarget == false) continue;
if (hasb == false)
{
result = new StringBuilder();
result.AppendLine("ReferencedItems");
hasb = true;
}
//var inUseProp = referencedObj.GetType().GetProperty("InUse");
//if (inUseProp == null) throw new Exception("panic: InUse.");
//var inUse = Convert.ToBoolean(inUseProp.GetValue(referencedObj, null));
var inUse = "?";
var targetProp = referencedObj.GetType().GetProperty("Target");
if (targetProp == null) throw new Exception("panic: Target.");
var objTarget = targetProp.GetValue(referencedObj, null);
result.AppendFormat("\tDiff.Item id=\"{0}\" inUse=\"{1}\" type=\"{2}\" hashCode=\"{3}\"" + Environment.NewLine,
i, inUse, objTarget.GetType(), objTarget.GetHashCode());
DbCommand cmd = null;
2018-05-30 16:40:25 +02:00
switch (objTarget)
2016-12-02 17:04:51 +01:00
{
2018-05-30 16:40:25 +02:00
case DbDataReader _:
//var rdr = objTarget as DbDataReader;
try
{
var commandProp = objTarget.GetType().GetProperty("Command", BindingFlags.Instance | BindingFlags.NonPublic);
if (commandProp == null)
throw new Exception($"panic: failed to get Command property of {objTarget.GetType().FullName}.");
cmd = commandProp.GetValue(objTarget, null) as DbCommand;
}
catch (Exception e)
{
result.AppendFormat("\t\tObjTarget: DbDataReader, Exception: {0}" + Environment.NewLine, e);
}
break;
case DbCommand command:
cmd = command;
break;
2016-12-02 17:04:51 +01:00
}
if (cmd == null)
{
result.AppendFormat("\t\tObjTarget: {0}" + Environment.NewLine, objTarget.GetType());
continue;
}
result.AppendFormat("\t\tCommand type=\"{0}\" hashCode=\"{1}\"" + Environment.NewLine,
cmd.GetType(), cmd.GetHashCode());
var context = GetCommandContext(cmd);
result.AppendFormat("\t\t\tContext: {0}" + Environment.NewLine, context);
var properties = cmd.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var pi in properties)
{
if (pi.PropertyType.IsPrimitive || pi.PropertyType == typeof(string))
result.AppendFormat("\t\t\t{0}: {1}" + Environment.NewLine, pi.Name, pi.GetValue(cmd, null));
if (pi.PropertyType != typeof (DbConnection) || pi.Name != "Connection") continue;
2018-05-30 16:40:25 +02:00
var con0 = pi.GetValue(cmd, null);
if (!(con0 is DbConnection con1))
throw new Exception($"panic: expected DbConnection, got {con0?.GetType().FullName ?? "null"}.");
2016-12-02 17:04:51 +01:00
result.AppendFormat("\t\t\tConnection type=\"{0}\" state=\"{1}\" hashCode=\"{2}\"" + Environment.NewLine,
con1.GetType(), con1.State, con1.GetHashCode());
var propertiesCon = con1.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var picon in propertiesCon)
{
if (picon.PropertyType.IsPrimitive || picon.PropertyType == typeof(string))
result.AppendFormat("\t\t\t\t{0}: {1}" + Environment.NewLine, picon.Name, picon.GetValue(con1, null));
}
}
}
2016-12-14 14:06:30 +01:00
return result?.ToString();
2016-12-02 17:04:51 +01:00
}
}
}
#endif