List:Commits« Previous MessageNext Message »
From:mmatthews Date:November 28 2007 11:08pm
Subject:Connector/J commit: r6688 - in trunk: . src/com/mysql/jdbc src/com/mysql/jdbc/jdbc2/optional src/testsuite/regression
View as plain text  
Modified:
   trunk/
   trunk/CHANGES
   trunk/src/com/mysql/jdbc/BufferRow.java
   trunk/src/com/mysql/jdbc/ByteArrayRow.java
   trunk/src/com/mysql/jdbc/ConnectionImpl.java
   trunk/src/com/mysql/jdbc/ConnectionProperties.java
   trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
   trunk/src/com/mysql/jdbc/EscapeProcessor.java
   trunk/src/com/mysql/jdbc/LocalizedErrorMessages.properties
   trunk/src/com/mysql/jdbc/PreparedStatement.java
   trunk/src/com/mysql/jdbc/ResultSetImpl.java
   trunk/src/com/mysql/jdbc/ResultSetRow.java
   trunk/src/com/mysql/jdbc/ServerPreparedStatement.java
   trunk/src/com/mysql/jdbc/StatementImpl.java
   trunk/src/com/mysql/jdbc/TimeUtil.java
   trunk/src/com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.java
   trunk/src/testsuite/regression/ResultSetRegressionTest.java
   trunk/src/testsuite/regression/StatementRegressionTest.java
Log:
Merged revisions
6585-6586,6593-6597,6599-6602,6605,6607-6609,6612,6614-6617,6619-6620,6623-6627,6632,6636-6638,6641,6649,6658-6659,6663,6665-6673,6676,6681-6682,6684,6686-6687
via svnmerge from 
svn+ssh://mmatthews@stripped/connectors-svnroot/connector-j/branches/branch_5_1

.......
  r6687 | mmatthews | 2007-11-28 15:50:11 -0600 (Wed, 28 Nov 2007) | 15 lines
  
  Fixed BUG#32577 - no way to store two timestamp/datetime values that happens
  
        over the DST switchover, as the hours end up being the same when sent as
  
        the literal that MySQL requires.
  
  
  
        Note that to get this scenario to work with MySQL (since it doesn't support
  
        per-value timezones), you need to configure your server (or session) to be in UTC
(which doesn't have DST),
  
        and tell the driver not to use the legacy date/time code by setting
  
        "useLegacyDatetimeCode" to "false". This will cause the driver to always convert
  
        to/from the server and client timezone consistently.
  
        
  
        This bug fix also fixes BUG#15604, by adding entirely new date/time handling
  
        code that can be switched on by "useLegacyDatetimeCode" being set to "false" as
  
        a JDBC configuration property. For Connector/J 5.1.x, the default is "true",
  
        in trunk and beyond it will be "false" (i.e. the old date/time handling code,
warts
  
        and all will be deprecated).
.......



Property changes on: trunk
___________________________________________________________________
Name: svnmerge-integrated
   - /branches/branch_5_0:1-6636,6638-6670 /branches/branch_5_1:1-6582,6584-6678,6680-6685
   + /branches/branch_5_0:1-6636,6638-6670 /branches/branch_5_1:1-6582,6584-6678,6680-6687

Modified: trunk/CHANGES
===================================================================
--- trunk/CHANGES	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/CHANGES	2007-11-28 22:08:47 UTC (rev 6688)
@@ -52,6 +52,22 @@
       of node non-responsive, it re-tries a *different* random node, rather 
       than waiting for the node to recover (for BUG#31053)
       
+    - Fixed BUG#32577 - no way to store two timestamp/datetime values that happens
+      over the DST switchover, as the hours end up being the same when sent as
+      the literal that MySQL requires.
+
+      Note that to get this scenario to work with MySQL (since it doesn't support
+      per-value timezones), you need to configure your server (or session) to be in UTC,
+      and tell the driver not to use the legacy date/time code by setting
+      "useLegacyDatetimeCode" to "false". This will cause the driver to always convert
+      to/from the server and client timezone consistently.
+      
+      This bug fix also fixes BUG#15604, by adding entirely new date/time handling
+      code that can be switched on by "useLegacyDatetimeCode" being set to "false" as
+      a JDBC configuration property. For Connector/J 5.1.x, the default is "true",
+      in trunk and beyond it will be "false" (i.e. the old date/time handling code, warts
+      and all will be deprecated).
+      
 10-09-07 - Version 5.1.5
 
     - Released instead of 5.1.4 to pickup patch for BUG#31053

Modified: trunk/src/com/mysql/jdbc/BufferRow.java
===================================================================
--- trunk/src/com/mysql/jdbc/BufferRow.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/BufferRow.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -684,7 +684,7 @@
 	}
 
 	public Date getDateFast(int columnIndex, ConnectionImpl conn,
-			ResultSetImpl rs) throws SQLException {
+			ResultSetImpl rs, Calendar targetCalendar) throws SQLException {
 		if (isNull(columnIndex)) {
 			return null;
 		}
@@ -696,7 +696,7 @@
 		int offset = this.rowFromServer.getPosition();
 
 		return getDateFast(columnIndex, this.rowFromServer.getByteBuffer(),
-				offset, (int)length, conn, rs);
+				offset, (int)length, conn, rs, targetCalendar);
 	}
 
 	public java.sql.Date getNativeDate(int columnIndex, ConnectionImpl conn,

Modified: trunk/src/com/mysql/jdbc/ByteArrayRow.java
===================================================================
--- trunk/src/com/mysql/jdbc/ByteArrayRow.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/ByteArrayRow.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -225,7 +225,7 @@
 	}
 
 	public Date getDateFast(int columnIndex, ConnectionImpl conn,
-			ResultSetImpl rs) throws SQLException {
+			ResultSetImpl rs, Calendar targetCalendar) throws SQLException {
 		byte[] columnValue = this.internalRowData[columnIndex];
 
 		if (columnValue == null) {
@@ -233,7 +233,7 @@
 		}
 
 		return getDateFast(columnIndex, this.internalRowData[columnIndex], 0,
-				columnValue.length, conn, rs);
+				columnValue.length, conn, rs, targetCalendar);
 	}
 
 	public Object getNativeDateTimeValue(int columnIndex, Calendar targetCalendar,

Modified: trunk/src/com/mysql/jdbc/ConnectionImpl.java
===================================================================
--- trunk/src/com/mysql/jdbc/ConnectionImpl.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/ConnectionImpl.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -1895,21 +1895,18 @@
 			}
 		}
 
