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 03:29:37 UTC

svn commit: r398058 - 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/jdk15/ testing/org/apache/derbyTesting/func...

Author: bpendleton
Date: Fri Apr 28 18:29:36 2006
New Revision: 398058

URL: http://svn.apache.org/viewcvs?rev=398058&view=rev
Log:
DERBY-125: Network Server can send DSS greater than 32K to client

This change migrates the fix to this issue 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/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out
    db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out
    db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out
    db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.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=398058&r1=398057&r2=398058&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 18:29:36 2006
@@ -1433,6 +1433,54 @@
 			ensureLength (shiftSize);
 			offset += shiftSize;
 
+			// Notes on the behavior of the Layer B segmenting loop below:
+			//
+			// We start with the right most chunk. For a 3-segment object we'd
+			// shift 2 segments: shift the first (rightmost) one 4 bytes and 
+			// the second one 2. Note that by 'first' we mean 'first time
+			// through the loop', but that is actually the last segment
+			// of data since we are moving right-to-left. For an object
+			// of K segments we will pass through this loop K-1 times.
+			// The 0th (leftmost) segment is not shifted, as it is
+			// already in the right place. When we are done, we will
+			// have made room in each segment for an additional
+			// 2 bytes for the continuation header. Thus, each
+			// segment K is shifted K*2 bytes to the right.
+			//
+			// Each time through the loop, "dataByte" points to the
+			// last byte in the segment; "dataToShift" is the amount of
+			// data that we need to shift, and "shiftSize" is the
+			// distance that we need to shift it. Since dataByte points
+			// at the last byte, not one byte beyond it (as with the
+			// "offset" variable used elsewhere in DDMWriter), the start
+			// of the segement is actually at (dataByte-dataToShift+1).
+			//
+			// After we have shifted the segment, we move back to the
+			// start of the segment and set the value of the 2-byte DSS
+			// continuation header, which needs to hold the length of
+			// this segment's data, together with the continuation flag
+			// if this is not the rightmost (passOne) segment.
+			//
+			// In general, each segment except the rightmost will contain
+			// 32765 bytes of data, plus the 2-byte header, and its
+			// continuation flag will be set, so the header value will
+			// be 0xFFFF. The rightmost segment will not have the
+			// continuation flag set, so its value may be anything from
+			// 0x0001 to 0x7FFF, depending on the amount of data in that
+			// segment.
+			//
+			// Note that the 0th (leftmost) segment also has a 2-byte
+			// DSS header, which needs to have its continuation flag set.
+			// This is done by resetting the "totalSize" variable below,
+			// at which point that variable no longer holds the total size
+			// of the object, but rather just the length of segment 0. The
+			// total size of the object was written using extended length
+			// bytes by the endDdm() method earlier.
+			//
+			// Additional information about this routine is available in the
+			// bug notes for DERBY-125:
+			// http://issues.apache.org/jira/browse/DERBY-125
+			
 			// mark passOne to help with calculating the length of the final (first or
 			// rightmost) continuation header.
 			boolean passOne = true;
@@ -1441,12 +1489,7 @@
 				int dataToShift = bytesRequiringContDssHeader % 32765;
 				if (dataToShift == 0)
 					dataToShift = 32765;
-				// We start with the right most chunk. If we had to copy two
-				// chunks we would shift the first one 4 bytes and then 
-				// the second one
-				// 2 when we come back on the next loop so they would each have
-				// 2 bytes for the continuation header
-				int startOfCopyData = dataByte - dataToShift;
+				int startOfCopyData = dataByte - dataToShift + 1;
 				System.arraycopy(bytes,startOfCopyData, bytes, 
 								 startOfCopyData + shiftSize, dataToShift);
 				dataByte -= dataToShift;
@@ -1462,7 +1505,9 @@
 				else
 				{
 					if (twoByteContDssHeader == DssConstants.MAX_DSS_LENGTH)
-				    	twoByteContDssHeader = DssConstants.CONTINUATION_BIT;
+					twoByteContDssHeader = (twoByteContDssHeader |
+						DssConstants.CONTINUATION_BIT);
+
 				}
 
 				// insert the header's length bytes
@@ -1481,7 +1526,9 @@
 			while (bytesRequiringContDssHeader > 0);
 
 			// set the continuation dss header flag on for the first header
-			totalSize = DssConstants.CONTINUATION_BIT;
+			totalSize = (DssConstants.MAX_DSS_LENGTH |
+					DssConstants.CONTINUATION_BIT);
+
 
 		}
 

Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out?rev=398058&r1=398057&r2=398058&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out Fri Apr 28 18:29:36 2006
@@ -77,4 +77,6 @@
 SQLState: 22007 message: The syntax of the string representation of a datetime value is incorrect.
 Test jira614 completed successfully -- no Distributed Protocol Exception occurred
 Jira170: caught expected table not found
+Iteration 1 successful: 555 parameter markers successfully prepared and executed.
+Test jira125 successful: 557 parameter markers successfully prepared and executed.
 prepStmt Test Ends

Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out?rev=398058&r1=398057&r2=398058&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out Fri Apr 28 18:29:36 2006
@@ -77,4 +77,6 @@
 SQLState: 22007 message: The syntax of the string representation of a datetime value is incorrect.
 Test jira614 completed successfully -- no Distributed Protocol Exception occurred
 Jira170: caught expected table not found
+Iteration 1 successful: 555 parameter markers successfully prepared and executed.
+Test jira125 successful: 557 parameter markers successfully prepared and executed.
 prepStmt Test Ends

Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out?rev=398058&r1=398057&r2=398058&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out Fri Apr 28 18:29:36 2006
@@ -77,4 +77,6 @@
 SQLState: 22007 message: The syntax of the string representation of a datetime value is incorrect.
 Test jira614 completed successfully -- no Distributed Protocol Exception occurred
 Jira170: caught expected table not found
