Skip to content

Commit

Permalink
Use new ADO components instead of ExecutionPlanBuilder directly
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Feb 2, 2022
1 parent 1265c88 commit 7a58203
Show file tree
Hide file tree
Showing 22 changed files with 199 additions and 99 deletions.
23 changes: 12 additions & 11 deletions MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ bool IQueryExecutionOptions.ConfirmDelete(int count, EntityMetadata meta)

Guid IQueryExecutionOptions.UserId => Guid.NewGuid();

bool IQueryExecutionOptions.QuotedIdentifiers => true;

[TestMethod]
public void SelectArithmetic()
{
Expand Down Expand Up @@ -259,24 +261,23 @@ public void RowCount()
}
}

//[TestMethod]
public void TDS()
[TestMethod]
public void LoadToDataTable()
{
using (var con = new Sql4CdsConnection("AuthType=OAuth;Username=markc@data-8.co.uk;Password=TonarinoTotoro;Url=https://orgc9d0c16b.crm11.dynamics.com;AppId=51f81489-12ee-4a9e-aaae-a2591f45987d;RedirectUri=app://58145B91-0C36-4500-8554-080854F2AC97;LoginPrompt=Auto"))
using (var con = new Sql4CdsConnection(_localDataSource.Values.ToList(), this))
using (var cmd = con.CreateCommand())
{
cmd.CommandText = "SELECT TOP (@top) name FROM account";
cmd.Parameters.Add(new Sql4CdsParameter("@top", 10));
cmd.CommandText = "SELECT 1, 'hello world'";

using (var reader = cmd.ExecuteReader())
{
for (var i = 0; i < 10; i++)
{
Assert.IsTrue(reader.Read());
var name = reader.GetString(0);
}
var table = new DataTable();
table.Load(reader);

Assert.IsFalse(reader.Read());
Assert.AreEqual(1, table.Rows.Count);
Assert.AreEqual(2, table.Columns.Count);
Assert.AreEqual(1, table.Rows[0][0]);
Assert.AreEqual("hello world", table.Rows[0][1]);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ void IQueryExecutionOptions.RetrievingNextPage()

Guid IQueryExecutionOptions.UserId => Guid.NewGuid();

bool IQueryExecutionOptions.QuotedIdentifiers => true;

[TestMethod]
public void SimpleSelect()
{
Expand Down
3 changes: 3 additions & 0 deletions MarkMpn.Sql4Cds.Engine.Tests/OptionsWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public OptionsWrapper(IQueryExecutionOptions options)
BypassCustomPlugins = options.BypassCustomPlugins;
PrimaryDataSource = options.PrimaryDataSource;
UserId = options.UserId;
QuotedIdentifiers = options.QuotedIdentifiers;
}

public bool Cancelled { get; set; }
Expand Down Expand Up @@ -60,6 +61,8 @@ public OptionsWrapper(IQueryExecutionOptions options)

public Guid UserId { get; set; }

public bool QuotedIdentifiers { get; set; }

public bool ConfirmDelete(int count, EntityMetadata meta)
{
return _options.ConfirmDelete(count, meta);
Expand Down
5 changes: 3 additions & 2 deletions MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ void IQueryExecutionOptions.RetrievingNextPage()

Guid IQueryExecutionOptions.UserId => Guid.NewGuid();

bool IQueryExecutionOptions.QuotedIdentifiers => false;

[TestMethod]
public void SimpleSelect()
{
Expand Down Expand Up @@ -1766,8 +1768,7 @@ public void QuotedIdentifierError()
try
{
var metadata = new AttributeMetadataCache(_service);
var planBuilder = new ExecutionPlanBuilder(metadata, new StubTableSizeCache(), this);
planBuilder.QuotedIdentifiers = true;
var planBuilder = new ExecutionPlanBuilder(metadata, new StubTableSizeCache(), new OptionsWrapper(this) { QuotedIdentifiers = true });
var queries = planBuilder.Build(query, null, out _);

Assert.Fail("Expected exception");
Expand Down
2 changes: 2 additions & 0 deletions MarkMpn.Sql4Cds.Engine.Tests/StubOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,7 @@ void IQueryExecutionOptions.RetrievingNextPage()
string IQueryExecutionOptions.PrimaryDataSource => "local";

Guid IQueryExecutionOptions.UserId => Guid.NewGuid();

bool IQueryExecutionOptions.QuotedIdentifiers => true;
}
}
2 changes: 2 additions & 0 deletions MarkMpn.Sql4Cds.Engine/Ado/CancellationTokenOptionsWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public CancellationTokenOptionsWrapper(IQueryExecutionOptions options, Cancellat

public Guid UserId => _options.UserId;

public bool QuotedIdentifiers => _options.QuotedIdentifiers;

public bool ConfirmDelete(int count, EntityMetadata meta)
{
return _options.ConfirmDelete(count, meta);
Expand Down
2 changes: 2 additions & 0 deletions MarkMpn.Sql4Cds.Engine/Ado/ChangeDatabaseOptionsWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public ChangeDatabaseOptionsWrapper(IQueryExecutionOptions options)

public Guid UserId => _options.UserId;

public bool QuotedIdentifiers => _options.QuotedIdentifiers;

public bool ConfirmDelete(int count, EntityMetadata meta)
{
return _options.ConfirmDelete(count, meta);
Expand Down
2 changes: 2 additions & 0 deletions MarkMpn.Sql4Cds.Engine/Ado/DefaultQueryExecutionOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ public DefaultQueryExecutionOptions(DataSource dataSource)

public Guid UserId { get; }

public bool QuotedIdentifiers => true;

public bool ConfirmDelete(int count, EntityMetadata meta)
{
return true;
Expand Down
15 changes: 15 additions & 0 deletions MarkMpn.Sql4Cds.Engine/Ado/ISql4CdsDataReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using MarkMpn.Sql4Cds.Engine.ExecutionPlan;

namespace MarkMpn.Sql4Cds.Engine
{
public interface ISql4CdsDataReader : IDataReader
{
IDataSetExecutionPlanNode CurrentResultQuery { get; }

DataTable GetCurrentDataTable();
}
}
6 changes: 5 additions & 1 deletion MarkMpn.Sql4Cds.Engine/Ado/InfoMessageEventArgs.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using MarkMpn.Sql4Cds.Engine.ExecutionPlan;

namespace MarkMpn.Sql4Cds.Engine
{
public class InfoMessageEventArgs : EventArgs
{
public InfoMessageEventArgs(string message)
public InfoMessageEventArgs(IRootExecutionPlanNode node, string message)
{
Statement = node;
Message = message;
}

public IRootExecutionPlanNode Statement { get; }

public string Message { get; }
}
}
8 changes: 4 additions & 4 deletions MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public Sql4CdsCommand(Sql4CdsConnection connection, string commandText)
_planBuilder = new ExecutionPlanBuilder(_connection.DataSources.Values, _connection.Options);
}

internal IRootExecutionPlanNode[] Plan => _plan;
public IRootExecutionPlanNode[] Plan => _plan;

public override string CommandText
{
Expand Down Expand Up @@ -70,12 +70,12 @@ public override CommandType CommandType

public event EventHandler<StatementCompletedEventArgs> StatementCompleted;

internal void OnStatementCompleted(int recordsAffected)
internal void OnStatementCompleted(IRootExecutionPlanNode node, int recordsAffected)
{
var handler = StatementCompleted;

if (handler != null)
handler(this, new StatementCompletedEventArgs(recordsAffected));
handler(this, new StatementCompletedEventArgs(node, recordsAffected));
}

protected override DbConnection DbConnection
Expand Down Expand Up @@ -178,7 +178,7 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
cmd.Parameters.Add(param);
}

return new SqlDataReaderWrapper(con, cmd);
return new SqlDataReaderWrapper(_connection, this, con, cmd, _connection.Database);
}

_cts = CommandTimeout == 0 ? new CancellationTokenSource() : new CancellationTokenSource(TimeSpan.FromSeconds(CommandTimeout));
Expand Down
5 changes: 3 additions & 2 deletions MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Text;
using Microsoft.Crm.Sdk.Messages;
using MarkMpn.Sql4Cds.Engine.ExecutionPlan;
#if NETCOREAPP
using Microsoft.PowerPlatform.Dataverse.Client;
#else
Expand Down Expand Up @@ -111,12 +112,12 @@ private static IReadOnlyList<DataSource> BuildDataSources(IOrganizationService o

public event EventHandler<InfoMessageEventArgs> InfoMessage;

internal void OnInfoMessage(string message)
internal void OnInfoMessage(IRootExecutionPlanNode node, string message)
{
var handler = InfoMessage;

if (handler != null)
handler(this, new InfoMessageEventArgs(message));
handler(this, new InfoMessageEventArgs(node, message));
}

internal Dictionary<string, DataSource> DataSources => _dataSources;
Expand Down
35 changes: 30 additions & 5 deletions MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@

namespace MarkMpn.Sql4Cds.Engine
{
public class Sql4CdsDataReader : DbDataReader
class Sql4CdsDataReader : DbDataReader, ISql4CdsDataReader
{
private readonly Sql4CdsConnection _connection;
private readonly Sql4CdsCommand _command;
private readonly IQueryExecutionOptions _options;
private readonly CommandBehavior _behavior;
private readonly List<DataTable> _results;
private readonly List<IDataSetExecutionPlanNode> _resultQueries;
private readonly int _recordsAffected;
private int _resultIndex;
private int _rowIndex;
Expand Down Expand Up @@ -63,6 +64,7 @@ public Sql4CdsDataReader(Sql4CdsCommand command, IQueryExecutionOptions options,
_behavior = behavior;

_results = new List<DataTable>();
_resultQueries = new List<IDataSetExecutionPlanNode>();
_recordsAffected = -1;

var parameterTypes = ((Sql4CdsParameterCollection)command.Parameters).GetParameterTypes();
Expand All @@ -79,18 +81,22 @@ public Sql4CdsDataReader(Sql4CdsCommand command, IQueryExecutionOptions options,
{
var table = dataSetNode.Execute(_connection.DataSources, options, parameterTypes, parameterValues);
_results.Add(table);
_resultQueries.Add(dataSetNode);

_connection.OnInfoMessage(plan, $"({table.Rows.Count} row{(table.Rows.Count == 1 ? "" : "s")} affected)");
command.OnStatementCompleted(plan, -1);
}
else if (plan is IDmlQueryExecutionPlanNode dmlNode)
{
var msg = dmlNode.Execute(_connection.DataSources, options, parameterTypes, parameterValues, out var recordsAffected);

if (!String.IsNullOrEmpty(msg))
_connection.OnInfoMessage(msg);
_connection.OnInfoMessage(plan, msg);

command.OnStatementCompleted(plan, recordsAffected);

if (recordsAffected != -1)
{
command.OnStatementCompleted(recordsAffected);

if (_recordsAffected == -1)
_recordsAffected = 0;

Expand All @@ -100,9 +106,13 @@ public Sql4CdsDataReader(Sql4CdsCommand command, IQueryExecutionOptions options,
}

_resultIndex = -1;
NextResult();

if (!NextResult())
Close();
}

public IDataSetExecutionPlanNode CurrentResultQuery => _resultQueries[_resultIndex];

public override object this[int ordinal] => ToClrType(GetRawValue(ordinal));

public override object this[string name] => ToClrType(GetRawValue(name));
Expand Down Expand Up @@ -296,6 +306,21 @@ public override bool Read()
return true;
}

public override DataTable GetSchemaTable()
{
return null;
}

public DataTable GetCurrentDataTable()
{
var table = _results[_resultIndex];

if (!NextResult())
Close();

return table;
}

public override void Close()
{
_closed = true;
Expand Down
31 changes: 29 additions & 2 deletions MarkMpn.Sql4Cds.Engine/Ado/SqlDataReaderWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Text;
using MarkMpn.Sql4Cds.Engine.ExecutionPlan;

namespace MarkMpn.Sql4Cds.Engine
{
class SqlDataReaderWrapper : DbDataReader
class SqlDataReaderWrapper : DbDataReader, ISql4CdsDataReader
{
private Sql4CdsConnection _connection;
private SqlConnection _sqlConnection;
private SqlCommand _sqlCommand;
private SqlDataReader _sqlDataReader;
private readonly SqlNode _node;

public SqlDataReaderWrapper(SqlConnection sqlConnection, SqlCommand sqlCommand)
public SqlDataReaderWrapper(Sql4CdsConnection connection, Sql4CdsCommand command, SqlConnection sqlConnection, SqlCommand sqlCommand, string dataSource)
{
_connection = connection;
_sqlConnection = sqlConnection;
_sqlCommand = sqlCommand;
_sqlDataReader = sqlCommand.ExecuteReader();
_node = new SqlNode { Sql = sqlCommand.CommandText, DataSource = dataSource };
command.OnStatementCompleted(_node, -1);
}

public IDataSetExecutionPlanNode CurrentResultQuery => _node;

public override object this[int ordinal] => _sqlDataReader[ordinal];

public override object this[string name] => _sqlDataReader[name];
Expand Down Expand Up @@ -154,6 +163,24 @@ public override bool Read()
return _sqlDataReader.Read();
}

public override DataTable GetSchemaTable()
{
return _sqlDataReader.GetSchemaTable();
}

public override void Close()
{
_sqlDataReader.Close();
}

public DataTable GetCurrentDataTable()
{
var table = new DataTable();
table.Load(this);
_connection.OnInfoMessage(_node, $"({table.Rows.Count} row{(table.Rows.Count == 1 ? "" : "s")} affected)");
return table;
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Expand Down
20 changes: 20 additions & 0 deletions MarkMpn.Sql4Cds.Engine/Ado/StatementCompletedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using MarkMpn.Sql4Cds.Engine.ExecutionPlan;

namespace MarkMpn.Sql4Cds.Engine
{
public class StatementCompletedEventArgs
{
public StatementCompletedEventArgs(IRootExecutionPlanNode node, int recordsAffected)
{
Statement = node;
RecordsAffected = recordsAffected;
}

public IRootExecutionPlanNode Statement { get; }

public int RecordsAffected { get; }
}
}
3 changes: 2 additions & 1 deletion MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,8 @@ public static Type ToNetType(this DataTypeReference type, out SqlDataTypeReferen
[typeof(SqlInt16)] = new SqlDataTypeReference { SqlDataTypeOption = SqlDataTypeOption.SmallInt },
[typeof(SqlByte)] = new SqlDataTypeReference { SqlDataTypeOption = SqlDataTypeOption.TinyInt },
[typeof(SqlGuid)] = new SqlDataTypeReference { SqlDataTypeOption = SqlDataTypeOption.UniqueIdentifier },
[typeof(SqlEntityReference)] = new UserDataTypeReference { Name = new SchemaObjectName { Identifiers = { new Identifier { Value = typeof(SqlEntityReference).FullName } } } }
[typeof(SqlEntityReference)] = new UserDataTypeReference { Name = new SchemaObjectName { Identifiers = { new Identifier { Value = typeof(SqlEntityReference).FullName } } } },
[typeof(object)] = new SqlDataTypeReference { SqlDataTypeOption = SqlDataTypeOption.Sql_Variant }
};

/// <summary>
Expand Down
Loading

0 comments on commit 7a58203

Please sign in to comment.