diff src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java @ 172:60063c67f9e7 embedded

Merged with default
author Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
date Tue, 19 Sep 2017 13:49:34 +0200 (2017-09-19)
parents 6c74540a8e6b 89e954e7acbb
children 89c285fc0a49
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
@@ -11,6 +11,7 @@ import nl.cwi.monetdb.mcl.protocol.Start
 import nl.cwi.monetdb.mcl.responses.*;
 
 import java.io.IOException;
+import java.net.SocketException;
 import java.net.SocketTimeoutException;
 import java.sql.*;
 import java.util.*;
@@ -41,1654 +42,1769 @@ import java.util.concurrent.Executor;
  * @author Fabian Groffen, Martin van Dinther, Pedro Ferreira
  * @version 1.3
  */
-public abstract class MonetConnection extends MonetWrapper implements Connection {
+public abstract class MonetConnection extends MonetWrapper implements Connection, AutoCloseable {
 
-    /** The sequence counter */
-    private static int SeqCounter = 0;
+	/** The sequence counter */
+	private static int SeqCounter = 0;
 
-    /**
-     * Gets the current sequence counter.
-     *
-     * @return The current sequence counter
-     */
-    public static int getSeqCounter() {
-        return SeqCounter;
-    }
+	/**
+	 * Gets the current sequence counter.
+	 *
+	 * @return The current sequence counter
+	 */
+	public static int getSeqCounter() {
+		return SeqCounter;
+	}
 
-    /** The successful processed input properties */
-    protected final Properties conn_props;
-    /** The language to connect with */
-    protected IMonetDBLanguage language;
-    /** Authentication hash method */
-    protected final String hash;
-    /** An optional thread that is used for sending large queries */
-    private SenderThread senderThread;
-    /** Whether this Connection is closed (and cannot be used anymore) */
-    private boolean closed;
-    /** Whether this Connection is in autocommit mode */
-    private boolean autoCommit = true;
-    /** The stack of warnings for this Connection object */
-    private SQLWarning warnings;
-    /** The Connection specific mapping of user defined types to Java types */
-    private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {
-        private static final long serialVersionUID = 1L; {
-            put("inet", MonetINET.class);
-            put("url", MonetURL.class);
-        }
-    };
+	/** The successful processed input properties */
+	protected final Properties conn_props;
+	/** The language to connect with */
+	protected IMonetDBLanguage language;
+	/** Authentication hash method */
+	protected final String hash;
+	/** An optional thread that is used for sending large queries */
+	private SenderThread senderThread;
+	/** Whether this Connection is closed (and cannot be used anymore) */
+	private boolean closed;
+	/** Whether this Connection is in autocommit mode */
+	private boolean autoCommit = true;
+	/** The stack of warnings for this Connection object */
+	private SQLWarning warnings;
+	/** The Connection specific mapping of user defined types to Java types */
+	private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {
+		private static final long serialVersionUID = 1L; {
+			put("inet", MonetINET.class);
+			put("url", MonetURL.class);
+		}
+	};
+
+	// See javadoc for documentation about WeakHashMap if you don't know what it does !!!NOW!!!
+	// (only when you deal with it of course)
+	/** A Map containing all (active) Statements created from this Connection */
+	private Map<Statement,?> statements = new WeakHashMap<>();
+	/** The number of results we receive from the server at once */
+	private int curReplySize = -1; // the server by default uses -1 (all)
+	/** Whether or not BLOB is mapped to LONGVARBINARY within the driver */
+	private final boolean blobIsBinary;
+	/** Whether or not CLOB is mapped to LONGVARCHAR within the driver */
+	private final boolean clobIsLongChar;
+	/** The underlying proticol provided by the connection (MAPI or embedded) */
+	protected AbstractProtocol protocol;
+	/** Tells if the connection is embedded or not */
+	private final boolean isEmbedded;
 
-    // See javadoc for documentation about WeakHashMap if you don't know what it does !!!NOW!!!
-    // (only when you deal with it of course)
-    /** A Map containing all (active) Statements created from this Connection */
-    private Map<Statement,?> statements = new WeakHashMap<>();
-    /** The number of results we receive from the server at once */
-    private int curReplySize = -1; // the server by default uses -1 (all)
-    /** Whether or not BLOB is mapped to LONGVARBINARY within the driver */
-    private final boolean blobIsBinary;
-    /** Whether or not CLOB is mapped to LONGVARCHAR within the driver */
-    private final boolean clobIsLongChar;
-    /** The underlying proticol provided by the connection (MAPI or embedded) */
-    protected AbstractProtocol protocol;
-    /** Tells if the connection is embedded or not */
-    private final boolean isEmbedded;
+	/**
+	 * Constructor of a Connection for MonetDB. At this moment the current implementation limits itself to storing the
+	 * given host, database, username and password for later use by the createStatement() call.  This constructor is
+	 * only accessible to classes from the jdbc package.
+	 */
+	public MonetConnection(Properties props, String hash, IMonetDBLanguage language, boolean blobIsBinary,
+						   boolean clobIsLongChar) {
+		this.conn_props = props;
+		this.hash = hash;
+		this.language = language;
+		this.blobIsBinary = blobIsBinary;
+		this.clobIsLongChar = clobIsLongChar;
+		//"instance of" should be cleanner, but this is faster.
+		this.isEmbedded = props.getProperty("embedded", "false").equals("true");
+	}
+
+	/**
+	 * Checks if the conection is embedded or not
+	 *
+	 * @return If the connection is embedded
+	 */
+	public boolean isEmbedded() {
+		return isEmbedded;
+	}
 
-    /**
-     * Constructor of a Connection for MonetDB. At this moment the current implementation limits itself to storing the
-     * given host, database, username and password for later use by the createStatement() call.  This constructor is
-     * only accessible to classes from the jdbc package.
-     *
-     * @throws IOException if an error occurs
-     */
-    public MonetConnection(Properties props, String hash, IMonetDBLanguage language, boolean blobIsBinary,
-                           boolean clobIsLongChar) throws IOException {
-        this.conn_props = props;
-        this.hash = hash;
-        this.language = language;
-        this.blobIsBinary = blobIsBinary;
-        this.clobIsLongChar = clobIsLongChar;
-        //"instance of" should be cleanner, but this is faster.
-        this.isEmbedded = props.getProperty("embedded", "false").equals("true");
-    }
+	/**
+	 * Gets the connection's language data.
+	 *
+	 * @return The connection's language data
+	 */
+	public IMonetDBLanguage getLanguage() {
+		return language;
+	}
 
-    /**
-     * Checks if the conection is embedded or not
-     *
-     * @return If the connection is embedded
-     */
-    public boolean isEmbedded() {
-        return isEmbedded;
-    }
+	/**
+	 * Gets the connection's protocol.
+	 *
+	 * @return The connection's protocol
+	 */
+	public AbstractProtocol getProtocol() {
+		return this.protocol;
+	}
 
-    /**
-     * Gets the connection's language data.
-     *
-     * @return The connection's language data
-     */
-    public IMonetDBLanguage getLanguage() {
-        return language;
-    }
-
-    /**
-     * Gets the connection's protocol.
-     *
-     * @return The connection's protocol
-     */
-    public AbstractProtocol getProtocol() {
-        return this.protocol;
-    }
+	/**
+	 * Connects to the server, authenticating the user.
+	 *
+	 * @param user The user name to authenticate
+	 * @param pass The user's password
+	 * @return A List with informational (warning) messages. If this list is empty; then there are no warnings.
+	 * @throws IOException if an I/O error occurs when creating the socket
+	 * @throws ProtocolException if bogus data is received
+	 * @throws MCLException if an MCL related error occurs
+	 */
+	public abstract List<String> connect(String user, String pass) throws IOException, ProtocolException, MCLException;
 
-    /**
-     * Connects to the server, authenticating the user.
-     *
-     * @param user The user name to authenticate
-     * @param pass The user's password
-     * @return A List with informational (warning) messages. If this list is empty; then there are no warnings.
-     * @throws IOException if an I/O error occurs when creating the socket
-     * @throws ProtocolException if bogus data is received
-     * @throws MCLException if an MCL related error occurs
-     */
-    public abstract List<String> connect(String user, String pass) throws IOException, ProtocolException, MCLException;
+	/**
+	 * Gets the underlying connection block size length.
+	 *
+	 * @return The block size length
+	 */
+	public abstract int getBlockSize();
 
-    /**
-     * Gets the underlying connection block size length.
-     *
-     * @return The block size length
-     */
-    public abstract int getBlockSize();
+	/**
+	 * Gets the underlying connection default fetch size for DataBlock responses.
+	 *
+	 * @return The default fetch size
+	 */
+	public abstract int getDefFetchsize();
+
+	/**
+	 * Gets the initial value for the StringBuilder size.
+	 *
+	 * @return The initial value for the StringBuilder size
+	 */
+	public abstract int initialStringBuilderSize();
 
-    /**
-     * Gets the underlying connection default fetch size for DataBlock responses.
-     *
-     * @return The default fetch size
-     */
-    public abstract int getDefFetchsize();
+	/**
+	 * Gets the underlying connection socket timeout.
+	 *
+	 * @return The underlying connection socket timeout
+	 */
+	public abstract int getSoTimeout() throws SocketException;
 
-    /**
-     * Gets the initial value for the StringBuilder size.
-     *
-     * @return The initial value for the StringBuilder size
-     */
-    public abstract int initialStringBuilderSize();
+	/**
+	 * Sets the underlying connection socket timeout.
+	 *
+	 * @param timeout The specified timeout, in milliseconds. A timeout of zero is interpreted as an infinite timeout
+	 */
+	public abstract void setSoTimeout(int timeout) throws SocketException;
 
-    /**
-     * Gets the underlying connection socket timeout.
-     *
-     * @return The underlying connection socket timeout
-     */
-    public abstract int getSoTimeout();
+	/**
+	 * Closes the underlying connection implementation.
+	 *
+	 * @throws IOException if an I/O error occurs while closing the connection
+	 */
+	public abstract void closeUnderlyingConnection() throws IOException;
 
-    /**
-     * Sets the underlying connection socket timeout.
-     *
-     * @param timeout The specified timeout, in milliseconds. A timeout of zero is interpreted as an infinite timeout
-     */
-    public abstract void setSoTimeout(int timeout);
+	/**
+	 * Gets the underlying connection JDBC String URL.
+	 *
+	 * @return The underlying connection JDBC String URL
+	 */
+	public abstract String getJDBCURL();
 
-    /**
-     * Closes the underlying connection implementation.
-     *
-     * @throws IOException if an I/O error occurs while closing the connection
-     */
-    public abstract void closeUnderlyingConnection() throws IOException;
-
-    /**
-     * Gets the underlying connection JDBC String URL.
-     *
-     * @return The underlying connection JDBC String URL
-     */
-    public abstract String getJDBCURL();
-
-    /**
-     * Sends a control command to the server.
-     *
-     * @param commandID the command identifier according to {@link ControlCommands} listing
-     * @param data The integer to send according to the control command
-     * @throws SQLException if an IO exception or a database error occurs
-     */
-    public abstract void sendControlCommand(int commandID, int data) throws SQLException;
+	/**
+	 * Sends a control command to the server.
+	 *
+	 * @param commandID the command identifier according to {@link ControlCommands} listing
+	 * @param data The integer to send according to the control command
+	 * @throws SQLException if an IO exception or a database error occurs
+	 */
+	public abstract void sendControlCommand(int commandID, int data) throws SQLException;
 
-    /**
-     * Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be
-     * automatically released. All Statements created from this Connection will be closed when this method is called.
-     *
-     * Calling the method close on a Connection object that is already closed is a no-op.
-     */
-    @Override
-    public void close() {
-        for (Statement st : statements.keySet()) {
-            try {
-                st.close();
-            } catch (SQLException e) {
-                // better luck next time!
-            }
-        }
-        // close the socket or the embedded server
-        try {
-            this.closeUnderlyingConnection();
-        } catch (IOException e) {
-            // ignore it
-        }
-        // close active SendThread if any
-        if (senderThread != null) {
-            senderThread.shutdown();
-            senderThread = null;
-        }
-        // report ourselves as closed
-        closed = true;
-    }
+	/**
+	 * Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be
+	 * automatically released. All Statements created from this Connection will be closed when this method is called.
+	 *
+	 * Calling the method close on a Connection object that is already closed is a no-op.
+	 */
+	@Override
+	public void close() {
+		for (Statement st : statements.keySet()) {
+			try {
+				st.close();
+			} catch (SQLException e) {
+				// better luck next time!
+			}
+		}
+		// close the socket or the embedded server
+		try {
+			this.closeUnderlyingConnection();
+		} catch (IOException e) {
+			// ignore it
+		}
+		// close active SendThread if any
+		if (senderThread != null) {
+			senderThread.shutdown();
+			senderThread = null;
+		}
+		// report ourselves as closed
+		closed = true;
+	}
+
+	/**
+	 * Destructor called by garbage collector before destroying this object tries to disconnect the MonetDB connection
+	 * if it has not been disconnected already.
+	 */
+	@Override
+	protected void finalize() throws Throwable {
+		this.close();
+		super.finalize();
+	}
+
+	//== methods of interface Connection
+
+	/**
+	 * Clears all warnings reported for this Connection object. After a call to this method, the method getWarnings
+	 * returns null until a new warning is reported for this Connection object.
+	 */
+	@Override
+	public void clearWarnings() {
+		warnings = null;
+	}
 
-    /**
-     * Destructor called by garbage collector before destroying this object tries to disconnect the MonetDB connection
-     * if it has not been disconnected already.
-     */
-    @Override
-    protected void finalize() throws Throwable {
-        this.close();
-        super.finalize();
-    }
-
-    //== methods of interface Connection
+	/**
+	 * Makes all changes made since the previous commit/rollback permanent and releases any database locks currently
+	 * held by this Connection object. This method should be used only when auto-commit mode has been disabled.
+	 *
+	 * @throws SQLException if a database access error occurs or this Connection object is in auto-commit mode
+	 * @see #setAutoCommit(boolean)
+	 */
+	@Override
+	public void commit() throws SQLException {
+		// note: can't use sendIndependentCommand here because we need to process the auto_commit state the server gives
+		this.sendTransactionCommand("COMMIT");
+	}
 
-    /**
-     * Clears all warnings reported for this Connection object. After a call to this method, the method getWarnings
-     * returns null until a new warning is reported for this Connection object.
-     */
-    @Override
-    public void clearWarnings() {
-        warnings = null;
-    }
+	/**
+	 * Creates a Statement object for sending SQL statements to the
+	 * database.  SQL statements without parameters are normally
+	 * executed using Statement objects. If the same SQL statement is
+	 * executed many times, it may be more efficient to use a
+	 * PreparedStatement object.
+	 *
+	 * Result sets created using the returned Statement object will by
+	 * default be type TYPE_FORWARD_ONLY and have a concurrency level of
+	 * CONCUR_READ_ONLY.
+	 *
+	 * @return a new default Statement object
+	 * @throws SQLException if a database access error occurs
+	 */
+	@Override
+	public Statement createStatement() throws SQLException {
+		return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+	}
 
-    private void createResponseList(String query) throws SQLException {
-        // create a container for the result
-        ResponseList l = new ResponseList(0, 0, ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY);
-        // send commit to the server
-        try {
-            l.processQuery(query);
-        } finally {
-            l.close();
-        }
-    }
+	/**
+	 * Creates a Statement object that will generate ResultSet objects
+	 * with the given type and concurrency. This method is the same as
+	 * the createStatement method above, but it allows the default
+	 * result set type and concurrency to be overridden.
+	 *
+	 * @param resultSetType a result set type; one of
+	 *        ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
+	 *        or ResultSet.TYPE_SCROLL_SENSITIVE
+	 * @param resultSetConcurrency a concurrency type; one of
+	 *        ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE
+	 * @return a new Statement object that will generate ResultSet objects with
+	 *         the given type and concurrency
+	 * @throws SQLException if a database access error occurs
+	 */
+	@Override
+	public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+		return createStatement(resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+	}
 
-    /**
-     * Makes all changes made since the previous commit/rollback permanent and releases any database locks currently
-     * held by this Connection object. This method should be used only when auto-commit mode has been disabled.
-     *
-     * @throws SQLException if a database access error occurs or this Connection object is in auto-commit mode
-     * @see #setAutoCommit(boolean)
-     */
-    @Override
-    public void commit() throws SQLException {
-        // note: can't use sendIndependentCommand here because we need to process the auto_commit state the server gives
-        this.createResponseList("COMMIT");
-    }
+	/**
+	 * Creates a Statement object that will generate ResultSet objects
+	 * with the given type, concurrency, and holdability.  This method
+	 * is the same as the createStatement method above, but it allows
+	 * the default result set type, concurrency, and holdability to be
+	 * overridden.
+	 *
+	 * @param resultSetType one of the following ResultSet constants:
+	 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
+	 * or ResultSet.TYPE_SCROLL_SENSITIVE
+	 * @param resultSetConcurrency one of the following ResultSet
+	 * constants: ResultSet.CONCUR_READ_ONLY or
+	 * ResultSet.CONCUR_UPDATABLE
+	 * @param resultSetHoldability one of the following ResultSet
+	 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
+	 * ResultSet.CLOSE_CURSORS_AT_COMMIT
+	 *
+	 * @return a new Statement      object that will generate ResultSet
+	 * objects with the given type, concurrency, and holdability
+	 * @throws SQLException if a database access error occurs or the
+	 * given parameters are not ResultSet constants indicating type,
+	 * concurrency, and holdability
+	 */
+	@Override
+	public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+		try {
+			Statement ret = new MonetStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability);
+			// store it in the map for when we close...
+			statements.put(ret, null);
+			return ret;
+		} catch (IllegalArgumentException e) {
+			throw new SQLException(e.toString(), "M0M03");
+		}
+		// we don't have to catch SQLException because that is declared to
+		// be thrown
+	}
 
