Skip to content

Commit

Permalink
Initial work to extract activity type when revoking access
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Sep 18, 2024
1 parent 992352f commit 2317098
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 4 deletions.
36 changes: 34 additions & 2 deletions MarkMpn.Sql4Cds.Engine/ExecutionPlan/DeleteNode.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Linq;
using System.ServiceModel;
using System.Threading;
Expand Down Expand Up @@ -49,6 +50,14 @@ class DeleteNode : BaseDmlNode
[DisplayName("SecondaryId Source")]
public string SecondaryIdSource { get; set; }

/// <summary>
/// The column that contains the type code of the records to delete (used for activity records)
/// </summary>
[Category("Delete")]
[Description("The column that contains the type code of the records to delete (used for activity records)")]
[DisplayName("ActivityTypeCode Source")]
public string ActivityTypeCodeSource { get; set; }

[Category("Delete")]
public override int MaxDOP { get; set; }

Expand All @@ -71,6 +80,9 @@ public override void AddRequiredColumns(NodeCompilationContext context, IList<st
if (SecondaryIdSource != null && !requiredColumns.Contains(SecondaryIdSource))
requiredColumns.Add(SecondaryIdSource);

if (ActivityTypeCodeSource != null && !requiredColumns.Contains(ActivityTypeCodeSource))
requiredColumns.Add(ActivityTypeCodeSource);

Source.AddRequiredColumns(context, requiredColumns);
}

Expand All @@ -89,7 +101,8 @@ public override IRootExecutionPlanNodeInternal[] FoldQuery(NodeCompilationContex
Source is FetchXmlScan fetch &&
LogicalName == fetch.Entity.name &&
PrimaryIdSource.Equals($"{fetch.Alias}.{dataSource.Metadata[LogicalName].PrimaryIdAttribute}") &&
String.IsNullOrEmpty(SecondaryIdSource))
String.IsNullOrEmpty(SecondaryIdSource) &&
String.IsNullOrEmpty(ActivityTypeCodeSource))
{
return new[] { new BulkDeleteJobNode { DataSource = DataSource, Source = fetch } };
}
Expand All @@ -104,6 +117,9 @@ protected override void RenameSourceColumns(IDictionary<string, string> columnRe

if (SecondaryIdSource != null && columnRenamings.TryGetValue(SecondaryIdSource, out var secondaryIdSourceRenamed))
SecondaryIdSource = secondaryIdSourceRenamed;

if (ActivityTypeCodeSource != null && columnRenamings.TryGetValue(ActivityTypeCodeSource, out var activityTypeCodeSourceRenamed))
ActivityTypeCodeSource = activityTypeCodeSourceRenamed;
}

public override void Execute(NodeExecutionContext context, out int recordsAffected, out string message)
Expand Down Expand Up @@ -217,11 +233,18 @@ private OrganizationRequest CreateDeleteRequest(EntityMetadata meta, Entity enti
{
if (meta.LogicalName == "principalobjectaccess")
{
return new RevokeAccessRequest
var revoke = new RevokeAccessRequest
{
Target = (EntityReference)primaryIdAccessor(entity),
Revokee = (EntityReference)secondaryIdAccessor(entity)
};

// Special case for activitypointer - need to set the specific activity type code
var activityTypeCode = entity.GetAttributeValue<SqlString>(ActivityTypeCodeSource);
if (!activityTypeCode.IsNull)
revoke.Target.LogicalName = activityTypeCode.Value;

return revoke;
}

var id = (Guid)primaryIdAccessor(entity);
Expand Down Expand Up @@ -268,6 +291,14 @@ private OrganizationRequest CreateDeleteRequest(EntityMetadata meta, Entity enti
};
}

// Special case for activitypointer - need to set the specific activity type code
if (ActivityTypeCodeSource != null)
{
var activityTypeCode = entity.GetAttributeValue<SqlString>(ActivityTypeCodeSource);
if (!activityTypeCode.IsNull)
req.Target.LogicalName = activityTypeCode.Value;
}

return req;
}

