[
https://issues.apache.org/jira/browse/DERBY-3221?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12557261#action_12557261
]
Dyre Tjeldvoll commented on DERBY-3221:
---------------------------------------
I did some more digging, and I now think I know how it should be fixed,
(creating a new TemporaryRowHolderImpl object in each execution works, but is
overkill). I noticed that the problem did not occur EVERY time a prepared
statement was re-executed. Sometimes it would not fail until the 9th execution.
It turns out that the problem was a lack of communication between
TemporaryRowHolderImpl and TemporaryRowHolderResultSet. When rows are inserted
into the RowHolder it will fill as many rows as it can into its internal
rowArray, before creating, and "spilling over" into a temporary conglomerate.
The RowHolderResultSet is used to read the rows back out, so it starts by
returning the rows from the rowArray, and then proceeds with rows from the
temporary conglomerate. Unfortunately, the RowHolder doesn't provide a proper
API for checking if a temporary conglomerate has actually been created. To get
around this RowHolderResultSet checks if RowHolder.CID (the conglomerate id of
the temporary conglomerate) is 0. If it is, RowHolderResultSet assumes that no
temporary conglomerate has been created.
This scheme worked well when internal result sets were not reused because then
each execution started with a newly created RowHolder which had its CID member
initialized to 0. But when results sets are reused this fact cannot be relied
upon since CID it NOT set back to 0 by RowHolder.close().
So the error will ONLY surface when a prepared statement has caused the
rowHolder to spill into a temporary conglomerate (thereby assigning a value !=
0 to CID), and some subsequent execution does NOT spill over. Then when the
latter execution tries to read from the RowHolderResultSet it will incorrectly
look for a temporary conglomerate that was never created in the insert-phase.
I'm currently running tests on a patch that provides an api for testing if the
conglomerate has been created (and also sets CID to 0 in close()). I plan to
upload it if the tests pass.
(There should probably be a regression test for this, but James' repro does not
have ASF license so I guess we can't just convert that to JUnit).
> "java.sql.SQLException: The conglomerate (-5) requested does not exist." from
> Derby 10.3.1.4 embedded within Eclipse 3.3 and RAD 7.0
> ------------------------------------------------------------------------------------------------------------------------------------
>
> Key: DERBY-3221
> URL: https://issues.apache.org/jira/browse/DERBY-3221
> Project: Derby
> Issue Type: Bug
> Components: JDBC
> Affects Versions: 10.3.1.4, 10.3.2.1
> Environment: Windows Vista Ubuntu Linux on IBM's VM (RAD 7.0)
> Reporter: Tim Halloran
> Attachments: conlomerate.tar.gz, derby-3221.prelim.diff,
> SubShape.properties
>
>
> We are getting an SQLException when several prepared statement deletes are
> done upon an existing database. As far as we can tell this exception should
> never occur unless (evil) things like deleting the database or editing files
> occurs. This is using the embedded driver within a plug-in inside RAD 7.0
> (and Eclipse 3.3).
> I'm not sure what else to submit that might be helpful.
> java.sql.SQLException: The conglomerate (-5) requested does not exist.
> at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown
> Source)
> at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
> at
> org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown
> Source)
> at
> org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown
> Source)
> at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
> at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
> at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
> at
> org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown
> Source)
> at org.apache.derby.impl.jdbc.EmbedPreparedStatement.execute(Unknown Source)
> at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
> at java.lang.reflect.Method.invoke(Unknown Source)
> at
> com.surelogic.sierra.jdbc.LazyPreparedStatementConnection$LazyPreparedStatement.invoke(Unknown
> Source)
> at $Proxy1.execute(Unknown Source)
> at com.surelogic.sierra.jdbc.finding.FindingManager.delete(Unknown Source)
> at
> com.surelogic.sierra.jdbc.finding.ClientFindingManager.updateLocalFindings(Unknown
> Source)
> at
> com.surelogic.sierra.jdbc.project.ClientProjectManager.synchronizeProject(Unknown
> Source)
> at
> com.surelogic.sierra.client.eclipse.jobs.SynchronizeJob.synchronize(Unknown
> Source)
> at com.surelogic.sierra.client.eclipse.jobs.SynchronizeJob.run(Unknown
> Source)
> at org.eclipse.core.internal.jobs.Worker.run(Unknown Source)
> Caused by: ERROR XSAI2: The conglomerate (-5) requested does not exist.
> at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
> at
> org.apache.derby.impl.store.access.RAMTransaction.findExistingConglomerate(Unknown
> Source)
> at org.apache.derby.impl.store.access.RAMTransaction.openScan(Unknown Source)
> at
> org.apache.derby.impl.sql.execute.TemporaryRowHolderResultSet.getNextRowCore(Unknown
> Source)
> at
> org.apache.derby.impl.sql.execute.TemporaryRowHolderResultSet.getNextRow(Unknown
> Source)
> at org.apache.derby.impl.sql.execute.IndexChanger.finish(Unknown Source)
> at org.apache.derby.impl.sql.execute.IndexSetChanger.finish(Unknown Source)
> at org.apache.derby.impl.sql.execute.RowChangerImpl.finish(Unknown Source)
> at org.apache.derby.impl.sql.execute.UpdateResultSet.open(Unknown Source)
> at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
> ... 14 more
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.