You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by bp...@apache.org on 2006/04/29 07:41:20 UTC
svn commit: r398093 - in /db/derby/code/branches/10.1/java:
drda/org/apache/derby/impl/drda/
testing/org/apache/derbyTesting/functionTests/master/
testing/org/apache/derbyTesting/functionTests/master/DerbyNet/
testing/org/apache/derbyTesting/functionTe...
Author: bpendleton
Date: Fri Apr 28 22:41:18 2006
New Revision: 398093
URL: http://svn.apache.org/viewcvs?rev=398093&view=rev
Log:
DERBY-491: Protocol exception when Network Server returns long replies
This change merges the fix for DERBY-491 from the trunk to the 10.1 branch.
Modified:
db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DDMWriter.java
db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java
Modified: db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DDMWriter.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DDMWriter.java?rev=398093&r1=398092&r2=398093&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DDMWriter.java (original)
+++ db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DDMWriter.java Fri Apr 28 22:41:18 2006
@@ -289,10 +289,29 @@
* Copy Data to End
* Create a buffer and copy from the position given to the end of data
*
+ * Note that the position given is treated as relative to the
+ * current DSS, for there may be other DSS blocks (chained, presumably)
+ * which are sitting unwritten in the buffer. The caller doesn't
+ * know this, though, and works only with the current DSS.
+ *
+ * getDSSLength, copyDSSDataToEnd, and truncateDSS work together to
+ * provide a sub-protocol for DRDAConnThread to use in its
+ * implementation of the LMTBLKPRC protocol. They enable the caller
+ * to determine when it has written too much data into the current
+ * DSS, to reclaim the extra data that won't fit, and to truncate
+ * that extra data once it has been reclaimed and stored elsewhere.
+ * Note that this support only works for the current DSS. Earlier,
+ * chained DSS blocks cannot be accessed using these methods. For
+ * additional background information, the interested reader should
+ * investigate bugs DERBY-491 and 492 at:
+ * http://issues.apache.org/jira/browse/DERBY-491 and
+ * http://issues.apache.org/jira/browse/DERBY-492
+ *
* @param start
*/
- protected byte [] copyDataToEnd(int start)
+ protected byte [] copyDSSDataToEnd(int start)
{
+ start = start + dssLengthLocation;
int length = offset - start;
byte [] temp = new byte[length];
System.arraycopy(bytes,start,temp,0,length);
@@ -399,26 +418,31 @@
}
- /**
- * Get offset
- *
- * @return offset into the buffer
- */
- protected int getOffset()
- {
- return offset;
- }
-
- /**
- * Set offset
- *
- * @param value new offset value
- */
- protected void setOffset(int value)
- {
- offset = value;
- }
-
+ /**
+ * Get the length of the current DSS block we're working on. This is
+ * used by the LMTBLKPRC protocol, which does its own conversational
+ * blocking protocol above the layer of the DRDA blocking. The LMTBLKPRC
+ * implementation (in DRDAConnThread) needs to be able to truncate a
+ * DSS block when splitting a QRYDTA response.
+ *
+ * @return current DSS block length
+ */
+ protected int getDSSLength()
+ {
+ return offset - dssLengthLocation;
+ }
+
+ /**
+ * Truncate the current DSS. Before making this call, you should ensure
+ * that you have copied the data to be truncated somewhere else, by
+ * calling copyDSSDataToEnd
+ *
+ * @param desired DSS length
+ */
+ protected void truncateDSS(int value)
+ {
+ offset = dssLengthLocation + value;
+ }
// Write routines
@@ -1904,7 +1928,7 @@
{
lastDSSBeforeMark = prevHdrLocation;
- return getOffset();
+ return offset;
}
@@ -1923,7 +1947,7 @@
{
// Logical clear.
- setOffset(mark);
+ offset = mark;
// Because we've just cleared out the most recently-
// written DSSes, we have to make sure the next thing
Modified: db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=398093&r1=398092&r2=398093&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/branches/10.1/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Fri Apr 28 22:41:18 2006
@@ -5655,7 +5655,7 @@
// check for remaining space in current query block
// Need to mod with blksize so remaining doesn't go negative. 4868
- int remaining = blksize - (writer.getOffset() % blksize) - (3 +
+ int remaining = blksize - (writer.getDSSLength() % blksize) - (3 +
FdocaConstants.SQLCADTA_SQLDTARD_RLO_SIZE);
@@ -5899,7 +5899,7 @@
{
boolean getMoreData = true;
boolean sentExtData = false;
- int startOffset = writer.getOffset();
+ int startLength = 0;
writer.createDssObject();
if (SanityManager.DEBUG)
@@ -5940,12 +5940,12 @@
// It would get split up but it is not very efficient.
if (getMoreData == true)
{
- int endOffset = writer.getOffset();
- int rowsize = endOffset- startOffset;
- if ((stmt.getBlksize() - endOffset ) < rowsize)
+ int endLength = writer.getDSSLength();
+ int rowsize = endLength - startLength;
+ if ((stmt.getBlksize() - endLength ) < rowsize)
getMoreData = false;
- startOffset = endOffset;
+ startLength = endLength;
}
}
@@ -6169,7 +6169,7 @@
}
}
// does all this fit in one QRYDTA
- if (writer.getOffset() >= blksize)
+ if (writer.getDSSLength() >= blksize)
{
splitQRYDTA(stmt, blksize);
return false;
@@ -6214,6 +6214,17 @@
* set. At some later point, when the client returns with a CNTQRY,
* we will call processLeftoverQRYDTA to handle that data.
*
+ * The interaction between DRDAConnThread and DDMWriter is rather
+ * complicated here. This routine gets called because DRDAConnThread
+ * realizes that it has constructed a QRYDTA message which is too
+ * large. At that point, we need to reclaim the "extra" data and
+ * hold on to it. To aid us in that processing, DDMWriter provides
+ * the routines getDSSLength, copyDSSDataToEnd, and truncateDSS.
+ * For some additional detail on this complex sub-protocol, the
+ * interested reader should study bug DERBY-491 and 492 at:
+ * http://issues.apache.org/jira/browse/DERBY-491 and
+ * http://issues.apache.org/jira/browse/DERBY-492
+ *
* @param stmt DRDA statment
* @param blksize size of query block
*
@@ -6223,9 +6234,9 @@
DRDAProtocolException
{
// make copy of extra data
- byte [] temp = writer.copyDataToEnd(blksize);
+ byte [] temp = writer.copyDSSDataToEnd(blksize);
// truncate to end of blocksize
- writer.setOffset(blksize);
+ writer.truncateDSS(blksize);
if (temp.length == 0)
agentError("LMTBLKPRC violation: splitQRYDTA was " +
"called to split a QRYDTA block, but the " +
@@ -6323,7 +6334,7 @@
writer.writeByte(CodePoint.NULLDATA);
// does all this fit in one QRYDTA
- if (writer.getOffset() >= blksize)
+ if (writer.getDSSLength() >= blksize)
{
splitQRYDTA(stmt, blksize);
}
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out?rev=398093&r1=398092&r2=398093&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/procedure.out Fri Apr 28 22:41:18 2006
@@ -933,3 +933,5 @@
CALL LITT.TY_DECIMAL ('12.34', ?) (42821) Columns of type 'DECIMAL' cannot hold values of type 'CHAR'.
CALL LITT.TY_CHAR ('12.34', ?)=>12.34 <
CALL LITT.TY_VARCHAR ('12.34', ?)=>12.34<
+JIRA-491 Successful.
+JIRA-492 successful -- no hang!
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out?rev=398093&r1=398092&r2=398093&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/procedure.out Fri Apr 28 22:41:18 2006
@@ -933,3 +933,5 @@
CALL LITT.TY_DECIMAL ('12.34', ?) (42821) Columns of type 'DECIMAL' cannot hold values of type 'CHAR'.
CALL LITT.TY_CHAR ('12.34', ?)=>12.34 <
CALL LITT.TY_VARCHAR ('12.34', ?)=>12.34<
+JIRA-491 Successful.
+JIRA-492 successful -- no hang!
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out?rev=398093&r1=398092&r2=398093&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/procedure.out Fri Apr 28 22:41:18 2006
@@ -1009,3 +1009,5 @@
CALL LITT.TY_DECIMAL ('12.34', ?) (42821) Columns of type 'DECIMAL' cannot hold values of type 'CHAR'.
CALL LITT.TY_CHAR ('12.34', ?)=>12.34 <
CALL LITT.TY_VARCHAR ('12.34', ?)=>12.34<
+JIRA-491 Successful.
+JIRA-492 successful -- no hang!
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java?rev=398093&r1=398092&r2=398093&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/procedure.java Fri Apr 28 22:41:18 2006
@@ -82,6 +82,7 @@
testSQLControl(conn);
testLiterals(conn);
+ jira_491_492(conn);
} catch (SQLException sqle) {
org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(System.out, sqle);
sqle.printStackTrace(System.out);
@@ -406,6 +407,129 @@
s.close();
}
+ // This test case provides tests for bugs DERBY-491 and DERBY-492. These
+ // two bug reports describe different symptoms, but the underlying bug
+ // is identical: the network server's implementation of LMTBLKPRC was
+ // incorrectly manipulating DDMWriter's bytes buffer. Depending on the
+ // details, the symptom of this bug was generally a hang, because the
+ // server mistakenly truncated the unsent data in its network buffer and
+ // hence sent only a partial transmission, causing the client to hang,
+ // waiting for data that would never arrive. A more detailed analysis
+ // of some other possible symptoms that could arise from these tests is
+ // available in the bug notes for bug 491 in JIRA at:
+ // http://issues.apache.org/jira/browse/DERBY-491
+ //
+ private static void jira_491_492(Connection conn)
+ throws SQLException
+ {
+ Statement st = conn.createStatement();
+ PreparedStatement pSt = null;
+
+ // JIRA-491: Result set has a row that is approx 32K long.
+ // When originally filed, this bug script caused a protocol
+ // exception and connection deallocation, but that was because the
+ // bug script provoked both JIRA-614 *and* JIRA-491. If you have
+ // the fix for JIRA-614, but JIRA-491 has regressed, you will hang.
+
+ try {
+ st.execute("drop table testtable1");
+ } catch (SQLException se) {}
+
+ // Create an array of chars to be used as the input parameter.
+ // Note that the array should roughly 32K or larger.
+ char [] cData = new char[32500];
+ for (int i = 0; i < cData.length; i++)
+ cData[i] = Character.forDigit(i%10, 10);
+
+ try {
+ st.execute("create table jira491 (int1 integer, varchar32k varchar(32500))");
+ pSt=conn.prepareStatement("insert into jira491 values (?,?)");
+ for (int i = 1; i <= 5; i++) {
+ pSt.setInt(1, i);
+ pSt.setString(2, new String(cData));
+ pSt.execute();
+ }
+ } catch (SQLException se) {
+ System.out.println("JIRA-491: FAILURE in data generation:");
+ se.printStackTrace(System.out);
+ }
+
+ try {
+ st.execute("drop procedure TEST_PROC_JIRA_491");
+ } catch (SQLException se) {} // Ignore "proc does not exist" errors
+
+ try {
+ st.execute("create procedure TEST_PROC_JIRA_491(in i int) " +
+ "language java parameter style java external name " +
+ "'org.apache.derbyTesting.functionTests.util.ProcedureTest.BIG_COL_491' result sets 2");
+ } catch (SQLException se) {
+ System.out.println("JIRA-491: FAILURE in procedure creation:");
+ se.printStackTrace(System.out);
+ }
+
+ CallableStatement cSt = conn.prepareCall("call TEST_PROC_JIRA_491(?)");
+ cSt.setInt(1, 3);
+ try {
+ cSt.execute();
+ do {
+ ResultSet rs = cSt.getResultSet();
+ while (rs.next()) {
+ String s = rs.getString(2);
+ }
+ } while (cSt.getMoreResults());
+ System.out.println("JIRA-491 Successful.");
+ }
+ catch (Exception e)
+ {
+ System.out.println("JIRA-491 FAILURE: Caught Exception:");
+ e.printStackTrace(System.out);
+ }
+
+ // JIRA-492: Result set has hundreds of columns.
+ // This test case, when originally filed, exposed several problems:
+ // - first, this test case causes the server to respond with a very
+ // long response message which gets handled using DRDA Layer B DSS
+ // segmentation. This long message was corrupted due to bug DERBY-125.
+ // - then, the test case causes the server to perform LMTBLKPRC
+ // message truncation in a situation in which there are multiple
+ // chained messages in the DDMWriter buffer. Due to bug DERBY-491/2,
+ // the message truncation logic truncated not only the last DSS block,
+ // but also the multi-segment long message which was still sitting
+ // unsent in the buffer.This then caused a HANG in the client, which
+ // waited forever for the never-to-be-sent truncated data.
+
+ try {
+ st.execute("drop table jira492");
+ } catch (SQLException se) {}
+
+ try {
+ st.execute("create table jira492 (id integer, nsi smallint, " +
+ "ni integer, nbi DECIMAL(19,0), nd decimal(7,2), nr real, " +
+ "ndo double)");
+ st.execute("insert into jira492 values (" +
+ "1, 2, 3, 4.5, 6.7, 8.9, 10.11)");
+ } catch (SQLException se) {
+ System.out.println("JIRA-492: FAILURE in data setup:");
+ se.printStackTrace(System.out);
+ }
+
+ try {
+ st.execute("drop procedure TEST_PROC_JIRA_492");
+ } catch (SQLException se) {}
+
+ try {
+ st.execute("create procedure TEST_PROC_JIRA_492() " +
+ "language java parameter style java external name " +
+ "'org.apache.derbyTesting.functionTests.util.ProcedureTest.LOTS_O_COLS_492' result sets 1");
+ } catch (SQLException se) {
+ System.out.println("JIRA-492: FAILURE in procedure creation:");
+ se.printStackTrace(System.out);
+ }
+
+ cSt = conn.prepareCall("call TEST_PROC_JIRA_492()");
+ cSt.execute();
+ System.out.println("JIRA-492 successful -- no hang!");
+ }
private static void executeProcedure(Statement s, String sql) throws SQLException {
boolean firstResultIsAResultSet = s.execute(sql);
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java?rev=398093&r1=398092&r2=398093&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/util/ProcedureTest.java Fri Apr 28 22:41:18 2006
@@ -737,5 +737,46 @@
conn.close();
return count;
}
+
+ // Procedure used by the test for bug JIRA-491. The client side part
+ // of this test is in lang/procedure.java
+
+ public static void BIG_COL_491 (int i, ResultSet [] rs1, ResultSet [] rs2)
+ throws SQLException
+ {
+ Connection conn = DriverManager.getConnection("jdbc:default:connection");
+ Statement st1 = conn.createStatement();
+ rs1[0] = st1.executeQuery(
+ "select int1, varchar32k from jira491 where int1 < " + i + " order by 1");
+
+ Statement st2 = conn.createStatement();
+ rs2[0] = st2.executeQuery(
+ "select int1, varchar32k from jira491 where int1 > " + i + " order by 1");
+ }
+
+ // Procedure used by the test for bug JIRA-492. The client side part of
+ // this test is in lang/procedure.java
+
+ public static void LOTS_O_COLS_492(ResultSet [] rs)
+ throws SQLException
+ {
+ Connection conn = DriverManager.getConnection("jdbc:default:connection");
+ Statement st1 = conn.createStatement();
+
+ StringBuffer query = new StringBuffer("SELECT ");
+ for (int i = 0; i < 100; i++)
+ {
+ int cno = 1000 + (i * 10);
+ if (i > 0) query.append(", ");
+ query.append("id AS col").append(cno).append(", nsi as col").
+ append(cno+1).append(", ni AS col").append(cno+2).
+ append(", nbi AS col").append(cno+3).append(", nd AS col").
+ append(cno+4).append(", nr AS col").append(cno+5).
+ append(", ndo AS col").append(cno+6).append(" ");
+ }
+ query.append("FROM jira492 a WHERE a.id = 0");
+
+ rs[0] = st1.executeQuery(query.toString());
+ }
}