changeset 80:0ae34196c54e embedded

Started the embedded connection on the JDBC part. Mostly done by now.
author Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
date Thu, 15 Dec 2016 16:11:58 +0100 (2016-12-15)
parents 17365ed26611
children a3c686217ca1
files src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java src/main/java/nl/cwi/monetdb/mcl/connection/embedded/EmbeddedConnection.java src/main/java/nl/cwi/monetdb/mcl/connection/embedded/EmbeddedLanguage.java src/main/java/nl/cwi/monetdb/mcl/connection/embedded/JDBCEmbeddedConnection.java src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java src/main/java/nl/cwi/monetdb/mcl/protocol/StarterHeaders.java src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiProtocol.java src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java src/main/java/nl/cwi/monetdb/mcl/responses/IIncompleteResponse.java src/main/java/nl/cwi/monetdb/mcl/responses/ResultSetResponse.java
diffstat 14 files changed, 252 insertions(+), 144 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java
@@ -30,7 +30,7 @@ public class MonetDBEmbeddedConnection {
 
 	protected MonetDBEmbeddedConnection(long connectionPointer) { this.connectionPointer = connectionPointer; }
 
-    public long getConnectionPointer() { return connectionPointer; }
+    long getConnectionPointer() { return connectionPointer; }
 
     /**
      * Gets the current schema set on the connection.
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
@@ -1613,7 +1613,7 @@ public abstract class MonetConnection ex
                                 while (iter.wantsMore()) {
                                     try {
                                         protocol.fetchNextResponseData();
-                                        iter.addLine(protocol.getCurrentServerResponseHeader(), protocol.getCurrentData());
+                                        iter.addLines(protocol);
                                     } catch (ProtocolException ex) {
                                         // right, some protocol violation, skip the rest of the result
                                         error = "M0M10!" + ex.getMessage();
@@ -1628,8 +1628,8 @@ public abstract class MonetConnection ex
                                 break;
                             }
 
-                            // it is of no use to store DataBlockResponses, you never want to
-                            // retrieve them directly anyway
+                            // it is of no use to store DataBlockResponses, you never want to retrieve them directly
+                            // anyway
                             if (!(res instanceof DataBlockResponse)) {
                                 responses.add(res);
                             }
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/embedded/EmbeddedConnection.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/embedded/EmbeddedConnection.java
@@ -7,6 +7,7 @@ import nl.cwi.monetdb.jdbc.MonetConnecti
 import nl.cwi.monetdb.mcl.connection.ControlCommands;
 import nl.cwi.monetdb.mcl.connection.MCLException;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
+import nl.cwi.monetdb.mcl.protocol.ServerResponses;
 import nl.cwi.monetdb.mcl.protocol.embedded.EmbeddedProtocol;
 
 import java.io.*;
@@ -79,5 +80,26 @@ public final class EmbeddedConnection ex
 
     @Override
     public void sendControlCommand(ControlCommands con, int data) throws SQLException {
+        try {
+            switch (con) {
+                case AUTO_COMMIT:
+                    ((EmbeddedProtocol)protocol).sendAutocommitCommand(data);
+                    break;
+                case REPLY_SIZE:
+                    ((EmbeddedProtocol)protocol).sendReplySizeCommand(data);
+                    break;
+                case RELEASE:
+                    ((EmbeddedProtocol)protocol).sendReleaseCommand(data);
+                    break;
+                case CLOSE:
+                    ((EmbeddedProtocol)protocol).sendCloseCommand(data);
+            }
+            protocol.waitUntilPrompt();
+            if (protocol.getCurrentServerResponseHeader() == ServerResponses.ERROR) {
+                throw new SQLException(protocol.getRemainingStringLine(0));
+            }
+        } catch (IOException | ProtocolException ex) {
+            throw new SQLException(ex);
+        }
     }
 }
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/embedded/EmbeddedLanguage.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/embedded/EmbeddedLanguage.java
@@ -8,7 +8,7 @@ import nl.cwi.monetdb.mcl.connection.IMo
 public enum EmbeddedLanguage implements IMonetDBLanguage {
 
     /** the SQL language */
-    LANG_SQL(new String[]{"", "\n;", "\n;\n"}, "sql"),
+    LANG_SQL(null, "sql"),
     /** an unknown language */
     LANG_UNKNOWN(null, "unknown");
 
--- a/src/main/java/nl/cwi/monetdb/mcl/connection/embedded/JDBCEmbeddedConnection.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/connection/embedded/JDBCEmbeddedConnection.java
@@ -1,13 +1,100 @@
 package nl.cwi.monetdb.mcl.connection.embedded;
 
 import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedConnection;
+import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedException;
+import nl.cwi.monetdb.mcl.protocol.ServerResponses;
+import nl.cwi.monetdb.mcl.protocol.StarterHeaders;
+import nl.cwi.monetdb.mcl.protocol.TableResultHeaders;
+import nl.cwi.monetdb.mcl.responses.IResponse;
 
 /**
  * Created by ferreira on 12/1/16.
  */
 public class JDBCEmbeddedConnection extends MonetDBEmbeddedConnection {
 
+    private long lastResultSetPointer;
+
+    private final ServerResponses[] lineResponse = new ServerResponses[8];
+
+    private int currentLineResponseState;
+
+    private StarterHeaders serverHeaderResponse;
+
+    private final int[] lastServerResponseParameters = new int[4]; //for ResultSetResponse and DataBlockResponse
+
+    private IResponse lastServerResponse; //for Update and Autocommit
+
+    private String lastError;
+
     protected JDBCEmbeddedConnection(long connectionPointer) {
         super(connectionPointer);
     }
+
+    public ServerResponses getNextServerResponse() {
+        return lineResponse[currentLineResponseState++];
+    }
+
+    public StarterHeaders getServerHeaderResponse() {
+        return serverHeaderResponse;
+    }
+
+    public int[] getLastServerResponseParameters() {
+        return lastServerResponseParameters;
+    }
+
+    public IResponse getLastServerResponse() {
+        return lastServerResponse;
+    }
+
+    public TableResultHeaders fillTableHeaders(String[] columnNames, int[] columnLengths, String[] types,
+                                               String[] tableNames) throws MonetDBEmbeddedException {
+        this.getNextTableHeader(this.connectionPointer, this.lastResultSetPointer, columnNames, columnLengths,
+                types, tableNames);
+        return TableResultHeaders.TABLE;
+    }
+
+    public int parseTupleLines(int[] typesMap, Object[] values, boolean[][] nulls) throws MonetDBEmbeddedException {
+        return this.parseTupleLines(this.connectionPointer, this.lastResultSetPointer, typesMap, values, nulls);
+    }
+
+    public String getLastError() {
+        return lastError;
+    }
+
+    public void processNextQuery(String query) throws MonetDBEmbeddedException {
+        if (!query.endsWith(";")) {
+            query += ";";
+        }
+        this.sendQueryInternal(this.connectionPointer, query, true);
+    }
+
+    public void sendAutocommitCommand(int flag) throws MonetDBEmbeddedException { //1 or 0
+        this.sendAutocommitCommandInternal(this.connectionPointer, flag);
+    }
+
+    public void sendReleaseCommand(int commandId) throws MonetDBEmbeddedException {
+        this.sendReleaseCommandInternal(this.connectionPointer, commandId);
+    }
+
+    public void sendCloseCommand(int commandId) throws MonetDBEmbeddedException {
+        this.sendCloseCommandInternal(this.connectionPointer, commandId);
+    }
+
+    private native void getNextTableHeader(long connectionPointer, long resultSetPointer, String[] columnNames,
+                                           int[] columnLengths, String[] types, String[] tableNames)
+            throws MonetDBEmbeddedException;
+
+    private native int parseTupleLines(long connectionPointer, long resultSetPointer, int[] typesMap, Object[] values,
+                                       boolean[][] nulls) throws MonetDBEmbeddedException;
+
+    private native void sendQueryInternal(long connectionPointer, String query, boolean execute)
+            throws MonetDBEmbeddedException;
+
+    private native void sendAutocommitCommandInternal(long connectionPointer, int flag)
+            throws MonetDBEmbeddedException;
+
+    private native void sendReleaseCommandInternal(long connectionPointer, int commandId)
+            throws MonetDBEmbeddedException;
+
+    private native void sendCloseCommandInternal(long connectionPointer, int commandId) throws MonetDBEmbeddedException;
 }
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/AbstractProtocol.java
@@ -15,17 +15,11 @@ import java.util.Map;
  */
 public abstract class AbstractProtocol {
 
-    protected ServerResponses currentServerResponseHeader = ServerResponses.UNKNOWN;
-
-    public abstract ServerResponses waitUntilPrompt() throws IOException;
+    public abstract void waitUntilPrompt() throws IOException;
 
     public abstract void fetchNextResponseData() throws IOException; //UPDATE currentData!!!
 
-    public ServerResponses getCurrentServerResponseHeader() {
-        return currentServerResponseHeader;
-    }
-
-    public abstract Object getCurrentData();
+    public abstract ServerResponses getCurrentServerResponseHeader();
 
     public abstract StarterHeaders getNextStarterHeader();
 
@@ -43,11 +37,11 @@ public abstract class AbstractProtocol {
     public abstract DataBlockResponse getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses)
             throws ProtocolException;
 
-    public abstract TableResultHeaders getNextTableHeader(Object line, String[] stringValues, int[] intValues)
-            throws ProtocolException;
+    public abstract TableResultHeaders getNextTableHeader(String[] columnNames, int[] columnLengths, String[] types,
+                                                          String[] tableNames) throws ProtocolException;
 
-    public abstract int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] values, boolean[] nulls)
-            throws ProtocolException;
+    public abstract int parseTupleLines(int firstLineNumber, int[] typesMap, Object[] values,
+                                        boolean[][] nulls) throws ProtocolException;
 
     public abstract String getRemainingStringLine(int startIndex);
 
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/StarterHeaders.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/StarterHeaders.java
@@ -17,8 +17,8 @@ public enum StarterHeaders {
     Q_SCHEMA,
     /** A response to a transaction statement (start, rollback, abort, commit) */
     Q_TRANS,
-    /** A tabular response in response to a PREPARE statement containing
-     * information about the wildcard values that need to be supplied */
+    /** A tabular response in response to a PREPARE statement containing information about the wildcard values that
+     * need to be supplied */
     Q_PREPARE,
     /** A tabular continuation response (for a ResultSet) */
     Q_BLOCK,
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/embedded/EmbeddedProtocol.java
@@ -1,5 +1,6 @@
 package nl.cwi.monetdb.mcl.protocol.embedded;
 
+import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedException;
 import nl.cwi.monetdb.jdbc.MonetConnection;
 import nl.cwi.monetdb.mcl.connection.embedded.JDBCEmbeddedConnection;
 import nl.cwi.monetdb.mcl.protocol.*;
@@ -27,62 +28,114 @@ public class EmbeddedProtocol extends Ab
     }
 
     @Override
