View Full Version : آموزش: تفسیر و آنالیز سورس SQL با استفاده از Microsoft.SqlServer.TransactSql.ScriptDom
  
mazoolagh
دوشنبه 05 دی 1401, 10: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, 10: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, 11: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, 11:04 صبح
نمونه:
154401
mazoolagh
دوشنبه 05 دی 1401, 11: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, 11:20 صبح
نمونه:
154402
mazoolagh
دوشنبه 05 دی 1401, 11:27 صبح
نمونه خطا:
154403
 
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.