Skip to content

Commit

Permalink
Do not fold DISTINCT to queries including audit.objectid
Browse files Browse the repository at this point in the history
Fixes #519
  • Loading branch information
MarkMpn committed Jul 25, 2024
1 parent 9a1bb1d commit da02945
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
27 changes: 27 additions & 0 deletions MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6040,6 +6040,33 @@ public void SelectAuditObjectId()
</fetch>");
}

[DataTestMethod]
[DataRow("objectid")]
[DataRow("objectidname")]
[DataRow("objectidtype")]
public void SelectAuditObjectIdDistinct(string column)
{
// https://github.com/MarkMpn/Sql4Cds/issues/296
// https://github.com/MarkMpn/Sql4Cds/issues/519
// We need to add the objecttypecode attribute to the FetchXML for the first issue, but combining this
// with DISTINCT doesn't work because of the second issue.
var planBuilder = new ExecutionPlanBuilder(_dataSources.Values, new OptionsWrapper(this) { PrimaryDataSource = "prod" });
var query = $"SELECT DISTINCT {column} AS o FROM audit";
var plans = planBuilder.Build(query, null, out _);

Assert.AreEqual(1, plans.Length);
var select = AssertNode<SelectNode>(plans[0]);
var distinct = AssertNode<DistinctNode>(select.Source);
var fetch = AssertNode<FetchXmlScan>(distinct.Source);
AssertFetchXml(fetch, @"
<fetch xmlns:generator='MarkMpn.SQL4CDS'>
<entity name='audit'>
<attribute name='objectid' />
<attribute name='objecttypecode' />
</entity>
</fetch>");
}

[TestMethod]
public void FilterAuditOnLeftJoinColumn()
{
Expand Down
5 changes: 5 additions & 0 deletions MarkMpn.Sql4Cds.Engine/ExecutionPlan/DistinctNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext

if (Source is FetchXmlScan fetch)
{
// Can't apply DISTINCT to audit.objectid
// https://github.com/MarkMpn/Sql4Cds/issues/519
if (fetch.Entity.name == "audit" && Columns.Any(col => col.StartsWith(fetch.Alias.EscapeIdentifier() + ".objectid")))
return this;

fetch.FetchXml.distinct = true;
fetch.FetchXml.distinctSpecified = true;
var metadata = context.DataSources[fetch.DataSource].Metadata;
Expand Down
1 change: 0 additions & 1 deletion MarkMpn.Sql4Cds.Engine/ExecutionPlan/HashJoinNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ public override IDataExecutionPlanNodeInternal FoldQuery(NodeCompilationContext

// Make sure the join keys are not null - the SqlType classes override == to prevent NULL = NULL
// but .Equals used by the hash table allows them to match
// TODO: We do this in the base class as well, can we delete this version?
if (ComparisonType == BooleanComparisonType.Equals)
{
if (JoinType == QualifiedJoinType.Inner || JoinType == QualifiedJoinType.RightOuter)
Expand Down

0 comments on commit da02945

Please sign in to comment.