-    public ServerResponses waitUntilPrompt() throws IOException {
-        return null;
+    public ServerResponses getCurrentServerResponseHeader() {
+        return connection.getNextServerResponse();
     }
 
     @Override
-    public void fetchNextResponseData() throws IOException {
-
-    }
+    public void waitUntilPrompt() throws IOException {} //Nothing really :)
 
     @Override
-    public Object getCurrentData() {
-        return new Object[0];
-    }
+    public void fetchNextResponseData() throws IOException {} //Nothing really :)
 
     @Override
     public StarterHeaders getNextStarterHeader() {
-        return null;
+        return connection.getServerHeaderResponse();
     }
 
     @Override
     public ResultSetResponse getNextResultSetResponse(MonetConnection con, MonetConnection.ResponseList list, int seqnr) throws ProtocolException {
-        return null;
+        int[] array = connection.getLastServerResponseParameters();
+        int id = array[0]; //The order cannot be switched!!
+        int tuplecount = array[1];
+        int columncount = array[2];
+        int rowcount = array[3];
+        return new ResultSetResponse(con, list, seqnr, id, rowcount, tuplecount, columncount);
     }
 
     @Override
     public UpdateResponse getNextUpdateResponse() throws ProtocolException {
-        return null;
+        return (UpdateResponse) connection.getLastServerResponse();
     }
 
     @Override
     public AutoCommitResponse getNextAutoCommitResponse() throws ProtocolException {
-        return null;
+        return (AutoCommitResponse) connection.getLastServerResponse();
     }
 
     @Override
     public DataBlockResponse getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses) throws ProtocolException {
-        return null;
+        int[] array = connection.getLastServerResponseParameters();
+        int id = array[0]; //The order cannot be switched!!
+        int columncount = array[1];
+        int rowcount = array[2];
+        int offset = array[3];
+
+        ResultSetResponse rs = rsresponses.get(id);
+        if (rs == null) {
+            return null;
+        }
+        return rs.addDataBlockResponse(offset, rowcount, columncount, this);
     }
 
     @Override