Expand Down Expand Up @@ -399,6 +430,7 @@ public override object Clone()
MaxDOP = MaxDOP,
PrimaryIdSource = PrimaryIdSource,
SecondaryIdSource = SecondaryIdSource,
ActivityTypeCodeSource = ActivityTypeCodeSource,
Source = (IExecutionPlanNodeInternal)Source.Clone(),
Sql = Sql
};
Expand Down
91 changes: 89 additions & 2 deletions MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,7 @@ private DeleteNode ConvertDeleteStatement(DeleteSpecification delete, IList<Opti

var primaryKey = targetMetadata.PrimaryIdAttribute;
string secondaryKey = null;
string activityTypeCode = null;
var requiredFields = new List<string>();

if (targetMetadata.LogicalName == "listmember")
Expand All @@ -1761,6 +1762,10 @@ private DeleteNode ConvertDeleteStatement(DeleteSpecification delete, IList<Opti
primaryKey = "objectid";
secondaryKey = "principalid";
}
else if (targetMetadata.LogicalName == "activitypointer")
{
activityTypeCode = "activitytypecode";
}

if (deleteTarget.TargetSchema?.Equals("bin", StringComparison.OrdinalIgnoreCase) == true)
{
Expand Down Expand Up @@ -1877,10 +1882,88 @@ private DeleteNode ConvertDeleteStatement(DeleteSpecification delete, IList<Opti
if (secondaryKey != null)
requiredFields.Add(secondaryKey);

if (activityTypeCode != null)
requiredFields.Add(activityTypeCode);

if (targetMetadata.LogicalName == "principalobjectaccess")
{
requiredFields.Add("objecttypecode");
requiredFields.Add("principaltypecode");

// In case any of the records are for an activity, include the activitytypecode by joining to the activitypointer table
queryExpression.SelectElements.Add(new SelectScalarExpression
{
Expression = new ScalarSubquery
{
QueryExpression = new QuerySpecification
{
SelectElements =
{
new SelectScalarExpression
{
Expression = new ColumnReferenceExpression
{
MultiPartIdentifier = new MultiPartIdentifier
{
Identifiers =
{
new Identifier { Value = "activitypointer" },
new Identifier { Value = "activitytypecode" }
}
}
}
}
},
FromClause = new FromClause
{
TableReferences =
{
new NamedTableReference
{
SchemaObject = new SchemaObjectName
{
Identifiers =
{
new Identifier { Value = "activitypointer" }
}
}
}
}
},
WhereClause = new WhereClause
{
SearchCondition = new BooleanComparisonExpression
{
FirstExpression = new ColumnReferenceExpression
{
MultiPartIdentifier = new MultiPartIdentifier
{
Identifiers =
{
new Identifier { Value = targetAlias },
new Identifier { Value = "objectid" }
}
}
},
ComparisonType = BooleanComparisonType.Equals,
SecondExpression = new ColumnReferenceExpression
{
MultiPartIdentifier = new MultiPartIdentifier
{
Identifiers =
{
new Identifier { Value = "activitypointer" },
new Identifier { Value = "activityid" }
}
}
}
}
}
}
},
ColumnName = new IdentifierOrValueExpression { Identifier = new Identifier { Value = "activitytypecode" } }
});
activityTypeCode = "activitytypecode";
}

foreach (var field in requiredFields)
Expand Down Expand Up @@ -1920,16 +2003,20 @@ private DeleteNode ConvertDeleteStatement(DeleteSpecification delete, IList<Opti
if (source is SelectNode select)
{
deleteNode.Source = select.Source;
deleteNode.PrimaryIdSource = $"{targetAlias}.{primaryKey}";
deleteNode.PrimaryIdSource = select.ColumnSet.Single(c => c.OutputColumn == primaryKey).SourceColumn;

if (secondaryKey != null)
deleteNode.SecondaryIdSource = $"{targetAlias}.{secondaryKey}";
deleteNode.SecondaryIdSource = select.ColumnSet.Single(c => c.OutputColumn == secondaryKey).SourceColumn;

if (activityTypeCode != null)
deleteNode.ActivityTypeCodeSource = select.ColumnSet.Single(c => c.OutputColumn == activityTypeCode).SourceColumn;
}
else
{
deleteNode.Source = source;
deleteNode.PrimaryIdSource = primaryKey;
deleteNode.SecondaryIdSource = secondaryKey;
deleteNode.ActivityTypeCodeSource = activityTypeCode;
}

return deleteNode;
Expand Down

0 comments on commit 2317098

Please sign in to comment.