ADO - ADO Data Provider Errors and Native Error Codes

ADO (ActiveX Data Objects) provides a structured way for applications to communicate with databases. During database operations, errors can occur for many reasons, such as an invalid SQL statement, a missing table, insufficient permissions, a network failure, or a constraint violation. ADO exposes these problems through its error-handling mechanisms, allowing applications to identify what went wrong and respond appropriately.

1. What Are ADO Data Provider Errors?

An ADO data provider error is an error reported by the underlying database provider when an operation cannot be completed successfully. ADO acts as an intermediary between the application and the provider. The provider communicates with the actual database system and returns information about errors that occur during operations.

For example, an application might execute:

cn.Execute "SELECT * FROM Employee"

If the Employee table does not exist, the database provider may return an error. ADO makes this error information available to the application through the Errors collection associated with the Connection object.

A provider error can contain information such as:

  • Error description

  • Error number

  • Native database error code

  • SQL state

  • Source of the error

  • Additional details supplied by the database provider

This information is particularly useful when a general ADO error message does not provide enough detail to determine the actual cause.

2. Understanding Native Error Codes

A native error code is a numeric code generated by the underlying database system or provider. It identifies a specific database-related problem.

The important distinction is that an ADO error number and a native error code are not necessarily the same thing.

ADO provides a general error-handling layer, while the native error code comes from the specific provider or database system. Therefore, native error codes can vary depending on the database and provider being used.

For example, a SQL Server provider may return a native error code indicating that a table does not exist, while another database provider may use a completely different code for a similar problem.

This makes native error codes valuable for provider-specific error diagnosis.

3. The ADO Errors Collection

The primary mechanism for examining provider errors in ADO is the Errors collection of the Connection object.

A connection can contain multiple errors after a failed operation. Therefore, checking only one error message may not always provide the complete picture.

A basic example is:

On Error Resume Next

cn.Execute "SELECT * FROM Employee"

If Err.Number <> 0 Then
    Debug.Print Err.Description
End If

Dim e As ADODB.Error

For Each e In cn.Errors
    Debug.Print e.Number
    Debug.Print e.Description
    Debug.Print e.NativeError
    Debug.Print e.Source
Next

Here, cn.Errors contains the provider-specific error information returned by the database provider.

The ADODB.Error object provides several useful properties.

4. Important Error Object Properties

Number

The Number property identifies the ADO error.

Debug.Print e.Number

This represents the error number exposed through ADO. It should not automatically be interpreted as the database's native error number.

Description

The Description property provides a human-readable explanation of the error.

Debug.Print e.Description

For example, it might contain a message explaining that a particular table, column, or database object could not be found.

NativeError

The NativeError property is particularly important when diagnosing provider-level problems.

Debug.Print e.NativeError

It represents the error number supplied by the underlying database provider.

Because the value originates from the provider, its meaning depends on the database technology being used.

Source

The Source property identifies the component that generated the error.

Debug.Print e.Source

This can help determine whether the problem originated in ADO, the provider, or another database component.

SQLState

Some providers also provide an SQL state value that helps categorize database errors according to SQL-related error classifications.

Debug.Print e.SQLState

The availability and usefulness of particular properties can depend on the provider.

5. Why Multiple Errors Can Occur

A single database operation can produce more than one error. For this reason, ADO provides an Errors collection rather than requiring the application to examine only one error object.

Consider an operation involving a database procedure. The database may report several related problems before the operation finishes. The provider can return these errors to ADO, where they become available through the connection's Errors collection.

A useful error-handling pattern is therefore:

On Error Resume Next

cn.Execute sql

If Err.Number <> 0 Then

    Dim errItem As ADODB.Error

    For Each errItem In cn.Errors
        Debug.Print "ADO Number: " & errItem.Number
        Debug.Print "Description: " & errItem.Description
        Debug.Print "Native Error: " & errItem.NativeError
        Debug.Print "Source: " & errItem.Source
        Debug.Print "SQL State: " & errItem.SQLState
    Next

End If

This approach provides more diagnostic information than simply displaying Err.Description.

6. ADO Errors vs. Visual Basic Err Object

ADO applications can encounter two related but different error mechanisms.

The Visual Basic Err object provides general runtime error information:

