2

When an sql query makes a call to a vba function and that function raises an error, the error handling code fails to handle the error.

See example below. The call to GetId() in the strSql generates an error when the Set rst = db.OpenRecordset(strSql) is executed. This error is not handled by the On Error GoTo Err_Test error handler!

Public Function GetId() As Long
    Err.Raise 11     'Divide by zero error
End Function

Public Function Test() As String

    On Error GoTo Err_Test
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim strSql As String

    Set db = CurrentDb()
    strSql = "Select * FROM MyTable WHERE MyTable.Id = GetId()"
    Set rst = db.OpenRecordset(strSql)
    Test = rst!name

Exit_Test:
    If Not rst Is Nothing Then
        rst.Close
        Set rst = Nothing
    End If
    Set db = Nothing
    Exit Function

Err_Test:
    MsgBox Error$
    Resume Exit_Test
End Function

Why does the error escape the error handler and is there some way to handle it gracefully when the sql makes a call to a vba function that generates an exception?

I know that removing the function call from the sql string as shown below, will enable the error handler to trap the error.

Dim id as Long
id = GetId()
strSql = "Select * FROM MyTable WHERE MyTable.Id = " & id

Is this the only way? If so, should one avoid using function calls in sql query strings to avoid unhandled exceptions?

2
  • 2
    Have you tried adding error handling to your GetId function? Try returning the error. Commented Dec 22, 2015 at 20:17
  • The function in question is a general use function and throws a specific error for handling by a calling procedure. However, when the calling procedure is an sql string or embedded in a query, it escapes the error handling in the calling procedure as outlined. As per Andre's response below, it's probably best to avoid using functions that can throw errors directly in queries. Commented Dec 24, 2015 at 14:22

1 Answer 1

1

My take on the observed behavior is this:

When you run "Select * FROM MyTable WHERE MyTable.Id = GetId()", GetId() is evaluated by the query engine, not by Test(), so the error handler in Test() cannot catch the runtime error. It's the same as if you would put the SQL into a query and run that.

When you do "Select * FROM MyTable WHERE MyTable.Id = " & GetId(), GetId() is evaluated by Test().
This would be the "normal" way to run your example (open a recordset in a VBA function), IMO.

But you can also use VBA functions like GetId() in queries. You only need to make sure that either the function is simple enough that it can't trigger a runtime error, or that the function has its own error handler.

If the function is run only once (in the WHERE clause), a MsgBox is acceptable as error handler. If the function is run for every row (i.e. it's in the SELECT clause), this can make for a truly horrible user experience. :p
So make sure that in this case the function returns an error code or NULL or whatever is applicable, like vacip wrote.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.