changeset 109:e026fe73bb5e embedded

After a lot of suffering, finnaly passed all the tests in a MAPI connection! :) Now I will port some for the embedded connection, as some features are no available on it.
author Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
date Tue, 24 Jan 2017 17:11:25 +0100 (2017-01-24)
parents d39f656b6614
children 8af0a7387b4e
files src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java src/main/java/nl/cwi/monetdb/jdbc/MonetINET.java src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java src/main/java/nl/cwi/monetdb/jdbc/MonetURL.java src/main/java/nl/cwi/monetdb/mcl/connection/helpers/GregorianCalendarParser.java src/main/java/nl/cwi/monetdb/mcl/connection/helpers/TimestampHelper.java src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java
diffstat 13 files changed, 679 insertions(+), 209 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
@@ -47,6 +47,11 @@ public abstract class MonetConnection ex
     /** The sequence counter */
     private static int SeqCounter = 0;
 
+    /**
+     * Gets the current sequence counter.
+     *
+     * @return The current sequence counter
+     */
     public static int GetSeqCounter() {
         return SeqCounter;
     }
@@ -69,6 +74,7 @@ public abstract class MonetConnection ex
     private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {
         private static final long serialVersionUID = 1L; {
             put("inet", MonetINET.class);
+            put("url", MonetURL.class);
         }
     };
 