Err.Number
Err.Description

ADO's Errors collection provides database-provider-specific information:

cn.Errors

Therefore, when dealing with database operations, a robust error-handling strategy often examines both.

For example:

On Error Resume Next

cn.Execute "SELECT * FROM UnknownTable"

If Err.Number <> 0 Then

    Debug.Print "General Error:"
    Debug.Print Err.Number
    Debug.Print Err.Description

    Debug.Print "Provider Errors:"

    Dim e As ADODB.Error

    For Each e In cn.Errors
        Debug.Print e.Number
        Debug.Print e.NativeError
        Debug.Print e.Description
    Next

End If

The Err object can indicate that the operation failed, while the ADO Errors collection can provide additional information about why the provider rejected the operation.

7. Why Native Error Codes Are Useful

Native error codes are especially useful in applications that need detailed error handling.

Suppose an application attempts to insert a record and the database rejects it because a unique constraint has been violated. A generic error message may only indicate that the operation failed. The native error information can help the developer determine that the actual problem is a constraint violation.

This allows an application to distinguish between different situations.

For example:

Connection failure
Invalid table
Invalid column
Permission failure
Constraint violation
Transaction failure
Deadlock
Database unavailable

The application can then respond differently to each situation.

8. Provider Dependency

One of the most important characteristics of native error codes is that they are provider-dependent.

ADO is designed to work with different data sources and providers. Consequently, an error code returned by one provider may have no equivalent numerical meaning in another provider.

For example, an application connected to SQL Server through one provider may receive one native error number, while an application connected to another database system may receive a completely different number for a similar error.

Therefore, developers should avoid assuming that a particular native error number has a universal meaning across all ADO data sources.

9. Practical Error-Handling Strategy

A good ADO application should not expose raw technical error information directly to ordinary users. Instead, the application should record detailed diagnostic information while displaying an understandable message to the user.

For example:

On Error Resume Next

cn.Execute sql

If Err.Number <> 0 Then

    Dim e As ADODB.Error

    For Each e In cn.Errors
        'Record detailed error information
        Debug.Print e.Number
        Debug.Print e.NativeError
        Debug.Print e.Description
    Next

    MsgBox "The database operation could not be completed."

End If

The developer can store the native error code and description in a log file or database while presenting a simpler message to the user.

10. Example Scenario

Consider an employee-management application that attempts to insert a new employee:

sql = "INSERT INTO Employee(EmployeeID, Name) VALUES (101, 'Rahul')"

cn.Execute sql

Suppose employee ID 101 already exists and the database has defined EmployeeID as a unique key.

The database provider may reject the operation and return provider-specific error information.

The application can examine:

For Each e In cn.Errors
    Debug.Print "Description: " & e.Description
    Debug.Print "Native Error: " & e.NativeError
Next

The developer can use this information to identify that the insertion failed because of a database constraint rather than because the connection itself failed.

The application could then display a more meaningful message such as:

The employee ID already exists. Please enter a different ID.

This is much more useful than displaying a generic database error.

11. Best Practices

When working with ADO provider errors and native error codes, developers should follow several practices.

First, examine the ADO Errors collection after database operations that can fail. A single operation can generate multiple provider errors.

Second, use NativeError when provider-specific diagnosis is required. It provides information originating from the underlying database provider.

Third, do not assume that native error numbers are universal. Their meaning depends on the provider and database system.

Fourth, log useful diagnostic information such as the error number, native error code, description, source, and SQL state when available.

Fifth, avoid displaying raw database error messages to end users when those messages contain unnecessary technical information.

Finally, design error handling around categories of failures rather than relying exclusively on one numeric error code. This makes applications easier to maintain when the database provider changes.

Conclusion

ADO Data Provider Errors and Native Error Codes provide a deeper level of database error diagnosis than ordinary runtime error handling. ADO exposes provider-generated information through the Errors collection, while properties such as Number, Description, NativeError, Source, and SQLState help developers understand the failure.

The NativeError property is especially important because it represents information supplied by the underlying database provider. Since native error codes are provider-specific, applications should interpret them within the context of the particular database and provider being used. Properly handling these errors enables developers to diagnose database problems accurately, create meaningful user responses, and build more reliable ADO-based applications.