Checking Status with Class RWDBStatus
Class RWDBStatus is an important component of the error model of the DB Interface Module. Each RWDBStatus instance encapsulates the error state of an object or operation. Here is a partial listing of the definition of class RWDBStatus:
 
class RWDBStatus {
public:
enum ErrorCode {
.
.
.
};
.
.
.
void raise() const;
bool isValid() const;
.
.
.
ErrorCode errorCode() const;
RWCString message() const;
long vendorError1() const;
long vendorError2() const;
RWCString vendorMessage1() const;
RWCString vendorMessage2() const;
};
Notice that the ErrorCode enumeration is scoped within class RWDBStatus. To avoid polluting the global name space, all enumerations of the DB Interface Module are scoped within classes. To refer to a member of the enumeration outside the scope of class RWDBStatus, use the scoping operator ::, as in RWDBStatus::ok, for example. For a list of the possible RWDBStatus::ErrorCode values, see the entry for RWDBStatus in the SourcePro API Reference Guide
A valid object, or a successful operation, is represented by an ErrorCode of RWDBStatus::ok. An RWDBStatus instance whose ErrorCode is vendorLib, serverError, or serverMessage reflects a database error or error of some kind, and contains database-dependent information. Other RWDBStatus instances represent errors generated by the DB Interface Module itself.
All classes of the DB Interface Module that interact with a database have a status, accessible through a status()method. Classes that do not have a status include:
*the concrete classes, including RWDBBlob, RWDBDuration, RWDBMBString, RWDBNullIndicator, and RWDBValue
*RWDBTBuffer, the class related to the bulk read and write mechanism.
*the classes RWDBAssignment, RWDBCriterion, RWDBEnvironmentHandle, RWDBExpr class hierarchy, RWDBForeignKeyList, RWDBManager, RWDBMultiRow, RWDBPhraseBook, RWDBRow, RWDBSystemHandle, and RWDBTracer
In classes that have status, certain member functions generate errors that do not affect the object itself. For example, the drop() method of RWDBTable succeeds or fails without affecting the RWDBTable itself. This type of method returns an RWDBStatus object instead. Errors encountered by all other member functions result in a change of status in the object itself.
Member functions that interact with a database either:
*Return an RWDBStatus object,
*Return an object that has a status, or
*Change the status of the object through which the function was invoked when an error occurs.
Returning to our earlier example, we could do this:
 
// Error Handling - Version 1
RWCString s; float f;
RWDBReader reader = anotherTable.reader();
while (reader()) {
 
reader >> s >> f;
if (reader.isValid()) {//1
.
. // process s and f
.
}
else {
// handle the error
cout << "Error reading anotherTable: "
<< reader.status().message() << endl;
}
}
On //1, the isValid() function, which in general checks the RWDBStatus of the object through which it was invoked, checks the status of the reader. This inline error checking technique has some advantages. For one thing, it is simple. Also, trapping an error close to the point where it occurs gives an application more context with which to handle the error. Here we are able to identify what was going on at the time the error occurred, that is, the application was reading anotherTable.
The error handling in this example is rudimentary: print a message, exit the processing loop, and continue. The loop is exited because the reader()call returns 0 when the reader's status is not ok.
This type of error handling is adequate in some contexts, but not in others. Inline error checking clutters up the original code, and distracts both the programmer and the reader of the code from its main purpose. Error Handlers presents a less disruptive, more centralized method of reporting errors using error handlers.