Skip to content

Commit

Permalink
Support for #5 - now logging database exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
edrdo committed Aug 10, 2018
1 parent 4f4d7ce commit c82ce3f
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 43 deletions.
48 changes: 24 additions & 24 deletions src/main/java/org/jdbdt/DB.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,32 +261,30 @@ public void setLog(File outputFile) {
* Compile a SQL statement.
* @param sql SQL code.
* @return Wrapper for prepared statement.
* @throws DBExecutionException If there is a error preparing the statement.
* @throws SQLException If there is a error preparing the statement.
*/
WrappedStatement compile(String sql) {
return access( () -> {
if (! isEnabled(Option.REUSE_STATEMENTS)) {
return new WrappedStatement(connection.prepareStatement(sql), false);
}
if (pool == null) {
pool = new IdentityHashMap<>();
}
String sqlI = sql.intern();
WrappedStatement ws = pool.get(sqlI);
if (ws == null) {
ws = new WrappedStatement(connection.prepareStatement(sql), true);
pool.put(sqlI, ws);
}
return ws;
});
WrappedStatement compile(String sql) throws SQLException {
if (! isEnabled(Option.REUSE_STATEMENTS)) {
return new WrappedStatement(connection.prepareStatement(sql), false);
}
if (pool == null) {
pool = new IdentityHashMap<>();
}
String sqlI = sql.intern();
WrappedStatement ws = pool.get(sqlI);
if (ws == null) {
ws = new WrappedStatement(connection.prepareStatement(sql), true);
pool.put(sqlI, ws);
}
return ws;
}

/**
* Set JDBDT save-point.
* @param callInfo Call info.
*/
void save(CallInfo callInfo) {
access( () -> {
access(callInfo, () -> {
if (!savepointSupport) {
throw new UnsupportedOperationException("Savepoints are not supported by the database driver.");
}
Expand All @@ -313,7 +311,7 @@ private void clearSavePointIfSet() {
* @param callInfo Call info.
*/
void commit(CallInfo callInfo) {
access( () -> {
access(callInfo, () -> {
logSetup(callInfo);
clearSavePointIfSet();
connection.commit();
Expand All @@ -329,7 +327,7 @@ void restore(CallInfo callInfo) {
// Note: this is a conservative implementation, it sets another save-point
// after roll-back, some engines seem to implicitly release the save point on roll-back
// (an issue with HSQLDB)
access(() -> {
access(callInfo, () -> {
logSetup(callInfo);
try {
if (!savepointSupport) {
Expand Down Expand Up @@ -392,15 +390,17 @@ interface Access<T> {
* Any {@link java.sql.SQLException} error that occurs is wrapped
* into a {@link DBExecutionException} instance.
* @param <T> Type of result.
* @param callInfo Call info.
* @param op Operation.
* @return DB access result.
* @throws DBExecutionException If a database error occurs.
*/
<T> T access(Access<T> op) {
<T> T access(CallInfo callInfo, Access<T> op) {
try {
return op.execute();
}
catch (SQLException e) {
log.write(callInfo, e);
throw new DBExecutionException(e);
}
}
Expand Down Expand Up @@ -445,7 +445,7 @@ void logDataSetOperation(CallInfo callInfo, DataSet data) {
log.write(callInfo, data);
}
}

/**
* Log delta assertion.
* @param callInfo Call info.
Expand All @@ -471,7 +471,7 @@ && isEnabled(Option.LOG_ASSERTION_ERRORS) )) {
log.write(callInfo, dsa);
}
}

/**
* Log simple assertion.
* @param callInfo Call info.
Expand Down Expand Up @@ -524,6 +524,6 @@ private void ignoreSQLException(SQLOperationThatMayFail op) {





}
7 changes: 4 additions & 3 deletions src/main/java/org/jdbdt/DBAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ static void dataSetAssertion(CallInfo callInfo, DataSet expected, DataSet actual
* @param expected Expect if table exists or not.
*/
static void assertTableExistence(CallInfo callInfo, DB db, String tableName, boolean expected) {
boolean actual = tableExists(db, tableName);
boolean actual = tableExists(callInfo, db, tableName);
SimpleAssertion assertion = new SimpleAssertion(null, expected, actual);
db.log(callInfo, assertion);
if (!assertion.passed()) {
Expand All @@ -131,12 +131,13 @@ static void assertTableExistence(CallInfo callInfo, DB db, String tableName, boo

/**
* Check if table exists.
* @param callInfo Call info.
* @param db Database.
* @param tableName Table name.
* @return <code>true<code> if and only if the table exists.
*/
private static boolean tableExists(DB db, String tableName) {
return db.access(() -> {
private static boolean tableExists(CallInfo callInfo, DB db, String tableName) {
return db.access(callInfo, () -> {
DatabaseMetaData dbmd = db.getConnection().getMetaData();
try(ResultSet rs = dbmd.getTables(null, null, null, new String[] {"TABLE"})) {
while(rs.next()) {
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/org/jdbdt/DBSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ private static void dataSetOperation(CallInfo callInfo, Table table, DataSet dat

db.logDataSetOperation(callInfo, data);

db.access(() -> {
db.access(callInfo, () -> {
try(WrappedStatement ws = db.compile(sql)) {
PreparedStatement stmt = ws.getStatement();
int batchSize = 0;
Expand Down Expand Up @@ -279,7 +279,7 @@ static int deleteAll(CallInfo callInfo, Table table) {
*/
private static int doDeleteAll(CallInfo callInfo, Table table) {
DB db = table.getDB();
return db.access( () -> {
return db.access(callInfo, () -> {
String sql = DELETE_FROM_ + table.getName();
db.logSetup(callInfo, sql);
try (WrappedStatement ws = db.compile(sql)) {
Expand All @@ -295,7 +295,7 @@ private static int doDeleteAll(CallInfo callInfo, Table table) {
*/
static void truncate(CallInfo callInfo, Table table) {
final DB db = table.getDB();
db.access(() -> {
db.access(callInfo, () -> {
String sql = "TRUNCATE TABLE " + table.getName();
table.setDirtyStatus(true);
db.logSetup(callInfo, sql);
Expand All @@ -318,7 +318,7 @@ static void truncate(CallInfo callInfo, Table table) {
static int deleteAll(CallInfo callInfo, Table table, String where, Object... args) {
final DB db = table.getDB();

return db.access( () -> {
return db.access(callInfo, () -> {
table.setDirtyStatus(true);
String sql =
DELETE_FROM_ + table.getName() +
Expand All @@ -344,7 +344,7 @@ static int deleteAll(CallInfo callInfo, Table table, String where, Object... arg
*/
public static void drop(CallInfo callInfo, DB db, String tableName) {
String sql = String.format("DROP TABLE %s", tableName);
db.access(() -> {
db.access(callInfo, () -> {
db.logSetup(callInfo, sql);
try (WrappedStatement ws = db.compile(sql)) {
PreparedStatement dropStmt = ws.getStatement();
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/org/jdbdt/DataSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,17 @@ public abstract class DataSource {

/**
* Constructor.
* @param callInfo Call info.
* @param db Database instance.
* @param sql SQL code for query.
* @param queryArgs Optional arguments for database query.
*/
protected DataSource(DB db, String sql, Object... queryArgs) {
protected DataSource(CallInfo callInfo, DB db, String sql, Object... queryArgs) {
this.db = db;
this.querySQL = sql;
this.queryArgs = queryArgs;
this.dirty = true;
db.access(() -> {
db.access(callInfo, () -> {
try (WrappedStatement stmt = db.compile(querySQL)) {
MetaData md = new MetaData(stmt.getStatement());
String[] cols = new String[md.getColumnCount()];
Expand Down Expand Up @@ -197,7 +198,7 @@ public final String getSQLForQuery() {
*/
final DataSet executeQuery(CallInfo callInfo, boolean takeSnapshot) {
DataSet data = new DataSet(this);
return db.access( () -> {
return db.access(callInfo, () -> {
try (WrappedStatement ws = db.compile(getSQLForQuery())) {
proceedWithQuery(ws.getStatement(), data);
if (takeSnapshot) {
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/jdbdt/Log.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.sql.Blob;
import java.sql.Clob;
Expand Down Expand Up @@ -146,6 +148,21 @@ void write(CallInfo callInfo, DataSet data) {
flush(rootNode);
}

/**
* Report a database exception onto the log.
* @param callInfo Call info.
* @param e Database exception.
*/
void write(CallInfo callInfo, SQLException e) {
Element rootNode = root(callInfo);
Element exNode = createNode(rootNode, DATABASE_EXCEPTION_TAG);
StringWriter sw = new StringWriter();
sw.append('\n');
e.printStackTrace(new PrintWriter(sw));
exNode.appendChild(xmlDoc.createCDATASection(sw.toString()));
flush(rootNode);
}

@SuppressWarnings("javadoc")
private void write(Element parent, DataSource source) {
Element node = createNode(parent, DATA_SOURCE_TAG);
Expand Down Expand Up @@ -434,6 +451,8 @@ private String arrayAsString(Object array, Class<?> elemClass) {
@SuppressWarnings("javadoc")
private static final String ASSERTION_TAG = "assertion";
@SuppressWarnings("javadoc")
private static final String DATABASE_EXCEPTION_TAG = "database-exception";
@SuppressWarnings("javadoc")
private static final String ERRORS_TAG = "errors";
@SuppressWarnings("javadoc")
private static final String EXPECTED_TAG = "expected";
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/org/jdbdt/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ public final class Query extends DataSource {
* @param args Optional arguments for query.
*/
public Query(DB db, String sql, Object... args) {
super(db, sql, args);
this(CallInfo.create(), db, sql, args);
}

/**
* Constructor with supplied call information.
* @param callInfo Call info.
* @param db Database handle.
* @param sql SQL for query
* @param args Optional arguments for query.
*/
Query(CallInfo callInfo, DB db, String sql, Object... args) {
super(callInfo, db, sql, args);
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/jdbdt/QueryBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public final QueryBuilder arguments(Object...args) {
* @return A new query instance.
*/
public final Query build(DB db) {
return new Query(db, toSQL(), queryArgs);
return new Query(CallInfo.create(), db, toSQL(), queryArgs);
}

@SuppressWarnings("javadoc")
Expand Down
24 changes: 19 additions & 5 deletions src/main/java/org/jdbdt/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,32 @@ public final class Table extends DataSource {
* @param db Database instance.
* @param name Table name
* @param columns Database columns.
* @param key Key columns.
* @param keyColumns Key columns.
* @see JDBDT#table(String)
* @see TableBuilder
*/
public Table(DB db, String name, String[] columns, String[] key) {
super(db,
public Table(DB db, String name, String[] columns, String[] keyColumns) {
this(CallInfo.create(), db, name, columns, keyColumns);
}

/**
* Constructor with supplied call info.
* @param callInfo Call info.
* @param db Database instance.
* @param name Table name
* @param columns Database columns.
* @param keyCols Key columns.
* @see JDBDT#table(String)
* @see TableBuilder
*/
Table(CallInfo callInfo, DB db, String name, String[] columns, String[] keyCols) {
super(callInfo, db,
String.format("SELECT %s FROM %s",
Misc.sqlArgumentList(columns), name));

tableName = name;
keyColumns = key != null ?
Collections.unmodifiableList(Arrays.asList(key))
keyColumns = keyCols != null ?
Collections.unmodifiableList(Arrays.asList(keyCols))
: Collections.emptyList();
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jdbdt/TableBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public Table build(DB db) {
if (tableColumns == null) {
tableColumns = ALL_COLUMNS;
}
return new Table(db, tableName, tableColumns, keyColumns);
return new Table(CallInfo.create(), db, tableName, tableColumns, keyColumns);
}

}
17 changes: 17 additions & 0 deletions src/site/markdown/Logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,5 +200,22 @@ relates to the fact that the entry for "user" `linus` was removed.
</new-data>
</errors>
</delta-assertion>

<a name="DatabaseExceptions"></a>
## Database exceptions

A `database-exception` node refers to the stack trace of an `SQLException` thrown by the database engine during the execution of a JDBDT operation.

*Illustration*

<database-exception><![CDATA[
java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: XXX in statement [SELECT XXX FROM Users]
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.<init>(Unknown Source)
at org.hsqldb.jdbc.JDBCConnection.prepareStatement(Unknown Source)
at org.jdbdt.DB.compile(DB.java:276)
... [etc]
]]></database-exception>


4 changes: 4 additions & 0 deletions src/test/java/org/jdbdt/TableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ public void testQueryExecution() {
assertDataSet(expected, actual);
}

@Test
public void testXXX() {
theSUT = table(UserDAO.TABLE_NAME).columns("XXX").build(getDB());
}
}

0 comments on commit c82ce3f

Please sign in to comment.