# HG changeset patch
# User Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
# Date 1481650530 -3600
# Node ID 953422c41194dac22e8f8fa7dd164f105968e412
# Parent  af83fa389393516ae4569f4361b5393f1b2ef626
The data retrieval in ResultSets is now Column wise. Ready to start the embedded integrate, but it has to perform extra tests for the more rare types.

diff --git a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
@@ -3,7 +3,7 @@ package nl.cwi.monetdb.jdbc;
 import nl.cwi.monetdb.jdbc.types.INET;
 import nl.cwi.monetdb.jdbc.types.URL;
 import nl.cwi.monetdb.mcl.connection.*;
-import nl.cwi.monetdb.mcl.connection.socket.MapiLanguage;
+import nl.cwi.monetdb.mcl.connection.mapi.MapiLanguage;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 import nl.cwi.monetdb.mcl.protocol.AbstractProtocol;
 import nl.cwi.monetdb.mcl.protocol.ServerResponses;
@@ -1344,9 +1344,8 @@ public abstract class MonetConnection ex
     }
 
     /**
-     * A list of Response objects.  Responses are added to this list.
-     * Methods of this class are not synchronized.  This is left as
-     * responsibility to the caller to prevent concurrent access.
+     * A list of Response objects. Responses are added to this list. Methods of this class are not synchronized. This is
+     * left as responsibility to the caller to prevent concurrent access.
      */
     public class ResponseList {
 
@@ -1368,9 +1367,8 @@ public abstract class MonetConnection ex
         private int curResponse = -1;
 
         /**
-         * Main constructor.  The query argument can either be a String
-         * or List.  An SQLException is thrown if another object
-         * instance is supplied.
+         * Main constructor. The query argument can either be a String or List.  An SQLException is thrown if another
+         * object instance is supplied.
          *
          * @param cachesize overall cachesize to use
          * @param maxrows maximum number of rows to allow in the set
@@ -1419,8 +1417,7 @@ public abstract class MonetConnection ex
             }
             curResponse++;
             if (curResponse >= responses.size()) {
-                // ResponseList is obviously completed so, there are no
-                // more responses
+                // ResponseList is obviously completed so, there are no more responses
                 return null;
             } else {
                 // return this response
diff --git a/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java b/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetDriver.java
@@ -293,12 +293,12 @@ final public class MonetDriver implement
 		typeMap.put("date", Types.DATE);
 		typeMap.put("decimal", Types.DECIMAL);
 		typeMap.put("double", Types.DOUBLE);
-		typeMap.put("geometry", Types.VARCHAR);
-		typeMap.put("geometrya", Types.VARCHAR);
+		typeMap.put("geometry", Types.OTHER);
+		typeMap.put("geometrya", Types.OTHER);
 		typeMap.put("hugeint", Types.NUMERIC); //but we will convert to java.math.BigInteger
-		typeMap.put("inet", Types.VARCHAR);
+		typeMap.put("inet", Types.OTHER);
 		typeMap.put("int", Types.INTEGER);
-		typeMap.put("json", Types.VARCHAR);
+		typeMap.put("json", Types.OTHER);
 		// typeMap.put("mbr", Types.???);
 		typeMap.put("month_interval", Types.INTEGER);
 		// typeMap.put("oid", Types.BIGINT);
@@ -314,8 +314,8 @@ final public class MonetDriver implement
 		typeMap.put("timetz", Types.TIME);
         // new in Java 8: Types.TIME_WITH_TIMEZONE (value 2013). Can't use it yet as we compile for java 7
 		typeMap.put("tinyint", Types.TINYINT);
-		typeMap.put("url", Types.VARCHAR);
-		typeMap.put("uuid", Types.VARCHAR);
+		typeMap.put("url", Types.OTHER);
+		typeMap.put("uuid", Types.OTHER);
 		typeMap.put("varchar", Types.VARCHAR);
 		typeMap.put("wrd", Types.BIGINT);
 	}
diff --git a/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java b/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java
@@ -67,6 +67,20 @@ import java.util.Map;
  * @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;
 	private final int[] digits;
@@ -77,28 +91,11 @@ public class MonetPreparedStatement exte
 	private final int id;
 	private final int size;
 	private final int rscolcnt;
-
 	private final String[] values;
-	
-	private final MonetConnection connection;
-
-	/* only parse the date patterns once, use multiple times */
-	/** Format of a timestamp with RFC822 time zone */
-	private final SimpleDateFormat mTimestampZ = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
-	/** Format of a timestamp */
-	private final SimpleDateFormat mTimestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-	/** Format of a time with RFC822 time zone */
-	private final SimpleDateFormat mTimeZ = new SimpleDateFormat("HH:mm:ss.SSSZ");
-	/** Format of a time */
-	private final SimpleDateFormat mTime = new SimpleDateFormat("HH:mm:ss.SSS");
-	/** Format of a date used by mserver */
-	private final SimpleDateFormat mDate = new SimpleDateFormat("yyyy-MM-dd");
 
 	/**
-	 * 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.
+	 * 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.
 	 *
 	 * @param connection the connection that created this Statement
 	 * @param resultSetType type of {@link ResultSet} to produce
@@ -153,8 +150,7 @@ public class MonetPreparedStatement exte
 	//== methods interface PreparedStatement
 
 	/**
-	 * Adds a set of parameters to this PreparedStatement object's batch
-	 * of commands.
+	 * Adds a set of parameters to this PreparedStatement object's batch of commands.
 	 *
 	 * @throws SQLException if a database access error occurs
 	 */
@@ -197,10 +193,9 @@ public class MonetPreparedStatement exte
 	 * getUpdateCount to retrieve the result; you must call
 	 * getMoreResults to move to any subsequent result(s).
 	 *
-	 * @return true if the first result is a ResultSet object; false if the
-	 *              first result is an update count or there is no result
-	 * @throws SQLException if a database access error occurs or an argument
-	 *                      is supplied to this method
+	 * @return true if the first result is a ResultSet object; false if the first result is an update count or there is
+	 * no result
+	 * @throws SQLException if a database access error occurs or an argument is supplied to this method
 	 */
 	@Override
 	public boolean execute() throws SQLException {
@@ -214,13 +209,10 @@ public class MonetPreparedStatement exte
 	}
 
 	/**
-	 * Executes the SQL query in this PreparedStatement object and returns the
-	 * ResultSet object generated by the query.
+	 * Executes the SQL query in this PreparedStatement object and returns the ResultSet object generated by the query.
 	 *
-	 * @return a ResultSet object that contains the data produced by the query;
-	 *         never null
-	 * @throws SQLException if a database access error occurs or the SQL
-	 *                      statement does not return a ResultSet object
+	 * @return a ResultSet object that contains the data produced by the query never null
+	 * @throws SQLException if a database access error occurs or the SQL statement does not return a ResultSet object
 	 */
 	@Override
 	public ResultSet executeQuery() throws SQLException {
@@ -243,8 +235,7 @@ public class MonetPreparedStatement exte
 	 *
 	 * @return either (1) the row count for INSERT, UPDATE, or DELETE
 	 *         statements or (2) 0 for SQL statements that return nothing
-	 * @throws SQLException if a database access error occurs or the SQL
-	 *                     statement returns a ResultSet object
+	 * @throws SQLException if a database access error occurs or the SQL statement returns a ResultSet object
 	 */
 	@Override
 	public int executeUpdate() throws SQLException {
@@ -275,6 +266,7 @@ public class MonetPreparedStatement exte
 		}
 		throw new SQLException("No such column with index: " + colnr, "M1M05");
 	}
+
 	/**
 	 * Returns the index (0..size-1) in the backing arrays for the given
 	 * parameter number or an SQLException when not found
@@ -291,7 +283,6 @@ public class MonetPreparedStatement exte
 		throw new SQLException("No such parameter with index: " + paramnr, "M1M05");
 	}
 
-
 	/* helper for the anonymous class inside getMetaData */
 	private abstract class rsmdw extends MonetWrapper implements ResultSetMetaData {}
 	/**
@@ -377,8 +368,7 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Indicates whether the designated column can be used in a
-			 * where clause.
+			 * Indicates whether the designated column can be used in a where clause.
 			 *
 			 * Returning true for all here, even for CLOB, BLOB.
 			 *
@@ -391,11 +381,9 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Indicates whether the designated column is a cash value.
-			 * From the MonetDB database perspective it is by definition
-			 * unknown whether the value is a currency, because there are
-			 * no currency datatypes such as MONEY.  With this knowledge
-			 * we can always return false here.
+			 * Indicates whether the designated column is a cash value. From the MonetDB database perspective it is by
+			 * definition unknown whether the value is a currency, because there are no currency datatypes such as
+			 * MONEY. With this knowledge we can always return false here.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return false
@@ -406,8 +394,7 @@ public class MonetPreparedStatement exte
 			}
 			
 			/**
-			 * Indicates whether values in the designated column are signed
-			 * numbers.
+			 * Indicates whether values in the designated column are signed numbers.
 			 * Within MonetDB all numeric types (except oid and ptr) are signed.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
@@ -438,12 +425,10 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Indicates the designated column's normal maximum width in
-			 * characters.
+			 * Indicates the designated column's normal maximum width in characters.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
-			 * @return the normal maximum number of characters allowed as the
-			 *         width of the designated column
+			 * @return the normal maximum number of characters allowed as the width of the designated column
 			 * @throws SQLException if there is no such column
 			 */
 			@Override
@@ -487,10 +472,8 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Get the designated column's number of decimal digits.
-			 * This method is currently very expensive as it needs to
-			 * retrieve the information from the database using an SQL
-			 * query.
+			 * Get the designated column's number of decimal digits. This method is currently very expensive as it
+			 * needs to retrieve the information from the database using an SQL query.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return precision
@@ -506,10 +489,8 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Gets the designated column's number of digits to right of
-			 * the decimal point.  This method is currently very
-			 * expensive as it needs to retrieve the information from
-			 * the database using an SQL query.
+			 * Gets the designated column's number of digits to right of the decimal point. This method is currently
+			 * very expensive as it needs to retrieve the information from the database using an SQL query.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return scale
@@ -525,10 +506,8 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Indicates the nullability of values in the designated
-			 * column.  This method is currently very expensive as it
-			 * needs to retrieve the information from the database using
-			 * an SQL query.
+			 * Indicates the nullability of values in the designated column. This method is currently very expensive as
+			 * it needs to retrieve the information from the database using an SQL query.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return nullability
@@ -544,8 +523,7 @@ public class MonetPreparedStatement exte
 			 * MonetDB does not support the catalog naming concept as in: catalog.schema.table naming scheme
 			 *
 			 * @param column the first column is 1, the second is 2, ...
-			 * @return the name of the catalog for the table in which the given
-			 *         column appears or "" if not applicable
+			 * @return the name of the catalog for the table in which the given column appears or "" if not applicable
 			 */
 			@Override
 			public String getCatalogName(int column) throws SQLException {
@@ -553,9 +531,8 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Indicates whether the designated column is definitely not
-			 * writable.  MonetDB does not support cursor updates, so
-			 * nothing is writable.
+			 * Indicates whether the designated column is definitely not writable.  MonetDB does not support cursor
+			 * updates, so nothing is writable.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return true if so; false otherwise
@@ -566,8 +543,7 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Indicates whether it is possible for a write on the
-			 * designated column to succeed.
+			 * Indicates whether it is possible for a write on the designated column to succeed.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return true if so; false otherwise
@@ -578,8 +554,7 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Indicates whether a write on the designated column will
-			 * definitely succeed.
+			 * Indicates whether a write on the designated column will definitely succeed.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return true if so; false otherwise
@@ -590,18 +565,14 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Returns the fully-qualified name of the Java class whose
-			 * instances are manufactured if the method
-			 * ResultSet.getObject is called to retrieve a value from
-			 * the column.  ResultSet.getObject may return a subclass of
-			 * the class returned by this method.
+			 * Returns the fully-qualified name of the Java class whose instances are manufactured if the method
+			 * ResultSet.getObject is called to retrieve a value from the column.  ResultSet.getObject may return a
+			 * subclass of the class returned by this method.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
-			 * @return the fully-qualified name of the class in the Java
-			 *         programming language that would be used by the method
-			 *         ResultSet.getObject to retrieve the value in the
-			 *         specified column. This is the class name used for custom
-			 *         mapping.
+			 * @return the fully-qualified name of the class in the Java programming language that would be used by the
+			 * method ResultSet.getObject to retrieve the value in the specified column. This is the class name used
+			 * for custom mapping.
 			 * @throws SQLException if there is no such column
 			 */
 			@Override
@@ -610,9 +581,8 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Gets the designated column's suggested title for use in
-			 * printouts and displays. This is currently equal to
-			 * getColumnName().
+			 * Gets the designated column's suggested title for use in printouts and displays. This is currently equal
+			 * to getColumnName().
 			 *
 			 * @param column the first column is 1, the second is 2, ...
 			 * @return the suggested column title
@@ -659,9 +629,8 @@ public class MonetPreparedStatement exte
 			 * Retrieves the designated column's database-specific type name.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
-			 * @return type name used by the database. If the column type is a
-			 *         user-defined type, then a fully-qualified type name is
-			 *         returned.
+			 * @return type name used by the database. If the column type is a user-defined type, then a
+			 * fully-qualified type name is returned.
 			 * @throws SQLException if there is no such column
 			 */
 			@Override
@@ -678,20 +647,17 @@ public class MonetPreparedStatement exte
 	/* helper class for the anonymous class in getParameterMetaData */
 	private abstract class pmdw extends MonetWrapper implements ParameterMetaData {}
 	/**
-	 * Retrieves the number, types and properties of this
-	 * PreparedStatement object's parameters.
+	 * Retrieves the number, types and properties of this PreparedStatement object's parameters.
 	 *
-	 * @return a ParameterMetaData object that contains information
-	 *         about the number, types and properties of this
-	 *         PreparedStatement object's parameters
+	 * @return a ParameterMetaData object that contains information about the number, types and properties of this
+	 * PreparedStatement object's parameters
 	 * @throws SQLException if a database access error occurs
 	 */
 	@Override
 	public ParameterMetaData getParameterMetaData() throws SQLException {
 		return new pmdw() {
 			/**
-			 * Retrieves the number of parameters in the
-			 * PreparedStatement object for which this ParameterMetaData
+			 * Retrieves the number of parameters in the PreparedStatement object for which this ParameterMetaData
 			 * object contains information.
 			 *
 			 * @return the number of parameters
@@ -710,16 +676,13 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Retrieves whether null values are allowed in the
-			 * designated parameter.
+			 * Retrieves whether null values are allowed in the designated parameter.
 			 *
 			 * This is currently always unknown for MonetDB/SQL.
 			 *
 			 * @param param the first parameter is 1, the second is 2, ...
-			 * @return the nullability status of the given parameter;
-			 *         one of ParameterMetaData.parameterNoNulls,
-			 *         ParameterMetaData.parameterNullable, or
-			 *         ParameterMetaData.parameterNullableUnknown
+			 * @return the nullability status of the given parameter; one of ParameterMetaData.parameterNoNulls,
+			 * ParameterMetaData.parameterNullable, or ParameterMetaData.parameterNullableUnknown
 			 * @throws SQLException if a database access error occurs
 			 */
 			@Override
@@ -728,8 +691,7 @@ public class MonetPreparedStatement exte
 			}
 
 			/**
-			 * Retrieves whether values for the designated parameter can
-			 * be signed numbers.
+			 * Retrieves whether values for the designated parameter can be signed numbers.
 			 *
 			 * @param param the first parameter is 1, the second is 2, ...
 			 * @return true if so; false otherwise
@@ -737,7 +699,7 @@ public class MonetPreparedStatement exte
 			 */
 			@Override
 			public boolean isSigned(int param) throws SQLException {
-				// we can hardcode this, based on the colum type
+				// we can hardcode this, based on the column type
 				switch (getParameterType(param)) {
 					case Types.NUMERIC:
 					case Types.DECIMAL:
@@ -1364,8 +1326,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) + "'");
 		}
 	}
 
@@ -2238,7 +2200,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
@@ -2248,8 +2210,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) + "'");
 			}
 		}
 	}
