【问题标题】:Cannot catch SQL Server SP errors that bypass try..catch in code无法捕获绕过代码中 try..catch 的 SQL Server SP 错误
【发布时间】:2020-05-28 09:26:25
【问题描述】:

我有一个 SQL Server 存储过程。如果我在代码周围放置一个 try 块,它只会捕获某些错误,而只是将一些错误推送到 SSMS 消息窗口。我相信文档 (TryCatch) 说 try..catch 块没有捕获某些错误(例如,从不存在的表中选择)

我的例子是通过同义词选择不存在的列,该同义词将其发送到消息输出窗格:

消息 207,级别 16,状态 1,程序 dbo.TestSP,第 185 行 [批处理开始第 2 行] 列名“InvalidColumn”无效。

但是,我从代码而不是 SSMS 运行 SP,并且没有返回任何错误或异常。

具体来说,我的 Command Execute 方法只是简单地返回而不引发异常,返回值是一个空值,所以我完全不知道记录或报告给用户的错误是什么。我也尝试过完全删除 try 块,结果相同。

我在 VBA 中使用老式 ADODB,但同样的原则也适用于 .Net。我查看了 Command 对象属性,那里似乎没有太多,返回的状态为 0。

有没有办法在我的 Command 或 Connection 对象的某处捕获或找到这些错误,以便我可以记录它们而不是简单地说“未知错误”?

作为一个例子,我的存储过程如下,具有无效列的select语句会引发如上所示的错误并且不会引发错误。

ALTER PROCEDURE [dbo].[TestSP]
AS
BEGIN
 SET NOCOUNT ON;
 BEGIN TRY
    declare @returnCode int;
    If object_id('syn_xxx','SN') is not null drop synonym syn_xxx
    exec('create synonym syn_xxx for sometable')
    SELECT TOP 1 InvalidColumn from syn_xxx
 END TRY
 BEGIN CATCH
     set @returnCode=ERROR_NUMBER()
 END CATCH
 return @returnCode
END     

我的代码是 VBA,如下所示。 Errors 集合不包含任何内容,返回值为空字符串。

Dim conn_ As ADODB.Connection
Dim cmd As New ADODB.Command
Set conn_ = New ADODB.Connection
conn_.Open dsn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "TestSP"
cmd.ActiveConnection = conn_
cmd.Execute

【问题讨论】:

  • 没有人可以调试看不见的代码。发布您的 vba 代码。
  • 不,同样的原则绝对不适用于 .NET。如果连接上出现错误,它将被转换为SqlException,并提供完整的详细信息。如果你的CATCH 没有重新抛出不会发生的错误,但只要在 SSMS 中执行它会给你一个错误(红色,所以不是消息),并且所有其他事情保持不变,所以将它运行为SqlCommand.
  • sql 错误是提供程序错误,应该在连接的错误集合中“记录”:docs.microsoft.com/en-us/sql/ado/reference/ado-api/…
  • @SMor 我已经添加了代码,但正如原始帖子中详述的那样,它有点无关紧要,只是存储过程在选择时失败,但在手动运行时从 TRY...CATCH 中排除(根据 Microsoft 文档),但我找不到任何方法来获取在代码中运行时在 ssms 中显示的内容。错误集合也不包含故障。
  • stackoverflow.com/questions/12816539/… 。 Try catch 将获取运行时异常,而不是编译时异常。我知道您正试图在 VBA 中捕获它们,但更改您的 SQL 可能会有所帮助。

标签: sql-server vba adodb


【解决方案1】:

您在 dsn 中使用什么提供程序?

Private Sub CommandButton1_Click()

    Dim con As New ADODB.Connection
    Dim cmd As New ADODB.Command
    Dim errLoop As ADODB.Error
    Dim i As Integer
    Dim StrTmp As String


    'On Error GoTo AdoError
    On Error Resume Next

    con.ConnectionString = "Provider=SQLNCLI11;" _
             & "Server=(local);" _
             & "Database=master;" _
             & "Integrated Security=SSPI;"

    con.Open

    cmd.ActiveConnection = con
    cmd.CommandType = adCmdStoredProc
    cmd.CommandText = "TestSP"
    cmd.Execute

    MsgBox ("number of errors after procedure 'testproc'  --- " & con.Errors.Count)

    If con.Errors.Count > 0 Then

        i = 1

        ' Process
        StrTmp = StrTmp & vbCrLf & "VB Error # " & Str(Err.Number)
        StrTmp = StrTmp & vbCrLf & "   Generated by " & Err.Source
        StrTmp = StrTmp & vbCrLf & "   Description  " & Err.Description

        ' Enumerate Errors collection and display properties of
        ' each Error object.

        For Each errLoop In con.Errors
            With errLoop
                StrTmp = StrTmp & vbCrLf & "Error #" & i & ":"
                StrTmp = StrTmp & vbCrLf & "   ADO Error   #" & .Number
                StrTmp = StrTmp & vbCrLf & "   Description  " & .Description
                StrTmp = StrTmp & vbCrLf & "   Source       " & .Source
                i = i + 1
            End With
        Next

        MsgBox (StrTmp)

    End If

    cmd.CommandText = "select 10 as test"
    cmd.CommandType = adCmdText
    cmd.Execute
    MsgBox ("number of errors after 'select 10 as test'  --- " & con.Errors.Count)


    ' Close all open objects.
    If con.State = adStateOpen Then
        con.Close
    End If


End Sub

【讨论】:

  • 数据源=服务器;初始目录=db;提供者=SQLOLEDB;集成安全=SSPI;除了我在失败之前添加为 cmets 的任何 RAISERROR 行之外,我没有从 SP 得到任何回报
  • 将连接字符串改为使用oledb后,上面答案中的代码返回:Error #1: ADO Error #-2147217900 Description Invalid column name 'InvalidColumn'. Source Microsoft OLE DB Provider for SQL Server
  • 谢谢,我试试看。
猜你喜欢
  • 1970-01-01
  • 2019-01-12
  • 2023-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-21
  • 1970-01-01
相关资源
最近更新 更多