Exception and Statement's cancel()-method
Hi,
I've written an object which is responsible for running and cancelling SQL-Statements. These are normally Statements which last quite a long time. So we gave the user the ability to cancel the execution, if he don't want to wait any longer. All works fine. But in some rare cases I get Exceptions
, at lines I didn't expect to get them.
Maybe anybody out there could give me a hint, what I'm missing:
1) Within the cancel()-method I get the following Exception at the line
_stmt.close();
java.sql.SQLException: ORA-01013: user requested cancel of current operation
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:168)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:208)
at oracle.jdbc.ttc7.Oclose.receive(Oclose.java:126)
at oracle.jdbc.ttc7.TTC7Protocol.close(TTC7Protocol.java:533)
at oracle.jdbc.driver.OracleStatement.close(OracleStatement.java:595)
at com.airplus.aim.bericht.auswertung.AbstractAuswertung$1.run(AbstractAuswertung.java:210)
2) Within the execute()-method I get the following Exception at the line
while (_rs.next()) {
java.sql.SQLException: Closed Statement: next
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:168)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:210)
at oracle.jdbc.dbaccess.DBError.check_error(DBError.java:829)
at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:191)
at com.airplus.aim.bericht.auswertung.AbstractAuswertung.execute(AbstractAuswertung.java:425)
Because of all the synchronization I didn't expect any of these Exceptions at these lines.
Any help would be great.
Harald
Environment:
Oracle RDBMS 8.1.7
Oracle JDBC Thin Driver 8.1.7
Source-Code( fragment, not compile clean):
package com.airplus.aim.bericht.auswertung;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import com.airplus.aim.bericht.DataNotFoundException;
import com.airplus.aim.datenbank.implementierung.AimPoolProxy;
import com.airplus.aim.bericht.IAuswertung;
import com.airplus.aim.bericht.IZeile;
import com.airplus.aim.bericht.IBerichtsdefinition;
import com.airplus.aim.bericht.IErgebnis;
import com.airplus.aim.bericht.DefaultErgebnis;
import com.airplus.aim.bericht.QueryCancelledException;
import com.airplus.aim.bericht.QueryTimeOutException;
import com.airplus.aim.util.SystemConstants;
public abstract class AbstractAuswertung implements IAuswertung {
private DataSource _connPool = AimPoolProxy.getInstance();
private Connection _conn = null;
private Statement _stmt = null;
private ResultSet _rs = null;
private DefaultErgebnis _erg = new DefaultErgebnis();
private StringBuffer _sqlText = new StringBuffer("Long running SELECT");
/**
* distinquish between "user Cancel" and "query timeout"
*/
private boolean userCanceled = false;
/**
* Der Lock fÃÂür die "Cancel"-Operation, damit das Abbrechen des Statements
* mit dem Auslesen daraus synchronisiert wird.
*/
private Boolean cancelLock = Boolean.TRUE;
public AbstractAuswertung() {
}
/**
cancel the current Statement
*/
public final boolean cancel() {
Thread ath = new Thread() { // Beginn Thread-Implementierung
public void run() { // run-Methode des Threads
if (_stmt != null) { // 1
// synchronization with execute()
synchronized (cancelLock) { // 2
if (_stmt != null) { // 3
// indicate "user cancel"
userCanceled = true;
try {
_stmt.cancel();
if (_rs != null) {
_rs.close();
_rs = null;
}
_stmt.close();
}
catch (SQLException ex) {
_rs = null;
CtxLogMgr.getContextCategory().debug("Statement konnte nicht abgebrochen werden", ex);
}
_stmt = null;
} //3
} // 2
} // 1
} // run-Methode des Threads
}; // Ende Thread-Implementierung
ath.start();
return true;
}
public final synchronized IErgebnis execute(IBerichtsdefinition definition)
throws SQLException,
DataNotFoundException,
QueryCancelledException {
try {
// Connection holen
conn = connPool.getConnection();
if (_conn == null)
throw new SQLException("Connection is not available");
stmt = conn.createStatement();
if (_stmt == null)
throw new SQLException("Statement is not available");
// normally _sqlText is generated dynamically here
// set Timeout from config-file
String timeout = SystemConstants.AIMSYSTEM_CONF.getString("com.airplus.aim.db.QueryTimeOutMinutes");
try {
_stmt.setQueryTimeout(Integer.parseInt(timeout) * 60);
}
catch (NumberFormatException ne) {
_stmt.setQueryTimeout(10*60);
}
rs = stmt.executeQuery(_sqlText.toString());
if (_rs == null)
throw new SQLException("Result is not available");
// synchronization with cancel()
// the statement should not be canceled, if we could already fetch the results
synchronized (this.cancelLock) {
if (_rs != null) {
while (_rs.next()) {
// construct result IErgebnis
}
} // end if _rs != null
} // ende vom synchronized-Block
if (_erg.getData().size() == 0) {
throw new DataNotFoundException();
}
}
catch (SQLException ex) {
// Logging
if (ex.getErrorCode() == 1013 && this.userCanceled) {
status = "USERBREAK";
throw new QueryCancelledException(ex.getMessage());
} else {
if (ex.getErrorCode() == 1013) {
status = "TIMEOUT";
throw new QueryTimeOutException(ex.getMessage());
} else {
throw ex;
}
}
}
finally {
// synchronization with cancel()
synchronized (this.cancelLock) {
// Resourcen freigeben
if (_rs != null) {
_rs.close();
_rs = null;
}
if (_stmt != null) {
_stmt.close();
_stmt = null;
}
}
if (_conn != null) {
_conn.close();
_conn = null;
}
}
}
// Berichtsdefinition im Ergebnis speichern.
_erg.setDefinition(definition);
//Ergebnis zurÃÂückgeben.
return (IErgebnis)_erg;
}
}