@@ -2295,7 +2257,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
@@ -2305,8 +2267,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) + "'");
 			}
 		}
 	}
@@ -2377,8 +2339,7 @@ public class MonetPreparedStatement exte
 	}
 
 	/**
-	 * Call close to release the server-sided handle for this
-	 * PreparedStatement.
+	 * Call close to release the server-sided handle for this PreparedStatement.
 	 */
 	@Override
 	protected void finalize() {
@@ -2388,9 +2349,8 @@ public class MonetPreparedStatement exte
 	//== end methods interface PreparedStatement
 
 	/**
-	 * Sets the given index with the supplied value. If the given index is
-	 * out of bounds, and SQLException is thrown.  The given value should
-	 * never be null.
+	 * Sets the given index with the supplied value. If the given index is out of bounds, and SQLException is thrown.
+	 * The given value should never be null.
 	 *
 	 * @param index the parameter index
 	 * @param val the exact String representation to set
diff --git a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java
@@ -10,12 +10,10 @@ package nl.cwi.monetdb.jdbc;
 
 import nl.cwi.monetdb.jdbc.types.INET;
 import nl.cwi.monetdb.jdbc.types.URL;
+import nl.cwi.monetdb.mcl.responses.DataBlockResponse;
 import nl.cwi.monetdb.mcl.responses.ResultSetResponse;
 
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.Reader;
-import java.io.StringReader;
+import java.io.*;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.math.BigDecimal;
@@ -92,7 +90,7 @@ public class MonetResultSet extends Mone
 	/** Just a dummy variable to keep store the fetchsize set. */
 	private int fetchSize;
 	/** The current row's values */
-	Object[] values;
+	DataBlockResponse currentBlock;
 
 	/**
 	 * Main constructor backed by the given Header.
@@ -120,7 +118,6 @@ public class MonetResultSet extends Mone
 		this.columns = header.getNames();
 		this.types = header.getTypes();
 		this.JdbcSQLTypes = header.getJdbcSQLTypes();
-		this.values = header.getLine(this.curRow);
 	}
 
 	/**
@@ -156,6 +153,11 @@ public class MonetResultSet extends Mone
 		this.JdbcSQLTypes = JdbcSQLTypes;
 	}
 
+	private boolean setLastNullValue(int columnIndex) {
+		this.lastReadWasNull = currentBlock.checkValueIsNull(columnIndex);
+		return this.lastReadWasNull;
+	}
+
 	//== methods of interface ResultSet
 
 	// Chapter 14.2.2 Sun JDBC 3.0 Specification
@@ -201,19 +203,17 @@ public class MonetResultSet extends Mone
 		} else if (row > tupleCount + 1) {
 			row = tupleCount + 1; // after last
 		}
-
-		this.values = header.getLine(row - 1);
 		// store it
 		this.curRow = row;
-		return this.values != null;
+		this.currentBlock = header.getDataBlockCorrespondingToLine(row - 1);
+		return this.curRow <= this.tupleCount;
 	}
 
 	/**
 	 * Moves the cursor to the end of this ResultSet object, just after the last row. This method has no effect if the
 	 * result set contains no rows.
 	 *
-	 * @throws SQLException if a database access error occurs or the result set
-	 *         type is TYPE_FORWARD_ONLY
+	 * @throws SQLException if a database access error occurs or the result set type is TYPE_FORWARD_ONLY
 	 */
 	@Override
 	public void afterLast() throws SQLException {
@@ -224,8 +224,7 @@ public class MonetResultSet extends Mone
 	 * Moves the cursor to the front of this ResultSet object, just before the first row. This method has no effect
 	 * if the result set contains no rows.
 	 *
-	 * @throws SQLException if a database access error occurs or the result set
-	 *         type is TYPE_FORWARD_ONLY
+	 * @throws SQLException if a database access error occurs or the result set type is TYPE_FORWARD_ONLY
 	 */
 	@Override
 	public void beforeFirst() throws SQLException {
@@ -407,13 +406,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public Reader getCharacterStream(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return new StringReader((String) val);
+			return new StringReader(currentBlock.getValueAsString(columnIndex - 1));
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -485,13 +481,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public Blob getBlob(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return (MonetBlob) val;
+			return (MonetBlob) currentBlock.getObjectValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -528,13 +521,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public Clob getClob(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return (MonetClob) val;
+			return (MonetClob) currentBlock.getObjectValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -605,13 +595,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return (BigDecimal) val;
+			return (BigDecimal) currentBlock.getObjectValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -633,16 +620,12 @@ public class MonetResultSet extends Mone
 	@Deprecated
 	public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-
-			BigDecimal bd = (BigDecimal) val;
-			bd.setScale(scale);
-			return bd;
+			BigDecimal val = (BigDecimal) currentBlock.getObjectValue(columnIndex - 1);
+			val.setScale(scale);
+			return val;
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -693,24 +676,21 @@ public class MonetResultSet extends Mone
 	@Override
 	public boolean getBoolean(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
-				return false;	// if the value is SQL NULL, the value returned is false
+			if(setLastNullValue(columnIndex - 1)) {
+				return false; // if the value is SQL NULL, the value returned is false
 			}
-			lastReadWasNull = false;
 			// match type specific values
 			switch (JdbcSQLTypes[columnIndex - 1]) {
 				case Types.BOOLEAN:
-					return (Boolean) val;
+					return currentBlock.getBooleanValue(columnIndex - 1);
 				case Types.CHAR:
 				case Types.VARCHAR:
 				case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness
 				case Types.CLOB:
-					String other = (String) val;
-					if ("false".equalsIgnoreCase(other) || "0".equals(val))
+					String val = currentBlock.getValueAsString(columnIndex - 1);
+					if ("false".equalsIgnoreCase(val) || "0".equals(val))
 						return false;
-					if ("true".equalsIgnoreCase(other) || "1".equals(val))
+					if ("true".equalsIgnoreCase(val) || "1".equals(val))
 						return true;
 					throw newSQLInvalidColumnIndexException(columnIndex);
 				case Types.BIT: // MonetDB doesn't use type BinaryDigit, it's here for completeness
@@ -764,13 +744,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public byte getByte(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
-				return (byte) 0;
+			if(setLastNullValue(columnIndex - 1)) {
+				return 0;
 			}
-			lastReadWasNull = false;
-			return (Byte) val;
+			return currentBlock.getByteValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -804,22 +781,18 @@ public class MonetResultSet extends Mone
 	@Override
 	public byte[] getBytes(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-
 			// According to Table B-6, getBytes() only operates on BINARY types
 			switch (JdbcSQLTypes[columnIndex - 1]) {
 				case Types.BLOB:
-					return ((MonetBlob) val).getBuffer();
+					return ((MonetBlob) currentBlock.getObjectValue(columnIndex - 1)).getBuffer();
 				case Types.BINARY:
 				case Types.VARBINARY:
 				case Types.LONGVARBINARY:
 					// unpack the HEX (BLOB) notation to real bytes
-					return (byte[]) val;
+					return (byte[]) currentBlock.getObjectValue(columnIndex - 1);
 				default:
 					throw new SQLException("Cannot operate on " + types[columnIndex - 1] + " type", "M1M05");
 			}
@@ -899,13 +872,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public double getDouble(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
-				return 0;
+			if(setLastNullValue(columnIndex - 1)) {
+				return 0.0d;
 			}
-			lastReadWasNull = false;
-			return (Double) val;
+			return currentBlock.getDoubleValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -1019,13 +989,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public float getFloat(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
-				return 0;
+			if(setLastNullValue(columnIndex - 1)) {
+				return 0.0f;
 			}
-			lastReadWasNull = false;
-			return (Float) val;
+			return currentBlock.getFloatValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -1056,15 +1023,11 @@ public class MonetResultSet extends Mone
 	 */
 	@Override
 	public int getInt(int columnIndex) throws SQLException {
-		Object val;
 		try {
-			val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return 0;
 			}
-			lastReadWasNull = false;
-			return (Integer) val;
+			return currentBlock.getIntValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -1095,15 +1058,13 @@ public class MonetResultSet extends Mone
 	 */
 	@Override
 	public long getLong(int columnIndex) throws SQLException {
-		Object val;
 		try {
-			val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return 0;
 			}
-			lastReadWasNull = false;
-			return (Long) val;
+			return currentBlock.getLongValue(columnIndex - 1);
+		} catch (ClassCastException ex) {
+			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
 			throw newSQLInvalidColumnIndexException(columnIndex);
 		}
@@ -1486,7 +1447,8 @@ public class MonetResultSet extends Mone
 			 * an SQL query.
 			 *
 			 * @param column the first column is 1, the second is 2, ...
-			 * @return the nullability status of the given column; one of columnNoNulls, columnNullable or columnNullableUnknown
+			 * @return the nullability status of the given column; one of columnNoNulls, columnNullable or
+			 * columnNullableUnknown
 			 * @throws SQLException if a database access error occurs
 			 */
 			@Override
@@ -1680,17 +1642,13 @@ public class MonetResultSet extends Mone
 	 */
 	@Override
 	public Object getObject(int columnIndex) throws SQLException {
-		// Many generic JDBC programs use getObject(colnr) to retrieve value objects from a resultset
-		// For speed the implementation should be as fast as possible, so avoid method calls (by inlining code) where possible
+		// Many generic JDBC programs use getObject(colnr) to retrieve value objects from a resultset. For speed the
+		// implementation should be as fast as possible, so avoid method calls (by inlining code) where possible
 		final int JdbcType;
-		final Object val;
 		try {
-			val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
 			JdbcType = JdbcSQLTypes[columnIndex - 1];
 		} catch (IndexOutOfBoundsException e) {
 			throw newSQLInvalidColumnIndexException(columnIndex);
@@ -1698,6 +1656,8 @@ public class MonetResultSet extends Mone
 
 		switch(JdbcType) {
 			case Types.BIT: // MonetDB doesn't use type BInary digiT, it's here for completeness
+			case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness
+			case Types.BOOLEAN:
 			case Types.TINYINT:
 			case Types.SMALLINT:
 			case Types.INTEGER:
@@ -1707,22 +1667,32 @@ public class MonetResultSet extends Mone
 			case Types.REAL:
 			case Types.DECIMAL:
 			case Types.NUMERIC:
-			case Types.BOOLEAN:
 			case Types.CHAR:
-			case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness
+			case Types.VARCHAR:
+			case Types.BLOB:
 			case Types.CLOB:
-			case Types.BLOB:
-				return val;
-			case Types.VARCHAR: {
+				return currentBlock.getValueAsObject(columnIndex - 1);
+			case Types.DATE:
+				return getDate(columnIndex);
+			case Types.TIME:
+				return getTime(columnIndex);
+			case Types.TIMESTAMP:
+				return getTimestamp(columnIndex);
+			case Types.BINARY:
+			case Types.VARBINARY:
+			case Types.LONGVARBINARY: // MonetDB doesn't use type LONGVARBINARY, it's here for completeness
+				return getBytes(columnIndex);
+			case Types.OTHER: {
 				// The MonetDB types: inet, json, url and uuid are all mapped to Types.VARCHAR in MonetDriver.typeMap
 				// For these MonetDB types (except json, see comments below) we try to create objects of the corresponding class.
 				String MonetDBType = types[columnIndex - 1];
+				String val = currentBlock.getValueAsString(columnIndex - 1);
 				switch (MonetDBType.length()) {
 				case 3:
 					if ("url".equals(MonetDBType)) {
 						try {
 							URL url_obj = new URL();
-							url_obj.fromString((String) val);
+							url_obj.fromString(val);
 							return url_obj;
 						} catch (Exception exc) {
 							// ignore exception and just return the val String object
@@ -1734,7 +1704,7 @@ public class MonetResultSet extends Mone
 					if ("inet".equals(MonetDBType)) {
 						try {
 							INET inet_obj = new INET();
-							inet_obj.fromString((String) val);
+							inet_obj.fromString(val);
 							return inet_obj;
 						} catch (Exception exc) {
 							// ignore exception and just return the val String object
@@ -1743,13 +1713,12 @@ public class MonetResultSet extends Mone
 					} else
 					if ("uuid".equals(MonetDBType)) {
 						try {
-							return UUID.fromString((String) val);
+							return UUID.fromString(val);
 						} catch (IllegalArgumentException exc) {
 							// ignore exception and just return the val String object
 							return val;
 						}
-//					} else
-//					if ("json".equals(MonetDBType)) {
+//					} else if ("json".equals(MonetDBType)) {
 						// There is no support for JSON in standard java class libraries.
 						// Possibly we could use org.json.simple.JSONObject or other/faster libs
 						// javax.json.Json is not released yet (see https://json-processing-spec.java.net/)
@@ -1762,17 +1731,6 @@ public class MonetResultSet extends Mone
 				}
 				return val;
 			}
-			case Types.DATE:
-				return getDate(columnIndex);
-			case Types.TIME:
-				return getTime(columnIndex);
-			case Types.TIMESTAMP:
-				return getTimestamp(columnIndex);
-			case Types.BINARY:
-			case Types.VARBINARY:
-			case Types.LONGVARBINARY: // MonetDB doesn't use type LONGVARBINARY, it's here for completeness
-				return getBytes(columnIndex);
-			case Types.OTHER:
 			default:
 				// When we get here the column type is a non-standard JDBC SQL type, possibly a User Defined Type.
 				// Just call getObject(int, Map) for those rare cases.
@@ -1821,15 +1779,11 @@ public class MonetResultSet extends Mone
 	@Override
 	@SuppressWarnings("unchecked")
 	public Object getObject(int columnIndex, Map<String,Class<?>> map) throws SQLException {
-		final Object val;
 		final String MonetDBtype;
 		try {
-			val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
 			MonetDBtype = types[columnIndex - 1];
 		} catch (IndexOutOfBoundsException e) {
 			throw newSQLInvalidColumnIndexException(columnIndex);
@@ -1845,7 +1799,7 @@ public class MonetResultSet extends Mone
 		}
 
 		if (type == null || type == String.class) {
-			return val;
+			return currentBlock.getValueAsString(columnIndex - 1);
 		} else if (type == BigDecimal.class) {
 			return getBigDecimal(columnIndex);
 		} else if (type == Boolean.class) {
@@ -2022,7 +1976,7 @@ public class MonetResultSet extends Mone
 			x.readSQL(input, MonetDBtype);
 			return x;
 		} else {
-			return val;
+			return currentBlock.getObjectValue(columnIndex - 1);
 		}
 	}
 
@@ -2234,13 +2188,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public short getShort(int columnIndex) throws SQLException {
 		try {
-			Object val = this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return 0;
 			}
-			lastReadWasNull = false;
-			return (Short) val;
+			return currentBlock.getShortValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -2285,13 +2236,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public String getString(int columnIndex) throws SQLException {
 		try {
-			String val = (String) this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return val;
+			return currentBlock.getValueAsString(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -2403,13 +2351,10 @@ public class MonetResultSet extends Mone
 	@Override
 	public Date getDate(int columnIndex, Calendar cal) throws SQLException {
 		try {
-			Date val = (Date) this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return val;
+			return (Date) currentBlock.getObjectValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -2479,13 +2424,10 @@ public class MonetResultSet extends Mone
 		if (cal == null)
 			throw new IllegalArgumentException("No Calendar object given!");
 		try {
-			Time val = (Time) this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return val;
+			return (Time) currentBlock.getObjectValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -2555,13 +2497,10 @@ public class MonetResultSet extends Mone
 		if (cal == null)
 			throw new IllegalArgumentException("No Calendar object given!");
 		try {
-			Timestamp val = (Timestamp) this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
-			return val;
+			return (Timestamp) currentBlock.getObjectValue(columnIndex - 1);
 		} catch (ClassCastException ex) {
 			throw new SQLException(ex.getMessage());
 		} catch (IndexOutOfBoundsException e) {
@@ -2624,14 +2563,11 @@ public class MonetResultSet extends Mone
 	@Override
 	public java.net.URL getURL(int columnIndex) throws SQLException {
 		try {
-			String val = (String) this.values[columnIndex - 1];
-			if (val == null) {
-				lastReadWasNull = true;
+			if(setLastNullValue(columnIndex - 1)) {
 				return null;
 			}
-			lastReadWasNull = false;
 			try {
-				return new java.net.URL(val);
+				return new java.net.URL(currentBlock.getValueAsString(columnIndex - 1));
 			} catch (MalformedURLException e) {
 				throw new SQLException(e.getMessage(), "M1M05");
 			}
diff --git a/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java b/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
@@ -678,13 +678,13 @@ public class MonetStatement extends Mone
 		if (header instanceof UpdateResponse) {
 			String lastid = ((UpdateResponse)header).getLastid();
 			if (lastid.equals("-1")) {
-				results = new String[0][1];
+				results = new String[1][1];
 			} else {
 				results = new String[1][1];
 				results[0][0] = lastid;
 			}
 		} else {
-			results = new String[0][1];
+			results = new String[1][1];
 		}
 
 		try {
@@ -1211,17 +1211,17 @@ final class MonetVirtualResultSet extend
 			throws IllegalArgumentException {
 		super(statement, columns, types, jdbcTypes, results.length);
 		this.results = results;
-		closed = false;
+		this.closed = false;
+        this.currentBlock.setData(results);
 	}
 
 	/**
-	 * This method is overridden in order to let it use the results array
-	 * instead of the cache in the Statement object that created it.
+	 * This method is overridden in order to let it use the results array instead of the cache in the Statement object
+     * that created it.
 	 *
-	 * @param row the number of the row to which the cursor should move. A
-	 *        positive number indicates the row number counting from the
-	 *        beginning of the result set; a negative number indicates the row
-	 *        number counting from the end of the result set
+	 * @param row the number of the row to which the cursor should move. A positive number indicates the row number
+     * counting from the beginning of the result set; a negative number indicates the row number counting from the end
+     * of the result set
 	 * @return true if the cursor is on the result set; false otherwise
 	 * @throws SQLException if a database error occurs
 	 */
@@ -1245,7 +1245,9 @@ final class MonetVirtualResultSet extend
 		// see if we have the row
 		if (row < 1 || row > tupleCount) return false;
 
-		System.arraycopy(this.results[row - 1], 0, this.values, 0, this.results[row - 1].length);
+		String[] values = (String[]) this.currentBlock.getData()[0];
+
+		System.arraycopy(this.results[row - 1], 0, values, 0, this.results[row - 1].length);
 
 		return true;
 	}
diff --git a/src/main/java/nl/cwi/monetdb/mcl/connection/MonetDBConnectionFactory.java b/src/main/java/nl/cwi/monetdb/mcl/connection/MonetDBConnectionFactory.java
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/MonetDBConnectionFactory.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/MonetDBConnectionFactory.java
@@ -3,8 +3,8 @@ package nl.cwi.monetdb.mcl.connection;
 import nl.cwi.monetdb.jdbc.MonetConnection;
 import nl.cwi.monetdb.jdbc.MonetDriver;
 import nl.cwi.monetdb.mcl.connection.embedded.EmbeddedConnection;
-import nl.cwi.monetdb.mcl.connection.socket.MapiConnection;
-import nl.cwi.monetdb.mcl.connection.socket.MapiLanguage;
+import nl.cwi.monetdb.mcl.connection.mapi.MapiConnection;
+import nl.cwi.monetdb.mcl.connection.mapi.MapiLanguage;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 
 import java.io.File;
diff --git a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/AbstractSocket.java b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java
rename from src/main/java/nl/cwi/monetdb/mcl/connection/socket/AbstractSocket.java
rename to src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/AbstractSocket.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/AbstractSocket.java
@@ -1,4 +1,4 @@
-package nl.cwi.monetdb.mcl.connection.socket;
+package nl.cwi.monetdb.mcl.connection.mapi;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -85,18 +85,23 @@ public abstract class AbstractSocket imp
     public int readLine(StringBuilder builder) throws IOException {
         builder.setLength(0);
         boolean found = false;
+        char[] array = this.stringsDecoded.array();
+        int position = this.stringsDecoded.position();
 
         while(!found) {
             if(!this.stringsDecoded.hasRemaining()) {
                 this.readToBuffer();
+                array = this.stringsDecoded.array();
+                position = 0;
             }
-            char c = this.stringsDecoded.get();
+            char c = array[position++];
             if(c == '\n') {
                 found = true;
             } else {
                 builder.append(c);
             }
         }
+        this.stringsDecoded.position(position);
         return builder.length();
     }
 
diff --git a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/MapiConnection.java b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiConnection.java
rename from src/main/java/nl/cwi/monetdb/mcl/connection/socket/MapiConnection.java
rename to src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiConnection.java
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/MapiConnection.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiConnection.java
@@ -1,4 +1,4 @@
-package nl.cwi.monetdb.mcl.connection.socket;
+package nl.cwi.monetdb.mcl.connection.mapi;
 
 import nl.cwi.monetdb.jdbc.MonetConnection;
 import nl.cwi.monetdb.mcl.connection.ChannelSecurity;
diff --git a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/MapiLanguage.java b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiLanguage.java
rename from src/main/java/nl/cwi/monetdb/mcl/connection/socket/MapiLanguage.java
rename to src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiLanguage.java
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/MapiLanguage.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/MapiLanguage.java
@@ -1,4 +1,4 @@
-package nl.cwi.monetdb.mcl.connection.socket;
+package nl.cwi.monetdb.mcl.connection.mapi;
 
 import nl.cwi.monetdb.mcl.connection.IMonetDBLanguage;
 
diff --git a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/OldMapiSocket.java b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/OldMapiSocket.java
rename from src/main/java/nl/cwi/monetdb/mcl/connection/socket/OldMapiSocket.java
rename to src/main/java/nl/cwi/monetdb/mcl/connection/mapi/OldMapiSocket.java
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/socket/OldMapiSocket.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/mapi/OldMapiSocket.java
@@ -1,4 +1,4 @@
-package nl.cwi.monetdb.mcl.connection.socket;
+package nl.cwi.monetdb.mcl.connection.mapi;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java b/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java
@@ -46,7 +46,8 @@ public abstract class AbstractProtocol<T
     public abstract TableResultHeaders getNextTableHeader(Object line, String[] stringValues, int[] intValues)
             throws ProtocolException;
 
-    public abstract int parseTupleLine(Object line, Object[] values, int[] typesMap) throws ProtocolException;
+    public abstract int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] values, boolean[] nulls)
+            throws ProtocolException;
 
     public abstract String getRemainingStringLine(int startIndex);
 
diff --git a/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java b/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java
@@ -72,7 +72,7 @@ public class EmbeddedProtocol extends Ab
     }
 
     @Override
-    public int parseTupleLine(Object line, Object[] values, int[] typesMap) throws ProtocolException {
+    public int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] values, boolean[] nulls) throws ProtocolException {
         return 0;
     }
 
diff --git a/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java b/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java
@@ -61,7 +61,7 @@ public class NewMapiProtocol extends Abs
     }
 
     @Override
-    public int parseTupleLine(Object line, Object[] values, int[] typesMap) throws ProtocolException {
+    public int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] values, boolean[] nulls) throws ProtocolException {
         return 0;
     }
 
diff --git a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java
@@ -1,7 +1,7 @@
 package nl.cwi.monetdb.mcl.protocol.oldmapi;
 
 import nl.cwi.monetdb.jdbc.MonetConnection;
-import nl.cwi.monetdb.mcl.connection.socket.OldMapiSocket;
+import nl.cwi.monetdb.mcl.connection.mapi.OldMapiSocket;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 import nl.cwi.monetdb.mcl.protocol.AbstractProtocol;
 import nl.cwi.monetdb.mcl.protocol.ServerResponses;
@@ -128,9 +128,10 @@ public class OldMapiProtocol extends Abs
     }
 
     @Override
-    public int parseTupleLine(Object line, Object[] values, int[] typesMap) throws ProtocolException {
-        return OldMapiTupleLineParser.OldMapiParseTupleLine((StringBuilder) line, values, this.tupleLineBuilder,
-                typesMap);
+    public int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] data, boolean[] nulls)
+            throws ProtocolException {
+        return OldMapiTupleLineParser.OldMapiParseTupleLine(lineNumber, (StringBuilder) line,
+                this.tupleLineBuilder, typesMap, data, nulls);
     }
 
     @Override
diff --git a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java
@@ -90,10 +90,10 @@ final class OldMapiTableHeaderParser {
             if (builder.charAt(i) == ',' && builder.charAt(i + 1) == '\t') {
                 intValues[elem++] = tmp;
                 tmp = 0;
+                i++;
             } else {
                 tmp *= 10;
-                // note: don't use Character.isDigit() here, because
-                // we only want ISO-LATIN-1 digits
+                // note: don't use Character.isDigit() here, because we only want ISO-LATIN-1 digits
                 if (builder.charAt(i) >= '0' && builder.charAt(i) <= '9') {
                     tmp += (int) builder.charAt(i) - (int)'0';
                 } else {
diff --git a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTupleLineParser.java
@@ -17,16 +17,17 @@ import java.text.SimpleDateFormat;
  */
 final class OldMapiTupleLineParser {
 
-    static int OldMapiParseTupleLine(StringBuilder line, Object[] values, StringBuilder helper, int[] jDBCTypesMap) throws ProtocolException {
+    static int OldMapiParseTupleLine(int lineNumber, StringBuilder line, StringBuilder helper, int[] typesMap,
+                                     Object[] values, boolean[] nulls) throws ProtocolException {
         int len = line.length();
 
         // first detect whether this is a single value line (=) or a real tuple ([)
         if (line.charAt(0) == '=') {
-            if (values.length != 1) {
-                throw new ProtocolException(values.length + " columns expected, but only single value found");
+            if (typesMap.length != 1) {
+                throw new ProtocolException(typesMap.length + " columns expected, but only single value found");
             }
             // return the whole string but the leading =
-            values[0] = line.substring(1);
+            OldMapiStringToJavaObjectConverter(line.substring(1), lineNumber, values[0], typesMap[0]);
             return 1;
         }
 
@@ -119,11 +120,14 @@ final class OldMapiTupleLineParser {
                             }
 
                             // put the unescaped string in the right place
-                            values[column] = OldMapiStringToJavaObjectConverter(helper.toString(), jDBCTypesMap[column]);
+                            OldMapiStringToJavaObjectConverter(helper.toString(), lineNumber, values[column], typesMap[column]);
+                            nulls[column] = false;
                         } else if ((i - 1) - cursor == 4 && line.indexOf("NULL", cursor) == cursor) {
-                            values[column] = null;
+                            SetNullValue(lineNumber, values[column], typesMap[column]);
+                            nulls[column] = true;
                         } else {
-                            values[column] = OldMapiStringToJavaObjectConverter(line.substring(cursor, i - 1), jDBCTypesMap[column]);
+                            OldMapiStringToJavaObjectConverter(line.substring(cursor, i - 1), lineNumber, values[column], typesMap[column]);
+                            nulls[column] = false;
                         }
                         column++;
                         cursor = i + 1;
@@ -134,7 +138,7 @@ final class OldMapiTupleLineParser {
             }
         }
         // check if this result is of the size we expected it to be
-        if (column != values.length)
+        if (column != typesMap.length)
             throw new ProtocolException("illegal result length: " + column + "\nlast read: " + (column > 0 ? values[column - 1] : "<none>"));
         return column;
     }
@@ -154,56 +158,101 @@ final class OldMapiTupleLineParser {
         return res;
     }
 
-    private static Object OldMapiStringToJavaObjectConverter(String toParse, int jDBCMapping) throws ProtocolException {
+    private static void OldMapiStringToJavaObjectConverter(String toParse, int lineNumber, Object columnArray,
+                                                           int jDBCMapping) throws ProtocolException {
         switch (jDBCMapping) {
+            case Types.BOOLEAN:
+                ((boolean[]) columnArray)[lineNumber] = Boolean.parseBoolean(toParse);
+                break;
+            case Types.TINYINT:
+                ((byte[]) columnArray)[lineNumber] = Byte.parseByte(toParse);
+                break;
+            case Types.SMALLINT:
+                ((short[]) columnArray)[lineNumber] = Short.parseShort(toParse);
+                break;
+            case Types.INTEGER:
+                ((int[]) columnArray)[lineNumber] = Integer.parseInt(toParse);
+                break;
             case Types.BIGINT:
-                return Long.parseLong(toParse);
-            case Types.BLOB:
-                return new MonetBlob(BinaryBlobConverter(toParse));
-            case Types.BINARY:
-                return BinaryBlobConverter(toParse);
-            case Types.BOOLEAN:
-                return Boolean.parseBoolean(toParse);
+                ((long[]) columnArray)[lineNumber] = Long.parseLong(toParse);
+                break;
+            case Types.REAL:
+                ((float[]) columnArray)[lineNumber] = Float.parseFloat(toParse);
+                break;
+            case Types.DOUBLE:
+                ((double[]) columnArray)[lineNumber] = Double.parseDouble(toParse);
+                break;
+            case Types.DECIMAL:
+                ((Object[]) columnArray)[lineNumber] = new BigDecimal(toParse);
+                break;
+            case Types.NUMERIC:
+                ((Object[]) columnArray)[lineNumber] = new BigInteger(toParse);
+                break;
             case Types.CHAR:
-                return toParse;
-            case Types.CLOB:
-                return new MonetClob(toParse);
+            case Types.VARCHAR:
+            case Types.OTHER:
+                ((Object[]) columnArray)[lineNumber] = toParse;
+                break;
             case Types.DATE:
                 try {
-                    return DateParser.parse(toParse);
+                    ((Object[]) columnArray)[lineNumber] = DateParser.parse(toParse);
+                } catch (ParseException e) {
+                    throw new ProtocolException(e.getMessage());
+                }
+                break;
+            case Types.TIME:
+                try {
+                    ((Object[]) columnArray)[lineNumber] = TimeParser.parse(toParse);
                 } catch (ParseException e) {
                     throw new ProtocolException(e.getMessage());
                 }
-            case Types.DECIMAL:
-                return new BigDecimal(toParse);
-            case Types.DOUBLE:
-                return Double.parseDouble(toParse);
-            case Types.NUMERIC:
-                return new BigInteger(toParse);
-            case Types.INTEGER:
-                return Integer.parseInt(toParse);
-            case Types.REAL:
-                return Float.parseFloat(toParse);
-            case Types.SMALLINT:
-                return Short.parseShort(toParse);
-            case Types.TIME:
+                break;
+            case Types.TIMESTAMP:
                 try {
-                    return TimeParser.parse(toParse);
+                    ((Object[]) columnArray)[lineNumber] = TimestampParser.parse(toParse);
                 } catch (ParseException e) {
                     throw new ProtocolException(e.getMessage());
                 }
-            case Types.TIMESTAMP:
-                try {
-                    return TimestampParser.parse(toParse);
-                } catch (ParseException e) {
-                    throw new ProtocolException(e.getMessage());
-                }
+                break;
+            case Types.CLOB:
+                ((Object[]) columnArray)[lineNumber] = new MonetClob(toParse);
+                break;
+            case Types.BLOB:
+                ((Object[]) columnArray)[lineNumber] = new MonetBlob(BinaryBlobConverter(toParse));
+                break;
+            case Types.BINARY:
+                ((Object[]) columnArray)[lineNumber] = BinaryBlobConverter(toParse);
+                break;
+            default:
+                throw new ProtocolException("Unknown type!");
+        }
+    }
+
+    private static void SetNullValue(int lineNumber, Object columnArray, int jDBCMapping) throws ProtocolException {
+        switch (jDBCMapping) {
+            case Types.BOOLEAN:
+                ((boolean[]) columnArray)[lineNumber] = false;
+                break;
             case Types.TINYINT:
-                return Byte.parseByte(toParse);
-            case Types.VARCHAR:
-                return toParse;
+                ((byte[]) columnArray)[lineNumber] = Byte.MIN_VALUE;
+                break;
+            case Types.SMALLINT:
+                ((short[]) columnArray)[lineNumber] = Short.MIN_VALUE;
+                break;
+            case Types.INTEGER:
+                ((int[]) columnArray)[lineNumber] = Integer.MIN_VALUE;
+                break;
+            case Types.BIGINT:
+                ((long[]) columnArray)[lineNumber] = Long.MIN_VALUE;
+                break;
+            case Types.REAL:
+                ((float[]) columnArray)[lineNumber] = Float.MIN_VALUE;
+                break;
+            case Types.DOUBLE:
+                ((double[]) columnArray)[lineNumber] = Double.MIN_VALUE;
+                break;
             default:
-                return null;
+                ((Object[]) columnArray)[lineNumber] = null;
         }
     }
 }
diff --git a/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java b/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java
@@ -5,6 +5,7 @@ import nl.cwi.monetdb.mcl.protocol.Proto
 import nl.cwi.monetdb.mcl.protocol.ServerResponses;
 
 import java.sql.SQLException;
+import java.sql.Types;
 
 /**
  * The DataBlockResponse is tabular data belonging to a
@@ -26,15 +27,17 @@ import java.sql.SQLException;
 public class DataBlockResponse implements IIncompleteResponse {
 
     /** The array to keep the data in */
-    private final Object[][] data;
+    private Object[] data;
     /** The counter which keeps the current position in the data array */
     private int pos;
-    /** Whether we can discard lines as soon as we have read them */
-    private boolean forwardOnly;
     /** The connection protocol to parse the tuple lines */
     private final AbstractProtocol<?> protocol;
     /** The JdbcSQLTypes mapping */
     private final int[] jdbcSQLTypes;
+    /** A mapping of null values of the current Row */
+    private boolean[][] nullMappings;
+    /** A 'pointer' to the current line */
+    private int blockLine;
 
     /**
      * Constructs a DataBlockResponse object.
@@ -45,8 +48,8 @@ public class DataBlockResponse implement
      */
     DataBlockResponse(int rowcount, int columncount, boolean forward, AbstractProtocol<?> protocol, int[] JdbcSQLTypes) {
         this.pos = -1;
-        this.forwardOnly = forward;
-        this.data = new Object[rowcount][columncount];
+        this.data = new Object[columncount];
+        this.nullMappings = new boolean[rowcount][columncount];
         this.protocol = protocol;
         this.jdbcSQLTypes = JdbcSQLTypes;
     }
@@ -63,9 +66,41 @@ public class DataBlockResponse implement
     public void addLine(ServerResponses response, Object line) throws ProtocolException {
         if (response != ServerResponses.RESULT)
             throw new ProtocolException("protocol violation: unexpected line in data block: " + line.toString());
+
+        if(this.pos == -1) { //if it's the first line, initialize the matrix
+            int numberOfColumns = this.data.length, numberOfRows = this.nullMappings.length;
+            for (int i = 0 ; i < numberOfColumns ; i++) {
+                switch (this.jdbcSQLTypes[i]) {
+                    case Types.BOOLEAN:
+                        this.data[i] = new boolean[numberOfRows];
+                        break;
+                    case Types.TINYINT:
+                        this.data[i] = new byte[numberOfRows];
+                        break;
+                    case Types.SMALLINT:
+                        this.data[i] = new short[numberOfRows];
+                        break;
+                    case Types.INTEGER:
+                        this.data[i] = new int[numberOfRows];
+                        break;
+                    case Types.BIGINT:
+                        this.data[i] = new long[numberOfRows];
+                        break;
+                    case Types.REAL:
+                        this.data[i] = new float[numberOfRows];
+                        break;
+                    case Types.DOUBLE:
+                        this.data[i] = new double[numberOfRows];
+                        break;
+                    default:
+                        this.data[i] = new Object[numberOfRows];
+                }
+            }
+        }
+
         // add to the backing array
-        Object[] next = this.data[++this.pos];
-        this.protocol.parseTupleLine(line, next, this.jdbcSQLTypes);
+        int nextPos = ++this.pos;
+        this.protocol.parseTupleLine(nextPos, line, this.jdbcSQLTypes, this.data, this.nullMappings[nextPos]);
     }
 
     /**
@@ -76,7 +111,7 @@ public class DataBlockResponse implement
     @Override
     public boolean wantsMore() {
         // remember: pos is the value already stored
-        return (this.pos + 1) < this.data.length;
+        return (this.pos + 1) < this.nullMappings.length;
     }
 
     /**
@@ -87,8 +122,8 @@ public class DataBlockResponse implement
      */
     @Override
     public void complete() throws SQLException {
-        if ((this.pos + 1) != this.data.length) {
-            throw new SQLException("Inconsistent state detected! Current block capacity: " + this.data.length +
+        if ((this.pos + 1) != this.nullMappings.length) {
+            throw new SQLException("Inconsistent state detected! Current block capacity: " + this.nullMappings.length +
                     ", block usage: " + (this.pos + 1) + ". Did MonetDB send what it promised to?", "M0M10");
         }
     }
@@ -99,28 +134,109 @@ public class DataBlockResponse implement
     @Override
     public void close() {
         // feed all rows to the garbage collector
-        for (int i = 0; i < data.length; i++) {
-            for (int j = 0; j < data[0].length; j++) {
-                data[i][j] = null;
-            }
+        int numberOfColumns = this.data.length;
+        for (int i = 0; i < numberOfColumns; i++) {
             data[i] = null;
+            nullMappings[i] = null;
+        }
+        data = null;
+        nullMappings = null;
+    }
+
+    /* Methods to be called after the block construction has been completed */
+
+    void setBlockLine(int blockLine) {
+        this.blockLine = blockLine;
+    }
+
+    public void setData(Object[] data) { /* For VirtualResultSet :( */
+        this.data = data;
+    }
+
+    public Object[] getData() { /* For VirtualResultSet :( */
+        return data;
+    }
+
+    public boolean checkValueIsNull(int column) {
+        return this.nullMappings[this.blockLine][column];
+    }
+
+    public boolean getBooleanValue(int column) {
+        return ((boolean[]) this.data[column])[this.blockLine];
+    }
+
+    public byte getByteValue(int column) {
+        return ((byte[]) this.data[column])[this.blockLine];
+    }
+
+    public short getShortValue(int column) {
+        return ((short[]) this.data[column])[this.blockLine];
+    }
+
+    public int getIntValue(int column) {
+        return ((int[]) this.data[column])[this.blockLine];
+    }
+
+    public long getLongValue(int column) {
+        return ((long[]) this.data[column])[this.blockLine];
+    }
+
+    public float getFloatValue(int column) {
+        return ((float[]) this.data[column])[this.blockLine];
+    }
+
+    public double getDoubleValue(int column) {
+        return ((double[]) this.data[column])[this.blockLine];
+    }
+
+    public Object getObjectValue(int column) {
+        return ((Object[]) this.data[column])[this.blockLine];
+    }
+
+    public String getValueAsString(int column) {
+        switch (this.jdbcSQLTypes[column]) {
+            case Types.BOOLEAN:
+                return Boolean.toString(((boolean[]) this.data[column])[this.blockLine]);
+            case Types.TINYINT:
+                return Byte.toString(((byte[]) this.data[column])[this.blockLine]);
+            case Types.SMALLINT:
+                return Short.toString(((short[]) this.data[column])[this.blockLine]);
+            case Types.INTEGER:
+                return Integer.toString(((int[]) this.data[column])[this.blockLine]);
+            case Types.BIGINT:
+                return Long.toString(((long[]) this.data[column])[this.blockLine]);
+            case Types.REAL:
+                return Float.toString(((float[]) this.data[column])[this.blockLine]);
+            case Types.DOUBLE:
+                return Double.toString(((double[]) this.data[column])[this.blockLine]);
+            case Types.CHAR:
+            case Types.VARCHAR:
+            case Types.CLOB:
+            case Types.OTHER:
+                return (String) ((Object[]) this.data[column])[this.blockLine];
+            default:
+                return ((Object[]) this.data[column])[this.blockLine].toString();
         }
     }
 
-    /**
-     * Retrieves the required row. Warning: if the requested rows is out of bounds, an IndexOutOfBoundsException will
-     * be thrown.
-     *
-     * @param line the row to retrieve
-     * @return the requested row as String
-     */
-    Object[] getRow(int line) {
-        if (forwardOnly) {
-            Object[] ret = data[line];
-            data[line] = null;
-            return ret;
-        } else {
-            return data[line];
+    public Object getValueAsObject(int column) {
+        switch (this.jdbcSQLTypes[column]) {
+            case Types.BOOLEAN:
+                return ((boolean[]) this.data[column])[this.blockLine];
+            case Types.TINYINT:
+                return (((byte[]) this.data[column])[this.blockLine]);
+            case Types.SMALLINT:
+                return (((short[]) this.data[column])[this.blockLine]);
+            case Types.INTEGER:
+                return (((int[]) this.data[column])[this.blockLine]);
+            case Types.BIGINT:
+                return (((long[]) this.data[column])[this.blockLine]);
+            case Types.REAL:
+                return (((float[]) this.data[column])[this.blockLine]);
+            case Types.DOUBLE:
+                return (((double[]) this.data[column])[this.blockLine]);
+            default:
+                return ((Object[]) this.data[column])[this.blockLine];
         }
     }
 }
diff --git a/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java b/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java
@@ -25,7 +25,7 @@ import java.sql.Types;
  */
 public class ResultSetResponse implements IIncompleteResponse {
 
-    private static final byte IsSetFinalValue = 15;
+    private static final byte IS_SET_FINAL_VALUE = 15;
 
     /** The number of columns in this result */
     private final int columncount;
@@ -73,8 +73,7 @@ public class ResultSetResponse implement
      * @param tuplecount the total number of tuples in the result set
      * @param columncount the number of columns in the result set
      * @param rowcount the number of rows in the current block
-     * @param parent the parent that created this Response and will
-     *               supply new result blocks when necessary
+     * @param parent the parent that created this Response and will supply new result blocks when necessary
      * @param seq the query sequence number
      */
     public ResultSetResponse(MonetConnection con, MonetConnection.ResponseList parent, int id, int seq, int rowcount,
@@ -139,7 +138,7 @@ public class ResultSetResponse implement
      */
     @Override
     public boolean wantsMore() {
-        return this.isSet < IsSetFinalValue || resultBlocks[0].wantsMore();
+        return this.isSet < IS_SET_FINAL_VALUE || resultBlocks[0].wantsMore();
     }
 
     /**
@@ -205,6 +204,11 @@ public class ResultSetResponse implement
         return type;
     }
 
+    /**
+     * Returns the JDBC types of the columns
+     *
+     * @return the JDBC types of the columns
+     */
     public int[] getJdbcSQLTypes() {
         return JdbcSQLTypes;
     }
@@ -272,7 +276,7 @@ public class ResultSetResponse implement
      */
     @Override
     public void addLine(ServerResponses response, Object line) throws ProtocolException {
-        if (this.isSet >= IsSetFinalValue) {
+        if (this.isSet >= IS_SET_FINAL_VALUE) {
             this.resultBlocks[0].addLine(response, line);
         } else if (response != ServerResponses.HEADER) {
             throw new ProtocolException("header expected, got: " + response.toString());
@@ -307,7 +311,7 @@ public class ResultSetResponse implement
      * @return the exact row read as requested or null if the requested row is out of the scope of the result set
      * @throws SQLException if an database error occurs
      */
-    public Object[] getLine(int row) throws SQLException {
+    public DataBlockResponse getDataBlockCorrespondingToLine(int row) throws SQLException {
         if (row >= tuplecount || row < 0)
             return null;
 
@@ -355,7 +359,8 @@ public class ResultSetResponse implement
                 throw new AssertionError("block " + block + " should have been fetched by now :(");
             }
         }
-        return rawr.getRow(blockLine);
+        rawr.setBlockLine(blockLine);
+        return rawr;
     }
 
     /**