-    /**
-     * Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are
-     * normally executed using Statement objects. If the same SQL statement is executed many times, it may be more
-     * efficient to use a PreparedStatement object.
-     *
-     * Result sets created using the returned Statement object will by default be type TYPE_FORWARD_ONLY and have a
-     * concurrency level of CONCUR_READ_ONLY.
-     *
-     * @return a new default Statement object
-     * @throws SQLException if a database access error occurs
-     */
-    @Override
-    public Statement createStatement() throws SQLException {
-        return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
-                ResultSet.HOLD_CURSORS_OVER_COMMIT);
-    }
+	/**
+	 * Retrieves the current auto-commit mode for this Connection object.
+	 *
+	 * @return the current state of this Connection object's auto-commit mode
+	 * @see #setAutoCommit(boolean)
+	 */
+	@Override
+	public boolean getAutoCommit() throws SQLException {
+		return autoCommit;
+	}
 
-    /**
-     * Creates a Statement object that will generate ResultSet objects with the given type and concurrency. This method
-     * is the same as the createStatement method above, but it allows the default result set type and concurrency to be
-     * overridden.
-     *
-     * @param resultSetType a result set type; one of ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
-     * or ResultSet.TYPE_SCROLL_SENSITIVE
-     * @param resultSetConcurrency a concurrency type; one of ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE
-     * @return a new Statement object that will generate ResultSet objects with the given type and concurrency
-     * @throws SQLException if a database access error occurs
-     */
-    @Override
-    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
-        return createStatement(resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
-    }
+	/**
+	 * Retrieves this Connection object's current catalog name.
+	 *
+	 * @return the current catalog name or null if there is none
+	 * @throws SQLException if a database access error occurs or the current language is not SQL
+	 */
+	@Override
+	public String getCatalog() throws SQLException {
+		// MonetDB does NOT support catalogs
+		return null;
+	}
 
-    /**
-     * Creates a Statement object that will generate ResultSet objects
-     * with the given type, concurrency, and holdability.  This method
-     * is the same as the createStatement method above, but it allows
-     * the default result set type, concurrency, and holdability to be
-     * overridden.
-     *
-     * @param resultSetType one of the following ResultSet constants:
-     * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
-     * or ResultSet.TYPE_SCROLL_SENSITIVE
-     * @param resultSetConcurrency one of the following ResultSet
-     * constants: ResultSet.CONCUR_READ_ONLY or
-     * ResultSet.CONCUR_UPDATABLE
-     * @param resultSetHoldability one of the following ResultSet
-     * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
-     * ResultSet.CLOSE_CURSORS_AT_COMMIT
-     *
-     * @return a new Statement      object that will generate ResultSet
-     * objects with the given type, concurrency, and holdability
-     * @throws SQLException if a database access error occurs or the
-     * given parameters are not ResultSet constants indicating type,
-     * concurrency, and holdability
-     */
-    @Override
-    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
-            throws SQLException {
-        try {
-            Statement ret = new MonetStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability);
-            // store it in the map for when we close...
-            statements.put(ret, null);
-            return ret;
-        } catch (IllegalArgumentException e) {
-            throw new SQLException(e.toString(), "M0M03");
-        }
-        // we don't have to catch SQLException because that is declared to
-        // be thrown
-    }
+	/**
+	 * Retrieves the current holdability of ResultSet objects created using this Connection object.
+	 *
+	 * @return the holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT
+	 */
+	@Override
+	public int getHoldability() {
+		// TODO: perhaps it is better to have the server implement
+		//       CLOSE_CURSORS_AT_COMMIT
+		return ResultSet.HOLD_CURSORS_OVER_COMMIT;
+	}
 
-    /**
-     * Retrieves the current auto-commit mode for this Connection object.
-     *
-     * @return the current state of this Connection object's auto-commit mode
-     * @see #setAutoCommit(boolean)
-     */
-    @Override
-    public boolean getAutoCommit() throws SQLException {
-        return autoCommit;
-    }
+	/**
+	 * Retrieves a DatabaseMetaData object that contains metadata about
+	 * the database to which this Connection object represents a
+	 * connection. The metadata includes information about the
+	 * database's tables, its supported SQL grammar, its stored
+	 * procedures, the capabilities of this connection, and so on.
+	 *
+	 * @throws SQLException if the current language is not SQL
+	 * @return a DatabaseMetaData object for this Connection object
+	 */
+	@Override
+	public DatabaseMetaData getMetaData() throws SQLException {
+		if (!this.language.getRepresentation().equals("sql")) {
+			throw new SQLException("This method is only supported in SQL mode", "M0M04");
+		}
+		return new MonetDatabaseMetaData(this);
+	}
 
-    /**
-     * Retrieves this Connection object's current catalog name.
-     *
-     * @return the current catalog name or null if there is none
-     * @throws SQLException if a database access error occurs or the current language is not SQL
-     */
-    @Override
-    public String getCatalog() throws SQLException {
-        // MonetDB does NOT support catalogs
-        return null;
-    }
+	/**
+	 * Retrieves this Connection object's current transaction isolation level.
+	 *
+	 * @return the current transaction isolation level, which will be Connection.TRANSACTION_SERIALIZABLE
+	 */
+	@Override
+	public int getTransactionIsolation() {
+		return TRANSACTION_SERIALIZABLE;
+	}
+
+	/**
+	 * Retrieves the Map object associated with this Connection object. Unless the application has added an entry,
+	 * the type map returned will be empty.
+	 *
+	 * @return the java.util.Map object associated with this Connection object
+	 */
+	@Override
+	public Map<String,Class<?>> getTypeMap() {
+		return typeMap;
+	}
 
-    /**
-     * Retrieves the current holdability of ResultSet objects created using this Connection object.
-     *
-     * @return the holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT
-     */
-    @Override
-    public int getHoldability() {
-        // TODO: perhaps it is better to have the server implement
-        //       CLOSE_CURSORS_AT_COMMIT
-        return ResultSet.HOLD_CURSORS_OVER_COMMIT;
-    }
-
-    /**
-     * Retrieves a DatabaseMetaData object that contains metadata about
-     * the database to which this Connection object represents a
-     * connection. The metadata includes information about the
-     * database's tables, its supported SQL grammar, its stored
-     * procedures, the capabilities of this connection, and so on.
-     *
-     * @throws SQLException if the current language is not SQL
-     * @return a DatabaseMetaData object for this Connection object
-     */
-    @Override
-    public DatabaseMetaData getMetaData() throws SQLException {
-        if (!this.language.getRepresentation().equals("sql")) {
-            throw new SQLException("This method is only supported in SQL mode", "M0M04");
-        }
-        return new MonetDatabaseMetaData(this);
-    }
+	/**
+	 * Retrieves the first warning reported by calls on this Connection
+	 * object.  If there is more than one warning, subsequent warnings
+	 * will be chained to the first one and can be retrieved by calling
+	 * the method SQLWarning.getNextWarning on the warning that was
+	 * retrieved previously.
+	 *
+	 * This method may not be called on a closed connection; doing so will cause an SQLException to be thrown.
+	 *
+	 * Note: Subsequent warnings will be chained to this SQLWarning.
+	 *
+	 * @return the first SQLWarning object or null if there are none
+	 * @throws SQLException if a database access error occurs or this method is called on a closed connection
+	 */
+	@Override
+	public SQLWarning getWarnings() throws SQLException {
+		if (closed) {
+			throw new SQLException("Cannot call on closed Connection", "M1M20");
+		}
+		// if there are no warnings, this will be null, which fits with the specification.
+		return warnings;
+	}
 
-    /**
-     * Retrieves this Connection object's current transaction isolation level.
-     *
-     * @return the current transaction isolation level, which will be Connection.TRANSACTION_SERIALIZABLE
-     */
-    @Override
-    public int getTransactionIsolation() {
-        return TRANSACTION_SERIALIZABLE;
-    }
-
-    /**
-     * Retrieves the Map object associated with this Connection object. Unless the application has added an entry,
-     * the type map returned will be empty.
-     *
-     * @return the java.util.Map object associated with this Connection object
-     */
-    @Override
-    public Map<String,Class<?>> getTypeMap() {
-        return typeMap;
-    }
+	/**
+	 * Retrieves whether this Connection object has been closed.  A
+	 * connection is closed if the method close has been called on it or
+	 * if certain fatal errors have occurred.  This method is guaranteed
+	 * to return true only when it is called after the method
+	 * Connection.close has been called.
+	 *
+	 * This method generally cannot be called to determine whether a
+	 * connection to a database is valid or invalid.  A typical client
+	 * can determine that a connection is invalid by catching any
+	 * exceptions that might be thrown when an operation is attempted.
+	 *
+	 * @return true if this Connection object is closed; false if it is still open
+	 */
+	@Override
+	public boolean isClosed() {
+		return closed;
+	}
 
-    /**
-     * Retrieves the first warning reported by calls on this Connection
-     * object.  If there is more than one warning, subsequent warnings
-     * will be chained to the first one and can be retrieved by calling
-     * the method SQLWarning.getNextWarning on the warning that was
-     * retrieved previously.
-     *
-     * This method may not be called on a closed connection; doing so will cause an SQLException to be thrown.
-     *
-     * Note: Subsequent warnings will be chained to this SQLWarning.
-     *
-     * @return the first SQLWarning object or null if there are none
-     * @throws SQLException if a database access error occurs or this method is called on a closed connection
-     */
-    @Override
-    public SQLWarning getWarnings() throws SQLException {
-        if (closed) {
-            throw new SQLException("Cannot call on closed Connection", "M1M20");
-        }
-        // if there are no warnings, this will be null, which fits with the specification.
-        return warnings;
-    }
+	/**
+	 * Retrieves whether this Connection object is in read-only mode.
+	 * MonetDB currently doesn't support updateable result sets, but
+	 * updates are possible.  Hence the Connection object is never in
+	 * read-only mode.
+	 *
+	 * @return true if this Connection object is read-only; false otherwise
+	 */
+	@Override
+	public boolean isReadOnly() {
+		return false;
+	}
+
+	@Override
+	public String nativeSQL(String sql) {
+		/* there is currently no way to get the native MonetDB rewritten SQL string back, so just return the original string */
+		/* in future we may replace/remove the escape sequences { <escape-type> ...} before sending it to the server */
+		return sql;
+	}
 
-    /**
-     * Retrieves whether this Connection object has been closed.  A
-     * connection is closed if the method close has been called on it or
-     * if certain fatal errors have occurred.  This method is guaranteed
-     * to return true only when it is called after the method
-     * Connection.close has been called.
-     *
-     * This method generally cannot be called to determine whether a
-     * connection to a database is valid or invalid.  A typical client
-     * can determine that a connection is invalid by catching any
-     * exceptions that might be thrown when an operation is attempted.
-     *
-     * @return true if this Connection object is closed; false if it is still open
-     */
-    @Override
-    public boolean isClosed() {
-        return closed;
-    }
+	@Override
+	public CallableStatement prepareCall(String sql) {
+		/* not implemented yet */
+		return null;
+	}
 
-    /**
-     * Retrieves whether this Connection object is in read-only mode.
-     * MonetDB currently doesn't support updateable result sets, but
-     * updates are possible.  Hence the Connection object is never in
-     * read-only mode.
-     *
-     * @return true if this Connection object is read-only; false otherwise
-     */
-    @Override
-    public boolean isReadOnly() {
-        return false;
-    }
+	@Override
+	public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) {
+		/* not implemented yet */
+		return null;
+	}
 
-    @Override
-    public String nativeSQL(String sql) {return sql;}
-
-    @Override
-    public CallableStatement prepareCall(String sql) {return null;}
+	@Override
+	public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
+		/* not implemented yet */
+		return null;
+	}
 
-    @Override
-    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) {return null;}
-
-    @Override
-    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
-                                         int resultSetHoldability) {return null;}
+	/**
+	 * Creates a PreparedStatement object for sending parameterized SQL
+	 * statements to the database.
+	 *
+	 * A SQL statement with or without IN parameters can be pre-compiled
+	 * and stored in a PreparedStatement object. This object can then be
+	 * used to efficiently execute this statement multiple times.
+	 *
+	 * Note: This method is optimized for handling parametric SQL
+	 * statements that benefit from precompilation. If the driver
+	 * supports precompilation, the method prepareStatement will send
+	 * the statement to the database for precompilation. Some drivers
+	 * may not support precompilation. In this case, the statement may
+	 * not be sent to the database until the PreparedStatement object is
+	 * executed. This has no direct effect on users; however, it does
+	 * affect which methods throw certain SQLException objects.
+	 *
+	 * Result sets created using the returned PreparedStatement object
+	 * will by default be type TYPE_FORWARD_ONLY and have a concurrency
+	 * level of CONCUR_READ_ONLY.
+	 *
+	 * @param sql an SQL statement that may contain one or more '?' IN
+	 *        parameter placeholders
+	 * @return a new default PreparedStatement object containing the
+	 *         pre-compiled SQL statement
+	 * @throws SQLException if a database access error occurs
+	 */
+	@Override
+	public PreparedStatement prepareStatement(String sql) throws SQLException {
+		return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+	}
 
