0

I currently have a database full of ACL entries which looks like so:

ACL database

I need to go through and parse out the difference between a root node (like \\chrlcltsvr02\AYY_LMO\ClientServices) and it's child nodes (ex. \\chrlcltsvr02\AYY_LMO\ClientServices\Client1).

I've attempted doing this in C# code by using an ORM and raw T-SQL like so (I do in fact know that opening a session per row is a horrible idea):

foreach (string path in distinctPaths)
{
    using (session = sessionFactory.OpenSession())
    {
        string query;

        query = String.Format("SELECT DISTINCT UserGroup, AllowDeny, Permissions FROM FilerACLs WHERE FullPath LIKE '{0}'", path.Replace("'", "''"));

        var parentACLs = session.CreateSQLQuery(query).SetResultTransformer(Transformers.AliasToBean<ShareACLEntry>()).List<ShareACLEntry>();

        query = String.Format("SELECT DISTINCT UserGroup, AllowDeny, Permissions FROM FilerACLs WHERE FullPath LIKE '{0}\\%'", path.Replace("'", "''"));

        var childACLs = session.CreateSQLQuery(query).SetResultTransformer(Transformers.AliasToBean<ShareACLEntry>()).List<ShareACLEntry>();

        if (childACLs.Except(parentACLs, comparer).ToList().Count > 0)
            Console.WriteLine("{0} has diffs!", path);
    }
}

And finally comparing the resulting data to see whether the child nodes differ from the root node.

By differ, I mean if I have an ACL for group "CLT-AD\Full Access Shared-CHRL" with allowed full control on the parent node and not on the child node, I'd like to note that the ACL exists on the child but not the parent.

Unfortuantely, this process is far too slow to parse the 500k rows in any decent amount of time.

I'd like to know if anyone has an idea for efficiently determining if there is differences in the data--be it using T-SQL directly, a SQL CLR function, or a better algorithm in general.

Please let me know if clarification is required.

Thanks!

EDIT

Since I've gotten a fair amount of hate on this question let me re-clarify exactly what I'm looking for minus the failed approaches I've outlined above.

I recently performed a scan against ~1,000 shared folders on a Windows server. This scan recursed from the top level directory all the way down the hierarchy of folders, and for each folder recorded a row for each ACL.

The database therefore looks like the screenshot above.

What I need to do is pull a report from this database which details the difference (or even whether there is any) between the ACLs recorded from a top level directory and the ACLs recorded for any directory under this top level directory.

Hopefully that makes more sense.

cjones26
  • 3,459
  • 1
  • 34
  • 51
  • 2
    that is not C# code it is TSQL. What do you mean by "differences"? – Jodrell Mar 27 '15 at 14:07
  • Sorry I forgot to mention I used an ORM to convert the result of the raw SQL to a CLR object. – cjones26 Mar 27 '15 at 14:09
  • You'll have to show your C# code to let us know if what you are doing there can be translated into a purely SQL solution, or to see if the algorithm can be improved. – juharr Mar 27 '15 at 14:11
  • Is the [FullPath] of the "root node" and "child node" known? Or do you wan't to know all differences of all parents and children across the whole set? – Jodrell Mar 27 '15 at 14:12
  • Okay I've clarified a bit more and added the relevant code. Please let me know if anything is still unclear. Thank you!! – cjones26 Mar 27 '15 at 14:14
  • I have to warn you, your code looks like an SQL Injection Attack waiting to happen. – Jodrell Mar 27 '15 at 14:24
  • I understand and know that it's not best practice--this is all internal to our organization and will simply be used once to run a report. Thanks for the fair warning. I've also noticed it's hard to phrase a difficult question on here without getting downvoted to hell so I appreciate your help. – cjones26 Mar 27 '15 at 14:27

2 Answers2

2

Here is some TSQL,

DECLARE @parentFullPath NVARCHAR(260) = N'\\chrlcltsvr02\AYY_LMO\ClientServices';
DECLARE @childFullPath NVARCHAR(260) = N'\\chrlcltsvr02\AYY_LMO\ClientServices\Client1';

