Subject Re: Some bugs and patches
Author rrokytskyy
Hi,

Thanks a lot! Unfortunatelly I will be able to patch sources only on
weekend. After I do this, I will post a message here. Thanks again!

Roman

--- In Firebird-Java@y..., "Blas Rodriguez Somoza" <blas@p...> wrote:
> Hello
>
> I spend some time testing the driver and I locate some bugs and
it solutions. I send the methods affected in a text file with
> the mail. I refresh my CVS repository on May-14 at 21:52 (Madrid
Time) so I think I make the changes on the current version.
>
> With this patches, the driver passes all the tests for
PreparedStatement. Otherwise, the bug about the statement closing have
> some serious consecuences, between which it is that the driver
locks a table and when after some other work, the program tries to
> close the connection, the method fails with an exception.
>
> 1.- FBPreparedStatement.internalExecute.
> BUG: a preparedStatement with the parameters cleared don't throw
SQLexception when executed.
> WHY: there is two internalExecute methods but only one is used.
There are a parameters check in the wrong method
> "internalExecute(String)". PATCH: copy the parameter check to the
correct method "internalExecute(boolean)". I think it is better to
> comment the unused method to avoid confusion.
>
> 2.- FBStatement.getResultSet()
> BUG: When getResultSet is called after a execute
(insert/update/delete) the driver throws an error "registerStatement
called with no
> transaction".
> WHY: The driver try to return a new resultSet but it can't.
> PATCH: Now there are some code to try to get more than one
resultSet, but the driver does not implement getMoreResults and I
don't
> know if the driver and Firebird can return multiple results with
one execute. The solution is to return null if there is no
> cachedResultSet, this behavoir is the one the specification expects
if there is no more resultSets.
>
> 3.- FBStatement.getMoreResults()
> BUG: Not implemented
> PATCH: return null.
>
> 4.- FBStatement.execute/executeQuery/executeUpdate
> BUG: The execute methods does not verify if the Statement is closed.
> PATCH: verify if the Statement is closed at the beggining of the
three execute methods and return an SQLException if the statement
> is closed.
>
> 5.- FBStatement.close
> BUG: If an Statement is closed before it is used to execute a SQL
command, the close method does not set closed=true because
> fixedStmt is null.
> PATCH: set closed=true in close() method if fixedStmt is false.
>
> 6.- FBConnection.setTransactionIsolation
> BUG: If a transaction isolation level is not supported, the driver
must upgrade the level to the next higher level, and if there is
> no one then it must throw a SQLException.
> PATCH: If READ_UNCOMMITTED isolation level is required then the
driver set the level to READ_COMMITTED.
>
>
> Regards
> Blas Rodriguez Somoza.
>
>
> Modified lines are marked with "MOD"
>
> FBConnection.setTransactionIsolation--------------------------------
-----
>
> public void setTransactionIsolation(int level) throws
SQLException {
> switch (level) {
> case TRANSACTION_SERIALIZABLE :
> mc.setTransactionIsolation(GDS.isc_tpb_consistency);
> break;
> case TRANSACTION_REPEATABLE_READ :
> mc.setTransactionIsolation(GDS.isc_tpb_concurrency);
> break;
> case TRANSACTION_READ_COMMITTED :
> mc.setTransactionIsolation
(GDS.isc_tpb_read_committed);
> break;
> MOD case TRANSACTION_READ_UNCOMMITTED :
> MOD mc.setTransactionIsolation
(GDS.isc_tpb_read_committed);
> MOD break;
> default: throw new SQLException("Unsupported
transaction isolation level");
> }
> }
>
> FBStatement.executeQuery-------------------------------------
>
> public ResultSet executeQuery(String sql) throws SQLException {
> MOD if (closed)
> MOD throw new SQLException("Statement is closed");
> try
> {
> c.ensureInTransaction();
> if (!internalExecute(sql)) {
> throw new SQLException("query did not return a
result set: " + sql);
> }
> if (c.willEndTransaction())
> {
> ResultSet rs = getCachedResultSet(false);
> //autocommits.
> return rs;
> } // end of if ()
> else
> {
> return getResultSet();
> } // end of else
> }
> catch (ResourceException re)
> {
> log.warn("resource exception", re);
> throw new SQLException("ResourceException: " + re);
> } // end of try-catch
> catch (GDSException ge)
> {
> throw new SQLException("GDSException: " + ge);
> } // end of try-catch
> finally
> {
> c.checkEndTransaction();
> } // end of finally
>
> }
>
> FBStatement.executeUpdate-------------------------------------
>
> public int executeUpdate(String sql) throws SQLException {
> MOD if(closed)
> MOD throw new SQLException("Statement is closed");
> try
> {
> c.ensureInTransaction();
> if (internalExecute(sql)) {
> throw new SQLException("update statement returned
results!");
> }
> return getUpdateCount();
> }
> catch (ResourceException re)
> {
> throw new SQLException("ResourceException: " + re);
> } // end of try-catch
> catch (GDSException ge)
> {
> throw new SQLException("GDSException: " + ge);
> } // end of try-catch
> finally
> {
> c.checkEndTransaction();
> } // end of finally
> }
>
> FBStatement.execute-------------------------------------
>
> public boolean execute(String sql) throws SQLException {
> MOD if (closed)
> MOD throw new SQLException("Statement is closed");
> try {
> c.ensureInTransaction();
> boolean hasResultSet = internalExecute(sql);
> if (hasResultSet && c.willEndTransaction())
> {
> getCachedResultSet(false);
> } // end of if ()
> return hasResultSet;
> }
> catch (ResourceException re)
> {
> throw new SQLException("ResourceException: " + re);
> } // end of try-catch
> catch (GDSException ge)
> {
> throw new SQLException("GDSException: " + ge);
> } // end of try-catch
> finally
> {
> c.checkEndTransaction();
> } // end of finally
> }
>
>
> FBStatement.close-------------------------------------
>
> public void close() throws SQLException {
> if (closed)
> throw new SQLException("This statement is already
closed.");
>
> if (fixedStmt != null) {
> try {
> //may need ensureTransaction?
> mc.closeStatement(fixedStmt, true);
> }
> catch (GDSException ge) {
> throw new SQLException("could not close
statement: " + ge.toString());
> }
> finally {
> fixedStmt = null;
> currentRs = null;
> currentCachedResultSet = null;
> closed = true;
> }
> }
> MOD else
> MOD closed = true;
> }
>
> FBStatement.getResultSet -------------------------------------------
-------------
>
> public ResultSet getResultSet() throws SQLException {
> if (currentRs != null) {
> throw new SQLException("Only one resultset at a
time/statement!");
> }
> if (fixedStmt == null) {
> throw new SQLException("No statement just executed");
> }
> if (currentCachedResultSet != null)
> {
> ResultSet rs = currentCachedResultSet;
> currentCachedResultSet = null;
> return rs;
> } // end of if ()
> else
> {
> //currentRs = new FBResultSet(mc, this, fixedStmt);
> MOD// currentRs = new FBResultSet(c, this, fixedStmt);
> MOD// return currentRs;
> MOD return null;
> } // end of else
> }
>
> FBStatement.getMoreResults -----------------------------------------
---------------
>
> public boolean getMoreResults() throws SQLException {
> MOD// throw new SQLException("Not yet implemented");
> MOD return false;
> }
>
>
> FBPreparedStatement ------------------------------------------------
--------
>
> protected boolean internalExecute(boolean sendOutParams)
throws SQLException
> {
> MOD boolean canExecute = true;
> MOD for (int i = 0; i < isParamSet.length; i++){
> MOD canExecute = canExecute && isParamSet[i];
> MOD }
>
> MOD if (!canExecute)
> MOD throw new SQLException("Not all parameters were set. " +
> MOD "Cannot execute query.");
>
> XSQLVAR[] inVars = fixedStmt.getInSqlda().sqlvar;
>
> for(int i = 0; i < inVars.length; i++)
> {
> boolean isBlobField =
> FBField.isType(inVars[i], Types.BLOB) ||
> FBField.isType(inVars[i], Types.BINARY) ||
> FBField.isType(inVars[i], Types.LONGVARCHAR);
>
> if (isBlobField)
> {
> FBBlobField blobField = (FBBlobField)getField(i +
1);
> blobField.flushCachedData();
> }
> }
> try {
> closeResultSet();
> mc.executeStatement(fixedStmt, sendOutParams);
> return (fixedStmt.getOutSqlda().sqld > 0);
> }
> catch (GDSException ge) {
> throw new SQLException("GDS exception: " + ge.toString
());
> }
> }