-    /**
-     * Creates a PreparedStatement object for sending parameterized SQL
-     * statements to the database.
-     *
-     * A SQL statement with or without IN parameters can be pre-compiled
-     * and stored in a PreparedStatement object. This object can then be
-     * used to efficiently execute this statement multiple times.
-     *
-     * Note: This method is optimized for handling parametric SQL
-     * statements that benefit from precompilation. If the driver
-     * supports precompilation, the method prepareStatement will send
-     * the statement to the database for precompilation. Some drivers
-     * may not support precompilation. In this case, the statement may
-     * not be sent to the database until the PreparedStatement object is
-     * executed. This has no direct effect on users; however, it does
-     * affect which methods throw certain SQLException objects.
-     *
-     * Result sets created using the returned PreparedStatement object
-     * will by default be type TYPE_FORWARD_ONLY and have a concurrency
-     * level of CONCUR_READ_ONLY.
-     *
-     * @param sql an SQL statement that may contain one or more '?' IN
-     *        parameter placeholders
-     * @return a new default PreparedStatement object containing the
-     *         pre-compiled SQL statement
-     * @throws SQLException if a database access error occurs
-     */
-    @Override
-    public PreparedStatement prepareStatement(String sql) throws SQLException {
-        return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
-                ResultSet.HOLD_CURSORS_OVER_COMMIT);
-    }
+	/**
+	 * Creates a PreparedStatement object that will generate ResultSet
+	 * objects with the given type and concurrency.  This method is the
+	 * same as the prepareStatement method above, but it allows the
+	 * default result set type and concurrency to be overridden.
+	 *
+	 * @param sql a String object that is the SQL statement to be sent to the
+	 *        database; may contain one or more ? IN parameters
+	 * @param resultSetType a result set type; one of
+	 *        ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
+	 *        or ResultSet.TYPE_SCROLL_SENSITIVE
+	 * @param resultSetConcurrency a concurrency type; one of
+	 *        ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE
+	 * @return a new PreparedStatement object containing the pre-compiled SQL
+	 *         statement that will produce ResultSet objects with the given
+	 *         type and concurrency
+	 * @throws SQLException if a database access error occurs or the given
+	 *         parameters are not ResultSet constants indicating
+	 *         type and concurrency
+	 */
+	@Override
+	public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+		return prepareStatement(sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+	}
 
-    /**
-     * Creates a PreparedStatement object that will generate ResultSet
-     * objects with the given type and concurrency.  This method is the
-     * same as the prepareStatement method above, but it allows the
-     * default result set type and concurrency to be overridden.
-     *
-     * @param sql a String object that is the SQL statement to be sent to the
-     *            database; may contain one or more ? IN parameters
-     * @param resultSetType a result set type; one of
-     *        ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
-     *        or ResultSet.TYPE_SCROLL_SENSITIVE
-     * @param resultSetConcurrency a concurrency type; one of
-     *        ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE
-     * @return a new PreparedStatement object containing the pre-compiled SQL
-     *         statement that will produce ResultSet objects with the given
-     *         type and concurrency
-     * @throws SQLException if a database access error occurs or the given
-     *                      parameters are not ResultSet constants indicating
-     *                      type and concurrency
-     */
-    @Override
-    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
-            throws SQLException {
-        return prepareStatement(sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
-    }
+	/**
+	 * Creates a PreparedStatement object that will generate ResultSet
+	 * objects with the given type, concurrency, and holdability.
+	 *
+	 * This method is the same as the prepareStatement method above, but
+	 * it allows the default result set type, concurrency, and
+	 * holdability to be overridden.
+	 *
+	 * @param sql a String object that is the SQL statement to be sent
+	 * to the database; may contain one or more ? IN parameters
+	 * @param resultSetType one of the following ResultSet constants:
+	 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
+	 * or ResultSet.TYPE_SCROLL_SENSITIVE
+	 * @param resultSetConcurrency one of the following ResultSet
+	 * constants: ResultSet.CONCUR_READ_ONLY or
+	 * ResultSet.CONCUR_UPDATABLE
+	 * @param resultSetHoldability one of the following ResultSet
+	 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
+	 * ResultSet.CLOSE_CURSORS_AT_COMMIT
+	 * @return a new PreparedStatement object, containing the
+	 * pre-compiled SQL statement, that will generate ResultSet objects
+	 * with the given type, concurrency, and holdability
+	 * @throws SQLException if a database access error occurs or the
+	 * given parameters are not ResultSet constants indicating type,
+	 * concurrency, and holdability
+	 */
+	@Override
+	public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+			throws SQLException {
+		try {
+			PreparedStatement ret = new MonetPreparedStatement(this, resultSetType, resultSetConcurrency,
+					resultSetHoldability, sql);
+			// store it in the map for when we close...
+			statements.put(ret, null);
+			return ret;
+		} catch (IllegalArgumentException e) {
+			throw new SQLException(e.toString(), "M0M03");
+		}
+		// we don't have to catch SQLException because that is declared to
+		// be thrown
+	}
 
-    /**
-     * Creates a PreparedStatement object that will generate ResultSet
-     * objects with the given type, concurrency, and holdability.
-     *
-     * This method is the same as the prepareStatement method above, but
-     * it allows the default result set type, concurrency, and
-     * holdability to be overridden.
-     *
-     * @param sql a String object that is the SQL statement to be sent
-     * to the database; may contain one or more ? IN parameters
-     * @param resultSetType one of the following ResultSet constants:
-     * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
-     * or ResultSet.TYPE_SCROLL_SENSITIVE
-     * @param resultSetConcurrency one of the following ResultSet
-     * constants: ResultSet.CONCUR_READ_ONLY or
-     * ResultSet.CONCUR_UPDATABLE
-     * @param resultSetHoldability one of the following ResultSet
-     * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
-     * ResultSet.CLOSE_CURSORS_AT_COMMIT
-     * @return a new PreparedStatement object, containing the
-     * pre-compiled SQL statement, that will generate ResultSet objects
-     * with the given type, concurrency, and holdability
-     * @throws SQLException if a database access error occurs or the
-     * given parameters are not ResultSet constants indicating type,
-     * concurrency, and holdability
-     */
-    @Override
-    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
-                                              int resultSetHoldability) throws SQLException {
-        try {
-            PreparedStatement ret = new MonetPreparedStatement(this, resultSetType, resultSetConcurrency,
-                    resultSetHoldability, sql);
-            // store it in the map for when we close...
-            statements.put(ret, null);
-            return ret;
-        } catch (IllegalArgumentException e) {
-            throw new SQLException(e.toString(), "M0M03");
-        }
-        // we don't have to catch SQLException because that is declared to
-        // be thrown
-    }
+	/**
+	 * Creates a default PreparedStatement object that has the
+	 * capability to retrieve auto-generated keys.  The given constant
+	 * tells the driver whether it should make auto-generated keys
+	 * available for retrieval.  This parameter is ignored if the SQL
+	 * statement is not an INSERT statement.
+	 *
+	 * Note: This method is optimized for handling parametric SQL
+	 * statements that benefit from precompilation.  If the driver
+	 * supports precompilation, the method prepareStatement will send
+	 * the statement to the database for precompilation. Some drivers
+	 * may not support precompilation.  In this case, the statement may
+	 * not be sent to the database until the PreparedStatement object is
+	 * executed.  This has no direct effect on users; however, it does
+	 * affect which methods throw certain SQLExceptions.
+	 *
+	 * Result sets created using the returned PreparedStatement object
+	 * will by default be type TYPE_FORWARD_ONLY and have a concurrency
+	 * level of CONCUR_READ_ONLY.
+	 *
+	 * @param sql an SQL statement that may contain one or more '?' IN
+	 *        parameter placeholders
+	 * @param autoGeneratedKeys a flag indicating whether auto-generated
+	 *        keys should be returned; one of
+	 *        Statement.RETURN_GENERATED_KEYS or
+	 *        Statement.NO_GENERATED_KEYS
+	 * @return a new PreparedStatement object, containing the
+	 *         pre-compiled SQL statement, that will have the capability
+	 *         of returning auto-generated keys
+	 * @throws SQLException - if a database access error occurs or the
+	 *         given parameter is not a Statement  constant indicating
+	 *         whether auto-generated keys should be returned
+	 */
+	@Override
+	public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+		if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS &&
+				autoGeneratedKeys != Statement.NO_GENERATED_KEYS)
+			throw new SQLException("Invalid argument, expected RETURN_GENERATED_KEYS or NO_GENERATED_KEYS", "M1M05");
 
-    /**
-     * Creates a default PreparedStatement object that has the
-     * capability to retrieve auto-generated keys.  The given constant
-     * tells the driver whether it should make auto-generated keys
-     * available for retrieval.  This parameter is ignored if the SQL
-     * statement is not an INSERT statement.
-     *
-     * Note: This method is optimized for handling parametric SQL
-     * statements that benefit from precompilation.  If the driver
-     * supports precompilation, the method prepareStatement will send
-     * the statement to the database for precompilation. Some drivers
-     * may not support precompilation.  In this case, the statement may
-     * not be sent to the database until the PreparedStatement object is
-     * executed.  This has no direct effect on users; however, it does
-     * affect which methods throw certain SQLExceptions.
-     *
-     * Result sets created using the returned PreparedStatement object
-     * will by default be type TYPE_FORWARD_ONLY and have a concurrency
-     * level of CONCUR_READ_ONLY.
-     *
-     * @param sql an SQL statement that may contain one or more '?' IN
-     *        parameter placeholders
-     * @param autoGeneratedKeys a flag indicating whether auto-generated
-     *        keys should be returned; one of
-     *        Statement.RETURN_GENERATED_KEYS or
-     *        Statement.NO_GENERATED_KEYS
-     * @return a new PreparedStatement object, containing the
-     *         pre-compiled SQL statement, that will have the capability
-     *         of returning auto-generated keys
-     * @throws SQLException - if a database access error occurs or the
-     *         given parameter is not a Statement  constant indicating
-     *         whether auto-generated keys should be returned
-     */
-    @Override
-    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
-        if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS && autoGeneratedKeys != Statement.NO_GENERATED_KEYS) {
-            throw new SQLException("Invalid argument, expected RETURN_GENERATED_KEYS or NO_GENERATED_KEYS", "M1M05");
-        }
-		/* MonetDB has no way to disable this, so just do the normal thing ;) */
-        return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
-    }
+		/* MonetDB has no way to disable this, so just do the normal
+		 * thing ;) */
+		return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+	}
 
-    @Override
-    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) {return null;}
-
-    @Override
-    public PreparedStatement prepareStatement(String sql, String[] columnNames) {return null;}
+	/**
+	 * Creates a default PreparedStatement object capable of returning the auto-generated keys designated by the given array.
+	 * This array contains the indexes of the columns in the target table that contain the auto-generated keys that should be made available.
+	 * The driver will ignore the array if the SQL statement is not an INSERT statement, or an SQL statement able to
+	 * return auto-generated keys (the list of such statements is vendor-specific).
+	 *
+	 * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object.
+	 * This object can then be used to efficiently execute this statement multiple times.
+	 *
+	 * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation.
+	 * If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation.
+	 * Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement
+	 * object is executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions.
+	 *
+	 * Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have
+	 * a concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling getHoldability().
+	 *
+	 * Parameters:
+	 *     sql - an SQL statement that may contain one or more '?' IN parameter placeholders
+	 *     columnIndexes - an array of column indexes indicating the columns that should be returned from the inserted row or rows
+	 * Returns:
+	 *     a new PreparedStatement object, containing the pre-compiled statement, that is capable of
+	 *     returning the auto-generated keys designated by the given array of column indexes
+	 * Throws:
+	 *     SQLException - if a database access error occurs or this method is called on a closed connection
+	 *     SQLFeatureNotSupportedException - if the JDBC driver does not support this method
+	 */
+	@Override
+	public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+		throw new SQLFeatureNotSupportedException("prepareStatement(String sql, int[] columnIndexes) not supported", "0A000");
+	}
 
-    /**
-     * Removes the given Savepoint object from the current transaction.
-     * Any reference to the savepoint after it have been removed will
-     * cause an SQLException to be thrown.
-     *
-     * @param savepoint the Savepoint object to be removed
-     * @throws SQLException if a database access error occurs or the given
-     *         Savepoint object is not a valid savepoint in the current
-     *         transaction
-     */
-    @Override
-    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
-        if (!(savepoint instanceof MonetSavepoint)) {
-            throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
-        }
-        MonetSavepoint sp = (MonetSavepoint) savepoint;
-        // note: can't use sendIndependentCommand here because we need
-        // to process the auto_commit state the server gives
-        // create a container for the result
-        this.createResponseList("RELEASE SAVEPOINT " + sp.getName());
-    }
-
-    /**
-     * Undoes all changes made in the current transaction and releases
-     * any database locks currently held by this Connection object. This
-     * method should be used only when auto-commit mode has been
-     * disabled.
-     *
-     * @throws SQLException if a database access error occurs or this
-     *         Connection object is in auto-commit mode
-     * @see #setAutoCommit(boolean)
-     */
-    @Override
-    public void rollback() throws SQLException {
-        // note: can't use sendIndependentCommand here because we need
-        // to process the auto_commit state the server gives
-        // create a container for the result
-        this.createResponseList("ROLLBACK");
-    }
+	/**
+	 * Creates a default PreparedStatement object capable of returning the auto-generated keys designated by the given array.
+	 * This array contains the names of the columns in the target table that contain the auto-generated keys that should be returned.
+	 * The driver will ignore the array if the SQL statement is not an INSERT statement, or an SQL statement able to
+	 * return auto-generated keys (the list of such statements is vendor-specific).
+	 *
+	 * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object.
+	 * This object can then be used to efficiently execute this statement multiple times.
+	 *
+	 * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation.
+	 * If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation.
+	 * Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement
+	 * object is executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions.
+	 *
+	 * Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have
+	 * a concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling getHoldability().
+	 *
+	 * Parameters:
+	 *     sql - an SQL statement that may contain one or more '?' IN parameter placeholders
+	 *     columnNames - an array of column names indicating the columns that should be returned from the inserted row or rows
+	 * Returns:
+	 *     a new PreparedStatement object, containing the pre-compiled statement, that is capable of
+	 *     returning the auto-generated keys designated by the given array of column names
+	 * Throws:
+	 *     SQLException - if a database access error occurs or this method is called on a closed connection
+	 *     SQLFeatureNotSupportedException - if the JDBC driver does not support this method
+	 */
+	@Override
+	public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+		throw new SQLFeatureNotSupportedException("prepareStatement(String sql, String[] columnNames) not supported", "0A000");
+	}
 
