PDA

View Full Version : آموزش: تفسیر و آنالیز سورس SQL با استفاده از Microsoft.SqlServer.TransactSql.ScriptDom



mazoolagh
دوشنبه 05 دی 1401, 09:06 صبح
اول افزودن رفرنس:

154398
154400

کار کردن با این api در نگاه اول قدری پیچیده بنظر میاد (همینجور هم هست)،
دو نمونه زیر به شما کمک میکنه چجوری ازش استفاده کنین و البته که امکاناتش خیلی گسترده تر از اینهاست.

Microsoft.SqlServer.TransactSql.ScriptDom Namespace | Microsoft Learn (https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.transactsql.scriptdom?view=sql-dacfx-160)

mazoolagh
دوشنبه 05 دی 1401, 09:35 صبح
در نمونه اول میخواهیم همه اجزای سورس رو بیرون بکشیم.
طبق مستندات باید چند آبجکت رو آماده کنیم:
یک tsqlparser که سورس رو به صورت stream میگیره،
یک tsqlscript که tsqlparser نتیجه parse رو برای آنالیزهای بعدی در اون برمیگردونه،
و یک parseerror که لیست خطاها (احتمالی) رو نگه میداره.

لیستی از همه اجزای سورس (حتی شامل whitespaceih هم میشه) در یکی از پراپرتی های tsqlscript به اسم ScriptTokenStream در دسترس هست.

TSqlParserToken Class (Microsoft.SqlServer.TransactSql.ScriptDom) | Microsoft Learn (https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.transactsql.scriptdom.tsqlpars ertoken?view=sql-dacfx-preview)

mazoolagh
دوشنبه 05 دی 1401, 10:00 صبح
1- آماده سازی:
Imports Microsoft.SqlServer.TransactSql
Dim dt_tokens As New DataTable
Dim dt_errors As New DataTable

Private Sub SQLscriptDom_ParseScript_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If dt_tokens.Columns.Count > 0 Then Exit Sub
With dt_tokens
.Columns.Add("Line", GetType(System.Int32))
.Columns.Add("Column", GetType(System.Int32))
.Columns.Add("Offset", GetType(System.Int32))
.Columns.Add("Text", GetType(System.String))
.Columns.Add("Type", GetType(System.String))
.Columns.Add("IsKeyword", GetType(System.Boolean))
End With
DGV_ScriptTokens.DataSource = dt_tokens


With dt_errors
.Columns.Add("Error", GetType(System.Int32))
.Columns.Add("Line", GetType(System.Int32))
.Columns.Add("Offset", GetType(System.Int32))
.Columns.Add("Message", GetType(System.String))
End With
DGV_Errors.DataSource = dt_errors
End Sub



2- خواندن سورس و بیرون کشیدن tokenها:
Private Sub Btn_Parse_Click(sender As Object, e As EventArgs) Handles Btn_Parse.Click
dt_script.Clear()
dt_errors.Clear()
Dim parse_errors As IList(Of ScriptDom.ParseError) = Nothing
Dim parser As New ScriptDom.TSql150Parser(True)
Dim script As New ScriptDom.TSqlScript
Using reader As New System.IO.StringReader(SQL_Source.Text)
script = parser.Parse(reader, parse_errors)
End Using

If parse_errors.Count > 0 Then
Dim dr_error As DataRow
For Each perr As ScriptDom.ParseError In parse_errors
dr_error = dt_errors.NewRow
dr_error("Error") = perr.Number
dr_error("Line") = perr.Line
dr_error("Offset") = perr.Offset
dr_error("Message") = "sc=" & perr.Message
dt_errors.Rows.Add(dr_error)
Next
End If


If script Is Nothing Then Exit Sub


Dim dr_script As DataRow
For Each token As ScriptDom.TSqlParserToken In script.ScriptTokenStream
If token.TokenType <> ScriptDom.TSqlTokenType.WhiteSpace Then
dr_script = dt_script.NewRow
dr_script("Line") = token.Line
dr_script("Column") = token.Column
dr_script("Offset") = token.Offset
dr_script("Type") = token.TokenType.ToString
dr_script("Text") = token.Text
dr_script("IsKeyword") = token.IsKeyword
dt_script.Rows.Add(dr_script)
End If
Next
End Sub

mazoolagh
دوشنبه 05 دی 1401, 10:04 صبح
نمونه:
154401

mazoolagh
دوشنبه 05 دی 1401, 10:13 صبح
در نمونه دوم یک لیست از دستورها و نوع اونها میسازیم:
TSqlParser.ParseStatementList Method (Microsoft.SqlServer.TransactSql.ScriptDom) | Microsoft Learn (https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.transactsql.scriptdom.tsqlpars er.parsestatementlist?view=sql-dacfx-preview)

1- آماده سازی
Dim dt_statements As New DataTable
Dim dt_errors As New DataTable


Private Sub SQLscripDom_ParseStatements_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If dt_statements.Columns.Count > 0 Then Exit Sub
With dt_statements
.Columns.Add("Line", GetType(System.Int32))
.Columns.Add("Type", GetType(System.String))
.Columns.Add("Statement", GetType(System.String))
End With
DGV_Statements.DataSource = dt_statements


With dt_errors
.Columns.Add("Error", GetType(System.Int32))
.Columns.Add("Line", GetType(System.Int32))
.Columns.Add("Offset", GetType(System.Int32))
.Columns.Add("Message", GetType(System.String))
End With
DGV_Errors.DataSource = dt_errors
End Sub

2- خواندن سورس و بیرون کشیدن statementها
Private Sub Btn_Parse_Click(sender As Object, e As EventArgs) Handles Btn_Parse.Click
dt_statements.Clear()
dt_errors.Clear()
Dim parse_errors As IList(Of ScriptDom.ParseError) = Nothing
Dim parser As New ScriptDom.TSql150Parser(True)
Dim statements_list As New ScriptDom.StatementList


Using reader As New System.IO.StringReader(SQL_Source.Text)
statements_list = parser.ParseStatementList(reader, parse_errors)
End Using


If parse_errors.Count > 0 Then
Dim dr_error As DataRow
For Each perr As ScriptDom.ParseError In parse_errors
dr_error = dt_errors.NewRow
dr_error("Error") = perr.Number
dr_error("Line") = perr.Line
dr_error("Offset") = perr.Offset
dr_error("Message") = perr.Message
dt_errors.Rows.Add(dr_error)
Next
End If


If statements_list Is Nothing Then Exit Sub


Dim dr_statements As DataRow
For Each statement As ScriptDom.TSqlStatement In statements_list.Statements
dr_statements = dt_statements.NewRow
dr_statements("Line") = dt_statements.Rows.Count + 1
dr_statements("Type") = statement.GetType.Name
Dim sb As New System.Text.StringBuilder
For i As Integer = statement.FirstTokenIndex To statement.LastTokenIndex
sb.Append(statement.ScriptTokenStream(i).Text)
Next
dr_statements("Statement") = sb.ToString
dt_statements.Rows.Add(dr_statements)
Next
End Sub

mazoolagh
دوشنبه 05 دی 1401, 10:20 صبح
نمونه:

154402

mazoolagh
دوشنبه 05 دی 1401, 10:27 صبح
نمونه خطا:
154403