Skip to content

Commit

Permalink
Improved error reporting with TDS endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Apr 9, 2024
1 parent 4e6e7aa commit f6d883a
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 17 deletions.
2 changes: 1 addition & 1 deletion MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
}
}

return new SqlDataReaderWrapper(_connection, this, con, cmd, _connection.Database, node, _cts.Token);
return new SqlDataReaderWrapper(con, cmd, behavior, node, _cts.Token);
}

var options = new CancellationTokenOptionsWrapper(_connection.Options, _cts);
Expand Down
9 changes: 4 additions & 5 deletions MarkMpn.Sql4Cds.Engine/Ado/SqlDataReaderWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,18 @@ namespace MarkMpn.Sql4Cds.Engine
{
class SqlDataReaderWrapper : DbDataReader
{
private Sql4CdsConnection _connection;
private SqlConnection _sqlConnection;
private SqlCommand _sqlCommand;
private SqlDataReader _sqlDataReader;
private readonly SqlNode _node;

public SqlDataReaderWrapper(Sql4CdsConnection connection, Sql4CdsCommand command, SqlConnection sqlConnection, SqlCommand sqlCommand, string dataSource, SqlNode node, CancellationToken cancellationToken)
public SqlDataReaderWrapper(SqlConnection sqlConnection, SqlCommand sqlCommand, CommandBehavior behavior, SqlNode node, CancellationToken cancellationToken)
{
_connection = connection;
_sqlConnection = sqlConnection;
_sqlCommand = sqlCommand;
cancellationToken.Register(() => _sqlCommand.Cancel());

HandleException(() => _sqlDataReader = sqlCommand.ExecuteReader());
HandleException(() => _sqlDataReader = sqlCommand.ExecuteReader(behavior));
_node = node;

foreach (SqlParameter parameter in sqlCommand.Parameters)
Expand Down Expand Up @@ -196,7 +194,8 @@ private T HandleException<T>(Func<T> action)
}
catch (SqlException ex)
{
throw new Sql4CdsException(new Sql4CdsError(ex.Class, ex.LineNumber, ex.Number, null, ex.Server, ex.State, ex.Message), ex);
var error = new Sql4CdsError(ex.Class, ex.LineNumber + _node.LineNumber - 1, ex.Number, String.IsNullOrEmpty(ex.Procedure) ? null : ex.Procedure, ex.Server, ex.State, ex.Message);
throw new Sql4CdsException(error, new QueryExecutionException(error, ex) { Node = _node });
}
}
}
Expand Down
6 changes: 2 additions & 4 deletions MarkMpn.Sql4Cds.Engine/ExecutionPlan/SqlNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,11 @@ public DbDataReader Execute(NodeExecutionContext context, CommandBehavior behavi
};
}

var reader = cmd.ExecuteReader(behavior | CommandBehavior.CloseConnection);