-    public TableResultHeaders getNextTableHeader(Object line, String[] stringValues, int[] intValues) throws ProtocolException {
-        return null;
+    public TableResultHeaders getNextTableHeader(String[] columnNames, int[] columnLengths, String[] types,
+                                                 String[] tableNames) throws ProtocolException {
+        try {
+            return connection.fillTableHeaders(columnNames, columnLengths, types, tableNames);
+        } catch (MonetDBEmbeddedException ex) {
+            throw new ProtocolException(ex.getMessage());
+        }
     }
 
     @Override
-    public int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] values, boolean[] nulls) throws ProtocolException {
-        return 0;
+    public int parseTupleLines(int lineNumber, int[] typesMap, Object[] values, boolean[][] nulls) throws ProtocolException {
+        try {
+            return connection.parseTupleLines(typesMap, values, nulls);
+        } catch (MonetDBEmbeddedException ex) {
+            throw new ProtocolException(ex.getMessage());
+        }
     }
 
     @Override
     public String getRemainingStringLine(int startIndex) {
-        return null;
+        return connection.getLastError();
     }
 
     @Override
     public void writeNextQuery(String prefix, String query, String suffix) throws IOException {
+        try {
+            connection.processNextQuery(query);
+        } catch (MonetDBEmbeddedException ex) {
+            throw new IOException(ex.getMessage());
+        }
+    }
 
+    public void sendAutocommitCommand(int flag) throws ProtocolException { //1 or 0
+        try {
+            connection.sendAutocommitCommand(flag);
+        } catch (MonetDBEmbeddedException ex) {
+            throw new ProtocolException(ex.getMessage());
+        }
+    }
+
+    public void sendReplySizeCommand(int size) throws ProtocolException {
+        //do nothing for now :)
+    }
+
+    public void sendReleaseCommand(int commandId) throws ProtocolException {
+        try {
+            connection.sendReleaseCommand(commandId);
+        } catch (MonetDBEmbeddedException ex) {
+            throw new ProtocolException(ex.getMessage());
+        }
+    }
+
+    public void sendCloseCommand(int commandId) throws ProtocolException {
+        try {
+            connection.sendCloseCommand(commandId);
+        } catch (MonetDBEmbeddedException ex) {
+            throw new ProtocolException(ex.getMessage());
+        }
     }
 }
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/newmapi/NewMapiProtocol.java
@@ -16,21 +16,21 @@ import java.util.Map;
 public class NewMapiProtocol extends AbstractProtocol {
 
     @Override
-    public ServerResponses waitUntilPrompt() throws IOException {
+    public ServerResponses getCurrentServerResponseHeader() {
         return null;
     }
 
     @Override
+    public void waitUntilPrompt() throws IOException {
+
+    }
+
+    @Override
     public void fetchNextResponseData() throws IOException {
 
     }
 
     @Override
-    public Object getCurrentData() {
-        return new Object[0];
-    }
-
-    @Override
     public StarterHeaders getNextStarterHeader() {
         return null;
     }
@@ -56,12 +56,12 @@ public class NewMapiProtocol extends Abs
     }
 
     @Override
-    public TableResultHeaders getNextTableHeader(Object line, String[] stringValues, int[] intValues) throws ProtocolException {
+    public TableResultHeaders getNextTableHeader(String[] columnNames, int[] columnLengths, String[] types, String[] tableNames) throws ProtocolException {
         return null;
     }
 
     @Override
-    public int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] values, boolean[] nulls) throws ProtocolException {
+    public int parseTupleLines(int lineNumber, int[] typesMap, Object[] values, boolean[][] nulls) throws ProtocolException {
         return 0;
     }
 
--- 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,8 @@ import java.util.Map;
  */
 public class OldMapiProtocol extends AbstractProtocol {
 
+    private ServerResponses currentServerResponseHeader = ServerResponses.UNKNOWN;
+
     private final OldMapiSocket socket;
 
     CharBuffer lineBuffer;
@@ -38,7 +40,12 @@ public class OldMapiProtocol extends Abs
     }
 
     @Override
-    public ServerResponses waitUntilPrompt() throws IOException {
+    public ServerResponses getCurrentServerResponseHeader() {
+        return currentServerResponseHeader;
+    }
+
+    @Override
+    public void waitUntilPrompt() throws IOException {
         while(this.currentServerResponseHeader != ServerResponses.PROMPT) {
             this.lineBuffer = this.socket.readLine(this.lineBuffer);
             if(this.lineBuffer.limit() == 0) {
@@ -50,7 +57,6 @@ public class OldMapiProtocol extends Abs
                 this.lineBuffer.position(1);
             }
         }
-        return this.currentServerResponseHeader;
     }
 
     @Override
@@ -71,11 +77,6 @@ public class OldMapiProtocol extends Abs
     }
 
     @Override
-    public CharBuffer getCurrentData() {
-        return this.lineBuffer;
-    }
-
-    @Override
     public StarterHeaders getNextStarterHeader() {
         StarterHeaders res = OldMapiStartOfHeaderParser.GetNextStartHeaderOnOldMapi(this);
         this.lineBuffer.position(this.lineBuffer.position() + 1);
@@ -108,7 +109,7 @@ public class OldMapiProtocol extends Abs
     @Override
     public DataBlockResponse getNextDatablockResponse(Map<Integer, ResultSetResponse> rsresponses)
             throws ProtocolException {
-        int id = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this);
+        int id = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this); //The order cannot be switched!!
         int columncount = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this);
         int rowcount = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this);
         int offset = OldMapiStartOfHeaderParser.GetNextResponseDataAsInt(this);