-    /**
-     * Undoes all changes made after the given Savepoint object was set.
-     *
-     * This method should be used only when auto-commit has been
-     * disabled.
-     *
-     * @param savepoint the Savepoint object to roll back to
-     * @throws SQLException if a database access error occurs, the
-     *         Savepoint object is no longer valid, or this Connection
-     *         object is currently in auto-commit mode
-     */
-    @Override
-    public void rollback(Savepoint savepoint) throws SQLException {
-        if (!(savepoint instanceof MonetSavepoint)) {
-            throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
-        }
-
-        MonetSavepoint sp = (MonetSavepoint)savepoint;
-        // note: can't use sendIndependentCommand here because we need
-        // to process the auto_commit state the server gives
-        // create a container for the result
-        this.createResponseList("ROLLBACK TO SAVEPOINT " + sp.getName());
-    }
+	/**
+	 * Removes the given Savepoint object from the current transaction.
+	 * Any reference to the savepoint after it have been removed will
+	 * cause an SQLException to be thrown.
+	 *
+	 * @param savepoint the Savepoint object to be removed
+	 * @throws SQLException if a database access error occurs or the given
+	 *         Savepoint object is not a valid savepoint in the current
+	 *         transaction
+	 */
+	@Override
+	public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+		if (!(savepoint instanceof MonetSavepoint)) {
+			throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
+		}
+		MonetSavepoint sp = (MonetSavepoint) savepoint;
+		// note: can't use sendIndependentCommand here because we need
+		// to process the auto_commit state the server gives
+		this.sendTransactionCommand("RELEASE SAVEPOINT " + sp.getName());
+	}
 
-    /**
-     * Sets this connection's auto-commit mode to the given state. If a
-     * connection is in auto-commit mode, then all its SQL statements
-     * will be executed and committed as individual transactions.
-     * Otherwise, its SQL statements are grouped into transactions that
-     * are terminated by a call to either the method commit or the
-     * method rollback. By default, new connections are in auto-commit
-     * mode.
-     *
-     * The commit occurs when the statement completes or the next
-     * execute occurs, whichever comes first. In the case of statements
-     * returning a ResultSet object, the statement completes when the
-     * last row of the ResultSet object has been retrieved or the
-     * ResultSet object has been closed. In advanced cases, a single
-     * statement may return multiple results as well as output parameter
-     * values. In these cases, the commit occurs when all results and
-     * output parameter values have been retrieved.
-     *
-     * NOTE: If this method is called during a transaction, the
-     * transaction is committed.
-     *
-     * @param autoCommit true to enable auto-commit mode; false to disable it
-     * @throws SQLException if a database access error occurs
-     * @see #getAutoCommit()
-     */
-    @Override
-    public void setAutoCommit(boolean autoCommit) throws SQLException {
-        if (this.autoCommit != autoCommit) {
-            this.sendControlCommand(ControlCommands.AUTO_COMMIT, (autoCommit ? 1 : 0));
-            this.autoCommit = autoCommit;
-        }
-    }
+	/**
+	 * Undoes all changes made in the current transaction and releases
+	 * any database locks currently held by this Connection object. This
+	 * method should be used only when auto-commit mode has been
+	 * disabled.
+	 *
+	 * @throws SQLException if a database access error occurs or this
+	 *         Connection object is in auto-commit mode
+	 * @see #setAutoCommit(boolean)
+	 */
+	@Override
+	public void rollback() throws SQLException {
+		// note: can't use sendIndependentCommand here because we need
+		// to process the auto_commit state the server gives
+		// create a container for the result
+		this.sendTransactionCommand("ROLLBACK");
+	}
 
-    /**
-     * Sets the given catalog name in order to select a subspace of this
-     * Connection object's database in which to work.  If the driver
-     * does not support catalogs, it will silently ignore this request.
-     */
-    @Override
-    public void setCatalog(String catalog) throws SQLException {
-        throw new SQLFeatureNotSupportedException("setCatalog(String catalog) not supported", "0A000");
-    }
+	/**
+	 * Undoes all changes made after the given Savepoint object was set.
+	 *
+	 * This method should be used only when auto-commit has been
+	 * disabled.
+	 *
+	 * @param savepoint the Savepoint object to roll back to
+	 * @throws SQLException if a database access error occurs, the
+	 *         Savepoint object is no longer valid, or this Connection
+	 *         object is currently in auto-commit mode
+	 */
+	@Override
+	public void rollback(Savepoint savepoint) throws SQLException {
+		if (!(savepoint instanceof MonetSavepoint)) {
+			throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
+		}
+
+		MonetSavepoint sp = (MonetSavepoint)savepoint;
+		// note: can't use sendIndependentCommand here because we need
+		// to process the auto_commit state the server gives
+		// create a container for the result
+		this.sendTransactionCommand("ROLLBACK TO SAVEPOINT " + sp.getName());
+	}
 
-    /**
-     * Changes the default holdability of ResultSet objects created using this
-     * Connection object to the given holdability. The default holdability of
-     * ResultSet objects can be be determined by invoking DatabaseMetaData.getResultSetHoldability().
-     *
-     * @param holdability - a ResultSet holdability constant; one of
-     *	ResultSet.HOLD_CURSORS_OVER_COMMIT or
-     *	ResultSet.CLOSE_CURSORS_AT_COMMIT
-     * @see #getHoldability()
-     */
-    @Override
-    public void setHoldability(int holdability) throws SQLException {
-        // we only support ResultSet.HOLD_CURSORS_OVER_COMMIT
-        if (holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT)
-            throw new SQLFeatureNotSupportedException("setHoldability(CLOSE_CURSORS_AT_COMMIT) not supported", "0A000");
-    }
+	/**
+	 * Sets this connection's auto-commit mode to the given state. If a
+	 * connection is in auto-commit mode, then all its SQL statements
+	 * will be executed and committed as individual transactions.
+	 * Otherwise, its SQL statements are grouped into transactions that
+	 * are terminated by a call to either the method commit or the
+	 * method rollback. By default, new connections are in auto-commit
+	 * mode.
+	 *
+	 * The commit occurs when the statement completes or the next
+	 * execute occurs, whichever comes first. In the case of statements
+	 * returning a ResultSet object, the statement completes when the
+	 * last row of the ResultSet object has been retrieved or the
+	 * ResultSet object has been closed. In advanced cases, a single
+	 * statement may return multiple results as well as output parameter
+	 * values. In these cases, the commit occurs when all results and
+	 * output parameter values have been retrieved.
+	 *
+	 * NOTE: If this method is called during a transaction, the
+	 * transaction is committed.
+	 *
+	 * @param autoCommit true to enable auto-commit mode; false to disable it
+	 * @throws SQLException if a database access error occurs
+	 * @see #getAutoCommit()
+	 */
+	@Override
+	public void setAutoCommit(boolean autoCommit) throws SQLException {
+		if (this.autoCommit != autoCommit) {
+			this.sendControlCommand(ControlCommands.AUTO_COMMIT, (autoCommit ? 1 : 0));
+			this.autoCommit = autoCommit;
+		}
+	}
 
-    /**
-     * Puts this connection in read-only mode as a hint to the driver to
-     * enable database optimizations.  MonetDB doesn't support any mode
-     * here, hence an SQLWarning is generated if attempted to set
-     * to true here.
-     *
-     * @param readOnly true enables read-only mode; false disables it
-     * @throws SQLException if a database access error occurs or this
-     *         method is called during a transaction.
-     */
-    @Override
-    public void setReadOnly(boolean readOnly) throws SQLException {
-        if (readOnly) {
-            addWarning("cannot setReadOnly(true): read-only Connection mode not supported", "01M08");
-        }
-    }
+	/**
+	 * Sets the given catalog name in order to select a subspace of this
+	 * Connection object's database in which to work.  If the driver
+	 * does not support catalogs, it will silently ignore this request.
+	 */
+	@Override
+	public void setCatalog(String catalog) throws SQLException {
+		throw new SQLFeatureNotSupportedException("setCatalog(String catalog) not supported", "0A000");
+	}
 
-    /**
-     * Creates an unnamed savepoint in the current transaction and
-     * returns the new Savepoint object that represents it.
-     *
-     * @return the new Savepoint object
-     * @throws SQLException if a database access error occurs or this Connection
-     *         object is currently in auto-commit mode
-     */
-    @Override
-    public Savepoint setSavepoint() throws SQLException {
-        // create a new Savepoint object
-        MonetSavepoint sp = new MonetSavepoint();
-        // note: can't use sendIndependentCommand here because we need
-        // to process the auto_commit state the server gives
-        // create a container for the result
-        this.createResponseList("SAVEPOINT " + sp.getName());
-        return sp;
-    }
+	/**
+	 * Changes the default holdability of ResultSet objects created using this
+	 * Connection object to the given holdability. The default holdability of
+	 * ResultSet objects can be be determined by invoking DatabaseMetaData.getResultSetHoldability().
+	 *
+	 * @param holdability - a ResultSet holdability constant; one of
+	 *	ResultSet.HOLD_CURSORS_OVER_COMMIT or
+	 *	ResultSet.CLOSE_CURSORS_AT_COMMIT
+	 * @see #getHoldability()
+	 */
+	@Override
+	public void setHoldability(int holdability) throws SQLException {
+		// we only support ResultSet.HOLD_CURSORS_OVER_COMMIT
+		if (holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT)
+			throw new SQLFeatureNotSupportedException("setHoldability(CLOSE_CURSORS_AT_COMMIT) not supported", "0A000");
+	}
 
-    /**
-     * Creates a savepoint with the given name in the current
-     * transaction and returns the new Savepoint object that represents
-     * it.
-     *
-     * @param name a String containing the name of the savepoint
-     * @return the new Savepoint object
-     * @throws SQLException if a database access error occurs or this Connection
-     *         object is currently in auto-commit mode
-     */
-    @Override
-    public Savepoint setSavepoint(String name) throws SQLException {
-        // create a new Savepoint object
-        MonetSavepoint sp;
-        try {
-            sp = new MonetSavepoint(name);
-        } catch (IllegalArgumentException e) {
-            throw new SQLException(e.getMessage(), "M0M03");
-        }
-        // note: can't use sendIndependentCommand here because we need
-        // to process the auto_commit state the server gives
-        // create a container for the result
-        this.createResponseList("SAVEPOINT " + sp.getName());
-        return sp;
-    }
+	/**
+	 * Puts this connection in read-only mode as a hint to the driver to
+	 * enable database optimizations.  MonetDB doesn't support any mode
+	 * here, hence an SQLWarning is generated if attempted to set
+	 * to true here.
+	 *
+	 * @param readOnly true enables read-only mode; false disables it
+	 * @throws SQLException if a database access error occurs or this
+	 *         method is called during a transaction.
+	 */
+	@Override
+	public void setReadOnly(boolean readOnly) throws SQLException {
+		if (readOnly) {
+			addWarning("cannot setReadOnly(true): read-only Connection mode not supported", "01M08");
+		}
+	}
+
+	/**
+	 * Creates an unnamed savepoint in the current transaction and
+	 * returns the new Savepoint object that represents it.
+	 *
+	 * @return the new Savepoint object
+	 * @throws SQLException if a database access error occurs or this Connection
+	 *         object is currently in auto-commit mode
+	 */
+	@Override
+	public Savepoint setSavepoint() throws SQLException {
+		// create a new Savepoint object
+		MonetSavepoint sp = new MonetSavepoint();
+		// note: can't use sendIndependentCommand here because we need
+		// to process the auto_commit state the server gives
+		// create a container for the result
+		this.sendTransactionCommand("SAVEPOINT " + sp.getName());
+		return sp;
+	}
 
-    /**
-     * Attempts to change the transaction isolation level for this
-     * Connection object to the one given.  The constants defined in the
-     * interface Connection are the possible transaction isolation
-     * levels.
-     *
-     * @param level one of the following Connection constants: Connection.TRANSACTION_READ_UNCOMMITTED,
-     *        Connection.TRANSACTION_READ_COMMITTED, Connection.TRANSACTION_REPEATABLE_READ, or
-     *        Connection.TRANSACTION_SERIALIZABLE.
-     */
-    @Override
-    public void setTransactionIsolation(int level) {
-        if (level != TRANSACTION_SERIALIZABLE) {
-            addWarning("MonetDB only supports fully serializable " +
-                    "transactions, continuing with transaction level raised to TRANSACTION_SERIALIZABLE", "01M09");
-        }
-    }
+	/**
+	 * Creates a savepoint with the given name in the current
+	 * transaction and returns the new Savepoint object that represents
+	 * it.
+	 *
+	 * @param name a String containing the name of the savepoint
+	 * @return the new Savepoint object
+	 * @throws SQLException if a database access error occurs or this Connection
+	 *         object is currently in auto-commit mode
+	 */
+	@Override
+	public Savepoint setSavepoint(String name) throws SQLException {
+		// create a new Savepoint object
+		MonetSavepoint sp;
+		try {
+			sp = new MonetSavepoint(name);
+		} catch (IllegalArgumentException e) {
+			throw new SQLException(e.getMessage(), "M0M03");
+		}
+		// note: can't use sendIndependentCommand here because we need
+		// to process the auto_commit state the server gives
+		// create a container for the result
+		this.sendTransactionCommand("SAVEPOINT " + sp.getName());
+		return sp;
+	}
 
-    /**
-     * Installs the given TypeMap object as the type map for this
-     * Connection object. The type map will be used for the custom
-     * mapping of SQL structured types and distinct types.
-     *
-     * @param map the java.util.Map object to install as the replacement for
-     *        this Connection  object's default type map
-     */
-    @Override
-    public void setTypeMap(Map<String, Class<?>> map) {
-        typeMap = map;
-    }
+	/**
+	 * Attempts to change the transaction isolation level for this
+	 * Connection object to the one given.  The constants defined in the
+	 * interface Connection are the possible transaction isolation
+	 * levels.
+	 *
+	 * @param level one of the following Connection constants: Connection.TRANSACTION_READ_UNCOMMITTED,
+	 *        Connection.TRANSACTION_READ_COMMITTED, Connection.TRANSACTION_REPEATABLE_READ, or
+	 *        Connection.TRANSACTION_SERIALIZABLE.
+	 */
+	@Override
+	public void setTransactionIsolation(int level) {
+		if (level != TRANSACTION_SERIALIZABLE) {
+			addWarning("MonetDB only supports fully serializable " +
+					"transactions, continuing with transaction level raised to TRANSACTION_SERIALIZABLE", "01M09");
+		}
+	}
+
+	/**
+	 * Installs the given TypeMap object as the type map for this
+	 * Connection object. The type map will be used for the custom
+	 * mapping of SQL structured types and distinct types.
+	 *
+	 * @param map the java.util.Map object to install as the replacement for
+	 *        this Connection  object's default type map
+	 */
+	@Override
+	public void setTypeMap(Map<String, Class<?>> map) {
+		typeMap = map;
+	}
 
-    /**
-     * Returns a string identifying this Connection to the MonetDB server.
-     *
-     * @return a String representing this Object
-     */
-    @Override
-    public String toString() {
-        return "MonetDB Connection (" + this.getJDBCURL() + ") " + (closed ? "disconnected" : "connected");
-    }
-
-    //== Java 1.6 methods (JDBC 4.0)
+	/**
+	 * Returns a string identifying this Connection to the MonetDB server.
+	 *
+	 * @return a String representing this Object
+	 */
+	@Override
+	public String toString() {
+		return "MonetDB Connection (" + this.getJDBCURL() + ") " + (closed ? "disconnected" : "connected");
+	}
 
