Error Support

A feature introduced in ODBC 3.0 is that of diagnostic fields. Following is information on how to use the ODBC Provider to access error information from those diagnostic fields.

To retrieve diagnostic information, the consumer registers the diagnostic fields of interest beforehand. The ODBC Provider includes a new interface, ISQLRequestDiagFields, to facilitate this process.

When an OLE DB consumer needs to retrieve certain diagnostic fields after a method call, it first calls ISQLRequestDiagFields::RequestDiagFields on the OLE DB object before calling the method to notify the ODBC Provider that it may request the diagnostic information. The ODBC Provider then caches those diagnostic fields. If the consumer does not call ISQLRequestDiagFields::RequestDiagFields, the ODBC Provider does not cache any extra diagnostic data except the information needed in the existing OLE DB error model.

ISQLRequestDiagFields (defined in the header file Msdasql.h) is an optional interface of any OLE DB object implemented in the ODBC Provider. Any object that supports diagnostic fields exposes this interface. It has one method, RequestDiagFields. Here is its calling convention:

enum KAGREQDIAGFLAGSENUM
 {   KAGREQDIAGFLAGS_HEADER  = 0x1,
    KAGREQDIAGFLAGS_RECORD  = 0x2
  };

typedef struct  tagKAGREQDIAG
{
 ULONG ulDiagFlags;
 VARTYPE vt;
 SHORT sDiagField;
} KAGREQDIAG;

ISQLRequestDiagFields : public IUnknown
{
public:
  virtual HRESULT STDMETHODCALLTYPE RequestDiagFields(
  ULONG cDiagFields,
  KAGREQDIAG rgDiagFields[  ]) = 0;

};

cDiagFields is the number of diagnostic fields to be requested; rgDiagFields is an array of KAGREQDIAG. KAGREQDIAG describes the diagnostic identifier, type, and flags of a diagnostic field. ulDiagFlags can be KAGREQDIAGFLAGS_HEADER or KAGREQDIAGFLAGS_RECORD. They tell whether the diagnostic field is a header field or record field. vt is data type of the diagnostic information and it must be VT_I2, VT_UI2, VT_I4, VT_UI4, VT_BSTR, or VT_UI1 | VT_ARRAY depending on the type of diagnostic field. For example, if the diagnostic field type is SQLINTEGER in ODBC, it must be VT_I4; if the type is string in ODBC, it must be VT_BSTR here. Otherwise, the result is undefined. This function clears the previous request of the diagnostic fields in the object. Setting cDiagFields to 0 means that no diagnostic fields should be cached by the provider on this object.

Although the ODBC Provider will support diagnostic fields for both 2.X and 3.X ODBC drivers, it should be noted that the functionality is limited for ODBC 2.X drivers because no 2.X driver supports diagnostics.

The diagnostic information is retrieved through IGetDiagField::GetDiagField. IGetDiagField is a new optional interface of TCustomErrorObject.

typedef struct  tagKAGGETDIAG
{
  ULONG ulSize;
  VARIANTARG vDiagInfo;
  SHORT sDiagField;
} KAGGETDIAG;

ISQLGetDiagField : public IUnknown
{
public:
 virtual HRESULT STDMETHODCALLTYPE GetDiagField(
     KAGGETDIAG *pDiagInfo) = 0;
};

pDiagInfo is an input/output argument.

On input, pDiagInfo->ulSize should be set the size of KAGGETDIAG; pDiagInfo->vDiagInfo should be initialized with VariantInit; and pDiagInfo->sDiagField is the diagnostic field identifier.

At return, pDiagInfo->vDiagInfo has the data for the diagnostic information. vDiagInfo.vt can be any of the values listed for argument vt in ISQLRequestDiagFields::RequestDiagFields.

If the diagnostic data is a string or binary, the data is stored as BSTR or VT_UI1 | VT_ARRAY. When the diagnostic information is no longer needed, pDiagInfo->vDiagInfo should be freed with VariantClear by the consumer.