-		if (getUseTimezone() && configuredTimeZoneOnServer != null) {
-			// user can specify/override as property
-			String canoncicalTimezone = getServerTimezone();
-
-			if ((canoncicalTimezone == null)
-					|| (canoncicalTimezone.length() == 0)) {
-				String serverTimezoneStr = configuredTimeZoneOnServer;
-
+		String canoncicalTimezone = getServerTimezone();
+		
+		if ((getUseTimezone() || !getUseLegacyDatetimeCode()) &&
configuredTimeZoneOnServer != null) {
+			// user can override this with driver properties, so don't detect if that's the case
+			if (canoncicalTimezone == null ||
StringUtils.isEmptyOrWhitespaceOnly(canoncicalTimezone)) {
 				try {
 					canoncicalTimezone = TimeUtil
-							.getCanoncialTimezone(serverTimezoneStr);
+							.getCanoncialTimezone(configuredTimeZoneOnServer);
 
 					if (canoncicalTimezone == null) {
 						throw SQLError.createSQLException("Can't map timezone '"
-								+ serverTimezoneStr + "' to "
+								+ configuredTimeZoneOnServer + "' to "
 								+ " canonical timezone.",
 								SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 					}
@@ -1918,9 +1915,13 @@
 							SQLError.SQL_STATE_GENERAL_ERROR);
 				}
 			}
+		} else {
+			canoncicalTimezone = getServerTimezone();
+		}
+		
+		if (canoncicalTimezone != null && canoncicalTimezone.length() > 0) {
+				this.serverTimezoneTZ = TimeZone.getTimeZone(canoncicalTimezone);
 
-			this.serverTimezoneTZ = TimeZone.getTimeZone(canoncicalTimezone);
-
 			//
 			// The Calendar class has the behavior of mapping
 			// unknown timezones to 'GMT' instead of throwing an

Modified: trunk/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
--- trunk/src/com/mysql/jdbc/ConnectionProperties.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/ConnectionProperties.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -1582,4 +1582,8 @@
 	public boolean getVerifyServerCertificate();
 
 	public void setVerifyServerCertificate(boolean flag);
+	
+	public abstract boolean getUseLegacyDatetimeCode();
+
+	public abstract void setUseLegacyDatetimeCode(boolean flag);
 }

Modified: trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
===================================================================
--- trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2007-11-28 21:50:11 UTC (rev
6687)
+++ trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2007-11-28 22:08:47 UTC (rev
6688)
@@ -1476,6 +1476,12 @@
 			Messages.getString("ConnectionProperties.useLocalSessionState"), //$NON-NLS-1$
 			"3.1.7", PERFORMANCE_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$
 	
+	private BooleanConnectionProperty useLegacyDatetimeCode = new BooleanConnectionProperty(
+			"useLegacyDatetimeCode",
+			true,
+			Messages.getString("ConnectionProperties.useLegacyDatetimeCode"),
+			"5.1.6", MISC_CATEGORY, Integer.MIN_VALUE);
+	
 	private BooleanConnectionProperty useNanosForElapsedTime = new
BooleanConnectionProperty(
 			"useNanosForElapsedTime", //$NON-NLS-1$
 			false,
@@ -4311,4 +4317,12 @@
 	public void setVerifyServerCertificate(boolean flag) {
 		this.verifyServerCertificate.setValue(flag);
 	}
+
+	public boolean getUseLegacyDatetimeCode() {
+		return this.useLegacyDatetimeCode.getValueAsBoolean();
+	}
+
+	public void setUseLegacyDatetimeCode(boolean flag) {
+		this.useLegacyDatetimeCode.setValue(flag);
+	}
 }

Modified: trunk/src/com/mysql/jdbc/EscapeProcessor.java
===================================================================
--- trunk/src/com/mysql/jdbc/EscapeProcessor.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/EscapeProcessor.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -32,6 +32,7 @@
 import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
 
 import java.util.Calendar;
 import java.util.Collections;
@@ -100,8 +101,8 @@
 	 *             DOCUMENT ME!
 	 */
 	public static final Object escapeSQL(String sql,
-			boolean serverSupportsConvertFn, 
-			ConnectionImpl conn) throws java.sql.SQLException {
+			boolean serverSupportsConvertFn, ConnectionImpl conn)
+			throws java.sql.SQLException {
 		boolean replaceEscapeSequence = false;
 		String escapeSequence = null;
 
@@ -135,8 +136,9 @@
 				if (token.charAt(0) == '{') { // It's an escape code
 
 					if (!token.endsWith("}")) {
-						throw SQLError.createSQLException("Not a valid escape sequence: "
-								+ token);
+						throw SQLError
+								.createSQLException("Not a valid escape sequence: "
+										+ token);
 					}
 
 					if (token.length() > 2) {
@@ -186,16 +188,21 @@
 							escapeSequence = st.nextToken();
 
 							if (escapeSequence.length() < 3) {
-								newSql.append(token); // it's just part of the query, push possible syntax errors
onto server's shoulders
+								newSql.append(token); // it's just part of the
+														// query, push possible
+														// syntax errors onto
+														// server's shoulders
 							} else {
-							
 
 								escapeSequence = escapeSequence.substring(1,
-									escapeSequence.length() - 1);
+										escapeSequence.length() - 1);
 								replaceEscapeSequence = true;
 							}
 						} catch (java.util.NoSuchElementException e) {
-							newSql.append(token); // it's just part of the query, push possible syntax errors
onto server's shoulders
+							newSql.append(token); // it's just part of the
+													// query, push possible
+													// syntax errors onto
+													// server's shoulders
 						}
 					} else if (StringUtils.startsWithIgnoreCase(collapsedToken,
 							"{fn")) {
@@ -220,14 +227,17 @@
 						int endPos = token.lastIndexOf('\''); // no }
 
 						if ((startPos == -1) || (endPos == -1)) {
-							newSql.append(token); // it's just part of the query, push possible syntax errors
onto server's shoulders
+							newSql.append(token); // it's just part of the
+													// query, push possible
+													// syntax errors onto
+													// server's shoulders
 						} else {
-	
+
 							String argument = token.substring(startPos, endPos);
-	
+
 							try {
-								StringTokenizer st = new StringTokenizer(argument,
-										" -");
+								StringTokenizer st = new StringTokenizer(
+										argument, " -");
 								String year4 = st.nextToken();
 								String month2 = st.nextToken();
 								String day2 = st.nextToken();
@@ -242,194 +252,10 @@
 						}
 					} else if (StringUtils.startsWithIgnoreCase(collapsedToken,
 							"{ts")) {
-						int startPos = token.indexOf('\'') + 1;
-						int endPos = token.lastIndexOf('\''); // no }
-
-						if ((startPos == -1) || (endPos == -1)) {
-							newSql.append(token); // it's just part of the query, push possible syntax errors
onto server's shoulders
-						} else {
-
-							String argument = token.substring(startPos, endPos);
-	
-							try {
-								StringTokenizer st = new StringTokenizer(argument,
-										" .-:");
-								String year4 = st.nextToken();
-								String month2 = st.nextToken();
-								String day2 = st.nextToken();
-								String hour = st.nextToken();
-								String minute = st.nextToken();
-								String second = st.nextToken();
-	
-								/*
-								 * For now, we get the fractional seconds part, but
-								 * we don't use it, as MySQL doesn't support it in
-								 * it's TIMESTAMP data type
-								 * 
-								 * String fractionalSecond = "";
-								 * 
-								 * if (st.hasMoreTokens()) { fractionalSecond =
-								 * st.nextToken(); }
-								 */
-								/*
-								 * Use the full format because number format will
-								 * not work for "between" clauses.
-								 * 
-								 * Ref. Mysql Docs
-								 * 
-								 * You can specify DATETIME, DATE and TIMESTAMP
-								 * values using any of a common set of formats:
-								 * 
-								 * As a string in either 'YYYY-MM-DD HH:MM:SS' or
-								 * 'YY-MM-DD HH:MM:SS' format.
-								 * 
-								 * Thanks to Craig Longman for pointing out this bug
-								 */
-								if (!conn.getUseTimezone() && !conn.getUseJDBCCompliantTimezoneShift()) {
-									newSql.append("'").append(year4).append("-")
-										.append(month2).append("-").append(day2)
-										.append(" ").append(hour).append(":")
-										.append(minute).append(":").append(second)
-										.append("'");
-								} else {
-									Calendar sessionCalendar;
-									
-									if (conn != null) {
-										sessionCalendar = conn.getCalendarInstanceForSessionOrNew();
-									} else {
-										sessionCalendar = new GregorianCalendar();
-										sessionCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));
-									}
-									
-									try {
-										int year4Int = Integer.parseInt(year4);
-										int month2Int = Integer.parseInt(month2);
-										int day2Int = Integer.parseInt(day2);
-										int hourInt = Integer.parseInt(hour);
-										int minuteInt = Integer.parseInt(minute);
-										int secondInt = Integer.parseInt(second);
-										
-										synchronized (sessionCalendar) {
-											boolean useGmtMillis = conn.getUseGmtMillisForDatetimes();
-											
-											Timestamp toBeAdjusted = TimeUtil.fastTimestampCreate(useGmtMillis,
-													useGmtMillis ? Calendar.getInstance(TimeZone.getTimeZone("GMT")): null,
-												sessionCalendar,
-												year4Int,
-												month2Int,
-												day2Int,
-												hourInt,
-												minuteInt,
-												secondInt,
-												0);
-										
-											Timestamp inServerTimezone = TimeUtil.changeTimezone(
-													conn,
-													sessionCalendar,
-													null,
-													toBeAdjusted,
-													sessionCalendar.getTimeZone(),
-													conn.getServerTimezoneTZ(),
-													false);
-											
-											
-											newSql.append("'");
-											
-											String timezoneLiteral = inServerTimezone.toString();
-											
-											int indexOfDot = timezoneLiteral.indexOf(".");
-											
-											if (indexOfDot != -1) {
-												timezoneLiteral = timezoneLiteral.substring(0, indexOfDot);
-											}
-											
-											newSql.append(timezoneLiteral);
-										}
-										
-										newSql.append("'");	
-										
-									
-									} catch (NumberFormatException nfe) {
-										throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '"

-											+ token + "'.",
-											SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-									}
-								}
-							} catch (java.util.NoSuchElementException e) {
-								throw SQLError.createSQLException(
-										"Syntax error for TIMESTAMP escape sequence '"
-												+ argument + "'", "42000");
-							}
-						}
+						processTimestampToken(conn, newSql, token);
 					} else if (StringUtils.startsWithIgnoreCase(collapsedToken,
 							"{t")) {
-						int startPos = token.indexOf('\'') + 1;
-						int endPos = token.lastIndexOf('\''); // no }
-
-						if ((startPos == -1) || (endPos == -1)) {
-							newSql.append(token); // it's just part of the query, push possible syntax errors
onto server's shoulders
-						} else {
-
-							String argument = token.substring(startPos, endPos);
-	
-							try {
-								StringTokenizer st = new StringTokenizer(argument,
-										" :");
-								String hour = st.nextToken();
-								String minute = st.nextToken();
-								String second = st.nextToken();
-								
-								if (!conn.getUseTimezone()) {
-									String timeString = "'" + hour + ":" + minute + ":"
-										+ second + "'";
-									newSql.append(timeString);
-								} else {
-									Calendar sessionCalendar = null;
-									
-									if (conn != null) {
-										sessionCalendar = conn.getCalendarInstanceForSessionOrNew();
-									} else {
-										sessionCalendar = new GregorianCalendar();
-									}
-	
-									try {
-										int hourInt = Integer.parseInt(hour);
-										int minuteInt = Integer.parseInt(minute);
-										int secondInt = Integer.parseInt(second);
-										
-										synchronized (sessionCalendar) {
-											Time toBeAdjusted = TimeUtil.fastTimeCreate(
-													sessionCalendar,
-													hourInt,
-													minuteInt,
-													secondInt);
-											
-											Time inServerTimezone = TimeUtil.changeTimezone(
-													conn,
-													sessionCalendar,
-													null,
-													toBeAdjusted,
-													sessionCalendar.getTimeZone(),
-													conn.getServerTimezoneTZ(),
-													false);
-											
-											newSql.append("'");
-											newSql.append(inServerTimezone.toString());
-											newSql.append("'");		
-										}
-									
-									} catch (NumberFormatException nfe) {
-										throw SQLError.createSQLException("Syntax error in TIMESTAMP escape sequence '"

-											+ token + "'.",
-											SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-									}
-								}
-							} catch (java.util.NoSuchElementException e) {
-								throw SQLError.createSQLException(
-										"Syntax error for escape sequence '"
-												+ argument + "'", "42000");
-							}
-						}
+						processTimeToken(conn, newSql, token);
 					} else if (StringUtils.startsWithIgnoreCase(collapsedToken,
 							"{call")
 							|| StringUtils.startsWithIgnoreCase(collapsedToken,
@@ -438,7 +264,7 @@
 						int startPos = StringUtils.indexOfIgnoreCase(token,
 								"CALL") + 5;
 						int endPos = token.length() - 1;
-		
+
 						if (StringUtils.startsWithIgnoreCase(collapsedToken,
 								"{?=call")) {
 							callingStoredFunction = true;
@@ -449,19 +275,21 @@
 							newSql.append("CALL ");
 							newSql.append(token.substring(startPos, endPos));
 						}
-						
+
 						for (int i = endPos - 1; i >= startPos; i--) {
 							char c = token.charAt(i);
-							
+
 							if (Character.isWhitespace(c)) {
 								continue;
 							}
-							
+
 							if (c != ')') {
-								newSql.append("()");  // handle no-parenthesis no-arg call not supported
-			                                         // by MySQL parser
+								newSql.append("()"); // handle no-parenthesis
+														// no-arg call not
+														// supported
+								// by MySQL parser
 							}
-							
+
 							break;
 						}
 					} else if (StringUtils.startsWithIgnoreCase(collapsedToken,
@@ -511,6 +339,275 @@
 		return epr;
 	}
 
+	private static void processTimeToken(ConnectionImpl conn,
+			StringBuffer newSql, String token) throws SQLException {
+		int startPos = token.indexOf('\'') + 1;
+		int endPos = token.lastIndexOf('\''); // no }
+
+		if ((startPos == -1) || (endPos == -1)) {
+			newSql.append(token); // it's just part of the
+									// query, push possible
+									// syntax errors onto
+									// server's shoulders
+		} else {
+
+			String argument = token.substring(startPos, endPos);
+
+			try {
+				StringTokenizer st = new StringTokenizer(
+						argument, " :");
+				String hour = st.nextToken();
+				String minute = st.nextToken();
+				String second = st.nextToken();
+
+				if (!conn.getUseTimezone()
+						|| !conn.getUseLegacyDatetimeCode()) {
+					String timeString = "'" + hour + ":"
+							+ minute + ":" + second + "'";
+					newSql.append(timeString);
+				} else {
+					Calendar sessionCalendar = null;
+
+					if (conn != null) {
+						sessionCalendar = conn
+								.getCalendarInstanceForSessionOrNew();
+					} else {
+						sessionCalendar = new GregorianCalendar();
+					}
+
+					try {
+						int hourInt = Integer.parseInt(hour);
+						int minuteInt = Integer
+								.parseInt(minute);
+						int secondInt = Integer
+								.parseInt(second);
+
+						synchronized (sessionCalendar) {
+							Time toBeAdjusted = TimeUtil
+									.fastTimeCreate(
+											sessionCalendar,
+											hourInt, minuteInt,
+											secondInt);
+
+							Time inServerTimezone = TimeUtil
+									.changeTimezone(
+											conn,
+											sessionCalendar,
+											null,
+											toBeAdjusted,
+											sessionCalendar
+													.getTimeZone(),
+											conn
+													.getServerTimezoneTZ(),
+											false);
+
+							newSql.append("'");
+							newSql.append(inServerTimezone
+									.toString());
+							newSql.append("'");
+						}
+
+					} catch (NumberFormatException nfe) {
+						throw SQLError
+								.createSQLException(
+										"Syntax error in TIMESTAMP escape sequence '"
+												+ token + "'.",
+										SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+					}
+				}
+			} catch (java.util.NoSuchElementException e) {
+				throw SQLError.createSQLException(
+						"Syntax error for escape sequence '"
+								+ argument + "'", "42000");
+			}
+		}
+	}
+
+	private static void processTimestampToken(ConnectionImpl conn,
+			StringBuffer newSql, String token) throws SQLException {
+		int startPos = token.indexOf('\'') + 1;
+		int endPos = token.lastIndexOf('\''); // no }
+
+		if ((startPos == -1) || (endPos == -1)) {
+			newSql.append(token); // it's just part of the
+									// query, push possible
+									// syntax errors onto
+									// server's shoulders
+		} else {
+
+			String argument = token.substring(startPos, endPos);
+
+			try {
+				if (!conn.getUseLegacyDatetimeCode()) {
+					Timestamp ts = Timestamp.valueOf(argument);
+					SimpleDateFormat tsdf = new SimpleDateFormat(
+							"''yyyy-MM-dd HH:mm:ss''", Locale.US); //$NON-NLS-1$
+
+					tsdf
+							.setTimeZone(conn
+									.getServerTimezoneTZ());
+
+					newSql.append(tsdf.format(ts));
+				} else {
+					StringTokenizer st = new StringTokenizer(
+							argument, " .-:");
+					try {
+						String year4 = st.nextToken();
+						String month2 = st.nextToken();
+						String day2 = st.nextToken();
+						String hour = st.nextToken();
+						String minute = st.nextToken();
+						String second = st.nextToken();
+
+						/*
+						 * For now, we get the fractional
+						 * seconds part, but we don't use it, as
+						 * MySQL doesn't support it in it's
+						 * TIMESTAMP data type
+						 * 
+						 * String fractionalSecond = "";
+						 * 
+						 * if (st.hasMoreTokens()) {
+						 * fractionalSecond = st.nextToken(); }
+						 */
+
+						/*
+						 * Use the full format because number
+						 * format will not work for "between"
+						 * clauses.
+						 * 
+						 * Ref. Mysql Docs
+						 * 
+						 * You can specify DATETIME, DATE and
+						 * TIMESTAMP values using any of a
+						 * common set of formats:
+						 * 
+						 * As a string in either 'YYYY-MM-DD
+						 * HH:MM:SS' or 'YY-MM-DD HH:MM:SS'
+						 * format.
+						 * 
+						 * Thanks to Craig Longman for pointing
+						 * out this bug
+						 */
+
+						if (!conn.getUseTimezone()
+								&& !conn
+										.getUseJDBCCompliantTimezoneShift()) {
+							newSql.append("'").append(year4)
+									.append("-").append(month2)
+									.append("-").append(day2)
+									.append(" ").append(hour)
+									.append(":").append(minute)
+									.append(":").append(second)
+									.append("'");
+						} else {
+							Calendar sessionCalendar;
+
+							if (conn != null) {
+								sessionCalendar = conn
+										.getCalendarInstanceForSessionOrNew();
+							} else {
+								sessionCalendar = new GregorianCalendar();
+								sessionCalendar
+										.setTimeZone(TimeZone
+												.getTimeZone("GMT"));
+							}
+
+							try {
+								int year4Int = Integer
+										.parseInt(year4);
+								int month2Int = Integer
+										.parseInt(month2);
+								int day2Int = Integer
+										.parseInt(day2);
+								int hourInt = Integer
+										.parseInt(hour);
+								int minuteInt = Integer
+										.parseInt(minute);
+								int secondInt = Integer
+										.parseInt(second);
+
+								synchronized (sessionCalendar) {
+									boolean useGmtMillis = conn
+											.getUseGmtMillisForDatetimes();
+
+									Timestamp toBeAdjusted = TimeUtil
+											.fastTimestampCreate(
+													useGmtMillis,
+													useGmtMillis ? Calendar
+															.getInstance(TimeZone
+																	.getTimeZone("GMT"))
+															: null,
+													sessionCalendar,
+													year4Int,
+													month2Int,
+													day2Int,
+													hourInt,
+													minuteInt,
+													secondInt,
+													0);
+
+									Timestamp inServerTimezone = TimeUtil
+											.changeTimezone(
+													conn,
+													sessionCalendar,
+													null,
+													toBeAdjusted,
+													sessionCalendar
+															.getTimeZone(),
+													conn
+															.getServerTimezoneTZ(),
+													false);
+
+									newSql.append("'");
+
+									String timezoneLiteral = inServerTimezone
+											.toString();
+
+									int indexOfDot = timezoneLiteral
+											.indexOf(".");
+
+									if (indexOfDot != -1) {
+										timezoneLiteral = timezoneLiteral
+												.substring(0,
+														indexOfDot);
+									}
+
+									newSql
+											.append(timezoneLiteral);
+								}
+
+								newSql.append("'");
+
+							} catch (NumberFormatException nfe) {
+								throw SQLError
+										.createSQLException(
+												"Syntax error in TIMESTAMP escape sequence '"
+														+ token
+														+ "'.",
+												SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+							}
+						}
+					} catch (java.util.NoSuchElementException e) {
+						throw SQLError.createSQLException(
+								"Syntax error for TIMESTAMP escape sequence '"
+										+ argument + "'",
+								"42000");
+					}
+				}
+			} catch (IllegalArgumentException illegalArgumentException) {
+				SQLException sqlEx = SQLError
+						.createSQLException(
+								"Syntax error for TIMESTAMP escape sequence '"
+										+ argument + "'",
+								"42000");
+				sqlEx.initCause(illegalArgumentException);
+
+				throw sqlEx;
+			}
+		}
+	}
+
 	/**
 	 * Re-writes {fn convert (expr, type)} as cast(expr AS type)
 	 * 
@@ -554,10 +651,11 @@
 		int firstIndexOfParen = functionToken.indexOf("(");
 
 		if (firstIndexOfParen == -1) {
-			throw SQLError.createSQLException(
-					"Syntax error while processing {fn convert (... , ...)} token, missing opening
parenthesis in token '"
-							+ functionToken + "'.",
-					SQLError.SQL_STATE_SYNTAX_ERROR);
+			throw SQLError
+					.createSQLException(
+							"Syntax error while processing {fn convert (... , ...)} token, missing opening
parenthesis in token '"
+									+ functionToken + "'.",
+							SQLError.SQL_STATE_SYNTAX_ERROR);
 		}
 
 		int tokenLength = functionToken.length();
@@ -565,19 +663,21 @@
 		int indexOfComma = functionToken.lastIndexOf(",");
 
 		if (indexOfComma == -1) {
-			throw SQLError.createSQLException(
-					"Syntax error while processing {fn convert (... , ...)} token, missing comma in
token '"
-							+ functionToken + "'.",
-					SQLError.SQL_STATE_SYNTAX_ERROR);
+			throw SQLError
+					.createSQLException(
+							"Syntax error while processing {fn convert (... , ...)} token, missing comma in
token '"
+									+ functionToken + "'.",
+							SQLError.SQL_STATE_SYNTAX_ERROR);
 		}
 
 		int indexOfCloseParen = functionToken.indexOf(')', indexOfComma);
 
 		if (indexOfCloseParen == -1) {
-			throw SQLError.createSQLException(
-					"Syntax error while processing {fn convert (... , ...)} token, missing closing
parenthesis in token '"
-							+ functionToken + "'.",
-					SQLError.SQL_STATE_SYNTAX_ERROR);
+			throw SQLError
+					.createSQLException(
+							"Syntax error while processing {fn convert (... , ...)} token, missing closing
parenthesis in token '"
+									+ functionToken + "'.",
+							SQLError.SQL_STATE_SYNTAX_ERROR);
 
 		}
 
@@ -609,11 +709,12 @@
 			// (date,time,timestamp, datetime)
 
 			if (newType == null) {
-				throw SQLError.createSQLException(
-						"Can't find conversion re-write for type '"
-								+ type
-								+ "' that is applicable for this server version while processing escape tokens.",
-						SQLError.SQL_STATE_GENERAL_ERROR);
+				throw SQLError
+						.createSQLException(
+								"Can't find conversion re-write for type '"
+										+ type
+										+ "' that is applicable for this server version while processing escape
tokens.",
+								SQLError.SQL_STATE_GENERAL_ERROR);
 			}
 		}
 

Modified: trunk/src/com/mysql/jdbc/LocalizedErrorMessages.properties
===================================================================
--- trunk/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2007-11-28 21:50:11 UTC
(rev 6687)
+++ trunk/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2007-11-28 22:08:47 UTC
(rev 6688)
@@ -596,6 +596,7 @@
 ConnectionProperties.useBlobToStoreUTF8OutsideBMP=Tells the driver to treat
[MEDIUM/LONG]BLOB columns as [LONG]VARCHAR columns holding text encoded in UTF-8 that has
characters outside the BMP (4-byte encodings), which MySQL server can't handle natively.
 ConnectionProperties.utf8OutsideBmpExcludedColumnNamePattern=When
"useBlobToStoreUTF8OutsideBMP" is set to "true", column names matching the given regex
will still be treated as BLOBs unless they match the regex specified for
"utf8OutsideBmpIncludedColumnNamePattern". The regex must follow the patterns used for
the java.util.regex package.
 ConnectionProperties.utf8OutsideBmpIncludedColumnNamePattern=Used to specify exclusion
rules to "utf8OutsideBmpExcludedColumnNamePattern". The regex must follow the patterns
used for the java.util.regex package.
+ConnectionProperties.useLegacyDatetimeCode=Use code for DATE/TIME/DATETIME/TIMESTAMP
handling in result sets and statements that consistently handles timezone conversions
from client to server and back again, or use the legacy code for these datatypes that has
been in the driver for backwards-compatibility?
 
 # 
 # Error Messages for Connection Properties
@@ -605,3 +606,7 @@
 ConnectionProperties.unsupportedCharacterEncoding=Unsupported character encoding '${0}'.
 ConnectionProperties.errorNotExpected=Huh?
 ConnectionProperties.InternalPropertiesFailure=Internal properties failure
+
+TimeUtil.TooGenericTimezoneId=The server timezone value ''${0}'' represents more than one
timezone. You must \
+configure either the server or JDBC driver (via the 'serverTimezone' configuration
property) to use a \
+more specifc timezone value if you want to utilize timezone support. The timezones that
''${0}'' maps to are: ${1}.
\ No newline at end of file

Modified: trunk/src/com/mysql/jdbc/PreparedStatement.java
===================================================================
--- trunk/src/com/mysql/jdbc/PreparedStatement.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/PreparedStatement.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -522,6 +522,8 @@
 	private boolean canRewrite = false;
 
 	private boolean doPingInstead;
+	private SimpleDateFormat ddf;
+	private SimpleDateFormat tdf;
 	
 	/**
 	 * Creates a prepared statement instance -- We need to provide factory-style
@@ -3153,17 +3155,7 @@
 	 */
 	public void setDate(int parameterIndex, java.sql.Date x)
 			throws java.sql.SQLException {
-		if (x == null) {
-			setNull(parameterIndex, java.sql.Types.DATE);
-		} else {
-			// FIXME: Have instance version of this, problem as it's
-			// not thread-safe :(
-			SimpleDateFormat dateFormatter = new SimpleDateFormat(
-					"''yyyy-MM-dd''", Locale.US); //$NON-NLS-1$
-			setInternal(parameterIndex, dateFormatter.format(x));
-			
-			this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = Types.DATE;
-		}
+		setDate(parameterIndex, x, null);
 	}
 
 	/**
@@ -3182,7 +3174,23 @@
 	 */
 	public void setDate(int parameterIndex, java.sql.Date x, Calendar cal)
 			throws SQLException {
-		setDate(parameterIndex, x);
+		if (x == null) {
+			setNull(parameterIndex, java.sql.Types.DATE);
+		} else {
+			checkClosed();
+			
+			if (!this.useLegacyDatetimeCode) {
+				newSetDateInternal(parameterIndex, x, cal);
+			} else {
+				// FIXME: Have instance version of this, problem as it's
+				// not thread-safe :(
+				SimpleDateFormat dateFormatter = new SimpleDateFormat(
+						"''yyyy-MM-dd''", Locale.US); //$NON-NLS-1$
+				setInternal(parameterIndex, dateFormatter.format(x));
+				
+				this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = Types.DATE;
+			}
+		}
 	}
 
 	/**
@@ -4202,18 +4210,22 @@
 		} else {
 			checkClosed();
 			
-			Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
-			
-			synchronized (sessionCalendar) {
-				x = TimeUtil.changeTimezone(this.connection, 
-						sessionCalendar,
-						targetCalendar,
-						 x, tz, this.connection
-						.getServerTimezoneTZ(), rollForward);
+			if (!this.useLegacyDatetimeCode) {
+				newSetTimeInternal(parameterIndex, x, targetCalendar);
+			} else {
+				Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
+				
+				synchronized (sessionCalendar) {
+					x = TimeUtil.changeTimezone(this.connection, 
+							sessionCalendar,
+							targetCalendar,
+							 x, tz, this.connection
+							.getServerTimezoneTZ(), rollForward);
+				}
+				
+				setInternal(parameterIndex, "'" + x.toString() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
 			}
 			
-			setInternal(parameterIndex, "'" + x.toString() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
-			
 			this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = Types.TIME;
 		}
 	}
@@ -4276,38 +4288,108 @@
 		} else {
 			checkClosed();
 			
-			String timestampString = null;
-			
-			Calendar sessionCalendar = this.connection.getUseJDBCCompliantTimezoneShift() ?
-					this.connection.getUtcCalendar() : 
-						getCalendarInstanceForSessionOrNew();
+			if (!this.useLegacyDatetimeCode) {
+				newSetTimestampInternal(parameterIndex, x, targetCalendar);
+			} else {
+				String timestampString = null;
+
+				Calendar sessionCalendar = this.connection.getUseJDBCCompliantTimezoneShift() ?
+						this.connection.getUtcCalendar() : 
+							getCalendarInstanceForSessionOrNew();
 					
-			synchronized (sessionCalendar) {
-				x = TimeUtil.changeTimezone(this.connection, 
-						sessionCalendar,
-						targetCalendar,
-						x, tz, this.connection
-					.getServerTimezoneTZ(), rollForward);
-			}
-
-			if (this.connection.getUseSSPSCompatibleTimezoneShift()) {
-				doSSPSCompatibleTimezoneShift(parameterIndex, x, sessionCalendar);
-			} else {
-				
-				if (this.tsdf == null) {
-					this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US);
//$NON-NLS-1$
+				synchronized (sessionCalendar) {
+					x = TimeUtil.changeTimezone(this.connection, 
+							sessionCalendar,
+							targetCalendar,
+							x, tz, this.connection
+						.getServerTimezoneTZ(), rollForward);
 				}
-				
-				timestampString = this.tsdf.format(x);
-
-				setInternal(parameterIndex, timestampString); // SimpleDateFormat is not
-															  // thread-safe
+	
+				if (this.connection.getUseSSPSCompatibleTimezoneShift()) {
+					doSSPSCompatibleTimezoneShift(parameterIndex, x, sessionCalendar);
+				} else {
+					synchronized (this) {
+						if (this.tsdf == null) {
+							this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US);
//$NON-NLS-1$
+						}
+						
+						timestampString = this.tsdf.format(x);
+		
+						setInternal(parameterIndex, timestampString); // SimpleDateFormat is not
+																	  // thread-safe
+					}
+				}
 			}
 			
 			this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = Types.TIMESTAMP;
 		}
 	}
+	
+	private synchronized void newSetTimestampInternal(int parameterIndex,
+			Timestamp x, Calendar targetCalendar) throws SQLException {
+		if (this.tsdf == null) {
+			this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US); //$NON-NLS-1$
+		}
+		
+		String timestampString = null;
+		
+		if (targetCalendar != null) {
+			targetCalendar.setTime(x);
+			this.tsdf.setTimeZone(targetCalendar.getTimeZone());
+			
+			timestampString = this.tsdf.format(x);
+		} else {
+			this.tsdf.setTimeZone(this.connection.getServerTimezoneTZ());
+			timestampString = this.tsdf.format(x);
+		}
 
+		setInternal(parameterIndex, timestampString); 
+	}
+	
+	private synchronized void newSetTimeInternal(int parameterIndex,
+			Time x, Calendar targetCalendar) throws SQLException {
+		if (this.tdf == null) {
+			this.tdf = new SimpleDateFormat("''HH:mm:ss''", Locale.US); //$NON-NLS-1$
+			
+		}
+
+		String timeString = null;
+		
+		if (targetCalendar != null) {
+			targetCalendar.setTime(x);
+			this.tdf.setTimeZone(targetCalendar.getTimeZone());
+			
+			timeString = this.tdf.format(x);
+		} else {
+			this.tdf.setTimeZone(this.connection.getServerTimezoneTZ());
+			timeString = this.tdf.format(x);
+		}
+
+		setInternal(parameterIndex, timeString); 
+	}
+	
+	private synchronized void newSetDateInternal(int parameterIndex,
+			Date x, Calendar targetCalendar) throws SQLException {
+		if (this.ddf == null) {
+			this.ddf = new SimpleDateFormat("''yyyy-MM-dd''", Locale.US); //$NON-NLS-1$
+			
+		}
+
+		String timeString = null;
+		
+		if (targetCalendar != null) {
+			targetCalendar.setTime(x);
+			this.ddf.setTimeZone(targetCalendar.getTimeZone());
+			
+			timeString = this.ddf.format(x);
+		} else {
+			this.ddf.setTimeZone(this.connection.getServerTimezoneTZ());
+			timeString = this.ddf.format(x);
+		}
+
+		setInternal(parameterIndex, timeString); 
+	}
+
 	private void doSSPSCompatibleTimezoneShift(int parameterIndex, Timestamp x, Calendar
sessionCalendar) throws SQLException {
 		Calendar sessionCalendar2 = (this.connection
 				.getUseJDBCCompliantTimezoneShift()) ? this.connection

Modified: trunk/src/com/mysql/jdbc/ResultSetImpl.java
===================================================================
--- trunk/src/com/mysql/jdbc/ResultSetImpl.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/ResultSetImpl.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -413,7 +413,10 @@
 				this.connection.getRetainStatementAfterResultSetClose();
 			
 			this.connectionId = this.connection.getId();
+			this.serverTimeZoneTz = this.connection.getServerTimezoneTZ();
 		}
+		
+		useLegacyDatetimeCode = !this.connection.getUseLegacyDatetimeCode();
 	}
 
 	/**
@@ -450,6 +453,7 @@
 				this.connection.getRetainStatementAfterResultSetClose();
 			this.jdbcCompliantTruncationForReads =
this.connection.getJdbcCompliantTruncationForReads();
 			this.useFastIntParsing = this.connection.getUseFastIntParsing();
+			this.serverTimeZoneTz = this.connection.getServerTimezoneTZ();
 		}
 
 		this.owningStatement = creatorStmt;
@@ -484,6 +488,7 @@
 		if (this.fields != null) {
 			initializeWithMetadata();
 		} // else called by Connection.initializeResultsMetadataFromCache() when cached
+		useLegacyDatetimeCode = !this.connection.getUseLegacyDatetimeCode();
 	}
 
 	public void initializeWithMetadata() throws SQLException {
@@ -822,6 +827,8 @@
 	
 	private boolean onValidRow = false;
 	private String invalidRowReason = null;
+	protected boolean useLegacyDatetimeCode;
+	private TimeZone serverTimeZoneTz;
 	
 	private void setRowPositionValidity() throws SQLException {
 		if (!this.rowData.isDynamic() && (this.rowData.size() == 0)) {
@@ -983,13 +990,17 @@
 
 	protected synchronized Date fastDateCreate(Calendar cal, int year, int month,
 			int day) {
+		if (this.useLegacyDatetimeCode) {
+			return TimeUtil.fastDateCreate(year, month, day, cal);
+		}
+		
 		if (cal == null) {
 			createCalendarIfNeeded();
 			cal = this.fastDateCal;
 		}
 
 		boolean useGmtMillis = this.connection.getUseGmtMillisForDatetimes();
-						
+		
 		return TimeUtil.fastDateCreate(useGmtMillis,
 				useGmtMillis ? getGmtCalendar() : null,
 				cal, year, month, day);
@@ -997,6 +1008,10 @@
 
 	protected synchronized Time fastTimeCreate(Calendar cal, int hour,
 			int minute, int second) throws SQLException {
+		if (!this.useLegacyDatetimeCode) {
+			return TimeUtil.fastTimeCreate(hour, minute, second, cal);
+		}
+		
 		if (cal == null) {
 			createCalendarIfNeeded();
 			cal = this.fastDateCal;
@@ -1008,6 +1023,11 @@
 	protected synchronized Timestamp fastTimestampCreate(Calendar cal, int year,
 			int month, int day, int hour, int minute, int seconds,
 			int secondsPart) {
+		if (!this.useLegacyDatetimeCode) {
+			return TimeUtil.fastTimestampCreate(cal.getTimeZone(), year, month, day, hour,
+					minute, seconds, secondsPart);
+		}
+		
 		if (cal == null) {
 			createCalendarIfNeeded();
 			cal = this.fastDateCal;
@@ -2091,7 +2111,7 @@
 				return null;
 			}
 			
-			return getDateFromString(stringVal, columnIndex);
+			return getDateFromString(stringVal, columnIndex, cal);
 		}
 		
 		checkColumnBounds(columnIndex);
@@ -2106,7 +2126,7 @@
 		
 		this.wasNullFlag = false;
 		
-		return this.thisRow.getDateFast(columnIndexMinusOne, this.connection, this);
+		return this.thisRow.getDateFast(columnIndexMinusOne, this.connection, this, cal);
 	}
 
 	/**
@@ -2146,7 +2166,7 @@
 	}
 
 	private final java.sql.Date getDateFromString(String stringVal,
-			int columnIndex) throws SQLException {
+			int columnIndex, Calendar targetCalendar) throws SQLException {
 		int year = 0;
 		int month = 0;
 		int day = 0;
@@ -2189,7 +2209,7 @@
 
 				// We're left with the case of 'round' to a date Java _can_
 				// represent, which is '0001-01-01'.
-				return fastDateCreate(null, 1, 1, 1);
+				return fastDateCreate(targetCalendar, 1, 1, 1);
 
 			} else if (this.fields[columnIndex - 1].getMysqlType() ==
MysqlDefs.FIELD_TYPE_TIMESTAMP) {
 				// Convert from TIMESTAMP
@@ -2200,7 +2220,7 @@
 					month = Integer.parseInt(stringVal.substring(5, 7));
 					day = Integer.parseInt(stringVal.substring(8, 10));
 
-					return fastDateCreate(null, year, month, day);
+					return fastDateCreate(targetCalendar, year, month, day);
 				}
 
 				case 14:
@@ -2209,7 +2229,7 @@
 					month = Integer.parseInt(stringVal.substring(4, 6));
 					day = Integer.parseInt(stringVal.substring(6, 8));
 
-					return fastDateCreate(null, year, month, day);
+					return fastDateCreate(targetCalendar, year, month, day);
 				}
 
 				case 12:
@@ -2224,7 +2244,7 @@
 					month = Integer.parseInt(stringVal.substring(2, 4));
 					day = Integer.parseInt(stringVal.substring(4, 6));
 
-					return fastDateCreate(null, year + 1900, month, day);
+					return fastDateCreate(targetCalendar, year + 1900, month, day);
 				}
 
 				case 4: {
@@ -2236,7 +2256,7 @@
 
 					month = Integer.parseInt(stringVal.substring(2, 4));
 
-					return fastDateCreate(null, year + 1900, month, 1);
+					return fastDateCreate(targetCalendar, year + 1900, month, 1);
 				}
 
 				case 2: {
@@ -2246,7 +2266,7 @@
 						year = year + 100;
 					}
 
-					return fastDateCreate(null, year + 1900, 1, 1);
+					return fastDateCreate(targetCalendar, year + 1900, 1, 1);
 				}
 
 				default:
@@ -2269,13 +2289,13 @@
 					year = Integer.parseInt(stringVal.substring(0, 4));
 				}
 
-				return fastDateCreate(null, year, 1, 1);
+				return fastDateCreate(targetCalendar, year, 1, 1);
 			} else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_TIME) {
-				return fastDateCreate(null, 1970, 1, 1); // Return EPOCH
+				return fastDateCreate(targetCalendar, 1970, 1, 1); // Return EPOCH
 			} else {
 				if (stringVal.length() < 10) {
 					if (stringVal.length() == 8) {
-						return fastDateCreate(null, 1970, 1, 1); // Return EPOCH for TIME
+						return fastDateCreate(targetCalendar, 1970, 1, 1); // Return EPOCH for TIME
 					}
 					
 					throw SQLError.createSQLException(Messages.getString(
@@ -2298,7 +2318,7 @@
 				}
 			}
 
-			return fastDateCreate(null, year, month, day);
+			return fastDateCreate(targetCalendar, year, month, day);
 		} catch (SQLException sqlEx) {
 			throw sqlEx; // don't re-wrap
 		} catch (Exception e) {
@@ -2310,6 +2330,10 @@
 	}
 	
 	private TimeZone getDefaultTimeZone() {
+		if (!this.useLegacyDatetimeCode && this.connection != null) {
+			return this.serverTimeZoneTz;
+		}
+		
 		return this.connection.getDefaultTimeZone();
 	}
 
@@ -3835,7 +3859,7 @@
 
 		String stringVal = getNativeString(columnIndex);
 
-		return getDateFromString(stringVal, columnIndex);
+		return getDateFromString(stringVal, columnIndex, null);
 	}
 
 	/**
@@ -5567,7 +5591,7 @@
 					return stringVal;
 				}
 
-				Date dt = getDateFromString(stringVal, columnIndex);
+				Date dt = getDateFromString(stringVal, columnIndex, null);
 
 				if (dt == null) {
 					this.wasNullFlag = true;
@@ -5599,7 +5623,7 @@
 					return tm.toString();
 				case Types.DATE:
 
-					Date dt = getDateFromString(stringVal, columnIndex);
+					Date dt = getDateFromString(stringVal, columnIndex, null);
 
 					if (dt == null) {
 						this.wasNullFlag = true;
@@ -5748,7 +5772,7 @@
 
 				// We're left with the case of 'round' to a time Java _can_
 				// represent, which is '00:00:00'
-				return fastTimeCreate(null, 0, 0, 0);
+				return fastTimeCreate(targetCalendar, 0, 0, 0);
 			}
 
 			this.wasNullFlag = false;
@@ -5831,7 +5855,7 @@
 					this.warningChain.setNextWarning(precisionLost);
 				}
 			} else if (timeColField.getMysqlType() == MysqlDefs.FIELD_TYPE_DATE) {
-				return fastTimeCreate(null, 0, 0, 0); // midnight on the given
+				return fastTimeCreate(targetCalendar, 0, 0, 0); // midnight on the given
 														// date
 			} else {
 				// convert a String to a Time
@@ -6043,15 +6067,20 @@
 					
 				} else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR)
{
 					
-					return TimeUtil.changeTimezone(this.connection,
-							sessionCalendar, 
-							targetCalendar,
-							fastTimestampCreate(sessionCalendar, 
-									Integer
-									.parseInt(timestampValue.substring(0, 4)), 1,
-									1, 0, 0, 0, 0), this.connection
-									.getServerTimezoneTZ(), tz, rollForward);
-					
+					if (!this.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz, Integer
+										.parseInt(timestampValue.substring(0, 4)), 1,
+										1, 0, 0, 0, 0);
+					} else {
+						return TimeUtil.changeTimezone(this.connection,
+								sessionCalendar, 
+								targetCalendar,
+								fastTimestampCreate(sessionCalendar, 
+										Integer
+										.parseInt(timestampValue.substring(0, 4)), 1,
+										1, 0, 0, 0, 0), this.connection
+										.getServerTimezoneTZ(), tz, rollForward);
+					}
 				} else {
 					if (timestampValue.endsWith(".")) {
 						timestampValue = timestampValue.substring(0, timestampValue
@@ -6059,6 +6088,15 @@
 					}
 					
 					// Convert from TIMESTAMP or DATE
+					
+					int year = 0;
+					int month = 0;
+					int day = 0;
+					int hour = 0;
+					int minutes = 0;
+					int seconds = 0;
+					int nanos = 0;
+					
 					switch (length) {
 					case 26:
 					case 25:
@@ -6068,18 +6106,18 @@
 					case 21:
 					case 20:
 					case 19: {
-						int year = Integer.parseInt(timestampValue.substring(0, 4));
-						int month = Integer
+						year = Integer.parseInt(timestampValue.substring(0, 4));
+						month = Integer
 						.parseInt(timestampValue.substring(5, 7));
-						int day = Integer.parseInt(timestampValue.substring(8, 10));
-						int hour = Integer.parseInt(timestampValue
+						day = Integer.parseInt(timestampValue.substring(8, 10));
+						hour = Integer.parseInt(timestampValue
 								.substring(11, 13));
-						int minutes = Integer.parseInt(timestampValue.substring(14,
+						minutes = Integer.parseInt(timestampValue.substring(14,
 								16));
-						int seconds = Integer.parseInt(timestampValue.substring(17,
+						seconds = Integer.parseInt(timestampValue.substring(17,
 								19));
 						
-						int nanos = 0;
+						nanos = 0;
 						
 						if (length > 19) {
 							int decimalIndex = timestampValue.lastIndexOf('.');
@@ -6099,65 +6137,46 @@
 							}
 						}
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year, month, day, hour,
-										minutes, seconds, nanos), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 14: {
-						int year = Integer.parseInt(timestampValue.substring(0, 4));
-						int month = Integer
+						year = Integer.parseInt(timestampValue.substring(0, 4));
+						month = Integer
 						.parseInt(timestampValue.substring(4, 6));
-						int day = Integer.parseInt(timestampValue.substring(6, 8));
-						int hour = Integer
+						day = Integer.parseInt(timestampValue.substring(6, 8));
+						hour = Integer
 						.parseInt(timestampValue.substring(8, 10));
-						int minutes = Integer.parseInt(timestampValue.substring(10,
+						minutes = Integer.parseInt(timestampValue.substring(10,
 								12));
-						int seconds = Integer.parseInt(timestampValue.substring(12,
+						seconds = Integer.parseInt(timestampValue.substring(12,
 								14));
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar, 
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year, month, day, hour,
-										minutes, seconds, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 12: {
-						int year = Integer.parseInt(timestampValue.substring(0, 2));
+						year = Integer.parseInt(timestampValue.substring(0, 2));
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						int month = Integer
+						year += 1900;
+						
+						month = Integer
 						.parseInt(timestampValue.substring(2, 4));
-						int day = Integer.parseInt(timestampValue.substring(4, 6));
-						int hour = Integer.parseInt(timestampValue.substring(6, 8));
-						int minutes = Integer.parseInt(timestampValue.substring(8,
+						day = Integer.parseInt(timestampValue.substring(4, 6));
+						hour = Integer.parseInt(timestampValue.substring(6, 8));
+						minutes = Integer.parseInt(timestampValue.substring(8,
 								10));
-						int seconds = Integer.parseInt(timestampValue.substring(10,
+						seconds = Integer.parseInt(timestampValue.substring(10,
 								12));
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year + 1900, month, day,
-										hour, minutes, seconds, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 10: {
-						int year;
-						int month;
-						int day;
-						int hour;
-						int minutes;
-						
 						if ((this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_DATE)
 								|| (timestampValue.indexOf("-") != -1)) {
 							year = Integer.parseInt(timestampValue.substring(0, 4));
@@ -6183,97 +6202,79 @@
 							year += 1900; // two-digit year
 						}
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year, month, day, hour,
-										minutes, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 8: {
 						if (timestampValue.indexOf(":") != -1) {
-							int hour = Integer.parseInt(timestampValue.substring(0,
+							hour = Integer.parseInt(timestampValue.substring(0,
 									2));
-							int minutes = Integer.parseInt(timestampValue
+							minutes = Integer.parseInt(timestampValue
 									.substring(3, 5));
-							int seconds = Integer.parseInt(timestampValue
+							seconds = Integer.parseInt(timestampValue
 									.substring(6, 8));
-							
-							return TimeUtil
-							.changeTimezone(this.connection,
-									sessionCalendar,
-									targetCalendar,
-									fastTimestampCreate(sessionCalendar, 1970, 1, 1,
-											hour, minutes, seconds, 0),
-											this.connection.getServerTimezoneTZ(),
-											tz, rollForward);
-							
+							year = 1970;
+							month = 1;
+							day = 1;
+							break;
 						}
 						
-						int year = Integer.parseInt(timestampValue.substring(0, 4));
-						int month = Integer
+						year = Integer.parseInt(timestampValue.substring(0, 4));
+						month = Integer
 						.parseInt(timestampValue.substring(4, 6));
-						int day = Integer.parseInt(timestampValue.substring(6, 8));
+						day = Integer.parseInt(timestampValue.substring(6, 8));
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year - 1900, month - 1,
-										day, 0, 0, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						year -= 1900;
+						month--;
+						
+						break;
 					}
 					
 					case 6: {
-						int year = Integer.parseInt(timestampValue.substring(0, 2));
+						year = Integer.parseInt(timestampValue.substring(0, 2));
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						int month = Integer
+						year += 1900;
+						
+						month = Integer
 						.parseInt(timestampValue.substring(2, 4));
-						int day = Integer.parseInt(timestampValue.substring(4, 6));
+						day = Integer.parseInt(timestampValue.substring(4, 6));
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year + 1900, month, day,
-										0, 0, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 4: {
-						int year = Integer.parseInt(timestampValue.substring(0, 2));
+						year = Integer.parseInt(timestampValue.substring(0, 2));
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						int month = Integer
+						year += 1900;
+						
+						month = Integer
 						.parseInt(timestampValue.substring(2, 4));
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year + 1900, month, 1, 0,
-										0, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						day = 1;
+						
+						break;
 					}
 					
 					case 2: {
-						int year = Integer.parseInt(timestampValue.substring(0, 2));
+						year = Integer.parseInt(timestampValue.substring(0, 2));
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(null, year + 1900, 1, 1, 0, 0,
-										0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						year += 1900;
+						month = 1;
+						day = 1;
+						
+						break;
 					}
 					
 					default:
@@ -6282,6 +6283,18 @@
 								+ "' in column " + columnIndex + ".",
 								SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 					}
+					
+					if (!this.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz, year, month, day, hour,
+								minutes, seconds, nanos);
+					}
+						
+					return TimeUtil.changeTimezone(this.connection,
+							sessionCalendar,
+							targetCalendar,
+							fastTimestampCreate(sessionCalendar, year, month, day, hour,
+									minutes, seconds, nanos), this.connection
+									.getServerTimezoneTZ(), tz, rollForward);
 				}
 			}
 		} catch (Exception e) {
@@ -6349,24 +6362,41 @@
 					
 					// We're left with the case of 'round' to a date Java _can_
 					// represent, which is '0001-01-01'.
+					if (!this.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz,
+								1, 1, 1, 0, 0, 0, 0);
+					}
+
 					return fastTimestampCreate(null, 1, 1, 1, 0, 0, 0, 0);
-					
 				} else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR)
{
 					
+					if (!this.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz,
+								StringUtils.getInt(timestampAsBytes, 0, 4), 1, 1, 0, 0, 0, 0);
+					}
+					
 					return TimeUtil.changeTimezone(this.connection,
-							sessionCalendar, 
-							targetCalendar,
-							fastTimestampCreate(sessionCalendar, 
-									StringUtils.getInt(timestampAsBytes, 0, 4), 1,
-									1, 0, 0, 0, 0), this.connection
-									.getServerTimezoneTZ(), tz, rollForward);
-					
+						sessionCalendar, 
+						targetCalendar,
+						fastTimestampCreate(sessionCalendar, 
+								StringUtils.getInt(timestampAsBytes, 0, 4), 1,
+								1, 0, 0, 0, 0), this.connection
+								.getServerTimezoneTZ(), tz, rollForward);
 				} else {
 					if (timestampAsBytes[length - 1] == '.') {
 						length--;
 					}
 					
 					// Convert from TIMESTAMP or DATE
+					
+					int year = 0;
+					int month = 0;
+					int day = 0;
+					int hour = 0;
+					int minutes = 0;
+					int seconds = 0;
+					int nanos = 0;
+					
 					switch (length) {
 					case 26:
 					case 25:
@@ -6376,14 +6406,14 @@
 					case 21:
 					case 20:
 					case 19: {
-						int year = StringUtils.getInt(timestampAsBytes, 0, 4);
-						int month = StringUtils.getInt(timestampAsBytes, 5, 7);
-						int day = StringUtils.getInt(timestampAsBytes, 8, 10);
-						int hour = StringUtils.getInt(timestampAsBytes, 11, 13);
-						int minutes = StringUtils.getInt(timestampAsBytes, 14, 16);
-						int seconds = StringUtils.getInt(timestampAsBytes, 17, 19);
+						year = StringUtils.getInt(timestampAsBytes, 0, 4);
+						month = StringUtils.getInt(timestampAsBytes, 5, 7);
+						day = StringUtils.getInt(timestampAsBytes, 8, 10);
+						hour = StringUtils.getInt(timestampAsBytes, 11, 13);
+						minutes = StringUtils.getInt(timestampAsBytes, 14, 16);
+						seconds = StringUtils.getInt(timestampAsBytes, 17, 19);
 						
-						int nanos = 0;
+						nanos = 0;
 						
 						if (length > 19) {
 							int decimalIndex = StringUtils.lastIndexOf(timestampAsBytes, '.');
@@ -6402,58 +6432,39 @@
 							}
 						}
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year, month, day, hour,
-										minutes, seconds, nanos), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 14: {
-						int year = StringUtils.getInt(timestampAsBytes, 0, 4);
-						int month = StringUtils.getInt(timestampAsBytes, 4, 6);
-						int day = StringUtils.getInt(timestampAsBytes, 6, 8);
-						int hour = StringUtils.getInt(timestampAsBytes, 8, 10);
-						int minutes = StringUtils.getInt(timestampAsBytes, 10, 12);
-						int seconds = StringUtils.getInt(timestampAsBytes, 12, 14);
+						year = StringUtils.getInt(timestampAsBytes, 0, 4);
+						month = StringUtils.getInt(timestampAsBytes, 4, 6);
+						day = StringUtils.getInt(timestampAsBytes, 6, 8);
+						hour = StringUtils.getInt(timestampAsBytes, 8, 10);
+						minutes = StringUtils.getInt(timestampAsBytes, 10, 12);
+						seconds = StringUtils.getInt(timestampAsBytes, 12, 14);
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar, 
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year, month, day, hour,
-										minutes, seconds, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 12: {
-						int year = StringUtils.getInt(timestampAsBytes, 0, 2);
+						year = StringUtils.getInt(timestampAsBytes, 0, 2);
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						int month = StringUtils.getInt(timestampAsBytes, 2, 4);
-						int day = StringUtils.getInt(timestampAsBytes, 4, 6);
-						int hour = StringUtils.getInt(timestampAsBytes, 6, 8);
-						int minutes = StringUtils.getInt(timestampAsBytes, 8,	10);
-						int seconds = StringUtils.getInt(timestampAsBytes, 10, 12);
+						year += 1900;
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year + 1900, month, day,
-										hour, minutes, seconds, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						month = StringUtils.getInt(timestampAsBytes, 2, 4);
+						day = StringUtils.getInt(timestampAsBytes, 4, 6);
+						hour = StringUtils.getInt(timestampAsBytes, 6, 8);
+						minutes = StringUtils.getInt(timestampAsBytes, 8,	10);
+						seconds = StringUtils.getInt(timestampAsBytes, 10, 12);
+						
+						break;
 					}
 					
 					case 10: {
-						int year;
-						int month;
-						int day;
-						int hour;
-						int minutes;
-						
 						if ((this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_DATE)
 								|| (StringUtils.indexOf(timestampAsBytes, '-') != -1)) {
 							year = StringUtils.getInt(timestampAsBytes, 0, 4);
@@ -6476,91 +6487,74 @@
 							year += 1900; // two-digit year
 						}
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year, month, day, hour,
-										minutes, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						break;
 					}
 					
 					case 8: {
 						if (StringUtils.indexOf(timestampAsBytes, ':') != -1) {
-							int hour = StringUtils.getInt(timestampAsBytes, 0, 2);
-							int minutes = StringUtils.getInt(timestampAsBytes, 3, 5);
-							int seconds = StringUtils.getInt(timestampAsBytes, 6, 8);
+							hour = StringUtils.getInt(timestampAsBytes, 0, 2);
+							minutes = StringUtils.getInt(timestampAsBytes, 3, 5);
+							seconds = StringUtils.getInt(timestampAsBytes, 6, 8);
 							
-							return TimeUtil
-							.changeTimezone(this.connection,
-									sessionCalendar,
-									targetCalendar,
-									fastTimestampCreate(sessionCalendar, 1970, 1, 1,
-											hour, minutes, seconds, 0),
-											this.connection.getServerTimezoneTZ(),
-											tz, rollForward);
+							year = 1970;
+							month = 1;
+							day = 1;
 							
+							break;
 						}
 						
-						int year = StringUtils.getInt(timestampAsBytes, 0, 4);
-						int month = StringUtils.getInt(timestampAsBytes, 4, 6);
-						int day = StringUtils.getInt(timestampAsBytes, 6, 8);
+						year = StringUtils.getInt(timestampAsBytes, 0, 4);
+						month = StringUtils.getInt(timestampAsBytes, 4, 6);
+						day = StringUtils.getInt(timestampAsBytes, 6, 8);
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year - 1900, month - 1,
-										day, 0, 0, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						year -= 1900;
+						month--;
+						
+						break;
 					}
 					
 					case 6: {
-						int year = StringUtils.getInt(timestampAsBytes, 0, 2);
+						year = StringUtils.getInt(timestampAsBytes, 0, 2);
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						int month = StringUtils.getInt(timestampAsBytes, 2, 4);
-						int day = StringUtils.getInt(timestampAsBytes, 4, 6);
+						year += 1900;
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year + 1900, month, day,
-										0, 0, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						month = StringUtils.getInt(timestampAsBytes, 2, 4);
+						day = StringUtils.getInt(timestampAsBytes, 4, 6);
+						
+						break;
 					}
 					
 					case 4: {
-						int year = StringUtils.getInt(timestampAsBytes, 0, 2);
+						year = StringUtils.getInt(timestampAsBytes, 0, 2);
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						int month = StringUtils.getInt(timestampAsBytes, 2, 4);
+						year += 1900;
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(sessionCalendar, year + 1900, month, 1, 0,
-										0, 0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						month = StringUtils.getInt(timestampAsBytes, 2, 4);
+						day = 1;
+						
+						break;
 					}
 					
 					case 2: {
-						int year = StringUtils.getInt(timestampAsBytes, 0, 2);
+						year = StringUtils.getInt(timestampAsBytes, 0, 2);
 						
 						if (year <= 69) {
 							year = (year + 100);
 						}
 						
-						return TimeUtil.changeTimezone(this.connection,
-								sessionCalendar,
-								targetCalendar,
-								fastTimestampCreate(null, year + 1900, 1, 1, 0, 0,
-										0, 0), this.connection
-										.getServerTimezoneTZ(), tz, rollForward);
+						year += 1900;
+						month = 1;
+						day = 1;
+						
+						break;
 					}
 					
 					default:
@@ -6569,6 +6563,18 @@
 								+ "' in column " + columnIndex + ".",
 								SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 					}
+					
+					if (!this.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz,
+								year, month, day, hour, minutes, seconds, nanos);
+					}
+					
+					return TimeUtil.changeTimezone(this.connection,
+						sessionCalendar,
+						targetCalendar,
+						fastTimestampCreate(sessionCalendar, year, month, day, hour,
+								minutes, seconds, nanos), this.connection
+								.getServerTimezoneTZ(), tz, rollForward);
 				}
 			}
 		} catch (Exception e) {

Modified: trunk/src/com/mysql/jdbc/ResultSetRow.java
===================================================================
--- trunk/src/com/mysql/jdbc/ResultSetRow.java	2007-11-28 21:50:11 UTC (rev 6687)
+++ trunk/src/com/mysql/jdbc/ResultSetRow.java	2007-11-28 22:08:47 UTC (rev 6688)
@@ -86,7 +86,7 @@
 
 	protected final java.sql.Date getDateFast(int columnIndex,
 			byte[] dateAsBytes, int offset, int length, ConnectionImpl conn,
-			ResultSetImpl rs) throws SQLException {
+			ResultSetImpl rs, Calendar targetCalendar) throws SQLException {
 
 		int year = 0;
 		int month = 0;
@@ -139,7 +139,7 @@
 
 				// We're left with the case of 'round' to a date Java _can_
 				// represent, which is '0001-01-01'.
-				return rs.fastDateCreate(null, 1, 1, 1);
+				return rs.fastDateCreate(targetCalendar, 1, 1, 1);
 
 			} else if (this.metadata[columnIndex].getMysqlType() ==
MysqlDefs.FIELD_TYPE_TIMESTAMP) {
 				// Convert from TIMESTAMP
@@ -153,7 +153,7 @@
 					day = StringUtils.getInt(dateAsBytes, offset + 8,
 							offset + 10);
 
-					return rs.fastDateCreate(null, year, month, day);
+					return rs.fastDateCreate(targetCalendar, year, month, day);
 				}
 
 				case 14:
@@ -165,7 +165,7 @@
 					day = StringUtils.getInt(dateAsBytes, offset + 6,
 							offset + 8);
 
-					return rs.fastDateCreate(null, year, month, day);
+					return rs.fastDateCreate(targetCalendar, year, month, day);
 				}
 
 				case 12:
@@ -183,7 +183,7 @@
 					day = StringUtils.getInt(dateAsBytes, offset + 4,
 							offset + 6);
 
-					return rs.fastDateCreate(null, year + 1900, month, day);
+					return rs.fastDateCreate(targetCalendar, year + 1900, month, day);
 				}
 
 				case 4: {
@@ -197,7 +197,7 @@
 					month = StringUtils.getInt(dateAsBytes, offset + 2,
 							offset + 4);
 
-					return rs.fastDateCreate(null, year + 1900, month, 1);
+					return rs.fastDateCreate(targetCalendar, year + 1900, month, 1);
 				}
 
 				case 2: {
@@ -208,7 +208,7 @@
 						year = year + 100;
 					}
 
-					return rs.fastDateCreate(null, year + 1900, 1, 1);
+					return rs.fastDateCreate(targetCalendar, year + 1900, 1, 1);
 				}
 
 				default:
@@ -240,13 +240,13 @@
 							offset + 4);
 				}
 
-				return rs.fastDateCreate(null, year, 1, 1);
+				return rs.fastDateCreate(targetCalendar, year, 1, 1);
 			} else if (this.metadata[columnIndex].getMysqlType() == MysqlDefs.FIELD_TYPE_TIME) {
-				return rs.fastDateCreate(null, 1970, 1, 1); // Return EPOCH
+				return rs.fastDateCreate(targetCalendar, 1970, 1, 1); // Return EPOCH
 			} else {
 				if (length < 10) {
 					if (length == 8) {
-						return rs.fastDateCreate(null, 1970, 1, 1); // Return
+						return rs.fastDateCreate(targetCalendar, 1970, 1, 1); // Return
 						// EPOCH for
 						// TIME
 					}
@@ -283,7 +283,7 @@
 				}
 			}
 
-			return rs.fastDateCreate(null, year, month, day);
+			return rs.fastDateCreate(targetCalendar, year, month, day);
 		} catch (SQLException sqlEx) {
 			throw sqlEx; // don't re-wrap
 		} catch (Exception e) {
@@ -296,7 +296,7 @@
 	}
 
 	public abstract java.sql.Date getDateFast(int columnIndex,
-			ConnectionImpl conn, ResultSetImpl rs) throws SQLException;
+			ConnectionImpl conn, ResultSetImpl rs, Calendar targetCalendar) throws SQLException;
 
 	/**
 	 * Returns the value at the given column (index starts at 0) as an int. *
@@ -354,6 +354,10 @@
 			day = 1;
 		}
 
+		if (!rs.useLegacyDatetimeCode) {
+			return TimeUtil.fastDateCreate(year, month, day, null);
+		}
+		
 		return rs.fastDateCreate(rs.getCalendarInstanceForSessionOrNew(), year,
 				month, day);
 	}
@@ -447,6 +451,10 @@
 		switch (jdbcType) {
 		case Types.TIME:
 			if (populatedFromDateTimeValue) {
+				if (!rs.useLegacyDatetimeCode) {
+					return TimeUtil.fastTimeCreate(hour, minute, seconds, targetCalendar);
+				}
+				
 				Time time = TimeUtil.fastTimeCreate(rs
 						.getCalendarInstanceForSessionOrNew(), hour, minute,
 						seconds);
@@ -480,6 +488,10 @@
 					day = 1;
 				}
 
+				if (!rs.useLegacyDatetimeCode) {
+					return TimeUtil.fastDateCreate(year, month, day, targetCalendar);
+				}
+				
 				return rs
 						.fastDateCreate(
 								rs.getCalendarInstanceForSessionOrNew(), year,
@@ -506,6 +518,11 @@
 					day = 1;
 				}
 
+				if (!rs.useLegacyDatetimeCode) {
+					return TimeUtil.fastTimestampCreate(tz, year, month, day, hour, minute, 
+							seconds, nanos);
+				}
+				
 				Timestamp ts = rs.fastTimestampCreate(rs
 						.getCalendarInstanceForSessionOrNew(), year, month,
 						day, hour, minute, seconds, nanos);
@@ -610,6 +627,10 @@
 			seconds = bits[offset + 7];
 		}
 
+		if (!rs.useLegacyDatetimeCode) {
+			return TimeUtil.fastTimeCreate(hour, minute, seconds, targetCalendar);
+		}
+		
 		Calendar sessionCalendar = rs.getCalendarInstanceForSessionOrNew();
 
 		synchronized (sessionCalendar) {
@@ -678,6 +699,11 @@
 			day = 1;
 		}
 
+		if (!rs.useLegacyDatetimeCode) {
+			return TimeUtil.fastTimestampCreate(tz, year, month,
+					day, hour, minute, seconds, nanos);
+		}
+		
 		Calendar sessionCalendar = conn.getUseJDBCCompliantTimezoneShift() ? conn
 				.getUtcCalendar()
 				: rs.getCalendarInstanceForSessionOrNew();
@@ -828,7 +854,7 @@
 
 				// We're left with the case of 'round' to a time Java _can_
 				// represent, which is '00:00:00'
-				return rs.fastTimeCreate(null, 0, 0, 0);
+				return rs.fastTimeCreate(targetCalendar, 0, 0, 0);
 			}
 
 			Field timeColField = this.metadata[columnIndex];
@@ -927,6 +953,10 @@
 
 			Calendar sessionCalendar = rs.getCalendarInstanceForSessionOrNew();
 
+			if (!rs.useLegacyDatetimeCode) {
+				return rs.fastTimeCreate(targetCalendar, hr, min, sec);
+			}
+			
 			synchronized (sessionCalendar) {
 				return TimeUtil.changeTimezone(conn, sessionCalendar,
 						targetCalendar, rs.fastTimeCreate(sessionCalendar, hr,
@@ -996,25 +1026,42 @@
 										SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 					}
 
+					if (!rs.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz, 1, 1, 1, 0, 0, 0, 0);
+					}
 					// We're left with the case of 'round' to a date Java _can_
 					// represent, which is '0001-01-01'.
 					return rs.fastTimestampCreate(null, 1, 1, 1, 0, 0, 0, 0);
 
 				} else if (this.metadata[columnIndex].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR) {
 
+					if (!rs.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz, StringUtils
+								.getInt(timestampAsBytes, offset, 4), 1, 1, 0,
+								0, 0, 0);
+					}
+					
 					return TimeUtil.changeTimezone(conn, sessionCalendar,
-							targetCalendar, rs.fastTimestampCreate(
-									sessionCalendar, StringUtils.getInt(
-											timestampAsBytes, offset, 4), 1, 1,
-									0, 0, 0, 0), conn.getServerTimezoneTZ(),
-							tz, rollForward);
-
+						targetCalendar, rs.fastTimestampCreate(
+								sessionCalendar, StringUtils.getInt(
+										timestampAsBytes, offset, 4), 1, 1,
+								0, 0, 0, 0), conn.getServerTimezoneTZ(),
+						tz, rollForward);
 				} else {
 					if (timestampAsBytes[offset + length - 1] == '.') {
 						length--;
 					}
 
 					// Convert from TIMESTAMP or DATE
+					
+					int year = 0;
+					int month = 0;
+					int day = 0;
+					int hour = 0;
+					int minutes = 0;
+					int seconds = 0;
+					int nanos = 0;
+					
 					switch (length) {
 					case 26:
 					case 25:
@@ -1024,20 +1071,20 @@
 					case 21:
 					case 20:
 					case 19: {
-						int year = StringUtils.getInt(timestampAsBytes,
+						year = StringUtils.getInt(timestampAsBytes,
 								offset + 0, offset + 4);
-						int month = StringUtils.getInt(timestampAsBytes,
+						month = StringUtils.getInt(timestampAsBytes,
 								offset + 5, offset + 7);
-						int day = StringUtils.getInt(timestampAsBytes,
+						day = StringUtils.getInt(timestampAsBytes,
 								offset + 8, offset + 10);
-						int hour = StringUtils.getInt(timestampAsBytes,
+						hour = StringUtils.getInt(timestampAsBytes,
 								offset + 11, offset + 13);
-						int minutes = StringUtils.getInt(timestampAsBytes,
+						minutes = StringUtils.getInt(timestampAsBytes,
 								offset + 14, offset + 16);
-						int seconds = StringUtils.getInt(timestampAsBytes,
+						seconds = StringUtils.getInt(timestampAsBytes,
 								offset + 17, offset + 19);
 
-						int nanos = 0;
+						nanos = 0;
 
 						if (length > 19) {
 							int decimalIndex = -1;
@@ -1064,76 +1111,51 @@
 							}
 						}
 
-						return TimeUtil
-								.changeTimezone(conn, sessionCalendar,
-										targetCalendar, rs.fastTimestampCreate(
-												sessionCalendar, year, month,
-												day, hour, minutes, seconds,
-												nanos), conn
-												.getServerTimezoneTZ(), tz,
-										rollForward);
+						break;
 					}
 
 					case 14: {
-						int year = StringUtils.getInt(timestampAsBytes,
+						year = StringUtils.getInt(timestampAsBytes,
 								offset + 0, offset + 4);
-						int month = StringUtils.getInt(timestampAsBytes,
+						month = StringUtils.getInt(timestampAsBytes,
 								offset + 4, offset + 6);
-						int day = StringUtils.getInt(timestampAsBytes,
+						day = StringUtils.getInt(timestampAsBytes,
 								offset + 6, offset + 8);
-						int hour = StringUtils.getInt(timestampAsBytes,
+						hour = StringUtils.getInt(timestampAsBytes,
 								offset + 8, offset + 10);
-						int minutes = StringUtils.getInt(timestampAsBytes,
+						minutes = StringUtils.getInt(timestampAsBytes,
 								offset + 10, offset + 12);
-						int seconds = StringUtils.getInt(timestampAsBytes,
+						seconds = StringUtils.getInt(timestampAsBytes,
 								offset + 12, offset + 14);
 
-						return TimeUtil
-								.changeTimezone(conn, sessionCalendar,
-										targetCalendar,
-										rs.fastTimestampCreate(sessionCalendar,
-												year, month, day, hour,
-												minutes, seconds, 0), conn
-												.getServerTimezoneTZ(), tz,
-										rollForward);
+						break;
 					}
 
 					case 12: {
-						int year = StringUtils.getInt(timestampAsBytes,
+						year = StringUtils.getInt(timestampAsBytes,
 								offset + 0, offset + 2);
 
 						if (year <= 69) {
 							year = (year + 100);
 						}
+						
+						year += 1900;
 
-						int month = StringUtils.getInt(timestampAsBytes,
+						month = StringUtils.getInt(timestampAsBytes,
 								offset + 2, offset + 4);
-						int day = StringUtils.getInt(timestampAsBytes,
+						day = StringUtils.getInt(timestampAsBytes,
 								offset + 4, offset + 6);
-						int hour = StringUtils.getInt(timestampAsBytes,
+						hour = StringUtils.getInt(timestampAsBytes,
 								offset + 6, offset + 8);
-						int minutes = StringUtils.getInt(timestampAsBytes,
+						minutes = StringUtils.getInt(timestampAsBytes,
 								offset + 8, offset + 10);
-						int seconds = StringUtils.getInt(timestampAsBytes,
+						seconds = StringUtils.getInt(timestampAsBytes,
 								offset + 10, offset + 12);
 
-						return TimeUtil
-								.changeTimezone(conn, sessionCalendar,
-										targetCalendar, rs.fastTimestampCreate(
-												sessionCalendar, year + 1900,
-												month, day, hour, minutes,
-												seconds, 0), conn
-												.getServerTimezoneTZ(), tz,
-										rollForward);
+						break;
 					}
 
 					case 10: {
-						int year;
-						int month;
-						int day;
-						int hour;
-						int minutes;
-
 						boolean hasDash = false;
 
 						for (int i = 0; i < length; i++) {
@@ -1173,13 +1195,7 @@
 							year += 1900; // two-digit year
 						}
 
-						return TimeUtil
-								.changeTimezone(conn, sessionCalendar,
-										targetCalendar, rs.fastTimestampCreate(
-												sessionCalendar, year, month,
-												day, hour, minutes, 0, 0), conn
-												.getServerTimezoneTZ(), tz,
-										rollForward);
+						break;
 					}
 
 					case 8: {
@@ -1193,95 +1209,80 @@
 						}
 
 						if (hasColon) {
-							int hour = StringUtils.getInt(timestampAsBytes,
+							hour = StringUtils.getInt(timestampAsBytes,
 									offset + 0, offset + 2);
-							int minutes = StringUtils.getInt(timestampAsBytes,
+							minutes = StringUtils.getInt(timestampAsBytes,
 									offset + 3, offset + 5);
-							int seconds = StringUtils.getInt(timestampAsBytes,
+							seconds = StringUtils.getInt(timestampAsBytes,
 									offset + 6, offset + 8);
+							
+							year = 1970;
+							month = 1;
+							day = 1;
 
-							return TimeUtil.changeTimezone(conn,
-									sessionCalendar, targetCalendar, rs
-											.fastTimestampCreate(
-													sessionCalendar, 1970, 1,
-													1, hour, minutes, seconds,
-													0), conn
-											.getServerTimezoneTZ(), tz,
-									rollForward);
-
+							break;
 						}
 
-						int year = StringUtils.getInt(timestampAsBytes,
+						year = StringUtils.getInt(timestampAsBytes,
 								offset + 0, offset + 4);
-						int month = StringUtils.getInt(timestampAsBytes,
+						month = StringUtils.getInt(timestampAsBytes,
 								offset + 4, offset + 6);
-						int day = StringUtils.getInt(timestampAsBytes,
+						day = StringUtils.getInt(timestampAsBytes,
 								offset + 6, offset + 8);
 
-						return TimeUtil
-								.changeTimezone(conn, sessionCalendar,
-										targetCalendar, rs.fastTimestampCreate(
-												sessionCalendar, year - 1900,
-												month - 1, day, 0, 0, 0, 0),
-										conn.getServerTimezoneTZ(), tz,
-										rollForward);
+						year -= 1900;
+						month--;
+						
+						break;
 					}
 
 					case 6: {
-						int year = StringUtils.getInt(timestampAsBytes,
+						year = StringUtils.getInt(timestampAsBytes,
 								offset + 0, offset + 2);
 
 						if (year <= 69) {
 							year = (year + 100);
 						}
 
-						int month = StringUtils.getInt(timestampAsBytes,
+						year += 1900;
+						
+						month = StringUtils.getInt(timestampAsBytes,
 								offset + 2, offset + 4);
-						int day = StringUtils.getInt(timestampAsBytes,
+						day = StringUtils.getInt(timestampAsBytes,
 								offset + 4, offset + 6);
 
-						return TimeUtil
-								.changeTimezone(conn, sessionCalendar,
-										targetCalendar, rs.fastTimestampCreate(
-												sessionCalendar, year + 1900,
-												month, day, 0, 0, 0, 0), conn
-												.getServerTimezoneTZ(), tz,
-										rollForward);
+						break;
 					}
 
 					case 4: {
-						int year = StringUtils.getInt(timestampAsBytes,
+						year = StringUtils.getInt(timestampAsBytes,
 								offset + 0, offset + 2);
 
 						if (year <= 69) {
 							year = (year + 100);
 						}
 
-						int month = StringUtils.getInt(timestampAsBytes,
+						month = StringUtils.getInt(timestampAsBytes,
 								offset + 2, offset + 4);
-
-						return TimeUtil.changeTimezone(conn, sessionCalendar,
-								targetCalendar, rs.fastTimestampCreate(
-										sessionCalendar, year + 1900, month, 1,
-										0, 0, 0, 0),
-								conn.getServerTimezoneTZ(), tz, rollForward);
+						
+						day = 1;
+						
+						break;
 					}
 
 					case 2: {
-						int year = StringUtils.getInt(timestampAsBytes,
+						year = StringUtils.getInt(timestampAsBytes,
 								offset + 0, offset + 2);
 
 						if (year <= 69) {
 							year = (year + 100);
 						}
 
-						return TimeUtil
-								.changeTimezone(conn, sessionCalendar,
-										targetCalendar, rs.fastTimestampCreate(
-												null, year + 1900, 1, 1, 0, 0,
-												0, 0), conn
-												.getServerTimezoneTZ(), tz,
-										rollForward);
+						year += 1900;
+						month = 1;
+						day = 1;
+						
+						break;
 					}
 
 					default:
@@ -1292,6 +1293,22 @@
 										+ ".",
 								SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 					}
+					
+					if (!rs.useLegacyDatetimeCode) {
+						return TimeUtil.fastTimestampCreate(tz,
+								year, month,
+								day, hour, minutes, seconds,
+								nanos);
+					}
+						
+					return TimeUtil
+							.changeTimezone(conn, sessionCalendar,
+									targetCalendar, rs.fastTimestampCreate(
+											sessionCalendar, year, month,
+											day, hour, minutes, seconds,
+											nanos), conn
+											.getServerTimezoneTZ(), tz,
+									rollForward);
 				}
 			}
 		} catch (Exception e) {

Modified: trunk/src/com/mysql/jdbc/ServerPreparedStatement.java
===================================================================
--- trunk/src/com/mysql/jdbc/ServerPreparedStatement.java	2007-11-28 21:50:11 UTC (rev
6687)
+++ trunk/src/com/mysql/jdbc/ServerPreparedStatement.java	2007-11-28 22:08:47 UTC (rev
6688)
@@ -55,6 +55,7 @@
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.GregorianCalendar;
 import java.util.Properties;
 import java.util.TimeZone;
 
@@ -575,6 +576,10 @@
 
 	private boolean useAutoSlowLog;
 
+	private Calendar serverTzCalendar;
+
+	private Calendar defaultTzCalendar;
+
 	protected void setClosed(boolean flag) {
 		this.isClosed = flag;
 	}
@@ -2144,15 +2149,19 @@
 			BindValue binding = getBinding(parameterIndex, false);
 			setType(binding, MysqlDefs.FIELD_TYPE_TIME);
 
-			Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
-			
-			synchronized (sessionCalendar) {
-				binding.value = TimeUtil.changeTimezone(this.connection, 
-						sessionCalendar,
-						targetCalendar,
-						x, tz,
-						this.connection.getServerTimezoneTZ(), 
-						rollForward);
+			if (!this.useLegacyDatetimeCode) {
+				binding.value = x;