diff --git a/SQL2012_BIDSHelper.csproj b/SQL2012_BIDSHelper.csproj
index 5553c6d..d94ee01 100644
--- a/SQL2012_BIDSHelper.csproj
+++ b/SQL2012_BIDSHelper.csproj
@@ -23,7 +23,7 @@
true
BIDSHelper.snk
- v4.0
+ v4.5
publish\
true
Disk
@@ -54,8 +54,11 @@
full
true
true
- ..\..\..\Program Files (x86)\Microsoft Visual Studio 11.0\Team Tools\Static Analysis Tools\Rule Sets\BIDSHelper.ruleset
+ BasicCorrectnessRules.ruleset
false
+ x86
+ false
+ false
false
@@ -70,6 +73,7 @@
1591
AllRules.ruleset
true
+ false
@@ -87,6 +91,7 @@
full
AnyCPU
AllRules.ruleset
+ false
@@ -110,6 +115,7 @@
True
+ False
$(ProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Business Intelligence Semantic Model\Microsoft.AnalysisServices.BackEnd.dll
@@ -129,16 +135,18 @@
c:\Program Files\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.AnalysisServices.Design.DLL
False
-
- $(ProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Business Intelligence Semantic Model\Microsoft.AnalysisServices.MPFProjectBase.dll
+
+ False
+ ..\..\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\PrivateAssemblies\Business Intelligence Semantic Model\Microsoft.AnalysisServices.MPFProjectBase.11.dll
False
True
False
-
- $(ProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Business Intelligence Semantic Model\Microsoft.AnalysisServices.VSHost.dll
+
+ False
+ ..\..\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\PrivateAssemblies\Business Intelligence Semantic Model\Microsoft.AnalysisServices.VSHost.11.dll
False
@@ -161,6 +169,7 @@
True
+ False
True
@@ -169,9 +178,11 @@
..\..\..\Windows\assembly\GAC_MSIL\Microsoft.ReportViewer.Common\11.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.Common.dll
+ False
..\..\..\Windows\assembly\GAC_MSIL\Microsoft.ReportViewer.WinForms\11.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.WinForms.DLL
+ False
True
@@ -179,15 +190,17 @@
True
+ False
True
False
-
+
False
False
- ..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SqlServer.ExecPackageTaskWrap\v4.0_12.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.ExecPackageTaskWrap.dll
+ ..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SqlServer.ExecPackageTaskWrap\v4.0_11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.ExecPackageTaskWrap.dll
+ False
False
@@ -204,19 +217,25 @@
True
+ False
False
..\..\Program Files (x86)\Microsoft SQL Server\110\DTS\Tasks\Microsoft.SqlServer.SQLTask.dll
+ False
True
+ False
False
+ False
+
+
+ False
-
True
DLLs\SQL2012\msddsp.dll
@@ -265,6 +284,7 @@
True
+ False
@@ -509,12 +529,6 @@
-
- Form
-
-
- FindReferences.cs
-
UserControl
@@ -527,9 +541,18 @@
FindUnusedVariables.cs
+
+ Form
+
+
+ FindVariableReferences.cs
+
+
+ Code
+
@@ -972,9 +995,6 @@
DesignWarningsOptionsPage.cs
Designer
-
- FindReferences.cs
-
FindReferencesControl.cs
Designer
@@ -982,6 +1002,9 @@
FindUnusedVariables.cs
+
+ FindVariableReferences.cs
+
ExpressionListControl.cs
diff --git a/SQL2012_BIDSHelper.csproj.user b/SQL2012_BIDSHelper.csproj.user
index 86ec0d8..9d8dfd6 100644
--- a/SQL2012_BIDSHelper.csproj.user
+++ b/SQL2012_BIDSHelper.csproj.user
@@ -1,7 +1,7 @@
- ProjectFiles
+ ShowAllFiles
C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\PrivateAssemblies\;C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\;C:\Program Files (x86)\Microsoft SQL Server\110\SDK\Assemblies\;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\;C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\PrivateAssemblies\Business Intelligence Semantic Model\
@@ -9,6 +9,6 @@
Program
C:\Program Files %28x86%29\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
- /resetaddin BIDSHelper2012-ForTesting.addin
+ "C:\Users\greendg\Documents\Visual Studio 2012\Projects\SSISPlay\SSISPlay.sln"
\ No newline at end of file
diff --git a/SQL2014_BIDSHelper.csproj b/SQL2014_BIDSHelper.csproj
index be7c1f5..b42b08c 100644
--- a/SQL2014_BIDSHelper.csproj
+++ b/SQL2014_BIDSHelper.csproj
@@ -503,17 +503,11 @@
-
+
Form
-
- FindReferences.cs
-
-
- UserControl
-
-
- FindReferencesControl.cs
+
+ FindVariableReferences.cs
Form
@@ -967,11 +961,8 @@
DesignWarningsOptionsPage.cs
Designer
-
- FindReferences.cs
-
-
- FindReferencesControl.cs
+
+ FindVariableReferences.cs
Designer
diff --git a/SSIS/Biml/BimlUtility.cs b/SSIS/Biml/BimlUtility.cs
index d17c82a..e19051c 100644
--- a/SSIS/Biml/BimlUtility.cs
+++ b/SSIS/Biml/BimlUtility.cs
@@ -113,14 +113,26 @@ private static string GetValidationReporterMessage(ValidationItem item)
builder.AppendFormat("Schema {0}. ", item.SchemaName);
}
- if (item.Exception != null)
+ ParseException(item.Exception, ref builder);
+
+ return builder.ToString().TrimEnd();
+ }
+
+ private static void ParseException(System.Exception exception, ref StringBuilder builder)
+ {
+ if (exception == null)
{
- // Just show the exception type name, which can help indicate the type of issue, e.g. invalid XML vs invalid BIML
- // We don't want the full Exception as it is confusing and makes you think something has gone wrong.
- builder.AppendFormat("Exception type: {0}", item.Exception.GetType().Name);
+ return;
}
- return builder.ToString().TrimEnd();
+ // Changed my mind!!!
+ //// Just show the exception type name, which can help indicate the type of issue, e.g. invalid XML vs invalid BIML
+ //// We don't want the full Exception as it is confusing and makes you think something has gone wrong.
+ //builder.AppendFormat("Exception type: {0}", item.Exception.GetType().Name);
+
+ builder.AppendFormat("\tException type: {0}, Message: {1}\r\n", exception.GetType().Name, exception.Message);
+
+ ParseException(exception.InnerException, ref builder);
}
private static void GetMessageString(string input, ref StringBuilder builder)
diff --git a/SSIS/ComponentInfo.cs b/SSIS/ComponentInfo.cs
index b5f96ff..f42a916 100644
--- a/SSIS/ComponentInfo.cs
+++ b/SSIS/ComponentInfo.cs
@@ -16,46 +16,65 @@ public class ComponentInfo
private static unsafe extern int DestroyIcon(IntPtr hIcon);
private DTSPipelineComponentType componentType;
- private string id;
- private string name;
- private string creationName;
- private Icon icon;
public ComponentInfo(PipelineComponentInfo componentInfo)
{
this.componentType = componentInfo.ComponentType;
- this.id = componentInfo.ID;
- this.name = componentInfo.Name;
- this.creationName = componentInfo.CreationName;
+ this.ID = componentInfo.ID;
+ this.Name = componentInfo.Name;
+ this.CreationName = componentInfo.CreationName;
+
+ Assembly assembly = GetComponentAssembly(componentInfo);
+
+ if (assembly != null)
+ {
+ Stream iconStream = assembly.GetManifestResourceStream(componentInfo.IconResource);
+ if (iconStream != null)
+ {
+ this.Icon = new Icon(iconStream, new Size(16, 16));
+ }
+ }
+ else
+ {
+ int index = 0;
+ Int32.TryParse(componentInfo.IconResource, out index);
+ this.Icon = ExtractIcon(componentInfo.IconFile, index, false);
+ }
+
+ // Ensure we always have an icon
+ if (this.Icon == null)
+ {
+ this.Icon = BIDSHelper.Resources.Common.NoIcon;
+ }
}
public ComponentInfo(TaskInfo componentInfo)
{
- this.id = componentInfo.ID;
- this.name = componentInfo.Name;
- this.creationName = componentInfo.CreationName;
+ this.ID = componentInfo.ID;
+ this.Name = componentInfo.Name;
+ this.CreationName = componentInfo.CreationName;
- Assembly assembly = ComponentInfo.GetComponentAssembly(componentInfo);
+ Assembly assembly = GetComponentAssembly(componentInfo);
if (assembly != null)
{
Stream iconStream = assembly.GetManifestResourceStream(componentInfo.IconResource);
if (iconStream != null)
{
- this.icon = new Icon(iconStream, new Size(16, 16));
+ this.Icon = new Icon(iconStream, new Size(16, 16));
}
}
else
{
int index = 0;
Int32.TryParse(componentInfo.IconResource, out index);
- this.icon = ExtractIcon(componentInfo.IconFile, index, false);
+ this.Icon = ExtractIcon(componentInfo.IconFile, index, false);
}
// Ensure we always have an icon
- if (this.icon == null)
+ if (this.Icon == null)
{
- this.icon = BIDSHelper.Resources.Common.NoIcon;
+ this.Icon = BIDSHelper.Resources.Common.NoIcon;
}
}
@@ -68,11 +87,11 @@ public ComponentInfo(Icon icon)
{
if (icon.Height > 16)
{
- this.icon = new Icon(icon, new Size(16, 16));
+ this.Icon = new Icon(icon, new Size(16, 16));
}
else
{
- this.icon = icon;
+ this.Icon = icon;
}
}
@@ -154,27 +173,27 @@ private static Icon ExtractIcon(string file, int index, bool large)
public DTSPipelineComponentType ComponentType
{
- get { return this.componentType; }
+ get; private set;
}
public string ID
{
- get { return this.id; }
+ get; private set;
}
public string Name
{
- get { return this.name; }
+ get; private set;
}
public string CreationName
{
- get { return this.creationName; }
+ get; private set;
}
public Icon Icon
{
- get { return this.icon; }
+ get; private set;
}
}
}
diff --git a/SSIS/FindUnusedVariables.cs b/SSIS/FindUnusedVariables.cs
index 9ebac1f..a71c43d 100644
--- a/SSIS/FindUnusedVariables.cs
+++ b/SSIS/FindUnusedVariables.cs
@@ -127,7 +127,7 @@ private void processPackage_DoWork(object sender, DoWorkEventArgs e)
stopwatch.Start();
Variable[] variables = e.Argument as Variable[];
- finder.FindReferences(this.package, variables);
+ finder.FindReferences(this.package, variables, null);
}
#endregion
diff --git a/SSIS/FindVariables.cs b/SSIS/FindVariables.cs
index e88d6f1..b953592 100644
--- a/SSIS/FindVariables.cs
+++ b/SSIS/FindVariables.cs
@@ -1,15 +1,29 @@
-using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
+using Microsoft.DataTransformationServices.Design;
+using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Tasks.ExecutePackageTask;
using Microsoft.SqlServer.Dts.Tasks.ExecuteSQLTask;
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Drawing;
+using System.Windows.Forms;
namespace BIDSHelper.SSIS
{
internal class FindVariables
{
+ public const string IconKeyFolder = "Folder";
+ public const string IconKeyProperties = "Properties";
+ public const string IconKeyInput = "Input";
+ public const string IconKeyOutput = "Output";
+ public const string IconKeyColumn = "Column";
+ public const string IconKeyPrecedenceConstraint = "PrecedenceConstraint";
+ public const string IconKeyVariable = "Variable";
+ public const string IconKeyVariableExpression = "VariableExpression";
+ public const string IconKeyProperty = "Property";
+ public const string IconKeyPropertyExpression = "PropertyExpression";
+
private string[] expressionMatches = null;
private string[] properytMatches = null;
@@ -18,6 +32,7 @@ internal class FindVariables
private const string ObjectTypeDataFlowTask = "DataFlowTask";
private const string ObjectTypeExecutePackageTask = "ExecutePackageTask";
+ private TreeView treeView;
public event EventHandler VariableFound;
@@ -34,12 +49,12 @@ public bool Cancel()
return true;
}
- public void FindReferences(Package package, Variable variable)
+ public void FindReferences(Package package, Variable variable, TreeView treeView)
{
- FindReferences(package, new Variable[] { variable });
+ FindReferences(package, new Variable[] { variable }, treeView);
}
- public void FindReferences(Package package, Variable[] variables)
+ public void FindReferences(Package package, Variable[] variables, TreeView treeView)
{
// Reset cancel pending flag
this.CancellationPending = false;
@@ -53,7 +68,7 @@ public void FindReferences(Package package, Variable[] variables)
expressions.Add(string.Format("@{0}", variable.Name));
expressions.Add(string.Format("@[{0}]", variable.Name));
expressions.Add(string.Format("@[{0}]", variable.QualifiedName));
-
+
// Clean qualified name for property match
properties.Add(variable.QualifiedName);
}
@@ -62,58 +77,257 @@ public void FindReferences(Package package, Variable[] variables)
this.expressionMatches = expressions.ToArray();
this.properytMatches = properties.ToArray();
- ProcessObject(package, string.Empty);
+ this.treeView = treeView;
+
+ if (treeView != null)
+ {
+ SetupImageList();
+
+ // Create package node, the top level node
+ int imageIndex = GetControlFlowImageIndex(PackageHelper.PackageCreationName);
+ TreeNode packageNode = new TreeNode(package.Name, imageIndex, imageIndex);
+ packageNode.Tag = package;
+ AddRootNode(packageNode);
+
+ ProcessObject(package, packageNode);
+ }
+ else
+ {
+ ProcessObject(package, null);
+ }
+
// Reset cancel pending in case we have cancelled, as about to exit, so no longer pending
this.CancellationPending = false;
}
- private void ProcessObject(object component, string path)
+ delegate void AddRootNodeCallback(TreeNode node);
+
+ private void AddRootNode(TreeNode node)
+ {
+ if (node == null)
+ throw new ArgumentNullException("node");
+
+ if (this.treeView.InvokeRequired)
+ {
+ AddRootNodeCallback callback = new AddRootNodeCallback(AddRootNode);
+ this.treeView.Invoke(callback, new object[] { node });
+ }
+ else
+ {
+ this.treeView.Nodes.Add(node);
+ }
+ }
+
+ delegate void AddNodeCallback(TreeNode treeView, TreeNode node);
+
+ private TreeNode AddNode(TreeNode parentNode, string text, int imageIndex, object tag)
+ {
+ return AddNode(parentNode, text, imageIndex, tag, false);
+ }
+
+ private TreeNode AddNode(TreeNode parentNode, string text, int imageIndex, object tag, bool found)
+ {
+ if (parentNode == null)
+ return null;
+
+ TreeNode node = new TreeNode(text, imageIndex, imageIndex);
+ node.Name = text;
+ node.Tag = tag;
+ node.Checked = found;
+
+ AddNodeSafe(parentNode, node);
+
+ return node;
+ }
+
+
+ private void AddNodeSafe(TreeNode parentNode, TreeNode childNode)
+ {
+ if (parentNode == null)
+ return;
+
+ if (childNode == null)
+ return;
+
+ if (treeView.InvokeRequired)
+ {
+ AddNodeCallback callback = new AddNodeCallback(AddNodeSafe);
+ treeView.Invoke(callback, new object[] { parentNode, childNode });
+ }
+ else
+ {
+ parentNode.Nodes.Add(childNode);
+
+ if (childNode.Checked)
+ {
+ TreeNode target = childNode;
+ while (target != null)
+ {
+ target.Expand();
+
+ target = target.Parent;
+ }
+ }
+ }
+ }
+
+ private int GetControlFlowImageIndex(string creationName)
+ {
+ if (treeView == null)
+ return -1;
+
+ int imageIndex = treeView.ImageList.Images.IndexOfKey(creationName);
+ if (imageIndex == -1)
+ {
+ AddImageListItem(creationName, PackageHelper.ControlFlowInfos[creationName].Icon);
+ imageIndex = treeView.ImageList.Images.Count - 1;
+ }
+
+ return imageIndex;
+ }
+
+ private int GetComponentImageIndex(string creationName)
+ {
+ if (treeView == null)
+ return -1;
+
+ int imageIndex = treeView.ImageList.Images.IndexOfKey(creationName);
+ if (imageIndex == -1)
+ {
+ AddImageListItem(creationName, PackageHelper.ComponentInfos[creationName].Icon);
+ imageIndex = treeView.ImageList.Images.Count - 1;
+ }
+
+ return imageIndex;
+ }
+
+ private int GetImageIndex(string iconKey)
+ {
+ if (treeView == null)
+ return -1;
+
+ return treeView.ImageList.Images.IndexOfKey(iconKey);
+ }
+
+ private void SetupImageList()
+ {
+ // Add some standard icons to our image list. Order is fixed, since we have hardcoded index values in GetImageIndex function
+ AddImageListItem(IconKeyFolder, SharedIcons.FolderOpened);
+ AddImageListItem(IconKeyProperties, SharedIcons.AllProperties);
+ AddImageListItem(IconKeyInput, SharedIcons.FolderOpened);
+ AddImageListItem(IconKeyOutput, SharedIcons.FolderOpened);
+ AddImageListItem(IconKeyColumn, SharedIcons.FolderOpened);
+ AddImageListItem(IconKeyPrecedenceConstraint, SharedIcons.PrecedenceConstraint);
+ AddImageListItem(IconKeyVariable, SharedIcons.Variable_properties);
+ AddImageListItem(IconKeyVariableExpression, SharedIcons.VariableExpressionIcon);
+ AddImageListItem(IconKeyProperty, BIDSHelper.Resources.Versioned.Variable);
+ AddImageListItem(IconKeyPropertyExpression, SharedIcons.VariableExpressionIcon);
+ }
+
+ delegate void AddImageListItemCallback(string creationName, Icon image);
+
+ private void AddImageListItem(string creationName, Icon image)
+ {
+ if (image == null)
+ return;
+
+ if (treeView.InvokeRequired)
+ {
+ AddImageListItemCallback callback = new AddImageListItemCallback(AddImageListItem);
+ treeView.Invoke(callback, new object[] { creationName, image });
+ }
+ else
+ {
+ this.treeView.ImageList.Images.Add(creationName, image);
+ }
+ }
+
+ private void ProcessObject(object component, TreeNode parentNode)
{
if (this.CancellationPending)
{
return;
}
- DtsContainer container = component as DtsContainer;
- // Should only get package as we call GetPackage up front. Could make scope like, but need UI indicator that this is happening
Package package = component as Package;
if (package != null)
{
- path = "\\Package";
- CheckConnectionManagers(package, path);
- }
- else if (!(component is DtsEventHandler))
- {
- path = path + "\\" + container.Name;
+ // Package node is created in calling function.
+ CheckConnectionManagers(package, parentNode);
}
- IDTSPropertiesProvider propertiesProvider = component as IDTSPropertiesProvider;
- if (propertiesProvider != null)
+ DtsContainer container = component as DtsContainer;
+ if (container != null)
{
- CheckProperties(propertiesProvider, path);
+ string containerKey = PackageHelper.GetContainerKey(container);
+ TaskHost taskHost = null;
+
+ if (package == null)
+ {
+ int imageIndex = GetControlFlowImageIndex(container.CreationName);
+ parentNode = AddNode(parentNode, container.Name, imageIndex, component);
+ taskHost = container as TaskHost;
+ }
+
+ if (taskHost != null)
+ {
+ CheckTask(taskHost, parentNode);
+ }
+ else if (containerKey == PackageHelper.ForLoopCreationName)
+ {
+ CheckForLoop(container as IDTSPropertiesProvider, parentNode);
+ }
+ else if (containerKey == PackageHelper.ForEachLoopCreationName)
+ {
+ CheckForEachLoop(container as ForEachLoop, parentNode);
+ }
+ else if (containerKey == PackageHelper.SequenceCreationName)
+ {
+ ScanProperties(container as IDTSPropertiesProvider, parentNode);
+ }
+ else
+ {
+ ScanProperties(container as IDTSPropertiesProvider, parentNode);
+ }
+
+ string currentPath = string.Empty;
+ IDTSPackagePath packagePath = component as IDTSPackagePath;
+ if (packagePath != null)
+ {
+ currentPath = packagePath.GetPackagePath();
+ }
+
+ ScanVariables(container.Variables, parentNode, currentPath);
}
EventsProvider eventsProvider = component as EventsProvider;
if (eventsProvider != null)
{
+ TreeNode eventHandlers = AddFolder("EventHandlers", parentNode);
+ int imageIndex = GetControlFlowImageIndex(PackageHelper.EventHandlerCreationName);
+
foreach (DtsEventHandler eventhandler in eventsProvider.EventHandlers)
{
- ProcessObject(eventhandler, path + ".EventHandlers[" + eventhandler.Name + "]");
+ TreeNode node = AddNode(parentNode, eventhandler.Name, imageIndex, eventhandler);
+ ProcessObject(eventhandler, node);
}
}
IDTSSequence sequence = component as IDTSSequence;
if (sequence != null)
{
- ProcessSequence(container, sequence, path);
- ScanPrecedenceConstraints(path, container.ID, sequence.PrecedenceConstraints);
+ ProcessSequence(sequence, parentNode);
+ ScanPrecedenceConstraints(container.ID, sequence.PrecedenceConstraints, parentNode);
}
}
- private void ProcessSequence(DtsContainer container, IDTSSequence sequence, string path)
+ private void ProcessSequence(IDTSSequence sequence, TreeNode parentNode)
{
+ if (sequence == null)
+ return;
+
if (this.CancellationPending)
{
return;
@@ -121,117 +335,72 @@ private void ProcessSequence(DtsContainer container, IDTSSequence sequence, stri
foreach (Executable executable in sequence.Executables)
{
- ProcessObject(executable, path);
+ ProcessObject(executable, parentNode);
}
}
- private void CheckConnectionManagers(Package package, string path)
+ private void CheckConnectionManagers(Package package, TreeNode parentNode)
{
if (this.CancellationPending) return;
+ TreeNode folder = AddFolder("Connections", parentNode);
+
+ int imageIndex = GetControlFlowImageIndex(PackageHelper.ConnectionCreationName);
+
foreach (ConnectionManager connection in package.Connections)
{
DtsContainer container = (DtsContainer)package;
- // TODO; Fix - Cheat and hard code creation name as icon routines cannot get the correct connection icon
-
- VariableFoundEventArgs foundArgument = new VariableFoundEventArgs();
- foundArgument.ContainerID = container.ID;
- foundArgument.ObjectID = connection.ID;
- foundArgument.ObjectType = connection.GetType().Name;
- foundArgument.Type = typeof(ConnectionManager);
- foundArgument.Icon = PackageHelper.ControlFlowInfos[PackageHelper.ConnectionCreationName].Icon;
- foundArgument.ObjectPath = path + ".Connections[" + connection.Name + "].";
- foundArgument.ObjectName = connection.Name;
-
- //private void ScanProperties(string objectPath, Type objectType, string objectTypeName, string containerID, string objectID, string objectName, IDTSPropertiesProvider provider, string containerKey)
- ScanProperties((IDTSPropertiesProvider)connection, foundArgument);
+ TreeNode node = AddNode(folder, connection.Name, imageIndex, connection);
+ ScanProperties((IDTSPropertiesProvider)connection, node);
}
}
- private void CheckProperties(IDTSPropertiesProvider propProvider, string path)
+ private TreeNode AddFolder(string folder, TreeNode parentNode)
{
- if (this.CancellationPending) return;
-
- if (propProvider is DtsContainer)
- {
- DtsContainer container = (DtsContainer)propProvider;
-
- VariableFoundEventArgs foundArgument = new VariableFoundEventArgs();
- foundArgument.ContainerID = container.ID;
- foundArgument.ObjectID = container.ID;
-
- foundArgument.ObjectPath = path;
-
- string containerKey = PackageHelper.GetContainerKey(container);
- foundArgument.Icon = PackageHelper.ControlFlowInfos[containerKey].Icon;
-
- TaskHost taskHost = container as TaskHost;
- if (taskHost != null)
- {
- CheckTask(taskHost, foundArgument);
- }
- else
- {
- foundArgument.ObjectType = container.GetType().Name;
+ if (parentNode == null)
+ return null;
- switch (foundArgument.ObjectType)
- {
- case "ForLoop" :
- CheckForLoop(propProvider, foundArgument);
- break;
- case "ForEachLoop":
- CheckForEachLoop(container as ForEachLoop, foundArgument);
- break;
- default:
- foundArgument.Type = container.GetType();
- ScanProperties(propProvider, foundArgument);
- break;
- }
- }
-
- ScanVariables(container.Variables, foundArgument);
- }
+ int imageIndex = treeView.ImageList.Images.IndexOfKey(IconKeyFolder);
+ return AddNode(parentNode, folder, imageIndex, null);
}
- private void CheckTask(TaskHost taskHost, VariableFoundEventArgs foundArgument)
+ private void CheckTask(TaskHost taskHost, TreeNode parent)
{
- foundArgument.Type = taskHost.InnerObject.GetType();
- string typeName = foundArgument.Type.Name;
+ string typeName = taskHost.InnerObject.GetType().Name;
- // Set type, used in case of expression editor, if we get that far. Correct it later as required too
- foundArgument.Type = taskHost.InnerObject.GetType();
+ // Scan regular task properties and expressions
+ // We may use the TreeView Properties folder in task specific checks, so do this first
+ ScanProperties(taskHost, parent);
-
// Task specific checks, split by native and managed
if (typeName == "__ComObject")
{
+ // Translate creation name via PackageHelper, as that caters for both nice and GUID formats, e.g. For SQL 2012 a dataFLow task can be either "{5918251B-2970-45A4-AB5F-01C3C588FE5A}" or SSIS.Pipeline.3
+ string creatioName = PackageHelper.ControlFlowInfos[taskHost.CreationName].CreationName;
+
// Native code tasks, can't use type name, so use creation name.
// Need to be wary of suffix, SSIS.ExecutePackageTask.3 for 2012, SSIS.ExecutePackageTask.4 for 2014 etc
- if (taskHost.CreationName == string.Format("SSIS.{0}.{1}", ObjectTypeExecutePackageTask, SSISHelpers.CreationNameIndex))
+ if (creatioName == string.Format("SSIS.{0}.{1}", ObjectTypeExecutePackageTask, SSISHelpers.CreationNameIndex))
{
- foundArgument.Type = typeof(ExecutePackageTask);
- foundArgument.ObjectType = ObjectTypeExecutePackageTask;
- CheckExecutePackageTask(taskHost, foundArgument);
+ //foundArgument.Type = typeof(ExecutePackageTask);
+ //foundArgument.ObjectType = ObjectTypeExecutePackageTask;
+ CheckExecutePackageTask(taskHost, parent);
}
- else if (taskHost.CreationName == string.Format("SSIS.Pipeline.{0}", SSISHelpers.CreationNameIndex))
+ else if (creatioName == string.Format("SSIS.Pipeline.{0}", SSISHelpers.CreationNameIndex))
{
- foundArgument.ObjectType = ObjectTypeDataFlowTask;
- foundArgument.Type = typeof(MainPipe);
+ //foundArgument.ObjectType = ObjectTypeDataFlowTask;
+ //foundArgument.Type = typeof(MainPipe);
//foundArgument.Icon = BIDSHelper.Resources.Versioned.DataFlow;
MainPipe pipeline = taskHost.InnerObject as MainPipe;
- ScanPipeline(pipeline, foundArgument);
+ ScanPipeline(pipeline, parent);
}
else
{
- foundArgument.ObjectType = "**UnknownNativeTask**";
System.Diagnostics.Debug.Assert(false, "Unrecognised native task - " + taskHost.CreationName);
}
}
else
{
- // Set type name, as it is correct for managed tasks
- foundArgument.ObjectType = typeName;
-
// For managed code tasks we can use type name. This means we don't have to have a
// full reference to the task assembly, but any properties we access must be simple
// ones accessible via IDTSPropertiesProvider, i.e. ExpressionTask. For more complex
@@ -239,19 +408,16 @@ private void CheckTask(TaskHost taskHost, VariableFoundEventArgs foundArgument)
switch (typeName)
{
case "ExecuteSQLTask":
- CheckExecuteSQLTask(taskHost, foundArgument);
+ CheckExecuteSQLTask(taskHost, parent);
break;
case "ExpressionTask":
- CheckExpressionTask(taskHost, foundArgument);
+ CheckExpressionTask(taskHost, parent);
break;
case "ExecutePackageTask":
- CheckExecutePackageTask(taskHost, foundArgument);
+ CheckExecutePackageTask(taskHost, parent);
break;
}
}
-
- // Scan regular task properties and epressions
- ScanProperties(taskHost, foundArgument);
}
private static bool GetIsFriendlyExpression(IDTSCustomPropertyCollection100 properties)
@@ -280,58 +446,61 @@ private static bool GetIsFriendlyExpression(IDTSCustomPropertyCollection100 prop
return false;
}
- private void ScanPipeline(MainPipe pipeline, VariableFoundEventArgs foundArgument)
+ private void ScanPipeline(MainPipe pipeline, TreeNode parent)
{
+ TreeNode folder = AddFolder("Components", parent);
+
// Careful if trying to use //Parallel.ForEach(pipeline.ComponentMetaDataCollection.OfType(), componentMetadata =>
- // Causes issues with twp threads using the same common foundArgument. Need to clone it first.
- foreach (IDTSComponentMetaData100 componentMetadata in pipeline.ComponentMetaDataCollection)
+ // Causes issues with two threads using the same common foundArgument. Need to clone it first.
+ foreach (IDTSComponentMetaData100 componentMetaData in pipeline.ComponentMetaDataCollection)
{
- foundArgument.ObjectID = componentMetadata.ID.ToString();
- foundArgument.ObjectName = componentMetadata.Name;
- string componentPath = foundArgument.ObjectPath + "\\" + componentMetadata.Name;
- string componentKey = PackageHelper.GetComponentKey(componentMetadata);
- foundArgument.ObjectType = PackageHelper.ComponentInfos[componentKey].Name;
+ string componentKey = PackageHelper.GetComponentKey(componentMetaData);
+ int imageIndex = GetComponentImageIndex(componentKey);
+ TreeNode componentNode = AddNode(folder, componentMetaData.Name, imageIndex, componentMetaData); ;
- ScanCustomPropertiesCollection(componentMetadata.CustomPropertyCollection, foundArgument, componentPath);// containerId, objectId, objectName, componentPath, objectType);
+ ScanCustomPropertiesCollection(componentMetaData.CustomPropertyCollection, componentNode);
#region Inputs, Outputs, Columns
// Scan inputs and input columns
- foreach (IDTSInput100 input in componentMetadata.InputCollection)
+ foreach (IDTSInput100 input in componentMetaData.InputCollection)
{
- string localPath = componentPath + ".Input[" + input.Name + "]";
- ScanCustomPropertiesCollection(input.CustomPropertyCollection, foundArgument, localPath);
+ TreeNode node = AddNode(componentNode, "Input [" + input.Name + "]", GetImageIndex(IconKeyInput), input);
+ ScanCustomPropertiesCollection(input.CustomPropertyCollection, node);
+ TreeNode columnsNode = AddFolder("Output Columns", node);
foreach (IDTSInputColumn100 column in input.InputColumnCollection)
{
- string columnPath = localPath + ".Columns[" + column.Name + "]";
- ScanCustomPropertiesCollection(column.CustomPropertyCollection, foundArgument, localPath);
+ TreeNode columnNode = AddNode(columnsNode, column.Name, GetImageIndex(IconKeyColumn), column);
+ ScanCustomPropertiesCollection(column.CustomPropertyCollection, columnNode);
}
}
// Scan outputs and output columns
- foreach (IDTSOutput100 output in componentMetadata.OutputCollection)
+ foreach (IDTSOutput100 output in componentMetaData.OutputCollection)
{
- string localPath = componentPath + ".Output[" + output.Name + "]";
- ScanCustomPropertiesCollection(output.CustomPropertyCollection, foundArgument, localPath);
+ TreeNode node = AddNode(componentNode, "Output [" + output.Name + "]", GetImageIndex(IconKeyOutput), output);
+ ScanCustomPropertiesCollection(output.CustomPropertyCollection, componentNode);
+ TreeNode columnsNode = AddFolder("Output Columns", node);
foreach (IDTSOutputColumn100 column in output.OutputColumnCollection)
{
- string columnPath = localPath + ".Columns[" + column.Name + "]";
- ScanCustomPropertiesCollection(column.CustomPropertyCollection, foundArgument, localPath);
+ TreeNode columnNode = AddNode(columnsNode, column.Name, GetImageIndex(IconKeyColumn), column);
+ ScanCustomPropertiesCollection(column.CustomPropertyCollection, columnNode);
}
}
#endregion
- #region Derived Column Transformation
+ // Derived Column Transformation
if (componentKey == "{18E9A11B-7393-47C5-9D47-687BE04A6B09}")
{
// Component specific logic - TBC
+ // Most seems to be covered by columns, as that is where the expressions are stored.
}
- #endregion
+
}
}
- private void ScanCustomPropertiesCollection(IDTSCustomPropertyCollection100 properties, VariableFoundEventArgs foundArgument, string componentPath)
+ private void ScanCustomPropertiesCollection(IDTSCustomPropertyCollection100 properties, TreeNode parent)
{
// string containerId, string objectId, string objectName, string path, string objectType
// First check if we have a "FriendlyExpression". We use the value from FriendlyExpression, because it is CPET_NOTIFY
@@ -359,14 +528,10 @@ private void ScanCustomPropertiesCollection(IDTSCustomPropertyCollection100 prop
propertyName = "Expression";
}
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = componentPath + ".Properties[" + propertyName + "]";
- info.PropertyName = propertyName;
- info.Value = value;
- info.IsExpression = true;
- info.Icon = BIDSHelper.Resources.Versioned.DataFlow;
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
info.Match = match;
OnRaiseVariableFound(info);
+ AddNode(parent, propertyName, GetImageIndex(IconKeyPropertyExpression), new PropertyExpression(propertyName, value, property.Value.GetType()), true);
}
}
else
@@ -376,28 +541,28 @@ private void ScanCustomPropertiesCollection(IDTSCustomPropertyCollection100 prop
continue;
}
- string pathOverride;
- if (propertyName.StartsWith("["))
- {
- pathOverride = componentPath + ".Properties" + propertyName + "";
- }
- else
+
+ if (PropertyMatch(propertyName, value, out match))
{
- pathOverride = componentPath + ".Properties[" + propertyName + "]";
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
+ info.Match = match;
+ OnRaiseVariableFound(info);
+ // new PropertyInfo(
+ AddNode(parent, propertyName, GetImageIndex(IconKeyProperty), property, true);
}
-
- PropertyMatch(foundArgument, pathOverride, propertyName, value);
}
}
}
- private void ScanPrecedenceConstraints(string objectPath, string containerID, PrecedenceConstraints constraints)
+ private void ScanPrecedenceConstraints(string containerID, PrecedenceConstraints constraints, TreeNode parent)
{
if (this.CancellationPending)
{
return;
}
+ TreeNode constraintsNode = AddFolder("PrecedenceConstraints", parent);
+
foreach (PrecedenceConstraint constraint in constraints)
{
// Check properties
@@ -419,29 +584,24 @@ private void ScanPrecedenceConstraints(string objectPath, string containerID, Pr
if (ExpressionMatch(constraint.Expression, out match))
{
VariableFoundEventArgs info = new VariableFoundEventArgs();
- info.ContainerID = containerID;
- info.ObjectID = constraint.ID;
- info.ObjectName = ((DtsContainer)constraint.PrecedenceExecutable).Name;
- info.ObjectPath = objectPath + ".PrecedenceConstraints[" + constraint.Name + "]";
- info.Type = typeof(PrecedenceConstraint);
- info.ObjectType = constraint.GetType().Name;
- info.PropertyName = constraint.Name;
- info.Value = constraint.Expression;
- info.IsExpression = true;
- info.Icon = BIDSHelper.Resources.Common.Path;
info.Match = match;
OnRaiseVariableFound(info);
+ AddNode(constraintsNode, "Expression", GetImageIndex(IconKeyPrecedenceConstraint), constraint, true);
+ //AddNode(constraintsNode, "Expression", GetImageIndex(IconKeyPrecedenceConstraint), new PropertyExpression(propertyName, expression, PackageHelper.GetTypeFromTypeCode(property.Type)), true);
}
}
}
- private void ScanVariables(Variables variables, VariableFoundEventArgs foundArgument)
+ private void ScanVariables(Variables variables, TreeNode parent, string currentPath)
{
if (this.CancellationPending)
{
return;
}
+ TreeNode variablesFolder = AddFolder("Variables", parent);
+ int imageIndex = GetImageIndex(IconKeyVariableExpression);
+
foreach (Variable variable in variables)
{
try
@@ -453,7 +613,7 @@ private void ScanVariables(Variables variables, VariableFoundEventArgs foundArgu
// Check path to ensure variable is parented by current scope
// only, not by child containers that inherit the variable
- if (!variable.GetPackagePath().StartsWith(foundArgument.ObjectPath + ".Variables["))
+ if (!variable.GetPackagePath().StartsWith(currentPath + ".Variables["))
{
continue;
}
@@ -461,30 +621,35 @@ private void ScanVariables(Variables variables, VariableFoundEventArgs foundArgu
string match;
if (ExpressionMatch(variable.Expression, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectID = variable.ID;
- info.ObjectPath = foundArgument.ObjectPath + ".Variables[" + variable.QualifiedName + "]";
- info.ObjectType = variable.GetType().Name;
- info.PropertyName = variable.QualifiedName;
- info.Value = variable.Expression;
- info.IsExpression = variable.EvaluateAsExpression;
- info.Icon = BIDSHelper.Resources.Versioned.Variable;
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
+ //info.ObjectID = variable.ID;
+ //info.ObjectPath = foundArgument.ObjectPath + ".Variables[" + variable.QualifiedName + "]";
+ //info.ObjectType = variable.GetType().Name;
+ //info.PropertyName = variable.QualifiedName;
+ //info.Value = variable.Expression;
+ //info.IsExpression = variable.EvaluateAsExpression;
+ //info.Icon = BIDSHelper.Resources.Versioned.Variable;
info.Match = match;
OnRaiseVariableFound(info);
+ AddNode(variablesFolder, variable.QualifiedName, imageIndex, variable, true);
+ //AddNode(expressions, "Expression", GetImageIndex(IconKeyProperti1es), new PropertyExpression(propertyName, expression, PackageHelper.GetTypeFromTypeCode(property.Type)), true);
}
}
catch { }
}
}
- private void ScanProperties(IDTSPropertiesProvider provider, VariableFoundEventArgs foundArgument)
+ private void ScanProperties(IDTSPropertiesProvider provider, TreeNode parent)
{
if (this.CancellationPending)
{
return;
}
- bool isPipeline = (foundArgument.ObjectType == ObjectTypeDataFlowTask);
+ TreeNode properties = AddFolder("Properties", parent);
+ TreeNode expressions = AddFolder("PropertyExpressions", parent);
+
+ //bool isPipeline = (foundArgument.ObjectType == ObjectTypeDataFlowTask);
// New 2012 + interface implemented by Package, Sequence, DtsEventHandler, ForLoop, ForEachLoop
// There are other objects that implement IDTSPropertiesProvider, and therefore support expressions, e.g. ConnectionManager, Variable
@@ -499,7 +664,7 @@ private void ScanProperties(IDTSPropertiesProvider provider, VariableFoundEventA
foreach (DtsProperty property in provider.Properties)
{
// Skip any expressuon properties on the Data Flow task, we deal with then in ScanPipeline explicitly
- if (isPipeline && property.Name.StartsWith("["))
+ if (property.Name.StartsWith("["))
{
continue;
}
@@ -514,33 +679,18 @@ private void ScanProperties(IDTSPropertiesProvider provider, VariableFoundEventA
string value = property.GetValue(provider) as string;
if (!string.IsNullOrEmpty(value))
{
-
- string pathOverride;
- if (property.Name.StartsWith("["))
+ if (PropertyMatch(propertyName, value, out match))
{
- pathOverride = foundArgument.ObjectPath + ".Properties" + property.Name + "";
+ VariableFoundEventArgs foundArgument = new VariableFoundEventArgs();
+ foundArgument.Match = match;
+ OnRaiseVariableFound(foundArgument);
+ AddNode(properties, propertyName, GetImageIndex(IconKeyProperty), new PropertyInfo(property, value), true);
}
- else
- {
- pathOverride = foundArgument.ObjectPath + ".Properties[" + property.Name + "]";
- }
-
- PropertyMatch(foundArgument, pathOverride, propertyName, value);
}
}
#endregion
#region Check property expression
- // Check expression
-
- // TODO can we use IDTSPropertiesProviderEx.HasExpressions Property
- //
-
- //if (!hasExpressions)
- //{
- // continue;
- //}
-
string expression = provider.GetExpression(property.Name);
if (expression == null)
{
@@ -552,21 +702,10 @@ private void ScanProperties(IDTSPropertiesProvider provider, VariableFoundEventA
if (ExpressionMatch(expression, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- if (property.Name.StartsWith("["))
- {
- info.ObjectPath = foundArgument.ObjectPath + ".PropertyExpression" + property.Name + "";
- }
- else
- {
- info.ObjectPath = foundArgument.ObjectPath + ".PropertyExpression[" + property.Name + "]";
- }
-
- info.PropertyName = property.Name;
- info.Value = expression;
- info.IsExpression = true;
- info.Match = match;
- OnRaiseVariableFound(info);
+ VariableFoundEventArgs foundArgument = new VariableFoundEventArgs();
+ foundArgument.Match = match;
+ OnRaiseVariableFound(foundArgument);
+ AddNode(expressions, "Expression", GetImageIndex(IconKeyVariableExpression), new PropertyExpression(propertyName, expression, PackageHelper.GetTypeFromTypeCode(property.Type)), true);
}
#endregion
@@ -589,42 +728,32 @@ private bool ExpressionMatch(string expression, out string match)
return false;
}
- private void PropertyMatch(VariableFoundEventArgs foundArgument, string pathOverride, string propertyName, string value)
+ private bool PropertyMatch(string propertyName, string value, out string match)
{
- string match;
if (propertyName == "ReadOnlyVariables" || propertyName == "ReadWriteVariables")
{
// Comma delimited list of variable names, split and then search
foreach (string item in value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
- if (PropertyMatch(item, out match))
+ if (PropertyMatchEval(item, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = pathOverride;
- info.PropertyName = propertyName;
- info.Value = value;
- info.IsExpression = false;
- info.Match = match;
- OnRaiseVariableFound(info);
+ return true;
}
}
}
else
{
- if (PropertyMatch(value, out match))
+ if (PropertyMatchEval(value, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = pathOverride;
- info.PropertyName = propertyName;
- info.Value = value;
- info.IsExpression = false;
- info.Match = match;
- OnRaiseVariableFound(info);
+ return true;
}
}
+
+ match = null;
+ return false;
}
- private bool PropertyMatch(string value, out string match)
+ private bool PropertyMatchEval(string value, out string match)
{
foreach (string test in this.properytMatches)
{
@@ -653,56 +782,56 @@ protected virtual void OnRaiseVariableFound(VariableFoundEventArgs e)
}
}
- private void CheckExecuteSQLTask(TaskHost taskHost, VariableFoundEventArgs foundArgument)
+ private void CheckExecuteSQLTask(TaskHost taskHost, TreeNode parent)
{
ExecuteSQLTask task = taskHost.InnerObject as ExecuteSQLTask;
+ TreeNode parameterBindings = AddFolder("ParameterBindings", parent);
+
foreach (IDTSParameterBinding binding in task.ParameterBindings)
{
string match;
string value = binding.DtsVariableName;
- if (!string.IsNullOrEmpty(value) && PropertyMatch(value, out match))
+ if (!string.IsNullOrEmpty(value) && PropertyMatchEval(value, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = foundArgument.ObjectPath + ".ParameterBindings[" + binding.ParameterName + "]";
- info.PropertyName = binding.ParameterName.ToString();
- info.Value = value;
- info.IsExpression = false;
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
info.Match = match;
OnRaiseVariableFound(info);
+ AddNode(parameterBindings, binding.ParameterName.ToString(), GetImageIndex(IconKeyProperty), binding, true);
}
}
+ TreeNode resultSetBindings = AddFolder("ResultSetBindings", parent);
+
foreach (IDTSResultBinding binding in task.ResultSetBindings)
{
string match;
string value = binding.DtsVariableName;
- if (!string.IsNullOrEmpty(value) && PropertyMatch(value, out match))
+ if (!string.IsNullOrEmpty(value) && PropertyMatchEval(value, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = foundArgument.ObjectPath + ".ResultSetBindings[" + binding.ResultName + "]";
- info.PropertyName = binding.ResultName.ToString();
- info.Value = value;
- info.IsExpression = false;
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
info.Match = match;
OnRaiseVariableFound(info);
+ AddNode(resultSetBindings, binding.ResultName.ToString(), GetImageIndex(IconKeyProperty), binding, true);
}
}
}
- private void CheckExpressionTask(TaskHost taskHost, VariableFoundEventArgs foundArgument)
+ private void CheckExpressionTask(TaskHost taskHost, TreeNode parent)
{
// Expression task has the Expression property which we need to treat as an expression rather than a literal value as we do for normal properties.
// Get the Expression value and run an expression matct test
DtsProperty property = taskHost.Properties["Expression"];
string expression = property.GetValue(taskHost).ToString();
- PropertyAsExpressionMatch(property.Name, expression, foundArgument);
+ PropertyAsExpressionMatch(property, expression, parent);
}
- private void CheckExecutePackageTask(TaskHost taskHost, VariableFoundEventArgs foundArgument)
+ private void CheckExecutePackageTask(TaskHost taskHost, TreeNode parent)
{
ExecutePackageTask task = taskHost.InnerObject as ExecutePackageTask;
+ TreeNode parameterAssignments = AddFolder("ParameterAssignments", parent);
+
// ParameterAssignments doesn't support foreach enumeration, so use for loop instead.
for (int i = 0; i < task.ParameterAssignments.Count; i++)
{
@@ -710,83 +839,78 @@ private void CheckExecutePackageTask(TaskHost taskHost, VariableFoundEventArgs f
string match;
string value = assignment.BindedVariableOrParameterName;
- if (!string.IsNullOrEmpty(value) && PropertyMatch(value, out match))
+ if (!string.IsNullOrEmpty(value) && PropertyMatchEval(value, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = foundArgument.ObjectPath + ".ParameterAssignments[" + assignment.ParameterName + "]";
- info.PropertyName = assignment.ParameterName.ToString();
- info.Value = value;
- info.IsExpression = false;
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
info.Match = match;
OnRaiseVariableFound(info);
+ AddNode(parameterAssignments, assignment.ParameterName.ToString(), GetImageIndex(IconKeyProperty), assignment, true);
}
}
}
- private void CheckForEachLoop(ForEachLoop forEachLoop, VariableFoundEventArgs foundArgument)
+ private void CheckForEachLoop(ForEachLoop forEachLoop, TreeNode parent)
{
// Check properties of loop itself
- foundArgument.Type = typeof(ForEachLoop);
- ScanProperties(forEachLoop, foundArgument);
+ //foundArgument.Type = typeof(ForEachLoop);
+ ScanProperties(forEachLoop, parent);
// Check properties of enumerator, when present
ForEachEnumeratorHost enumerator = forEachLoop.ForEachEnumerator;
if (enumerator == null)
return;
- VariableFoundEventArgs foundEnumerator = new VariableFoundEventArgs(foundArgument);
- foundEnumerator.ObjectPath = foundArgument.ObjectPath + "\\" + foundEnumerator.Type.Name + ".";
- foundEnumerator.Type = enumerator.GetType();
- ScanProperties(enumerator, foundEnumerator);
+ TreeNode enumeratorFolder = AddFolder(enumerator.GetType().Name, parent);
+ ScanProperties(enumerator, enumeratorFolder);
+ TreeNode variableMappings = AddFolder("VariableMappings", parent);
foreach (ForEachVariableMapping mapping in forEachLoop.VariableMappings)
{
string match;
string value = mapping.VariableName;
- if (!string.IsNullOrEmpty(value) && PropertyMatch(value, out match))
+ if (!string.IsNullOrEmpty(value) && PropertyMatchEval(value, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = foundArgument.ObjectPath + ".VariableMappings[" + mapping.ValueIndex.ToString() + "]";
- info.PropertyName = mapping.ValueIndex.ToString();
- info.Value = value;
- info.IsExpression = false;
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
info.Match = match;
OnRaiseVariableFound(info);
+ AddNode(variableMappings, mapping.ValueIndex.ToString(), GetImageIndex(IconKeyProperty), mapping, true);
}
}
}
- private void CheckForLoop(IDTSPropertiesProvider forLoop, VariableFoundEventArgs foundArgument)
+ private void CheckForLoop(IDTSPropertiesProvider forLoop, TreeNode parent)
{
// Check regular properties of the loop for variables and regular property expressions
- foundArgument.Type = typeof(ForEachLoop);
- ScanProperties(forLoop, foundArgument);
+ ScanProperties(forLoop, parent);
// Check explicit expression properties as expressions, missed if we are looking for literal variables.
DtsProperty property;
property = forLoop.Properties["AssignExpression"];
- PropertyAsExpressionMatch(property.Name, property.GetValue(forLoop).ToString(), foundArgument);
+ PropertyAsExpressionMatch(property, property.GetValue(forLoop).ToString(), parent);
property = forLoop.Properties["EvalExpression"];
- PropertyAsExpressionMatch(property.Name, property.GetValue(forLoop).ToString(), foundArgument);
+ PropertyAsExpressionMatch(property, property.GetValue(forLoop).ToString(), parent);
property = forLoop.Properties["InitExpression"];
- PropertyAsExpressionMatch(property.Name, property.GetValue(forLoop).ToString(), foundArgument);
+ PropertyAsExpressionMatch(property, property.GetValue(forLoop).ToString(), parent);
}
- private void PropertyAsExpressionMatch(string propertyName, string expression, VariableFoundEventArgs foundArgument)
+ private void PropertyAsExpressionMatch(DtsProperty property, string expression, TreeNode parent)
{
string match;
if (ExpressionMatch(expression, out match))
{
- VariableFoundEventArgs info = new VariableFoundEventArgs(foundArgument);
- info.ObjectPath = foundArgument.ObjectPath + ".Properties[" + propertyName + "]";
- info.PropertyName = propertyName;
- info.Value = expression;
- info.IsExpression = true;
+ VariableFoundEventArgs info = new VariableFoundEventArgs();
info.Match = match;
OnRaiseVariableFound(info);
+
+ if (parent != null)
+ {
+ TreeNode propertiesNode = parent.Nodes["Properties"];
+ System.Diagnostics.Debug.Assert(!(parent != null && propertiesNode == null), "Properties node doesn't exist when it should already. We will lose this property match. Find the Properties node.");
+ AddNode(propertiesNode, property.Name, GetImageIndex(IconKeyVariableExpression), new PropertyInfo(property, expression), true);
+ }
}
}
}
@@ -800,29 +924,69 @@ public VariableFoundEventArgs()
public VariableFoundEventArgs(VariableFoundEventArgs variableFoundEventArgs)
{
- this.Icon = variableFoundEventArgs.Icon;
- this.Type = variableFoundEventArgs.Type;
- this.IsExpression = variableFoundEventArgs.IsExpression;
- this.ContainerID = variableFoundEventArgs.ContainerID;
+ //this.Icon = variableFoundEventArgs.Icon;
+ //this.Type = variableFoundEventArgs.Type;
+ //this.IsExpression = variableFoundEventArgs.IsExpression;
+ //this.ContainerID = variableFoundEventArgs.ContainerID;
this.Match = variableFoundEventArgs.Match;
- this.ObjectID = variableFoundEventArgs.ObjectID;
- this.ObjectName = variableFoundEventArgs.ObjectName;
- this.ObjectPath = variableFoundEventArgs.ObjectPath;
- this.ObjectType = variableFoundEventArgs.ObjectType;
- this.PropertyName = variableFoundEventArgs.PropertyName;
- this.Value = variableFoundEventArgs.Value;
- }
-
- public Icon Icon { get; set; }
- public Type Type { get; set; }
- public bool IsExpression { get; set; }
- public string ContainerID { get; set; }
+ //this.ObjectID = variableFoundEventArgs.ObjectID;
+ //this.ObjectName = variableFoundEventArgs.ObjectName;
+ //this.ObjectPath = variableFoundEventArgs.ObjectPath;
+ //this.ObjectType = variableFoundEventArgs.ObjectType;
+ //this.PropertyName = variableFoundEventArgs.PropertyName;
+ //this.Value = variableFoundEventArgs.Value;
+ }
+
public string Match { get; set; }
- public string ObjectID { get; set; }
- public string ObjectName { get; set; }
- public string ObjectPath { get; set; }
- public string ObjectType { get; set; }
- public string PropertyName { get; set; }
- public string Value { get; set; }
+ }
+
+ public class PropertyExpression
+ {
+ public PropertyExpression(string name, string expression, Type type)
+ {
+ this.PropertyName = name;
+ this.Expression = expression;
+ this.Type = type;
+ }
+
+ [ParenthesizePropertyName(), Browsable(true), Category("General")]
+ public string PropertyName { get; private set; }
+
+ [Category("General")]
+ public object Expression { get; private set; }
+
+ [Category("General")]
+ public Type Type { get; private set; }
+ }
+
+ [DisplayName("Property")]
+ public class PropertyInfo
+ {
+ // We don't need an IDTSCustomProperty100 version because that already does a good job of displaying both the property information AND the value.
+ // DtsProper doesn't include the value, hence we use thso wrapper for teh TreeView tag object
+
+ public PropertyInfo(DtsProperty property, object value)
+ {
+ this.Name = property.Name;
+ this.Value = value;
+ this.Type = PackageHelper.GetTypeFromTypeCode(property.Type);
+ this.Get = property.Get;
+ this.Set = property.Set;
+ }
+
+ [ParenthesizePropertyName(), Browsable(true), Category("General")]
+ public string Name { get; private set; }
+
+ [Category("General")]
+ public bool Get { get; private set; }
+
+ [Category("General")]
+ public bool Set { get; private set; }
+
+ [Category("General")]
+ public object Value { get; private set; }
+
+ [Category("General")]
+ public Type Type { get; private set; }
}
}
diff --git a/SSIS/PackageHelper.cs b/SSIS/PackageHelper.cs
index 8fb6118..0de0ba4 100644
--- a/SSIS/PackageHelper.cs
+++ b/SSIS/PackageHelper.cs
@@ -4,20 +4,9 @@
using System.Collections.Generic;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime;
-
+ using System.Runtime.InteropServices;
internal class PackageHelper
{
- ///
- /// All managed components in the data flow share the same wrapper, identified by this GUID.
- /// The specific type of managed component is identified by the UserComponentTypeName
- /// custom property of the component.
- ///
- public const string ManagedComponentWrapper = "{33D831DE-5DCF-48F0-B431-4D327B9E785D}";//{bf01d463-7089-41ee-8f05-0a6dc17ce633}";
-
-
- // Script Component ID
- public const string ScriptComponentID = "Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost, Microsoft.SqlServer.TxScript, Version=12.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91";
-
public const string PackageCreationName = "Package";
public const string EventHandlerCreationName = "EventHandler";
public const string ConnectionCreationName = "Connection";
@@ -26,18 +15,55 @@ internal class PackageHelper
public const string ForEachLoopCreationName = "ForEachLoop";
///
- /// Private field for ComponentInfos property
+ /// Private field for the ComponentInfos property
///
private static ComponentInfos componentInfos = new ComponentInfos();
///
- /// Private field for ComponentInfos property
+ /// Private field for the ComponentInfos property
///
private static ComponentInfos controlInfos = new ComponentInfos();
+ ///
+ /// Indicates if the ComponentInfos propertry has been initialied or not, prevents repeating the expensive component search
+ ///
private static bool componentInitialised = false;
+
+ ///
+ /// Object used for locking
+ ///
private static object componentLock = new object();
+ ///
+ /// Private field for the ManagedComponentWrapper property
+ ///
+ private static string managedComponentWrapper;
+
+ ///
+ /// All managed components in the data flow share the same wrapper, identified by this GUID.
+ /// The specific type of managed component is identified by the UserComponentTypeName custom property of the component.
+ ///
+ public static string ManagedComponentWrapper
+ {
+ get
+ {
+ if (managedComponentWrapper == null)
+ {
+ // This value changed unexpectedly
+ // SQL2014 - {33D831DE-5DCF-48F0-B431-4D327B9E785D}
+ // SQL2005 - {BF01D463-7089-41EE-8F05-0A6DC17CE633}
+ // See documentation https://technet.microsoft.com/nl-nl/library/microsoft.sqlserver.dts.pipeline.wrapper.cmanagedcomponentwrapperclass(v=sql.90).aspx
+
+ // To prevent future issues, we will get it from the object itself.
+ GuidAttribute attribute = (GuidAttribute)Attribute.GetCustomAttribute(typeof(CManagedComponentWrapperClass), typeof(GuidAttribute));
+ managedComponentWrapper = attribute.Value;
+ }
+
+ return managedComponentWrapper;
+ }
+ }
+
+
public static List GetControlFlowObjects(DtsContainer container)
{
List returnItems = new List();
@@ -97,6 +123,8 @@ public static ComponentInfos ComponentInfos
}
else
{
+ // Script Component ID
+ ////public const string ScriptComponentID = "Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost, Microsoft.SqlServer.TxScript, Version=12.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91";
////if (pipelineComponentInfo.ID == ScriptComponentID)
////{
//// // For the script component on SQL 2014, PipelineComponentInfo shows an ID of Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost, Microsoft.SqlServer.TxScript, Version=12.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
@@ -145,11 +173,15 @@ public static ComponentInfos ControlFlowInfos
}
// Special containers, see GetCreationName usage
+ // TODO: Consider switching to Microsoft.DataTransformationServices.Design.SharedIcons instead of supplying our own, but is that available in all SQL versions, or just 2014?
controlInfos.Add(PackageCreationName, new ComponentInfo(BIDSHelper.Resources.Common.Package));
controlInfos.Add(EventHandlerCreationName, new ComponentInfo(BIDSHelper.Resources.Versioned.Event));
controlInfos.Add(SequenceCreationName, new ComponentInfo(BIDSHelper.Resources.Versioned.Sequence));
+ controlInfos.Add("STOCK:" + SequenceCreationName.ToUpper(), new ComponentInfo(BIDSHelper.Resources.Versioned.Sequence));
controlInfos.Add(ForLoopCreationName, new ComponentInfo(BIDSHelper.Resources.Versioned.ForLoop));
+ controlInfos.Add("STOCK:" + ForLoopCreationName.ToUpper(), new ComponentInfo(BIDSHelper.Resources.Versioned.ForLoop));
controlInfos.Add(ForEachLoopCreationName, new ComponentInfo(BIDSHelper.Resources.Versioned.ForEachLoop));
+ controlInfos.Add("STOCK:" + ForEachLoopCreationName.ToUpper(), new ComponentInfo(BIDSHelper.Resources.Versioned.ForEachLoop));
// Connections - Cannot get them as with components - Attribute pattern is broken, only used by third
// parties. The Connection toolbox doesn't use it so MS haven't attributed their connections.
diff --git a/SSIS/ParametersWindowPlugin.cs b/SSIS/ParametersWindowPlugin.cs
index d2be799..508a7ef 100644
--- a/SSIS/ParametersWindowPlugin.cs
+++ b/SSIS/ParametersWindowPlugin.cs
@@ -266,7 +266,7 @@ private void FindReferencesButtonClick()
Parameter parameter = GetParameterForRow(selectedRow);
if (parameter == null) return;
- FindReferences dialog = new FindReferences();
+ FindVariableReferences dialog = new FindVariableReferences();
dialog.Show(package, parameter);
}
catch (Exception ex)
diff --git a/SSIS/VariablesMove.Designer.cs b/SSIS/VariablesMove.Designer.cs
index 5dfa2f4..fc976d0 100644
--- a/SSIS/VariablesMove.Designer.cs
+++ b/SSIS/VariablesMove.Designer.cs
@@ -39,20 +39,19 @@ private void InitializeComponent()
//
// treeView
//
- this.treeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
+ this.treeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.treeView.HideSelection = false;
this.treeView.ImageIndex = 0;
this.treeView.ImageList = this.imageList;
+ this.treeView.ItemHeight = 18;
this.treeView.Location = new System.Drawing.Point(13, 36);
this.treeView.Name = "treeView";
this.treeView.SelectedImageIndex = 0;
- this.treeView.Size = new System.Drawing.Size(260, 237);
+ this.treeView.Size = new System.Drawing.Size(300, 237);
this.treeView.TabIndex = 0;
this.treeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView_AfterSelect);
- this.treeView.ItemHeight = 18;
-
//
// imageList
//
@@ -64,7 +63,7 @@ private void InitializeComponent()
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
- this.btnCancel.Location = new System.Drawing.Point(198, 285);
+ this.btnCancel.Location = new System.Drawing.Point(238, 285);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 2;
@@ -75,7 +74,7 @@ private void InitializeComponent()
//
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
- this.btnOK.Location = new System.Drawing.Point(117, 285);
+ this.btnOK.Location = new System.Drawing.Point(157, 285);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23);
this.btnOK.TabIndex = 3;
@@ -110,7 +109,7 @@ private void InitializeComponent()
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
- this.ClientSize = new System.Drawing.Size(285, 320);
+ this.ClientSize = new System.Drawing.Size(325, 320);
this.Controls.Add(this.radCopy);
this.Controls.Add(this.radMove);
this.Controls.Add(this.btnOK);
diff --git a/SSIS/VariablesMove.resx b/SSIS/VariablesMove.resx
index e93f85e..843ba53 100644
--- a/SSIS/VariablesMove.resx
+++ b/SSIS/VariablesMove.resx
@@ -112,12 +112,15 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
17, 17
+
+ 42
+
\ No newline at end of file
diff --git a/SSIS/VariablesWindowPluginPartial.cs b/SSIS/VariablesWindowPluginPartial.cs
index 4917c1f..94b3e0f 100644
--- a/SSIS/VariablesWindowPluginPartial.cs
+++ b/SSIS/VariablesWindowPluginPartial.cs
@@ -34,8 +34,8 @@ private void FindReferencesButtonClick()
if (variable == null) return;
- FindReferences dialog = new FindReferences();
- dialog.EditExpressionSelected += new EventHandler(findReferences_EditExpressionSelected);
+ FindVariableReferences dialog = new FindVariableReferences();
+ //dialog.EditExpressionSelected += new EventHandler(findReferences_EditExpressionSelected);
dialog.Show(package, variable);
}