Regarding exception handling, letting internal exceptions define external behavior is perhaps a bad idea. The possible exception types can be wide and change over time as new parts or features are added. Example:
// pseudo-code
qry = new query(sql=theSql, dbConfig=DB_FOO);
if (! qry.Execute()) {
errMsg = "Something went wrong during your query. ";
if (qry.errorExceptionName=="DB_Busy") {
errMsg += "The database appears to be busy."; // append more
}
displayAlert(errMsg);
} else {
processQuery(qry.resultRows);
}
Here any fatal errors are caught inside the query object, but details are available if and when you wish to take advantage of them outside the query object. The query object (API) user doesn't have to know all possible exceptions types in order to handle an exception properly (or at least in a good-enough way).