Fix database debugging tools
This commit is contained in:
@@ -3,9 +3,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.FaultHandling;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
@@ -29,11 +31,7 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
lock (Commands)
|
||||
{
|
||||
var tuple = Commands.FirstOrDefault(x =>
|
||||
{
|
||||
IDbCommand c;
|
||||
return x.Item2.TryGetTarget(out c) && c == command;
|
||||
});
|
||||
var tuple = Commands.FirstOrDefault(x => x.Item2.TryGetTarget(out var c) && c == command);
|
||||
return tuple == null ? "?" : tuple.Item1;
|
||||
}
|
||||
}
|
||||
@@ -42,28 +40,30 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
con = con.UnwrapUmbraco();
|
||||
|
||||
var ceCon = con as System.Data.SqlServerCe.SqlCeConnection;
|
||||
if (ceCon != null) return null; // "NotSupported: SqlCE";
|
||||
if (con is SqlCeConnection) return null; // "NotSupported: SqlCE";
|
||||
|
||||
var dbCon = con as DbConnection;
|
||||
return dbCon == null
|
||||
? "NotSupported: " + con.GetType()
|
||||
: GetReferencedObjects(dbCon);
|
||||
return con is DbConnection dbCon
|
||||
? GetReferencedObjects(dbCon)
|
||||
: "NotSupported: " + con.GetType();
|
||||
}
|
||||
|
||||
public static string GetReferencedObjects(DbConnection con)
|
||||
{
|
||||
var t = con.GetType();
|
||||
if (con.UnwrapUmbraco() is DbConnection ucon && !(ucon is SqlCeConnection))
|
||||
con = ucon;
|
||||
else
|
||||
return "NotSupported: " + con.GetType();
|
||||
|
||||
var t = con.GetType();
|
||||
var field = t.GetField("_innerConnection", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (field == null) throw new Exception("panic: _innerConnection (" + t + ").");
|
||||
var innerConnection = field.GetValue(con);
|
||||
|
||||
var tin = innerConnection.GetType();
|
||||
|
||||
var tin = innerConnection.GetType();
|
||||
var fi = con is System.Data.SqlClient.SqlConnection
|
||||
? tin.BaseType.BaseType.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
: tin.BaseType.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
? tin.BaseType?.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
: tin.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (fi == null)
|
||||
//return "";
|
||||
throw new Exception("panic: referenceCollection.");
|
||||
@@ -73,7 +73,7 @@ namespace Umbraco.Core.Persistence
|
||||
//return "";
|
||||
throw new Exception("panic: innerCollection.");
|
||||
|
||||
field = rc.GetType().BaseType.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
field = rc.GetType().BaseType?.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (field == null) throw new Exception("panic: items.");
|
||||
var items = field.GetValue(rc);
|
||||
var prop = items.GetType().GetProperty("Length", BindingFlags.Instance | BindingFlags.Public);
|
||||
@@ -116,21 +116,26 @@ namespace Umbraco.Core.Persistence
|
||||
i, inUse, objTarget.GetType(), objTarget.GetHashCode());
|
||||
|
||||
DbCommand cmd = null;
|
||||
if (objTarget is DbDataReader)
|
||||
switch (objTarget)
|
||||
{
|
||||
//var rdr = objTarget as DbDataReader;
|
||||
try
|
||||
{
|
||||
cmd = objTarget.GetType().GetProperty("Command", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(objTarget, null) as DbCommand;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result.AppendFormat("\t\tObjTarget: DbDataReader, Exception: {0}" + Environment.NewLine, e);
|
||||
}
|
||||
}
|
||||
else if (objTarget is DbCommand)
|
||||
{
|
||||
cmd = objTarget as DbCommand;
|
||||
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;
|
||||
}
|
||||
if (cmd == null)
|
||||
{
|
||||
@@ -152,7 +157,9 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
if (pi.PropertyType != typeof (DbConnection) || pi.Name != "Connection") continue;
|
||||
|
||||
var con1 = pi.GetValue(cmd, null) as DbConnection;
|
||||
var con0 = pi.GetValue(cmd, null);
|
||||
if (!(con0 is DbConnection con1))
|
||||
throw new Exception($"panic: expected DbConnection, got {con0?.GetType().FullName ?? "null"}.");
|
||||
result.AppendFormat("\t\t\tConnection type=\"{0}\" state=\"{1}\" hashCode=\"{2}\"" + Environment.NewLine,
|
||||
con1.GetType(), con1.State, con1.GetHashCode());
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Data.SqlClient;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.Linq;
|
||||
using MySql.Data.MySqlClient;
|
||||
using StackExchange.Profiling.Data;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.FaultHandling;
|
||||
@@ -78,18 +79,13 @@ namespace Umbraco.Core.Persistence
|
||||
/// OnConnectionOpened); this unwraps and returns the original database connection.</remarks>
|
||||
internal static IDbConnection UnwrapUmbraco(this IDbConnection connection)
|
||||
{
|
||||
IDbConnection unwrapped;
|
||||
|
||||
var c = connection;
|
||||
var unwrapped = connection;
|
||||
IDbConnection c;
|
||||
do
|
||||
{
|
||||
unwrapped = c;
|
||||
|
||||
var profiled = unwrapped as StackExchange.Profiling.Data.ProfiledDbConnection;
|
||||
if (profiled != null) unwrapped = profiled.InnerConnection;
|
||||
|
||||
var retrying = unwrapped as RetryDbConnection;
|
||||
if (retrying != null) unwrapped = retrying.Inner;
|
||||
c = unwrapped;
|
||||
if (unwrapped is ProfiledDbConnection profiled) unwrapped = profiled.InnerConnection;
|
||||
if (unwrapped is RetryDbConnection retrying) unwrapped = retrying.Inner;
|
||||
|
||||
} while (c != unwrapped);
|
||||
|
||||
@@ -100,22 +96,23 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
try
|
||||
{
|
||||
if (connection is SqlConnection)
|
||||
switch (connection)
|
||||
{
|
||||
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
|
||||
return $"DataSource: {builder.DataSource}, InitialCatalog: {builder.InitialCatalog}";
|
||||
}
|
||||
|
||||
if (connection is SqlCeConnection)
|
||||
{
|
||||
var builder = new SqlCeConnectionStringBuilder(connection.ConnectionString);
|
||||
return $"DataSource: {builder.DataSource}";
|
||||
}
|
||||
|
||||
if (connection is MySqlConnection)
|
||||
{
|
||||
var builder = new MySqlConnectionStringBuilder(connection.ConnectionString);
|
||||
return $"Server: {builder.Server}, Database: {builder.Database}";
|
||||
case SqlConnection _:
|
||||
{
|
||||
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
|
||||
return $"DataSource: {builder.DataSource}, InitialCatalog: {builder.InitialCatalog}";
|
||||
}
|
||||
case SqlCeConnection _:
|
||||
{
|
||||
var builder = new SqlCeConnectionStringBuilder(connection.ConnectionString);
|
||||
return $"DataSource: {builder.DataSource}";
|
||||
}
|
||||
case MySqlConnection _:
|
||||
{
|
||||
var builder = new MySqlConnectionStringBuilder(connection.ConnectionString);
|
||||
return $"Server: {builder.Server}, Database: {builder.Database}";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -177,8 +177,7 @@ namespace Umbraco.Core.Persistence.FaultHandling
|
||||
set
|
||||
{
|
||||
if (value == null) throw new ArgumentNullException(nameof(value));
|
||||
var connection = value as RetryDbConnection;
|
||||
if (connection == null) throw new ArgumentException("Value is not a FaultHandlingDbConnection instance.");
|
||||
if (!(value is RetryDbConnection connection)) throw new ArgumentException("Value is not a FaultHandlingDbConnection instance.");
|
||||
if (_connection != null && _connection != connection) throw new Exception("Value is another FaultHandlingDbConnection instance.");
|
||||
_connection = connection;
|
||||
_inner.Connection = connection.Inner;
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
#if DEBUG_DATABASES
|
||||
// determines the database connection SPID for debugging
|
||||
if (DatabaseType == DBType.MySql)
|
||||
if (DatabaseType.IsMySql())
|
||||
{
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
@@ -157,7 +157,7 @@ namespace Umbraco.Core.Persistence
|
||||
_spid = Convert.ToInt32(command.ExecuteScalar());
|
||||
}
|
||||
}
|
||||
else if (DatabaseType == DBType.SqlServer)
|
||||
else if (DatabaseType.IsSqlServer())
|
||||
{
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
|
||||
#if DEBUG_DATABASES
|
||||
public override void OnConnectionClosing(IDbConnection conn)
|
||||
protected override void OnConnectionClosing(DbConnection conn)
|
||||
{
|
||||
_spid = -1;
|
||||
base.OnConnectionClosing(conn);
|
||||
@@ -212,7 +212,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
#if DEBUG_DATABASES
|
||||
// detects whether the command is already in use (eg still has an open reader...)
|
||||
DatabaseDebugHelper.SetCommand(cmd, InstanceId + " [T" + Thread.CurrentThread.ManagedThreadId + "]");
|
||||
DatabaseDebugHelper.SetCommand(cmd, InstanceId + " [T" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]");
|
||||
var refsobj = DatabaseDebugHelper.GetReferencedObjects(cmd.Connection);
|
||||
if (refsobj != null) _logger.Debug<UmbracoDatabase>("Oops!" + Environment.NewLine + refsobj);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user