@@ -106,6 +112,15 @@ public abstract class MonetConnection ex
     }
 
     /**
+     * Checks if the conection is embedded or not
+     *
+     * @return If the connection is embedded
+     */
+    public boolean isEmbedded() {
+        return isEmbedded;
+    }
+
+    /**
      * Gets the connection's language data.
      *
      * @return The connection's language data
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetINET.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetINET.java
@@ -29,6 +29,8 @@ import java.sql.SQLOutput;
  * This class allows to retrieve the value of this INET as InetAddress.
  * This is probably meaningful only and only if the netmask is 32.  The
  * getNetmaskBits() method can be used to retrieve the subnet bits.
+ *
+ * @author Fabian Groffen
  */
 public class MonetINET implements SQLData {
 
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java
@@ -44,23 +44,11 @@ import java.util.Map;
  * [ "int",        9,      0       ]
  * </pre>
  *
- * @author Fabian Groffen, Martin van Dinther
+ * @author Fabian Groffen, Martin van Dinther, Pedro Ferreira
  * @version 0.4
  */
 public class MonetPreparedStatement extends MonetStatement implements PreparedStatement {
 
-	/* only parse the date patterns once, use multiple times */
-	/** Format of a timestamp with RFC822 time zone */
-	private static final SimpleDateFormat MTimestampZ = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
-	/** Format of a timestamp */
-	private static final SimpleDateFormat MTimestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-	/** Format of a time with RFC822 time zone */
-	private static final SimpleDateFormat MTimeZ = new SimpleDateFormat("HH:mm:ss.SSSZ");
-	/** Format of a time */
-	private static final SimpleDateFormat MTime = new SimpleDateFormat("HH:mm:ss.SSS");
-	/** Format of a date used by mserver */
-	private static final SimpleDateFormat MDate = new SimpleDateFormat("yyyy-MM-dd");
-
 	private final MonetConnection connection;
 	private final String[] monetdbType;
 	private final int[] javaType;
@@ -74,6 +62,12 @@ public class MonetPreparedStatement exte
 	private final int rscolcnt;
 	private final String[] values;
 
+	private final SimpleDateFormat mTimestampZ;
+	private final SimpleDateFormat mTimestamp;
+	private final SimpleDateFormat mTimeZ;
+	private final SimpleDateFormat mTime;
+	private final SimpleDateFormat mDate;
+
 	/**
 	 * MonetPreparedStatement constructor which checks the arguments for validity. A MonetPreparedStatement is backed
 	 * by a {@link MonetStatement}, which deals with most of the required stuff of this class.
@@ -126,6 +120,12 @@ public class MonetPreparedStatement exte
 
 		// PreparedStatements are by default poolable
 		poolable = true;
+
+		mTimestampZ = connection.getProtocol().getMonetTimestampTz();
+		mTimestamp = connection.getProtocol().getMonetTimestamp();
+		mTimeZ = connection.getProtocol().getMonetTimeTz();
+		mTime = connection.getProtocol().getMonetTime();
+		mDate = connection.getProtocol().getMonetDate();
 	}
 
 	//== methods interface PreparedStatement
@@ -335,7 +335,7 @@ public class MonetPreparedStatement exte
 					case Types.LONGVARCHAR:
 						return true;
 					default:
-						return true;
+						return false;
 				}
 			}
 
@@ -1307,8 +1307,8 @@ public class MonetPreparedStatement exte
 		if (cal == null) {
 			setValue(parameterIndex, "date '" + x.toString() + "'");
 		} else {
-			MDate.setTimeZone(cal.getTimeZone());
-			setValue(parameterIndex, "date '" + MDate.format(x) + "'");
+			mDate.setTimeZone(cal.getTimeZone());
+			setValue(parameterIndex, "date '" + mDate.format(x) + "'");
 		}
 	}
 
@@ -2152,7 +2152,7 @@ public class MonetPreparedStatement exte
 		if (hasTimeZone) {
 			// timezone shouldn't matter, since the server is timezone
 			// aware in this case
-			String RFC822 = MTimeZ.format(x);
+			String RFC822 = mTimeZ.format(x);
 			setValue(index, "timetz '" + RFC822.substring(0, 15) + ":" + RFC822.substring(15) + "'");
 		} else {
 			// server is not timezone aware for this field, and no
@@ -2162,8 +2162,8 @@ public class MonetPreparedStatement exte
 			if (cal == null) {
 				setValue(index, "time '" + x.toString() + "'");
 			} else {
-				MTime.setTimeZone(cal.getTimeZone());
-				setValue(index, "time '" + MTime.format(x) + "'");
+				mTime.setTimeZone(cal.getTimeZone());
+				setValue(index, "time '" + mTime.format(x) + "'");
 			}
 		}
 	}
@@ -2209,7 +2209,7 @@ public class MonetPreparedStatement exte
 		if (hasTimeZone) {
 			// timezone shouldn't matter, since the server is timezone
 			// aware in this case
-			String RFC822 = MTimestampZ.format(x);
+			String RFC822 = mTimestampZ.format(x);
 			setValue(index, "timestamptz '" + RFC822.substring(0, 26) + ":" + RFC822.substring(26) + "'");
 		} else {
 			// server is not timezone aware for this field, and no
@@ -2219,8 +2219,8 @@ public class MonetPreparedStatement exte
 			if (cal == null) {
 				setValue(index, "timestamp '" + x.toString() + "'");
 			} else {
-				MTimestamp.setTimeZone(cal.getTimeZone());
-				setValue(index, "timestamp '" + MTimestamp.format(x) + "'");
+				mTimestamp.setTimeZone(cal.getTimeZone());
+				setValue(index, "timestamp '" + mTimestamp.format(x) + "'");
 			}
 		}
 	}
@@ -2263,6 +2263,7 @@ public class MonetPreparedStatement exte
 	@Override
 	public void setURL(int parameterIndex, URL x) throws SQLException {
 		setString(parameterIndex, x.toString());
+		values[getParamIdx(parameterIndex)] = "url " + values[getParamIdx(parameterIndex)];
 	}
 
 	/**
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
@@ -8,8 +8,6 @@
 
 package nl.cwi.monetdb.jdbc;
 
-import nl.cwi.monetdb.mcl.connection.helpers.GregorianCalendarParser;
-import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 import nl.cwi.monetdb.mcl.responses.DataBlockResponse;
 import nl.cwi.monetdb.mcl.responses.ResultSetResponse;
 
@@ -40,7 +38,6 @@ import java.sql.Statement;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
-import java.text.ParsePosition;
 import java.util.*;
 
 /**
@@ -61,7 +58,7 @@ import java.util.*;
  * for FORWARD_ONLY result sets the memory usage will be likely lower for large
  * result sets.
  *
- * @author Fabian Groffen, Martin van Dinther
+ * @author Fabian Groffen, Martin van Dinther, Pedro Ferreira
  * @version 0.8
  */
 public class MonetResultSet extends MonetWrapper implements ResultSet {
@@ -707,40 +704,36 @@ public class MonetResultSet extends Mone
 			}
 			// match type specific values
 			switch (JdbcSQLTypes[columnIndex - 1]) {
-				case Types.BOOLEAN:
-					return currentBlock.getBooleanValue(columnIndex - 1);
-				case Types.TINYINT:
-					return currentBlock.getByteValue(columnIndex - 1) != 0;
-				case Types.SMALLINT:
-					return currentBlock.getShortValue(columnIndex - 1) != 0;
-				case Types.INTEGER:
-					return currentBlock.getIntValue(columnIndex - 1) != 0;
-				case Types.BIGINT:
-					return currentBlock.getLongValue(columnIndex - 1) != 0L;
-				case Types.REAL:
-					return currentBlock.getFloatValue(columnIndex - 1) != 0.0f;
-				case Types.DOUBLE:
-					return currentBlock.getDoubleValue(columnIndex - 1) != 0.0d;
-				case Types.CHAR:
-				case Types.VARCHAR:
-				case Types.LONGVARCHAR:
-				case Types.CLOB:
-				case Types.BLOB:
-				case Types.LONGVARBINARY:
-					String val = currentBlock.getValueAsString(columnIndex - 1);
-					if ("false".equalsIgnoreCase(val) || "0".equals(val))
-						return false;
-					if ("true".equalsIgnoreCase(val) || "1".equals(val))
-						return true;
-					throw newSQLInvalidColumnIndexException(columnIndex);
-				case Types.NUMERIC:
-				case Types.DECIMAL:
-					BigDecimal bigdec = (BigDecimal) currentBlock.getValueAsObject(columnIndex - 1);
-					return bigdec.compareTo(BigDecimal.ZERO) != 0;
-				default: //OTHERS, BLOB, LONGVARBINARY, TIME...
-					throw new SQLException("Conversion from " + types[columnIndex - 1] +
-							" to boolean type not supported", "M1M05");
-			}
+                case Types.BOOLEAN:
+                    return currentBlock.getBooleanValue(columnIndex - 1);
+                case Types.TINYINT:
+                    return currentBlock.getByteValue(columnIndex - 1) != 0;
+                case Types.SMALLINT:
+                    return currentBlock.getShortValue(columnIndex - 1) != 0;
+                case Types.INTEGER:
+                    return currentBlock.getIntValue(columnIndex - 1) != 0;
+                case Types.BIGINT:
+                    return currentBlock.getLongValue(columnIndex - 1) != 0L;
+                case Types.REAL:
+                    return currentBlock.getFloatValue(columnIndex - 1) != 0.0f;
+                case Types.DOUBLE:
+                    return currentBlock.getDoubleValue(columnIndex - 1) != 0.0d;
+                case Types.CHAR:
+                case Types.VARCHAR:
+                case Types.LONGVARCHAR:
+                case Types.CLOB:
+                case Types.BLOB:
+                case Types.LONGVARBINARY:
+                    String val = currentBlock.getValueAsString(columnIndex - 1);
+                    return !"0".equals(val) && ("1".equals(val) || Boolean.parseBoolean(val));
+                case Types.NUMERIC:
+                case Types.DECIMAL:
+                    BigDecimal bigdec = (BigDecimal) currentBlock.getValueAsObject(columnIndex - 1);
+                    return bigdec.compareTo(BigDecimal.ZERO) != 0;
+                default: //OTHERS, BLOB, LONGVARBINARY, TIME...
+                    throw new SQLException("Conversion from " + types[columnIndex - 1] +
+                            " to boolean type not supported", "M1M05");
+            }
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -1828,7 +1821,7 @@ public class MonetResultSet extends Mone
 						case 3:
 							if ("url".equals(MonetDBType)) {
 								try {
-									return new URL(val);
+									return new MonetURL(val);
 								} catch (Exception exc) {
 									// ignore exception and just return the val String object
 									return val;
@@ -2504,33 +2497,40 @@ public class MonetResultSet extends Mone
 			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-            Calendar res;
+			Calendar res;
+            long millis;
             switch (JdbcSQLTypes[columnIndex - 1]) {
-				case Types.DATE:
+                case Types.DATE:
+                case Types.TIME:
+                case Types.TIMESTAMP:
 					res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
+                    millis = res.getTimeInMillis() - res.getTimeZone().getRawOffset() + cal.getTimeZone().getRawOffset();
 					break;
+                case Types.TIME_WITH_TIMEZONE:
+                case Types.TIMESTAMP_WITH_TIMEZONE:
+                    res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
+                    millis = res.getTimeInMillis();
+                    break;
                 case Types.CHAR:
                 case Types.VARCHAR:
                 case Types.LONGVARCHAR:
                 case Types.CLOB:
 				case Types.BLOB:
 				case Types.LONGVARBINARY:
-                    String value = currentBlock.getValueAsString(columnIndex - 1);
-                    res = GregorianCalendarParser.ParseDate(value, new ParsePosition(0));
+                    res = currentBlock.getDateValueFromString(this, columnIndex - 1, Types.DATE);
+                    millis = res.getTimeInMillis() - res.getTimeZone().getRawOffset() + cal.getTimeZone().getRawOffset();
                     break;
                 default:
-                    throw new SQLException("Conversion from " + types[columnIndex - 1] +
-                            " to Date not supported", "M1M05");
+                    this.addWarning("unsupported data type", "01M03");
+                    cal.clear();
+                    millis = 0;
             }
-            res.setTimeZone(cal.getTimeZone());
-            return new Date(res.getTimeInMillis());
+            return new Date(millis);
         } catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
 			throw newSQLInvalidColumnIndexException(columnIndex);
-		} catch (ProtocolException ep) {
-            throw new SQLException(ep.getMessage(), "M1M05");
-        }
+		}
 	}
 
 	/**
@@ -2597,13 +2597,18 @@ public class MonetResultSet extends Mone
                 return null;
             }
             Calendar res;
+            long millis;
             switch (JdbcSQLTypes[columnIndex - 1]) {
-				case Types.TIME:
+                case Types.DATE:
+                case Types.TIME:
+                case Types.TIMESTAMP:
 					res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
-					res.setTimeZone(cal.getTimeZone());
+					millis = res.getTimeInMillis() - res.getTimeZone().getRawOffset() + cal.getTimeZone().getRawOffset();
 					break;
-				case Types.TIME_WITH_TIMEZONE:
+                case Types.TIME_WITH_TIMEZONE:
+                case Types.TIMESTAMP_WITH_TIMEZONE:
 					res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
+					millis = res.getTimeInMillis();
 					break;
                 case Types.CHAR:
                 case Types.VARCHAR:
@@ -2611,21 +2616,19 @@ public class MonetResultSet extends Mone
                 case Types.CLOB:
 				case Types.BLOB:
 				case Types.LONGVARBINARY:
-                    String value = currentBlock.getValueAsString(columnIndex - 1);
-                    res = GregorianCalendarParser.ParseTime(value, new ParsePosition(0), false);
-                    res.setTimeZone(cal.getTimeZone());
+                    res = currentBlock.getDateValueFromString(this, columnIndex - 1, Types.TIME);
+					millis = res.getTimeInMillis() - res.getTimeZone().getRawOffset() + cal.getTimeZone().getRawOffset();
                     break;
                 default:
-                    throw new SQLException("Conversion from " + types[columnIndex - 1] +
-                            " to Time not supported", "M1M05");
+                    this.addWarning("unsupported data type", "01M03");
+                    cal.clear();
+                    millis = 0;
             }
-            return new Time(res.getTimeInMillis());
+            return new Time(millis);
         } catch (ClassCastException ex) {
             throw new SQLException(ex.getMessage());
         } catch (IndexOutOfBoundsException e) {
             throw newSQLInvalidColumnIndexException(columnIndex);
-        } catch (ProtocolException ep) {
-            throw new SQLException(ep.getMessage(), "M1M05");
         }
 	}
 
@@ -2693,13 +2696,27 @@ public class MonetResultSet extends Mone
                 return null;
             }
             Calendar res;
+			long millis;
+			int nanos = 0;
             switch (JdbcSQLTypes[columnIndex - 1]) {
+                case Types.DATE:
+                case Types.TIME:
+                    res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
+                    millis = res.getTimeInMillis() - res.getTimeZone().getRawOffset() + cal.getTimeZone().getRawOffset();
+                    break;
+                case Types.TIME_WITH_TIMEZONE:
+                    res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
+                    millis = res.getTimeInMillis();
+                    break;
 				case Types.TIMESTAMP:
 					res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
-					res.setTimeZone(cal.getTimeZone());
+                    nanos = currentBlock.getNanos(columnIndex - 1);
+					millis = res.getTimeInMillis() - res.getTimeZone().getRawOffset() + cal.getTimeZone().getRawOffset();
 					break;
 				case Types.TIMESTAMP_WITH_TIMEZONE:
 					res = (Calendar) currentBlock.getValueAsObject(columnIndex - 1);
+                    nanos = currentBlock.getNanos(columnIndex - 1);
+					millis = res.getTimeInMillis();
 					break;
                 case Types.CHAR:
                 case Types.VARCHAR:
@@ -2707,21 +2724,21 @@ public class MonetResultSet extends Mone
                 case Types.CLOB:
 				case Types.BLOB:
 				case Types.LONGVARBINARY:
-                    String value = currentBlock.getValueAsString(columnIndex - 1);
-                    res = GregorianCalendarParser.ParseTimestamp(value, new ParsePosition(0), false);
-                    res.setTimeZone(cal.getTimeZone());
+                    res = currentBlock.getDateValueFromString(this, columnIndex - 1, Types.TIMESTAMP);
+					millis = res.getTimeInMillis() - res.getTimeZone().getRawOffset() + cal.getTimeZone().getRawOffset();
                     break;
                 default:
-                    throw new SQLException("Conversion from " + types[columnIndex - 1] +
-                            " to Timestamp not supported", "M1M05");
+                    this.addWarning("unsupported data type", "01M03");
+                    cal.clear();
+                    millis = 0;
             }
-            return new Timestamp(res.getTimeInMillis());
+            Timestamp result = new Timestamp(millis);
+            result.setNanos(nanos);
+            return result;
         } catch (ClassCastException ex) {
             throw new SQLException(ex.getMessage());
         } catch (IndexOutOfBoundsException e) {
             throw newSQLInvalidColumnIndexException(columnIndex);
-        } catch (ProtocolException ep) {
-            throw new SQLException(ep.getMessage(), "M1M05");
         }
 	}
 
@@ -2787,6 +2804,7 @@ public class MonetResultSet extends Mone
 					if("url".equals(types[columnIndex - 1])) {
 						return new URL(currentBlock.getValueAsString(columnIndex - 1));
 					}
+					break;
 				case Types.CHAR:
 				case Types.VARCHAR:
 				case Types.LONGVARCHAR:
@@ -2794,9 +2812,8 @@ public class MonetResultSet extends Mone
 				case Types.BLOB:
 				case Types.LONGVARBINARY:
 					return new URL(currentBlock.getValueAsString(columnIndex - 1));
-				default:
-					throw new SQLException("Cannot convert " + types[columnIndex - 1] + " to an url", "M1M05");
 			}
+			throw new SQLException("Cannot convert " + types[columnIndex - 1] + " to an url", "M1M05");
 		} catch (IndexOutOfBoundsException e) {
 			throw newSQLInvalidColumnIndexException(columnIndex);
 		} catch (MalformedURLException e) {
@@ -3016,6 +3033,22 @@ public class MonetResultSet extends Mone
 		return false;
 	}
 
+    /**
+     * Adds a warning to the pile of warnings this ResultSet object has. If
+     * there were no warnings (or clearWarnings was called) this warning will
+     * be the first, otherwise this warning will get appended to the current
+     * warning.
+     *
+     * @param reason the warning message
+     */
+    public void addWarning(String reason, String sqlstate) {
+        if (warnings == null) {
+            warnings = new SQLWarning(reason, sqlstate);
+        } else {
+            warnings.setNextWarning(new SQLWarning(reason, sqlstate));
+        }
+    }
+
 	/* the next methods are all related to updateable result sets, which we currently do not support */
 	@Override
 	public void cancelRowUpdates() throws SQLException {
new file mode 100644
--- /dev/null
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetURL.java
@@ -0,0 +1,77 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0.  If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright 1997 - July 2008 CWI, August 2008 - 2017 MonetDB B.V.
+ */
+
+package nl.cwi.monetdb.jdbc;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.sql.SQLData;
+import java.sql.SQLException;
+import java.sql.SQLInput;
+import java.sql.SQLOutput;
+
+/**
+ * The URL class represents the URL datatype in MonetDB. It represents an URL, that is, a well-formed string conforming
+ * to RFC2396.
+ *
+ * @author Fabian Groffen
+ */
+public class MonetURL implements SQLData {
+
+	public static String FromString(String newurl) throws Exception {
+		if (newurl == null) {
+			return null;
+		}
+		// if above doesn't fail (throws an Exception), it is fine
+		new URL(newurl);
+		return newurl;
+	}
+
+	private String url;
+
+	public MonetURL(String inet) throws Exception {
+		this.url = FromString(inet);
+	}
+
+	@Override
+	public String getSQLTypeName() {
+		return "url";
+	}
+
+	@Override
+	public void readSQL(SQLInput stream, String typeName) throws SQLException {
+		if (typeName.compareTo("url") != 0)
+			throw new SQLException("can only use this class with 'url' type", "M1M05");
+		url = stream.readString();
+	}
+
+	@Override
+	public void writeSQL(SQLOutput stream) throws SQLException {
+		stream.writeString(url);
+	}
+
+	@Override
+	public String toString() {
+		return url;
+	}
+
+	public URL getURL() throws SQLException {
+		if (url == null)
+			return null;
+
+		try {
+			return new URL(url);
+		} catch (MalformedURLException mue) {
+			throw new SQLException("data is not a valid URL", "M0M27");
+		}
+	}
+
+	public void setURL(URL nurl) throws Exception {
+		url = nurl.toString();
+	}
+}
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/GregorianCalendarParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/GregorianCalendarParser.java
@@ -8,8 +8,10 @@
 
 package nl.cwi.monetdb.mcl.connection.helpers;
 
+import nl.cwi.monetdb.jdbc.MonetResultSet;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 
+import java.sql.Types;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
@@ -25,21 +27,6 @@ import java.util.TimeZone;
 public final class GregorianCalendarParser {
 
     /**
-     * The date parser, with intention for re-usage to save memory allocations.
-     */
-    private static final SimpleDateFormat DateParser = new SimpleDateFormat("yyyy-MM-dd");
-
-    /**
-     * The time parser, with intention for re-usage to save memory allocations.
-     */
-    private static final SimpleDateFormat TimeParser = new SimpleDateFormat("HH:mm:ss");
-
-    /**
-     * The timestamp parser, with intention for re-usage to save memory allocations.
-     */
-    private static final SimpleDateFormat TimestampParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
-    /**
      * Small helper method that returns the intrinsic value of a char if it represents a digit. If a non-digit character
      * is encountered an MCLParseException is thrown.
      *
@@ -57,18 +44,90 @@ public final class GregorianCalendarPars
         }
     }
 
+    /** The time zone information, to be resused to avoid memory allocations */
+    private static final TimeZone DefaultTimeZone = TimeZone.getDefault();
+
+    /**
+     * Parses a date or time or timestamp MAPI String into a Java {@link Calendar} instance.
+     *
+     * @param mrs A MonetResultSet instance where warning can be added
+     * @param toParse The date or time or timestamp String to parse
+     * @param pos The position of the String to start the parsing
+     * @param parser The parser to use
+     * @param jdbcType The JDBC type of the column
+     * @return A {@link Calendar} instance of the parsed date
+     */
+    public static Calendar ParseDateString(MonetResultSet mrs, String toParse, ParsePosition pos,
+                                           SimpleDateFormat parser, int jdbcType) {
+        pos.setIndex(0);
+        Calendar res = new GregorianCalendar();
+        if(jdbcType == Types.TIME || jdbcType == Types.TIMESTAMP || jdbcType == Types.DATE) {
+            parser.setTimeZone(TimeZone.getTimeZone("GMT" + toParse.substring(toParse.length() - 6)));
+        } else {
+            parser.setTimeZone(DefaultTimeZone);
+        }
+
+        Date aux = parser.parse(toParse, pos);
+        if (aux == null) {
+            // parsing failed
+            int epos = pos.getErrorIndex();
+            if (epos == -1) {
+                mrs.addWarning("parsing '" + toParse + "' failed", "01M10");
+            } else if (epos < toParse.length()) {
+                mrs.addWarning("parsing failed, found: '" + toParse.charAt(epos) + "' in: \"" + toParse +
+                        "\" at pos: " + pos.getErrorIndex(), "01M10");
+            } else {
+                mrs.addWarning("parsing failed, expected more data after '" + toParse + "'", "01M10");
+            }
+            res.clear();
+        } else {
+            res.setTime(aux);
+        }
+
+        if (jdbcType != Types.DATE) {
+            // parse additional nanos (if any)
+            int pos1 = pos.getIndex(), nanos;
+            char[] monDate = toParse.toCharArray();
+            if (pos1 < monDate.length && monDate[pos1] == '.') {
+                pos1++;
+                int ctr;
+                try {
+                    nanos = getIntrinsicValue(monDate[pos1], pos1++);
+                    for (ctr = 1; pos1 < monDate.length && monDate[pos1] >= '0' && monDate[pos1] <= '9'; ctr++) {
+                        if (ctr < 9) {
+                            nanos *= 10;
+                            nanos += (getIntrinsicValue(monDate[pos1], pos1));
+                        }
+                        if (ctr == 2) // we have three at this point
+                            res.set(Calendar.MILLISECOND, nanos);
+                        pos1++;
+                    }
+                    while (ctr++ < 9)
+                        nanos *= 10;
+                } catch(ProtocolException e) {
+                    mrs.addWarning(e.getMessage() + " found: '" + monDate[e.getErrorOffset()] + "' in: \"" +
+                            toParse + "\" at pos: " + e.getErrorOffset(), "01M10");
+                    res.clear();
+                }
+            }
+        }
+        return res;
+    }
+
     /**
      * Parses a date MAPI String into a Java {@link Calendar} instance.
      *
      * @param toParse The date String to parse
      * @param pos The position of the String to start the parsing
+     * @param parser The parser to use (date)
      * @return A {@link Calendar} instance of the parsed date
      * @throws ProtocolException If the String could not be parsed
      */
-    public static Calendar ParseDate(String toParse, ParsePosition pos) throws ProtocolException {
+    public static Calendar ParseDate(String toParse, ParsePosition pos, SimpleDateFormat parser)
+            throws ProtocolException {
         pos.setIndex(0);
         Calendar res = new GregorianCalendar();
-        Date util = DateParser.parse(toParse, pos);
+        Date util = parser.parse(toParse, pos);
         if(util == null) {
             res.clear();
         } else {
@@ -80,16 +139,22 @@ public final class GregorianCalendarPars
     /**
      * Parses a time or a timestamp MAPI String into a Java {@link Calendar} instance.
      *
-     * @param toParse The time/timestamp String to parse
+     * @param toParse The time String to parse
      * @param pos The position of the String to start the parsing
-     * @param hasTimeZone If the time/timestamp String has timezone information
-     * @param parser The parser to use (time or timestamp)
-     * @return A {@link Calendar} instance of the parsed time/timestamp
+     * @param hasTimeZone If the time String has timezone information
+     * @param parser The parser to use (time)
+     * @return A {@link Calendar} instance of the parsed time
      * @throws ProtocolException If the String could not be parsed
      */
-    private static Calendar ParseTimeIn(String toParse, ParsePosition pos, boolean hasTimeZone, SimpleDateFormat parser)
+    public static Calendar ParseTime(String toParse, ParsePosition pos, SimpleDateFormat parser, boolean hasTimeZone)
             throws ProtocolException {
         pos.setIndex(0);
+        if(hasTimeZone) { // MonetDB/SQL99:  Sign TwoDigitHours : Minutes
+            parser.setTimeZone(TimeZone.getTimeZone("GMT" + toParse.substring(toParse.length() - 6)));
+        } else {
+            parser.setTimeZone(DefaultTimeZone);
+        }
+
         Calendar res = new GregorianCalendar();
         Date util = parser.parse(toParse, pos);
         if(util == null) {
@@ -97,9 +162,38 @@ public final class GregorianCalendarPars
         } else {
             res.setTime(util);
         }
+        return res;
+    }
+
+    /**
+     * Parses a timestamp MAPI String into a {@link TimestampHelper} instance.
+     *
+     * @param toParse The timestamp String to parse
+     * @param pos The position of the String to start the parsing
+     * @param hasTimeZone If the timestamp String has timezone information
+     * @param parser The parser to use (timestamp)
+     * @return A {@link TimestampHelper} instance of the parsed timestamp with nanos information
+     * @throws ProtocolException If the String could not be parsed
+     */
+    public static TimestampHelper ParseTimestamp(String toParse, ParsePosition pos, SimpleDateFormat parser,
+                                                 boolean hasTimeZone) throws ProtocolException {
+        pos.setIndex(0);
+        if(hasTimeZone) { // MonetDB/SQL99:  Sign TwoDigitHours : Minutes
+            parser.setTimeZone(TimeZone.getTimeZone("GMT" + toParse.substring(toParse.length() - 6)));
+        } else {
+            parser.setTimeZone(DefaultTimeZone);
+        }
+
+        GregorianCalendar res = new GregorianCalendar();
+        Date util = parser.parse(toParse, pos);
+        if(util != null) {
+            res.setTime(util);
+        } else {
+            res.clear();
+        }
 
         // parse additional nanos (if any)
-        int pos1 = pos.getIndex(), nanos;
+        int pos1 = pos.getIndex(), nanos = 0;
         if (pos1 < toParse.length() && toParse.charAt(pos1) == '.') {
             pos1++;
             int ctr;
@@ -110,47 +204,14 @@ public final class GregorianCalendarPars
                     nanos *= 10;
                     nanos += (getIntrinsicValue(toParse.charAt(pos1), pos1));
                 }
-                if (ctr == 2) // we have three at this point
+                if (ctr == 2) { // we have three at this point
                     res.set(Calendar.MILLISECOND, nanos);
+                }
                 pos1++;
             }
             while (ctr++ < 9)
                 nanos *= 10;
         }
-
-        if(hasTimeZone) {
-            int vallen = toParse.length();
-            if (vallen >= 6) { // MonetDB/SQL99:  Sign TwoDigitHours : Minutes
-                res.setTimeZone(TimeZone.getTimeZone("GMT" + toParse.substring(vallen - 6, vallen)));
-            }
-        }
-        return res;
-    }
-
-    /**
-     * Parses a time MAPI String into a Java {@link Calendar} instance.
-     *
-     * @param toParse The time String to parse
-     * @param pos The position of the String to start the parsing
-     * @param hasTimeZone If the time String has timezone information
-     * @return A {@link Calendar} instance of the parsed time
-     * @throws ProtocolException If the String could not be parsed
-     */
-    public static Calendar ParseTime(String toParse, ParsePosition pos, boolean hasTimeZone) throws ProtocolException {
-        return ParseTimeIn(toParse, pos, hasTimeZone, TimeParser);
-    }
-
-    /**
-     * Parses a timestamp MAPI String into a Java {@link Calendar} instance.
-     *
-     * @param toParse The timestamp String to parse
-     * @param pos The position of the String to start the parsing
-     * @param hasTimeZone If the timestamp String has timezone information
-     * @return A {@link Calendar} instance of the parsed timestamp
-     * @throws ProtocolException If the String could not be parsed
-     */
-    public static Calendar ParseTimestamp(String toParse, ParsePosition pos, boolean hasTimeZone)
-            throws ProtocolException {
-        return ParseTimeIn(toParse, pos, hasTimeZone, TimestampParser);
+        return new TimestampHelper(res, nanos);
     }
 }
new file mode 100644
--- /dev/null
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/helpers/TimestampHelper.java
@@ -0,0 +1,72 @@
+package nl.cwi.monetdb.mcl.connection.helpers;
+
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+/**
+ * Due to the poor design of the old Java date and time API, when retrieving timestamps from the MAPI connection, this
+ * class is used to store the calendar with timezone information and the nanoseconds information to generate a
+ * {@link Timestamp} instance, as there is no mapping in Java Classes to store both information.
+ *
+ * @author Pedro Ferreira
+ */
+public class TimestampHelper {
+
+    /** The calendar instance */
+    private Calendar calendar;
+
+    /** The nanoseconds information */
+    private int nanoseconds;
+
+    TimestampHelper(Calendar calendar, int nanoseconds) {
+        this.calendar = calendar;
+        this.nanoseconds = nanoseconds;
+    }
+
+    /**
+     * Gets the Calendar instance.
+     *
+     * @return The Calendar instance
+     */
+    public Calendar getCalendar() {
+        return calendar;
+    }
+
+    /**
+     * Sets the Calendar instance.
+     *
+     * @param calendar The Calendar instance
+     */
+    public void setCalendar(Calendar calendar) {
+        this.calendar = calendar;
+    }
+
+    /**
+     * Gets the nanoseconds information.
+     *
+     * @return The nanoseconds information
+     */
+    public int getNanoseconds() {
+        return nanoseconds;
+    }
+
+    /**
+     * Sets the nanoseconds information.
+     *
+     * @param nanoseconds The nanoseconds information
+     */
+    public void setNanoseconds(int nanoseconds) {
+        this.nanoseconds = nanoseconds;
+    }
+
+    /**
+     * Generates a {@link Timestamp} instance from the provided information.
+     *
+     * @return The generated {@link Timestamp} instance
+     */
+    public Timestamp getTimestamp() {
+        Timestamp res = new Timestamp(calendar.getTimeInMillis());
+        res.setNanos(nanoseconds);
+        return res;
+    }
+}
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java
@@ -208,7 +208,7 @@ public abstract class AbstractSocket imp
         this.utf8Encoder.reset();
         CoderResult res;
         int written = 0;
-        do {
+        do { //to avoid overflow in the UTF-16 to UTF-8 conversion, has to do this cycle
             res = this.utf8Encoder.encode(this.stringsEncoded, this.bufferOut, false);
             written += this.writeFromBufferOut(this.bufferOut);
         } while (res == CoderResult.OVERFLOW);
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java
@@ -16,6 +16,8 @@ import nl.cwi.monetdb.mcl.responses.Data
 import nl.cwi.monetdb.mcl.responses.ResultSetResponse;
 
 import java.io.IOException;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
 import java.util.Map;
 
 /**
@@ -26,6 +28,121 @@ import java.util.Map;
  */
 public abstract class AbstractProtocol {
 
+    /* only parse the date patterns once, use multiple times */
+    /** Format of a date used by mserver */
+    private final SimpleDateFormat monetDate = new SimpleDateFormat("yyyy-MM-dd");
+
+    /** Format of a time */
+    private final SimpleDateFormat monetTime = new SimpleDateFormat("HH:mm:ss.SSS");
+    /** Format of a time with RFC822 time zone */
+    private final SimpleDateFormat monetTimeTz = new SimpleDateFormat("HH:mm:ss.SSSZ");
+    /** Format to print a Time String */
+    private final SimpleDateFormat monetTimePrinter = new SimpleDateFormat("HH:mm:ss");
+    /** Format to print a TimeTz String */
+    private final SimpleDateFormat monetTimeTzPrinter = new SimpleDateFormat("HH:mm:ssXXX");
+
+    /** Format of a timestamp */
+    private final SimpleDateFormat monetTimestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+    /** Format of a timestamp with RFC822 time zone */
+    private final SimpleDateFormat monetTimestampTz = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
+    /** Format to print a TimeStamp String */
+    private final SimpleDateFormat monetTimestampPrinter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
+    /** Format to print a TimeStampTz String */
+    private final SimpleDateFormat monetTimestampTzPrinter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSXXX");
+
+    /** A helper to parse Dates, Times and Timestamps, to be reused during the connection to save memory allocations. */
+    private final ParsePosition monetParserPosition = new ParsePosition(0);
+
+    /**
+     * Gets the MonetDB Date formatter.
+     *
+     * @return The MonetDB Date formatter
+     */
+    public SimpleDateFormat getMonetDate() {
+        return monetDate;
+    }
+
+    /**
+     * Gets the MonetDB Time formatter.
+     *
+     * @return The MonetDB Time formatter
+     */
+    public SimpleDateFormat getMonetTime() {
+        return monetTime;
+    }
+
+    /**
+     * Gets the MonetDB Time with RFC822 time zone formatter.
+     *
+     * @return The MonetDB Time with RFC822 time zone formatter
+     */
+    public SimpleDateFormat getMonetTimeTz() {
+        return monetTimeTz;
+    }
+
+    /**
+     * Gets the MonetDB Time printer.
+     *
+     * @return The MonetDB Time printer
+     */
+    public SimpleDateFormat getMonetTimePrinter() {
+        return monetTimePrinter;
+    }
+
+    /**
+     * Gets the MonetDB Time with timezone printer.
+     *
+     * @return The MonetDB Time with timezone printer.
+     */
+    public SimpleDateFormat getMonetTimeTzPrinter() {
+        return monetTimeTzPrinter;
+    }
+
+    /**
+     * Gets the MonetDB Timestamp formatter.
+     *
+     * @return The MonetDB Timestamp formatter
+     */
+    public SimpleDateFormat getMonetTimestamp() {
+        return monetTimestamp;
+    }
+
+    /**
+     * Gets the MonetDB Timestamp with RFC822 time zone formatter.
+     *
+     * @return The MonetDB Timestamp with RFC822 time zone formatter
+     */
+    public SimpleDateFormat getMonetTimestampTz() {
+        return monetTimestampTz;
+    }
+
+    /**
+     * Gets the MonetDB Timestamp printer.
+     *
+     * @return The MonetDB Timestamp printer
+     */
+    public SimpleDateFormat getMonetTimestampPrinter() {
+        return monetTimestampPrinter;
+    }
+
+    /**
+     * Gets the MonetDB Timestamp with timezone printer.
+     *
+     * @return The MonetDB Timestamp with timezone printer.
+     */
+    public SimpleDateFormat getMonetTimestampTzPrinter() {
+        return monetTimestampTzPrinter;
+    }
+
+    /**
+     * Gets the Protocol parser position.
+     *
+     * @return The Protocol parser position
+     */
+    public ParsePosition getMonetParserPosition() {
+        return monetParserPosition;
+    }
+
     /**
      * Waits until the server sends the PROMPT message, meaning that the next response is ready for retrieval.
      *
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java
@@ -21,6 +21,7 @@ import nl.cwi.monetdb.mcl.responses.Resu
 
 import java.io.IOException;
 import java.nio.CharBuffer;
+import java.text.SimpleDateFormat;
 import java.util.Map;
 
 /**
@@ -37,24 +38,22 @@ public class OldMapiProtocol extends Abs
      */
     private static final int TUPLE_LINE_BUFFER_DEFAULT_SIZE = 1024;
 
-    /**
-     * The current server response.
-     */
+    /** Format of a time string from the old MAPI connection */
+    final SimpleDateFormat timeParser = new SimpleDateFormat("HH:mm:ss");
+
+    /** Format of a timestamp string from the old MAPI connection */
+    final SimpleDateFormat timestampParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    /**The current server response */
     private int currentServerResponseHeader = ServerResponses.UNKNOWN;
 
-    /**
-     * The underlying MAPI socket connection.
-     */
+    /** The underlying MAPI socket connection */
     private final OldMapiSocket socket;
 
-    /**
-     * The buffer used to parse server's responses.
-     */
+    /** The buffer used to parse server's responses */
     CharBuffer lineBuffer;
 
-    /**
-     * A helper buffer used to parse tuple line responses.
-     */
+    /** A helper buffer used to parse tuple line responses */
     CharBuffer tupleLineBuffer;
 
     public OldMapiProtocol(OldMapiSocket socket) {
@@ -205,7 +204,7 @@ public class OldMapiProtocol extends Abs
         if (rs == null) {
             return null;
         }
-        return rs.addDataBlockResponse(offset, rowcount, this);
+        return rs.addDataBlockResponse(offset, rowcount);
     }
 
     /**
@@ -251,6 +250,9 @@ public class OldMapiProtocol extends Abs
     @Override
     public String getRemainingStringLine(int startIndex) {
         if(this.lineBuffer.limit() > startIndex) {
+            if(this.lineBuffer.array()[startIndex] == '!') {
+                startIndex++;
+            }
             return new String(this.lineBuffer.array(), startIndex, this.lineBuffer.limit() - startIndex);
         } else {
             return null;
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java
@@ -12,13 +12,12 @@ import nl.cwi.monetdb.jdbc.MonetBlob;
 import nl.cwi.monetdb.jdbc.MonetClob;
 import nl.cwi.monetdb.mcl.connection.helpers.BufferReallocator;
 import nl.cwi.monetdb.mcl.connection.helpers.GregorianCalendarParser;
+import nl.cwi.monetdb.mcl.connection.helpers.TimestampHelper;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 
 import java.math.BigDecimal;
-import java.math.BigInteger;
 import java.nio.CharBuffer;
 import java.sql.Types;
-import java.text.ParsePosition;
 import java.util.Calendar;
 
 /**
@@ -36,12 +35,6 @@ final class OldMapiTupleLineParser {
     private static final char[] NULL_STRING = new char[]{'N','U','L','L'};
 
     /**
-     * A Java parser to parse Date, Time and Timestamp data, to be reused during the connection to save memory
-     * allocation.
-     */
-    private static final ParsePosition Ppos = new ParsePosition(0);
-
-    /**
      * Parses the given OldMapiProtocol's lineBuffer source as tuple line for a DataBlock. If source cannot be parsed, a
      * ProtocolException is thrown. The OldMapiProtocol's tupleLineBuffer is used to help parsing a column value.
      *
@@ -66,7 +59,7 @@ final class OldMapiTupleLineParser {
                 throw new ProtocolException(typesMap.length + " columns expected, but only single value found");
             }
             // return the whole string but the leading =
-            OldMapiStringToJavaDataConversion(array, 1, len - 1, lineNumber, values[0], typesMap[0]);
+            OldMapiStringToJavaDataConversion(protocol, array, 1, len - 1, lineNumber, values[0], typesMap[0]);
             return 1;
         }
 
@@ -147,18 +140,32 @@ final class OldMapiTupleLineParser {
                                             break;
                                     }
                                 } else if(array[pos] == '\\') {
-
+                                    pos++;
+                                    switch (array[pos]) {
+                                        case '\\':
+                                            tupleLineBuffer.put('\\');
+                                            break;
+                                        case 'n':
+                                            tupleLineBuffer.put('\n');
+                                            break;
+                                        case 't':
+                                            tupleLineBuffer.put('\t');
+                                            break;
+                                        case '"':
+                                            tupleLineBuffer.put('"');
+                                            break;
+                                    }
                                 } else {
                                     tupleLineBuffer.put(array[pos]);
                                 }
                             }
                             // put the unescaped string in the right place
                             tupleLineBuffer.flip();
-                            OldMapiStringToJavaDataConversion(tupleLineBuffer.array(), 0, tupleLineBuffer.limit(), lineNumber, values[column], typesMap[column]);
+                            OldMapiStringToJavaDataConversion(protocol, tupleLineBuffer.array(), 0, tupleLineBuffer.limit(), lineNumber, values[column], typesMap[column]);
                         } else if ((i - 1) - cursor == 4 && OldMapiTupleLineParserHelper.CharIndexOf(array, 0, array.length, NULL_STRING, 0,4, cursor) == cursor) {
                             SetNullValue(lineNumber, values[column], typesMap[column]);
                         } else {
-                            OldMapiStringToJavaDataConversion(array, cursor, i - 1 - cursor, lineNumber, values[column], typesMap[column]);
+                            OldMapiStringToJavaDataConversion(protocol, array, cursor, i - 1 - cursor, lineNumber, values[column], typesMap[column]);
                         }
                         column++;
                         cursor = i + 1;
@@ -204,8 +211,9 @@ final class OldMapiTupleLineParser {
      * @param jDBCMapping The JDBC mapping of the value
      * @throws ProtocolException If the JDBC Mapping is unknown
      */
-    private static void OldMapiStringToJavaDataConversion(char[] toParse, int startPosition, int count, int lineNumber,
-                                                          Object columnArray, int jDBCMapping) throws ProtocolException {
+    private static void OldMapiStringToJavaDataConversion(OldMapiProtocol protocol, char[] toParse, int startPosition,
+                                                          int count, int lineNumber, Object columnArray,
+                                                          int jDBCMapping) throws ProtocolException {
         switch (jDBCMapping) {
             case Types.BOOLEAN:
                 ((byte[]) columnArray)[lineNumber] = OldMapiTupleLineParserHelper.CharArrayToBoolean(toParse, startPosition);
@@ -239,19 +247,19 @@ final class OldMapiTupleLineParser {
                 ((String[]) columnArray)[lineNumber] = new String(toParse, startPosition, count);
                 break;
             case Types.DATE:
-                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseDate(new String(toParse, startPosition, count), Ppos);
+                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseDate(new String(toParse, startPosition, count), protocol.getMonetParserPosition(), protocol.getMonetDate());
                 break;
             case Types.TIME:
-                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTime(new String(toParse, startPosition, count), Ppos, false);
+                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTime(new String(toParse, startPosition, count), protocol.getMonetParserPosition(), protocol.timeParser, false);
                 break;
             case Types.TIME_WITH_TIMEZONE:
-                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTime(new String(toParse, startPosition, count), Ppos, true);
+                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTime(new String(toParse, startPosition, count), protocol.getMonetParserPosition(), protocol.timeParser, true);
                 break;
             case Types.TIMESTAMP:
-                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTimestamp(new String(toParse, startPosition, count), Ppos, false);
+                ((TimestampHelper[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTimestamp(new String(toParse, startPosition, count), protocol.getMonetParserPosition(), protocol.timestampParser, false);
                 break;
             case Types.TIMESTAMP_WITH_TIMEZONE:
-                ((Calendar[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTimestamp(new String(toParse, startPosition, count), Ppos, true);
+                ((TimestampHelper[]) columnArray)[lineNumber] = GregorianCalendarParser.ParseTimestamp(new String(toParse, startPosition, count), protocol.getMonetParserPosition(), protocol.timestampParser, true);
                 break;
             case Types.CLOB:
                 ((MonetClob[]) columnArray)[lineNumber] = new MonetClob(toParse, startPosition, count);
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java
@@ -10,12 +10,17 @@ package nl.cwi.monetdb.mcl.responses;
 
 import nl.cwi.monetdb.jdbc.MonetBlob;
 import nl.cwi.monetdb.jdbc.MonetClob;
+import nl.cwi.monetdb.jdbc.MonetConnection;
+import nl.cwi.monetdb.jdbc.MonetResultSet;
+import nl.cwi.monetdb.mcl.connection.helpers.GregorianCalendarParser;
+import nl.cwi.monetdb.mcl.connection.helpers.TimestampHelper;
 import nl.cwi.monetdb.mcl.protocol.AbstractProtocol;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 import nl.cwi.monetdb.mcl.protocol.ServerResponses;
 
 import java.math.BigDecimal;
-import java.sql.Types;
+import java.sql.*;
+import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Calendar;
 
@@ -41,6 +46,8 @@ public class DataBlockResponse implement
     private Object[] data;
     /** The counter which keeps the current position in the data array */
     private int pos;
+    /** If the underlying connection is embedded or not */
+    private final boolean isEmbedded;
     /** The connection protocol to parse the tuple lines */
     private final AbstractProtocol protocol;
     /** The JdbcSQLTypes mapping */
@@ -58,10 +65,12 @@ public class DataBlockResponse implement
      * @param protocol the underlying protocol
      * @param JdbcSQLTypes an array of the JDBC mappings of the columns
      */
-    DataBlockResponse(int rowcount, int columncount, AbstractProtocol protocol, int[] JdbcSQLTypes) {
+    DataBlockResponse(int rowcount, int columncount, MonetConnection connection, AbstractProtocol protocol,
+                      int[] JdbcSQLTypes) {
         this.pos = -1;
         this.rowcount = rowcount;
         this.data = new Object[columncount];
+        this.isEmbedded = connection.isEmbedded();
         this.protocol = protocol;
         this.jdbcSQLTypes = JdbcSQLTypes;
     }
@@ -84,6 +93,9 @@ public class DataBlockResponse implement
             int numberOfColumns = this.data.length;
             for (int i = 0 ; i < numberOfColumns ; i++) {
                 switch (this.jdbcSQLTypes[i]) {
+                    case Types.INTEGER:
+                        this.data[i] = new int[this.rowcount];
+                        break;
                     case Types.BOOLEAN:
                     case Types.TINYINT:
                         this.data[i] = new byte[this.rowcount];
@@ -91,18 +103,28 @@ public class DataBlockResponse implement
                     case Types.SMALLINT:
                         this.data[i] = new short[this.rowcount];
                         break;
-                    case Types.INTEGER:
-                        this.data[i] = new int[this.rowcount];
-                        break;
-                    case Types.BIGINT:
-                        this.data[i] = new long[this.rowcount];
-                        break;
                     case Types.REAL:
                         this.data[i] = new float[this.rowcount];
                         break;
                     case Types.DOUBLE:
                         this.data[i] = new double[this.rowcount];
                         break;
+                    case Types.BIGINT:
+                        this.data[i] = new long[this.rowcount];
+                        break;
+                    case Types.DATE:
+                    case Types.TIME:
+                    case Types.TIME_WITH_TIMEZONE:
+                        this.data[i] = new Calendar[this.rowcount];
+                        break;
+                    case Types.TIMESTAMP:
+                    case Types.TIMESTAMP_WITH_TIMEZONE:
+                        if(this.isEmbedded) {
+                            this.data[i] = new Calendar[this.rowcount];
+                        } else {
+                            this.data[i] = new TimestampHelper[this.rowcount];
+                        }
+                        break;
                     case Types.NUMERIC:
                     case Types.DECIMAL:
                         this.data[i] = new BigDecimal[this.rowcount];
@@ -113,13 +135,6 @@ public class DataBlockResponse implement
                     case Types.CLOB:
                         this.data[i] = new MonetClob[this.rowcount];
                         break;
-                    case Types.TIME:
-                    case Types.TIME_WITH_TIMEZONE:
-                    case Types.DATE:
-                    case Types.TIMESTAMP:
-                    case Types.TIMESTAMP_WITH_TIMEZONE:
-                        this.data[i] = new Calendar[this.rowcount];
-                        break;
                     case Types.LONGVARBINARY:
                         this.data[i] = new byte[this.rowcount][];
                         break;
@@ -276,6 +291,44 @@ public class DataBlockResponse implement
     }
 
     /**
+     * To parse a String column in a date, time or timestamp instance, this method is used.
+
+     * @param mrs A MonetResultSet instance where warning can be added     *
+     * @param column The column index starting from 0
+     * @param jdbcType The JDBC type of the column desired to convert
+     * @return A {@link Calendar} instance of the parsed date
+     * @throws SQLException If the conversation cannot be performed
+     */
+    public Calendar getDateValueFromString(MonetResultSet mrs, int column, int jdbcType) throws SQLException {
+        String value = ((Object[]) this.data[column])[this.blockLine].toString();
+        SimpleDateFormat aux;
+        switch (jdbcType) {
+            case Types.DATE:
+                aux = protocol.getMonetDate();
+                break;
+            case Types.TIME:
+            case Types.TIME_WITH_TIMEZONE:
+                aux = protocol.getMonetTimePrinter();
+                break;
+            case Types.TIMESTAMP:
+            case Types.TIMESTAMP_WITH_TIMEZONE:
+                aux = protocol.getMonetTimestampPrinter();
+                break;
+            default:
+                throw new SQLException("Internal error!", "M1M05");
+        }
+        return GregorianCalendarParser.ParseDateString(mrs, value, protocol.getMonetParserPosition(), aux, jdbcType);
+    }
+
+    public int getNanos(int column) {
+        if(isEmbedded) {
+            return 0;
+        } else {
+            return ((TimestampHelper[]) this.data[column])[this.blockLine].getTimestamp().getNanos();
+        }
+    }
+
+    /**
      * Gets the current row value as a Java String.
      *
      * @param column The column index starting from 0
@@ -304,7 +357,32 @@ public class DataBlockResponse implement
                 return Float.toString(((float[]) this.data[column])[this.blockLine]);
             case Types.DOUBLE:
                 return Double.toString(((double[]) this.data[column])[this.blockLine]);
-            default: //BLOB, CLOB, BigDecimal, Time, Timestamp and Date
+            case Types.DATE:
+                Date aux1 = new Date(((Calendar[]) this.data[column])[this.blockLine].getTimeInMillis());
+                return protocol.getMonetDate().format(aux1);
+            case Types.TIME:
+                Time aux2 = new Time(((Calendar[]) this.data[column])[this.blockLine].getTimeInMillis());
+                return protocol.getMonetTimePrinter().format(aux2);
+            case Types.TIME_WITH_TIMEZONE:
+                Time aux3 = new Time(((Calendar[]) this.data[column])[this.blockLine].getTimeInMillis());
+                return protocol.getMonetTimeTzPrinter().format(aux3);
+            case Types.TIMESTAMP:
+                Timestamp aux4;
+                if(this.isEmbedded) {
+                    aux4 = new Timestamp(((Calendar[]) this.data[column])[this.blockLine].getTimeInMillis());
+                } else {
+                    aux4 = ((TimestampHelper[]) this.data[column])[this.blockLine].getTimestamp();
+                }
+                return protocol.getMonetTimestampPrinter().format(aux4);
+            case Types.TIMESTAMP_WITH_TIMEZONE:
+                Timestamp aux5;
+                if(this.isEmbedded) {
+                    aux5 = new Timestamp(((Calendar[]) this.data[column])[this.blockLine].getTimeInMillis());
+                } else {
+                    aux5 = ((TimestampHelper[]) this.data[column])[this.blockLine].getTimestamp();
+                }
+                return protocol.getMonetTimestampTzPrinter().format(aux5);
+            default: //BLOB, CLOB, BigDecimal
                 return ((Object[]) this.data[column])[this.blockLine].toString();
         }
     }
@@ -331,6 +409,13 @@ public class DataBlockResponse implement
                 return ((float[]) this.data[column])[this.blockLine];
             case Types.DOUBLE:
                 return ((double[]) this.data[column])[this.blockLine];
+            case Types.TIMESTAMP:
+            case Types.TIMESTAMP_WITH_TIMEZONE:
+                if(isEmbedded) {
+                    return ((Calendar[]) this.data[column])[this.blockLine];
+                } else {
+                    return ((TimestampHelper[]) this.data[column])[this.blockLine].getCalendar();
+                }
             default:
                 return ((Object[]) this.data[column])[this.blockLine];
         }
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java
@@ -35,9 +35,7 @@ import java.sql.Types;
  */
 public class ResultSetResponse implements IIncompleteResponse {
 
-    /**
-     * The expected final value after the table headers are set.
-     */
+    /** The expected final value after the table headers are set. */
     private static final byte IS_SET_FINAL_VALUE = 15;
 
     /** The number of rows in the current block */
@@ -124,7 +122,7 @@ public class ResultSetResponse implement
         this.JdbcSQLTypes = new int[columncount];
 
         this.resultBlocks = new DataBlockResponse[(tuplecount / cacheSize) + 1];
-        this.resultBlocks[0] = new DataBlockResponse(rowcount, columncount, con.getProtocol(), this.JdbcSQLTypes);
+        this.resultBlocks[0] = new DataBlockResponse(rowcount, columncount, con, con.getProtocol(), this.JdbcSQLTypes);
     }
 
     /**
@@ -159,11 +157,10 @@ public class ResultSetResponse implement
      *
      * @param offset the offset number of rows for this block
      * @param rowcount the number of rows for this block
-     * @param proto The connection's protocol
      */
-    public DataBlockResponse addDataBlockResponse(int offset, int rowcount, AbstractProtocol proto) {
+    public DataBlockResponse addDataBlockResponse(int offset, int rowcount) {
         int block = (offset - blockOffset) / cacheSize;
-        DataBlockResponse res = new DataBlockResponse(rowcount, this.name.length, proto, JdbcSQLTypes);
+        DataBlockResponse res = new DataBlockResponse(rowcount, this.name.length, this.con, this.con.getProtocol(), JdbcSQLTypes);
         resultBlocks[block] = res;
         return res;
     }