PageRenderTime 87ms CodeModel.GetById 45ms RepoModel.GetById 2ms app.codeStats 1ms

/EFRepository/DependencyAnalyzer2008/SsisEnumerator.cs

#
C# | 1509 lines | 1150 code | 151 blank | 208 comment | 206 complexity | 0ff17fe1a5a83952218c52cc5eeb5274 MD5 | raw file
Possible License(s): CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. ///
  2. /// Microsoft SQL Server 2008 Business Intelligence Metadata Reporting Samples
  3. /// Dependency Analyzer Sample
  4. ///
  5. /// Copyright (c) Microsoft Corporation. All rights reserved.
  6. ///
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Data.OleDb;
  10. using System.Diagnostics;
  11. using System.Text;
  12. using System.Xml;
  13. using Microsoft.SqlServer.Dts.Runtime;
  14. using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
  15. using DTR = Microsoft.SqlServer.Dts.Runtime.Wrapper;
  16. using System.Collections.Specialized;
  17. using TSQLParser;
  18. #if SQL2005
  19. using IDTSComponentMetaData = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSComponentMetaData90;
  20. using IDTSPipeline = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSPipeline90;
  21. using IDTSInput = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSInput90;
  22. using IDTSInputColumn = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSInputColumn90;
  23. using IDTSOutput = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSOutput90;
  24. using IDTSOutputColumn = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSOutputColumn90;
  25. using IDTSRuntimeConnection = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSRuntimeConnection90;
  26. using IDTSPath = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSPath90;
  27. using IDTSCustomProperty = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSCustomProperty90;
  28. #else
  29. using IDTSComponentMetaData = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSComponentMetaData100;
  30. using IDTSPipeline = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSPipeline100;
  31. using IDTSInput = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSInput100;
  32. using IDTSInputColumn = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSInputColumn100;
  33. using IDTSOutput = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSOutput100;
  34. using IDTSOutputColumn = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSOutputColumn100;
  35. using IDTSRuntimeConnection = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSRuntimeConnection100;
  36. using IDTSPath = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSPath100;
  37. using IDTSCustomProperty = Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSCustomProperty100;
  38. #endif
  39. namespace Microsoft.Samples.DependencyAnalyzer
  40. {
  41. /// <summary>
  42. /// Enumerates Integration Services objects and the relationships between them. The result of this enumeration is persisted
  43. /// in a repository.
  44. /// </summary>
  45. class SSISEnumerator
  46. {
  47. // 5 access modes used by ole db adapters
  48. enum AccessMode : int
  49. {
  50. AM_OPENROWSET = 0,
  51. AM_OPENROWSET_VARIABLE = 1,
  52. AM_SQLCOMMAND = 2,
  53. AM_SQLCOMMAND_VARIABLE = 3,
  54. AM_OPENROWSET_FASTLOAD_VARIABLE = 4
  55. }
  56. enum SqlStatementSourceType : int
  57. {
  58. DirectInput = 1,
  59. FileConnection = 2,
  60. Variable = 3
  61. }
  62. private Application app;
  63. private Repository repository;
  64. private const string dtsxPattern = "*.dtsx";
  65. /// <summary>
  66. /// Different component Class IDs that we understand about
  67. /// </summary>
  68. private class ClassIDs
  69. {
  70. #if SQL2005
  71. internal const string OleDbSource = "{2C0A8BE5-1EDC-4353-A0EF-B778599C65A0}";
  72. internal const string ExcelSource = "{B551FCA8-23BD-4719-896F-D8F352A5283C}";
  73. internal const string FlatFileSource = "{90C7770B-DE7C-435E-880E-E718C92C0573}";
  74. internal const string RawFileSource = "{E2568105-9550-4F71-A638-B7FE42E66930}";
  75. internal const string XmlSource = "Microsoft.SqlServer.Dts.Pipeline.XmlSourceAdapter, Microsoft.SqlServer.XmlSrc, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91";
  76. internal const string OleDbDestination = "{E2568105-9550-4F71-A638-B7FE42E66922}";
  77. internal const string SqlDestination = "{5244B484-7C76-4026-9A01-00928EA81550}";
  78. internal const string FlatFileDest = "{A1DF9F6D-8EE4-4EF0-BB2E-D526130D7A7B}";
  79. internal const string RawFileDest = "{E2568105-9550-4F71-A638-B7FE42E66933}";
  80. internal const string Lookup = "{0FB4AABB-C027-4440-809A-1198049BF117}";
  81. internal const string FuzzyLookup = "{9F4EB4D4-AD71-496D-B70B-31ECE1139884}";
  82. internal const string ManagedComponentWrapper = "{bf01d463-7089-41ee-8f05-0a6dc17ce633}";
  83. internal const string DerivedColumn = "{9CF90BF0-5BCC-4C63-B91D-1F322DC12C26}";
  84. internal const string MultipleHash = "Martin.SQLServer.Dts.MultipleHash, MultipleHash2005, Version=1.0.0.0, Culture=neutral, PublicKeyToken=51c551904274ab44";
  85. internal const string KimballSCD = "MouldingAndMillwork.SSIS.KimballMethodSCD, KimballMethodSCD90, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8b0551303405e96c";
  86. internal const string OLEDBCommand = "{C60ACAD1-9BE8-46B3-87DA-70E59EADEA46}";
  87. #else
  88. internal const string OleDbSource = "{BCEFE59B-6819-47F7-A125-63753B33ABB7}";
  89. internal const string ExcelSource = "{A4B1E1C8-17F3-46C8-AAD0-34F0C6FE42DE}";
  90. internal const string FlatFileSource = "{5ACD952A-F16A-41D8-A681-713640837664}";
  91. internal const string RawFileSource = "{51DC0B24-7421-45C3-B4AB-9481A683D91D}";
  92. internal const string XmlSource = "Microsoft.SqlServer.Dts.Pipeline.XmlSourceAdapter, Microsoft.SqlServer.XmlSrc, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91";
  93. internal const string OleDbDestination = "{5A0B62E8-D91D-49F5-94A5-7BE58DE508F0}";
  94. internal const string SqlDestination = "{E4B61516-847B-4BDF-9CC6-1968A2D43E73}";
  95. internal const string FlatFileDest = "{D658C424-8CF0-441C-B3C4-955E183B7FBA}";
  96. internal const string RawFileDest = "{485E7329-8754-42B4-AA5B-29C5DA09CAD5}";
  97. internal const string ExcelDestination = "{C9269E28-EBDE-4DED-91EB-0BF42842F9F4}";
  98. internal const string Lookup = "{27648839-180F-45E6-838D-AFF53DF682D2}";
  99. internal const string FuzzyLookup = "{5056651F-F227-4978-94DF-53CDF9E8CCB6}";
  100. internal const string ManagedComponentWrapper = "{2E42D45B-F83C-400F-8D77-61DDE6A7DF29}";
  101. internal const string DerivedColumn = "{2932025B-AB99-40F6-B5B8-783A73F80E24}";
  102. internal const string MultipleHash = "Martin.SQLServer.Dts.MultipleHash, MultipleHash2008, Version=1.0.0.0, Culture=neutral, PublicKeyToken=51c551904274ab44";
  103. internal const string KimballSCD = "MouldingAndMillwork.SSIS.KimballMethodSCD, KimballMethodSCD100, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8b0551303405e96c";
  104. internal const string OLEDBCommand = "{8E61C8F6-C91D-43B6-97EB-3423C06571CC}";
  105. #endif
  106. }
  107. private const string objectTypePackage = "SSIS Package";
  108. private const string attributePackageLocation = "PackageLocation";
  109. private const string attributePackageID = "PackageGUID";
  110. private OleDbConnectionStringBuilder connectionStringBuilder = new OleDbConnectionStringBuilder();
  111. /// <summary>
  112. /// information about registered pipeline components
  113. /// </summary>
  114. private PipelineComponentInfos pipelineComponentInfos = null;
  115. /// <summary>
  116. /// information about registered connections
  117. /// </summary>
  118. private ConnectionInfos connectionInfos = null;
  119. /// <summary>
  120. /// information about registered tasks
  121. /// </summary>
  122. private TaskInfos taskInfos = null;
  123. private Dictionary<string, string> connectionTypeToIDMap = null;
  124. public SSISEnumerator()
  125. {
  126. }
  127. public bool Initialize(Repository repository)
  128. {
  129. bool success;
  130. try
  131. {
  132. this.repository = repository;
  133. // lets handle the infos enumeration right here.
  134. app = new Application();
  135. EnumerateInfos(app);
  136. success = true;
  137. }
  138. catch (System.Exception ex)
  139. {
  140. Console.WriteLine(string.Format("Could not initialize the SSIS Packages Enumerator: {0}", ex.Message));
  141. success = false;
  142. }
  143. return success;
  144. }
  145. /// <summary>
  146. /// enumerates all packages stored off in SQL Server database
  147. /// </summary>
  148. /// <param name="sqlConnectionString"></param>
  149. public void EnumerateSqlPackages(string server, string user, string pwd, string[] rootFolders)
  150. {
  151. try
  152. {
  153. Queue<string> folders = new Queue<string>();
  154. foreach (string folderName in rootFolders)
  155. {
  156. folders.Enqueue(folderName);
  157. }
  158. if (folders.Count == 0)
  159. {
  160. folders.Enqueue("\\"); // the root folder
  161. }
  162. do
  163. {
  164. string folder = folders.Dequeue();
  165. PackageInfos packageInfos = app.GetPackageInfos(folder, server, user, pwd);
  166. foreach (PackageInfo packageInfo in packageInfos)
  167. {
  168. string location = packageInfo.Folder + "\\" + packageInfo.Name;
  169. if (packageInfo.Flags == DTSPackageInfoFlags.Folder)
  170. {
  171. folders.Enqueue(location);
  172. }
  173. else
  174. {
  175. Debug.Assert(packageInfo.Flags == DTSPackageInfoFlags.Package);
  176. try
  177. {
  178. Console.Write(string.Format("Loading SQL package '{0}'... ", location));
  179. using (Package package = app.LoadFromSqlServer(location, server, user, pwd, null))
  180. {
  181. EnumeratePackage(package, location);
  182. }
  183. Console.WriteLine("Completed Successfully.");
  184. }
  185. catch (System.Exception ex2)
  186. {
  187. Console.WriteLine(string.Format("Error occurred: '{0}'", ex2.Message));
  188. }
  189. }
  190. }
  191. } while (folders.Count > 0);
  192. }
  193. catch (System.Exception ex)
  194. {
  195. Console.WriteLine(string.Format("Error enumerating packages on SQL Server '{0}': {1}", server, ex.Message));
  196. }
  197. }
  198. /// <summary>
  199. /// Enumerates all packages that're in a directory and all sub directories if user asked us to.
  200. /// </summary>
  201. /// <param name="rootFolders"></param>
  202. /// <param name="recurseSubFolders"></param>
  203. public void EnumerateFileSystemPackages(string[] rootFolders, bool recurseSubFolders)
  204. {
  205. foreach (string rootFolder in rootFolders)
  206. {
  207. if (System.IO.Directory.Exists(rootFolder) == false)
  208. {
  209. throw new Exception(string.Format("Root package folder '{0}' doesn't exist.", rootFolder));
  210. }
  211. EnumeratePackages(rootFolder, dtsxPattern, recurseSubFolders);
  212. }
  213. }
  214. private void EnumeratePackages(string rootFolder, string pattern, bool recurseSubFolders)
  215. {
  216. Console.Write("Enumerating packages...");
  217. string[] filesToInspect = System.IO.Directory.GetFiles(rootFolder, pattern, (recurseSubFolders) ? System.IO.SearchOption.AllDirectories : System.IO.SearchOption.TopDirectoryOnly);
  218. Console.WriteLine("done.");
  219. foreach (string packageFileName in filesToInspect)
  220. {
  221. try
  222. {
  223. Console.Write(string.Format("Loading file package '{0}'... ", packageFileName));
  224. // load the package
  225. using (Package package = app.LoadPackage(packageFileName, null))
  226. {
  227. EnumeratePackage(package, packageFileName);
  228. }
  229. Console.WriteLine("Completed Successfully.");
  230. }
  231. catch (System.Exception ex)
  232. {
  233. Console.WriteLine(string.Format("Error occurred: '{0}'", ex.Message));
  234. }
  235. }
  236. }
  237. private void EnumerateInfos(Application app)
  238. {
  239. Console.Write("Enumerating registered SSIS Data Flow components...");
  240. pipelineComponentInfos = app.PipelineComponentInfos;
  241. foreach (PipelineComponentInfo pipelineComponentInfo in pipelineComponentInfos)
  242. {
  243. repository.AddObjectType(Repository.Domains.SSIS, pipelineComponentInfo.ID, pipelineComponentInfo.Name, pipelineComponentInfo.Description);
  244. }
  245. Console.WriteLine("Done");
  246. Console.Write("Enumerating registered SSIS Connection Managers...");
  247. connectionInfos = app.ConnectionInfos;
  248. connectionTypeToIDMap = new Dictionary<string, string>(connectionInfos.Count);
  249. foreach (ConnectionInfo connectionInfo in connectionInfos)
  250. {
  251. connectionTypeToIDMap.Add(connectionInfo.ConnectionType, connectionInfo.ID);
  252. repository.AddObjectType(Repository.Domains.SSIS, connectionInfo.ID, connectionInfo.Name, connectionInfo.Description);
  253. }
  254. Console.WriteLine("Done");
  255. Console.Write("Enumerating registered SSIS Tasks...");
  256. taskInfos = app.TaskInfos;
  257. foreach (TaskInfo taskInfo in taskInfos)
  258. {
  259. repository.AddObjectType(Repository.Domains.SSIS, taskInfo.ID, taskInfo.Name, taskInfo.Description);
  260. }
  261. Console.WriteLine("Done");
  262. }
  263. /// <summary>
  264. /// recurses through all dtsContainers looking for any pipelines...
  265. /// Now handles ForEachLoop, ForLoop and Sequence Containers
  266. /// Disabled Tasks are not tested...
  267. /// </summary>
  268. /// <param name="package">The SSIS Package that is being investigated</param>
  269. /// <param name="location">The text string of the location of this package</param>
  270. /// <param name="packageRepositoryID">The internal ID for this package</param>
  271. /// <param name="dtsContainer">The Container that is to be assessed</param>
  272. private void EnumerateTask(Package package, string location, int packageRepositoryID, DtsContainer dtsContainer)
  273. {
  274. if (!dtsContainer.Disable)
  275. {
  276. if (dtsContainer is TaskHost)
  277. {
  278. TaskHost taskHost = dtsContainer as TaskHost;
  279. IDTSPipeline pipeline = taskHost.InnerObject as IDTSPipeline;
  280. if (pipeline != null)
  281. {
  282. // this is a data flow task
  283. packageRepositoryID = InspectDataFlow(pipeline, packageRepositoryID, package, taskHost, location);
  284. }
  285. else if (dtsContainer.CreationName.Contains("Microsoft.SqlServer.Dts.Tasks.ExecuteSQLTask.ExecuteSQLTask"))
  286. {
  287. EnumerateSqlTask(package, location, packageRepositoryID, taskHost);
  288. }
  289. }
  290. else if (dtsContainer is ForEachLoop)
  291. {
  292. ForEachLoop felContainer = dtsContainer as ForEachLoop;
  293. foreach (DtsContainer innerDtsContainer in felContainer.Executables)
  294. {
  295. EnumerateTask(package, location, packageRepositoryID, innerDtsContainer);
  296. }
  297. }
  298. else if (dtsContainer is ForLoop)
  299. {
  300. ForLoop flContainer = dtsContainer as ForLoop;
  301. foreach (DtsContainer innerDtsContainer in flContainer.Executables)
  302. {
  303. EnumerateTask(package, location, packageRepositoryID, innerDtsContainer);
  304. }
  305. }
  306. else if (dtsContainer is Sequence)
  307. {
  308. Sequence sContainer = dtsContainer as Sequence;
  309. foreach (DtsContainer innerDtsContainer in sContainer.Executables)
  310. {
  311. EnumerateTask(package, location, packageRepositoryID, innerDtsContainer);
  312. }
  313. }
  314. }
  315. }
  316. /// <summary>
  317. /// Handles parsing an SQLTask object, and finding what is used within it.
  318. /// </summary>
  319. /// <param name="package">The SSIS Package that is being investigated</param>
  320. /// <param name="location">The text string of the location of this package</param>
  321. /// <param name="packageRepositoryID">The internal ID for this package</param>
  322. /// <param name="taskHost">The SQL Task that is to be investigated.</param>
  323. private void EnumerateSqlTask(Package package, string location, int packageRepositoryID, TaskHost taskHost)
  324. {
  325. if (packageRepositoryID == -1)
  326. {
  327. // add this package to the repository
  328. packageRepositoryID = AddObject(package.Name, package.Description, objectTypePackage, repository.RootRepositoryObjectID);
  329. repository.AddAttribute(packageRepositoryID, attributePackageLocation, location);
  330. repository.AddAttribute(packageRepositoryID, attributePackageID, package.ID);
  331. }
  332. // Add this task to the repository
  333. int sqlTaskRepositoryObjectID = AddObject(taskHost.Name, taskHost.Description, taskHost.CreationName, packageRepositoryID);
  334. if (taskHost.Properties.Contains("SqlStatementSource") & taskHost.Properties.Contains("SqlStatementSourceType") & taskHost.Properties.Contains("Connection"))
  335. {
  336. string queryDefinition = string.Empty;
  337. SqlStatementSourceType stmtSource = (SqlStatementSourceType)taskHost.Properties["SqlStatementSourceType"].GetValue(taskHost);
  338. switch (stmtSource)
  339. {
  340. case SqlStatementSourceType.DirectInput:
  341. queryDefinition = taskHost.Properties["SqlStatementSource"].GetValue(taskHost).ToString();
  342. repository.AddAttribute(sqlTaskRepositoryObjectID, Repository.Attributes.QueryDefinition, queryDefinition);
  343. break;
  344. case SqlStatementSourceType.FileConnection:
  345. break;
  346. case SqlStatementSourceType.Variable:
  347. queryDefinition = GetVariable(package, taskHost.Properties["SqlStatementSource"].GetValue(taskHost).ToString());
  348. repository.AddAttribute(sqlTaskRepositoryObjectID, Repository.Attributes.QueryDefinition, queryDefinition);
  349. break;
  350. default:
  351. throw new Exception(string.Format("Invalid Sql Statement Source Type {0}.", stmtSource));
  352. }
  353. ConnectionManager connectionManager = package.Connections[taskHost.Properties["Connection"].GetValue(taskHost).ToString()];
  354. string connectionManagerType = connectionManager.CreationName;
  355. int connectionID = repository.GetConnection(connectionManager.ConnectionString);
  356. string serverName = null;
  357. if (connectionID == -1)
  358. {
  359. connectionID = CreateConnection(connectionManager, out serverName);
  360. }
  361. if (!string.IsNullOrEmpty(queryDefinition))
  362. {
  363. try
  364. {
  365. SqlStatement toBeParsed = new SqlStatement();
  366. //toBeParsed.sqlString = statement;
  367. toBeParsed.quotedIdentifiers = true;
  368. if (toBeParsed.ParseString(queryDefinition))
  369. {
  370. foreach (string tableName in toBeParsed.getTableNames(true))
  371. {
  372. int tableID = repository.GetTable(connectionID, tableName);
  373. repository.AddMapping(tableID, sqlTaskRepositoryObjectID);
  374. }
  375. foreach (string procedureName in toBeParsed.getProcedureNames(true))
  376. {
  377. int procID = repository.GetProcedure(connectionID, procedureName);
  378. repository.AddMapping(procID, sqlTaskRepositoryObjectID);
  379. }
  380. foreach (string funcName in toBeParsed.getFunctionNames(true))
  381. {
  382. int funcID = repository.GetFunction(connectionID, funcName);
  383. repository.AddMapping(funcID, sqlTaskRepositoryObjectID);
  384. }
  385. }
  386. else
  387. {
  388. string errorMessage = "The following messages where generated whilst parsing the sql statement\r\n" + queryDefinition + "\r\n";
  389. foreach (string error in toBeParsed.parseErrors)
  390. {
  391. errorMessage += error + "\r\n";
  392. }
  393. Console.WriteLine(errorMessage);
  394. }
  395. }
  396. catch (System.Exception err)
  397. {
  398. Console.WriteLine("The exception \r\n{0}\r\nwas raised against query \r\n{1}\r\nPlease report to http://sqlmetadata.codeplex.com/WorkItem/List.aspx\r\n", err.Message, queryDefinition);
  399. }
  400. }
  401. }
  402. //ExecuteSQLTask sqlTask = taskHost.InnerObject as ExecuteSQLTask;
  403. //string queryDefinition = sqlTask.SqlStatementSource;
  404. //// add the query definition attribute if we have one
  405. //if (queryDefinition != null)
  406. //{
  407. // repository.AddAttribute(sqlTaskRepositoryObjectID, Repository.Attributes.QueryDefinition, queryDefinition);
  408. //}
  409. }
  410. /// <summary>
  411. /// handles loading information about a package to the repository
  412. /// </summary>
  413. /// <param name="package"></param>
  414. private void EnumeratePackage(Package package, string location)
  415. {
  416. // add this package to the repository
  417. int packageRepositoryID = AddObject(package.Name, package.Description, objectTypePackage, repository.RootRepositoryObjectID);
  418. repository.AddAttribute(packageRepositoryID, attributePackageLocation, location);
  419. repository.AddAttribute(packageRepositoryID, attributePackageID, package.ID);
  420. // loop through all data flow tasks
  421. foreach (DtsContainer dtsContainer in package.Executables)
  422. {
  423. EnumerateTask(package, location, packageRepositoryID, dtsContainer);
  424. }
  425. //foreach (Executable executable in package.Executables)
  426. //{
  427. // if (executable is TaskHost)
  428. // {
  429. // if ((executable as TaskHost).InnerObject is ExecuteSQLTask)
  430. // {
  431. // EnumerateSqlTask(package, location, packageRepositoryID, (executable as TaskHost));
  432. // }
  433. // }
  434. //}
  435. }
  436. /// <summary>
  437. /// adds interesting components to the repository. If at least one interesting object exists in the data flow task
  438. /// the data flow task is also added to the repository. If at least one such interesting data flow task exists in the
  439. /// package and the package hasn't been created in the repository as yet, it will be created as well. What's returned
  440. /// is the package repository ID.
  441. /// </summary>
  442. /// <param name="packageRepositoryID"></param>
  443. /// <param name="package"></param>
  444. /// <param name="taskHost"></param>
  445. /// <returns></returns>
  446. private int InspectDataFlow(IDTSPipeline pipeline, int packageRepositoryID, Package package, TaskHost taskHost, string packageLocation)
  447. {
  448. int dataFlowRepositoryObjectID = -1;
  449. Dictionary<int, int> componentIDToSourceRepositoryObjectMap = new Dictionary<int, int>();
  450. Dictionary<int, int> componentIDToRepositoryObjectMap = new Dictionary<int, int>();
  451. // go through all components looking for sources or destinations
  452. foreach (IDTSComponentMetaData component in pipeline.ComponentMetaDataCollection)
  453. {
  454. EnumerateDataFlowComponent(ref packageRepositoryID, package, taskHost, packageLocation, ref dataFlowRepositoryObjectID, ref componentIDToSourceRepositoryObjectMap, ref componentIDToRepositoryObjectMap, component);
  455. }
  456. // after all the objects have been added, traverse their mappings
  457. if (componentIDToSourceRepositoryObjectMap.Count > 0)
  458. {
  459. EnumerateMappings(pipeline, dataFlowRepositoryObjectID, componentIDToSourceRepositoryObjectMap, componentIDToRepositoryObjectMap);
  460. }
  461. return packageRepositoryID;
  462. }
  463. private void EnumerateDataFlowComponent(ref int packageRepositoryID, Package package, TaskHost taskHost, string packageLocation, ref int dataFlowRepositoryObjectID, ref Dictionary<int, int> componentIDToSourceRepositoryObjectMap, ref Dictionary<int, int> componentIDToRepositoryObjectMap, IDTSComponentMetaData component)
  464. {
  465. string objectType;
  466. DTSPipelineComponentType dataFlowComponentType;
  467. string domain, tableOrViewName, queryDefinition;
  468. bool tableOrViewSource;
  469. string kimballPropertyValue;
  470. XmlReaderSettings settings = new XmlReaderSettings();
  471. settings.IgnoreComments = true;
  472. settings.IgnoreProcessingInstructions = true;
  473. settings.IgnoreWhitespace = true;
  474. XmlReader objXMLText;
  475. // if we have a source, note it as the starting point and add it to the repository
  476. if (IsComponentInteresting(package, component, out objectType, out dataFlowComponentType, out domain, out tableOrViewName, out tableOrViewSource, out queryDefinition))
  477. {
  478. // if the data flow object itself hasn't been created as yet, do so now
  479. if (dataFlowRepositoryObjectID == -1)
  480. {
  481. // if the package itself doesn't exist either, create it now
  482. if (packageRepositoryID == -1)
  483. {
  484. // add this package to the repository
  485. packageRepositoryID = AddObject(package.Name, package.Description, objectTypePackage, repository.RootRepositoryObjectID);
  486. repository.AddAttribute(packageRepositoryID, attributePackageLocation, packageLocation);
  487. repository.AddAttribute(packageRepositoryID, attributePackageID, package.ID);
  488. }
  489. dataFlowRepositoryObjectID = AddObject(taskHost.Name, taskHost.Description, taskHost.CreationName, packageRepositoryID);
  490. }
  491. // add the component to the repository
  492. int componentRepositoryID = AddObject(component.Name, component.Description, objectType, dataFlowRepositoryObjectID);
  493. Debug.Assert(componentRepositoryID > 0);
  494. if (dataFlowComponentType == DTSPipelineComponentType.SourceAdapter)
  495. {
  496. componentIDToSourceRepositoryObjectMap.Add(component.ID, componentRepositoryID);
  497. }
  498. componentIDToRepositoryObjectMap.Add(component.ID, componentRepositoryID);
  499. // add the query definition attribute if we have one
  500. if (queryDefinition != null)
  501. {
  502. repository.AddAttribute(componentRepositoryID, Repository.Attributes.QueryDefinition, queryDefinition);
  503. }
  504. if (component.ComponentClassID == ClassIDs.OLEDBCommand)
  505. {
  506. GetStringComponentPropertyValue(component, "SqlCommand");
  507. }
  508. else if (component.ComponentClassID == ClassIDs.DerivedColumn)
  509. {
  510. foreach (IDTSInput localInput in component.InputCollection)
  511. {
  512. if (localInput.IsAttached)
  513. {
  514. foreach (IDTSInputColumn localIColumn in localInput.InputColumnCollection)
  515. {
  516. if (localIColumn.CustomPropertyCollection.Count == 2)
  517. {
  518. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale) + " Expression " + localIColumn.CustomPropertyCollection["FriendlyExpression"].Value.ToString());
  519. }
  520. else
  521. {
  522. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale) + " Expression (See Ouput Column)");
  523. }
  524. //repository.AddObject(localIColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  525. }
  526. }
  527. }
  528. foreach (IDTSOutput localOutput in component.OutputCollection)
  529. {
  530. if (localOutput.IsAttached)
  531. {
  532. foreach (IDTSOutputColumn localOColumn in localOutput.OutputColumnCollection)
  533. {
  534. if (localOColumn.CustomPropertyCollection.Count == 2)
  535. {
  536. repository.AddAttribute(componentRepositoryID, localOutput.Name + " [" + localOColumn.Name + "] [ID: " + localOColumn.ID.ToString() + "]", FormatColumnDescription(localOColumn.Name, localOColumn.DataType, localOColumn.Length, localOColumn.Precision, localOColumn.Scale) + " Expression " + localOColumn.CustomPropertyCollection["FriendlyExpression"].Value.ToString());
  537. }
  538. //repository.AddObject(localOColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  539. //ToDo: Add connection from Input to Output Column.
  540. }
  541. }
  542. }
  543. }
  544. else if (component.ComponentClassID == ClassIDs.Lookup)
  545. {
  546. foreach (IDTSInput localInput in component.InputCollection)
  547. {
  548. if (localInput.IsAttached)
  549. {
  550. foreach (IDTSInputColumn localIColumn in localInput.InputColumnCollection)
  551. {
  552. if (localIColumn.CustomPropertyCollection.Count == 2)
  553. {
  554. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale) + " Reference Column [" + localIColumn.CustomPropertyCollection["JoinToReferenceColumn"].Value.ToString() + "]");
  555. }
  556. else
  557. {
  558. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale) + " Expression (See Ouput Column)");
  559. }
  560. //repository.AddObject(localIColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  561. }
  562. }
  563. }
  564. foreach (IDTSOutput localOutput in component.OutputCollection)
  565. {
  566. if (localOutput.IsAttached)
  567. {
  568. foreach (IDTSOutputColumn localOColumn in localOutput.OutputColumnCollection)
  569. {
  570. if (localOColumn.CustomPropertyCollection.Count == 1)
  571. {
  572. repository.AddAttribute(componentRepositoryID, localOutput.Name + " [" + localOColumn.Name + "] [ID: " + localOColumn.ID.ToString() + "]", FormatColumnDescription(localOColumn.Name, localOColumn.DataType, localOColumn.Length, localOColumn.Precision, localOColumn.Scale) + " Return Column [" + localOColumn.CustomPropertyCollection["CopyFromReferenceColumn"].Value.ToString() + "]");
  573. }
  574. //repository.AddObject(localOColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  575. }
  576. }
  577. }
  578. }
  579. else if (component.ComponentClassID == ClassIDs.FuzzyLookup)
  580. {
  581. foreach (IDTSInput localInput in component.InputCollection)
  582. {
  583. if (localInput.IsAttached)
  584. {
  585. foreach (IDTSInputColumn localIColumn in localInput.InputColumnCollection)
  586. {
  587. if (localIColumn.CustomPropertyCollection.Count == 5)
  588. {
  589. if (localIColumn.CustomPropertyCollection["JoinToReferenceColumn"].Value != null)
  590. {
  591. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale) + " Reference Column [" + localIColumn.CustomPropertyCollection["JoinToReferenceColumn"].Value.ToString() + "]");
  592. }
  593. else
  594. {
  595. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale));
  596. }
  597. }
  598. else
  599. {
  600. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale) + " Expression (See Ouput Column)");
  601. }
  602. //repository.AddObject(localIColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  603. }
  604. }
  605. }
  606. foreach (IDTSOutput localOutput in component.OutputCollection)
  607. {
  608. if (localOutput.IsAttached)
  609. {
  610. foreach (IDTSOutputColumn localOColumn in localOutput.OutputColumnCollection)
  611. {
  612. if (localOColumn.CustomPropertyCollection.Count == 3)
  613. {
  614. if (localOColumn.CustomPropertyCollection["CopyFromReferenceColumn"].Value != null)
  615. {
  616. repository.AddAttribute(componentRepositoryID, localOutput.Name + " [" + localOColumn.Name + "] [ID: " + localOColumn.ID.ToString() + "]", FormatColumnDescription(localOColumn.Name, localOColumn.DataType, localOColumn.Length, localOColumn.Precision, localOColumn.Scale) + " Return Column [" + localOColumn.CustomPropertyCollection["CopyFromReferenceColumn"].Value.ToString() + "]");
  617. }
  618. else
  619. {
  620. repository.AddAttribute(componentRepositoryID, localOutput.Name + " [" + localOColumn.Name + "] [ID: " + localOColumn.ID.ToString() + "]", FormatColumnDescription(localOColumn.Name, localOColumn.DataType, localOColumn.Length, localOColumn.Precision, localOColumn.Scale));
  621. }
  622. }
  623. else
  624. {
  625. repository.AddAttribute(componentRepositoryID, localOutput.Name + " [" + localOColumn.Name + "] [ID: " + localOColumn.ID.ToString() + "]", FormatColumnDescription(localOColumn.Name, localOColumn.DataType, localOColumn.Length, localOColumn.Precision, localOColumn.Scale));
  626. }
  627. //repository.AddObject(localOColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  628. }
  629. }
  630. }
  631. }
  632. else if (component.ComponentClassID == ClassIDs.ManagedComponentWrapper)
  633. {
  634. if (component.CustomPropertyCollection["UserComponentTypeName"].Value.ToString() == ClassIDs.MultipleHash)
  635. {
  636. foreach (IDTSInput localInput in component.InputCollection)
  637. {
  638. if (localInput.IsAttached)
  639. {
  640. foreach (IDTSInputColumn localIColumn in localInput.InputColumnCollection)
  641. {
  642. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale));
  643. //repository.AddObject(localIColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  644. }
  645. }
  646. }
  647. foreach (IDTSOutput localOutput in component.OutputCollection)
  648. {
  649. if (localOutput.IsAttached)
  650. {
  651. foreach (IDTSOutputColumn localOColumn in localOutput.OutputColumnCollection)
  652. {
  653. if (localOColumn.CustomPropertyCollection.Count == 2)
  654. {
  655. string localResults = "";
  656. if (localOColumn.CustomPropertyCollection["InputColumnLineageIDs"].Value.ToString().Length > 0)
  657. {
  658. foreach (string localIDs in localOColumn.CustomPropertyCollection["InputColumnLineageIDs"].Value.ToString().Split(','))
  659. {
  660. string withoutHash = localIDs;
  661. if (localIDs[0] == '#')
  662. {
  663. withoutHash = localIDs.Substring(1);
  664. }
  665. if (localResults.Length == 0)
  666. {
  667. localResults = component.InputCollection[0].InputColumnCollection.GetInputColumnByLineageID(System.Convert.ToInt32(withoutHash)).Name;
  668. }
  669. else
  670. {
  671. localResults += ", " + component.InputCollection[0].InputColumnCollection.GetInputColumnByLineageID(System.Convert.ToInt32(withoutHash)).Name;
  672. }
  673. }
  674. }
  675. repository.AddAttribute(componentRepositoryID, localOutput.Name + " [" + localOColumn.Name + "] [ID: " + localOColumn.ID.ToString() + "]", FormatColumnDescription(localOColumn.Name, localOColumn.DataType, localOColumn.Length, localOColumn.Precision, localOColumn.Scale) + " Generated From " + localResults);
  676. }
  677. //repository.AddObject(localOColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  678. }
  679. }
  680. }
  681. }
  682. else if (component.CustomPropertyCollection["UserComponentTypeName"].Value.ToString() == ClassIDs.KimballSCD)
  683. {
  684. foreach (IDTSInput localInput in component.InputCollection)
  685. {
  686. if (localInput.IsAttached)
  687. {
  688. foreach (IDTSInputColumn localIColumn in localInput.InputColumnCollection)
  689. {
  690. repository.AddAttribute(componentRepositoryID, localInput.Name + " [" + localIColumn.Name + "] [ID: " + localIColumn.ID.ToString() + "]", "From [" + localIColumn.UpstreamComponentName + "] " + FormatColumnDescription(localIColumn.Name, localIColumn.DataType, localIColumn.Length, localIColumn.Precision, localIColumn.Scale));
  691. //repository.AddObject(localIColumn.Name, "", ColumnEnumerator.ObjectTypes.Column, componentRepositoryID);
  692. }
  693. }
  694. }
  695. foreach (IDTSOutput localOutput in component.OutputCollection)
  696. {
  697. if (localOutput.IsAttached)
  698. {
  699. kimballPropertyValue = string.Empty;
  700. switch (localOutput.Name)
  701. {
  702. case "New":
  703. kimballPropertyValue = component.CustomPropertyCollection["New Output Columns"].Value.ToString();
  704. break;
  705. case "Unchanged":
  706. kimballPropertyValue = component.CustomPropertyCollection["Unchanged Output Columns"].Value.ToString();
  707. break;
  708. case "Deleted":
  709. kimballPropertyValue = component.CustomPropertyCollection["Deleted Output Columns"].Value.ToString();
  710. break;
  711. case "Updated SCD1":
  712. kimballPropertyValue = component.CustomPropertyCollection["Update SCD1 Columns"].Value.ToString();
  713. break;
  714. case "Auditing":
  715. kimballPropertyValue = component.CustomPropertyCollection["Audit Columns"].Value.ToString();
  716. break;
  717. case "Expired SCD2":
  718. kimballPropertyValue = component.CustomPropertyCollection["Expired SCD2 Columns"].Value.ToString();
  719. break;
  720. case "Invalid Input":
  721. break;
  722. case "New SCD2":
  723. kimballPropertyValue = component.CustomPropertyCollection["New SCD2 Columns"].Value.ToString();
  724. break;
  725. default:
  726. break;
  727. }
  728. string localResults = "Unknown.";
  729. if (kimballPropertyValue != string.Empty)
  730. {
  731. objXMLText = XmlReader.Create(new System.IO.StringReader(kimballPropertyValue), settings);
  732. objXMLText.Read();
  733. foreach (IDTSOutputColumn localOColumn in localOutput.OutputColumnCollection)
  734. {
  735. string strLineageID;
  736. string strMappedToExistingDimensionLineageID;
  737. objXMLText.ReadToFollowing("OutputColumnDefinition");
  738. do
  739. {
  740. localResults = "Unknown.";
  741. strLineageID = objXMLText.GetAttribute("LineageID");
  742. strMappedToExistingDimensionLineageID = objXMLText.GetAttribute("MappedToExistingDimensionLineageID");
  743. if (localOColumn.LineageID == System.Convert.ToInt32(strLineageID))
  744. {
  745. foreach (IDTSInput localInput in component.InputCollection)
  746. {
  747. IDTSInputColumn temp;
  748. try
  749. {
  750. temp = localInput.InputColumnCollection.GetInputColumnByLineageID(System.Convert.ToInt32(strMappedToExistingDimensionLineageID));
  751. localResults = "[" + localInput.Name + "] Column [" + temp.Name + "].";
  752. break;
  753. }
  754. catch (Exception)
  755. {
  756. }
  757. }
  758. break;
  759. }
  760. }
  761. while (objXMLText.ReadToFollowing("OutputColumnDefinition"));

Large files files are truncated, but you can click here to view the full file