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 ka...@apache.org on 2006/10/25 13:52:06 UTC

svn commit: r467612 - in /db/derby/code/trunk/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/functionTest...

Author: kahatlen
Date: Wed Oct 25 04:52:05 2006
New Revision: 467612

URL: http://svn.apache.org/viewvc?view=rev&rev=467612
Log:
DERBY-815: Prevent unneeded object creation and excessive decoding in
parseSQLDTA_work()

Patch contributed by Dyre Tjeldvoll.

Modified:
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?view=diff&rev=467612&r1=467611&r2=467612
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Wed Oct 25 04:52:05 2006
@@ -4111,9 +4111,10 @@
 		PreparedStatement ps = stmt.getPreparedStatement();
 		int codePoint;
 		EngineParameterMetaData pmeta = null;
-		Vector paramDrdaTypes = new Vector();
-		Vector paramLens = new Vector();
-		ArrayList paramExtPositions = null;
+
+		// Clear params without releasing storage
+		stmt.clearDrdaParams();
+
 		int numVars = 0;
 		boolean rtnParam = false;
 
@@ -4135,17 +4136,17 @@
 						reader.readByte();		// id
 						for (int j = 0; j < numVarsInGrp; j++)
 						{
-							paramDrdaTypes.addElement(new Byte(reader.readByte()));
+							final byte t = reader.readByte();
 							if (SanityManager.DEBUG) 
 								trace("drdaType is: "+ "0x" +
-       								  Integer.toHexString(((Byte ) paramDrdaTypes.lastElement()).byteValue()));
+       								  Integer.toHexString(t));
 							int drdaLength = reader.readNetworkShort();
 							if (SanityManager.DEBUG) 
 								trace("drdaLength is: "+drdaLength);
-							paramLens.addElement(new Integer(drdaLength));
+							stmt.addDrdaParam(t, drdaLength);
 						}
 					}
-					numVars = paramDrdaTypes.size();
+					numVars = stmt.getDrdaParamCount();
 					if (SanityManager.DEBUG)
 						trace("numVars = " + numVars);
 					if (ps == null)		// it is a CallableStatement under construction
@@ -4197,7 +4198,7 @@
 					for (int i = 0; i < numVars; i++)
 					{
 					
-						if ((((Byte)paramDrdaTypes.elementAt(i)).byteValue() & 0x1) == 0x1)	// nullable
+						if ((stmt.getParamDRDAType(i+1) & 0x1) == 0x1)	// nullable
 						{
 							int nullData = reader.readUnsignedByte();
 							if ((nullData & 0xFF) == FdocaConstants.NULL_DATA)
@@ -4214,15 +4215,8 @@
 						}
 
 						// not null, read and set it
-						paramExtPositions = readAndSetParams(i, stmt,
-															 ((Byte)paramDrdaTypes.elementAt(i)).byteValue(),
-															 pmeta,
-															 paramExtPositions,
-															 ((Integer)(paramLens.elementAt(i))).intValue());
+						readAndSetParams(i, stmt, pmeta);
 					}
-					stmt.cliParamExtPositions = paramExtPositions;
-					stmt.cliParamDrdaTypes = paramDrdaTypes;
-					stmt.cliParamLens = paramLens;	
 					break;
 				case CodePoint.EXTDTA:
 					readAndSetAllExtParams(stmt, false);
@@ -4244,27 +4238,25 @@
 	}
 
 	/**
-	 * Read different types of input parameters and set them in PreparedStatement
+	 * Read different types of input parameters and set them in
+	 * PreparedStatement
 	 * @param i			index of the parameter
-	 * @param stmt       drda statement
-	 * @param drdaType	drda type of the parameter
+	 * @param stmt      drda statement
 	 * @param pmeta		parameter meta data
-	 * @param paramExtPositions  ArrayList of parameters with extdta
-	 * @param paramLenNumBytes Number of bytes for encoding LOB Length
 	 *
-	 * @return updated paramExtPositions
 	 * @throws DRDAProtocolException
      * @throws SQLException
 	 */