@@ -121,16 +122,16 @@ public class OldMapiProtocol extends Abs
     }
 
     @Override
-    public TableResultHeaders getNextTableHeader(Object line, String[] stringValues, int[] intValues)
-            throws ProtocolException {
-        return OldMapiTableHeaderParser.GetNextTableHeader((CharBuffer) line, stringValues, intValues);
+    public TableResultHeaders getNextTableHeader(String[] columnNames, int[] columnLengths, String[] types, String[] tableNames) throws ProtocolException {
+        return OldMapiTableHeaderParser.GetNextTableHeader(this.lineBuffer, columnNames, columnLengths, types, tableNames);
     }
 
     @Override
-    public int parseTupleLine(int lineNumber, Object line, int[] typesMap, Object[] data, boolean[] nulls)
+    public int parseTupleLines(int firstLineNumber, int[] typesMap, Object[] data, boolean[][] nulls)
             throws ProtocolException {
-        return OldMapiTupleLineParser.OldMapiParseTupleLine(lineNumber, (CharBuffer) line,
-                this.tupleLineBuilder, typesMap, data, nulls);
+        OldMapiTupleLineParser.OldMapiParseTupleLine(firstLineNumber, this.lineBuffer,
+                this.tupleLineBuilder, typesMap, data, nulls[firstLineNumber]);
+        return firstLineNumber;
     }
 
     @Override
--- a/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/protocol/oldmapi/OldMapiTableHeaderParser.java
@@ -10,8 +10,8 @@ import java.nio.CharBuffer;
  */
 final class OldMapiTableHeaderParser {
 
-    static TableResultHeaders GetNextTableHeader(CharBuffer lineBuffer, String[] stringValues, int[] intValues)
-            throws ProtocolException {
+    static TableResultHeaders GetNextTableHeader(CharBuffer lineBuffer, String[] columnNames, int[] columnLengths,
+                                                 String[] types, String[] tableNames) throws ProtocolException {
         TableResultHeaders res = TableResultHeaders.UNKNOWN;
         int currentLength = lineBuffer.limit();
         char[] array = lineBuffer.array();
@@ -51,22 +51,22 @@ final class OldMapiTableHeaderParser {
         switch (array[pos]) {
             case 'n': //name
                 if (currentLength - pos == 4) {
-                    GetStringValues(array, pos - 3, stringValues);
+                    GetStringValues(array, pos - 3, columnNames);
                     res = TableResultHeaders.NAME;
                 }
                 break;
             case 'l': //length
                 if (currentLength - pos == 6) {
-                    GetIntValues(array, pos - 3, intValues);
+                    GetIntValues(array, pos - 3, columnLengths);
                     res = TableResultHeaders.LENGTH;
                 }
                 break;
             case 't':
                 if (currentLength - pos == 4) { //type
-                    GetStringValues(array, pos - 3, stringValues);
+                    GetStringValues(array, pos - 3, types);
                     res = TableResultHeaders.TYPE;
                 } else if (currentLength - pos == 10) { //table_name
-                    GetStringValues(array, pos - 3, stringValues);
+                    GetStringValues(array, pos - 3, tableNames);
                     res = TableResultHeaders.TABLE;
                 }
                 break;
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java
@@ -4,7 +4,6 @@ import nl.cwi.monetdb.mcl.protocol.Abstr
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
 import nl.cwi.monetdb.mcl.protocol.ServerResponses;
 
-import java.sql.SQLException;
 import java.sql.Types;
 
 /**
@@ -44,9 +43,8 @@ public class DataBlockResponse implement
      *
      * @param rowcount the number of rows
      * @param columncount the number of columns
-     * @param forward whether this is a forward only result
      */
-    DataBlockResponse(int rowcount, int columncount, boolean forward, AbstractProtocol protocol, int[] JdbcSQLTypes) {
+    DataBlockResponse(int rowcount, int columncount, AbstractProtocol protocol, int[] JdbcSQLTypes) {
         this.pos = -1;
         this.data = new Object[columncount];
         this.nullMappings = new boolean[rowcount][columncount];
@@ -58,14 +56,15 @@ public class DataBlockResponse implement
      * addLine adds a String of data to this object's data array. Note that an IndexOutOfBoundsException can be thrown
      * when an attempt is made to add more than the original construction size specified.
      *
-     * @param line the header line as String
-     * @param response the line type according to the MAPI protocol
+     * @param protocol The connection's protocol
      * @throws ProtocolException If the result line is not expected
      */
     @Override
-    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());
+    public void addLines(AbstractProtocol protocol) throws ProtocolException {
+        if (protocol.getCurrentServerResponseHeader() != ServerResponses.RESULT) {
+            throw new ProtocolException("protocol violation: unexpected line in data block: " +
+                    protocol.getRemainingStringLine(0));
+        }
 
         if(this.pos == -1) { //if it's the first line, initialize the matrix
             int numberOfColumns = this.data.length, numberOfRows = this.nullMappings.length;
@@ -99,8 +98,8 @@ public class DataBlockResponse implement
         }
 
         // add to the backing array
-        int nextPos = ++this.pos;
-        this.protocol.parseTupleLine(nextPos, line, this.jdbcSQLTypes, this.data, this.nullMappings[nextPos]);
+        int nextPos = this.pos + 1;
+        this.pos = this.protocol.parseTupleLines(nextPos, this.jdbcSQLTypes, this.data, this.nullMappings);
     }
 
     /**
@@ -115,20 +114,6 @@ public class DataBlockResponse implement
     }
 
     /**
-     * Indicates that no more header lines will be added to this Response implementation. In most cases this is a
-     * redundant operation because the data array is full. However... it can happen that this is NOT the case!
-     *
-     * @throws SQLException if not all rows are filled
-     */
-    @Override
-    public void complete() throws SQLException {
-        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");
-        }
-    }
-
-    /**
      * Instructs the Response implementation to close and do the necessary clean up procedures.
      */
     @Override
--- a/src/main/java/nl/cwi/monetdb/mcl/responses/IIncompleteResponse.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/responses/IIncompleteResponse.java
@@ -1,30 +1,18 @@
 package nl.cwi.monetdb.mcl.responses;
 
+import nl.cwi.monetdb.mcl.protocol.AbstractProtocol;
 import nl.cwi.monetdb.mcl.protocol.ProtocolException;
-import nl.cwi.monetdb.mcl.protocol.ServerResponses;
-
-import java.sql.SQLException;
 
 /**
- * Created by ferreira on 12/5/16.
+ * Created by ferreira on 12/15/16.
  */
 public interface IIncompleteResponse extends IResponse {
     /**
-     * Returns whether this Response expects more lines to be added
-     * to it.
+     * Returns whether this Response expects more lines to be added to it.
      *
      * @return true if a next line should be added, false otherwise
      */
     boolean wantsMore();
 
-    /**
-     * Indicates that no more header lines will be added to this
-     * Response implementation.
-     *
-     * @throws SQLException if the contents of the Response is not
-     *         consistent or sufficient.
-     */
-    void complete() throws SQLException;
-
-    void addLine(ServerResponses response, Object line) throws ProtocolException;
+    void addLines(AbstractProtocol protocol) throws ProtocolException;
 }
--- 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 IS_SET_FINAL_VALUE = 15;
+    private static final byte IS_SET_FINAL_VALUE = 4;
 
     /** The number of columns in this result */
     private final int columncount;
@@ -113,14 +113,13 @@ public class ResultSetResponse implement
         this.JdbcSQLTypes = new int[this.columncount];
 
         this.resultBlocks = new DataBlockResponse[(tuplecount / cacheSize) + 1];
-        this.resultBlocks[0] = new DataBlockResponse(rowcount, columncount,
-                parent.getRstype() == ResultSet.TYPE_FORWARD_ONLY, con.getProtocol(), this.JdbcSQLTypes);
+        this.resultBlocks[0] = new DataBlockResponse(rowcount, columncount, con.getProtocol(), this.JdbcSQLTypes);
     }
 
     /**
-     * Internal utility method to fill the JdbcSQLTypes array with derivable values.
-     * By doing it once (in the constructor) we can avoid doing this in many getXyz() methods again and again
-     * thereby improving getXyz() method performance.
+     * Internal utility method to fill the JdbcSQLTypes array with derivable values. By doing it once (in the
+     * constructor) we can avoid doing this in many getXyz() methods again and again thereby improving getXyz() method
+     * performance.
      */
     private void populateJdbcSQLTypesArray() {
         for (int i = 0; i < this.type.length; i++) {
@@ -136,7 +135,6 @@ public class ResultSetResponse implement
      * Returns whether this ResultSetResponse needs more lines. This method returns true if not all headers are set,
      * or the first DataBlockResponse reports to want more.
      */
-    @Override
     public boolean wantsMore() {
         return this.isSet < IS_SET_FINAL_VALUE || resultBlocks[0].wantsMore();
     }
@@ -148,28 +146,11 @@ public class ResultSetResponse implement
      */
     public DataBlockResponse addDataBlockResponse(int offset, int rowcount, int columncount, AbstractProtocol proto) {
         int block = (offset - blockOffset) / cacheSize;
-        DataBlockResponse res = new DataBlockResponse(rowcount, columncount,
-                parent.getRstype() == ResultSet.TYPE_FORWARD_ONLY, proto, JdbcSQLTypes);
+        DataBlockResponse res = new DataBlockResponse(rowcount, columncount, proto, JdbcSQLTypes);
         resultBlocks[block] = res;
         return res;
     }
 
-    /**
-     * Marks this Response as being completed.  A complete Response needs to be consistent with regard to its internal
-     * data.
-     *
-     * @throws SQLException if the data currently in this Response is not sufficient to be consistent
-     */
-    @Override
-    public void complete() throws SQLException {
-        String error = "";
-        if ((isSet & 1) == 0) error += "name header missing\n";
-        if ((isSet & 2) == 0) error += "column width header missing\n";
-        if ((isSet & 4) == 0) error += "table name header missing\n";
-        if ((isSet & 8) == 0) error += "type header missing\n";
-        if (!error.equals("")) throw new SQLException(error, "M0M10");
-    }
-
     public int getId() {
         return id;
     }
@@ -271,32 +252,29 @@ public class ResultSetResponse implement
      * Parses the given string and changes the value of the matching header appropriately, or passes it on to the
      * underlying DataResponse.
      *
-     * @param line the string that contains the header
+     * @param protocol the connection's protocol
      * @throws ProtocolException if has a wrong header
      */
     @Override
-    public void addLine(ServerResponses response, Object line) throws ProtocolException {
+    public void addLines(AbstractProtocol protocol) throws ProtocolException {
         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());
+            this.resultBlocks[0].addLines(protocol);
+        } else if (protocol.getCurrentServerResponseHeader() != ServerResponses.HEADER) {
+            throw new ProtocolException("header expected, got: " + protocol.getRemainingStringLine(0));
         } else {
-            //we will always pass the tableNames pointer
-            switch (con.getProtocol().getNextTableHeader(line, this.tableNames, this.columnLengths)) {
+            switch (con.getProtocol().getNextTableHeader(this.name, this.columnLengths, this.type, this.tableNames)) {
                 case NAME:
-                    System.arraycopy(this.tableNames, 0, this.name, 0, this.columncount);
-                    isSet |= 1;
+                    isSet = 1;
                     break;
                 case LENGTH:
-                    isSet |= 2;
+                    isSet = 2;
                     break;
                 case TYPE:
-                    System.arraycopy(this.tableNames, 0, this.type, 0, this.columncount);
-                    this.populateJdbcSQLTypesArray(); //VERY IMPORTANT!
-                    isSet |= 4;
+                    isSet = 3;
                     break;
                 case TABLE:
-                    isSet |= 8;
+                    isSet = 4;
+                    this.populateJdbcSQLTypesArray(); //VERY IMPORTANT!
                     break;
             }
         }