-    /**
-     * Factory method for creating Array objects.
-     *
-     * Note: When createArrayOf is used to create an array object that
-     * maps to a primitive data type, then it is implementation-defined
-     * whether the Array object is an array of that primitive data type
-     * or an array of Object.
-     *
-     * Note: The JDBC driver is responsible for mapping the elements
-     * Object array to the default JDBC SQL type defined in
-     * java.sql.Types for the given class of Object. The default mapping
-     * is specified in Appendix B of the JDBC specification. If the
-     * resulting JDBC type is not the appropriate type for the given
-     * typeName then it is implementation defined whether an
-     * SQLException is thrown or the driver supports the resulting conversion.
-     *
-     * @param typeName the SQL name of the type the elements of the
-     *        array map to. The typeName is a database-specific name
-     *        which may be the name of a built-in type, a user-defined
-     *        type or a standard SQL type supported by this database.
-     *        This is the value returned by Array.getBaseTypeName
-     * @return an Array object whose elements map to the specified SQL type
-     * @throws SQLException if a database error occurs, the JDBC type
-     *         is not appropriate for the typeName and the conversion is
-     *         not supported, the typeName is null or this method is
-     *         called on a closed connection
-     * @throws SQLFeatureNotSupportedException the JDBC driver does
-     *         not support this data type
-     * @since 1.6
-     */
-    @Override
-    public java.sql.Array createArrayOf(String typeName, Object[] elements) throws SQLException {
-        throw new SQLFeatureNotSupportedException("createArrayOf() not supported", "0A000");
-    }
+	/**
+	 * Factory method for creating Array objects.
+	 *
+	 * Note: When createArrayOf is used to create an array object that
+	 * maps to a primitive data type, then it is implementation-defined
+	 * whether the Array object is an array of that primitive data type
+	 * or an array of Object.
+	 *
+	 * Note: The JDBC driver is responsible for mapping the elements
+	 * Object array to the default JDBC SQL type defined in
+	 * java.sql.Types for the given class of Object. The default mapping
+	 * is specified in Appendix B of the JDBC specification. If the
+	 * resulting JDBC type is not the appropriate type for the given
+	 * typeName then it is implementation defined whether an
+	 * SQLException is thrown or the driver supports the resulting conversion.
+	 *
+	 * @param typeName the SQL name of the type the elements of the
+	 *        array map to. The typeName is a database-specific name
+	 *        which may be the name of a built-in type, a user-defined
+	 *        type or a standard SQL type supported by this database.
+	 *        This is the value returned by Array.getBaseTypeName
+	 * @return an Array object whose elements map to the specified SQL type
+	 * @throws SQLException if a database error occurs, the JDBC type
+	 *         is not appropriate for the typeName and the conversion is
+	 *         not supported, the typeName is null or this method is
+	 *         called on a closed connection
+	 * @throws SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support this data type
+	 * @since 1.6
+	 */
+	@Override
+	public java.sql.Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+		throw new SQLFeatureNotSupportedException("createArrayOf() not supported", "0A000");
+	}
+
+
+	//== end methods of interface java.sql.Connection
 
-    /**
-     * Constructs an object that implements the Clob interface. The
-     * object returned initially contains no data. The setAsciiStream,
-     * setCharacterStream and setString methods of the Clob interface
-     * may be used to add data to the Clob.
-     *
-     * @return a MonetClob instance
-     * @throws SQLFeatureNotSupportedException the JDBC driver does
-     *         not support MonetClob objects that can be filled in
-     * @since 1.6
-     */
-    @Override
-    public java.sql.Clob createClob() throws SQLException {
-        return new MonetClob("");
-    }
+	/**
+	 * Constructs an object that implements the Clob interface. The
+	 * object returned initially contains no data. The setAsciiStream,
+	 * setCharacterStream and setString methods of the Clob interface
+	 * may be used to add data to the Clob.
+	 *
+	 * @return a MonetClob instance
+	 * @throws SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support MonetClob objects that can be filled in
+	 * @since 1.6
+	 */
+	@Override
+	public java.sql.Clob createClob() throws SQLException {
+		return new MonetClob("");
+	}
 
-    /**
-     * Constructs an object that implements the Blob interface. The
-     * object returned initially contains no data. The setBinaryStream
-     * and setBytes methods of the Blob interface may be used to add
-     * data to the Blob.
-     *
-     * @return a MonetBlob instance
-     * @throws SQLFeatureNotSupportedException the JDBC driver does
-     *         not support MonetBlob objects that can be filled in
-     * @since 1.6
-     */
-    @Override
-    public java.sql.Blob createBlob() throws SQLException {
-        return new MonetBlob(new byte[1]);
-    }
+	/**
+	 * Constructs an object that implements the Blob interface. The
+	 * object returned initially contains no data. The setBinaryStream
+	 * and setBytes methods of the Blob interface may be used to add
+	 * data to the Blob.
+	 *
+	 * @return a MonetBlob instance
+	 * @throws SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support MonetBlob objects that can be filled in
+	 * @since 1.6
+	 */
+	@Override
+	public java.sql.Blob createBlob() throws SQLException {
+		return new MonetBlob(new byte[1]);
+	}
 
-    /**
-     * Constructs an object that implements the NClob interface. The
-     * object returned initially contains no data. The setAsciiStream,
-     * setCharacterStream and setString methods of the NClob interface
-     * may be used to add data to the NClob.
-     *
-     * @return an NClob instance
-     * @throws SQLFeatureNotSupportedException the JDBC driver does
-     *         not support MonetNClob objects that can be filled in
-     * @since 1.6
-     */
-    @Override
-    public java.sql.NClob createNClob() throws SQLException {
-        throw new SQLFeatureNotSupportedException("createNClob() not supported", "0A000");
-    }
+	/**
+	 * Constructs an object that implements the NClob interface. The
+	 * object returned initially contains no data. The setAsciiStream,
+	 * setCharacterStream and setString methods of the NClob interface
+	 * may be used to add data to the NClob.
+	 *
+	 * @return an NClob instance
+	 * @throws SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support MonetNClob objects that can be filled in
+	 * @since 1.6
+	 */
+	@Override
+	public java.sql.NClob createNClob() throws SQLException {
+		throw new SQLFeatureNotSupportedException("createNClob() not supported", "0A000");
+	}
 
-    /**
-     * Factory method for creating Struct objects.
-     *
-     * @param typeName the SQL type name of the SQL structured type that
-     *        this Struct object maps to. The typeName is the name of a
-     *        user-defined type that has been defined for this database.
-     *        It is the value returned by Struct.getSQLTypeName.
-     * @param attributes the attributes that populate the returned object
-     * @return a Struct object that maps to the given SQL type and is
-     *         populated with the given attributes
-     * @throws SQLException if a database error occurs, the typeName
-     *         is null or this method is called on a closed connection
-     * @throws SQLFeatureNotSupportedException the JDBC driver does
-     *         not support this data type
-     * @since 1.6
-     */
-    @Override
-    public java.sql.Struct createStruct(String typeName, Object[] attributes) throws SQLException {
-        throw new SQLFeatureNotSupportedException("createStruct() not supported", "0A000");
-    }
+	/**
+	 * Factory method for creating Struct objects.
+	 *
+	 * @param typeName the SQL type name of the SQL structured type that
+	 *        this Struct object maps to. The typeName is the name of a
+	 *        user-defined type that has been defined for this database.
+	 *        It is the value returned by Struct.getSQLTypeName.
+	 * @param attributes the attributes that populate the returned object
+	 * @return a Struct object that maps to the given SQL type and is
+	 *         populated with the given attributes
+	 * @throws SQLException if a database error occurs, the typeName
+	 *         is null or this method is called on a closed connection
+	 * @throws SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support this data type
+	 * @since 1.6
+	 */
+	@Override
+	public java.sql.Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+		throw new SQLFeatureNotSupportedException("createStruct() not supported", "0A000");
+	}
 
-    /**
-     * Constructs an object that implements the SQLXML interface. The
-     * object returned initially contains no data. The
-     * createXmlStreamWriter object and setString method of the SQLXML
-     * interface may be used to add data to the SQLXML object.
-     *
-     * @return An object that implements the SQLXML interface
-     * @throws SQLFeatureNotSupportedException the JDBC driver does
-     *         not support this data type
-     * @since 1.6
-     */
-    @Override
-    public java.sql.SQLXML createSQLXML() throws SQLException {
-        throw new SQLFeatureNotSupportedException("createSQLXML() not supported", "0A000");
-    }
+	/**
+	 * Constructs an object that implements the SQLXML interface. The
+	 * object returned initially contains no data. The
+	 * createXmlStreamWriter object and setString method of the SQLXML
+	 * interface may be used to add data to the SQLXML object.
+	 *
+	 * @return An object that implements the SQLXML interface
+	 * @throws SQLFeatureNotSupportedException the JDBC driver does
+	 *         not support this data type
+	 * @since 1.6
+	 */
+	@Override
+	public java.sql.SQLXML createSQLXML() throws SQLException {
+		throw new SQLFeatureNotSupportedException("createSQLXML() not supported", "0A000");
+	}
 