-	private ArrayList readAndSetParams(int i, DRDAStatement stmt, int
-									   drdaType, EngineParameterMetaData pmeta,
-									   ArrayList paramExtPositions,
-									   int paramLenNumBytes)
+	private void readAndSetParams(int i,
+								  DRDAStatement stmt,
+								  EngineParameterMetaData pmeta)
 				throws DRDAProtocolException, SQLException
 	{
 		PreparedStatement ps = stmt.getPreparedStatement();
+
 		// mask out null indicator
-		drdaType = ((drdaType | 0x01) & 0x000000ff);
+		final int drdaType = ((stmt.getParamDRDAType(i+1) | 0x01) & 0xff);
+		final int paramLenNumBytes = stmt.getParamLen(i+1);
 
 		if (ps instanceof CallableStatement)
 		{
@@ -4425,9 +4417,7 @@
 				 long length = readLobLength(paramLenNumBytes);
 				 if (length != 0) //can be -1 for CLI if "data at exec" mode, see clifp/exec test
 				 {
-					if (paramExtPositions == null)
-						 paramExtPositions = new ArrayList();
-				 	paramExtPositions.add(new Integer(i));
+					stmt.addExtPosition(i);
 				 }
 				 else   /* empty */
 				 {
@@ -4446,7 +4436,6 @@
 				ps.setObject(i+1, paramVal);
 			}
 		}
-		return paramExtPositions;
 	}
 
 	private long readLobLength(int extLenIndicator) 
