--- PreparedStatement.java	Sat Feb 17 01:45:00 2001
+++ PreparedStatement.java.new	Wed Jun 20 12:34:57 2001
@@ -39,10 +39,12 @@
         // Some performance caches
         private StringBuffer sbuf = new StringBuffer();
 
-        // We use ThreadLocal for SimpleDateFormat's because they are not that
-        // thread safe, so each calling thread has its own object.
-        private ThreadLocal tl_df   = new ThreadLocal(); // setDate() SimpleDateFormat
-        private ThreadLocal tl_tsdf = new ThreadLocal(); // setTimestamp() SimpleDateFormat
+	// Because SimpleDateFormat is not thread safe we create one for each
+	// PreparedStatemnt here AND synchronize on it for each usage.
+	// We can NOT use ThreadLocal because they are not freed until the thread
+	// completes. This would be a memory leak for long running threads.
+	private SimpleDateFormat df = null;
+	private SimpleDateFormat tsdf = null;
 
 	/**
 	 * Constructor for the PreparedStatement class.
@@ -90,9 +92,6 @@
          * New in 7.1 - overides Statement.close() to dispose of a few local objects
          */
         public void close() throws SQLException {
-          // free the ThreadLocal caches
-          tl_df.set(null);
-
           super.close();
         }
 
@@ -332,14 +331,18 @@
 	 */
 	public void setDate(int parameterIndex, java.sql.Date x) throws SQLException
 	{
-          SimpleDateFormat df = (SimpleDateFormat) tl_df.get();
-          if(df==null) {
+		// The df DateFormat is initialized here to delay creation until needed.
+		if( df == null ) {
+			synchronized( this ) {
+				if( df == null ) {
             df = new SimpleDateFormat("''yyyy-MM-dd''");
-            tl_df.set(df);
+				}
+			}
           }
 
-	  set(parameterIndex, df.format(x));
-
+		// We must synchronize here because SimpleDateFormat is not thread safe.
+		synchronized( df ) {
+			set( parameterIndex, df.format(x) );
 	  // The above is how the date should be handled.
 	  //
 	  // However, in JDK's prior to 1.1.6 (confirmed with the
@@ -351,6 +354,7 @@
 	  //
 	  //set(parameterIndex, df.format(new java.util.Date(x.getTime()+86400000)));
 	}
+	}
 
 	/**
 	 * Set a parameter to a java.sql.Time value.  The driver converts
@@ -375,17 +379,22 @@
 	 */
 	public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
         {
-          SimpleDateFormat df = (SimpleDateFormat) tl_tsdf.get();
-          if(df==null) {
-            df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            tl_tsdf.set(df);
+		// The tsdf DateFormat is initialized here to delay creation until needed.
+		if( tsdf == null ) {
+			synchronized( this ) {
+				if( tsdf == null ) {
+					tsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+					tsdf.setTimeZone(TimeZone.getTimeZone("GMT"));
+				}
+			}
           }
-          df.setTimeZone(TimeZone.getTimeZone("GMT"));
 
+		// We must synchronize here because SimpleDateFormat is not thread safe.
+		synchronized( tsdf ) {
           // Use the shared StringBuffer
           synchronized(sbuf) {
             sbuf.setLength(0);
-            sbuf.append("'").append(df.format(x)).append('.').append(x.getNanos()/10000000).append("+00'");
+				sbuf.append("'").append(tsdf.format(x)).append('.').append(x.getNanos()/10000000).append("+00'");
             set(parameterIndex, sbuf.toString());
           }
 
@@ -393,6 +402,7 @@
           // to be identical. Pays to read the docs ;-)
           //set(parameterIndex,"'"+x.toString()+"'");
 	}
+	}
 
 	/**
 	 * When a very large ASCII value is input to a LONGVARCHAR parameter,