return reader;
return new SqlDataReaderWrapper(con, cmd, behavior | CommandBehavior.CloseConnection, this, context.Options.CancellationToken);
}
catch (SqlException ex)
{
throw new QueryExecutionException(new Sql4CdsError(ex.Class, ex.Number, ex.Message), ex)
throw new QueryExecutionException(new Sql4CdsError(ex.Class, ex.LineNumber + LineNumber - 1, ex.Number, String.IsNullOrEmpty(ex.Procedure) ? null : ex.Procedure, ex.Server, ex.State, ex.Message), ex)
{
Node = this
};
Expand Down
30 changes: 24 additions & 6 deletions MarkMpn.Sql4Cds.SSMS/DmlExecute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using MarkMpn.Sql4Cds.Engine.ExecutionPlan;
using Microsoft.SqlServer.Management.QueryExecution;
using Microsoft.SqlServer.Management.UI.VSIntegration;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;

Expand Down Expand Up @@ -127,14 +128,14 @@ private void OnExecuteQuery(string Guid, int ID, object CustomIn, object CustomO

con.InfoMessage += (s, msg) =>
{
sqlScriptEditorControl.Results.AddStringToMessages(msg.Message + "\r\n\r\n");
sqlScriptEditorControl.Results.AddStringToMessages(msg.Message.Message + "\r\n\r\n");
resultFlag |= 1; // Success
};

cmd.StatementCompleted += (s, stmt) =>
{
if (tabPage != null)
ShowPlan(sqlScriptEditorControl, tabPage, stmt.Statement, dataSource, true);
ShowPlan(sqlScriptEditorControl, tabPage, stmt.Statement, dataSource, true, null);

if (stmt.Message != null)
sqlScriptEditorControl.Results.AddStringToMessages(stmt.Message + "\r\n\r\n");
Expand Down Expand Up @@ -170,6 +171,10 @@ private void OnExecuteQuery(string Guid, int ID, object CustomIn, object CustomO
catch (Exception ex)
{
AddException(sqlScriptEditorControl, textSpan, ex);

if (ex is Sql4CdsException sqlEx && sqlEx.InnerException is QueryExecutionException qee && tabPage != null)
ShowPlan(sqlScriptEditorControl, tabPage, GetRootNode(qee.Node), dataSource, true, qee);

resultFlag |= 2; // Failure
}

Expand All @@ -190,6 +195,19 @@ private void OnExecuteQuery(string Guid, int ID, object CustomIn, object CustomO
}
}

private IRootExecutionPlanNode GetRootNode(IExecutionPlanNode node)
{
while (node != null)
{
if (node is IRootExecutionPlanNode root)
return root;

node = node.Parent;
}

return null;
}

private void OnCancelQuery(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
{
ThreadHelper.ThrowIfNotOnUIThread();
Expand Down Expand Up @@ -255,7 +273,7 @@ private void OnShowEstimatedPlan(string Guid, int ID, object CustomIn, object Cu
sqlScriptEditorControl.Results.ResultsTabCtrl.SelectedTab = tabPage;

foreach (var query in plans)
ShowPlan(sqlScriptEditorControl, tabPage, query, dataSource, false);
ShowPlan(sqlScriptEditorControl, tabPage, query, dataSource, false, null);

var resultFlag = 1; // Success

Expand Down Expand Up @@ -289,15 +307,15 @@ private TabPage AddShowPlanTab(SqlScriptEditorControlWrapper sqlScriptEditorCont
return tabPage;
}

private void ShowPlan(SqlScriptEditorControlWrapper sqlScriptEditorControl, TabPage tabPage, IRootExecutionPlanNode query, DataSource dataSource, bool executed)
private void ShowPlan(SqlScriptEditorControlWrapper sqlScriptEditorControl, TabPage tabPage, IRootExecutionPlanNode query, DataSource dataSource, bool executed, QueryExecutionException ex)
{
if (tabPage.InvokeRequired)
{
tabPage.Invoke((Action) (() =>
{
ThreadHelper.ThrowIfNotOnUIThread();

ShowPlan(sqlScriptEditorControl, tabPage, query, dataSource, executed);
ShowPlan(sqlScriptEditorControl, tabPage, query, dataSource, executed, ex);
}));
return;
}
Expand All @@ -316,7 +334,7 @@ private void ShowPlan(SqlScriptEditorControlWrapper sqlScriptEditorControl, TabP
AutoEllipsis = true,
UseMnemonic = false
};
var planView = new ExecutionPlanView { Dock = DockStyle.Fill, Executed = executed, DataSources = new Dictionary<string, DataSource> { [dataSource.Name] = dataSource } };
var planView = new ExecutionPlanView { Dock = DockStyle.Fill, Executed = executed, DataSources = new Dictionary<string, DataSource> { [dataSource.Name] = dataSource }, Exception = ex };
planView.Plan = query;

planView.NodeSelected += (s, e) =>
Expand Down
11 changes: 10 additions & 1 deletion MarkMpn.Sql4Cds.SSMS/Reflection/ReflectionObjectBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,16 @@ protected object InvokeMethod(object target, string methodName, params object[]
.ToArray();

if (method.Length == 1)
return method[0].Invoke(target, args);
{
try
{
return method[0].Invoke(target, args);
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
}

if (method.Length > 1)
{
Expand Down

0 comments on commit f6d883a

Please sign in to comment.