SELECT
            [UserGroup],
            [AllowDeny],
            [Permissions]
    FROM
            [ACLs]
    WHERE
            [FullPath] = @childFullPath
EXCEPT
SELECT
            [UserGroup],
            [AllowDeny],
            [Permissions]
    FROM
            [ACLs]
    WHERE
            [FullPath] = @parentFullPath;

It may or may not do what your require, its hard to tell.


To find all the parent child pairs,

WITH [paths] AS (
SELECT
             [FullPath]
    FROM
             [ACLs]
    GROUP BY
             [FullPath])
SELECT
            [P].[FullPath] [ParentFullPath],
            [C].[FullPath] [ChildFullPath]
    FROM
            [paths] [P]
        JOIN
            [paths] [C]
                ON
                        [C].[FullPath] <> [P].[FullPath]
                    AND
                        CHARINDEX([P].[FullPath], [C].[FullPath]) = 1;

so you could in fact do it all at once, something like this.

WITH [paths] AS (
SELECT
             [FullPath]
    FROM
             [ACLs]
    GROUP BY
             [FullPath])
SELECT
            [PC].[ParentFullPath],
            [PC].[ChildFullPath],
            [D].[UserGroup],
            [D].[AllowDeny],
            [D].[Permissions]
    FROM (
            SELECT
                        [P].[FullPath] [ParentFullPath],
                        [C].[FullPath] [ChildFullPath]
                FROM
                        [paths] [P]
                    JOIN
                        [paths] [C]
                            ON
                                    [C].[FullPath] <> [P].[FullPath]
                                AND
                                    CHARINDEX([P].[FullPath], [C].[FullPath]) = 1;
        ) [PC]
CROSS APPLY
(
SELECT
            [UserGroup],
            [AllowDeny],
            [Permissions]
    FROM
            [ACLs]
    WHERE
            [FullPath] = [PC].[ChildFullPath]
EXCEPT
SELECT
            [UserGroup],
            [AllowDeny],
            [Permissions]
    FROM
            [ACLs]
    WHERE
            [FullPath] = [PC].[ParentFullPath]
) [D];

Ultimately, if you want this code to run efficiently you'll need to normalize your schema somewhat. As long as the parent child relationship exists only by inference through string comparison this will be a relatively slow operation.

Jodrell
  • 34,946
  • 5
  • 87
  • 124
  • This is very close to what I've tried in T-SQL--I'm curious as if there's a way to loop through through all distinct paths that I have--so in response to your comment on my questions I guess the root nodes would be pulled using a DISTCINT on full path and child nodes would need to be calculated from there. – cjones26 Mar 27 '15 at 14:21
  • This works flawlessly to pull the data I am looking for. Thank you for your assistance Jodrell!!! – cjones26 Mar 27 '15 at 17:51
1

If you want to do it for the whole list in one go you might write an SQL expression (for example using substring()) to get_parent_path_from_child_path and run a following SQL structure. It is not clear from your question how to separate parent from child in a general case. So I am just giving you a wireframe code.

(
SELECT -- parents
            [UserGroup],
            [AllowDeny],
            [Permissions],
            [FullPath] as parent_path
    FROM
            [ACLs]
  WHERE add a filter for parents here

minus 
SELECT -- children
            [UserGroup],
            [AllowDeny],
            [Permissions],
            get_parent_path_from_child_path([FullPath]) as parent_path
    FROM
            [ACLs]
    WHERE add a filter for children here

)
union 
(
SELECT -- children
            [UserGroup],
            [AllowDeny],
            [Permissions],
            get_parent_path_from_child_path([FullPath]) as parent_path
    FROM
            [ACLs]
    WHERE add a filter for children here
minus
SELECT -- parents
            [UserGroup],
            [AllowDeny],
            [Permissions],
            [FullPath] as parent_path
    FROM
            [ACLs]
  WHERE add a filter for parents here

) 
Diego
  • 812
  • 7
  • 25