-    /**
-     * Returns true if the connection has not been closed and is still
-     * valid. The driver shall submit a query on the connection or use
-     * some other mechanism that positively verifies the connection is
-     * still valid when this method is called.
-     *
-     * The query submitted by the driver to validate the connection
-     * shall be executed in the context of the current transaction.
-     *
-     * @param timeout The time in seconds to wait for the database
-     *        operation used to validate the connection to complete. If
-     *        the timeout period expires before the operation completes,
-     *        this method returns false. A value of 0 indicates a
-     *        timeout is not applied to the database operation.
-     * @return true if the connection is valid, false otherwise
-     * @throws SQLException if the value supplied for timeout is less than 0
-     * @since 1.6
-     */
-    @Override
-    public boolean isValid(int timeout) throws SQLException {
-        if (timeout < 0)
-            throw new SQLException("timeout is less than 0", "M1M05");
-        if (closed)
-            return false;
+	/**
+	 * Returns true if the connection has not been closed and is still
+	 * valid. The driver shall submit a query on the connection or use
+	 * some other mechanism that positively verifies the connection is
+	 * still valid when this method is called.
+	 *
+	 * The query submitted by the driver to validate the connection
+	 * shall be executed in the context of the current transaction.
+	 *
+	 * @param timeout The time in seconds to wait for the database
+	 *        operation used to validate the connection to complete. If
+	 *        the timeout period expires before the operation completes,
+	 *        this method returns false. A value of 0 indicates a
+	 *        timeout is not applied to the database operation.
+	 * @return true if the connection is valid, false otherwise
+	 * @throws SQLException if the value supplied for timeout is less than 0
+	 * @since 1.6
+	 */
+	@Override
+	public boolean isValid(int timeout) throws SQLException {
+		if (timeout < 0)
+			throw new SQLException("timeout is less than 0", "M1M05");
+		if (closed)
+			return false;
 
-        // ping db using query: select 1;
-        Statement stmt = null;
-        ResultSet rs = null;
-        try {
-            stmt = createStatement();
-            stmt.setQueryTimeout(timeout);
-            rs = stmt.executeQuery("SELECT 1");
-            rs.close();
-            rs = null;
-            stmt.close();
-            return true;
-        } catch (Exception e) {
-            if (rs != null) {
-                try {
-                    rs.close();
-                } catch (Exception ignored) {}
-            }
-            if (stmt != null) {
-                try {
-                    stmt.close();
-                } catch (Exception ignored) {}
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the value of the client info property specified by name.
-     * This method may return null if the specified client info property
-     * has not been set and does not have a default value.
-     * This method will also return null if the specified client info
-     * property name is not supported by the driver.
-     * Applications may use the DatabaseMetaData.getClientInfoProperties method
-     * to determine the client info properties supported by the driver.
-     *
-     * @param name - The name of the client info property to retrieve
-     * @return The value of the client info property specified or null
-     * @throws SQLException - if the database server returns an error
-     *	when fetching the client info value from the database
-     *	or this method is called on a closed connection
-     * @since 1.6
-     */
-    @Override
-    public String getClientInfo(String name) throws SQLException {
-        if (name == null || name.isEmpty())
-            return null;
-        return conn_props.getProperty(name);
-    }
+		// ping db using query: select 1;
+		Statement stmt = null;
+		ResultSet rs = null;
+		boolean isValid = false;
+		try {
+			stmt = createStatement();
+			if (stmt != null) {
+				int original_timeout = stmt.getQueryTimeout();
+				if (timeout > 0 && original_timeout != timeout) {
+					// we need to change the requested timeout for this test query
+					stmt.setQueryTimeout(timeout);
+				}
+				rs = stmt.executeQuery("SELECT 1");
+				if (rs != null && rs.next()) {
+					isValid = true;
+				}
+				if (timeout > 0 && original_timeout != timeout) {
+					// restore the original server timeout value
+					stmt.setQueryTimeout(original_timeout);
+				}
+			}
+		} catch (SQLException se) {
+			String msg = se.getMessage();
+			if (msg != null && msg.equals("Current transaction is aborted (please ROLLBACK)")) {
+				isValid = true;
+			}
+			/* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */
+		} finally {
+			if (rs != null) {
+				try {
+					rs.close();
+				} catch (Exception e2) { /* ignore error */ }
+			}
+			if (stmt != null) {
+				try {
+					stmt.close();
+				} catch (Exception e2) { /* ignore error */ }
+			}
+		}
+		return isValid;
+	}
 
-    /**
-     * Returns a list containing the name and current value of each client info
-     * property supported by the driver. The value of a client info property may
-     * be null if the property has not been set and does not have a default value.
-     *
-     * @return A Properties object that contains the name and current value
-     *         of each of the client info properties supported by the driver.
-     * @throws SQLException - if the database server returns an error
-     *	when fetching the client info value from the database
-     *	or this method is called on a closed connection
-     * @since 1.6
-     */
-    @Override
-    public Properties getClientInfo() throws SQLException {
-        // return a clone of the connection properties object
-        return new Properties(conn_props);
-    }
+	/**
+	 * Returns the value of the client info property specified by name.
+	 * This method may return null if the specified client info property
+	 * has not been set and does not have a default value.
+	 * This method will also return null if the specified client info
+	 * property name is not supported by the driver.
+	 * Applications may use the DatabaseMetaData.getClientInfoProperties method
+	 * to determine the client info properties supported by the driver.
+	 *
+	 * @param name - The name of the client info property to retrieve
+	 * @return The value of the client info property specified or null
+	 * @throws SQLException - if the database server returns an error
+	 *	when fetching the client info value from the database
+	 *	or this method is called on a closed connection
+	 * @since 1.6
+	 */
+	@Override
+	public String getClientInfo(String name) throws SQLException {
+		if (name == null || name.isEmpty())
+			return null;
+		return conn_props.getProperty(name);
+	}
+
+	/**
+	 * Returns a list containing the name and current value of each client info
+	 * property supported by the driver. The value of a client info property may
+	 * be null if the property has not been set and does not have a default value.
+	 *
+	 * @return A Properties object that contains the name and current value
+	 *         of each of the client info properties supported by the driver.
+	 * @throws SQLException - if the database server returns an error
+	 *	when fetching the client info value from the database
+	 *	or this method is called on a closed connection
+	 * @since 1.6
+	 */
+	@Override
+	public Properties getClientInfo() throws SQLException {
+		// return a clone of the connection properties object
+		return new Properties(conn_props);
+	}
 
-    /**
-     * Sets the value of the client info property specified by name to the value specified by value.
-     * Applications may use the DatabaseMetaData.getClientInfoProperties method to determine
-     * the client info properties supported by the driver and the maximum length that may be specified
-     * for each property.
-     *
-     * The driver stores the value specified in a suitable location in the database. For example
-     * in a special register, session parameter, or system table column. For efficiency the driver
-     * may defer setting the value in the database until the next time a statement is executed
-     * or prepared. Other than storing the client information in the appropriate place in the
-     * database, these methods shall not alter the behavior of the connection in anyway.
-     * The values supplied to these methods are used for accounting, diagnostics and debugging purposes only.
-     *
-     * The driver shall generate a warning if the client info name specified is not recognized by the driver.
-     *
-     * If the value specified to this method is greater than the maximum length for the property
-     * the driver may either truncate the value and generate a warning or generate a SQLClientInfoException.
-     * If the driver generates a SQLClientInfoException, the value specified was not set on the connection.
-     *
-     * The following are standard client info properties. Drivers are not required to support these
-     * properties however if the driver supports a client info property that can be described by one
-     * of the standard properties, the standard property name should be used.
-     *
-     *	ApplicationName - The name of the application currently utilizing the connection
-     *	ClientUser - The name of the user that the application using the connection is performing work for.
-     *		This may not be the same as the user name that was used in establishing the connection.
-     *	ClientHostname - The hostname of the computer the application using the connection is running on.
-     *
-     * @param name - The name of the client info property to set
-     * @param value - The value to set the client info property to. If the
-     *        value is null, the current value of the specified property is cleared.
-     * @throws SQLClientInfoException - if the database server returns an error
-     *         while setting the clientInfo values on the database server
-     *         or this method is called on a closed connection
-     * @since 1.6
-     */
-    @Override
-    public void setClientInfo(String name, String value) throws java.sql.SQLClientInfoException {
-        if (name == null || name.isEmpty()) {
-            addWarning("setClientInfo: missing property name", "01M07");
-            return;
-        }
-        // If the value is null, the current value of the specified property is cleared.
-        if (value == null) {
-            if (conn_props.containsKey(name))
-                conn_props.remove(name);
-            return;
-        }
-        // only set value for supported property names
-        if (name.equals("host") || name.equals("port") || name.equals("user") || name.equals("password") ||
-                name.equals("database") || name.equals("language") || name.equals("so_timeout") ||
-                name.equals("hash") || name.equals("treat_blob_as_binary") || name.equals("follow_redirects") ||
-                name.equals("treat_clob_as_longvarchar") || name.equals("embedded") || name.equals("directory")) {
-            conn_props.setProperty(name, value);
-        } else {
-            addWarning("setClientInfo: " + name + "is not a recognised property", "01M07");
-        }
-    }
+	/**
+	 * Sets the value of the client info property specified by name to the value specified by value.
+	 * Applications may use the DatabaseMetaData.getClientInfoProperties method to determine
+	 * the client info properties supported by the driver and the maximum length that may be specified
+	 * for each property.
+	 *
+	 * The driver stores the value specified in a suitable location in the database. For example
+	 * in a special register, session parameter, or system table column. For efficiency the driver
+	 * may defer setting the value in the database until the next time a statement is executed
+	 * or prepared. Other than storing the client information in the appropriate place in the
+	 * database, these methods shall not alter the behavior of the connection in anyway.
+	 * The values supplied to these methods are used for accounting, diagnostics and debugging purposes only.
+	 *
+	 * The driver shall generate a warning if the client info name specified is not recognized by the driver.
+	 *
+	 * If the value specified to this method is greater than the maximum length for the property
+	 * the driver may either truncate the value and generate a warning or generate a SQLClientInfoException.
+	 * If the driver generates a SQLClientInfoException, the value specified was not set on the connection.
+	 *
+	 * The following are standard client info properties. Drivers are not required to support these
+	 * properties however if the driver supports a client info property that can be described by one
+	 * of the standard properties, the standard property name should be used.
+	 *
+	 *	ApplicationName - The name of the application currently utilizing the connection
+	 *	ClientUser - The name of the user that the application using the connection is performing work for.
+	 *		This may not be the same as the user name that was used in establishing the connection.
+	 *	ClientHostname - The hostname of the computer the application using the connection is running on.
+	 *
+	 * @param name - The name of the client info property to set
+	 * @param value - The value to set the client info property to. If the
+	 *        value is null, the current value of the specified property is cleared.
+	 * @throws SQLClientInfoException - if the database server returns an error
+	 *         while setting the clientInfo values on the database server
+	 *         or this method is called on a closed connection
+	 * @since 1.6
+	 */
+	@Override
+	public void setClientInfo(String name, String value) throws java.sql.SQLClientInfoException {
+		if (name == null || name.isEmpty()) {
+			addWarning("setClientInfo: missing property name", "01M07");
+			return;
+		}
+		// If the value is null, the current value of the specified property is cleared.
+		if (value == null) {
+			if (conn_props.containsKey(name))
+				conn_props.remove(name);
+			return;
+		}
+		// only set value for supported property names
+		if (name.equals("host") || name.equals("port") || name.equals("user") || name.equals("password") ||
+				name.equals("database") || name.equals("language") || name.equals("so_timeout") ||
+				name.equals("hash") || name.equals("treat_blob_as_binary") || name.equals("follow_redirects") ||
+				name.equals("treat_clob_as_longvarchar") || name.equals("embedded") || name.equals("directory")) {
+			conn_props.setProperty(name, value);
+		} else {
+			addWarning("setClientInfo: " + name + "is not a recognised property", "01M07");
+		}
+	}
 
-    /**
-     * Sets the value of the connection's client info properties.
-     * The Properties object contains the names and values of the client info
-     * properties to be set. The set of client info properties contained in the
-     * properties list replaces the current set of client info properties on the connection.
-     * If a property that is currently set on the connection is not present in the
-     * properties list, that property is cleared. Specifying an empty properties list
-     * will clear all of the properties on the connection.
-     * See setClientInfo (String, String) for more information.
-     *
-     * If an error occurs in setting any of the client info properties, a
-     * SQLClientInfoException is thrown. The SQLClientInfoException contains information
-     * indicating which client info properties were not set. The state of the client
-     * information is unknown because some databases do not allow multiple client info
-     * properties to be set atomically. For those databases, one or more properties may
-     * have been set before the error occurred.
-     *
-     * @param props - The list of client info properties to set
-     * @throws SQLClientInfoException - if the database server returns an error
-     *	while setting the clientInfo values on the database server
-     *	or this method is called on a closed connection
-     * @since 1.6
-     */
-    @Override
-    public void setClientInfo(Properties props) throws java.sql.SQLClientInfoException {
-        if (props != null) {
-            for (Map.Entry<Object, Object> entry : props.entrySet()) {
-                setClientInfo(entry.getKey().toString(), entry.getValue().toString());
-            }
-        }
-    }
+	/**
+	 * Sets the value of the connection's client info properties.
+	 * The Properties object contains the names and values of the client info
+	 * properties to be set. The set of client info properties contained in the
+	 * properties list replaces the current set of client info properties on the connection.
+	 * If a property that is currently set on the connection is not present in the
+	 * properties list, that property is cleared. Specifying an empty properties list
+	 * will clear all of the properties on the connection.
+	 * See setClientInfo (String, String) for more information.
+	 *
+	 * If an error occurs in setting any of the client info properties, a
+	 * SQLClientInfoException is thrown. The SQLClientInfoException contains information
+	 * indicating which client info properties were not set. The state of the client
+	 * information is unknown because some databases do not allow multiple client info
+	 * properties to be set atomically. For those databases, one or more properties may
+	 * have been set before the error occurred.
+	 *
+	 * @param props - The list of client info properties to set
+	 * @throws SQLClientInfoException - if the database server returns an error
+	 *	while setting the clientInfo values on the database server
+	 *	or this method is called on a closed connection
+	 * @since 1.6
+	 */
+	@Override
+	public void setClientInfo(Properties props) throws java.sql.SQLClientInfoException {
+		if (props != null) {
+			for (Map.Entry<Object, Object> entry : props.entrySet()) {
+				setClientInfo(entry.getKey().toString(), entry.getValue().toString());
+			}
+		}
+	}
 
-    //== Java 1.7 methods (JDBC 4.1)
+	/**
+	 * Sets the given schema name to access.
+	 *
+	 * @param schema the name of a schema in which to work
+	 * @throws SQLException if a database access error occurs or this method is called on a closed connection
+	 * @since 1.7
+	 */
+	@Override
+	public void setSchema(String schema) throws SQLException {
+		if (closed)
+			throw new SQLException("Cannot call on closed Connection", "M1M20");
+		if (schema == null)
+			throw new SQLException("Missing schema name", "M1M05");
 
-    /**
-     * Sets the given schema name to access.
-     *
-     * @param schema the name of a schema in which to work
-     * @throws SQLException if a database access error occurs or this method is called on a closed connection
-     * @since 1.7
-     */
-    @Override
-    public void setSchema(String schema) throws SQLException {
-        if (closed)
-            throw new SQLException("Cannot call on closed Connection", "M1M20");
-        if (schema == null)
-            throw new SQLException("Missing schema name", "M1M05");
-
-        try (Statement st = createStatement()) {
-            st.execute("SET SCHEMA \"" + schema + "\"");
-        }
-    }
+		Statement st = createStatement();
+		schema = schema.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'");
+		try {
+			st.execute("SET SCHEMA \"" + schema + "\"");
+		} finally {
+			st.close();
+		}
+	}
 
-    /**
-     * Retrieves this Connection object's current schema name.
-     *
-     * @return the current schema name or null if there is none
-     * @throws SQLException if a database access error occurs or this method is called on a closed connection
-     */
-    @Override
-    public String getSchema() throws SQLException {
-        if (closed) {
-            throw new SQLException("Cannot call on closed Connection", "M1M20");
-        }
-        String cur_schema;
-        Statement st = createStatement();
-        ResultSet rs = null;
-        try {
-            rs = st.executeQuery("SELECT CURRENT_SCHEMA");
-            if (!rs.next())
-                throw new SQLException("Row expected", "02000");
-            cur_schema = rs.getString(1);
-        } finally {
-            if (rs != null)
-                rs.close();
-            st.close();
-        }
-        return cur_schema;
-    }
+	/**
+	 * Retrieves this Connection object's current schema name.
+	 *
+	 * @return the current schema name or null if there is none
+	 * @throws SQLException if a database access error occurs or this method is called on a closed connection
+	 */
+	@Override
+	public String getSchema() throws SQLException {
+		if (closed) {
+			throw new SQLException("Cannot call on closed Connection", "M1M20");
+		}
+		String cur_schema;
+		Statement st = createStatement();
+		ResultSet rs = null;
+		try {
+			rs = st.executeQuery("SELECT CURRENT_SCHEMA");
+			if (!rs.next())
+				throw new SQLException("Row expected", "02000");
+			cur_schema = rs.getString(1);
+		} finally {
+			if (rs != null)
+				rs.close();
+			st.close();
+		}
+		return cur_schema;
+	}
 
-    /**
-     * Terminates an open connection. Calling abort results in:
-     *  * The connection marked as closed
-     *  * Closes any physical connection to the database
-     *  * Releases resources used by the connection
-     *  * Insures that any thread that is currently accessing the
-     *    connection will either progress to completion or throw an
-     *    SQLException.
-     * Calling abort marks the connection closed and releases any
-     * resources. Calling abort on a closed connection is a no-op.
-     *
-     * @param executor The Executor implementation which will be used by abort
-     * @throws SQLException if a database access error occurs or the executor is null
-     * @throws SecurityException if a security manager exists and its checkPermission method denies calling abort
-     */
-    @Override
-    public void abort(Executor executor) throws SQLException {
-        if (closed)
-            return;
-        if (executor == null)
-            throw new SQLException("executor is null", "M1M05");
-        // this is really the simplest thing to do, it destroys
-        // everything (in particular the server connection)
-        close();
-    }
+	/**
+	 * Terminates an open connection. Calling abort results in:
+	 *  * The connection marked as closed
+	 *  * Closes any physical connection to the database
+	 *  * Releases resources used by the connection
+	 *  * Insures that any thread that is currently accessing the
+	 *    connection will either progress to completion or throw an
+	 *    SQLException.
+	 * Calling abort marks the connection closed and releases any
+	 * resources. Calling abort on a closed connection is a no-op.
+	 *
+	 * @param executor The Executor implementation which will be used by abort
+	 * @throws SQLException if a database access error occurs or the executor is null
+	 * @throws SecurityException if a security manager exists and its checkPermission method denies calling abort
+	 */
+	@Override
+	public void abort(Executor executor) throws SQLException {
+		if (closed)
+			return;
+		if (executor == null)
+			throw new SQLException("executor is null", "M1M05");
+		// this is really the simplest thing to do, it destroys
+		// everything (in particular the server connection)
+		close();
+	}
 
-    /**
-     * Sets the maximum period a Connection or objects created from the
-     * Connection will wait for the database to reply to any one
-     * request. If any request remains unanswered, the waiting method
-     * will return with a SQLException, and the Connection or objects
-     * created from the Connection will be marked as closed. Any
-     * subsequent use of the objects, with the exception of the close,
-     * isClosed or Connection.isValid methods, will result in a
-     * SQLException.
-     *
-     * @param executor The Executor implementation which will be used by setNetworkTimeout
-     * @param millis The time in milliseconds to wait for the database operation to complete
-     * @throws SQLException if a database access error occurs, this method is called on a closed connection, the
-     * executor is null, or the value specified for seconds is less than 0.
-     */
-    @Override
-    public void setNetworkTimeout(Executor executor, int millis) throws SQLException {
-        if (closed) {
-            throw new SQLException("Cannot call on closed Connection", "M1M20");
-        }
-        if (executor == null)
-            throw new SQLException("executor is null", "M1M05");
-        if (millis < 0)
-            throw new SQLException("milliseconds is less than zero", "M1M05");
-        this.setSoTimeout(millis);
-    }
+	/**
+	 * Sets the maximum period a Connection or objects created from the
+	 * Connection will wait for the database to reply to any one
+	 * request. If any request remains unanswered, the waiting method
+	 * will return with a SQLException, and the Connection or objects
+	 * created from the Connection will be marked as closed. Any
+	 * subsequent use of the objects, with the exception of the close,
+	 * isClosed or Connection.isValid methods, will result in a
+	 * SQLException.
+	 *
+	 * @param executor The Executor implementation which will be used by setNetworkTimeout
+	 * @param millis The time in milliseconds to wait for the database operation to complete
+	 * @throws SQLException if a database access error occurs, this method is called on a closed connection, the
+	 * executor is null, or the value specified for seconds is less than 0.
+	 */
+	@Override
+	public void setNetworkTimeout(Executor executor, int millis) throws SQLException {
+		if (closed)
+			throw new SQLException("Cannot call on closed Connection", "M1M20");
+		if (executor == null)
+			throw new SQLException("executor is null", "M1M05");
+		if (millis < 0)
+			throw new SQLException("milliseconds is less than zero", "M1M05");
+
+		try {
+			this.setSoTimeout(millis);
+		} catch (SocketException e) {
+			throw new SQLNonTransientConnectionException(e.getMessage(), "08000");
+		}
+	}
 
-    /**
-     * Retrieves the number of milliseconds the driver will wait for a database request to complete. If the limit is
-     * exceeded, a SQLException is thrown.
-     *
-     * @return the current timeout limit in milliseconds; zero means there is no limit
-     * @throws SQLException if a database access error occurs or this method is called on a closed Connection
-     */
-    @Override
-    public int getNetworkTimeout() throws SQLException {
-        if (closed) {
-            throw new SQLException("Cannot call on closed Connection", "M1M20");
-        }
-        return this.getSoTimeout();
-    }
+	/**
+	 * Retrieves the number of milliseconds the driver will wait for a
+	 * database request to complete. If the limit is exceeded, a
+	 * SQLException is thrown.
+	 *
+	 * @return the current timeout limit in milliseconds; zero means
+	 *         there is no limit
+	 * @throws SQLException if a database access error occurs or
+	 *         this method is called on a closed Connection
+	 * @since 1.7
+	 */
+	@Override
+	public int getNetworkTimeout() throws SQLException {
+		if (closed)
+			throw new SQLException("Cannot call on closed Connection", "M1M20");
 
-    //== end methods of interface Connection
+		try {
+			return this.getSoTimeout();
+		} catch (SocketException e) {
+			throw new SQLNonTransientConnectionException(e.getMessage(), "08000");
+		}
+	}
+
+	//== end methods of interface Connection
 
-    /**
-     * Returns whether the BLOB type should be mapped to BINARY type.
-     */
-    public boolean getBlobAsBinary() {
-        return blobIsBinary;
-    }
+	/**
+	 * Returns whether the BLOB type should be mapped to BINARY type.
+	 */
+	public boolean getBlobAsBinary() {
+		return blobIsBinary;
+	}
 
-    /**
-     * Returns whether the CLOB type should be mapped to LONGVARCHAR type.
-     */
-    public boolean getClobAsLongChar() {
-        return clobIsLongChar;
-    }
+	/**
+	 * Returns whether the CLOB type should be mapped to LONGVARCHAR type.
+	 */
+	public boolean getClobAsLongChar() {
+		return clobIsLongChar;
+	}
 
-    /**
-     * Sends the given string to MonetDB as regular statement, making sure there is a prompt after the command is sent.
-     * All possible returned information is discarded. Encountered errors are reported.
-     *
-     * @param command the exact string to send to MonetDB
-     * @throws SQLException if an IO exception or a database error occurs
-     */
-    void sendIndependentCommand(String command) throws SQLException {
-        try {
-            protocol.writeNextQuery(language.getQueryTemplateIndex(0), command, language.getQueryTemplateIndex(1));
-            protocol.waitUntilPrompt();
-            int csrh = protocol.getCurrentServerResponse();
-            if (csrh == ServerResponses.ERROR) {
-                String error = protocol.getRemainingStringLine(0);
-                throw new SQLException(error.substring(6), error.substring(0, 5));
-            }
-        } catch (SocketTimeoutException e) {
-            close(); // JDBC 4.1 semantics: abort()
-            throw new SQLException("connection timed out", "08M33");
-        } catch (IOException e) {
-            throw new SQLException(e.getMessage(), "08000");
-        }
-    }
+	/**
+	 * Sends the given string to MonetDB as special transaction command.
+	 * All possible returned information is discarded.
+	 * Encountered errors are reported.
+	 *
+	 * @param command the exact string to send to MonetDB
+	 * @throws SQLException if an IO exception or a database error occurs
+	 */
+	private void sendTransactionCommand(String command) throws SQLException {
+		// create a container for the result
+		ResponseList l = new ResponseList(0, 0, ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY);
+		// send the appropriate query string to the database
+		try {
+			l.processQuery(command);
+		} finally {
+			l.close();
+		}
+	}
 
-    /**
-     * Adds a warning to the pile of warnings this Connection object has. If there were no warnings (or clearWarnings
-     * was called) this warning will be the first, otherwise this warning will get appended to the current warning.
-     *
-     * @param reason the warning message
-     */
-    protected void addWarning(String reason, String sqlstate) {
-        if (warnings == null) {
-            warnings = new SQLWarning(reason, sqlstate);
-        } else {
-            warnings.setNextWarning(new SQLWarning(reason, sqlstate));
-        }
-    }
+	/**
+	 * Sends the given string to MonetDB as regular statement, making sure there is a prompt after the command is sent.
+	 * All possible returned information is discarded. Encountered errors are reported.
+	 *
+	 * @param command the exact string to send to MonetDB
+	 * @throws SQLException if an IO exception or a database error occurs
+	 */
+	void sendIndependentCommand(String command) throws SQLException {
+		try {
+			protocol.writeNextQuery(language.getQueryTemplateIndex(0), command, language.getQueryTemplateIndex(1));
+			protocol.waitUntilPrompt();
+			int csrh = protocol.getCurrentServerResponse();
+			if (csrh == ServerResponses.ERROR) {
+				String error = protocol.getRemainingStringLine(0);
+				throw new SQLException(error.substring(6), error.substring(0, 5));
+			}
+		} catch (SocketTimeoutException e) {
+			close(); // JDBC 4.1 semantics: abort()
+			throw new SQLNonTransientConnectionException("connection timed out", "08M33");
+		} catch (IOException e) {
+			throw new SQLNonTransientConnectionException(e.getMessage(), "08000");
+		}
+	}
 
-    /**
-     * A list of Response objects. Responses are added to this list. Methods of this class are not synchronized. This is
-     * left as responsibility to the caller to prevent concurrent access.
-     */
-    public class ResponseList {
+	/**
+	 * Adds a warning to the pile of warnings this Connection object has. If there were no warnings (or clearWarnings
+	 * was called) this warning will be the first, otherwise this warning will get appended to the current warning.
+	 *
+	 * @param reason the warning message
+	 */
+	void addWarning(String reason, String sqlstate) {
+		if (warnings == null) {
+			warnings = new SQLWarning(reason, sqlstate);
+		} else {
+			warnings.setNextWarning(new SQLWarning(reason, sqlstate));
+		}
+	}
 
-        /** The cache size (number of rows in a DataBlockResponse object) */
-        private final int cachesize;
-        /** The maximum number of results for this query */
-        private final int maxrows;
-        /** The ResultSet type to produce */
-        private final int rstype;
-        /** The ResultSet concurrency to produce */
-        private final int rsconcur;
-        /** The sequence number of this ResponseList */
-        private final int seqnr;
-        /** A list of the Responses associated with the query, in the right order */
-        private final List<IResponse> responses = new ArrayList<>();
-        /** A map of ResultSetResponses, used for additional DataBlockResponse mapping */
-        private Map<Integer, ResultSetResponse> rsresponses;
-        /** The current header returned by getNextResponse() */
-        private int curResponse = -1;
+	/**
+	 * A list of Response objects. Responses are added to this list. Methods of this class are not synchronized. This is
+	 * left as responsibility to the caller to prevent concurrent access.
+	 */
+	public class ResponseList {
 
-        /**
-         * Main constructor. The query argument can either be a String or List.  An SQLException is thrown if another
-         * object instance is supplied.
-         *
-         * @param cachesize overall cachesize to use
-         * @param maxrows maximum number of rows to allow in the set
-         * @param rstype the type of result sets to produce
-         * @param rsconcur the concurrency of result sets to produce
-         */
-        ResponseList(int cachesize, int maxrows, int rstype, int rsconcur) {
-            this.cachesize = cachesize;
-            this.maxrows = maxrows;
-            this.rstype = rstype;
-            this.rsconcur = rsconcur;
-            this.seqnr = SeqCounter++;
-        }
+		/** The cache size (number of rows in a DataBlockResponse object) */
+		private final int cachesize;
+		/** The maximum number of results for this query */
+		private final int maxrows;
+		/** The ResultSet type to produce */
+		private final int rstype;
+		/** The ResultSet concurrency to produce */
+		private final int rsconcur;
+		/** The sequence number of this ResponseList */
+		private final int seqnr;
+		/** A list of the Responses associated with the query, in the right order */
+		private final List<IResponse> responses = new ArrayList<>();
+		/** A map of ResultSetResponses, used for additional DataBlockResponse mapping */
+		private Map<Integer, ResultSetResponse> rsresponses;
+		/** The current header returned by getNextResponse() */
+		private int curResponse = -1;
 
-        public int getCachesize() {
-            return cachesize;
-        }
-
-        public int getRstype() {
-            return rstype;
-        }
+		/**
+		 * Main constructor. The query argument can either be a String or List.  An SQLException is thrown if another
+		 * object instance is supplied.
+		 *
+		 * @param cachesize overall cachesize to use
+		 * @param maxrows maximum number of rows to allow in the set
+		 * @param rstype the type of result sets to produce
+		 * @param rsconcur the concurrency of result sets to produce
+		 */
+		ResponseList(int cachesize, int maxrows, int rstype, int rsconcur) {
+			this.cachesize = cachesize;
+			this.maxrows = maxrows;
+			this.rstype = rstype;
+			this.rsconcur = rsconcur;
+			this.seqnr = SeqCounter++;
+		}
 
-        public int getRsconcur() {
-            return rsconcur;
-        }
+		public int getCachesize() {
+			return cachesize;
+		}
+
+		public int getRstype() {
+			return rstype;
+		}
 
-        public int getMaxrows() {
-            return maxrows;
-        }
+		public int getRsconcur() {
+			return rsconcur;
+		}
+
+		public int getMaxrows() {
+			return maxrows;
+		}
 
-        /**
-         * Retrieves the next available response, or null if there are no more responses.
-         *
-         * @return the next Response available or null
-         */
-        IResponse getNextResponse() throws SQLException {
-            if (rstype == ResultSet.TYPE_FORWARD_ONLY) {
-                // free resources if we're running forward only
-                if (curResponse >= 0 && curResponse < responses.size()) {
-                    IResponse tmp = responses.get(curResponse);
-                    if (tmp != null) {
-                        tmp.close();
-                    }
-                    responses.set(curResponse, null);
-                }
-            }
-            curResponse++;
-            if (curResponse >= responses.size()) {
-                // ResponseList is obviously completed so, there are no more responses
-                return null;
-            } else {
-                // return this response
-                return responses.get(curResponse);
-            }
-        }
+		/**
+		 * Retrieves the next available response, or null if there are no more responses.
+		 *
+		 * @return the next Response available or null
+		 */
+		IResponse getNextResponse() throws SQLException {
+			if (rstype == ResultSet.TYPE_FORWARD_ONLY) {
+				// free resources if we're running forward only
+				if (curResponse >= 0 && curResponse < responses.size()) {
+					IResponse tmp = responses.get(curResponse);
+					if (tmp != null) {
+						tmp.close();
+					}
+					responses.set(curResponse, null);
+				}
+			}
+			curResponse++;
+			if (curResponse >= responses.size()) {
+				// ResponseList is obviously completed so, there are no more responses
+				return null;
+			} else {
+				// return this response
+				return responses.get(curResponse);
+			}
+		}
 
-        /**
-         * Closes the Response at index i, if not null.
-         *
-         * @param i the index position of the header to close
-         */
-        void closeResponse(int i) {
-            if (i < 0 || i >= responses.size()) return;
-            IResponse tmp = responses.set(i, null);
-            if (tmp != null)
-                tmp.close();
-        }
-
-        /**
-         * Closes the current response.
-         */
-        void closeCurrentResponse() {
-            closeResponse(curResponse);
-        }
+		/**
+		 * Closes the Response at index i, if not null.
+		 *
+		 * @param i the index position of the header to close
+		 */
+		void closeResponse(int i) {
+			if (i < 0 || i >= responses.size()) return;
+			IResponse tmp = responses.set(i, null);
+			if (tmp != null)
+				tmp.close();
+		}
 
-        /**
-         * Closes the current and previous responses.
-         */
-        void closeCurOldResponses() {
-            for (int i = curResponse; i >= 0; i--) {
-                closeResponse(i);
-            }
-        }
+		/**
+		 * Closes the current response.
+		 */
+		void closeCurrentResponse() {
+			closeResponse(curResponse);
+		}
 
-        /**
-         * Closes this ResponseList by closing all the Responses in this ResponseList.
-         */
-        public void close() {
-            for (int i = 0; i < responses.size(); i++) {
-                closeResponse(i);
-            }
-        }
+		/**
+		 * Closes the current and previous responses.
+		 */
+		void closeCurOldResponses() {
+			for (int i = curResponse; i >= 0; i--) {
+				closeResponse(i);
+			}
+		}
 
-        /**
-         * Returns whether this ResponseList has still unclosed Responses.
-         */
-        boolean hasUnclosedResponses() {
-            for (IResponse r : responses) {
-                if (r != null)
-                    return true;
-            }
-            return false;
-        }
+		/**
+		 * Closes this ResponseList by closing all the Responses in this ResponseList.
+		 */
+		public void close() {
+			for (int i = 0; i < responses.size(); i++) {
+				closeResponse(i);
+			}
+		}
 
-        /**
-         * Executes the query contained in this ResponseList, and stores the Responses resulting from this query in this
-         * ResponseList.
-         *
-         * @throws SQLException if a database error occurs
-         */
-        void processQuery(String query) throws SQLException {
-            this.executeQuery(language.getQueryTemplates(), query);
-        }
-
-        /**
-         * Internal executor of queries.
-         *
-         * @param templ the template to fill in
-         * @param query the query to execute
-         * @throws SQLException if a database error occurs
-         */
-        @SuppressWarnings("fallthrough")
-        public void executeQuery(String[] templ, String query) throws SQLException {
-            String error = null;
+		/**
+		 * Returns whether this ResponseList has still unclosed Responses.
+		 */
+		boolean hasUnclosedResponses() {
+			for (IResponse r : responses) {
+				if (r != null)
+					return true;
+			}
+			return false;
+		}
 
-            try {
-                // make sure we're ready to send query; read data till we have the prompt it is possible (and most
-                // likely) that we already have the prompt and do not have to skip any lines. Ignore errors from
-                // previous result sets.
-                protocol.waitUntilPrompt();
+		/**
+		 * Executes the query contained in this ResponseList, and stores the Responses resulting from this query in this
+		 * ResponseList.
+		 *
+		 * @throws SQLException if a database error occurs
+		 */
+		void processQuery(String query) throws SQLException {
+			this.executeQuery(language.getQueryTemplates(), query);
+		}
 
-                // {{{ set reply size
-                /*
-                 * Change the reply size of the server.  If the given value is the same as the current value known
-                 * to use, then ignore this call.  If it is set to 0 we get a prompt after the server sent it's
-                 * header.
-                 *
-                 * 2017: For now, in the embedded connection, the value set cachesize will be always the default one.
-                 */
-                int size = (cachesize != 0 && !isEmbedded) ? cachesize : MonetConnection.this.getDefFetchsize();
-                size = maxrows != 0 ? Math.min(maxrows, size) : size;
-                // don't do work if it's not needed
-                if (!isEmbedded && language.getRepresentation().equals("sql") && size != curReplySize &&
-                        !Arrays.deepEquals(templ, language.getCommandTemplates())) {
-                    sendControlCommand(ControlCommands.REPLY_SIZE, size);
-                    // store the reply size after a successful change
-                    curReplySize = size;
-                }
-                // }}} set reply size
+		/**
+		 * Internal executor of queries.
+		 *
+		 * @param templ the template to fill in
+		 * @param query the query to execute
+		 * @throws SQLException if a database error occurs
+		 */
+		@SuppressWarnings("fallthrough")
+		public void executeQuery(String[] templ, String query) throws SQLException {
+			String error = null;
+
+			try {
+				// make sure we're ready to send query; read data till we have the prompt it is possible (and most
+				// likely) that we already have the prompt and do not have to skip any lines. Ignore errors from
+				// previous result sets.
+				protocol.waitUntilPrompt();
 
-                // If the query is larger than the TCP buffer size, use a special send thread to avoid deadlock with
-                // the server due to blocking behaviour when the buffer is full. Because the server will be writing
-                // back results to us, it will eventually block as well when its TCP buffer gets full, as we are
-                // blocking an not consuming from it. The result is a state where both client and server want to
-                // write, but block.
-                if (query.length() > getBlockSize()) {
-                    // get a reference to the send thread
-                    if (senderThread == null) {
-                        senderThread = new SenderThread(protocol);
-                    }
-                    // tell it to do some work!
-                    senderThread.runQuery(templ, query);
-                } else {
-                    // this is a simple call, which is a lot cheaper and will always succeed for small queries.
-                    protocol.writeNextQuery((templ[0] == null) ? "" : templ[0], query,
-                            (templ[1] == null) ? "" : templ[1]);
-                }
+				// {{{ set reply size
+				/*
+				 * Change the reply size of the server.  If the given value is the same as the current value known
+				 * to use, then ignore this call.  If it is set to 0 we get a prompt after the server sent it's
+				 * header.
+				 *
+				 * 2017: For now, in the embedded connection, the value set cachesize will be always the default one.
+				 */
+				int size = (cachesize != 0 && !isEmbedded) ? cachesize : MonetConnection.this.getDefFetchsize();
+				size = maxrows != 0 ? Math.min(maxrows, size) : size;
+				// don't do work if it's not needed
+				if (!isEmbedded && language.getRepresentation().equals("sql") && size != curReplySize &&
+						!Arrays.deepEquals(templ, language.getCommandTemplates())) {
+					sendControlCommand(ControlCommands.REPLY_SIZE, size);
+					// store the reply size after a successful change
+					curReplySize = size;
+				}
+				// }}} set reply size
 
-                // go for new results
-                protocol.fetchNextResponseData();
-                int nextResponse = protocol.getCurrentServerResponse();
-                IResponse res = null;
-                while (nextResponse != ServerResponses.PROMPT) {
-                    // each response should start with a start of header (or error)
-                    switch (nextResponse) {
-                        case ServerResponses.SOHEADER:
-                            // make the response object, and fill it
-                            int nextStartHeader = protocol.getNextStarterHeader();
-                            try {
-                                switch (nextStartHeader) {
-                                    case StarterHeaders.Q_PARSE:
-                                        throw new ProtocolException("Q_PARSE header not allowed here");
-                                    case StarterHeaders.Q_TABLE:
-                                    case StarterHeaders.Q_PREPARE: {
-                                        res = protocol.getNextResultSetResponse(MonetConnection.this,
-                                                ResponseList.this, this.seqnr, this.maxrows);
-                                        ResultSetResponse rsreponse = (ResultSetResponse) res;
-                                        if (rsresponses == null) {
-                                            rsresponses = new HashMap<>();
-                                        }
-                                        rsresponses.put(rsreponse.getId(), rsreponse);
-                                    }
-                                    break;
-                                    case StarterHeaders.Q_UPDATE:
-                                        res = protocol.getNextUpdateResponse();
-                                        break;
-                                    case StarterHeaders.Q_SCHEMA:
-                                        res = protocol.getNextSchemaResponse();
-                                        break;
-                                    case StarterHeaders.Q_TRANS:
-                                        res = protocol.getNextAutoCommitResponse();
-                                        boolean isAutoCommit = ((AutoCommitResponse) res).isAutocommit();
+				// If the query is larger than the TCP buffer size, use a special send thread to avoid deadlock with
+				// the server due to blocking behaviour when the buffer is full. Because the server will be writing
+				// back results to us, it will eventually block as well when its TCP buffer gets full, as we are
+				// blocking an not consuming from it. The result is a state where both client and server want to
+				// write, but block.
+				if (query.length() > getBlockSize()) {
+					// get a reference to the send thread
+					if (senderThread == null) {
+						senderThread = new SenderThread(protocol);
+					}
+					// tell it to do some work!
+					senderThread.runQuery(templ, query);
+				} else {
+					// this is a simple call, which is a lot cheaper and will always succeed for small queries.
+					protocol.writeNextQuery((templ[0] == null) ? "" : templ[0], query,
+							(templ[1] == null) ? "" : templ[1]);
+				}
+
+				// go for new results
+				protocol.fetchNextResponseData();
+				int nextResponse = protocol.getCurrentServerResponse();
+				IResponse res = null;
+				while (nextResponse != ServerResponses.PROMPT) {
+					// each response should start with a start of header (or error)
+					switch (nextResponse) {
+						case ServerResponses.SOHEADER:
+							// make the response object, and fill it
+							int nextStartHeader = protocol.getNextStarterHeader();
+							try {
+								switch (nextStartHeader) {
+									case StarterHeaders.Q_PARSE:
+										throw new ProtocolException("Q_PARSE header not allowed here");
+									case StarterHeaders.Q_TABLE:
+									case StarterHeaders.Q_PREPARE: {
+										res = protocol.getNextResultSetResponse(MonetConnection.this,
+												ResponseList.this, this.seqnr, this.maxrows);
+										ResultSetResponse rsreponse = (ResultSetResponse) res;
+										if (rsresponses == null) {
+											rsresponses = new HashMap<>();
+										}
+										rsresponses.put(rsreponse.getId(), rsreponse);
+									}
+									break;
+									case StarterHeaders.Q_UPDATE:
+										res = protocol.getNextUpdateResponse();
+										break;
+									case StarterHeaders.Q_SCHEMA:
+										res = protocol.getNextSchemaResponse();
+										break;
+									case StarterHeaders.Q_TRANS:
+										res = protocol.getNextAutoCommitResponse();
+										boolean isAutoCommit = ((AutoCommitResponse) res).isAutocommit();
 
-                                        if (MonetConnection.this.getAutoCommit() && isAutoCommit) {
-                                            MonetConnection.this.addWarning("Server enabled auto commit mode " +
-                                                    "while local state already was auto commit.", "01M11");
-                                        }
-                                        MonetConnection.this.autoCommit = isAutoCommit;
-                                        break;
-                                    case StarterHeaders.Q_BLOCK: {
-                                        AbstractDataBlockResponse next = protocol.getNextDatablockResponse(rsresponses);
-                                        if (next == null) {
-                                            error = "M0M12!No ResultSetResponse for a DataBlock found";
-                                            break;
-                                        }
-                                        res = next;
-                                    }
-                                    break;
-                                }
-                            } catch (ProtocolException e) {
-                                error = "M0M10!error while parsing start of header:\n" + e.getMessage() + " found: '"
-                                        + protocol.getRemainingStringLine(0).charAt(e.getErrorOffset()) + "'" +
-                                        " in: \"" + protocol.getRemainingStringLine(0) + "\"" + " at pos: "
-                                        + e.getErrorOffset();
-                                // flush all the rest
-                                protocol.waitUntilPrompt();
-                                nextResponse = protocol.getCurrentServerResponse();
-                                break;
-                            }
+										if (MonetConnection.this.getAutoCommit() && isAutoCommit) {
+											MonetConnection.this.addWarning("Server enabled auto commit mode " +
+													"while local state already was auto commit.", "01M11");
+										}
+										MonetConnection.this.autoCommit = isAutoCommit;
+										break;
+									case StarterHeaders.Q_BLOCK: {
+										AbstractDataBlockResponse next = protocol.getNextDatablockResponse(rsresponses);
+										if (next == null) {
+											error = "M0M12!No ResultSetResponse for a DataBlock found";
+											break;
+										}
+										res = next;
+									}
+									break;
+								}
+							} catch (ProtocolException e) {
+								error = "M0M10!error while parsing start of header:\n" + e.getMessage() + " found: '"
+										+ protocol.getRemainingStringLine(0).charAt(e.getErrorOffset()) + "'" +
+										" in: \"" + protocol.getRemainingStringLine(0) + "\"" + " at pos: "
+										+ e.getErrorOffset();
+								// flush all the rest
+								protocol.waitUntilPrompt();
+								nextResponse = protocol.getCurrentServerResponse();
+								break;
+							}
+							// immediately handle errors after parsing the header (res may be null)
+							if (error != null) {
+								protocol.waitUntilPrompt();
+								nextResponse = protocol.getCurrentServerResponse();
+								break;
+							}
+							// here we have a res object, which we can start filling
+							if (res instanceof IIncompleteResponse) {
+								IIncompleteResponse iter = (IIncompleteResponse) res;
+								while (iter.wantsMore()) {
+									try {
+										protocol.fetchNextResponseData();
+										iter.addLines(protocol);
+									} catch (ProtocolException ex) {
+										// right, some protocol violation, skip the rest of the result
+										error = "M0M10!" + ex.getMessage();
+										protocol.waitUntilPrompt();
+										nextResponse = protocol.getCurrentServerResponse();
+										break;
+									}
+								}
+							}
 
-                            // immediately handle errors after parsing the header (res may be null)
-                            if (error != null) {
-                                protocol.waitUntilPrompt();
-                                nextResponse = protocol.getCurrentServerResponse();
-                                break;
-                            }
-
-                            // here we have a res object, which we can start filling
-                            if (res instanceof IIncompleteResponse) {
-                                IIncompleteResponse iter = (IIncompleteResponse) res;
-                                while (iter.wantsMore()) {
-                                    try {
-                                        protocol.fetchNextResponseData();
-                                        iter.addLines(protocol);
-                                    } catch (ProtocolException ex) {
-                                        // right, some protocol violation, skip the rest of the result
-                                        error = "M0M10!" + ex.getMessage();
-                                        protocol.waitUntilPrompt();
-                                        nextResponse = protocol.getCurrentServerResponse();
-                                        break;
-                                    }
-                                }
-                            }
-
-                            if (error != null) {
-                                break;
-                            }
+							if (error != null) {
+								break;
+							}
 
-                            // it is of no use to store DataBlockResponses, you never want to retrieve them directly
-                            // anyway
-                            if (!(res instanceof AbstractDataBlockResponse)) {
-                                responses.add(res);
-                            }
-                            // read the next line (can be prompt, new result, error, etc.) before we start the loop over
-                            protocol.fetchNextResponseData();
-                            nextResponse = protocol.getCurrentServerResponse();
-                            break;
-                        case ServerResponses.INFO:
-                            addWarning(protocol.getRemainingStringLine(0), "01000");
-                            // read the next line (can be prompt, new result, error, etc.) before we start the loop over
-                            protocol.fetchNextResponseData();
-                            nextResponse = protocol.getCurrentServerResponse();
-                            break;
-                        case ServerResponses.ERROR:
-                            // read everything till the prompt (should be error) we don't know if we ignore some
-                            // garbage here... but the log should reveal that
-                            error = protocol.getRemainingStringLine(0);
-                            protocol.waitUntilPrompt();
-                            nextResponse = protocol.getCurrentServerResponse();
-                            break;
-                        default:
-                            throw new SQLException("Protocol violation, unexpected line!", "M0M10");
-                    }
-                }
+							// it is of no use to store DataBlockResponses, you never want to retrieve them directly
+							// anyway
+							if (!(res instanceof AbstractDataBlockResponse)) {
+								responses.add(res);
+							}
+							// read the next line (can be prompt, new result, error, etc.) before we start the loop over
+							protocol.fetchNextResponseData();
+							nextResponse = protocol.getCurrentServerResponse();
+							break;
+						case ServerResponses.INFO:
+							addWarning(protocol.getRemainingStringLine(0), "01000");
+							// read the next line (can be prompt, new result, error, etc.) before we start the loop over
+							protocol.fetchNextResponseData();
+							nextResponse = protocol.getCurrentServerResponse();
+							break;
+						case ServerResponses.ERROR:
+							// read everything till the prompt (should be error) we don't know if we ignore some
+							// garbage here... but the log should reveal that
+							error = protocol.getRemainingStringLine(0);
+							protocol.waitUntilPrompt();
+							nextResponse = protocol.getCurrentServerResponse();
+							break;
+						default:
+							throw new SQLException("Protocol violation, unexpected line!", "M0M10");
+					}
+				}
 
-                // if we used the senderThread, make sure it has finished
-                if (senderThread != null) {
-                    String tmp = senderThread.getErrors();
-                    if (tmp != null) {
-                        if (error == null) {
-                            error = "08000!" + tmp;
-                        } else {
-                            error += "\n08000!" + tmp;
-                        }
-                    }
-                }
-                if (error != null) {
-                    SQLException ret = null;
-                    String[] errorsList = error.split("\n");
-                    for (String singleError : errorsList) {
-                        String reason = isEmbedded() ? singleError : singleError.substring(6);
-                        String sqlState = isEmbedded() ? "M0M10" : singleError.substring(0, 5);
-                        if (ret == null) {
-                            ret = new SQLException(reason, sqlState);
-                        } else {
-                            ret.setNextException(new SQLException(reason, sqlState));
-                        }
-                    }
-                    throw ret;
-                }
-            } catch (SocketTimeoutException e) {
-                this.close(); // JDBC 4.1 semantics, abort()
-                throw new SQLException("connection timed out", "08M33");
-            } catch (IOException e) {
-                closed = true;
-                throw new SQLException(e.getMessage() + " (mserver still alive?)", "08000");
-            }
-        }
-    }
+				// if we used the senderThread, make sure it has finished
+				if (senderThread != null) {
+					String tmp = senderThread.getErrors();
+					if (tmp != null) {
+						if (error == null) {
+							error = "08000!" + tmp;
+						} else {
+							error += "\n08000!" + tmp;
+						}
+					}
+				}
+				if (error != null) {
+					SQLException ret = null;
+					String[] errorsList = error.split("\n");
+					for (String singleError : errorsList) {
+						SQLException newErr;
+						String reason = isEmbedded() ? singleError : singleError.substring(6);
+						String sqlState = isEmbedded() ? "M0M10" : singleError.substring(0, 5);
+						if (singleError.length() >= 6) {
+							newErr = new SQLException(reason, sqlState);
+						} else {
+							newErr = new SQLNonTransientConnectionException(singleError, "08000");
+						}
+						if (ret == null) {
+							ret = newErr;
+						} else {
+							ret.setNextException(newErr);
+						}
+					}
+					throw ret;
+				}
+			} catch (SocketTimeoutException e) {
+				this.close(); // JDBC 4.1 semantics, abort()
+				throw new SQLNonTransientConnectionException("connection timed out", "08M33");
+			} catch (IOException e) {
+				closed = true;
+				throw new SQLNonTransientConnectionException(e.getMessage() + " (mserver5 still alive?)", "08006");
+			}
+		}
+	}
 }