Repository: neo4j-contrib/neo4j-jdbc
Pull request #120 (2018-01-02 13:40:57)

issue #46 - refactored classes to add debug feature


Patch:
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jCallableStatement.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jCallableStatement.java
index f5828174..3b96111d 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jCallableStatement.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jCallableStatement.java
@@ -20,10 +20,32 @@
 package org.neo4j.jdbc.bolt;
 
 import org.neo4j.jdbc.Neo4jCallableStatement;
+import org.neo4j.jdbc.Neo4jConnection;
+
+import java.sql.ParameterMetaData;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
 
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
 class BoltNeo4jCallableStatement extends Neo4jCallableStatement {
+	/**
+	 * Default constructor with connection and statement.
+	 *
+	 * @param connection   The JDBC connection
+	 * @param rawStatement The prepared statement
+	 */
+	protected BoltNeo4jCallableStatement(Neo4jConnection connection, String rawStatement) {
+		super(connection, rawStatement);
+	}
+
+	@Override public ResultSetMetaData getMetaData() throws SQLException {
+		return null;
+	}
+
+	@Override public ParameterMetaData getParameterMetaData() throws SQLException {
+		return null;
+	}
 }
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jConnection.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jConnection.java
index de9ef862..9236f791 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jConnection.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jConnection.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (c) 2016 LARUS Business Automation [http://www.larus-ba.it]
  * <p>
  * This file is part of the "LARUS Integration Framework for Neo4j".
@@ -15,240 +15,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * <p>
- * Created on 17/02/16
+ * Created on 22/12/17
  */
 package org.neo4j.jdbc.bolt;
 
 import org.neo4j.driver.v1.Session;
 import org.neo4j.driver.v1.Transaction;
-import org.neo4j.jdbc.*;
-import org.neo4j.jdbc.utils.TimeLimitedCodeBlock;
 
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
+import java.sql.Connection;
 
 /**
- * @author AgileLARUS
- * @since 3.0.0
+ * @author Gianmarco Laggia @ Larus B.A.
+ * @since 3.2.0
  */
-public class BoltNeo4jConnection extends Neo4jConnection implements Loggable {
-
-	private Session     session;
-	private Transaction transaction;
-	private boolean autoCommit = true;
-	private boolean loggable   = false;
-
-	/**
-	 * Constructor with Session and Properties.
-	 *
-	 * @param session    Bolt Session
-	 * @param properties Driver properties
-	 * @param url        Url used for this connection
-	 */
-	public BoltNeo4jConnection(Session session, Properties properties, String url) {
-		super(properties, url, BoltNeo4jResultSet.DEFAULT_HOLDABILITY);
-		this.session = session;
-	}
-
-	/**
-	 * Constructor with Session.
-	 *
-	 * @param session Bolt Session
-	 */
-	public BoltNeo4jConnection(Session session) {
-		this(session, new Properties(), "");
-	}
+public interface BoltNeo4jConnection extends Connection {
 
 	/**
 	 * Getter for transaction.
 	 *
 	 * @return the transaction
 	 */
-	public Transaction getTransaction() {
-		return this.transaction;
-	}
+	Transaction getTransaction();
 
 	/**
 	 * Getter for session.
 	 *
 	 * @return the internal session
 	 */
-	public Session getSession() {
-		return this.session;
-	}
-
-	@Override public Neo4jDatabaseMetaData getMetaData() throws SQLException {
-		return new BoltNeo4jDatabaseMetaData(this);
-	}
-
-	/*------------------------------*/
-	/*       Commit, rollback       */
-	/*------------------------------*/
-
-	@Override public void setAutoCommit(boolean autoCommit) throws SQLException {
-		if (this.autoCommit != autoCommit) {
-			if (this.transaction != null && !this.autoCommit) {
-				this.commit();
-				this.transaction.close();
-			}
-
-			if (this.autoCommit) {
-				//Simply restart the transaction
-				this.transaction = this.session.beginTransaction();
-			}
-
-			this.autoCommit = autoCommit;
-		}
-	}
-
-	@Override public boolean getAutoCommit() throws SQLException {
-		this.checkClosed();
-		return autoCommit;
-	}
-
-	@Override public void commit() throws SQLException {
-		this.checkClosed();
-		this.checkAutoCommit();
-		if (this.transaction == null) {
-			throw new SQLException("The transaction is null");
-		}
-		this.transaction.success();
-		this.transaction.close();
-		this.transaction = this.session.beginTransaction();
-	}
-
-	@Override public void rollback() throws SQLException {
-		this.checkClosed();
-		this.checkAutoCommit();
-		if (this.transaction == null) {
-			throw new SQLException("The transaction is null");
-		}
-		this.transaction.failure();
-	}
-
-	/*------------------------------*/
-	/*       Create Statement       */
-	/*------------------------------*/
-
-	@Override public Neo4jStatement createStatement() throws SQLException {
-		this.checkClosed();
-		if (this.transaction == null && !this.autoCommit) {
-			this.transaction = this.session.beginTransaction();
-		}
-		return InstanceFactory
-				.debug(BoltNeo4jStatement.class, new BoltNeo4jStatement(this, Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT),
-						this.isLoggable());
-	}
-
-	@Override public Neo4jStatement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
-		this.checkClosed();
-		this.checkTypeParams(resultSetType);
-		this.checkConcurrencyParams(resultSetConcurrency);
-		return InstanceFactory
-				.debug(BoltNeo4jStatement.class, new BoltNeo4jStatement(this, resultSetType, resultSetConcurrency, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT), this.isLoggable());
-	}
-
-	@Override public Neo4jStatement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
-		this.checkClosed();
-		this.checkTypeParams(resultSetType);
-		this.checkConcurrencyParams(resultSetConcurrency);
-		this.checkHoldabilityParams(resultSetHoldability);
-		return InstanceFactory
-				.debug(BoltNeo4jStatement.class, new BoltNeo4jStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability), this.isLoggable());
-	}
-
-	/*-------------------------------*/
-	/*       Prepare Statement       */
-	/*-------------------------------*/
-
-	@Override public PreparedStatement prepareStatement(String sql) throws SQLException {
-		this.checkClosed();
-		return InstanceFactory.debug(BoltNeo4jPreparedStatement.class,
-				new BoltNeo4jPreparedStatement(this, nativeSQL(sql), Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT),
-				this.isLoggable());
-	}
-
-	@Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
-		this.checkClosed();
-		this.checkTypeParams(resultSetType);
-		this.checkConcurrencyParams(resultSetConcurrency);
-		return InstanceFactory.debug(BoltNeo4jPreparedStatement.class,
-				new BoltNeo4jPreparedStatement(this, sql, resultSetType, resultSetConcurrency, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT), this.isLoggable());
-	}
-
-	@Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
-		this.checkClosed();
-		this.checkTypeParams(resultSetType);
-		this.checkConcurrencyParams(resultSetConcurrency);
-		this.checkHoldabilityParams(resultSetHoldability);
-		return InstanceFactory
-				.debug(BoltNeo4jPreparedStatement.class, new BoltNeo4jPreparedStatement(this, sql, resultSetType, resultSetConcurrency, resultSetHoldability),
-						this.isLoggable());
-	}
-
-	/*-------------------*/
-	/*       Close       */
-	/*-------------------*/
-
-	@Override public boolean isClosed() throws SQLException {
-		return !this.session.isOpen();
-	}
-
-	@Override public void close() throws SQLException {
-		try {
-			if (!this.isClosed()) {
-				session.close();
-			}
-		} catch (Exception e) {
-			throw new SQLException("A database access error has occurred: " + e.getMessage());
-		}
-	}
-
-	/*-------------------*/
-	/*      isValid      */
-	/*-------------------*/
-	@Override public boolean isValid(int timeout) throws SQLException {
-		if (timeout < 0) {
-			throw new SQLException("Timeout can't be less than zero");
-		}
-		if (this.isClosed()) {
-			return false;
-		}
-
-		Runnable r = new Runnable() {
-			@Override public void run() {
-				Session s = getSession();
-				Transaction tr = getTransaction();
-				if (tr != null && tr.isOpen()) {
-					tr.run(FASTEST_STATEMENT);
-				} else {
-					s.run(FASTEST_STATEMENT);
-				}
-			}
-		};
-
-		try {
-			TimeLimitedCodeBlock.runWithTimeout(r, timeout, TimeUnit.SECONDS);
-		}
-		catch (Exception e) { // also timeout
-			return false;
-		}
-
-		return true;
-	}
-
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
-
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
+	Session getSession();
 
 }
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDataSource.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDataSource.java
index 0ffaf0ce..1be2b8ac 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDataSource.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDataSource.java
@@ -26,9 +26,9 @@ import java.sql.DriverManager;
 import java.sql.SQLException;
 
 /**
- * @author AgileLARUS
+ * @author Gianmarco Laggia @ Larus B.A.
  *
- * @since 3.0.0
+ * @since 3.2.0
  */
 public class BoltNeo4jDataSource extends Neo4jDataSource {
 
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaData.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaData.java
index 681c268a..4a7e23fb 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaData.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaData.java
@@ -19,29 +19,40 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.List;
-
 import org.neo4j.driver.v1.Record;
 import org.neo4j.driver.v1.Session;
 import org.neo4j.driver.v1.StatementResult;
 import org.neo4j.jdbc.Neo4jDatabaseMetaData;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
 import org.neo4j.jdbc.metadata.Column;
 import org.neo4j.jdbc.metadata.Table;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
+
+import java.lang.reflect.Proxy;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Provides metadata
  *
- * @author AgileLARUS	
+ * @author AgileLARUS
  * @since 3.0.0
  */
-class BoltNeo4jDatabaseMetaData extends Neo4jDatabaseMetaData {
+public class BoltNeo4jDatabaseMetaData extends Neo4jDatabaseMetaData {
+
+	/**
+	 * Used for some extra logging (for example in the constructor)
+	 */
+	private static final Logger LOGGER = Logger.getLogger(BoltNeo4jDatabaseMetaData.class.getCanonicalName());
 
-	public BoltNeo4jDatabaseMetaData(BoltNeo4jConnection connection) {
+	public BoltNeo4jDatabaseMetaData(BoltNeo4jConnectionImpl connection) {
 		super(connection);
 
-		// compute database metadata: version, tables == labels, columns = properties (by label)   
+		// compute database metadata: version, tables == labels, columns = properties (by label)
 		if (connection != null) {
 			try {
 				BoltNeo4jConnection conn = (BoltNeo4jConnection) DriverManager.getConnection(connection.getUrl(), connection.getProperties());
@@ -51,10 +62,17 @@ class BoltNeo4jDatabaseMetaData extends Neo4jDatabaseMetaData {
 				getDatabaseProperties(session);
 				conn.close();
 			} catch (SQLException e) {
+				LOGGER.log(Level.SEVERE, e.getMessage(), e);
 			}
 		}
 	}
 
+	public static DatabaseMetaData newInstance(boolean debug, BoltNeo4jConnectionImpl connection) {
+		DatabaseMetaData dbmd = new BoltNeo4jDatabaseMetaData(connection);
+		return (DatabaseMetaData) Proxy.newProxyInstance(BoltNeo4jDatabaseMetaData.class.getClassLoader(), new Class[] { DatabaseMetaData.class },
+				new Neo4jInvocationHandler(dbmd, debug));
+	}
+
 	private void getDatabaseVersion(Session session) {
 		StatementResult rs = session.run("CALL dbms.components() yield name,versions WITH * WHERE name=\"Neo4j Kernel\" RETURN versions[0] AS version");
 		if (rs != null && rs.hasNext()) {
@@ -64,21 +82,22 @@ class BoltNeo4jDatabaseMetaData extends Neo4jDatabaseMetaData {
 			}
 		}
 	}
-	
+
 	private void getDatabaseLabels(Session session) {
 		StatementResult rs = session.run("CALL db.labels() yield label return label");
 		if (rs != null) {
 			while (rs.hasNext()) {
 				Record record = rs.next();
 				this.databaseLabels.add(new Table(record.get("label").asString()));
-		  }
+			}
 		}
 	}
-	
+
 	private void getDatabaseProperties(Session session) {
 		if (this.databaseLabels != null) {
 			for (Table databaseLabel : this.databaseLabels) {
-				StatementResult rs = session.run("MATCH (n:" + databaseLabel.getTableName() + ") WITH n LIMIT " + Neo4jDatabaseMetaData.PROPERTY_SAMPLE_SIZE + " UNWIND keys(n) as key RETURN collect(distinct key) as keys");
+				StatementResult rs = session.run("MATCH (n:" + databaseLabel.getTableName() + ") WITH n LIMIT " + Neo4jDatabaseMetaData.PROPERTY_SAMPLE_SIZE
+						+ " UNWIND keys(n) as key RETURN collect(distinct key) as keys");
 				if (rs != null) {
 					cycleResultSetToSetDatabaseProperties(rs, databaseLabel);
 				}
@@ -86,7 +105,7 @@ class BoltNeo4jDatabaseMetaData extends Neo4jDatabaseMetaData {
 		}
 	}
 
-	private void cycleResultSetToSetDatabaseProperties (StatementResult rs, Table databaseLabel) {
+	private void cycleResultSetToSetDatabaseProperties(StatementResult rs, Table databaseLabel) {
 		while (rs.hasNext()) {
 			Record record = rs.next();
 			List<Object> keys = record.get("keys").asList();
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDriver.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDriver.java
index f98c1eb9..acdee281 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDriver.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jDriver.java
@@ -21,7 +21,7 @@ package org.neo4j.jdbc.bolt;
 
 import org.neo4j.driver.v1.*;
 import org.neo4j.jdbc.Neo4jDriver;
-import org.neo4j.jdbc.InstanceFactory;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
 
 import java.io.File;
 import java.sql.Connection;
@@ -37,10 +37,10 @@ import static org.neo4j.driver.v1.Config.build;
  */
 public class BoltNeo4jDriver extends Neo4jDriver {
 
-	public static final String JDBC_BOLT_PREFIX = "bolt";
+	public static final String JDBC_BOLT_PREFIX         = "bolt";
 	public static final String JDBC_BOLT_ROUTING_PREFIX = "bolt+routing";
-	public static final String TRUST_STRATEGY_KEY = "trust.strategy";
-	public static final String TRUSTED_CERTIFICATE_KEY = "trusted.certificate.file";
+	public static final String TRUST_STRATEGY_KEY       = "trust.strategy";
+	public static final String TRUSTED_CERTIFICATE_KEY  = "trusted.certificate.file";
 
 	static {
 		try {
@@ -53,6 +53,7 @@ public class BoltNeo4jDriver extends Neo4jDriver {
 
 	/**
 	 * Default constructor.
+	 *
 	 * @throws SQLException sqlexception
 	 */
 	public BoltNeo4jDriver() throws SQLException {
@@ -78,8 +79,7 @@ public class BoltNeo4jDriver extends Neo4jDriver {
 				AuthToken authToken = getAuthToken(info);
 				Driver driver = GraphDatabase.driver(boltUrl, authToken, config);
 				Session session = driver.session();
-                BoltNeo4jConnection boltConnection = new BoltNeo4jConnection(session, info, url);
-				connection = InstanceFactory.debug(BoltNeo4jConnection.class, boltConnection, BoltNeo4jConnection.hasDebug(info));
+				connection = BoltNeo4jConnectionImpl.newInstance(session, info, url);
 			} catch (Exception e) {
 				throw new SQLException(e);
 			}
@@ -132,11 +132,12 @@ public class BoltNeo4jDriver extends Neo4jDriver {
 		return newBuilder;
 	}
 
-	private Config.ConfigBuilder handleTrustStrategyWithFile(Properties properties, Config.TrustStrategy.Strategy strategy, Config.ConfigBuilder builder) throws SQLException {
+	private Config.ConfigBuilder handleTrustStrategyWithFile(Properties properties, Config.TrustStrategy.Strategy strategy, Config.ConfigBuilder builder)
+			throws SQLException {
 		if (properties.containsKey(TRUSTED_CERTIFICATE_KEY)) {
 			Object file = properties.get(TRUSTED_CERTIFICATE_KEY);
 			if (file instanceof File) {
-				Config.ConfigBuilder newBuilder = builder;
+				Config.ConfigBuilder newBuilder;
 				switch (strategy) {
 					case TRUST_CUSTOM_CA_SIGNED_CERTIFICATES:
 						newBuilder = builder.withTrustStrategy(Config.TrustStrategy.trustCustomCertificateSignedBy((File) file));
@@ -147,6 +148,9 @@ public class BoltNeo4jDriver extends Neo4jDriver {
 					case TRUST_SIGNED_CERTIFICATES:
 						newBuilder = builder.withTrustStrategy(Config.TrustStrategy.trustSignedBy((File) file));
 						break;
+					default:
+						newBuilder = builder;
+						break;
 				}
 				return newBuilder;
 			} else {
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jParameterMetaData.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jParameterMetaData.java
index 6e81d02b..cc00f8bd 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jParameterMetaData.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jParameterMetaData.java
@@ -19,16 +19,13 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import org.neo4j.jdbc.Loggable;
 import org.neo4j.jdbc.Neo4jParameterMetaData;
 
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
-public class BoltNeo4jParameterMetaData extends Neo4jParameterMetaData implements Loggable {
-
-	private boolean loggable = false;
+public class BoltNeo4jParameterMetaData extends Neo4jParameterMetaData {
 
 	private BoltNeo4jPreparedStatement preparedStatement;
 
@@ -36,14 +33,6 @@ public class BoltNeo4jParameterMetaData extends Neo4jParameterMetaData implement
 		this.preparedStatement = preparedStatement;
 	}
 
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
-
 	public BoltNeo4jPreparedStatement getPreparedStatement() {
 		return preparedStatement;
 	}
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatement.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatement.java
index 07ac25e4..6447f0eb 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatement.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatement.java
@@ -22,9 +22,16 @@ package org.neo4j.jdbc.bolt;
 import org.neo4j.driver.v1.StatementResult;
 import org.neo4j.driver.v1.Transaction;
 import org.neo4j.driver.v1.summary.SummaryCounters;
-import org.neo4j.jdbc.*;
-
+import org.neo4j.jdbc.Loggable;
+import org.neo4j.jdbc.Neo4jParameterMetaData;
+import org.neo4j.jdbc.Neo4jPreparedStatement;
+import org.neo4j.jdbc.Neo4jResultSetMetaData;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
+
+import java.lang.reflect.Proxy;
 import java.sql.BatchUpdateException;
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.Map;
@@ -37,19 +44,22 @@ import static java.util.Arrays.copyOf;
  */
 public class BoltNeo4jPreparedStatement extends Neo4jPreparedStatement implements Loggable {
 
-	private int[]       rsParams;
-	private boolean loggable = false;
-
-	public BoltNeo4jPreparedStatement(BoltNeo4jConnection connection, String rawStatement, int... rsParams) {
+	private BoltNeo4jPreparedStatement(BoltNeo4jConnectionImpl connection, String rawStatement, int... rsParams) {
 		super(connection, rawStatement);
-		this.rsParams = rsParams;
+		this.resultSetParams = rsParams;
+	}
+
+	public static PreparedStatement newInstance(boolean debug, BoltNeo4jConnectionImpl connection, String rawStatement, int... rsParams) {
+		PreparedStatement ps = new BoltNeo4jPreparedStatement(connection, rawStatement, rsParams);
+		((Neo4jPreparedStatement) ps).setDebug(debug);
+		return (PreparedStatement) Proxy.newProxyInstance(BoltNeo4jPreparedStatement.class.getClassLoader(), new Class[] { PreparedStatement.class },
+				new Neo4jInvocationHandler(ps, debug));
 	}
 
 	@Override public ResultSet executeQuery() throws SQLException {
 		StatementResult result = executeInternal();
 
-		BoltNeo4jResultSet resultSet = new BoltNeo4jResultSet(this, result, this.rsParams);
-		this.currentResultSet = InstanceFactory.debug(BoltNeo4jResultSet.class, resultSet, this.isLoggable());
+		this.currentResultSet = BoltNeo4jResultSet.newInstance(this.hasDebug(), this, result, this.resultSetParams);
 		this.currentUpdateCount = -1;
 		return currentResultSet;
 	}
@@ -68,16 +78,14 @@ public class BoltNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 
 		boolean hasResultSet = hasResultSet(result);
 		if (hasResultSet) {
-			this.currentResultSet = InstanceFactory.debug(BoltNeo4jResultSet.class, new BoltNeo4jResultSet(this,result, this.rsParams), this.isLoggable());
+			this.currentResultSet = BoltNeo4jResultSet.newInstance(this.hasDebug(), this, result, this.resultSetParams);
 			this.currentUpdateCount = -1;
-		}
-		else {
+		} else {
 			this.currentResultSet = null;
 			try {
-			  SummaryCounters stats = result.consume().counters();
-			  this.currentUpdateCount = stats.nodesCreated() + stats.nodesDeleted() + stats.relationshipsCreated() + stats.relationshipsDeleted();
-			}
-			catch (Exception e) {
+				SummaryCounters stats = result.consume().counters();
+				this.currentUpdateCount = stats.nodesCreated() + stats.nodesDeleted() + stats.relationshipsCreated() + stats.relationshipsDeleted();
+			} catch (Exception e) {
 				throw new SQLException(e);
 			}
 		}
@@ -90,21 +98,19 @@ public class BoltNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 		StatementResult result;
 		if (this.getConnection().getAutoCommit()) {
 			try (Transaction t = ((BoltNeo4jConnection) this.getConnection()).getSession().beginTransaction()) {
-			  result = t.run(this.statement, this.parameters);
-			  t.success();
-			}
-			catch (Exception e) {
+				result = t.run(this.statement, this.parameters);
+				t.success();
+			} catch (Exception e) {
 				throw new SQLException(e.getMessage(), e);
 			}
 		} else {
 			try {
-			  result = ((BoltNeo4jConnection) this.getConnection()).getTransaction().run(this.statement, this.parameters);
-			}
-			catch (Exception e) {
+				result = ((BoltNeo4jConnection) this.getConnection()).getTransaction().run(this.statement, this.parameters);
+			} catch (Exception e) {
 				throw new SQLException(e.getMessage(), e);
 			}
 		}
-		
+
 		return result;
 	}
 
@@ -115,7 +121,7 @@ public class BoltNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 			return false;
 		}
 	}
-	
+
 	@Override public Neo4jParameterMetaData getParameterMetaData() throws SQLException {
 		this.checkClosed();
 		return new BoltNeo4jParameterMetaData(this);
@@ -123,42 +129,6 @@ public class BoltNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 
 	@Override public Neo4jResultSetMetaData getMetaData() throws SQLException {
 		return this.currentResultSet == null ? null : (Neo4jResultSetMetaData) this.currentResultSet.getMetaData();
-		/*return InstanceFactory.debug(BoltNeo4jResultSetMetaData.class,
-				new BoltNeo4jResultSetMetaData(((BoltNeo4jResultSet) this.currentResultSet).getIterator(), ((BoltNeo4jResultSet) this.currentResultSet).getKeys()),
-				this.isLoggable());*/
-	}
-
-	@Override public int getResultSetConcurrency() throws SQLException {
-		this.checkClosed();
-		if (currentResultSet != null) {
-			return currentResultSet.getConcurrency();
-		}
-		if (this.rsParams.length > 1) {
-			return this.rsParams[1];
-		}
-		return BoltNeo4jResultSet.DEFAULT_CONCURRENCY;
-	}
-
-	@Override public int getResultSetType() throws SQLException {
-		this.checkClosed();
-		if (currentResultSet != null) {
-			return currentResultSet.getType();
-		}
-		if (this.rsParams.length > 0) {
-			return this.rsParams[0];
-		}
-		return BoltNeo4jResultSet.DEFAULT_TYPE;
-	}
-
-	@Override public int getResultSetHoldability() throws SQLException {
-		this.checkClosed();
-		if (currentResultSet != null) {
-			return currentResultSet.getHoldability();
-		}
-		if (this.rsParams.length > 2) {
-			return this.rsParams[2];
-		}
-		return BoltNeo4jResultSet.DEFAULT_HOLDABILITY;
 	}
 
 	/*-------------------*/
@@ -172,7 +142,7 @@ public class BoltNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 		try {
 			for (Map<String, Object> parameter : this.batchParameters) {
 				StatementResult res;
-				if(this.connection.getAutoCommit()) {
+				if (this.connection.getAutoCommit()) {
 					res = ((BoltNeo4jConnection) this.connection).getSession().run(this.statement, parameter);
 				} else {
 					res = ((BoltNeo4jConnection) this.connection).getTransaction().run(this.statement, parameter);
@@ -187,16 +157,4 @@ public class BoltNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 
 		return result;
 	}
-
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
-
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
 }
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSet.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSet.java
index 33307877..aa112188 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSet.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSet.java
@@ -19,23 +19,8 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
 import org.neo4j.driver.internal.types.InternalTypeSystem;
-import org.neo4j.driver.internal.value.BooleanValue;
-import org.neo4j.driver.internal.value.FloatValue;
-import org.neo4j.driver.internal.value.IntegerValue;
-import org.neo4j.driver.internal.value.ListValue;
-import org.neo4j.driver.internal.value.NodeValue;
-import org.neo4j.driver.internal.value.PathValue;
-import org.neo4j.driver.internal.value.RelationshipValue;
-import org.neo4j.driver.internal.value.StringValue;
+import org.neo4j.driver.internal.value.*;
 import org.neo4j.driver.v1.Record;
 import org.neo4j.driver.v1.StatementResult;
 import org.neo4j.driver.v1.Value;
@@ -46,41 +31,36 @@ import org.neo4j.driver.v1.types.Relationship;
 import org.neo4j.driver.v1.types.Type;
 import org.neo4j.driver.v1.util.Pair;
 import org.neo4j.jdbc.*;
-import org.neo4j.jdbc.Neo4jStatement;
 import org.neo4j.jdbc.impl.ListArray;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
+
+import java.lang.reflect.Proxy;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.*;
 
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
-public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
-
-	private StatementResult        iterator;
-	private Neo4jResultSetMetaData metaData;
-	private Record                 current;
-	private List<String>           keys;
-	private List<Type>             classes;
-	private int                    type;
-	private int                    concurrency;
-	private int                    holdability;
-	private boolean                wasNull;
-
-	public static final int DEFAULT_TYPE        = TYPE_FORWARD_ONLY;
-	public static final int DEFAULT_CONCURRENCY = CONCUR_READ_ONLY;
-	public static final int DEFAULT_HOLDABILITY = CLOSE_CURSORS_AT_COMMIT;
-
-	private boolean loggable  = false;
+public class BoltNeo4jResultSet extends Neo4jResultSet {
+
+	private StatementResult   iterator;
+	private ResultSetMetaData metaData;
+	private Record            current;
+	private List<String>      keys;
+	private List<Type>        classes;
+
 	private boolean flattened = false;
 
 	private static final List<String> ACCEPTED_TYPES_FOR_FLATTENING = Arrays.asList("NODE", "RELATIONSHIP");
-	private Neo4jStatement statement;
 
 	private int flatten;
 
 	private LinkedList<Record> prefetchedRecords = null;
 
-	private static final String COLUMN_NOT_PRESENT = "Column not present in ResultSet";
-
 	/**
 	 * Default constructor for this class, if no params are given or if some params are missing it uses the defaults.
 	 *
@@ -90,8 +70,8 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 	 *                  The defaults are <code>TYPE_FORWARD_ONLY</code>,
 	 *                  <code>CONCUR_READ_ONLY</code>,
 	 */
-	public BoltNeo4jResultSet(Neo4jStatement statement, StatementResult iterator, int... params) {
-		this.statement = statement;
+	private BoltNeo4jResultSet(Statement statement, StatementResult iterator, int... params) {
+		super(statement, params);
 		this.iterator = iterator;
 
 		this.keys = new ArrayList<>();
@@ -99,7 +79,7 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 		this.prefetchedRecords = new LinkedList<>();
 
 		try {
-			this.flatten = this.statement.getConnection().getFlattening();
+			this.flatten = ((Neo4jConnection) this.statement.getConnection()).getFlattening();
 		} catch (Exception e) {
 			this.flatten = 0;
 		}
@@ -118,11 +98,14 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 			}
 		}
 
-		this.type = params.length > 0 ? params[0] : TYPE_FORWARD_ONLY;
-		this.concurrency = params.length > 1 ? params[1] : CONCUR_READ_ONLY;
-		this.holdability = params.length > 2 ? params[2] : CLOSE_CURSORS_AT_COMMIT;
 
-		this.metaData = InstanceFactory.debug(BoltNeo4jResultSetMetaData.class, new BoltNeo4jResultSetMetaData(this.classes, this.keys), this.isLoggable());
+		this.metaData = BoltNeo4jResultSetMetaData.newInstance(false, this.classes, this.keys);
+	}
+
+	public static ResultSet newInstance(boolean debug, Statement statement, StatementResult iterator, int... params) {
+		ResultSet rs = new BoltNeo4jResultSet(statement, iterator, params);
+		return (ResultSet) Proxy
+				.newProxyInstance(BoltNeo4jResultSet.class.getClassLoader(), new Class[] { ResultSet.class }, new Neo4jInvocationHandler(rs, debug));
 	}
 
 	private void flattenResultSet() {
@@ -242,9 +225,9 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 			String result = null;
 			if (value instanceof IntegerValue) {
 				result = ((IntegerValue) value).asLiteralString();
-			}	else if (value instanceof FloatValue) {
+			} else if (value instanceof FloatValue) {
 				result = ((FloatValue) value).asLiteralString();
-			}	else if (value instanceof NodeValue) {
+			} else if (value instanceof NodeValue) {
 				result = this.convertNodeToString(value.asNode());
 			} else if (value instanceof RelationshipValue) {
 				result = this.convertRelationshipToString(value.asRelationship());
@@ -255,8 +238,7 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 		}
 	}
 
-	@SuppressWarnings("rawtypes")
-	private String convertToJSONProperty(String key, Object value) {
+	@SuppressWarnings("rawtypes") private String convertToJSONProperty(String key, Object value) {
 		String result = key == null ? "" : "\"" + key + "\":";
 
 		if (value instanceof String) {
@@ -505,8 +487,7 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 		return new ListArray(list, Neo4jArray.getObjectType(list.get(0)));
 	}
 
-	@SuppressWarnings("rawtypes")
-	@Override public Neo4jArray getArray(String columnLabel) throws SQLException {
+	@SuppressWarnings("rawtypes") @Override public Neo4jArray getArray(String columnLabel) throws SQLException {
 		checkClosed();
 		List list = this.fetchValueFromLabel(columnLabel).asList();
 		return new ListArray(list, Neo4jArray.getObjectType(list.get(0)));
@@ -518,7 +499,7 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 		return value.isNull() ? 0 : value.asDouble();
 	}
 
-	@Override public Neo4jResultSetMetaData getMetaData() throws SQLException {
+	@Override public ResultSetMetaData getMetaData() throws SQLException {
 		return metaData;
 	}
 
@@ -566,15 +547,7 @@ public class BoltNeo4jResultSet extends Neo4jResultSet implements Loggable {
 		return this.generateObject(obj);
 	}
 
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
-
-	@Override public java.sql.Statement getStatement() throws SQLException {
+	@Override public Statement getStatement() throws SQLException {
 		return statement;
 	}
 }
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaData.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaData.java
index df667229..2463d45b 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaData.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaData.java
@@ -19,25 +19,23 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import java.sql.Array;
-import java.sql.SQLException;
-import java.sql.Types;
+import java.lang.reflect.Proxy;
+import java.sql.*;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.neo4j.driver.internal.types.InternalTypeSystem;
 import org.neo4j.driver.v1.types.Type;
-import org.neo4j.jdbc.Loggable;
 import org.neo4j.jdbc.Neo4jResultSetMetaData;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
 
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
-public class BoltNeo4jResultSetMetaData extends Neo4jResultSetMetaData implements Loggable {
+public class BoltNeo4jResultSetMetaData extends Neo4jResultSetMetaData {
 
-	private boolean loggable = false;
 	private Type[] columnType;
 	private static final Map<Type, Class> INTERNAL_TYPE_TO_CLASS_MAP = new HashMap<>();
 	private static final Map<Type, Integer> INTERNAL_TYPE_TO_SQL_TYPES_MAP = new HashMap<>();
@@ -75,15 +73,15 @@ public class BoltNeo4jResultSetMetaData extends Neo4jResultSetMetaData implement
 	 * @param types  List of types
 	 * @param keys     List of column name (ie. key)
 	 */
-	BoltNeo4jResultSetMetaData(List<Type> types, List<String> keys) {
+	private BoltNeo4jResultSetMetaData(List<Type> types, List<String> keys) {
 		super(keys);
 		this.columnType = types.toArray(new Type[this.keys.size() + 1]);
+	}
 
-		// we init columnType with the first record
-		// in case first == last record
-		/*for (int i = 1; i <= this.keys.size(); i++) {
-			columnType[i] = this.getColumnDriverTypeOrDefault(i, InternalTypeSystem.TYPE_SYSTEM.STRING());
-		}*/
+	public static ResultSetMetaData newInstance(boolean debug, List<Type> types, List<String> keys) {
+		ResultSetMetaData rsmd = new BoltNeo4jResultSetMetaData(types, keys);
+		return (ResultSetMetaData) Proxy
+				.newProxyInstance(BoltNeo4jResultSetMetaData.class.getClassLoader(), new Class[] { ResultSetMetaData.class }, new Neo4jInvocationHandler(rsmd, debug));
 	}
 
 	/**
@@ -120,16 +118,4 @@ public class BoltNeo4jResultSetMetaData extends Neo4jResultSetMetaData implement
 		Type type = this.columnType[column - 1];
 		return type.name();
 	}
-
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
-
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
 }
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jStatement.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jStatement.java
index 7d27d2e0..a97e89d4 100644
--- a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jStatement.java
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/BoltNeo4jStatement.java
@@ -22,13 +22,15 @@ package org.neo4j.jdbc.bolt;
 import org.neo4j.driver.v1.StatementResult;
 import org.neo4j.driver.v1.Transaction;
 import org.neo4j.driver.v1.summary.SummaryCounters;
-import org.neo4j.jdbc.InstanceFactory;
-import org.neo4j.jdbc.Loggable;
 import org.neo4j.jdbc.Neo4jStatement;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
 
+import java.lang.reflect.Proxy;
 import java.sql.BatchUpdateException;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -36,11 +38,7 @@ import java.util.Arrays;
  * @author AgileLARUS
  * @since 3.0.0
  */
-public class BoltNeo4jStatement extends Neo4jStatement implements Loggable {
-
-	private int[]        rsParams;
-
-	private boolean loggable = false;
+public class BoltNeo4jStatement extends Neo4jStatement {
 
 	/**
 	 * Default Constructor
@@ -48,27 +46,34 @@ public class BoltNeo4jStatement extends Neo4jStatement implements Loggable {
 	 * @param connection The connection used for sharing the transaction between statements
 	 * @param rsParams   The params (type, concurrency and holdability) used to create a new ResultSet
 	 */
-	public BoltNeo4jStatement(BoltNeo4jConnection connection, int... rsParams) {
+	private BoltNeo4jStatement(BoltNeo4jConnectionImpl connection, int... rsParams) {
 		super(connection);
-		this.rsParams = rsParams;
+		this.resultSetParams = rsParams;
 		this.batchStatements = new ArrayList<>();
 	}
 
+	public static Statement newInstance(boolean debug, BoltNeo4jConnectionImpl connection, int... rsParams) {
+		Statement statement = new BoltNeo4jStatement(connection, rsParams);
+		((Neo4jStatement) statement).setDebug(debug);
+		return (Statement) Proxy.newProxyInstance(BoltNeo4jStatement.class.getClassLoader(), new Class[] { Statement.class },
+				new Neo4jInvocationHandler(statement, debug));
+	}
+
 	@Override public ResultSet executeQuery(String sql) throws SQLException {
-			StatementResult result = executeInternal(sql);
+		StatementResult result = executeInternal(sql);
 
-			this.currentResultSet = InstanceFactory.debug(BoltNeo4jResultSet.class, new BoltNeo4jResultSet(this, result, this.rsParams), this.isLoggable());
-			this.currentUpdateCount = -1;
-			return this.currentResultSet;
+		this.currentResultSet = BoltNeo4jResultSet.newInstance(this.hasDebug(), this, result, this.resultSetParams);
+		this.currentUpdateCount = -1;
+		return this.currentResultSet;
 	}
 
 	@Override public int executeUpdate(String sql) throws SQLException {
-			StatementResult result = executeInternal(sql);
+		StatementResult result = executeInternal(sql);
 
-			SummaryCounters stats = result.consume().counters();
-			this.currentUpdateCount = stats.nodesCreated() + stats.nodesDeleted() + stats.relationshipsCreated() + stats.relationshipsDeleted();
-			this.currentResultSet = null;
-			return this.currentUpdateCount;
+		SummaryCounters stats = result.consume().counters();
+		this.currentUpdateCount = stats.nodesCreated() + stats.nodesDeleted() + stats.relationshipsCreated() + stats.relationshipsDeleted();
+		this.currentResultSet = null;
+		return this.currentUpdateCount;
 	}
 
 	@Override public boolean execute(String sql) throws SQLException {
@@ -78,16 +83,14 @@ public class BoltNeo4jStatement extends Neo4jStatement implements Loggable {
 		if (result != null) {
 			hasResultSet = hasResultSet(sql);
 			if (hasResultSet) {
-				this.currentResultSet = InstanceFactory.debug(BoltNeo4jResultSet.class, new BoltNeo4jResultSet(this,result, this.rsParams), this.isLoggable());
+				this.currentResultSet = BoltNeo4jResultSet.newInstance(this.hasDebug(), this, result, this.resultSetParams);
 				this.currentUpdateCount = -1;
-			}
-			else {
+			} else {
 				this.currentResultSet = null;
 				try {
 					SummaryCounters stats = result.consume().counters();
 					this.currentUpdateCount = stats.nodesCreated() + stats.nodesDeleted() + stats.relationshipsCreated() + stats.relationshipsDeleted();
-				}
-				catch (Exception e) {
+				} catch (Exception e) {
 					throw new SQLException(e);
 				}
 			}
@@ -103,8 +106,7 @@ public class BoltNeo4jStatement extends Neo4jStatement implements Loggable {
 			try (Transaction t = ((BoltNeo4jConnection) this.getConnection()).getSession().beginTransaction()) {
 				result = t.run(sql);
 				t.success();
-			}
-			catch (Exception e) {
+			} catch (Exception e) {
 				throw new SQLException(e);
 			}
 		} else {
@@ -121,39 +123,6 @@ public class BoltNeo4jStatement extends Neo4jStatement implements Loggable {
 		return sql != null && sql.toLowerCase().contains("return");
 	}
 
-	@Override public int getResultSetConcurrency() throws SQLException {
-		this.checkClosed();
-		if (currentResultSet != null) {
-			return currentResultSet.getConcurrency();
-		}
-		if (this.rsParams.length > 1) {
-			return this.rsParams[1];
-		}
-		return BoltNeo4jResultSet.DEFAULT_CONCURRENCY;
-	}
-
-	@Override public int getResultSetType() throws SQLException {
-		this.checkClosed();
-		if (currentResultSet != null) {
-			return currentResultSet.getType();
-		}
-		if (this.rsParams.length > 0) {
-			return this.rsParams[0];
-		}
-		return BoltNeo4jResultSet.DEFAULT_TYPE;
-	}
-
-	@Override public int getResultSetHoldability() throws SQLException {
-		this.checkClosed();
-		if (currentResultSet != null) {
-			return currentResultSet.getHoldability();
-		}
-		if (this.rsParams.length > 2) {
-			return this.rsParams[2];
-		}
-		return BoltNeo4jResultSet.DEFAULT_HOLDABILITY;
-	}
-
 	/*-------------------*/
 	/*       Batch       */
 	/*-------------------*/
@@ -182,16 +151,4 @@ public class BoltNeo4jStatement extends Neo4jStatement implements Loggable {
 		return result;
 	}
 
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
-
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
-
 }
diff --git a/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/impl/BoltNeo4jConnectionImpl.java b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/impl/BoltNeo4jConnectionImpl.java
new file mode 100644
index 00000000..ac9bedc8
--- /dev/null
+++ b/neo4j-jdbc-bolt/src/main/java/org/neo4j/jdbc/bolt/impl/BoltNeo4jConnectionImpl.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2016 LARUS Business Automation [http://www.larus-ba.it]
+ * <p>
+ * This file is part of the "LARUS Integration Framework for Neo4j".
+ * <p>
+ * The "LARUS Integration Framework for Neo4j" is licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * <p>
+ * Created on 17/02/16
+ */
+package org.neo4j.jdbc.bolt.impl;
+
+import org.neo4j.driver.v1.Session;
+import org.neo4j.driver.v1.Transaction;
+import org.neo4j.jdbc.Neo4jDatabaseMetaData;
+import org.neo4j.jdbc.Neo4jResultSet;
+import org.neo4j.jdbc.bolt.*;
+import org.neo4j.jdbc.impl.Neo4jConnectionImpl;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
+import org.neo4j.jdbc.utils.TimeLimitedCodeBlock;
+
+import java.lang.reflect.Proxy;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author AgileLARUS
+ * @since 3.0.0
+ */
+public class BoltNeo4jConnectionImpl extends Neo4jConnectionImpl implements BoltNeo4jConnection {
+
+	private Session     session;
+	private Transaction transaction;
+	private boolean autoCommit = true;
+
+	private static final Logger LOGGER = Logger.getLogger(BoltNeo4jConnectionImpl.class.getName());
+
+	/**
+	 * Constructor with Session and Properties.
+	 *
+	 * @param session    Bolt Session
+	 * @param properties Driver properties
+	 * @param url        Url used for this connection
+	 */
+	public BoltNeo4jConnectionImpl(Session session, Properties properties, String url) {
+		super(properties, url, BoltNeo4jResultSet.DEFAULT_HOLDABILITY);
+		this.session = session;
+	}
+
+	/**
+	 * Constructor with Session.
+	 *
+	 * @param session Bolt Session
+	 */
+	public BoltNeo4jConnectionImpl(Session session) {
+		this(session, new Properties(), "");
+	}
+
+	public static BoltNeo4jConnection newInstance(Session session, Properties info, String url) {
+		BoltNeo4jConnection boltConnection = new BoltNeo4jConnectionImpl(session, info, url);
+		return (BoltNeo4jConnection) Proxy
+				.newProxyInstance(BoltNeo4jConnectionImpl.class.getClassLoader(), new Class[] { Connection.class, BoltNeo4jConnection.class },
+						new Neo4jInvocationHandler(boltConnection, BoltNeo4jConnectionImpl.hasDebug(info)));
+	}
+
+	/**
+	 * Getter for transaction.
+	 *
+	 * @return the transaction
+	 */
+	@Override public Transaction getTransaction() {
+		return this.transaction;
+	}
+
+	/**
+	 * Getter for session.
+	 *
+	 * @return the internal session
+	 */
+	@Override public Session getSession() {
+		return this.session;
+	}
+
+	@Override public Neo4jDatabaseMetaData getMetaData() throws SQLException {
+		return new BoltNeo4jDatabaseMetaData(this);
+	}
+
+	/*------------------------------*/
+	/*       Commit, rollback       */
+	/*------------------------------*/
+
+	@Override public void setAutoCommit(boolean autoCommit) throws SQLException {
+		if (this.autoCommit != autoCommit) {
+			if (this.transaction != null && !this.autoCommit) {
+				this.commit();
+				this.transaction.close();
+			}
+
+			if (this.autoCommit) {
+				//Simply restart the transaction
+				this.transaction = this.session.beginTransaction();
+			}
+
+			this.autoCommit = autoCommit;
+		}
+	}
+
+	@Override public boolean getAutoCommit() throws SQLException {
+		this.checkClosed();
+		return autoCommit;
+	}
+
+	@Override public void commit() throws SQLException {
+		this.checkClosed();
+		this.checkAutoCommit();
+		if (this.transaction == null) {
+			throw new SQLException("The transaction is null");
+		}
+		this.transaction.success();
+		this.transaction.close();
+		this.transaction = this.session.beginTransaction();
+	}
+
+	@Override public void rollback() throws SQLException {
+		this.checkClosed();
+		this.checkAutoCommit();
+		if (this.transaction == null) {
+			throw new SQLException("The transaction is null");
+		}
+		this.transaction.failure();
+	}
+
+	/*------------------------------*/
+	/*       Create Statement       */
+	/*------------------------------*/
+
+	@Override public Statement createStatement() throws SQLException {
+		if (this.transaction == null && !this.autoCommit) {
+			this.transaction = this.session.beginTransaction();
+		}
+		return createStatement(Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
+	}
+
+	@Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+		return createStatement(resultSetType, resultSetConcurrency, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
+	}
+
+	@Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+		this.checkClosed();
+		this.checkTypeParams(resultSetType);
+		this.checkConcurrencyParams(resultSetConcurrency);
+		this.checkHoldabilityParams(resultSetHoldability);
+		return BoltNeo4jStatement.newInstance(false, this, resultSetType, resultSetConcurrency, resultSetHoldability);
+	}
+
+	/*-------------------------------*/
+	/*       Prepare Statement       */
+	/*-------------------------------*/
+
+	@Override public PreparedStatement prepareStatement(String sql) throws SQLException {
+		return prepareStatement(nativeSQL(sql), Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
+	}
+
+	@Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+		return prepareStatement(nativeSQL(sql), resultSetType, resultSetConcurrency, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
+	}
+
+	@Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+		this.checkClosed();
+		this.checkTypeParams(resultSetType);
+		this.checkConcurrencyParams(resultSetConcurrency);
+		this.checkHoldabilityParams(resultSetHoldability);
+		return BoltNeo4jPreparedStatement.newInstance(false, this, nativeSQL(sql), resultSetType, resultSetConcurrency, resultSetHoldability);
+	}
+
+	/*-------------------*/
+	/*       Close       */
+	/*-------------------*/
+
+	@Override public boolean isClosed() throws SQLException {
+		return !this.session.isOpen();
+	}
+
+	@Override public void close() throws SQLException {
+		try {
+			if (!this.isClosed()) {
+				session.close();
+			}
+		} catch (Exception e) {
+			throw new SQLException("A database access error has occurred: " + e.getMessage());
+		}
+	}
+
+	/*-------------------*/
+	/*      isValid      */
+	/*-------------------*/
+	@Override public boolean isValid(int timeout) throws SQLException {
+		if (timeout < 0) {
+			throw new SQLException("Timeout can't be less than zero");
+		}
+		if (this.isClosed()) {
+			return false;
+		}
+
+		Runnable r = new Runnable() {
+			@Override public void run() {
+				Session s = getSession();
+				Transaction tr = getTransaction();
+				if (tr != null && tr.isOpen()) {
+					tr.run(FASTEST_STATEMENT);
+				} else {
+					s.run(FASTEST_STATEMENT);
+				}
+			}
+		};
+
+		try {
+			TimeLimitedCodeBlock.runWithTimeout(r, timeout, TimeUnit.SECONDS);
+		} catch (Exception e) { // also timeout
+			LOGGER.log(Level.FINEST, "Catch exception totally fine", e);
+			return false;
+		}
+
+		return true;
+	}
+
+}
diff --git a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jConnection.java b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jConnection.java
index e16eb0df..3acd9804 100644
--- a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jConnection.java
+++ b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jConnection.java
@@ -23,6 +23,7 @@ import org.neo4j.jdbc.*;
 import org.neo4j.jdbc.http.driver.CypherExecutor;
 import org.neo4j.jdbc.http.driver.Neo4jResponse;
 import org.neo4j.jdbc.http.driver.Neo4jStatement;
+import org.neo4j.jdbc.impl.Neo4jConnectionImpl;
 import org.neo4j.jdbc.utils.ExceptionBuilder;
 import org.neo4j.jdbc.utils.Neo4jJdbcRuntimeException;
 import org.neo4j.jdbc.utils.TimeLimitedCodeBlock;
@@ -35,11 +36,12 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
-public class HttpNeo4jConnection extends Neo4jConnection implements Loggable {
+public class HttpNeo4jConnection extends Neo4jConnectionImpl implements Loggable {
 
 	CypherExecutor executor;
 	private boolean isClosed = false;
-	private boolean loggable = false;
+	private boolean debug = false;
+	private int debugLevel;
 
 	/**
 	 * Default constructor.
@@ -145,17 +147,17 @@ public class HttpNeo4jConnection extends Neo4jConnection implements Loggable {
 
 	@Override public java.sql.Statement createStatement() throws SQLException {
 		this.checkClosed();
-		return InstanceFactory.debug(HttpNeo4jStatement.class, new HttpNeo4jStatement(this), this.isLoggable());
+		return InstanceFactory.debug(new HttpNeo4jStatement(this));
 	}
 
 	@Override public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
 		this.checkClosed();
-		return InstanceFactory.debug(HttpNeo4jStatement.class, new HttpNeo4jStatement(this), this.isLoggable());
+		return InstanceFactory.debug(new HttpNeo4jStatement(this));
 	}
 
 	@Override public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
 		this.checkClosed();
-		return InstanceFactory.debug(HttpNeo4jStatement.class, new HttpNeo4jStatement(this), this.isLoggable());
+		return InstanceFactory.debug(new HttpNeo4jStatement(this));
 	}
 
 	/*-------------------------------*/
@@ -164,18 +166,18 @@ public class HttpNeo4jConnection extends Neo4jConnection implements Loggable {
 
 	@Override public PreparedStatement prepareStatement(String cypher) throws SQLException {
 		this.checkClosed();
-		return InstanceFactory.debug(HttpNeo4jPreparedStatement.class, new HttpNeo4jPreparedStatement(this, cypher), this.isLoggable());
+		return InstanceFactory.debug(new HttpNeo4jPreparedStatement(this, cypher));
 	}
 
 	@Override public PreparedStatement prepareStatement(String cypher, int resultSetType, int resultSetConcurrency) throws SQLException {
 		this.checkClosed();
-		return InstanceFactory.debug(HttpNeo4jPreparedStatement.class, new HttpNeo4jPreparedStatement(this, cypher), this.isLoggable());
+		return InstanceFactory.debug(new HttpNeo4jPreparedStatement(this, cypher));
 	}
 
 	@Override public PreparedStatement prepareStatement(String cypher, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
 			throws SQLException {
 		this.checkClosed();
-		return InstanceFactory.debug(HttpNeo4jPreparedStatement.class, new HttpNeo4jPreparedStatement(this, cypher), this.isLoggable());
+		return InstanceFactory.debug(new HttpNeo4jPreparedStatement(this, cypher));
 	}
 
 	/*-------------------*/
@@ -226,16 +228,19 @@ public class HttpNeo4jConnection extends Neo4jConnection implements Loggable {
 		return true;
 	}
 
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
+	@Override public boolean hasDebug() {
+		return this.debug;
+	}
 
-	@Override public boolean isLoggable() {
-		return loggable;
+	@Override public void setDebug(boolean debug) {
+		this.debug = debug;
 	}
 
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
+	@Override public void setDebugLevel(int level) {
+		this.debugLevel = level;
 	}
 
+	@Override public int getDebugLevel() {
+		return this.debugLevel;
+	}
 }
diff --git a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jDriver.java b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jDriver.java
index a70d8ba0..c6e5b96e 100644
--- a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jDriver.java
+++ b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jDriver.java
@@ -73,7 +73,7 @@ public class HttpNeo4jDriver extends Neo4jDriver {
 				if (neo4jUrl.getPort() > 0) {
 					port = neo4jUrl.getPort();
 				}
-				connection = InstanceFactory.debug(HttpNeo4jConnection.class, new HttpNeo4jConnection(host, port, secure, props, url), HttpNeo4jConnection.hasDebug(props));
+				connection = InstanceFactory.debug(new HttpNeo4jConnection(host, port, secure, props, url));
 			}
 		} catch (MalformedURLException e) {
 			throw new SQLException(e);
diff --git a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jParameterMetaData.java b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jParameterMetaData.java
index bfe46563..49f046eb 100644
--- a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jParameterMetaData.java
+++ b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jParameterMetaData.java
@@ -19,26 +19,16 @@
  */
 package org.neo4j.jdbc.http;
 
-import org.neo4j.jdbc.Loggable;
 import org.neo4j.jdbc.Neo4jParameterMetaData;
 
-public class HttpNeo4jParameterMetaData extends Neo4jParameterMetaData implements Loggable {
+public class HttpNeo4jParameterMetaData extends Neo4jParameterMetaData {
 
-	private boolean loggable = false;
 	private HttpNeo4jPreparedStatement preparedStatement;
 
 	public HttpNeo4jParameterMetaData(HttpNeo4jPreparedStatement preparedStatement) {
 		this.preparedStatement = preparedStatement;
 	}
 
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
-
 	public HttpNeo4jPreparedStatement getPreparedStatement() {
 		return preparedStatement;
 	}
diff --git a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jPreparedStatement.java b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jPreparedStatement.java
index 45937a9e..221bb5de 100644
--- a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jPreparedStatement.java
+++ b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jPreparedStatement.java
@@ -30,8 +30,6 @@ import java.util.List;
 
 public class HttpNeo4jPreparedStatement extends Neo4jPreparedStatement implements Loggable {
 
-	private boolean loggable = false;
-
 	/**
 	 * Default constructor.
 	 *
@@ -76,7 +74,7 @@ public class HttpNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 	}
 
 	@Override public Neo4jResultSetMetaData getMetaData() throws SQLException {
-		return InstanceFactory.debug(HttpNeo4jResultSetMetaData.class, new HttpNeo4jResultSetMetaData(((HttpNeo4jResultSet) this.currentResultSet).result), this.isLoggable());
+		return new HttpNeo4jResultSetMetaData(((HttpNeo4jResultSet) this.currentResultSet).result);
 	}
 
 	@Override public Neo4jParameterMetaData getParameterMetaData() throws SQLException {
@@ -127,16 +125,4 @@ public class HttpNeo4jPreparedStatement extends Neo4jPreparedStatement implement
 
 		return result;
 	}
-
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
-
-	@Override public boolean isLoggable() {
-		return loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
 }
diff --git a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSet.java b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSet.java
index c11cc65e..ab19c437 100644
--- a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSet.java
+++ b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSet.java
@@ -37,7 +37,7 @@ import java.util.List;
  * ResultSet for the HTTP connector.
  * This is a wrapper of Neo4jResult.
  */
-public class HttpNeo4jResultSet extends Neo4jResultSet implements Loggable {
+public class HttpNeo4jResultSet extends Neo4jResultSet {
 
 	/**
 	 * Jackson mapper to make toString() method for complex object.
@@ -59,18 +59,11 @@ public class HttpNeo4jResultSet extends Neo4jResultSet implements Loggable {
 	 */
 	private List<Object> currentRow;
 
-	/**
-	 * Is the last read column was null.
-	 */
-	private boolean wasNull = false;
-
 	/**
 	 * Statement that have produced this ResultSet.
 	 */
 	private Neo4jStatement statement;
 
-	private boolean loggable;
-
 	private static final String INVALID_COLUMN = "Column %s is invalid";
 	private static final String UNDEFINED_COLUMN = "Column %s is not defined";
 	private static final String COLUMN_NOT_ARRAY = "Column %s is not an array";
@@ -82,7 +75,7 @@ public class HttpNeo4jResultSet extends Neo4jResultSet implements Loggable {
 	 * @param result    A Neo4j query result.
 	 */
 	public HttpNeo4jResultSet(Neo4jStatement statement, Neo4jResult result) {
-
+		super(statement);
 		this.statement = statement;
 		this.result = result;
 		this.row = -1;
@@ -392,18 +385,6 @@ public class HttpNeo4jResultSet extends Neo4jResultSet implements Loggable {
 		return this.isClosed;
 	}
 
-	@Override
-	public boolean isLoggable() {
-
-		return this.loggable;
-	}
-
-	@Override
-	public void setLoggable(boolean loggable) {
-
-		this.loggable = loggable;
-	}
-
 	@Override
 	public java.sql.Statement getStatement() throws SQLException {
 
diff --git a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSetMetaData.java b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSetMetaData.java
index 0e7245e0..843ab3da 100644
--- a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSetMetaData.java
+++ b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jResultSetMetaData.java
@@ -19,18 +19,17 @@
  */
 package org.neo4j.jdbc.http;
 
-import org.neo4j.jdbc.Loggable;
 import org.neo4j.jdbc.Neo4jResultSetMetaData;
 import org.neo4j.jdbc.http.driver.Neo4jResult;
 
 import java.sql.Array;
 import java.sql.SQLException;
 import java.sql.Types;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-public class HttpNeo4jResultSetMetaData extends Neo4jResultSetMetaData implements Loggable {
-
-	private boolean loggable = false;
+public class HttpNeo4jResultSetMetaData extends Neo4jResultSetMetaData {
 
 	private Neo4jResult result;
 
@@ -93,17 +92,5 @@ public class HttpNeo4jResultSetMetaData extends Neo4jResultSetMetaData implement
 		}
 		return Object.class.getName();
 	}
-
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
-
-	@Override public boolean isLoggable() {
-		return this.loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
 }
 
diff --git a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jStatement.java b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jStatement.java
index 553004ce..60741341 100644
--- a/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jStatement.java
+++ b/neo4j-jdbc-http/src/main/java/org/neo4j/jdbc/http/HttpNeo4jStatement.java
@@ -33,8 +33,6 @@ import java.util.Map;
 
 public class HttpNeo4jStatement extends Neo4jStatement implements Loggable {
 
-	private boolean loggable = false;
-
 	public HttpNeo4jStatement(HttpNeo4jConnection httpConnection) {
 		super(httpConnection);
 		batchStatements = new ArrayList<>();
@@ -114,16 +112,4 @@ public class HttpNeo4jStatement extends Neo4jStatement implements Loggable {
 
 		return result;
 	}
-
-	/*--------------------*/
-	/*       Logger       */
-	/*--------------------*/
-
-	@Override public boolean isLoggable() {
-		return loggable;
-	}
-
-	@Override public void setLoggable(boolean loggable) {
-		this.loggable = loggable;
-	}
 }
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/InstanceFactory.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/InstanceFactory.java
index b030a7cb..07dafffd 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/InstanceFactory.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/InstanceFactory.java
@@ -21,8 +21,6 @@
  */
 package org.neo4j.jdbc;
 
-//import org.mockito.Mockito;
-
 /**
  * @author AgileLARUS
  * @since 3.0.0
@@ -31,12 +29,7 @@ public class InstanceFactory {
 
 	private InstanceFactory () {}
 
-	public static <T extends Loggable> T debug(Class<T> cls, T obj, boolean log) {
-/*		if (log) {
-			obj.setLoggable(true);
-			obj = Mockito.mock(cls, Mockito.withSettings().spiedInstance(obj).verboseLogging().defaultAnswer(Mockito.CALLS_REAL_METHODS));
-		}
-*/
+	public static <T extends Loggable> T debug(T obj) {
 		return obj;
 	}
 }
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Loggable.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Loggable.java
index 4c05a000..adca5794 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Loggable.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Loggable.java
@@ -26,7 +26,11 @@ package org.neo4j.jdbc;
  * @since 3.0.0
  */
 public interface Loggable {
-	boolean isLoggable();
+	boolean hasDebug();
 
-	void setLoggable(boolean loggable);
+	void setDebug(boolean debug);
+
+	void setDebugLevel(int level);
+
+	int getDebugLevel();
 }
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jCallableStatement.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jCallableStatement.java
index c0560aa7..3c005325 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jCallableStatement.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jCallableStatement.java
@@ -26,9 +26,6 @@ import java.io.Reader;
 import java.math.BigDecimal;
 import java.net.URL;
 import java.sql.*;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
 import java.util.Calendar;
 import java.util.Map;
 
@@ -36,7 +33,17 @@ import java.util.Map;
  * @author AgileLARUS
  * @since 3.0.0
  */
-public abstract class Neo4jCallableStatement implements java.sql.CallableStatement {
+public abstract class Neo4jCallableStatement extends Neo4jPreparedStatement implements java.sql.CallableStatement {
+
+	/**
+	 * Default constructor with connection and statement.
+	 *
+	 * @param connection   The JDBC connection
+	 * @param rawStatement The prepared statement
+	 */
+	protected Neo4jCallableStatement(Neo4jConnection connection, String rawStatement) {
+		super(connection, rawStatement);
+	}
 
 	/*---------------------------------------*/
 	/*       Some useful check method        */
@@ -566,42 +573,6 @@ public abstract class Neo4jCallableStatement implements java.sql.CallableStateme
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
 
-	@Override public void setString(int parameterIndex, String x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setBytes(int parameterIndex, byte[] x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setDate(int parameterIndex, Date x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setTime(int parameterIndex, Time x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void clearParameters() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
 	@Override public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
@@ -614,134 +585,6 @@ public abstract class Neo4jCallableStatement implements java.sql.CallableStateme
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
 
-	@Override public void addBatch() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setRef(int parameterIndex, Ref x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setBlob(int parameterIndex, Blob x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setClob(int parameterIndex, Clob x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setArray(int parameterIndex, java.sql.Array x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public ResultSetMetaData getMetaData() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setURL(int parameterIndex, URL x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public java.sql.ParameterMetaData getParameterMetaData() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setRowId(int parameterIndex, RowId x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNString(int parameterIndex, String value) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNClob(int parameterIndex, NClob value) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setClob(int parameterIndex, Reader reader) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNClob(int parameterIndex, Reader reader) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
 	@Override public ResultSet executeQuery(String sql) throws SQLException {
 		throw new SQLException("Method executeQuery(String) cannot be called on PreparedStatement");
 	}
@@ -842,46 +685,10 @@ public abstract class Neo4jCallableStatement implements java.sql.CallableStateme
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
 
-	@Override public Connection getConnection() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
 	@Override public boolean getMoreResults(int current) throws SQLException {
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
 
-	@Override public ResultSet getGeneratedKeys() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public int executeUpdate(String sql, String[] columnNames) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public boolean execute(String sql, int[] columnIndexes) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public boolean execute(String sql, String[] columnNames) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public int getResultSetHoldability() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
 	@Override public boolean isClosed() throws SQLException {
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jConnection.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jConnection.java
index 6c5042a1..cbd84c14 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jConnection.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jConnection.java
@@ -19,443 +19,40 @@
  */
 package org.neo4j.jdbc;
 
-import org.neo4j.jdbc.utils.ExceptionBuilder;
-
-import java.sql.*;
-import java.sql.CallableStatement;
-import java.sql.PreparedStatement;
-import java.sql.Statement;
-import java.util.Map;
 import java.util.Properties;
-import java.util.concurrent.Executor;
 
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
-public abstract class Neo4jConnection implements java.sql.Connection {
-
-	/**
-	 * JDBC Url used for this connection
-	 */
-	private String url;
-
-	/**
-	 * JDBC driver properties
-	 */
-	private Properties properties;
-
-	/**
-	 * Is the connection is in readonly mode ?
-	 */
-	private boolean readOnly = false;
-
-	/**
-	 * Holdability of the connection
-	 */
-	private int holdability;
-
-	protected static final String FASTEST_STATEMENT = "RETURN 1";
-	
-	/**
-	 * Default constructor with properties.
-	 *
-	 * @param properties driver properties
-	 * @param url connection url
-	 * @param defaultHoldability connection holdability
-	 */
-	protected Neo4jConnection(Properties properties, String url, int defaultHoldability) {
-		this.url = url;
-		this.properties = properties;
-		this.holdability = defaultHoldability;
-	}
-
-	public static boolean hasDebug(Properties properties) {
-		return "true".equalsIgnoreCase(properties.getProperty("debug", "false"));
-	}
+public interface Neo4jConnection extends java.sql.Connection {
 
 	/**
 	 * Get the connection url.
-	 * 
+	 *
 	 * @return String the connection url
 	 */
-	public String getUrl() {
-		return url;
-	}
-	
+	String getUrl();
+
 	/**
 	 * Get the properties for this connection.
-	 * 
+	 *
 	 * @return Properties the properties for this connection
 	 */
-	public Properties getProperties() {
-		return properties;
-	}
-	
+	Properties getProperties();
+
 	/**
 	 * Get the user of this connection.
 	 *
 	 * @return String
 	 */
-	public String getUserName() {
-		return properties.getProperty("user");
-	}
+	String getUserName();
 
 	/**
 	 * Get the flattening sample rows (-1 if no flattening).
 	 *
 	 * @return int
 	 */
-	public int getFlattening() {
-		String flatten = properties.getProperty("flatten");
-		return flatten == null ? 0 : Integer.parseInt(flatten);
-	}
-
-	/*---------------------------------------*/
-	/*       Some useful check method        */
-	/*---------------------------------------*/
-
-	/**
-	 * Check if this connection is closed or not.
-	 * If it's closed, then we throw a SQLException, otherwise we do nothing.
-	 * @throws SQLException sqlexception
-	 */
-	protected void checkClosed() throws SQLException {
-		if (this.isClosed()) {
-			throw new SQLException("Connection already closed");
-		}
-	}
-
-	/**
-	 * Method to check if we are into autocommit mode.
-	 * If we do, then it throw an exception.
-	 * This method is for using into commit and rollback method.
-	 * @throws SQLException sqlexception
-	 */
-	protected void checkAutoCommit() throws SQLException {
-		if (this.getAutoCommit()) {
-			throw new SQLException("Cannot commit when in autocommit");
-		}
-	}
-
-	/**
-	 * Check if can execute the query into the current mode (ie. readonly or not).
-	 * If we can't an SQLException is throw.
-	 *
-	 * @param query Cypher query
-	 * @throws SQLException sqlexception
-	 */
-	protected void checkReadOnly(String query) throws SQLException {
-		if (isReadOnly() && isMutating(query)) {
-			throw new SQLException("Mutating Query in readonly mode: " + query);
-		}
-	}
-
-	/**
-	 * Detect some cypher keyword to know if this query mutated the graph.
-	 * /!\ This not enough now due to procedure procedure.
-	 *
-	 * @param query Cypher query
-	 * @return
-	 */
-	private boolean isMutating(String query) {
-		return query.matches("(?is).*\\b(create|relate|delete|set)\\b.*");
-	}
-
-	/**
-	 * Check if the holdability parameter conform to specification.
-	 * If it doesn't, we throw an exception.
-	 * {@link java.sql.Connection#setHoldability(int)}
-	 *
-	 * @param resultSetHoldability The holdability value to check
-	 * @throws SQLException sqlexception
-	 */
-	protected void checkHoldabilityParams(int resultSetHoldability) throws SQLException {
-		// @formatter:off
-		if( resultSetHoldability != Neo4jResultSet.HOLD_CURSORS_OVER_COMMIT &&
-			resultSetHoldability != Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT
-		){
-			throw new SQLFeatureNotSupportedException();
-		}
-		// @formatter:on
-	}
-
-	/**
-	 * Check if the concurrency parameter conform to specification.
-	 * If it doesn't, we throw an exception.
-	 *
-	 * @param resultSetConcurrency The concurrency value to check
-	 * @throws SQLException sqlexception
-	 */
-	protected void checkConcurrencyParams(int resultSetConcurrency) throws SQLException {
-		// @formatter:off
-		if( resultSetConcurrency != Neo4jResultSet.CONCUR_UPDATABLE &&
-			resultSetConcurrency != Neo4jResultSet.CONCUR_READ_ONLY
-		){
-			throw new SQLFeatureNotSupportedException();
-		}
-		// @formatter:on
-	}
-
-	/**
-	 * Check if the resultset type parameter conform to specification.
-	 * If it doesn't, we throw an exception.
-	 *
-	 * @param resultSetType The concurrency value to check
-	 * @throws SQLException sqlexception
-	 */
-	protected void checkTypeParams(int resultSetType) throws SQLException {
-		// @formatter:off
-		if( resultSetType != Neo4jResultSet.TYPE_FORWARD_ONLY &&
-			resultSetType != Neo4jResultSet.TYPE_SCROLL_INSENSITIVE &&
-			resultSetType != Neo4jResultSet.TYPE_SCROLL_SENSITIVE
-		){
-			throw new SQLFeatureNotSupportedException();
-		}
-		// @formatter:on
-	}
-
-	/**
-	 * Check if the transaction isolation level parameter conform to specification.
-	 * If it doesn't, we throw an exception.
-	 *
-	 * @param level The transaction isolation level value to check
-	 * @throws SQLException sqlexception
-	 */
-	protected void checkTransactionIsolation(int level) throws SQLException {
-		// @formatter:off
-		if( level != TRANSACTION_NONE &&
-				level != TRANSACTION_READ_COMMITTED &&
-				level != TRANSACTION_READ_UNCOMMITTED &&
-				level != TRANSACTION_REPEATABLE_READ &&
-				level != TRANSACTION_SERIALIZABLE
-				){
-			throw new SQLException();
-		}
-		// @formatter:on
-	}
-	
-	/**
-	 * Check if the auto generated keys parameter conform to specification.
-	 * If it doesn't, we throw an exception.
-	 * 
-	 * @param autoGeneratedKeys the auto generated keys value to check
-	 * @throws SQLException sqlexception
-	 */
-	private void checkAutoGeneratedKeys(int autoGeneratedKeys) throws SQLException {
-		// @formatter:off
-		if( autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS &&
-				autoGeneratedKeys != Statement.NO_GENERATED_KEYS
-				){
-			throw new SQLException();
-		}
-		// @formatter:on
-	}
-
-	/*------------------------------------*/
-	/*       Default implementation       */
-	/*------------------------------------*/
-
-	@Override public void setReadOnly(boolean readOnly) throws SQLException {
-		this.checkClosed();
-		this.readOnly = readOnly;
-	}
-
-	@Override public boolean isReadOnly() throws SQLException {
-		this.checkClosed();
-		return this.readOnly;
-	}
-
-	@Override public void setHoldability(int holdability) throws SQLException {
-		this.checkClosed();
-		this.checkHoldabilityParams(holdability);
-		this.holdability = holdability;
-	}
-
-	@Override public int getHoldability() throws SQLException {
-		this.checkClosed();
-		return this.holdability;
-	}
-
-	/**
-	 * Default implementation of setCatalog.
-	 * Neo4j doesn't implement catalog feature, so we do nothing to avoid some tools exception.
-	 */
-	@Override public void setCatalog(String catalog) throws SQLException {
-		this.checkClosed();
-		return;
-	}
-
-	/**
-	 * Default implementation of getCatalog.
-	 * Neo4j doesn't implement catalog feature, so return <code>null</code> (@see {@link java.sql.Connection#getCatalog})
-	 */
-	@Override public String getCatalog() throws SQLException {
-		this.checkClosed();
-		return null;
-	}
-
-	/**
-	 * Default implementation of getTransactionIsolation.
-	 */
-	@Override public int getTransactionIsolation() throws SQLException {
-		this.checkClosed();
-		return TRANSACTION_READ_COMMITTED;
-	}
-
-	/**
-	 * Default implementation of setTransactionIsolation.
-	 */
-	@Override public void setTransactionIsolation(int level) throws SQLException {
-		this.checkClosed();
-		this.checkTransactionIsolation(level);
-		if (level != TRANSACTION_READ_COMMITTED) {
-			throw new SQLException("Unsupported isolation level");
-		}
-	}
-
-  /**
-   * Default implementation of preparedStatement(String, int).
-   * We're just ignoring the autoGeneratedKeys param.
-   */
-	@Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
-		this.checkAutoGeneratedKeys(autoGeneratedKeys);
-		return prepareStatement(sql);
-	}
-
-	/**
-	 * Default implementation of nativeSQL.
-	 * Here we should implement some hacks for JDBC tools if needed.
-	 * This method must be used before running a query.
-	 */
-	@Override public String nativeSQL(String sql) throws SQLException {
-		return sql;
-	}
-
-	@Override public <T> T unwrap(Class<T> iface) throws SQLException {
-		return org.neo4j.jdbc.Wrapper.unwrap(iface, this);
-	}
-
-	@Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
-		return org.neo4j.jdbc.Wrapper.isWrapperFor(iface, this.getClass());
-	}
-
-	@Override public SQLWarning getWarnings() throws SQLException {
-		checkClosed();
-		return null;
-	}
-
-	@Override public void clearWarnings() throws SQLException {
-		checkClosed();
-	}
-
-	@Override public String getSchema() throws SQLException {
-		checkClosed();
-		return null;
-	}
-
-	/*---------------------------------*/
-	/*       Not implemented yet       */
-	/*---------------------------------*/
-
-	@Override public java.sql.CallableStatement prepareCall(String sql) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Map<String, Class<?>> getTypeMap() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Savepoint setSavepoint() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Savepoint setSavepoint(String name) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void rollback(Savepoint savepoint) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void releaseSavepoint(Savepoint savepoint) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Clob createClob() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Blob createBlob() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public NClob createNClob() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public SQLXML createSQLXML() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setClientInfo(String name, String value) throws SQLClientInfoException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setClientInfo(Properties properties) throws SQLClientInfoException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public String getClientInfo(String name) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Properties getClientInfo() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Neo4jArray createArrayOf(String typeName, Object[] elements) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setSchema(String schema) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void abort(Executor executor) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
-
-	@Override public int getNetworkTimeout() throws SQLException {
-		throw ExceptionBuilder.buildUnsupportedOperationException();
-	}
+	int getFlattening();
 
 }
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDatabaseMetaData.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDatabaseMetaData.java
index ee425ebd..bae489ba 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDatabaseMetaData.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDatabaseMetaData.java
@@ -30,6 +30,8 @@ import java.sql.ResultSet;
 import java.sql.RowIdLifetime;
 import java.sql.SQLException;
 import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -39,6 +41,8 @@ import java.util.regex.Pattern;
  */
 public abstract class Neo4jDatabaseMetaData implements java.sql.DatabaseMetaData {
 
+	public static final Logger LOGGER = Logger.getLogger(Neo4jDatabaseMetaData.class.getName());
+
 	/**
 	 * The regex to parse the version driver.
 	 * NUMBER + . + NUMBER + .|- + STRING
@@ -117,7 +121,7 @@ public abstract class Neo4jDatabaseMetaData implements java.sql.DatabaseMetaData
 				result = Integer.valueOf(matcher.group(position));
 			}
 		} catch (SQLException e) {
-			// silent exception, but there is the default value
+			LOGGER.log(Level.FINEST, "Silent exception", e);
 		}
 		return result;
 	}
@@ -247,11 +251,11 @@ public abstract class Neo4jDatabaseMetaData implements java.sql.DatabaseMetaData
 	}
 
 	@Override public ResultSet getSchemas() throws SQLException {
-		return new ListNeo4jResultSet(Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
+		return ListNeo4jResultSet.newInstance(false, Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
 	}
 
 	@Override public ResultSet getCatalogs() throws SQLException {
-		return new ListNeo4jResultSet(Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
+		return ListNeo4jResultSet.newInstance(false, Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
 	}
 
 	@Override public ResultSet getTableTypes() throws SQLException {
@@ -259,40 +263,42 @@ public abstract class Neo4jDatabaseMetaData implements java.sql.DatabaseMetaData
 		tableTypes.add("TABLE");
 		List<List<Object>> schemas = new ArrayList<>();
 		schemas.add(tableTypes);
-		return new ListNeo4jResultSet(schemas, Arrays.asList("TABLE_TYPE"));
+		return ListNeo4jResultSet.newInstance(false, schemas, Arrays.asList("TABLE_TYPE"));
 	}
 
 	@Override public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException {
-		return new ListNeo4jResultSet(Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
+		return ListNeo4jResultSet.newInstance(false, Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
 	}
 
 	@Override public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
 		if (this.databaseLabels == null || this.databaseLabels.isEmpty()) {
-			return new ListNeo4jResultSet(Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
+			return ListNeo4jResultSet.newInstance(false, Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
 		}
 		List<List<Object>> schemas = new ArrayList<>();
 		for (Table databaseLabel : this.databaseLabels) {
-			if ((tableNamePattern == null || "".equals(tableNamePattern) || databaseLabel.getTableName().equals(tableNamePattern)) && (types == null || (
-					types.length > 0 && Arrays.asList(types).contains(databaseLabel.getTableType())))) {
+			final boolean tableNameNotNullNorEmpty = tableNamePattern == null || "".equals(tableNamePattern);
+			final boolean typesNotNullAndContainsDBLabel = types == null || (types.length > 0 && Arrays.asList(types).contains(databaseLabel.getTableType()));
+			if ((tableNameNotNullNorEmpty || databaseLabel.getTableName().equals(tableNamePattern)) && typesNotNullAndContainsDBLabel) {
 				schemas.add(databaseLabel.toResultSetRow());
 			}
 		}
-		return new ListNeo4jResultSet(schemas, Table.getColumns());
+		return ListNeo4jResultSet.newInstance(false, schemas, Table.getColumns());
 	}
 
 	
 	@Override public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
 		if (this.databaseProperties == null || this.databaseProperties.isEmpty()) {
-			return new ListNeo4jResultSet(Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
+			return ListNeo4jResultSet.newInstance(false, Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
 		}
 		List<List<Object>> schemas = new ArrayList<>();
 		for (Column databaseKey : this.databaseProperties) {
-			if ((tableNamePattern == null || "".equals(tableNamePattern) || databaseKey.getTableName().equals(tableNamePattern)) && (columnNamePattern == null
-					|| "".equals(columnNamePattern) || databaseKey.getColumnName().equals(columnNamePattern))) {
+			final boolean tableNameNotNullNorEmpty = tableNamePattern == null || "".equals(tableNamePattern);
+			final boolean columnNameNotNullAndColumnNameMatches = columnNamePattern == null || "".equals(columnNamePattern) || databaseKey.getColumnName().equals(columnNamePattern);
+			if ((tableNameNotNullNorEmpty || databaseKey.getTableName().equals(tableNamePattern)) && columnNameNotNullAndColumnNameMatches) {
 				schemas.add(databaseKey.toResultSetRow());
 			}
 		}
-		return new ListNeo4jResultSet(schemas, Column.getColumns());
+		return ListNeo4jResultSet.newInstance(false, schemas, Column.getColumns());
 	}
 
 	@Override public String getSearchStringEscape() throws SQLException {
@@ -722,7 +728,7 @@ public abstract class Neo4jDatabaseMetaData implements java.sql.DatabaseMetaData
 	}
 
 	@Override public ResultSet getTypeInfo() throws SQLException {
-		return new ListNeo4jResultSet(Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
+		return ListNeo4jResultSet.newInstance(false, Collections.<List<Object>>emptyList(), Collections.<String>emptyList());
 	}
 
 	@Override public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException {
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDriver.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDriver.java
index 59447f79..e7cd240f 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDriver.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jDriver.java
@@ -24,7 +24,6 @@ import org.neo4j.jdbc.utils.Neo4jJdbcRuntimeException;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
-import java.sql.DriverManager;
 import java.sql.DriverPropertyInfo;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
@@ -52,9 +51,8 @@ public abstract class Neo4jDriver implements java.sql.Driver {
 	 * Constructor for extended class.
 	 *
 	 * @param prefix Prefix of the driver for the connection url.
-	 * @throws SQLException sqlexception
 	 */
-	protected Neo4jDriver(String prefix) throws SQLException {
+	protected Neo4jDriver(String prefix) {
 		this.driverPrefix = prefix;
 	}
 
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jPreparedStatement.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jPreparedStatement.java
index aa315db4..fc7e6ba6 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jPreparedStatement.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jPreparedStatement.java
@@ -39,7 +39,7 @@ import static java.sql.Types.*;
  * @author AgileLARUS
  * @since 3.0.0
  */
-public abstract class Neo4jPreparedStatement extends Neo4jStatement implements java.sql.PreparedStatement {
+public abstract class Neo4jPreparedStatement extends Neo4jStatement implements PreparedStatement {
 
 	protected String                    statement;
 	protected HashMap<String, Object>   parameters;
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jResultSet.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jResultSet.java
index 71710dbe..932fe680 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jResultSet.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jResultSet.java
@@ -33,17 +33,39 @@ import java.util.Map;
  * @author AgileLARUS
  * @since 3.0.0
  */
-public abstract class Neo4jResultSet implements java.sql.ResultSet {
+public abstract class Neo4jResultSet implements ResultSet, Loggable {
+
+	public static final int DEFAULT_TYPE        = TYPE_FORWARD_ONLY;
+	public static final int DEFAULT_CONCURRENCY = CONCUR_READ_ONLY;
+	public static final int DEFAULT_HOLDABILITY = CLOSE_CURSORS_AT_COMMIT;
+
+	protected static final int    DEFAULT_FETCH_SIZE = 1;
+	protected static final String COLUMN_NOT_PRESENT = "Column not present in ResultSet";
 
 	/**
 	 * Close state of this ResultSet.
 	 */
-	protected boolean isClosed = false;
+	protected boolean isClosed         = false;
+	protected int     currentRowNumber = 0;
+	protected boolean debug;
+	protected int     debugLevel;
+	protected int     type;
+	protected int     concurrency;
+	protected int     holdability;
 
-	protected int currentRowNumber = 0;
+	protected Statement statement;
 
-	protected static final int DEFAULT_FETCH_SIZE = 1;
+	/**
+	 * Is the last read column was null.
+	 */
+	protected boolean wasNull = false;
 
+	public Neo4jResultSet(Statement statement, int... params) {
+		this.statement = statement;
+		this.type = params.length > 0 ? params[0] : TYPE_FORWARD_ONLY;
+		this.concurrency = params.length > 1 ? params[1] : CONCUR_READ_ONLY;
+		this.holdability = params.length > 2 ? params[2] : CLOSE_CURSORS_AT_COMMIT;
+	}
 
 	/*----------------------------------------*/
 	/*       Some useful, check method        */
@@ -92,7 +114,7 @@ public abstract class Neo4jResultSet implements java.sql.ResultSet {
 		checkClosed();
 	}
 
-	@Override public final boolean next() throws SQLException {
+	@Override public boolean next() throws SQLException {
 		boolean result = innerNext();
 		if (result) {
 			currentRowNumber++;
@@ -750,4 +772,19 @@ public abstract class Neo4jResultSet implements java.sql.ResultSet {
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
 
+	@Override public boolean hasDebug() {
+		return this.debug;
+	}
+
+	@Override public void setDebug(boolean debug) {
+		this.debug = debug;
+	}
+
+	@Override public void setDebugLevel(int debugLevel) {
+		this.debugLevel = debugLevel;
+	}
+
+	@Override public int getDebugLevel() {
+		return this.debugLevel;
+	}
 }
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jStatement.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jStatement.java
index bb1e282e..fc50ccbf 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jStatement.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Neo4jStatement.java
@@ -19,23 +19,27 @@
  */
 package org.neo4j.jdbc;
 
+import org.neo4j.jdbc.utils.ExceptionBuilder;
+
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLWarning;
+import java.sql.Statement;
 import java.util.List;
 
-import org.neo4j.jdbc.utils.ExceptionBuilder;
-
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
-public abstract class Neo4jStatement implements java.sql.Statement {
+public abstract class Neo4jStatement implements Statement, Loggable {
 
 	protected Neo4jConnection connection;
 	protected ResultSet       currentResultSet;
 	protected int             currentUpdateCount;
 	protected List<String>    batchStatements;
+	protected boolean         debug;
+	protected int             debugLevel;
+	protected int[]           resultSetParams;
 	private   int             maxRows;
 	private   int             queryTimeout;
 
@@ -58,6 +62,7 @@ public abstract class Neo4jStatement implements java.sql.Statement {
 	/**
 	 * Check if this statement is closed or not.
 	 * If it is, we throw an exception.
+	 *
 	 * @throws SQLException sqlexception
 	 */
 	protected void checkClosed() throws SQLException {
@@ -154,7 +159,7 @@ public abstract class Neo4jStatement implements java.sql.Statement {
 	 */
 	@Override public boolean getMoreResults() throws SQLException {
 		this.checkClosed();
-		return !( this.currentResultSet == null && this.currentUpdateCount == -1 );
+		return !(this.currentResultSet == null && this.currentUpdateCount == -1);
 	}
 
 	/**
@@ -176,6 +181,7 @@ public abstract class Neo4jStatement implements java.sql.Statement {
 
 	/**
 	 * Added just for value memorization
+	 *
 	 * @return the current query timeout limit in seconds; zero means there is no limit
 	 * @throws SQLException if a database error occurs
 	 */
@@ -185,8 +191,9 @@ public abstract class Neo4jStatement implements java.sql.Statement {
 
 	/**
 	 * Added just for value memorization
-   * @param seconds the new query timeout limit in seconds; zero means there is no limit
-   * @exception SQLException if a database error occurs
+	 *
+	 * @param seconds the new query timeout limit in seconds; zero means there is no limit
+	 * @throws SQLException if a database error occurs
 	 */
 	@Override public void setQueryTimeout(int seconds) throws SQLException {
 		this.queryTimeout = seconds;
@@ -202,6 +209,39 @@ public abstract class Neo4jStatement implements java.sql.Statement {
 		this.batchStatements.clear();
 	}
 
+	@Override public int getResultSetConcurrency() throws SQLException {
+		this.checkClosed();
+		if (currentResultSet != null) {
+			return currentResultSet.getConcurrency();
+		}
+		if (this.resultSetParams.length > 1) {
+			return this.resultSetParams[1];
+		}
+		return Neo4jResultSet.DEFAULT_CONCURRENCY;
+	}
+
+	@Override public int getResultSetType() throws SQLException {
+		this.checkClosed();
+		if (currentResultSet != null) {
+			return currentResultSet.getType();
+		}
+		if (this.resultSetParams.length > 0) {
+			return this.resultSetParams[0];
+		}
+		return Neo4jResultSet.DEFAULT_TYPE;
+	}
+
+	@Override public int getResultSetHoldability() throws SQLException {
+		this.checkClosed();
+		if (currentResultSet != null) {
+			return currentResultSet.getHoldability();
+		}
+		if (this.resultSetParams.length > 2) {
+			return this.resultSetParams[2];
+		}
+		return Neo4jResultSet.DEFAULT_HOLDABILITY;
+	}
+
 	/*---------------------------------*/
 	/*       Not implemented yet       */
 	/*---------------------------------*/
@@ -290,4 +330,19 @@ public abstract class Neo4jStatement implements java.sql.Statement {
 		throw ExceptionBuilder.buildUnsupportedOperationException();
 	}
 
+	@Override public boolean hasDebug() {
+		return this.debug;
+	}
+
+	@Override public void setDebug(boolean debug) {
+		this.debug = debug;
+	}
+
+	@Override public void setDebugLevel(int level) {
+		this.debugLevel = level;
+	}
+
+	@Override public int getDebugLevel() {
+		return this.debugLevel;
+	}
 }
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Wrapper.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Wrapper.java
index 989fddcc..98c157be 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Wrapper.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/Wrapper.java
@@ -25,7 +25,7 @@ import java.sql.SQLException;
  * @author AgileLARUS
  * @since 3.0.0
  */
-class Wrapper {
+public class Wrapper {
 
 	private Wrapper() {};
 
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/impl/ListNeo4jResultSet.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/impl/ListNeo4jResultSet.java
index 78347a6b..64b9ad97 100644
--- a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/impl/ListNeo4jResultSet.java
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/impl/ListNeo4jResultSet.java
@@ -22,8 +22,12 @@ package org.neo4j.jdbc.impl;
 import org.neo4j.jdbc.Neo4jArray;
 import org.neo4j.jdbc.Neo4jResultSet;
 import org.neo4j.jdbc.Neo4jResultSetMetaData;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
 
+import java.lang.reflect.Proxy;
+import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.List;
 
 /**
@@ -38,11 +42,18 @@ public class ListNeo4jResultSet extends Neo4jResultSet {
 	private boolean closed = false;
 	private List<String> keys;
 
-	public ListNeo4jResultSet(List<List<Object>> list, List<String> keys) {
+	private ListNeo4jResultSet(List<List<Object>> list, List<String> keys) {
+		super(null);
 		this.list = list;
 		this.keys = keys;
 	}
 
+	public static ResultSet newInstance(boolean debug, List<List<Object>> list, List<String> keys) {
+		ResultSet rs = new ListNeo4jResultSet(list, keys);
+		return (ResultSet) Proxy
+				.newProxyInstance(ListNeo4jResultSet.class.getClassLoader(), new Class[] { ResultSet.class }, new Neo4jInvocationHandler(rs, debug));
+	}
+
 	@Override protected boolean innerNext() throws SQLException {
 		return ++this.index < this.list.size();
 	}
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/impl/Neo4jConnectionImpl.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/impl/Neo4jConnectionImpl.java
new file mode 100644
index 00000000..687cfe38
--- /dev/null
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/impl/Neo4jConnectionImpl.java
@@ -0,0 +1,464 @@
+/**
+ * Copyright (c) 2016 LARUS Business Automation [http://www.larus-ba.it]
+ * <p>
+ * This file is part of the "LARUS Integration Framework for Neo4j".
+ * <p>
+ * The "LARUS Integration Framework for Neo4j" is licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * <p>
+ * Created on 27/12/17
+ */
+package org.neo4j.jdbc.impl;
+
+import org.neo4j.jdbc.Neo4jArray;
+import org.neo4j.jdbc.Neo4jConnection;
+import org.neo4j.jdbc.Neo4jResultSet;
+import org.neo4j.jdbc.utils.ExceptionBuilder;
+
+import java.sql.*;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+/**
+ * @author Gianmarco Laggia @ Larus B.A.
+ * @since 3.2.0
+ */
+public abstract class Neo4jConnectionImpl implements Neo4jConnection {
+	/**
+	 * JDBC Url used for this connection
+	 */
+	private String url;
+
+	/**
+	 * JDBC driver properties
+	 */
+	private Properties properties;
+
+	/**
+	 * Is the connection is in readonly mode ?
+	 */
+	private boolean readOnly = false;
+
+	/**
+	 * Holdability of the connection
+	 */
+	private int holdability;
+
+	protected static final String FASTEST_STATEMENT = "RETURN 1";
+
+	/**
+	 * Default constructor with properties.
+	 *
+	 * @param properties driver properties
+	 * @param url connection url
+	 * @param defaultHoldability connection holdability
+	 */
+	protected Neo4jConnectionImpl(Properties properties, String url, int defaultHoldability) {
+		this.url = url;
+		this.properties = properties;
+		this.holdability = defaultHoldability;
+	}
+
+	public static boolean hasDebug(Properties properties) {
+		return "true".equalsIgnoreCase(properties.getProperty("debug", "false"));
+	}
+
+	/**
+	 * Get the connection url.
+	 *
+	 * @return String the connection url
+	 */
+	public String getUrl() {
+		return url;
+	}
+
+	/**
+	 * Get the properties for this connection.
+	 *
+	 * @return Properties the properties for this connection
+	 */
+	public Properties getProperties() {
+		return properties;
+	}
+
+	/**
+	 * Get the user of this connection.
+	 *
+	 * @return String
+	 */
+	public String getUserName() {
+		return properties.getProperty("user");
+	}
+
+	/**
+	 * Get the flattening sample rows (-1 if no flattening).
+	 *
+	 * @return int
+	 */
+	public int getFlattening() {
+		String flatten = properties.getProperty("flatten");
+		return flatten == null ? 0 : Integer.parseInt(flatten);
+	}
+
+	/*---------------------------------------*/
+	/*       Some useful check method        */
+	/*---------------------------------------*/
+
+	/**
+	 * Check if this connection is closed or not.
+	 * If it's closed, then we throw a SQLException, otherwise we do nothing.
+	 * @throws SQLException sqlexception
+	 */
+	protected void checkClosed() throws SQLException {
+		if (this.isClosed()) {
+			throw new SQLException("Connection already closed");
+		}
+	}
+
+	/**
+	 * Method to check if we are into autocommit mode.
+	 * If we do, then it throw an exception.
+	 * This method is for using into commit and rollback method.
+	 * @throws SQLException sqlexception
+	 */
+	protected void checkAutoCommit() throws SQLException {
+		if (this.getAutoCommit()) {
+			throw new SQLException("Cannot commit when in autocommit");
+		}
+	}
+
+	/**
+	 * Check if can execute the query into the current mode (ie. readonly or not).
+	 * If we can't an SQLException is throw.
+	 *
+	 * @param query Cypher query
+	 * @throws SQLException sqlexception
+	 */
+	protected void checkReadOnly(String query) throws SQLException {
+		if (isReadOnly() && isMutating(query)) {
+			throw new SQLException("Mutating Query in readonly mode: " + query);
+		}
+	}
+
+	/**
+	 * Detect some cypher keyword to know if this query mutated the graph.
+	 * /!\ This not enough now due to procedure procedure.
+	 *
+	 * @param query Cypher query
+	 * @return
+	 */
+	private boolean isMutating(String query) {
+		return query.matches("(?is).*\\b(create|relate|delete|set)\\b.*");
+	}
+
+	/**
+	 * Check if the holdability parameter conform to specification.
+	 * If it doesn't, we throw an exception.
+	 * {@link java.sql.Connection#setHoldability(int)}
+	 *
+	 * @param resultSetHoldability The holdability value to check
+	 * @throws SQLException sqlexception
+	 */
+	protected void checkHoldabilityParams(int resultSetHoldability) throws SQLException {
+		// @formatter:off
+		if( resultSetHoldability != Neo4jResultSet.HOLD_CURSORS_OVER_COMMIT &&
+			resultSetHoldability != Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT
+		){
+			throw new SQLFeatureNotSupportedException();
+		}
+		// @formatter:on
+	}
+
+	/**
+	 * Check if the concurrency parameter conform to specification.
+	 * If it doesn't, we throw an exception.
+	 *
+	 * @param resultSetConcurrency The concurrency value to check
+	 * @throws SQLException sqlexception
+	 */
+	protected void checkConcurrencyParams(int resultSetConcurrency) throws SQLException {
+		// @formatter:off
+		if( resultSetConcurrency != Neo4jResultSet.CONCUR_UPDATABLE &&
+			resultSetConcurrency != Neo4jResultSet.CONCUR_READ_ONLY
+		){
+			throw new SQLFeatureNotSupportedException();
+		}
+		// @formatter:on
+	}
+
+	/**
+	 * Check if the resultset type parameter conform to specification.
+	 * If it doesn't, we throw an exception.
+	 *
+	 * @param resultSetType The concurrency value to check
+	 * @throws SQLException sqlexception
+	 */
+	protected void checkTypeParams(int resultSetType) throws SQLException {
+		// @formatter:off
+		if( resultSetType != Neo4jResultSet.TYPE_FORWARD_ONLY &&
+			resultSetType != Neo4jResultSet.TYPE_SCROLL_INSENSITIVE &&
+			resultSetType != Neo4jResultSet.TYPE_SCROLL_SENSITIVE
+		){
+			throw new SQLFeatureNotSupportedException();
+		}
+		// @formatter:on
+	}
+
+	/**
+	 * Check if the transaction isolation level parameter conform to specification.
+	 * If it doesn't, we throw an exception.
+	 *
+	 * @param level The transaction isolation level value to check
+	 * @throws SQLException sqlexception
+	 */
+	protected void checkTransactionIsolation(int level) throws SQLException {
+		// @formatter:off
+		int[] invalid = {
+			TRANSACTION_NONE,
+			TRANSACTION_READ_COMMITTED,
+			TRANSACTION_READ_UNCOMMITTED,
+			TRANSACTION_REPEATABLE_READ,
+			TRANSACTION_SERIALIZABLE
+		};
+
+		if(!Arrays.asList(invalid).contains(level)){
+			throw new SQLException();
+		}
+		// @formatter:on
+	}
+
+	/**
+	 * Check if the auto generated keys parameter conform to specification.
+	 * If it doesn't, we throw an exception.
+	 *
+	 * @param autoGeneratedKeys the auto generated keys value to check
+	 * @throws SQLException sqlexception
+	 */
+	private void checkAutoGeneratedKeys(int autoGeneratedKeys) throws SQLException {
+		// @formatter:off
+		if( autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS &&
+				autoGeneratedKeys != Statement.NO_GENERATED_KEYS
+				){
+			throw new SQLException();
+		}
+		// @formatter:on
+	}
+
+	/*------------------------------------*/
+	/*       Default implementation       */
+	/*------------------------------------*/
+
+	@Override public void setReadOnly(boolean readOnly) throws SQLException {
+		this.checkClosed();
+		this.readOnly = readOnly;
+	}
+
+	@Override public boolean isReadOnly() throws SQLException {
+		this.checkClosed();
+		return this.readOnly;
+	}
+
+	@Override public void setHoldability(int holdability) throws SQLException {
+		this.checkClosed();
+		this.checkHoldabilityParams(holdability);
+		this.holdability = holdability;
+	}
+
+	@Override public int getHoldability() throws SQLException {
+		this.checkClosed();
+		return this.holdability;
+	}
+
+	/**
+	 * Default implementation of setCatalog.
+	 * Neo4j doesn't implement catalog feature, so we do nothing to avoid some tools exception.
+	 */
+	@Override public void setCatalog(String catalog) throws SQLException {
+		this.checkClosed();
+		return;
+	}
+
+	/**
+	 * Default implementation of getCatalog.
+	 * Neo4j doesn't implement catalog feature, so return <code>null</code> (@see {@link java.sql.Connection#getCatalog})
+	 */
+	@Override public String getCatalog() throws SQLException {
+		this.checkClosed();
+		return null;
+	}
+
+	/**
+	 * Default implementation of getTransactionIsolation.
+	 */
+	@Override public int getTransactionIsolation() throws SQLException {
+		this.checkClosed();
+		return TRANSACTION_READ_COMMITTED;
+	}
+
+	/**
+	 * Default implementation of setTransactionIsolation.
+	 */
+	@Override public void setTransactionIsolation(int level) throws SQLException {
+		this.checkClosed();
+		this.checkTransactionIsolation(level);
+		if (level != TRANSACTION_READ_COMMITTED) {
+			throw new SQLException("Unsupported isolation level");
+		}
+	}
+
+	/**
+	 * Default implementation of preparedStatement(String, int).
+	 * We're just ignoring the autoGeneratedKeys param.
+	 */
+	@Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+		this.checkAutoGeneratedKeys(autoGeneratedKeys);
+		return prepareStatement(sql);
+	}
+
+	/**
+	 * Default implementation of nativeSQL.
+	 * Here we should implement some hacks for JDBC tools if needed.
+	 * This method must be used before running a query.
+	 */
+	@Override public String nativeSQL(String sql) throws SQLException {
+		return sql;
+	}
+
+	@Override public <T> T unwrap(Class<T> iface) throws SQLException {
+		return org.neo4j.jdbc.Wrapper.unwrap(iface, this);
+	}
+
+	@Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
+		return org.neo4j.jdbc.Wrapper.isWrapperFor(iface, this.getClass());
+	}
+
+	@Override public SQLWarning getWarnings() throws SQLException {
+		checkClosed();
+		return null;
+	}
+
+	@Override public void clearWarnings() throws SQLException {
+		checkClosed();
+	}
+
+	@Override public String getSchema() throws SQLException {
+		checkClosed();
+		return null;
+	}
+
+	/*---------------------------------*/
+	/*       Not implemented yet       */
+	/*---------------------------------*/
+
+	@Override public java.sql.CallableStatement prepareCall(String sql) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Map<String, Class<?>> getTypeMap() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Savepoint setSavepoint() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Savepoint setSavepoint(String name) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void rollback(Savepoint savepoint) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Clob createClob() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Blob createBlob() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public NClob createNClob() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public SQLXML createSQLXML() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void setClientInfo(String name, String value) throws SQLClientInfoException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void setClientInfo(Properties properties) throws SQLClientInfoException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public String getClientInfo(String name) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Properties getClientInfo() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Neo4jArray createArrayOf(String typeName, Object[] elements) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void setSchema(String schema) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void abort(Executor executor) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+	@Override public int getNetworkTimeout() throws SQLException {
+		throw ExceptionBuilder.buildUnsupportedOperationException();
+	}
+
+}
diff --git a/neo4j-jdbc/src/main/java/org/neo4j/jdbc/utils/Neo4jInvocationHandler.java b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/utils/Neo4jInvocationHandler.java
new file mode 100644
index 00000000..820218df
--- /dev/null
+++ b/neo4j-jdbc/src/main/java/org/neo4j/jdbc/utils/Neo4jInvocationHandler.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2016 LARUS Business Automation [http://www.larus-ba.it]
+ * <p>
+ * This file is part of the "LARUS Integration Framework for Neo4j".
+ * <p>
+ * The "LARUS Integration Framework for Neo4j" is licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * <p>
+ * Created on 22/12/17
+ */
+package org.neo4j.jdbc.utils;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * @author Gianmarco Laggia @ Larus B.A.
+ * @since 3.2.0
+ */
+public class Neo4jInvocationHandler implements InvocationHandler {
+
+	private static final Logger LOGGER = Logger.getLogger(Neo4jInvocationHandler.class.getName());
+
+	private final Map<String, Method> methods = new HashMap<>();
+
+	private Object  target;
+	private boolean debug;
+
+	public Neo4jInvocationHandler(Object target, boolean debug) {
+		this.target = target;
+		this.debug = debug;
+
+		for (Method method : target.getClass().getMethods()) {
+			String key = getUniqueKeyFromMethod(method);
+			this.methods.put(key, method);
+		}
+	}
+
+	@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+		try {
+			Object result = methods.get(getUniqueKeyFromMethod(method)).invoke(target, args);
+
+			if (debug) {
+				LOGGER.info("[" + target.getClass().getCanonicalName() + "] " + method.getName());
+			}
+
+			return result;
+		} catch (InvocationTargetException e) {
+			throw e.getCause();
+		}
+	}
+
+	private String getUniqueKeyFromMethod(Method method) {
+		String key = method.getName() + "_";
+		for(Class type : method.getParameterTypes()) {
+			key += type.getCanonicalName() + "_";
+		}
+		return key;
+	}
+}


Test patch:
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jCallableStatementTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jCallableStatementTest.java
deleted file mode 100644
index a35b3de7..00000000
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jCallableStatementTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2016 LARUS Business Automation [http://www.larus-ba.it]
- * <p>
- * This file is part of the "LARUS Integration Framework for Neo4j".
- * <p>
- * The "LARUS Integration Framework for Neo4j" is licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * <p>
- * Created on 21/04/16
- */
-package org.neo4j.jdbc.bolt;
-
-import org.neo4j.jdbc.Neo4jCallableStatement;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import java.sql.SQLException;
-
-/**
- * @author AgileLARUS
- *
- * @since 3.0.0
- */
-public class BoltNeo4jCallableStatementTest {
-
-	@Rule public ExpectedException expectedEx = ExpectedException.none();
-
-	/*------------------------------*/
-	/*           addBatch           */
-	/*------------------------------*/
-
-	@Ignore @Test public void addBatchShouldThrowException() throws SQLException {
-		expectedEx.expect(SQLException.class);
-
-		Neo4jCallableStatement stmt = new BoltNeo4jCallableStatement();
-		stmt.addBatch("");
-	}
-}
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jConnectionTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jConnectionTest.java
index 8b10f9fb..a4fe190a 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jConnectionTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jConnectionTest.java
@@ -31,6 +31,7 @@ import org.neo4j.driver.internal.spi.*;
 import org.neo4j.driver.v1.AccessMode;
 import org.neo4j.driver.v1.Session;
 import org.neo4j.jdbc.bolt.data.StatementData;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
 
 import java.sql.*;
 import java.sql.Connection;
@@ -47,16 +48,16 @@ public class BoltNeo4jConnectionTest {
 
 	@Rule public ExpectedException expectedEx = ExpectedException.none();
 
-	private BoltNeo4jConnection openConnection;
-	private BoltNeo4jConnection closedConnection;
-	private BoltNeo4jConnection slowOpenConnection;
-	private BoltNeo4jConnection exceptionOpenConnection;
+	private BoltNeo4jConnectionImpl openConnection;
+	private BoltNeo4jConnectionImpl closedConnection;
+	private BoltNeo4jConnectionImpl slowOpenConnection;
+	private BoltNeo4jConnectionImpl exceptionOpenConnection;
 
 	@Before public void tearUp() {
-		openConnection = new BoltNeo4jConnection(mockSessionOpen());
-		closedConnection = new BoltNeo4jConnection(mockSessionClosed());
-		slowOpenConnection = new BoltNeo4jConnection(mockSessionOpenSlow());
-		exceptionOpenConnection = new BoltNeo4jConnection(mockSessionException());
+		openConnection = new BoltNeo4jConnectionImpl(mockSessionOpen());
+		closedConnection = new BoltNeo4jConnectionImpl(mockSessionClosed());
+		slowOpenConnection = new BoltNeo4jConnectionImpl(mockSessionOpenSlow());
+		exceptionOpenConnection = new BoltNeo4jConnectionImpl(mockSessionException());
 	}
 
 	/*------------------------------*/
@@ -106,7 +107,7 @@ public class BoltNeo4jConnectionTest {
 	@Test public void closeShouldCloseConnection() throws SQLException {
 		Session session = mock(Session.class);
 		when(session.isOpen()).thenReturn(true).thenReturn(false);
-		Connection connection = new BoltNeo4jConnection(session);
+		Connection connection = new BoltNeo4jConnectionImpl(session);
 		connection.close();
 		verify(session, times(1)).close();
 		assertTrue(connection.isClosed());
@@ -114,7 +115,7 @@ public class BoltNeo4jConnectionTest {
 
 	@Test public void closeShouldNotThrowExceptionWhenClosingAClosedConnection() throws SQLException {
 		Session session = mockSessionClosed();
-		Connection connection = new BoltNeo4jConnection(session);
+		Connection connection = new BoltNeo4jConnectionImpl(session);
 		connection.close();
 		verify(session, never()).close();
 		assertTrue(connection.isClosed());
@@ -130,7 +131,7 @@ public class BoltNeo4jConnectionTest {
 		when(connectionProvider.acquireConnection(AccessMode.READ)).thenReturn(boltConnection);
 		Session session = new NetworkSession(connectionProvider, AccessMode.READ, null, DevNullLogging.DEV_NULL_LOGGING);
 		session.run("return 1");
-		Connection connection = new BoltNeo4jConnection(session);
+		Connection connection = new BoltNeo4jConnectionImpl(session);
 		connection.close();
 	}
 
@@ -184,10 +185,10 @@ public class BoltNeo4jConnectionTest {
 	/*------------------------------*/
 
 	@Test public void createStatementNoParamsShouldReturnNewStatement() throws SQLException {
-		Connection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.createStatement();
 
-		assertTrue(statement instanceof BoltNeo4jStatement);
+		assertNotNull(statement);
 		assertEquals(connection.getHoldability(), statement.getResultSetHoldability());
 		assertEquals(ResultSet.CONCUR_READ_ONLY, statement.getResultSetConcurrency());
 		assertEquals(ResultSet.TYPE_FORWARD_ONLY, statement.getResultSetType());
@@ -199,7 +200,7 @@ public class BoltNeo4jConnectionTest {
 	}
 
 	@Test public void createStatementTwoParamsShouldReturnNewStatement() throws SQLException {
-		Connection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		int[] types = { ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE };
 		int[] concurrencies = { ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY };
 
@@ -250,7 +251,7 @@ public class BoltNeo4jConnectionTest {
 	}
 
 	@Test public void createStatementThreeParamsShouldReturnNewStatement() throws SQLException {
-		Connection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		int[] types = { ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE };
 		int[] concurrencies = { ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY };
 		int[] holdabilities = { ResultSet.HOLD_CURSORS_OVER_COMMIT, ResultSet.CLOSE_CURSORS_AT_COMMIT };
@@ -315,10 +316,10 @@ public class BoltNeo4jConnectionTest {
 			}
 		}
 	}
-	
+
 	@Ignore
 	@Test public void createStatementWithWrongSyntax() throws SQLException {
-		try (Connection connection = new BoltNeo4jConnection(mockSessionOpen())) {
+		try (Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen())) {
 			try {
 				boolean ret = connection.createStatement().execute("CREATE (n:Test {name:'TEST'}) SET n.p1 = 'A1', n.。p2 = 'A2';");
 				System.out.println("execute ret: " + ret);
@@ -341,10 +342,10 @@ public class BoltNeo4jConnectionTest {
 	/*------------------------------*/
 
 	@Test public void prepareStatementNoParamsShouldReturnNewStatement() throws SQLException {
-		Connection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareStatement(StatementData.STATEMENT_MATCH_ALL_STRING_PARAMETRIC);
 
-		assertTrue(statement instanceof BoltNeo4jPreparedStatement);
+		assertNotNull(statement);
 		assertEquals(connection.getHoldability(), statement.getResultSetHoldability());
 		assertEquals(ResultSet.CONCUR_READ_ONLY, statement.getResultSetConcurrency());
 		assertEquals(ResultSet.TYPE_FORWARD_ONLY, statement.getResultSetType());
@@ -356,7 +357,7 @@ public class BoltNeo4jConnectionTest {
 	}
 
 	@Test public void prepareStatementTwoParamsShouldReturnNewStatement() throws SQLException {
-		Connection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		int[] types = { ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE };
 		int[] concurrencies = { ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY };
 
@@ -407,7 +408,7 @@ public class BoltNeo4jConnectionTest {
 	}
 
 	@Test public void prepareStatementThreeParamsShouldReturnNewStatement() throws SQLException {
-		Connection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		int[] types = { ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE };
 		int[] concurrencies = { ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY };
 		int[] holdabilities = { ResultSet.HOLD_CURSORS_OVER_COMMIT, ResultSet.CLOSE_CURSORS_AT_COMMIT };
@@ -485,7 +486,7 @@ public class BoltNeo4jConnectionTest {
 		expectedEx.expect(SQLException.class);
 
 		Session session = new NetworkSession(null, AccessMode.READ,null, DevNullLogging.DEV_NULL_LOGGING);
-		Connection connection = new BoltNeo4jConnection(session);
+		Connection connection = new BoltNeo4jConnectionImpl(session);
 		connection.setAutoCommit(true);
 	}
 
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaDataTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaDataTest.java
index d45dcb1a..ac4a1fd1 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaDataTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jDatabaseMetaDataTest.java
@@ -21,6 +21,7 @@ package org.neo4j.jdbc.bolt;
 
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
 
 import java.sql.SQLException;
 
@@ -41,7 +42,7 @@ public class BoltNeo4jDatabaseMetaDataTest {
 	/*------------------------------*/
 
 	@Test public void getConnectionShouldGetConnection() throws SQLException, NoSuchFieldException, IllegalAccessException {
-		BoltNeo4jConnection connection = Mockito.mock(BoltNeo4jConnection.class);
+		BoltNeo4jConnectionImpl connection = Mockito.mock(BoltNeo4jConnectionImpl.class);
 		BoltNeo4jDatabaseMetaData boltDatabaseMetaData = new BoltNeo4jDatabaseMetaData(connection);
 
 		assertEquals(connection, boltDatabaseMetaData.getConnection());
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jParameterMetaDataTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jParameterMetaDataTest.java
deleted file mode 100644
index f33bfe6a..00000000
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jParameterMetaDataTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2016 LARUS Business Automation [http://www.larus-ba.it]
- * <p>
- * This file is part of the "LARUS Integration Framework for Neo4j".
- * <p>
- * The "LARUS Integration Framework for Neo4j" is licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * <p>
- * Created on 24/03/16
- */
-package org.neo4j.jdbc.bolt;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.powermock.api.mockito.PowerMockito.mock;
-
-/**
- * @author AgileLARUS
- * @since 3.0.0
- */
-public class BoltNeo4jParameterMetaDataTest {
-
-	BoltNeo4jParameterMetaData boltParameterMetaData;
-
-	@Rule public ExpectedException expectedEx = ExpectedException.none();
-
-	@Before public void setUp() {
-		BoltNeo4jPreparedStatement preparedStatement = mock(BoltNeo4jPreparedStatement.class);
-		boltParameterMetaData = new BoltNeo4jParameterMetaData(preparedStatement);
-	}
-
-	@Test public void isLoggableTest() {
-		assertFalse(boltParameterMetaData.isLoggable());
-	}
-
-	@Test public void setLoggableTest() {
-		assertFalse(boltParameterMetaData.isLoggable());
-		boltParameterMetaData.setLoggable(true);
-		assertTrue(boltParameterMetaData.isLoggable());
-		boltParameterMetaData.setLoggable(false);
-		assertFalse(boltParameterMetaData.isLoggable());
-	}
-
-}
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatementTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatementTest.java
index 52828cd7..de280cbc 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatementTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jPreparedStatementTest.java
@@ -19,9 +19,6 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import org.neo4j.jdbc.Neo4jPreparedStatement;
-import org.neo4j.jdbc.bolt.data.StatementData;
-import org.neo4j.jdbc.bolt.utils.Mocker;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -32,54 +29,82 @@ import org.neo4j.driver.v1.Session;
 import org.neo4j.driver.v1.StatementResult;
 import org.neo4j.driver.v1.summary.ResultSummary;
 import org.neo4j.driver.v1.summary.SummaryCounters;
+import org.neo4j.jdbc.Neo4jStatement;
+import org.neo4j.jdbc.bolt.data.StatementData;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
+import org.neo4j.jdbc.bolt.utils.Mocker;
+import org.neo4j.jdbc.utils.PreparedStatementBuilder;
+import org.powermock.api.mockito.PowerMockito;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 import org.powermock.reflect.Whitebox;
 
-import java.sql.BatchUpdateException;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
+import java.sql.*;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 
-import static org.neo4j.jdbc.bolt.utils.Mocker.*;
 import static java.sql.Types.*;
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
-import static org.powermock.api.mockito.PowerMockito.verifyNew;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.neo4j.jdbc.bolt.utils.Mocker.*;
+import static org.powermock.api.mockito.PowerMockito.*;
 
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
-@RunWith(PowerMockRunner.class) @PrepareForTest({ BoltNeo4jPreparedStatement.class, BoltNeo4jResultSet.class }) public class BoltNeo4jPreparedStatementTest {
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ BoltNeo4jPreparedStatement.class, BoltNeo4jResultSet.class })
+public class BoltNeo4jPreparedStatementTest {
 
-	@Rule public ExpectedException expectedEx = ExpectedException.none();
+	@Rule
+	public ExpectedException expectedEx = ExpectedException.none();
 
-	private Neo4jPreparedStatement preparedStatementOneParam;
-	private Neo4jPreparedStatement preparedStatementTwoParams;
+	private PreparedStatement preparedStatementOneParam;
+	private PreparedStatement preparedStatementTwoParams;
 
 	private BoltNeo4jResultSet mockedRS;
 
 	@Before public void interceptBoltResultSetConstructor() throws Exception {
-		this.preparedStatementOneParam = new BoltNeo4jPreparedStatement(mockConnectionOpenWithTransactionThatReturns(null), "MATCH n RETURN n WHERE n.name = ?");
-		this.preparedStatementTwoParams = new BoltNeo4jPreparedStatement(mockConnectionOpenWithTransactionThatReturns(null),
-				"MATCH n RETURN n WHERE n.name = ? AND n.surname = ?");
+		preparedStatementOneParam = mock(BoltNeo4jPreparedStatement.class, CALLS_REAL_METHODS);
+		Whitebox.setInternalState(preparedStatementOneParam, "batchStatements", new ArrayList<>());
+		String statementOneParam = "MATCH n RETURN n WHERE n.name = ?";
+		String replacedStatementOneParam = PreparedStatementBuilder.replacePlaceholders(statementOneParam);
+		Whitebox.setInternalState(preparedStatementOneParam, "statement", replacedStatementOneParam);
+		Whitebox.setInternalState(preparedStatementOneParam, "connection", mockConnectionOpenWithTransactionThatReturns(null));
+		Whitebox.setInternalState(preparedStatementOneParam, "parametersNumber", PreparedStatementBuilder.namedParameterCount(replacedStatementOneParam));
+		Whitebox.setInternalState(preparedStatementOneParam, "parameters", new HashMap<>());
+
+		preparedStatementTwoParams = mock(BoltNeo4jPreparedStatement.class, CALLS_REAL_METHODS);
+		Whitebox.setInternalState(preparedStatementTwoParams, "batchStatements", new ArrayList<>());
+		String statementTwoParams = "MATCH n RETURN n WHERE n.name = ? AND n.surname = ?";
+		String replacedStatementTwoParams = PreparedStatementBuilder.replacePlaceholders(statementTwoParams);
+		Whitebox.setInternalState(preparedStatementTwoParams, "statement", replacedStatementTwoParams);
+		Whitebox.setInternalState(preparedStatementTwoParams, "connection", mockConnectionOpenWithTransactionThatReturns(null));
+		Whitebox.setInternalState(preparedStatementTwoParams, "parametersNumber", PreparedStatementBuilder.namedParameterCount(replacedStatementTwoParams));
+		Whitebox.setInternalState(preparedStatementTwoParams, "parameters", new HashMap<>());
+
+		/*this.preparedStatementOneParam = BoltNeo4jPreparedStatement.newInstance(mockConnectionOpenWithTransactionThatReturns(null),
+				"MATCH n RETURN n WHERE n.name = ?");
+		this.preparedStatementTwoParams = BoltNeo4jPreparedStatement.newInstance(mockConnectionOpenWithTransactionThatReturns(null),
+				"MATCH n RETURN n WHERE n.name = ? AND n.surname = ?");*/
 
 		this.mockedRS = mock(BoltNeo4jResultSet.class);
 		doNothing().when(this.mockedRS).close();
-		whenNew(BoltNeo4jResultSet.class).withArguments(anyObject(), anyObject()).thenReturn(this.mockedRS);
+		mockStatic(BoltNeo4jResultSet.class);
+		PowerMockito.when(BoltNeo4jResultSet.newInstance(anyBoolean(), any(Neo4jStatement.class), any(StatementResult.class))).thenReturn(mockedRS);
 	}
 
 	/*------------------------------*/
 	/*             close            */
 	/*------------------------------*/
 	@Test public void closeShouldCloseExistingResultSet() throws Exception {
-		Neo4jPreparedStatement prStatement = new BoltNeo4jPreparedStatement(mockConnectionOpenWithTransactionThatReturns(null), "");
+		PreparedStatement prStatement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpenWithTransactionThatReturns(null), "");
 		assertNotNull(prStatement.executeQuery());
 		prStatement.close();
 
@@ -87,14 +112,14 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	}
 
 	@Test public void closeShouldNotCallCloseOnAnyResultSet() throws Exception {
-		Neo4jPreparedStatement prStatement = new BoltNeo4jPreparedStatement(mockConnectionOpenWithTransactionThatReturns(null), "");
+		PreparedStatement prStatement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpenWithTransactionThatReturns(null), "");
 		prStatement.close();
 
 		verify(this.mockedRS, never()).close();
 	}
 
 	@Test public void closeMultipleTimesIsNOOP() throws Exception {
-		Neo4jPreparedStatement prStatement = new BoltNeo4jPreparedStatement(mockConnectionOpenWithTransactionThatReturns(null), "");
+		PreparedStatement prStatement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpenWithTransactionThatReturns(null), "");
 		prStatement.executeQuery();
 		prStatement.close();
 		prStatement.close();
@@ -107,9 +132,9 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*           isClosed           */
 	/*------------------------------*/
 	@Test public void isClosedShouldReturnFalseWhenCreated() throws SQLException {
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpen(), "");
+		PreparedStatement prStatement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpen(), "");
 
-		assertFalse(statement.isClosed());
+		assertFalse(prStatement.isClosed());
 	}
 
 	/*------------------------------*/
@@ -513,7 +538,8 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		HashMap<String, Object> value = Whitebox.getInternalState(this.preparedStatementOneParam, "parameters");
 		assertEquals(obj, value.get("1"));
 
-		Object newObj = new ArrayList<>();;
+		Object newObj = new ArrayList<>();
+		;
 		this.preparedStatementOneParam.setObject(1, newObj);
 		value = Whitebox.getInternalState(this.preparedStatementOneParam, "parameters");
 		assertEquals(newObj, value.get("1"));
@@ -564,7 +590,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetConcurrencyShouldThrowExceptionWhenCalledOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionClosed(), "");
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionClosed(), "");
 		statement.close();
 		statement.getResultSetConcurrency();
 	}
@@ -575,7 +601,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetHoldabilityShouldThrowExceptionWhenCalledOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionClosed(), "");
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionClosed(), "");
 		statement.close();
 		statement.getResultSetHoldability();
 	}
@@ -586,7 +612,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetTypeShouldThrowExceptionWhenCalledOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionClosed(), "");
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionClosed(), "");
 		statement.close();
 		statement.getResultSetType();
 	}
@@ -597,24 +623,25 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeQueryShouldThrowExceptionWhenClosedConnection() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionClosed(), "", 0, 0, 0);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionClosed(), "", 0, 0, 0);
 		statement.executeQuery();
 	}
 
 	@Test public void executeQueryShouldReturnCorrectResultSetStructureConnectionNotAutocommit() throws Exception {
-		BoltNeo4jConnection mockConnection = mockConnectionOpenWithTransactionThatReturns(null);
+		BoltNeo4jConnectionImpl mockConnection = mockConnectionOpenWithTransactionThatReturns(null);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnection, "", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
-				ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		PreparedStatement statement = BoltNeo4jPreparedStatement
+				.newInstance(false, mockConnection, "", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.executeQuery();
 
-		verifyNew(BoltNeo4jResultSet.class).withArguments(statement,null, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		verifyStatic(BoltNeo4jResultSet.class);
+		BoltNeo4jResultSet.newInstance(false, statement, null, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
 	}
 
 	@Test public void executeQueryShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
 		statement.close();
 
 		statement.executeQuery();
@@ -633,9 +660,9 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		when(mockSummaryCounters.nodesCreated()).thenReturn(1);
 		when(mockSummaryCounters.nodesDeleted()).thenReturn(0);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpenWithTransactionThatReturns(mockResult),
-				StatementData.STATEMENT_CREATE_TWO_PROPERTIES_PARAMETRIC, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
-				ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		PreparedStatement statement = BoltNeo4jPreparedStatement
+				.newInstance(false, mockConnectionOpenWithTransactionThatReturns(mockResult), StatementData.STATEMENT_CREATE_TWO_PROPERTIES_PARAMETRIC,
+						ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.setString(1, "test");
 		statement.setString(2, "test2");
 		statement.executeUpdate();
@@ -644,7 +671,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeUpdateShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
 		statement.close();
 
 		statement.executeUpdate();
@@ -653,7 +680,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeUpdateShouldThrowExceptionOnClosedConnection() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionClosed(), "", 0, 0, 0);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionClosed(), "", 0, 0, 0);
 		statement.executeUpdate();
 	}
 
@@ -678,9 +705,9 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		when(mockSummaryCounters.nodesCreated()).thenReturn(1);
 		when(mockSummaryCounters.nodesDeleted()).thenReturn(0);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpenWithTransactionThatReturns(mockResult),
-				StatementData.STATEMENT_CREATE_TWO_PROPERTIES_PARAMETRIC, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
-				ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		PreparedStatement statement = BoltNeo4jPreparedStatement
+				.newInstance(false, mockConnectionOpenWithTransactionThatReturns(mockResult), StatementData.STATEMENT_CREATE_TWO_PROPERTIES_PARAMETRIC,
+						ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.setString(1, "test");
 		statement.setString(2, "test2");
 		statement.execute();
@@ -689,7 +716,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldThrowExceptionOnQueryOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
 		statement.close();
 
 		statement.execute();
@@ -698,7 +725,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldThrowExceptionOnUpdateOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpen(), StatementData.STATEMENT_CREATE);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpen(), StatementData.STATEMENT_CREATE);
 		statement.close();
 
 		statement.execute();
@@ -707,7 +734,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldThrowExceptionOnQueryOnClosedConnection() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionClosed(), "", 0, 0, 0);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionClosed(), "", 0, 0, 0);
 		when(statement.executeQuery()).thenCallRealMethod();
 		Whitebox.setInternalState(statement, "statement", StatementData.STATEMENT_MATCH_ALL);
 		statement.execute();
@@ -716,7 +743,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldThrowExceptionOnUpdateOnClosedConnection() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionClosed(), "", 0, 0, 0);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionClosed(), "", 0, 0, 0);
 		when(statement.executeUpdate()).thenCallRealMethod();
 		Whitebox.setInternalState(statement, "statement", StatementData.STATEMENT_CREATE);
 		statement.execute();
@@ -747,7 +774,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getUpdateCountShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
 		statement.close();
 
 		statement.getUpdateCount();
@@ -778,7 +805,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement statement = new BoltNeo4jPreparedStatement(mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
+		PreparedStatement statement = BoltNeo4jPreparedStatement.newInstance(false, mockConnectionOpen(), StatementData.STATEMENT_MATCH_ALL);
 		statement.close();
 
 		statement.getResultSet();
@@ -789,7 +816,16 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void addBatchShouldAddParametersToStack() throws SQLException {
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "MATCH n WHERE id(n) = ? SET n.property=1");
+		PreparedStatement stmt = mock(BoltNeo4jPreparedStatement.class, CALLS_REAL_METHODS);
+		Whitebox.setInternalState(stmt, "batchStatements", new ArrayList<>());
+		String statementString = "MATCH n WHERE id(n) = ? SET n.property=1";
+		String replacedStatementString = PreparedStatementBuilder.replacePlaceholders(statementString);
+		Whitebox.setInternalState(stmt, "statement", replacedStatementString);
+		Whitebox.setInternalState(stmt, "connection", mockConnectionOpenWithTransactionThatReturns(null));
+		Whitebox.setInternalState(stmt, "parametersNumber", PreparedStatementBuilder.namedParameterCount(replacedStatementString));
+		Whitebox.setInternalState(stmt, "parameters", new HashMap<>());
+		Whitebox.setInternalState(stmt, "batchParameters", new ArrayList<>());
+
 		stmt.setInt(1, 1);
 		stmt.addBatch();
 		stmt.setInt(1, 2);
@@ -807,7 +843,16 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	}
 
 	@Test public void addBatchShouldClearParameters() throws SQLException {
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "MATCH n WHERE id(n) = ? SET n.property=1");
+		PreparedStatement stmt = mock(BoltNeo4jPreparedStatement.class, CALLS_REAL_METHODS);
+		Whitebox.setInternalState(stmt, "batchStatements", new ArrayList<>());
+		String statementString = "MATCH n WHERE id(n) = ? SET n.property=1";
+		String replacedStatementString = PreparedStatementBuilder.replacePlaceholders(statementString);
+		Whitebox.setInternalState(stmt, "statement", replacedStatementString);
+		Whitebox.setInternalState(stmt, "connection", mockConnectionOpenWithTransactionThatReturns(null));
+		Whitebox.setInternalState(stmt, "parametersNumber", PreparedStatementBuilder.namedParameterCount(replacedStatementString));
+		Whitebox.setInternalState(stmt, "parameters", new HashMap<>());
+		Whitebox.setInternalState(stmt, "batchParameters", new ArrayList<>());
+
 		stmt.setInt(1, 1);
 		stmt.addBatch();
 
@@ -817,7 +862,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void addBatchShouldThrowExceptionIfClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "?");
+		PreparedStatement stmt = BoltNeo4jPreparedStatement.newInstance(false, Mocker.mockConnectionOpen(), "?");
 		stmt.setInt(1, 1);
 		stmt.close();
 		stmt.addBatch();
@@ -828,7 +873,16 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void clearBatchShouldWork() throws SQLException {
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "?");
+		PreparedStatement stmt = mock(BoltNeo4jPreparedStatement.class, CALLS_REAL_METHODS);
+		Whitebox.setInternalState(stmt, "batchStatements", new ArrayList<>());
+		String statementString = "?";
+		String replacedStatementString = PreparedStatementBuilder.replacePlaceholders(statementString);
+		Whitebox.setInternalState(stmt, "statement", replacedStatementString);
+		Whitebox.setInternalState(stmt, "connection", mockConnectionOpenWithTransactionThatReturns(null));
+		Whitebox.setInternalState(stmt, "parametersNumber", PreparedStatementBuilder.namedParameterCount(replacedStatementString));
+		Whitebox.setInternalState(stmt, "parameters", new HashMap<>());
+		Whitebox.setInternalState(stmt, "batchParameters", new ArrayList<>());
+
 		stmt.setInt(1, 1);
 		stmt.clearBatch();
 
@@ -838,7 +892,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void clearBatchShouldThrowExceptionIfClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "?");
+		PreparedStatement stmt = BoltNeo4jPreparedStatement.newInstance(false, Mocker.mockConnectionOpen(), "?");
 		stmt.close();
 		stmt.clearBatch();
 	}
@@ -848,7 +902,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void executeBatchShouldWork() throws SQLException {
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "MATCH n WHERE id(n) = ? SET n.property=1");
+		PreparedStatement stmt = BoltNeo4jPreparedStatement.newInstance(false, Mocker.mockConnectionOpen(), "MATCH n WHERE id(n) = ? SET n.property=1");
 		stmt.setInt(1, 1);
 		stmt.addBatch();
 		stmt.setInt(1, 2);
@@ -873,7 +927,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	}
 
 	@Test public void executeBatchShouldThrowExceptionOnError() throws SQLException {
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "?");
+		PreparedStatement stmt = BoltNeo4jPreparedStatement.newInstance(false, Mocker.mockConnectionOpen(), "?");
 		stmt.setInt(1, 1);
 		stmt.addBatch();
 		stmt.setInt(1, 2);
@@ -897,7 +951,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeBatchShouldThrowExceptionOnClosed() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionClosed(), "?");
+		PreparedStatement stmt = BoltNeo4jPreparedStatement.newInstance(false, Mocker.mockConnectionClosed(), "?");
 		stmt.setInt(1, 1);
 		stmt.addBatch();
 		stmt.setInt(1, 2);
@@ -912,7 +966,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void getConnectionShouldWork() throws SQLException {
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionOpen(), "?");
+		PreparedStatement stmt = BoltNeo4jPreparedStatement.newInstance(false, Mocker.mockConnectionOpen(), "?");
 
 		assertNotNull(stmt.getConnection());
 		assertEquals(Mocker.mockConnectionOpen().getClass(), stmt.getConnection().getClass());
@@ -921,7 +975,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getConnectionShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jPreparedStatement stmt = new BoltNeo4jPreparedStatement(Mocker.mockConnectionClosed(), "?");
+		PreparedStatement stmt = BoltNeo4jPreparedStatement.newInstance(false, Mocker.mockConnectionClosed(), "?");
 		stmt.close();
 
 		stmt.getConnection();
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetGettersTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetGettersTest.java
index 09b931c1..48bbe9b4 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetGettersTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetGettersTest.java
@@ -31,6 +31,7 @@ import org.mockito.Mockito;
 import org.mockito.internal.util.reflection.Whitebox;
 import org.neo4j.driver.v1.StatementResult;
 
+import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -58,7 +59,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void findColumnShouldReturnCorrectIndex() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		assertEquals(1, resultSet.findColumn("columnA"));
 		assertEquals(2, resultSet.findColumn("columnB"));
@@ -67,7 +68,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void findColumnShouldReturnCorrectIndexOnDifferentColumns() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_DIFF, ResultSetData.RECORD_LIST_MORE_ELEMENTS_DIFF);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		assertEquals(1, resultSet.findColumn("columnA"));
 		assertEquals(2, resultSet.findColumn("columnB"));
@@ -79,7 +80,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.findColumn("columnZ");
@@ -89,7 +90,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.findColumn("columnA");
@@ -102,7 +103,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getStringByLabelShouldReturnString() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("value1", resultSet.getString("columnString"));
@@ -116,7 +117,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getString("columnZ");
@@ -126,7 +127,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getString("columnString");
@@ -135,7 +136,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getStringByIndexShouldReturnString() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("value1", resultSet.getString(2));
@@ -149,7 +150,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getString(99);
@@ -160,7 +161,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getString(0);
@@ -170,7 +171,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getString(2);
@@ -183,7 +184,7 @@ public class BoltNeo4jResultSetGettersTest {
 		Mockito.when(c.getFlattening()).thenReturn(1);
 		Neo4jStatement stmt = Mockito.mock(Neo4jStatement.class);
 		Mockito.when(stmt.getConnection()).thenReturn(c);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(stmt, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, stmt, statementResult);
 
 		resultSet.next();
 		assertEquals("value1", resultSet.getString("node.property1"));
@@ -196,7 +197,7 @@ public class BoltNeo4jResultSetGettersTest {
 		Mockito.when(c.getFlattening()).thenReturn(1);
 		Neo4jStatement stmt = Mockito.mock(Neo4jStatement.class);
 		Mockito.when(stmt.getConnection()).thenReturn(c);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(stmt, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, stmt, statementResult);
 
 		resultSet.next();
 		assertEquals("value1", resultSet.getString(5));
@@ -205,7 +206,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getStringShouldReturnStringOnNode() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_NODES, ResultSetData.RECORD_LIST_MORE_ELEMENTS_NODES);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("{\"id\":1, \"labels\":[\"label1\", \"label2\"], \"property2\":1, \"property1\":\"value1\"}", resultSet.getString("node"));
@@ -217,7 +218,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getStringShouldReturnStringOnRelationship() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_RELATIONS, ResultSetData.RECORD_LIST_MORE_ELEMENTS_RELATIONS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("{\"id\":1, \"type\":\"type1\", \"startId\":1, \"endId\":2, \"property2\":100, \"property1\":\"value\"}", resultSet.getString("relation"));
@@ -229,7 +230,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getStringShouldReturnStringOnPath() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_PATHS, ResultSetData.RECORD_LIST_MORE_ELEMENTS_PATHS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(
@@ -249,7 +250,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getIntByLabelShouldReturnInt() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(1, resultSet.getInt("columnInt"));
@@ -263,7 +264,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getInt("columnZ");
@@ -273,7 +274,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getInt("columnInt");
@@ -282,7 +283,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getIntByIndexShouldReturnInt() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(1, resultSet.getInt(1));
@@ -296,7 +297,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getInt(99);
@@ -307,7 +308,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getInt(0);
@@ -317,7 +318,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getInt(1);
@@ -330,7 +331,7 @@ public class BoltNeo4jResultSetGettersTest {
 		Mockito.when(c.getFlattening()).thenReturn(1);
 		Neo4jStatement stmt = Mockito.mock(Neo4jStatement.class);
 		Mockito.when(stmt.getConnection()).thenReturn(c);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(stmt, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, stmt, statementResult);
 
 		resultSet.next();
 		assertEquals(1, resultSet.getInt("node.id"));
@@ -344,7 +345,7 @@ public class BoltNeo4jResultSetGettersTest {
 		Mockito.when(c.getFlattening()).thenReturn(1);
 		Neo4jStatement stmt = Mockito.mock(Neo4jStatement.class);
 		Mockito.when(stmt.getConnection()).thenReturn(c);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(stmt, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, stmt, statementResult);
 
 		resultSet.next();
 		assertEquals(1, resultSet.getInt(2));
@@ -354,7 +355,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getIntShouldReturnZeroForNull() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_NULL_ELEMENT, ResultSetData.RECORD_LIST_ONE_NULL_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(0, resultSet.getInt("columnA"));
@@ -368,7 +369,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getFloatByLabelShouldReturnFloat() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(0.1F, resultSet.getFloat("columnFloat"), 0);
@@ -382,7 +383,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getFloat("columnZ");
@@ -392,7 +393,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getFloat("columnFloat");
@@ -401,7 +402,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getFloatByIndexShouldReturnFloat() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(0.1F, resultSet.getFloat(3), 0);
@@ -415,7 +416,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getFloat(99);
@@ -426,7 +427,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getFloat(0);
@@ -436,7 +437,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getFloat(3);
@@ -445,7 +446,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getFloatShouldReturnZeroForNull() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_NULL_ELEMENT, ResultSetData.RECORD_LIST_ONE_NULL_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(0F, resultSet.getFloat("columnA"), 0);
@@ -459,7 +460,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getShortByLabelShouldReturnShort() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(1, resultSet.getShort("columnShort"));
@@ -473,7 +474,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getShort("columnZ");
@@ -483,7 +484,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getShort("columnShort");
@@ -492,7 +493,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getShortByIndexShouldReturnShort() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(1, resultSet.getShort(1));
@@ -506,7 +507,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getShort(99);
@@ -517,7 +518,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getShort(0);
@@ -527,7 +528,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getShort(3);
@@ -536,7 +537,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getShortShouldReturnZeroForNull() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_NULL_ELEMENT, ResultSetData.RECORD_LIST_ONE_NULL_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(0, resultSet.getShort("columnA"));
@@ -550,7 +551,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getDoubleByLabelShouldReturnDouble() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(02.29D, resultSet.getDouble("columnDouble"), 0);
@@ -564,7 +565,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getDouble("columnZ");
@@ -574,7 +575,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getDouble("columnDouble");
@@ -583,7 +584,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getDoubleByIndexShouldReturnDouble() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(02.29D, resultSet.getDouble(5), 0);
@@ -597,7 +598,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 		resultSet.next();
 		resultSet.getDouble(99);
 	}
@@ -607,7 +608,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getDouble(0);
@@ -617,7 +618,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getDouble(5);
@@ -626,7 +627,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getDoubleShouldReturnZeroForNull() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_NULL_ELEMENT, ResultSetData.RECORD_LIST_ONE_NULL_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(0D, resultSet.getDouble("columnA"), 0);
@@ -640,7 +641,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getObjectByLabelShouldReturnObject() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("value1", resultSet.getObject("columnString").toString());
@@ -657,7 +658,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getObject("not present");
@@ -668,7 +669,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.close();
 		resultSet.getObject("not present");
@@ -677,7 +678,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getObjectByIndexShouldReturnObject() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("value1", resultSet.getObject(2).toString());
@@ -693,7 +694,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getObject(99);
@@ -704,7 +705,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getObject(0);
@@ -715,7 +716,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.close();
 		resultSet.getObject(1);
@@ -724,7 +725,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getObjectShouldReturnCorrectNodeAsMap() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_NODES, ResultSetData.RECORD_LIST_MORE_ELEMENTS_NODES);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 
@@ -750,7 +751,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getObjectShouldReturnCorrectRelationsAsMap() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_RELATIONS, ResultSetData.RECORD_LIST_MORE_ELEMENTS_RELATIONS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(new HashMap<String, Object>() {
@@ -779,7 +780,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getObjectShouldReturnCorrectPathAsMap() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_PATHS, ResultSetData.RECORD_LIST_MORE_ELEMENTS_PATHS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		assertTrue(resultSet.next());
 		assertEquals(new ArrayList<Object>() {
@@ -863,7 +864,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getBooleanByLabelShouldReturnBoolean() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertTrue(resultSet.getBoolean("columnBoolean"));
@@ -877,7 +878,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getBoolean("columnZ");
@@ -887,7 +888,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getBoolean("columnBoolean");
@@ -896,7 +897,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getBooleanByIndexShouldReturnBoolean() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertTrue(resultSet.getBoolean(6));
@@ -910,7 +911,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getBoolean(99);
@@ -921,7 +922,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getBoolean(0);
@@ -931,7 +932,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getBoolean(6);
@@ -940,7 +941,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getBooleanShouldReturnFalseForNull() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_NULL_ELEMENT, ResultSetData.RECORD_LIST_ONE_NULL_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(false, resultSet.getBoolean("columnA"));
@@ -954,7 +955,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getLongByLabelShouldReturnLong() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(2L, resultSet.getLong("columnLong"));
@@ -968,7 +969,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getLong("columnZ");
@@ -978,7 +979,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getLong("columnLong");
@@ -987,7 +988,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getLongByIndexShouldReturnLong() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(2L, resultSet.getLong(7));
@@ -1001,7 +1002,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getLong(99);
@@ -1012,7 +1013,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getLong(0);
@@ -1022,7 +1023,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getLong(7);
@@ -1031,7 +1032,7 @@ public class BoltNeo4jResultSetGettersTest {
 	@Test public void getLongShouldReturnZeroForNull() throws SQLException {
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_NULL_ELEMENT, ResultSetData.RECORD_LIST_ONE_NULL_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals(0, resultSet.getLong("columnA"));
@@ -1046,14 +1047,14 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getHoldability();
 	}
 
 	@Test public void getHoldabilityShouldReturnCorrectHoldability() throws SQLException {
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null, Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null, Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
 		assertEquals(Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT, resultSet.getHoldability());
 	}
 
@@ -1065,14 +1066,14 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getType();
 	}
 
 	@Test public void getTypeShouldReturnCorrectType() throws SQLException {
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null, Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null, Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
 		assertEquals(Neo4jResultSet.TYPE_FORWARD_ONLY, resultSet.getType());
 	}
 
@@ -1084,14 +1085,14 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getConcurrency();
 	}
 
 	@Test public void getConcurrencyShouldReturnCorrectConcurrency() throws SQLException {
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null, Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null, Neo4jResultSet.TYPE_FORWARD_ONLY, Neo4jResultSet.CONCUR_READ_ONLY, Neo4jResultSet.CLOSE_CURSORS_AT_COMMIT);
 		assertEquals(Neo4jResultSet.CONCUR_READ_ONLY, resultSet.getConcurrency());
 	}
 
@@ -1100,7 +1101,7 @@ public class BoltNeo4jResultSetGettersTest {
 	/*------------------------------*/
 	@Test public void getArrayByLabelShouldReturnArray() throws SQLException {
 		StatementResult statementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_WITH_ARRAY, ResultSetData.RECORD_LIST_WITH_ARRAY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("a", ((String[]) resultSet.getArray("array").getArray())[0]);
@@ -1127,7 +1128,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult statementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_WITH_ARRAY, ResultSetData.RECORD_LIST_WITH_ARRAY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getLong("columnZ");
@@ -1137,7 +1138,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_WITH_ARRAY, ResultSetData.RECORD_LIST_WITH_ARRAY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getLong("array");
@@ -1145,7 +1146,7 @@ public class BoltNeo4jResultSetGettersTest {
 
 	@Test public void getArrayByIndexShouldReturnArray() throws SQLException {
 		StatementResult statementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_WITH_ARRAY, ResultSetData.RECORD_LIST_WITH_ARRAY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		assertEquals("a", ((String[]) resultSet.getArray(1).getArray())[0]);
@@ -1172,7 +1173,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult statementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_WITH_ARRAY, ResultSetData.RECORD_LIST_WITH_ARRAY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getLong(99);
@@ -1182,7 +1183,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult statementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_WITH_ARRAY, ResultSetData.RECORD_LIST_WITH_ARRAY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.next();
 		resultSet.getLong(0);
@@ -1192,7 +1193,7 @@ public class BoltNeo4jResultSetGettersTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult spyCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_WITH_ARRAY, ResultSetData.RECORD_LIST_WITH_ARRAY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, spyCursor);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, spyCursor);
 
 		resultSet.close();
 		resultSet.getLong(7);
@@ -1205,7 +1206,7 @@ public class BoltNeo4jResultSetGettersTest {
 		Mockito.when(c.getFlattening()).thenReturn(1);
 		Neo4jStatement stmt = Mockito.mock(Neo4jStatement.class);
 		Mockito.when(stmt.getConnection()).thenReturn(c);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(stmt, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, stmt, statementResult);
 
 		resultSet.next();
 		assertArrayEquals(new String[] { "label1", "label2" }, (String[]) resultSet.getArray("node.labels").getArray());
@@ -1218,7 +1219,7 @@ public class BoltNeo4jResultSetGettersTest {
 		Mockito.when(c.getFlattening()).thenReturn(1);
 		Neo4jStatement stmt = Mockito.mock(Neo4jStatement.class);
 		Mockito.when(stmt.getConnection()).thenReturn(c);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(stmt, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, stmt, statementResult);
 
 		resultSet.next();
 		assertArrayEquals(new String[] { "label1", "label2" }, (String[]) resultSet.getArray(3).getArray());
@@ -1232,20 +1233,20 @@ public class BoltNeo4jResultSetGettersTest {
 
 		StatementResult statementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_MIXED, ResultSetData.RECORD_LIST_MORE_ELEMENTS_MIXED);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, statementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, statementResult);
 
 		resultSet.close();
 		resultSet.wasNull();
 	}
 
 	@Test public void wasNullShouldReturnFalse() throws SQLException {
-		Neo4jResultSet resultSet = Mockito.mock(BoltNeo4jResultSet.class);
+		ResultSet resultSet = Mockito.mock(BoltNeo4jResultSet.class);
 		Whitebox.setInternalState(resultSet, "wasNull", false);
 		resultSet.wasNull();
 	}
 
 	@Test public void wasNullShouldReturnTrue() throws SQLException {
-		Neo4jResultSet resultSet = Mockito.mock(BoltNeo4jResultSet.class);
+		ResultSet resultSet = Mockito.mock(BoltNeo4jResultSet.class);
 		Whitebox.setInternalState(resultSet, "wasNull", true);
 		resultSet.wasNull();
 	}
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetIterationTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetIterationTest.java
index 151410b4..21980c42 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetIterationTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetIterationTest.java
@@ -19,12 +19,12 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import org.neo4j.jdbc.Neo4jResultSet;
-import org.neo4j.jdbc.bolt.data.ResultSetData;
 import org.junit.*;
 import org.junit.rules.ExpectedException;
 import org.neo4j.driver.v1.StatementResult;
+import org.neo4j.jdbc.bolt.data.ResultSetData;
 
+import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 
@@ -45,14 +45,14 @@ public class BoltNeo4jResultSetIterationTest {
 	/*------------------------------*/
 	@Test public void nextShouldReturnFalseEmpty() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertFalse(resultSet.next());
 	}
 
 	@Test public void nextShouldReturnTrue() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_ELEMENT, ResultSetData.RECORD_LIST_ONE_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 	}
@@ -60,7 +60,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Test public void nextShouldReturnTrueMoreElements() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 		Assert.assertTrue(resultSet.next());
@@ -69,7 +69,7 @@ public class BoltNeo4jResultSetIterationTest {
 
 	@Test public void nextShouldReturnFalseAfterLast() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_ELEMENT, ResultSetData.RECORD_LIST_ONE_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 
@@ -79,7 +79,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Test public void nextShouldReturnFalseAfterLastMoreElements() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 		Assert.assertTrue(resultSet.next());
@@ -92,7 +92,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Test public void nextShouldReturnTrueAndPointNextNode() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 		Assert.assertEquals("valueA1", resultSet.getString("columnA"));
@@ -106,7 +106,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Test public void nextShouldThrowExceptionEmpty() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null);
 
 		resultSet.next();
 	}
@@ -116,7 +116,7 @@ public class BoltNeo4jResultSetIterationTest {
 	/*------------------------------*/
 	@Ignore @Test public void previousShouldReturnFalseEmpty() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertFalse(resultSet.previous());
 	}
@@ -124,7 +124,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void previousShouldReturnTrue() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 		Assert.assertTrue(resultSet.next());
@@ -135,7 +135,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void previousShouldReturnFalseBeforeFirst() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 		Assert.assertTrue(resultSet.next());
@@ -148,7 +148,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void previousShouldReturnTrueAndPointPreviousNode() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.last());
 
@@ -164,7 +164,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void previousShouldThrowExceptionEmpty() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null);
 
 		resultSet.previous();
 	}
@@ -174,21 +174,21 @@ public class BoltNeo4jResultSetIterationTest {
 	/*------------------------------*/
 	@Ignore @Test public void firstShouldReturnFalseEmpty() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertFalse(resultSet.first());
 	}
 
 	@Ignore @Test public void firstShouldReturnTrueOnFirst() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_ELEMENT, ResultSetData.RECORD_LIST_ONE_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.first());
 	}
 
 	@Ignore @Test public void firstShouldReturnTrueNotOnFirst() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_ELEMENT, ResultSetData.RECORD_LIST_ONE_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.next());
 
@@ -197,7 +197,7 @@ public class BoltNeo4jResultSetIterationTest {
 
 	@Ignore @Test public void firstShouldReturnTrueAndPointFirstElement() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_ELEMENT, ResultSetData.RECORD_LIST_ONE_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.first());
 		Assert.assertEquals("valueA1", resultSet.getString("columnA"));
@@ -207,7 +207,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void firstShouldThrowExceptionClosed() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null);
 
 		resultSet.close();
 		resultSet.first();
@@ -216,11 +216,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void firstShouldThrowExceptionForwardOnly() throws SQLException {
 		expectedEx.expect(SQLFeatureNotSupportedException.class);
 
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null) {
-			@Override public int getType() {
-				return Neo4jResultSet.TYPE_FORWARD_ONLY;
-			}
-		};
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null);
 
 		resultSet.first();
 	}
@@ -230,14 +226,14 @@ public class BoltNeo4jResultSetIterationTest {
 	/*------------------------------*/
 	@Ignore @Test public void lastShouldReturnFalseEmpty() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertFalse(resultSet.last());
 	}
 
 	@Ignore @Test public void lastShouldReturnTrue() throws SQLException {
 		StatementResult StatementResult = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_ONE_ELEMENT, ResultSetData.RECORD_LIST_ONE_ELEMENT);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.last());
 	}
@@ -245,7 +241,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void lastShouldReturnTrueAndPointLastNode() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		Assert.assertTrue(resultSet.last());
 		Assert.assertEquals("valueA3", resultSet.getString("columnA"));
@@ -255,7 +251,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void lastShouldThrowExceptionClosed() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null);
 
 		resultSet.close();
 		resultSet.last();
@@ -264,11 +260,7 @@ public class BoltNeo4jResultSetIterationTest {
 	@Ignore @Test public void lastShouldThrowExceptionForwardOnly() throws SQLException {
 		expectedEx.expect(SQLFeatureNotSupportedException.class);
 
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null) {
-			@Override public int getType() {
-				return Neo4jResultSet.TYPE_FORWARD_ONLY;
-			}
-		};
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null);
 
 		resultSet.last();
 	}
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaDataTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaDataTest.java
index 346e32f5..0255422e 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaDataTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetMetaDataTest.java
@@ -26,9 +26,9 @@ import org.junit.rules.ExpectedException;
 import org.neo4j.driver.internal.types.InternalTypeSystem;
 import org.neo4j.driver.v1.StatementResult;
 import org.neo4j.driver.v1.types.Type;
-import org.neo4j.jdbc.Neo4jResultSetMetaData;
 import org.neo4j.jdbc.bolt.data.ResultSetData;
 
+import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Types;
 import java.util.Arrays;
@@ -55,14 +55,14 @@ public class BoltNeo4jResultSetMetaDataTest {
 
 	@Test public void getColumnsCountShouldReturnCorrectNumberEmpty() throws SQLException {
 		StatementResult resultIterator = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultIterator.keys());
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultIterator.keys());
 
 		assertEquals(0, resultSet.getColumnCount());
 	}
 
 	@Test public void getColumnsCountShouldReturnCorrectNumberMoreElements() throws SQLException {
 		StatementResult resultCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultCursor.keys());
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultCursor.keys());
 
 		assertEquals(2, resultSet.getColumnCount());
 	}
@@ -73,7 +73,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 
 	@Test public void getColumnNameShouldReturnCorrectColumnName() throws SQLException {
 		StatementResult resultCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultCursor.keys());
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultCursor.keys());
 
 		assertEquals("columnA", resultSet.getColumnName(1));
 	}
@@ -82,7 +82,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult resultCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSetMetaData resultSetMetaData = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultCursor.keys());
+		ResultSetMetaData resultSetMetaData = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultCursor.keys());
 
 		resultSetMetaData.getColumnName(1);
 	}
@@ -91,7 +91,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult resultCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultCursor.keys());
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultCursor.keys());
 
 		resultSet.getColumnName(99);
 	}
@@ -99,7 +99,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 	@Test public void getColumnNameShouldThrowExceptionIfCursorNull() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
 
 		resultSet.getColumnName(1);
 	}
@@ -110,7 +110,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 
 	@Test public void getColumnLabelShouldReturnCorrectColumnName() throws SQLException {
 		StatementResult resultCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultCursor.keys());
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultCursor.keys());
 
 		assertEquals("columnA", resultSet.getColumnLabel(1));
 	}
@@ -119,7 +119,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult resultCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultCursor.keys());
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultCursor.keys());
 
 		resultSet.getColumnLabel(1);
 	}
@@ -128,7 +128,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 		expectedEx.expect(SQLException.class);
 
 		StatementResult resultCursor = ResultSetData.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_EMPTY, ResultSetData.RECORD_LIST_EMPTY);
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, resultCursor.keys());
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, resultCursor.keys());
 
 		resultSet.getColumnLabel(99);
 	}
@@ -136,7 +136,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 	@Test public void getColumnLabelShouldThrowExceptionIfCursorNull() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
 
 		resultSet.getColumnLabel(1);
 	}
@@ -146,7 +146,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 	/*------------------------------*/
 
 	@Test public void getSchemaNameShouldReturnDefaultValue() throws SQLException {
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
 
 		assertEquals("", resultSet.getSchemaName(1));
 	}
@@ -156,7 +156,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 	/*------------------------------*/
 
 	@Test public void getCatalogNameShouldReturnEmptyString() throws SQLException {
-		Neo4jResultSetMetaData resultSet = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+		ResultSetMetaData resultSet = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
 
 		assertEquals("", resultSet.getCatalogName(1));
 	}
@@ -168,7 +168,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 	@Test public void flatteningTestWorking() throws SQLException {
 		StatementResult resultCursor = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS_NODES, ResultSetData.RECORD_LIST_MORE_ELEMENTS_NODES);
-		Neo4jResultSetMetaData rsm = new BoltNeo4jResultSetMetaData(Collections.EMPTY_LIST,
+		ResultSetMetaData rsm = BoltNeo4jResultSetMetaData.newInstance(false, Collections.EMPTY_LIST,
 				Arrays.asList(new String[] { "node", "node.id", "node.label", "node.property2", "node.property1" }));
 
 		assertEquals(5, rsm.getColumnCount());
@@ -198,7 +198,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 		List<String> cols = Arrays.asList(
 				"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"
 		);
-		Neo4jResultSetMetaData rsm = new BoltNeo4jResultSetMetaData(types, cols);
+		ResultSetMetaData rsm = BoltNeo4jResultSetMetaData.newInstance(false, types, cols);
 		assertEquals("java.lang.String", rsm.getColumnClassName(1));
 		assertEquals("java.lang.Long", rsm.getColumnClassName(2));
 		assertEquals("java.lang.Boolean", rsm.getColumnClassName(3));
@@ -232,7 +232,7 @@ public class BoltNeo4jResultSetMetaDataTest {
 		List<String> cols = Arrays.asList(
 				"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"
 		);
-		Neo4jResultSetMetaData rsm = new BoltNeo4jResultSetMetaData(types, cols);
+		ResultSetMetaData rsm = BoltNeo4jResultSetMetaData.newInstance(false, types, cols);
 		assertEquals(Types.VARCHAR, rsm.getColumnType(1));
 		assertEquals(Types.INTEGER, rsm.getColumnType(2));
 		assertEquals(Types.BOOLEAN, rsm.getColumnType(3));
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetTest.java
index ef001198..5a494021 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jResultSetTest.java
@@ -19,7 +19,6 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import org.neo4j.jdbc.Neo4jResultSet;
 import org.neo4j.jdbc.bolt.data.ResultSetData;
 import org.junit.BeforeClass;
 import org.junit.Rule;
@@ -27,6 +26,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.neo4j.driver.v1.StatementResult;
 
+import java.sql.ResultSet;
 import java.sql.SQLException;
 
 import static org.junit.Assert.assertFalse;
@@ -51,7 +51,7 @@ public class BoltNeo4jResultSetTest {
 	@Test public void isClosedReturnFalseWhenConnectionOpen() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		assertFalse(resultSet.isClosed());
 	}
@@ -60,7 +60,7 @@ public class BoltNeo4jResultSetTest {
 	@Test public void isClosedReturnTrueWhenConnectionClosed() throws SQLException {
 		StatementResult StatementResult = ResultSetData
 				.buildResultCursor(ResultSetData.KEYS_RECORD_LIST_MORE_ELEMENTS, ResultSetData.RECORD_LIST_MORE_ELEMENTS);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, StatementResult);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, StatementResult);
 
 		resultSet.close();
 		assertTrue(resultSet.isClosed());
@@ -72,7 +72,7 @@ public class BoltNeo4jResultSetTest {
 
 	@Test public void closeShouldThrowExceptionIfIteratorIsNull() throws SQLException {
 		expectedEx.expect(SQLException.class);
-		Neo4jResultSet resultSet = new BoltNeo4jResultSet(null, null);
+		ResultSet resultSet = BoltNeo4jResultSet.newInstance(false, null, null);
 
 		resultSet.close();
 	}
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jStatementTest.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jStatementTest.java
index 4be7e3fb..9d48278b 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jStatementTest.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/BoltNeo4jStatementTest.java
@@ -19,9 +19,6 @@
  */
 package org.neo4j.jdbc.bolt;
 
-import org.neo4j.jdbc.Neo4jConnection;
-import org.neo4j.jdbc.bolt.data.StatementData;
-import org.neo4j.jdbc.bolt.utils.Mocker;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Rule;
@@ -35,38 +32,47 @@ import org.neo4j.driver.v1.StatementResult;
 import org.neo4j.driver.v1.Transaction;
 import org.neo4j.driver.v1.summary.ResultSummary;
 import org.neo4j.driver.v1.summary.SummaryCounters;
+import org.neo4j.jdbc.Neo4jStatement;
+import org.neo4j.jdbc.bolt.data.StatementData;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
+import org.neo4j.jdbc.bolt.utils.Mocker;
+import org.neo4j.jdbc.utils.Neo4jInvocationHandler;
+import org.powermock.api.mockito.PowerMockito;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
-import java.sql.BatchUpdateException;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
+import java.lang.reflect.Proxy;
+import java.sql.*;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 
-import static org.neo4j.jdbc.bolt.utils.Mocker.*;
 import static org.junit.Assert.*;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.*;
-import static org.powermock.api.mockito.PowerMockito.verifyNew;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
+import static org.neo4j.jdbc.bolt.utils.Mocker.*;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.verifyStatic;
 
 /**
  * @author AgileLARUS
  * @since 3.0.0
  */
-@RunWith(PowerMockRunner.class) @PrepareForTest({ BoltNeo4jStatement.class, BoltNeo4jResultSet.class, Session.class }) public class BoltNeo4jStatementTest {
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ BoltNeo4jStatement.class, BoltNeo4jResultSet.class, Session.class })
+public class BoltNeo4jStatementTest {
 
-	@Rule public ExpectedException expectedEx = ExpectedException.none();
+	@Rule
+	public ExpectedException expectedEx = ExpectedException.none();
 
 	private BoltNeo4jResultSet mockedRS;
 
 	@Before public void interceptBoltResultSetConstructor() throws Exception {
 		mockedRS = mock(BoltNeo4jResultSet.class);
 		doNothing().when(mockedRS).close();
-		whenNew(BoltNeo4jResultSet.class).withArguments(anyObject(), anyObject()).thenReturn(mockedRS);
+		mockStatic(BoltNeo4jResultSet.class);
+		PowerMockito.when(BoltNeo4jResultSet.newInstance(anyBoolean(), any(Neo4jStatement.class), any(StatementResult.class))).thenReturn(mockedRS);
 	}
 
 	/*------------------------------*/
@@ -74,7 +80,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 	@Test public void closeShouldCloseExistingResultSet() throws Exception {
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpenWithTransactionThatReturns(null));
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpenWithTransactionThatReturns(null));
 		statement.executeQuery(StatementData.STATEMENT_MATCH_ALL);
 		statement.close();
 
@@ -84,7 +90,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 
 	@Test public void closeShouldNotCallCloseOnAnyResultSet() throws Exception {
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpenWithTransactionThatReturns(null));
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpenWithTransactionThatReturns(null));
 		statement.close();
 
 		verify(mockedRS, never()).close();
@@ -92,7 +98,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 
 	@Test public void closeMultipleTimesIsNOOP() throws Exception {
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpenWithTransactionThatReturns(null));
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpenWithTransactionThatReturns(null));
 		statement.executeQuery(StatementData.STATEMENT_MATCH_ALL);
 		statement.close();
 		statement.close();
@@ -105,10 +111,10 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 
 		Transaction mockTransaction = mock(Transaction.class);
 
-		BoltNeo4jConnection mockConnection = mockConnectionOpen();
+		BoltNeo4jConnectionImpl mockConnection = mockConnectionOpen();
 		when(mockConnection.getTransaction()).thenReturn(mockTransaction);
 
-		Statement statement = new BoltNeo4jStatement(mockConnection);
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnection);
 
 		statement.close();
 
@@ -122,7 +128,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void isClosedShouldReturnFalseWhenCreated() throws SQLException {
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpen());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpen());
 		assertFalse(statement.isClosed());
 	}
 
@@ -133,31 +139,34 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeQueryShouldRun() throws SQLException {
 		StatementResult mockResult = mock(StatementResult.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY,
-				ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		Statement statement = BoltNeo4jStatement
+				.newInstance(false, mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+						ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.executeQuery(StatementData.STATEMENT_CREATE);
 	}
 
 	@Test public void executeQueryShouldThrowExceptionWhenClosedConnection() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionClosed(), 0, 0, 0);
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionClosed(), 0, 0, 0);
 		statement.executeQuery(StatementData.STATEMENT_MATCH_ALL);
 	}
 
 	@Test public void executeQueryShouldReturnCorrectResultSetStructureConnectionNotAutocommit() throws Exception {
-		BoltNeo4jConnection mockConnection = mockConnectionOpenWithTransactionThatReturns(null);
+		BoltNeo4jConnectionImpl mockConnection = mockConnectionOpenWithTransactionThatReturns(null);
 
-		Statement statement = new BoltNeo4jStatement(mockConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		Statement statement = BoltNeo4jStatement
+				.newInstance(false, mockConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.executeQuery(StatementData.STATEMENT_MATCH_ALL);
 
-		verifyNew(BoltNeo4jResultSet.class).withArguments(statement, null, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		verifyStatic(BoltNeo4jResultSet.class);
+		BoltNeo4jResultSet.newInstance(false, statement, null, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
 	}
 
 	@Test public void executeQueryShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpen());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpen());
 		statement.close();
 
 		statement.executeQuery(StatementData.STATEMENT_MATCH_ALL);
@@ -166,7 +175,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeQueryShouldThrowExceptionOnPreparedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareStatement("");
 		statement.executeQuery(StatementData.STATEMENT_MATCH_ALL);
 	}
@@ -174,7 +183,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Ignore @Test public void executeQueryShouldThrowExceptionOnCallableStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareCall("");
 		statement.executeQuery(StatementData.STATEMENT_MATCH_ALL);
 	}
@@ -193,7 +202,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		given(session.beginTransaction()).willReturn(transaction);
 		given(session.isOpen()).willReturn(true);
 
-		Statement statement = new BoltNeo4jStatement(new BoltNeo4jConnection(session), 0, 0, 0);
+		Statement statement = BoltNeo4jStatement.newInstance(false, new BoltNeo4jConnectionImpl(session), 0, 0, 0);
 
 		statement.setQueryTimeout(1);
 		statement.executeQuery(StatementData.STATEMENT_CREATE);
@@ -215,15 +224,16 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		when(mockSummaryCounters.nodesCreated()).thenReturn(1);
 		when(mockSummaryCounters.nodesDeleted()).thenReturn(0);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY,
-				ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		Statement statement = BoltNeo4jStatement
+				.newInstance(false, mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+						ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.executeUpdate(StatementData.STATEMENT_CREATE);
 	}
 
 	@Test public void executeUpdateShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.createStatement();
 		statement.close();
 		statement.executeUpdate(StatementData.STATEMENT_CREATE);
@@ -232,7 +242,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeUpdateShouldThrowExceptionOnPreparedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareStatement("");
 		statement.executeUpdate(StatementData.STATEMENT_CREATE);
 	}
@@ -240,7 +250,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Ignore @Test public void executeUpdateShouldThrowExceptionOnCallableStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareCall(null);
 		statement.executeUpdate(StatementData.STATEMENT_CREATE);
 	}
@@ -259,7 +269,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		given(session.beginTransaction()).willReturn(transaction);
 		given(session.isOpen()).willReturn(true);
 
-		Statement statement = new BoltNeo4jStatement(new BoltNeo4jConnection(session), 0, 0, 0);
+		Statement statement = BoltNeo4jStatement.newInstance(false, new BoltNeo4jConnectionImpl(session), 0, 0, 0);
 
 		statement.setQueryTimeout(1);
 		statement.executeUpdate(StatementData.STATEMENT_CREATE);
@@ -273,7 +283,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetConcurrencyShouldThrowExceptionWhenCalledOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionClosed());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionClosed());
 		statement.close();
 		statement.getResultSetConcurrency();
 	}
@@ -284,7 +294,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetHoldabilityShouldThrowExceptionWhenCalledOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionClosed());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionClosed());
 		statement.close();
 		statement.getResultSetHoldability();
 	}
@@ -295,7 +305,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetTypeShouldThrowExceptionWhenCalledOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionClosed());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionClosed());
 		statement.close();
 		statement.getResultSetType();
 	}
@@ -306,8 +316,9 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldRunQuery() throws SQLException {
 		StatementResult mockResult = mock(StatementResult.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY,
-				ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		Statement statement = BoltNeo4jStatement
+				.newInstance(false, mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+						ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.execute(StatementData.STATEMENT_MATCH_ALL);
 	}
 
@@ -321,29 +332,30 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		when(mockSummaryCounters.nodesCreated()).thenReturn(1);
 		when(mockSummaryCounters.nodesDeleted()).thenReturn(0);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY,
-				ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+		Statement statement = BoltNeo4jStatement
+				.newInstance(false, mockConnectionOpenWithTransactionThatReturns(mockResult), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+						ResultSet.HOLD_CURSORS_OVER_COMMIT);
 		statement.execute(StatementData.STATEMENT_CREATE);
 	}
 
 	@Test public void executeShouldThrowExceptionOnQueryWhenClosedConnection() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionClosed(), 0, 0, 0);
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionClosed(), 0, 0, 0);
 		statement.execute(StatementData.STATEMENT_MATCH_ALL);
 	}
 
 	@Test public void executeShouldThrowExceptionOnUpdateWhenClosedConnection() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionClosed(), 0, 0, 0);
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionClosed(), 0, 0, 0);
 		statement.execute(StatementData.STATEMENT_CREATE);
 	}
 
 	@Test public void executeShouldThrowExceptionOnQueryOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpen());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpen());
 		statement.close();
 
 		statement.execute(StatementData.STATEMENT_MATCH_ALL);
@@ -352,7 +364,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldThrowExceptionOnUpdateOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpen());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpen());
 		statement.close();
 
 		statement.execute(StatementData.STATEMENT_CREATE);
@@ -361,7 +373,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldThrowExceptionOnQueryOnPreparedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareStatement("");
 
 		statement.execute(StatementData.STATEMENT_MATCH_ALL);
@@ -370,7 +382,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeShouldThrowExceptionOnUpdateOnPreparedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareStatement("");
 		when(statement.executeUpdate(anyString())).thenCallRealMethod();
 
@@ -380,7 +392,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Ignore @Test public void executeShouldThrowExceptionOnCallableStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = new BoltNeo4jConnection(mockSessionOpen());
+		Connection connection = new BoltNeo4jConnectionImpl(mockSessionOpen());
 		Statement statement = connection.prepareCall("");
 		statement.execute(StatementData.STATEMENT_MATCH_ALL);
 	}
@@ -399,7 +411,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 		given(session.beginTransaction()).willReturn(transaction);
 		given(session.isOpen()).willReturn(true);
 
-		Statement statement = new BoltNeo4jStatement(new BoltNeo4jConnection(session), 0, 0, 0);
+		Statement statement = BoltNeo4jStatement.newInstance(false, new BoltNeo4jConnectionImpl(session), 0, 0, 0);
 
 		statement.setQueryTimeout(1);
 		statement.execute(StatementData.STATEMENT_CREATE);
@@ -432,7 +444,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getUpdateCountShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpen());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpen());
 		statement.close();
 
 		statement.getUpdateCount();
@@ -463,7 +475,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getResultSetShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement statement = new BoltNeo4jStatement(mockConnectionOpen());
+		Statement statement = BoltNeo4jStatement.newInstance(false, mockConnectionOpen());
 		statement.close();
 
 		statement.getResultSet();
@@ -475,19 +487,24 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void addBatchShouldAddStringToStack() throws SQLException {
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionOpen());
+		mockStatic(Proxy.class);
+		Statement s = mock(BoltNeo4jStatement.class);
+		doCallRealMethod().when(s).addBatch(anyString());
+		Whitebox.setInternalState(s, "batchStatements", new ArrayList<>());
+		PowerMockito.when(Proxy.newProxyInstance(any(ClassLoader.class), any(Class[].class), any(Neo4jInvocationHandler.class))).thenReturn(s);
+
 		String str1 = "MATCH n WHERE id(n) = 1 SET n.property=1";
 		String str2 = "MATCH n WHERE id(n) = 2 SET n.property=2";
-		stmt.addBatch(str1);
-		stmt.addBatch(str2);
+		s.addBatch(str1);
+		s.addBatch(str2);
 
-		assertEquals(Arrays.asList(str1, str2), Whitebox.getInternalState(stmt, "batchStatements"));
+		assertEquals(Arrays.asList(str1, str2), Whitebox.getInternalState(s, "batchStatements"));
 	}
 
 	@Test public void addBatchShouldThrowExceptionIfClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionOpen());
+		Statement stmt = BoltNeo4jStatement.newInstance(false, Mocker.mockConnectionOpen());
 		stmt.close();
 		stmt.addBatch("");
 	}
@@ -497,18 +514,24 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void clearBatchShouldWork() throws SQLException {
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionOpen());
-		stmt.addBatch("MATCH n WHERE id(n) = 1 SET n.property=1");
-		stmt.addBatch("MATCH n WHERE id(n) = 2 SET n.property=2");
-		stmt.clearBatch();
+		mockStatic(Proxy.class);
+		Statement s = mock(BoltNeo4jStatement.class);
+		doCallRealMethod().when(s).addBatch(anyString());
+		doCallRealMethod().when(s).clearBatch();
+		Whitebox.setInternalState(s, "batchStatements", new ArrayList<>());
+		PowerMockito.when(Proxy.newProxyInstance(any(ClassLoader.class), any(Class[].class), any(Neo4jInvocationHandler.class))).thenReturn(s);
+
+		s.addBatch("MATCH n WHERE id(n) = 1 SET n.property=1");
+		s.addBatch("MATCH n WHERE id(n) = 2 SET n.property=2");
+		s.clearBatch();
 
-		assertEquals(Collections.EMPTY_LIST, Whitebox.getInternalState(stmt, "batchStatements"));
+		assertEquals(Collections.EMPTY_LIST, Whitebox.getInternalState(s, "batchStatements"));
 	}
 
 	@Test public void clearBatchShouldThrowExceptionIfClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionOpen());
+		Statement stmt = BoltNeo4jStatement.newInstance(false, Mocker.mockConnectionOpen());
 		stmt.close();
 		stmt.clearBatch();
 	}
@@ -518,7 +541,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void executeBatchShouldWork() throws SQLException {
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionOpen());
+		Statement stmt = BoltNeo4jStatement.newInstance(false, Mocker.mockConnectionOpen());
 		String str1 = "MATCH n WHERE id(n) = 1 SET n.property=1";
 		String str2 = "MATCH n WHERE id(n) = 2 SET n.property=2";
 		stmt.addBatch(str1);
@@ -543,7 +566,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	}
 
 	@Test public void executeBatchShouldThrowExceptionOnError() throws SQLException {
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionOpen());
+		Statement stmt = BoltNeo4jStatement.newInstance(false, Mocker.mockConnectionOpen());
 		String str1 = "MATCH n WHERE id(n) = 1 SET n.property=1";
 		String str2 = "MATCH n WHERE id(n) = 2 SET n.property=2";
 		stmt.addBatch(str1);
@@ -567,7 +590,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void executeBatchShouldThrowExceptionOnClosed() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionClosed());
+		Statement stmt = BoltNeo4jStatement.newInstance(false, Mocker.mockConnectionClosed());
 		String str1 = "MATCH n WHERE id(n) = 1 SET n.property=1";
 		String str2 = "MATCH n WHERE id(n) = 2 SET n.property=2";
 		stmt.addBatch(str1);
@@ -582,7 +605,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	/*------------------------------*/
 
 	@Test public void getConnectionShouldWork() throws SQLException {
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionOpen());
+		Statement stmt = BoltNeo4jStatement.newInstance(false, Mocker.mockConnectionOpen());
 
 		assertNotNull(stmt.getConnection());
 		assertEquals(Mocker.mockConnectionOpen().getClass(), stmt.getConnection().getClass());
@@ -591,7 +614,7 @@ import static org.powermock.api.mockito.PowerMockito.whenNew;
 	@Test public void getConnectionShouldThrowExceptionOnClosedStatement() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Statement stmt = new BoltNeo4jStatement(Mocker.mockConnectionClosed());
+		Statement stmt = BoltNeo4jStatement.newInstance(false, Mocker.mockConnectionClosed());
 		stmt.close();
 
 		stmt.getConnection();
diff --git a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/utils/Mocker.java b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/utils/Mocker.java
index 47657755..feeeadb6 100644
--- a/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/utils/Mocker.java
+++ b/neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/utils/Mocker.java
@@ -26,7 +26,7 @@ import org.neo4j.driver.internal.NetworkSession;
 import org.neo4j.driver.internal.logging.DevNullLogging;
 import org.neo4j.driver.internal.spi.ConnectionProvider;
 import org.neo4j.driver.v1.*;
-import org.neo4j.jdbc.bolt.BoltNeo4jConnection;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -85,24 +85,24 @@ public class Mocker {
 		return session;
 	}
 
-	public static BoltNeo4jConnection mockConnectionOpen() throws SQLException {
-		BoltNeo4jConnection mockConnection = mock(BoltNeo4jConnection.class);
+	public static BoltNeo4jConnectionImpl mockConnectionOpen() throws SQLException {
+		BoltNeo4jConnectionImpl mockConnection = mock(BoltNeo4jConnectionImpl.class);
 		when(mockConnection.isClosed()).thenReturn(false);
 		return mockConnection;
 	}
 
-	public static BoltNeo4jConnection mockConnectionClosed() throws SQLException {
-		BoltNeo4jConnection mockConnection = mock(BoltNeo4jConnection.class);
+	public static BoltNeo4jConnectionImpl mockConnectionClosed() throws SQLException {
+		BoltNeo4jConnectionImpl mockConnection = mock(BoltNeo4jConnectionImpl.class);
 		when(mockConnection.isClosed()).thenReturn(true);
 		return mockConnection;
 	}
 
-	public static BoltNeo4jConnection mockConnectionOpenWithTransactionThatReturns(StatementResult cur) throws SQLException {
+	public static BoltNeo4jConnectionImpl mockConnectionOpenWithTransactionThatReturns(StatementResult cur) throws SQLException {
 		Transaction mockTransaction = mock(Transaction.class);
 		when(mockTransaction.run(anyString())).thenReturn(cur);
 		when(mockTransaction.run(anyString(), any(HashMap.class))).thenReturn(cur);
 
-		BoltNeo4jConnection mockConnection = mockConnectionOpen();
+		BoltNeo4jConnectionImpl mockConnection = mockConnectionOpen();
 		when(mockConnection.getTransaction()).thenReturn(mockTransaction);
 		return mockConnection;
 	}
diff --git a/neo4j-jdbc-driver/src/test/java/org/neo4j/jdbc/DriverTestIT.java b/neo4j-jdbc-driver/src/test/java/org/neo4j/jdbc/DriverTestIT.java
index 6bb62e2e..19ff2ada 100644
--- a/neo4j-jdbc-driver/src/test/java/org/neo4j/jdbc/DriverTestIT.java
+++ b/neo4j-jdbc-driver/src/test/java/org/neo4j/jdbc/DriverTestIT.java
@@ -34,6 +34,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.neo4j.harness.junit.Neo4jRule;
 import org.neo4j.jdbc.bolt.BoltNeo4jConnection;
+import org.neo4j.jdbc.bolt.impl.BoltNeo4jConnectionImpl;
 import org.neo4j.jdbc.http.HttpNeo4jConnection;
 
 import static org.mockito.Matchers.anyString;
diff --git a/neo4j-jdbc/src/test/java/org/neo4j/jdbc/Neo4jConnectionTest.java b/neo4j-jdbc/src/test/java/org/neo4j/jdbc/Neo4jConnectionTest.java
index a385c174..79ca177e 100644
--- a/neo4j-jdbc/src/test/java/org/neo4j/jdbc/Neo4jConnectionTest.java
+++ b/neo4j-jdbc/src/test/java/org/neo4j/jdbc/Neo4jConnectionTest.java
@@ -23,6 +23,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.mockito.Mockito;
+import org.neo4j.jdbc.impl.Neo4jConnectionImpl;
 
 import java.sql.SQLException;
 
@@ -42,7 +43,7 @@ public class Neo4jConnectionTest {
 	/*------------------------------*/
 
 	@Test public void isWrapperForShouldReturnTrue() throws SQLException {
-		Neo4jConnection connection = mock(Neo4jConnection.class, Mockito.CALLS_REAL_METHODS);
+		Neo4jConnection connection = mock(Neo4jConnectionImpl.class, Mockito.CALLS_REAL_METHODS);
 
 		assertTrue(connection.isWrapperFor(Neo4jConnection.class));
 		assertTrue(connection.isWrapperFor(java.sql.Connection.class));
@@ -51,7 +52,7 @@ public class Neo4jConnectionTest {
 	}
 
 	@Test public void isWrapperForShouldReturnFalse() throws SQLException {
-		Neo4jConnection connection = mock(Neo4jConnection.class, Mockito.CALLS_REAL_METHODS);
+		Neo4jConnection connection = mock(Neo4jConnectionImpl.class, Mockito.CALLS_REAL_METHODS);
 
 		assertFalse(connection.isWrapperFor(Neo4jStatement.class));
 		assertFalse(connection.isWrapperFor(java.sql.Driver.class));
@@ -64,7 +65,7 @@ public class Neo4jConnectionTest {
 	/*------------------------------*/
 
 	@Test public void unwrapShouldReturnCorrectClass() throws SQLException {
-		Neo4jConnection connection = mock(Neo4jConnection.class, Mockito.CALLS_REAL_METHODS);
+		Neo4jConnection connection = mock(Neo4jConnectionImpl.class, Mockito.CALLS_REAL_METHODS);
 
 		assertNotNull(connection.unwrap(Neo4jConnection.class));
 		assertNotNull(connection.unwrap(java.sql.Connection.class));
@@ -75,7 +76,7 @@ public class Neo4jConnectionTest {
 	@Test public void unwrapShouldThrowException() throws SQLException {
 		expectedEx.expect(SQLException.class);
 
-		Neo4jConnection connection = mock(Neo4jConnection.class, Mockito.CALLS_REAL_METHODS);
+		Neo4jConnection connection = mock(Neo4jConnectionImpl.class, Mockito.CALLS_REAL_METHODS);
 
 		connection.unwrap(Neo4jStatement.class);
 	}