diff --git a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs index a8dfb011..8170aae4 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs @@ -82,6 +82,8 @@ void IQueryExecutionOptions.RetrievingNextPage() { } + string IQueryExecutionOptions.PrimaryDataSource => "local"; + Guid IQueryExecutionOptions.UserId => Guid.NewGuid(); [TestMethod] @@ -2996,7 +2998,7 @@ public void CrossInstanceJoin() TableSizeCache = new StubTableSizeCache() } }; - var planBuilder = new ExecutionPlanBuilder(datasources, "uat", this); + var planBuilder = new ExecutionPlanBuilder(datasources, this); var query = "SELECT uat.name, prod.name FROM uat.dbo.account AS uat INNER JOIN prod.dbo.account AS prod ON uat.accountid = prod.accountid WHERE uat.name <> prod.name AND uat.name LIKE '%test%'"; diff --git a/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs index cc97222b..615a0db6 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs @@ -52,6 +52,8 @@ void IQueryExecutionOptions.RetrievingNextPage() { } + string IQueryExecutionOptions.PrimaryDataSource => "local"; + Guid IQueryExecutionOptions.UserId => Guid.NewGuid(); [TestMethod] diff --git a/MarkMpn.Sql4Cds.Engine.Tests/StubOptions.cs b/MarkMpn.Sql4Cds.Engine.Tests/StubOptions.cs index aa814f6d..d851cd11 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/StubOptions.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/StubOptions.cs @@ -64,6 +64,8 @@ void IQueryExecutionOptions.RetrievingNextPage() { } + string IQueryExecutionOptions.PrimaryDataSource => "local"; + Guid IQueryExecutionOptions.UserId => Guid.NewGuid(); } } diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs index 925928c6..c93bfd3a 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExpressionExtensions.cs @@ -1197,9 +1197,9 @@ private static SqlDateTime GetCurrentTimestamp(IQueryExecutionOptions options) return new SqlDateTime(DateTime.UtcNow); } - private static SqlGuid GetCurrentUser(IQueryExecutionOptions options) + private static SqlEntityReference GetCurrentUser(IQueryExecutionOptions options) { - return options.UserId; + return new SqlEntityReference(options.PrimaryDataSource, "systemuser", options.UserId); } /// diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 5eaa9304..dade75df 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -21,14 +21,13 @@ public class ExecutionPlanBuilder private int _colNameCounter; public ExecutionPlanBuilder(IAttributeMetadataCache metadata, ITableSizeCache tableSize, IQueryExecutionOptions options) - : this(new[] { new DataSource { Name = "local", Metadata = metadata, TableSizeCache = tableSize } }, "local", options) + : this(new[] { new DataSource { Name = "local", Metadata = metadata, TableSizeCache = tableSize } }, options) { } - public ExecutionPlanBuilder(IEnumerable dataSources, string primaryDataSource, IQueryExecutionOptions options) + public ExecutionPlanBuilder(IEnumerable dataSources, IQueryExecutionOptions options) { DataSources = dataSources.ToDictionary(ds => ds.Name, StringComparer.OrdinalIgnoreCase); - PrimaryDataSource = primaryDataSource; Options = options; } @@ -37,11 +36,6 @@ public ExecutionPlanBuilder(IEnumerable dataSources, string primaryD /// public IDictionary DataSources { get; } - /// - /// The name of the connection that will be used by default - /// - public string PrimaryDataSource { get; set; } - /// /// Returns or sets a value indicating if SQL will be parsed using quoted identifiers /// @@ -212,7 +206,7 @@ private ExecuteAsNode ConvertExecuteAsStatement(ExecuteAsStatement impersonate) { UserIdSource = "systemuser.systemuserid", Source = source, - DataSource = PrimaryDataSource + DataSource = Options.PrimaryDataSource }; } @@ -220,7 +214,7 @@ private RevertNode ConvertRevertStatement(RevertStatement revert) { return new RevertNode { - DataSource = PrimaryDataSource + DataSource = Options.PrimaryDataSource }; } @@ -301,7 +295,7 @@ private IExecutionPlanNode ConvertInsertSelectSource(SelectInsertSource selectSo private DataSource SelectDataSource(SchemaObjectName schemaObject) { - var databaseName = schemaObject.DatabaseIdentifier?.Value ?? PrimaryDataSource; + var databaseName = schemaObject.DatabaseIdentifier?.Value ?? Options.PrimaryDataSource; if (!DataSources.TryGetValue(databaseName, out var dataSource)) throw new NotSupportedQueryFragmentException("Invalid database name", schemaObject) { Suggestion = $"Available database names:\r\n* {String.Join("\r\n*", DataSources.Keys.OrderBy(k => k))}" }; @@ -526,7 +520,7 @@ private DeleteNode ConvertDeleteStatement(DeleteSpecification delete, IList 0) diff --git a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs index bb14145d..7396ae77 100644 --- a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs @@ -385,9 +385,9 @@ public static SqlInt32 CharIndex(SqlString find, SqlString search, SqlInt32 star /// /// The options that provide access to the user details /// - public static SqlGuid User_Name(IQueryExecutionOptions options) + public static SqlEntityReference User_Name(IQueryExecutionOptions options) { - return options.UserId; + return new SqlEntityReference(options.PrimaryDataSource, "systemuser", options.UserId); } /// diff --git a/MarkMpn.Sql4Cds.Engine/IQueryExecutionOptions.cs b/MarkMpn.Sql4Cds.Engine/IQueryExecutionOptions.cs index c67d95c7..1e1086cf 100644 --- a/MarkMpn.Sql4Cds.Engine/IQueryExecutionOptions.cs +++ b/MarkMpn.Sql4Cds.Engine/IQueryExecutionOptions.cs @@ -118,6 +118,11 @@ public interface IQueryExecutionOptions /// void RetrievingNextPage(); + /// + /// Returns the name of the primary data source the query is being executed in + /// + string PrimaryDataSource { get; } + /// /// Returns the unique identifier of the current user /// diff --git a/MarkMpn.Sql4Cds.Engine/Sql2FetchXml.cs b/MarkMpn.Sql4Cds.Engine/Sql2FetchXml.cs index 60ce3bfe..b7660815 100644 --- a/MarkMpn.Sql4Cds.Engine/Sql2FetchXml.cs +++ b/MarkMpn.Sql4Cds.Engine/Sql2FetchXml.cs @@ -59,6 +59,8 @@ public QueryExecutionOptions(Sql2FetchXml sql2FetchXml) public bool UseLocalTimeZone => false; + public string PrimaryDataSource => "local"; + public Guid UserId { get; set; } public List JoinOperatorsAvailable => new List { JoinOperator.Inner, JoinOperator.LeftOuter }; diff --git a/MarkMpn.Sql4Cds/QueryExecutionOptions.cs b/MarkMpn.Sql4Cds/QueryExecutionOptions.cs index b80b2644..d72b54d9 100644 --- a/MarkMpn.Sql4Cds/QueryExecutionOptions.cs +++ b/MarkMpn.Sql4Cds/QueryExecutionOptions.cs @@ -174,6 +174,8 @@ public void RetrievingNextPage() throw new QueryExecutionException($"Hit maximum retrieval limit. This limit is in place to protect against excessive API requests. Try restricting the data to retrieve with WHERE clauses or eliminating subqueries.\r\nYour limit of {Settings.Instance.MaxRetrievesPerQuery:N0} retrievals per query can be modified in Settings."); } + public string PrimaryDataSource => _con.ConnectionName; + public Guid UserId { get diff --git a/MarkMpn.Sql4Cds/SqlQueryControl.cs b/MarkMpn.Sql4Cds/SqlQueryControl.cs index f9d83d1e..fefcb906 100644 --- a/MarkMpn.Sql4Cds/SqlQueryControl.cs +++ b/MarkMpn.Sql4Cds/SqlQueryControl.cs @@ -854,7 +854,7 @@ private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) backgroundWorker.ReportProgress(0, "Executing query..."); var options = new QueryExecutionOptions(_con, DataSources[_con.ConnectionName].Connection, backgroundWorker, this); - var converter = new ExecutionPlanBuilder(DataSources.Values, _con.ConnectionName, options); + var converter = new ExecutionPlanBuilder(DataSources.Values, options); if (Settings.Instance.UseTSQLEndpoint && args.Execute &&