Error Handling
As we know, even valid SQL statements don’t always succeed when executed. Problems such as loss of connectivity, invalid data, and myriad other errors can cause an otherwise good SQL statement to fail. Fortunately, checking the success or failure of an Open SQL execution is straightforward: you follow the same error model used in the standard API of the DB Interface Module. (See Chapter 6, The Error Model.)
With Open SQL, any error that occurs during execution causes the RWDBOSql instance to become invalid, and its status is changed to reflect the error. However, the RWDBOSql instance may still be reused; it remains invalid only until the next successful execution.
Let’s see how error handling works with Open SQL. Using the error model of the DB Interface Module, we can easily add in-line error checking to the previous code sample:
 
RWDBConnection aConn = aDb.connection(); // 1
RWDBOSql anOSql(“INSERT INTO MYTABLE VALUES(10)”); // 2
anOSql.execute(aConn); // 3
 
// Did the execution fail?
if ( !anOSql.isValid() ) { // 4
// It failed. Print out the error message.
// someOstream is an ostream or std::ostream, such as
// cout or cerr (or std::cout, std::cerr)
someOstream << “Error: “
<< anOSql.status().message() // 5
<< endl;
}
In //1 - //3, we execute the statement as in the previous example. On //4, we use the isValid() method on the RWDBOSql; here isValid() returns false if the execution of the SQL statement fails. On //5, we use the status() method to return an RWDBStatus that contains information about the error, such as a printable error message, and error codes. Although the RWDBOSql is invalid at this point, we can choose to reinvoke execute(). If the re-execution succeeds, the RWDBOSql becomes valid again, so that calling isValid() on it returns true.