{"id":18664324,"url":"https://github.com/dzsquared/scriptdom-parse-sample","last_synced_at":"2025-11-06T09:30:34.122Z","repository":{"id":243941495,"uuid":"813847968","full_name":"dzsquared/scriptdom-parse-sample","owner":"dzsquared","description":"Sample SQL script parser to extract a call to sp_executesql from a lump of T-SQL code.","archived":false,"fork":false,"pushed_at":"2024-06-11T21:32:30.000Z","size":10,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-13T09:15:32.077Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dzsquared.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-11T21:30:36.000Z","updated_at":"2024-06-11T21:32:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"65e65305-037a-4c3e-a3dc-a171255a3bae","html_url":"https://github.com/dzsquared/scriptdom-parse-sample","commit_stats":null,"previous_names":["dzsquared/scriptdom-parse-sample"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dzsquared%2Fscriptdom-parse-sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dzsquared%2Fscriptdom-parse-sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dzsquared%2Fscriptdom-parse-sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dzsquared%2Fscriptdom-parse-sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dzsquared","download_url":"https://codeload.github.com/dzsquared/scriptdom-parse-sample/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239491352,"owners_count":19647811,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T08:23:05.529Z","updated_at":"2025-02-18T14:45:40.288Z","avatar_url":"https://github.com/dzsquared.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ScriptDOM sample for handling SQL statements with sp_executesql\n\nThis sample assumes the input is a T-SQL script that uses sp_executesql once to execute a SQL statement. The SQL statement may contain variables that are passed as parameters to sp_executesql.\n\nExample input T-SQL content:\n```sql\ndeclare @p0001 nvarchar(73)\nset @p0001 = N'UPDATE session SET ss_last_used = @LastUsed WHERE ss_sequence = @sequence'\ndeclare @p0002 nvarchar(32)\nset @p0002 = N'@LastUsed datetime,@sequence int'\ndeclare @P0003 datetime set @P0003 = '20240305 15:53:09.093'\ndeclare @P0004 int\nset @P0004 = 9482\n\nexec sp_executesql @p0001, @p0002, @LastUsed = @P0003, @sequence = @P0004\n```\n(line breaks added for readability)\n\nUsing [ScriptDOM](https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.transactsql.scriptdom?view=sql-transactsql-161) we can parse the T-SQL script and extract different versions of the SQL statement executed by sp_executesql.\n\n\u003e [!TIP]\n\u003e ScriptDOM is open source and available on [GitHub](https://github.com/microsoft/sqlscriptdom).\n\n## Option 1: what is the SQL statement passed to sp_executesql?\n\nThis returns a string based on the content of the variable passed as the first parameter to sp_executesql.\n\noption 1 should output:\n    \n```sql\nUPDATE session SET ss_last_used = @LastUsed WHERE ss_sequence = @sequence\n```\n\n## Option 2: what is the SQL statement executed?\n\nThis parses variable substitution such that we get the T-SQL from option 1 after replacing the variables with their values.\n\noption 2 should output:\n\n```sql\nUPDATE session SET ss_last_used = '20240305 15:53:09.093' WHERE ss_sequence = 9482\n```\n\n## Try it yourself\n\n\u003e [!NOTE]\n\u003e The sample code is written in C# and uses the .NET Core SDK. You can download the .NET Core SDK from [here](https://dotnet.microsoft.com/download).\n\nTo run the sample, you can use the following command:\n\n```bash\ndotnet run\n```\n\nTo run the sample without the additional output provided to improve your understanding of the process, you can use the following command:\n\n```bash\ndotnet run -c Release\n```\n\n### Change the code to dynamically accept input\n\nTo change the code to accept input from the command line, you can modify the `Program.cs` file.\n\nReplace these 2 lines:\n```cs\nstring filePath = \"sample.sql\";\nint outputTypeInt = 1;\n```\n\nwith:\n```cs\n//  get file path from user\nConsole.WriteLine(\"Enter SQL file path:\");\nstring? filePath = Console.ReadLine();\nwhile (filePath == null)\n{\n    filePath = Console.ReadLine();\n}\n// get the output type from the user\nConsole.WriteLine(\"Enter output type (1 for initial sp_executesql query, 2 for substituted query):\");\nstring? outputType = Console.ReadLine();\nint outputTypeInt = 0;\nwhile (Int32.TryParse(outputType, out outputTypeInt) == false)\n{\n    outputType = Console.ReadLine();\n}\n```\n\n### What are these visitors?\n\nThe `TSqlFragmentVisitor` is a class that allows you to visit each node in the parsed T-SQL script. The `TSqlFragmentVisitor` class is abstract, so you need to create a class that inherits from it and override the methods you want to use.\n\nIn this sample, we have three visitors:\n- **VariableFinderVisitor**: gives us access to all of the `SetVariableStatement` nodes, eg `SET @P0003 = '20240305 15:53:09.093'`\n- **spExecuteVisitor**: gives us access to all of the `ExecuteStatement` nodes and we filter it to when the procedure called is `sp_executesql`, eg `exec sp_executesql @p0001, @p0002, @LastUsed = @P0003, @sequence = @P0004`\n- **VariableReferenceVisitor**: gives us access to all of the `VariableReference` nodes, eg `@LastUsed` out of `UPDATE session SET ss_last_used = @LastUsed WHERE ss_sequence = @sequence`\n\nWhen we create an instance of a visitor and pass it to the script (as in the `Accept` method), the visitor will traverse the script and call the appropriate method for each node it encounters.\n\n## References\nhttps://www.sqlservercentral.com/steps/stairway-to-scriptdom-level-1-an-introduction-to-scriptdom\nhttps://deep.data.blog/2013/04/04/using-the-transactsql-scriptdom-parser-to-get-statement-counts/\nhttps://devblogs.microsoft.com/azure-sql/programmatically-parsing-transact-sql-t-sql-with-the-scriptdom-parser/\n\n## License\n\nThis sample is available under the MIT license. For more information, see the [LICENSE](LICENSE) file. No support is implied.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdzsquared%2Fscriptdom-parse-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdzsquared%2Fscriptdom-parse-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdzsquared%2Fscriptdom-parse-sample/lists"}