+Iteration 1 successful: 555 parameter markers successfully prepared and executed.
+Test jira125 successful: 557 parameter markers successfully prepared and executed.
 prepStmt Test Ends

Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java?rev=398058&r1=398057&r2=398058&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java (original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java Fri Apr 28 18:29:36 2006
@@ -304,6 +304,7 @@
 			jira614Test(conn);
 			jira614Test_a(conn);
 			jira170Test(conn);
+			jira125Test(conn);
 			conn.close();
 			System.out.println("prepStmt Test Ends");
         }
@@ -818,5 +819,121 @@
                 e.printStackTrace();
         }
     }
-}
+	/**
+	 * Jira-125 has to do with proper use of continuation headers 
+	 * for very large reply messages, such as the SQLDARD which is
+	 * returned for a prepared statement with an enormous number of
+	 * parameter markers. This test generates a multi-segment SQLDARD
+	 * response message from the server, to verify that the code in
+	 * DDMWriter.finalizeDSSLength is executed.
+	 *
+	 * Repro for DERBY-125 off-by-one error.  This repro runs in
+	 * two iterations.  The first iteration, we use a table name
+	 * and a column name that are extra long, so that the server-
+	 * side buffer has more data in it.  The second iteration, we
+	 * use simpler names for the table and column, which take up
+	 * less space in the server buffer.  Then, since the server-
+	 * side bytes array was previously used for a larger amount of
+	 * data, then the unused bytes contain old data.  Since we
+	 * intentionally put the "larger amount of data" into the buffer
+	 * during the first iteration, we know what the old data bytes
+	 * are going to be.  Thus, by using specific lengths for the 
+	 * table and column names, we can 'shift' the old data until we
+	 * reach a point where the off-by-one error manifests itself:
+	 * namely, we end up incorrectly leaving a non-zero data byte
+	 * in the last position of the current server buffer, which
+	 * is wrong.
+	 */
+
+    private static void jira125Test(Connection conn)
+        throws Exception
+    {
+		jira125Test_a(conn);
+		jira125Test_b(conn);
+    }
 
+    private static void jira125Test_b(Connection conn)
+	    throws Exception
+    {
+	    Statement stmt = conn.createStatement();
+        PreparedStatement ps ;
+	    try {
+		    stmt.execute("drop table jira125");
+	    } catch (Throwable t) { }
+		try {
+	        stmt.execute("create table jira125 (id integer)");
+			stmt.execute("insert into jira125 values 1, 2, 3");
+		} catch (Throwable t) { }
+        StringBuffer buf = new StringBuffer();
+        buf.append("SELECT id FROM jira125 WHERE id IN ( ");
+
+		// Must have at least 551 columns here, in order to force
+		// server buffer beyond 32k.  NOTE: Changing this number
+		// could cause the test to "pass" even if a regression
+		// occurs--so only change it if needed!
+        int nCols = 556;
+        for (int i = 0; i < nCols; i++) buf.append("?,");
+        buf.append("?)");
+        ps = conn.prepareStatement(buf.toString());
+        // Note that we actually have nCols+1 parameter markers
+        for (int i = 0; i <= nCols; i++) ps.setInt(i+1, 1);
+        ResultSet rs = ps.executeQuery();
+        while (rs.next());
+        System.out.println("Test jira125 successful: " + (nCols + 1) +
+			" parameter markers successfully prepared and executed.");
+    }
+
+    private static void jira125Test_a(Connection conn)
+	    throws Exception
+    {
+	    Statement stmt = conn.createStatement();
+
+		// Build a column name that is 99 characters long;
+		// the length of the column name and the length of
+		// the table name are important to the repro--so
+		// do not change these unless you can confirm that
+		// the new values will behave in the same way.
+		StringBuffer id = new StringBuffer();
+		for (int i = 0; i < 49; i++)
+			id.append("id");
+		id.append("i");
+
+		// Build a table name that is 97 characters long;
+		// the length of the column name and the length of
+		// the table name are important to the repro--so
+		// do not change these unless you can confirm that
+		// the new values will behave in the same way.
+		StringBuffer tabName = new StringBuffer("jira");
+		for (int i = 0; i < 31; i++)
+			tabName.append("125");
+
+	    try {
+		    stmt.execute("drop table " + tabName.toString());
+	    } catch (Throwable t) { }
+		try {
+	        stmt.execute("create table " + tabName.toString() + " (" +
+				id.toString() + " integer)");
+			stmt.execute("insert into " + tabName.toString() + " values 1, 2, 3");
+		} catch (Throwable t) { }
+
+        PreparedStatement ps;
+        StringBuffer buf = new StringBuffer();
+        buf.append("SELECT " + id.toString() + " FROM " +
+			tabName.toString() + " WHERE " + id.toString() + " IN ( ");
+
+		// Must have at least 551 columns here, in order to force
+		// server buffer beyond 32k.  NOTE: Changing this number
+		// could cause the test to "pass" even if a regression
+		// occurs--so only change it if needed!
+        int nCols = 554;
+        for (int i = 0; i < nCols; i++) buf.append("?,");
+        buf.append("?)");
+        ps = conn.prepareStatement(buf.toString());
+        // Note that we actually have nCols+1 parameter markers
+        for (int i = 0; i <= nCols; i++) ps.setInt(i+1, 1);
+        ResultSet rs = ps.executeQuery();
+        while (rs.next());
+        System.out.println("Iteration 1 successful: " + (nCols + 1) +
+			" parameter markers successfully prepared and executed.");
+    }
+}