@@ -4475,15 +4464,15 @@
 	private void readAndSetAllExtParams(final DRDAStatement stmt, final boolean streamLOB) 
 		throws SQLException, DRDAProtocolException
 	{
-		int numExt = stmt.cliParamExtPositions.size();
-		for (int i = 0; i < stmt.cliParamExtPositions.size(); i++)
+		final int numExt = stmt.getExtPositionCount();
+		for (int i = 0; i < numExt; i++)
 					{
-						int paramPos = ((Integer) (stmt.cliParamExtPositions).get(i)).intValue();
+						int paramPos = stmt.getExtPosition(i);
 						final boolean doStreamLOB = (streamLOB && i == numExt -1);
 						readAndSetExtParam(paramPos,
 										   stmt,
-										   ((Byte)stmt.cliParamDrdaTypes.elementAt(paramPos)).intValue(),
-										   ((Integer)(stmt.cliParamLens.elementAt(paramPos))).intValue(),
+										   stmt.getParamDRDAType(paramPos+1),
+										   stmt.getParamLen(paramPos+1),
 										   doStreamLOB);
 						// Each extdta in it's own dss
 						if (i < numExt -1)
@@ -6452,7 +6441,7 @@
 		else	// it's for a CallableStatement
 		{
 			hasdata = stmt.hasOutputParams();
-			numCols = stmt.getNumParams();
+			numCols = stmt.getDrdaParamCount();
 		}
 
 

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java?view=diff&rev=467612&r1=467611&r2=467612
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java Wed Oct 25 04:52:05 2006
@@ -35,6 +35,7 @@
 import java.util.Hashtable;
 import java.util.StringTokenizer;
 import java.util.Vector;
+import java.lang.reflect.Array;
 
 import org.apache.derby.iapi.jdbc.BrokeredConnection;
 import org.apache.derby.iapi.jdbc.BrokeredPreparedStatement;
@@ -98,10 +99,130 @@
 	private ArrayList resultSetKeyList;  // ordered list of hash keys
 	private int numResultSets = 0;  
 
-	// State for parameter data
-	protected  Vector cliParamDrdaTypes = new Vector();
-	protected Vector cliParamLens = new Vector();
-	protected ArrayList cliParamExtPositions = null;
+	/** This class is used to keep track of the statement's parameters
+	 * as they are received from the client. It uses arrays to track
+	 * the DRDA type, the length in bytes and the externalness of each
+	 * parameter. Arrays of int/byte are used rather than ArrayLists
+	 * of Integer/Byte in order to re-use the same storage each time
+	 * the statement is executed. */
+	private static class DrdaParamState {
+		private int typeLstEnd_ = 0;
+		private byte[] typeLst_ = new byte[10];
+		private int[]  lenLst_ = new int[10];
+		private int extLstEnd_ = 0;
+		private int[]  extLst_ = new int[10];
+
+		private static Object growArray(Object array) {
+			final int oldLen = Array.getLength(array);
+			Object tmp =
+				Array.newInstance(array.getClass().getComponentType(),
+								  Math.max(oldLen,1)*2);
+			System.arraycopy(array, 0, tmp, 0, oldLen);
+			return tmp;
+		}
+
+		/**
+		 * <code>clear</code> resets the arrays so that new parameters
+		 * will be added at the beginning. No initialization or
+		 * releasing of storage takes place unless the trim argument
+		 * is true.
+		 *
+		 * @param trim - if true; release excess storage
+		 */
+		protected void clear(boolean trim) {
+			typeLstEnd_ = 0;
+			extLstEnd_ = 0;
+			if (trim && typeLst_.length > 10) {
+				typeLst_ = new byte[10];
+				lenLst_ = new int[10];
+				extLst_ = new int[10];
+			}
+		}
+
+		/**
+		 * <code>addDrdaParam</code> adds a new parameter with its
+		 * DRDA type and byte length. The arrays are automatically
+		 * grown if needed.
+		 *
+		 * @param t a <code>byte</code> value, the DRDA type of the
+		 * parameter being added
+		 * @param s an <code>int</code> value, the length in bytes of
+		 * the parameter being added
+		 */
+		protected void addDrdaParam(byte t, int s) {
+			if (typeLstEnd_ >= typeLst_.length) {
+				typeLst_ = (byte[])growArray(typeLst_);
+				lenLst_ = (int[])growArray(lenLst_);
+			}
+			typeLst_[typeLstEnd_] = t;
+			lenLst_[typeLstEnd_] = s;
+			++typeLstEnd_;
+		}
+
+		/**
+		 * <code>getDrdaParamCount</code> return the number of
+		 * parameters added so far (since last clear).
+		 *
+		 * @return an <code>int</code> value, the number of parameters
+		 */
+		protected int  getDrdaParamCount() { return typeLstEnd_; }
+
+		/**
+		 * <code>getDrdaType</code> returns a byte that represents the
+		 * DRDA type of the ith parameter.
+		 *
+		 * @param i an <code>int</code> value, a parameter position
+		 * (zero-based)
+		 * @return a <code>byte</code> value, the DRDA type
+		 */
+		protected byte getDrdaType(int i) { return typeLst_[i]; }
+
+		/**
+		 * <code>getDrdaLen</code> returns the length in bytes of the
+		 * ith parameter.
+		 *
+		 * @param i an <code>int</code> value, a parameter position
+		 * (zero-based)
+		 * @return an <code>int</code> value
+		 */
+		protected int getDrdaLen(int i) { return lenLst_[i]; }
+
+		/**
+		 * <code>addExtPos</code> marks parameter i as external. The
+		 * array is grown as needed.
+		 *
+		 * @param p an <code>int</code> value, a parameter position
+		 * (zero-based)
+		 */
+		protected void addExtPos(int p) {
+			if (extLstEnd_ >= extLst_.length) {
+				extLst_ = (int[])growArray(extLst_);
+			}
+			extLst_[extLstEnd_] = p;
+			++extLstEnd_;
+		}
+
+		/**
+		 * <code>getExtPosCount</code> returns the number of
+		 * parameters marked as external so far (since last clear).
+		 *
+		 * @return an <code>int</code> value, the number of external
+		 * parameters.
+		 */
+		protected int getExtPosCount() { return extLstEnd_; }
+
+		/**
+		 * <code>getExtPos</code> returns the actual parameter position
+		 * of the ith external parameter.
+		 *
+		 * @param i an <code>int</code> value, index into the list of
+		 * external parameters, zero-based
+		 * @return an <code>int</code> value, the parameter position
+		 * of the ith external parameter (zero-based)
+		 */
+		protected int getExtPos(int i) { return extLst_[i]; }
+	}
+	private DrdaParamState drdaParamState_ = new DrdaParamState();
 
 	// Query options  sent on EXCSQLSTT
 	// These the default for ResultSets created for this statement.
@@ -974,10 +1095,8 @@
 		rslsetflg = null;
 		procName = null;
 		outputTypes = null;
-		cliParamDrdaTypes = null;
-		cliParamLens = null;
-		cliParamExtPositions = null;
-
+		// Clear parameters and release excess storage
+		drdaParamState_.clear(true);
 	}
 	
 	/**
@@ -1015,9 +1134,8 @@
 		resultSetKeyList = null;
 		numResultSets = 0;
 		
-		cliParamDrdaTypes = new Vector();
-		cliParamLens = new Vector();
-		cliParamExtPositions = null;
+		// Clear parameters without releasing storage
+		drdaParamState_.clear(false);
 		
 		nbrrow = 0;
 		qryrowset = 0;	
@@ -1104,42 +1222,76 @@
 		
 	}
 
-	
-	/**
-	 * get parameter DRDAType
-	 *
-	 * @param index - starting with 1
-	 * @return  DRDA Type of column
+	/** Clears the parameter state (type, length and ext information)
+	 * stored in this statement, but does not release any
+	 * storage. This reduces the cost of re-executing the statement
+	 * since no new storage needs to be allocated. */
+	protected void clearDrdaParams() {
+		drdaParamState_.clear(false);
+	}
+
+	/** Get the number of external parameters in this
+	 * statement. External means parameters that are transmitted in a
+	 * separate DSS in the DRDA protocol.
+	 * @return the number of external parameters
 	 */
-	protected int getParamDRDAType(int index)
-	{
-		
-		return ((Byte)cliParamDrdaTypes.get(index -1)).intValue();
+	protected int getExtPositionCount() {
+		return drdaParamState_.getExtPosCount();
 	}
 
+	/** Get the parameter position of the i'th external parameter
+	 * @param i - zero-based index into list of external parameters
+	 * @return the parameter position of the i'th external parameter
+	 */
+	protected int getExtPosition(int i) {
+		return drdaParamState_.getExtPos(i);
+	}
+
+	/** Mark the pos'th parameter as external
+	 * @param pos - zero-based index into list of external parameters
+	 */
+	protected void addExtPosition(int pos) {
+		drdaParamState_.addExtPos(pos);
+	}
+
+	/** Get the number of parameters, internal and external, that has
+	 * been added to this statement.
+	 * @return the number of parameters
+	 */
+	protected int getDrdaParamCount() {
+		return drdaParamState_.getDrdaParamCount();
+	}
+
+	/** Add another parameter to this statement.
+	 * @param t - type of the parameter
+	 * @param l - length in bytes of the parameter
+	 */
+	protected void addDrdaParam(byte t, int l) {
+		drdaParamState_.addDrdaParam(t, l);
+	}
 
 	/**
-	 * set param  DRDAType
+	 * get parameter DRDAType
 	 *
 	 * @param index - starting with 1
-	 * @param type
+	 * @return  DRDA Type of column
 	 */
-	protected  void setParamDRDAType(int index, byte type)
-	{
-		cliParamDrdaTypes.addElement(new Byte(type));
-		
-	}
+ 	protected int getParamDRDAType(int index) {
+		return drdaParamState_.getDrdaType(index-1);
+ 	}
+
 	/**
 	 * returns drda length of parameter as sent by client.
-	 * @param index
+	 * @param index - starting with 1
 	 * @return data length
 
 	 */
-
 	protected int getParamLen(int index)
 	{
-		return ((Integer) cliParamLens.elementAt(index -1)).intValue();
+		return drdaParamState_.getDrdaLen(index-1);
 	}
+
+
 	/**
 	 *  get parameter precision or DB2 max (31)
 	 *
@@ -1179,30 +1331,6 @@
 			return -1;
 	}
 
-	/**
-	 * save parameter len sent by client
-	 * @param index parameter index starting with 1
-	 * @param value  length of data value
-	 *
-	 */
-	protected void  setParamLen(int index, int value)
-	{
-		cliParamLens.add(index -1, new Integer(value));
-	}
-
-	/**
-	 * get the number of parameters for this statement
-	 * 
-	 * @return number of parameters
-	 */
-	protected int getNumParams()
-	{
-		if (cliParamDrdaTypes != null)
-			return cliParamDrdaTypes.size();
-		else
-			return 0;
-	}
-	   
 	/** 
 	 * get the number of result set columns for the current resultSet
 	 * 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out?view=diff&rev=467612&r1=467611&r2=467612
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/jdk15/prepStmt.out Wed Oct 25 04:52:05 2006
@@ -79,6 +79,14 @@
 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.
+Inserting first row...
+  -> Succeeded.
+Inserting second row...
+  -> Succeeded.
+Now inserting 3rd row, using lobs from 1st row...
+  -> Succeeded.
+Now inserting 4th row, using lobs from 2nd row...
+  -> Succeeded.
 JIRA-1454 repro with c2 len=12748
 Fetched a row, c2.length=12748
 JIRA-1454 repro with c2 len=12750

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out?view=diff&rev=467612&r1=467611&r2=467612
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk15/prepStmt.out Wed Oct 25 04:52:05 2006
@@ -79,6 +79,14 @@
 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.
+Inserting first row...
+  -> Succeeded.
+Inserting second row...
+  -> Succeeded.
+Now inserting 3rd row, using lobs from 1st row...
+  -> Succeeded.
+Now inserting 4th row, using lobs from 2nd row...
+  -> Succeeded.
 JIRA-1454 repro with c2 len=12748
 Fetched a row, c2.length=12748
 JIRA-1454 repro with c2 len=12750

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out?view=diff&rev=467612&r1=467611&r2=467612
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/prepStmt.out Wed Oct 25 04:52:05 2006
@@ -79,6 +79,14 @@
 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.
+Inserting first row...
+  -> Succeeded.
+Inserting second row...
+  -> Succeeded.
+Now inserting 3rd row, using lobs from 1st row...
+  -> Succeeded.
+Now inserting 4th row, using lobs from 2nd row...
+  -> Succeeded.
 JIRA-1454 repro with c2 len=12748
 Fetched a row, c2.length=12748
 JIRA-1454 repro with c2 len=12750

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java?view=diff&rev=467612&r1=467611&r2=467612
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/prepStmt.java Wed Oct 25 04:52:05 2006
@@ -26,6 +26,7 @@
 import java.sql.PreparedStatement;
 import java.sql.Statement;
 import java.sql.ResultSet;
+import java.sql.Types;
 import java.math.BigDecimal;
 import java.sql.Date;
 import java.sql.Time;
@@ -322,10 +323,12 @@
 			jira614Test_a(conn);
 			jira170Test(conn);
 			jira125Test(conn);
+			jira815Test(conn);
 			jira428Test(conn);
 			jira1454Test(conn);
                         jira1533Test_a(conn);
                         jira1533Test_b(conn);
+			conn.rollback();
 			conn.close();
 			// refresh conn before cleaning up
 			conn = ij.startJBMS();
@@ -1043,6 +1046,89 @@
         System.out.println("Iteration 1 successful: " + (nCols + 1) +
 			" parameter markers successfully prepared and executed.");
     }
+
+    /**
+     * The first patch for Jira-815 introduced a bug that resulted
+     * in a hang if a prepared statement was first executed with a
+     * lob value, and then re-executed with a null-value in place
+     * of the lob. This test case ensures that the same bug has
+     * not been re-introduced.
+     */
+    private static void jira815Test(Connection conn)
+		throws Exception
+    {
+		conn.setAutoCommit(false);
+		Statement st = conn.createStatement();
+		try {
+			st.execute("drop table tt1");
+		} catch (SQLException se) {}
+
+		st.execute("create table tt1  (CLICOL01 smallint not null)");
+		st.execute("alter table tt1 add clicol02 smallint");
+		st.execute("alter table tt1 add clicol03 int not null default 1");
+		st.execute("alter table tt1 add clicol04 int");
+		st.execute("alter table tt1 add clicol05 decimal(10,0) not null default 1");
+		st.execute("alter table tt1 add clicol51 blob(1G)");
+		st.execute("alter table tt1 add clicol52 blob(50)");
+		st.execute("alter table tt1 add clicol53 clob(2G) not null default ''");
+		st.execute("alter table tt1 add clicol54 clob(60)");
+		conn.commit();
+
+		PreparedStatement pSt =
+			conn.prepareStatement("insert into tt1 values (?,?,?,?,?,?,?,?,?)");
+		pSt.setShort(1, (short)500);
+		pSt.setShort(2, (short)501);
+		pSt.setInt(3, 496);
+		pSt.setInt(4, 497);
+		pSt.setDouble(5, 484);
+		pSt.setBytes(6, "404 bit".getBytes());
+		pSt.setBytes(7, "405 bit".getBytes());
+		pSt.setString(8, "408 bit");
+		pSt.setString(9, "409 bit");
+
+		System.out.println("Inserting first row...");
+		pSt.execute();
+		System.out.println("  -> Succeeded.");
+
+		pSt.setNull(2, Types.SMALLINT);
+		pSt.setNull(4, Types.DOUBLE);
+		pSt.setNull(7, Types.BLOB);
+		pSt.setNull(9, Types.CLOB);
+
+		System.out.println("\nInserting second row...");
+		pSt.execute();
+		System.out.println("  -> Succeeded.");
+
+		System.out.println("\nNow inserting 3rd row, using lobs from 1st row...");
+		ResultSet rs = st.executeQuery("select * from tt1");
+		if (rs.next()) {
+			pSt.setShort(1, rs.getShort(1));
+			pSt.setShort(2, rs.getShort(2));
+			pSt.setInt(3, rs.getInt(3));
+			pSt.setInt(4, rs.getInt(4));
+			pSt.setDouble(5, rs.getDouble(5));
+			pSt.setBlob(6, rs.getBlob(6));
+			pSt.setBlob(7, rs.getBlob(7));
+			pSt.setClob(8, rs.getClob(8));
+			pSt.setClob(9, rs.getClob(9));
+			pSt.execute();
+			System.out.println("  -> Succeeded.");
+		}
+
+		System.out.println("\nNow inserting 4th row, using lobs from 2nd row...");
+		if (rs.next()) {
+			pSt.setNull(2, Types.SMALLINT);
+			pSt.setNull(4, Types.DOUBLE);
+			pSt.setBlob(6, rs.getBlob(6));
+			pSt.setNull(7, Types.BLOB);
+			pSt.setClob(8, rs.getClob(8));
+			pSt.setNull(9, Types.CLOB);
+			pSt.execute();
+			System.out.println("  -> Succeeded.");
+		}
+		conn.commit();
+    }
+
     // Jira 1533 involves two different bugs regarding the handling of large
     // amounts of parameter data: first, the Network Server was incorrectly
     // handling the desegmentation of continued DSS segements, and second,