changeset 45:c2bf983dc79b

Implemented Connection methods: getClientInfo(name) and getClientInfo(). They used to return null and empty Properties object. Improved robustness and error reporting when processing property values in Connection constructor. Added @since 1.6 and @since 1.7 tags for methods introduced in those java versions. Rearranged place of 1.6 and 1.7 methods implementation code to match the order as used in http://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html The 1.6 (JDBC 4.0) and 1.7 (JDBC 4.1) methods are now listed at the end of the source file. Removed unneeded trailing spaces (mostly in comment lines)
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 10 Nov 2016 18:07:59 +0100 (2016-11-10)
parents c26213e86442
children 5d4524c27902
files ChangeLog src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
diffstat 2 files changed, 529 insertions(+), 349 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
 # ChangeLog file for java
 # This file is updated with Maddlog
 
+* Thu Nov 10 2016 Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
+- Implemented Connection methods: getClientInfo(name) and getClientInfo().
+  They used to return null and empty Properties object.
+  Method Connection.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT) now
+  throws an SQLFeatureNotSupportedException.
+
 * Thu Oct 13 2016 Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
 - Corrected implementation of java.sql.Wrapper methods isWrapperFor()
   and unwrap().  They now properly return expected results instead of
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java
@@ -12,22 +12,16 @@ import java.io.File;
 import java.io.IOException;
 import java.net.SocketException;
 import java.net.SocketTimeoutException;
-import java.sql.Array;
-import java.sql.Blob;
 import java.sql.CallableStatement;
-import java.sql.Clob;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
-import java.sql.NClob;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.SQLWarning;
-import java.sql.SQLXML;
 import java.sql.Savepoint;
 import java.sql.Statement;
-import java.sql.Struct;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -53,40 +47,45 @@ import nl.cwi.monetdb.mcl.parser.StartOf
 
 /**
  * A {@link Connection} suitable for the MonetDB database.
- * 
+ *
  * This connection represents a connection (session) to a MonetDB
  * database. SQL statements are executed and results are returned within
  * the context of a connection. This Connection object holds a physical
  * connection to the MonetDB database.
- * 
+ *
  * A Connection object's database should able to provide information
  * describing its tables, its supported SQL grammar, its stored
  * procedures, the capabilities of this connection, and so on. This
  * information is obtained with the getMetaData method.
- * 
+ *
  * Note: By default a Connection object is in auto-commit mode, which
  * means that it automatically commits changes after executing each
  * statement. If auto-commit mode has been disabled, the method commit
  * must be called explicitly in order to commit changes; otherwise,
  * database changes will not be saved.
- * 
+ *
  * The current state of this connection is that it nearly implements the
  * whole Connection interface.
  *
  * @author Fabian Groffen
- * @version 1.2
+ * @author Martin van Dinther
+ * @version 1.3
  */
 public class MonetConnection extends MonetWrapper implements Connection {
+	/** the successful processed input properties */
+	private final Properties conn_props = new Properties();
+
 	/** The hostname to connect to */
 	private final String hostname;
 	/** The port to connect on the host to */
-	private final int port;
+	private int port = 0;
 	/** The database to use (currently not used) */
 	private final String database;
 	/** The username to use when authenticating */
 	private final String username;
 	/** The password to use when authenticating */
 	private final String password;
+
 	/** A connection to mserver5 using a TCP socket */
 	private final MapiSocket server;
 	/** The Reader from the server */
@@ -107,9 +106,7 @@ public class MonetConnection extends Mon
 	private SQLWarning warnings = null;
 	/** The Connection specific mapping of user defined types to Java
 	 * types */
-	private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {/**
-		 * 
-		 */
+	private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {
 		private static final long serialVersionUID = 1L;
 		{
 			put("inet", INET.class);
@@ -125,10 +122,11 @@ public class MonetConnection extends Mon
 	/** The number of results we receive from the server at once */
 	private int curReplySize = -1;	// the server by default uses -1 (all)
 
-	/** A template to apply to each query (like pre and post fixes) */
-	String[] queryTempl;
-	/** A template to apply to each command (like pre and post fixes) */
-	String[] commandTempl;
+	/** A template to apply to each query (like pre and post fixes), filled in constructor */
+	final String[] queryTempl = new String[3]; // pre, post, sep
+
+	/** A template to apply to each command (like pre and post fixes), filled in constructor */
+	final String[] commandTempl = new String[3]; // pre, post, sep
 
 	/** the SQL language */
 	final static int LANG_SQL = 0;
@@ -149,57 +147,99 @@ public class MonetConnection extends Mon
 	 * createStatement() call.  This constructor is only accessible to
 	 * classes from the jdbc package.
 	 *
-	 * @param props a Property hashtable holding the properties needed for
-	 *              connecting
+	 * @param props a Property hashtable holding the properties needed for connecting
 	 * @throws SQLException if a database error occurs
 	 * @throws IllegalArgumentException is one of the arguments is null or empty
 	 */
 	MonetConnection(Properties props)
 		throws SQLException, IllegalArgumentException
 	{
+		// get supported property values from the props argument.
+		// When a value is found add it to the internal conn_props list for use by getClientInfo().
 		this.hostname = props.getProperty("host");
-		int port;
-		try {
-			port = Integer.parseInt(props.getProperty("port"));
-		} catch (NumberFormatException e) {
-			port = 0;
+		if (this.hostname != null)
+			conn_props.setProperty("host", this.hostname);
+
+		String port_prop = props.getProperty("port");
+		if (port_prop != null) {
+			try {
+				this.port = Integer.parseInt(port_prop);
+			} catch (NumberFormatException e) {
+				addWarning("Unable to parse port number from: " + port_prop, "M1M05");
+			}
+			conn_props.setProperty("port", Integer.toString(this.port));
 		}
-		this.port = port;
+
 		this.database = props.getProperty("database");
+		if (this.database != null)
+			conn_props.setProperty("database", this.database);
+
 		this.username = props.getProperty("user");
+		if (this.username != null)
+			conn_props.setProperty("user", this.username);
+
 		this.password = props.getProperty("password");
+		if (this.password != null)
+			conn_props.setProperty("password", this.password);
+
 		String language = props.getProperty("language");
-		boolean debug = Boolean.valueOf(props.getProperty("debug")).booleanValue();
-		String hash = props.getProperty("hash");
-		blobIsBinary = Boolean.valueOf(props.getProperty("treat_blob_as_binary")).booleanValue();
-		int sockTimeout = 0;
-		try {
-			sockTimeout = Integer.parseInt(props.getProperty("so_timeout"));
-		} catch (NumberFormatException e) {
-			sockTimeout = 0;
-		}
-		// check input arguments
-		if (hostname == null || hostname.trim().isEmpty())
-			throw new IllegalArgumentException("hostname should not be null or empty");
-		if (port == 0)
-			throw new IllegalArgumentException("port should not be 0");
-		if (username == null || username.trim().isEmpty())
-			throw new IllegalArgumentException("user should not be null or empty");
-		if (password == null || password.trim().isEmpty())
-			throw new IllegalArgumentException("password should not be null or empty");
-		if (language == null || language.trim().isEmpty()) {
-			language = "sql";
-			addWarning("No language given, defaulting to 'sql'", "M1M05");
+		if (language != null)
+			conn_props.setProperty("language", language);
+
+		boolean debug = false;
+		String debug_prop = props.getProperty("debug");
+		if (debug_prop != null) {
+			debug = Boolean.parseBoolean(debug_prop);
+			conn_props.setProperty("debug", Boolean.toString(debug));
 		}
 
-		// initialise query templates (filled later, but needed below)
-		queryTempl = new String[3]; // pre, post, sep
-		commandTempl = new String[3]; // pre, post, sep
+		String hash = props.getProperty("hash");
+		if (hash != null)
+			conn_props.setProperty("hash", hash);
+
+		String blobIsBinary_prop = props.getProperty("treat_blob_as_binary");
+		if (blobIsBinary_prop != null) {
+			blobIsBinary = Boolean.parseBoolean(blobIsBinary_prop);
+			conn_props.setProperty("treat_blob_as_binary", Boolean.toString(blobIsBinary));
+		} else {
+			blobIsBinary = false;
+		}
+
+		int sockTimeout = 0;
+		String so_timeout_prop = props.getProperty("so_timeout");
+		if (so_timeout_prop != null) {
+			try {
+				sockTimeout = Integer.parseInt(so_timeout_prop);
+				if (sockTimeout < 0) {
+					addWarning("Negative socket timeout not allowed. Value ignored", "M1M05");
+					sockTimeout = 0;
+				}
+			} catch (NumberFormatException e) {
+				addWarning("Unable to parse socket timeout number from: " + so_timeout_prop, "M1M05");
+			}
+			conn_props.setProperty("so_timeout", Integer.toString(sockTimeout));
+		}
+
+		// check mandatory input arguments
+		if (hostname == null || hostname.isEmpty())
+			throw new IllegalArgumentException("Missing or empty host name");
+		if (port <= 0)
+			throw new IllegalArgumentException("Invalid port number. It should not be " + (port < 0 ? "negative" : "0"));
+		if (username == null || username.isEmpty())
+			throw new IllegalArgumentException("Missing or empty user name");
+		if (password == null || password.isEmpty())
+			throw new IllegalArgumentException("Missing or empty password");
+		if (language == null || language.isEmpty()) {
+			// fallback to default language: sql
+			language = "sql";
+			addWarning("No language specified, defaulting to 'sql'", "M1M05");
+		}
 
 		server = new MapiSocket();
-
-		if (hash != null) server.setHash(hash);
-		if (database != null) server.setDatabase(database);
+		if (hash != null)
+			server.setHash(hash);
+		if (database != null)
+			server.setDatabase(database);
 		server.setLanguage(language);
 
 		// we're debugging here... uhm, should be off in real life
@@ -209,7 +249,8 @@ public class MonetConnection extends Mon
 					System.currentTimeMillis() + ".log");
 				File f = new File(fname);
 				int ext = fname.lastIndexOf('.');
-				if (ext < 0) ext = fname.length();
+				if (ext < 0)
+					ext = fname.length();
 				String pre = fname.substring(0, ext);
 				String suf = fname.substring(ext);
 
@@ -224,12 +265,11 @@ public class MonetConnection extends Mon
 		}
 
 		try {
-			List<String> warnings = 
-				server.connect(hostname, port, username, password);
+			List<String> warnings = server.connect(hostname, port, username, password);
 			for (String warning : warnings) {
 				addWarning(warning, "01M02");
 			}
-			
+
 			// apply NetworkTimeout value from legacy (pre 4.1) driver
 			// so_timeout calls
 			server.setSoTimeout(sockTimeout);
@@ -239,7 +279,7 @@ public class MonetConnection extends Mon
 
 			String error = in.waitForPrompt();
 			if (error != null)
-				throw new SQLException(error.substring(6), "08001");
+				throw new SQLException((error.length() > 6) ? error.substring(6) : error, "08001");
 		} catch (IOException e) {
 			throw new SQLException("Unable to connect (" + hostname + ":" + port + "): " + e.getMessage(), "08006");
 		} catch (MCLParseException e) {
@@ -254,17 +294,10 @@ public class MonetConnection extends Mon
 		}
 
 		// we seem to have managed to log in, let's store the
-		// language used
+		// language used and language specific query templates
 		if ("sql".equals(language)) {
 			lang = LANG_SQL;
-		} else if ("mal".equals(language)) {
-			lang = LANG_MAL;
-		} else {
-			lang = LANG_UNKNOWN;
-		}
-		
-		// fill the query templates
-		if (lang == LANG_SQL) {
+
 			queryTempl[0] = "s";		// pre
 			queryTempl[1] = "\n;";		// post
 			queryTempl[2] = "\n;\n";	// separator
@@ -272,7 +305,9 @@ public class MonetConnection extends Mon
 			commandTempl[0] = "X";		// pre
 			commandTempl[1] = null;		// post
 			commandTempl[2] = "\nX";	// separator
-		} else if (lang == LANG_MAL) {
+		} else if ("mal".equals(language)) {
+			lang = LANG_MAL;
+
 			queryTempl[0] = null;
 			queryTempl[1] = ";\n";
 			queryTempl[2] = ";\n";
@@ -280,13 +315,15 @@ public class MonetConnection extends Mon
 			commandTempl[0] = null;		// pre
 			commandTempl[1] = null;		// post
 			commandTempl[2] = null;		// separator
+		} else {
+			lang = LANG_UNKNOWN;
 		}
 
-		// the following initialisers are only valid when the language
-		// is SQL...
+		// the following initialisers are only valid when the language is SQL...
 		if (lang == LANG_SQL) {
 			// enable auto commit
 			setAutoCommit(true);
+
 			// set our time zone on the server
 			Calendar cal = Calendar.getInstance();
 			int offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
@@ -319,7 +356,7 @@ public class MonetConnection extends Mon
 	 * 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.
 	 */
@@ -376,50 +413,12 @@ public class MonetConnection extends Mon
 	}
 
 	/**
-	 * 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
-	 */
-	@Override
-	public Array createArrayOf(String typeName, Object[] elements)
-		throws SQLException
-	{
-		throw new SQLFeatureNotSupportedException("createArrayOf(String, Object[]) not supported", "0A000");
-	}
-
-	/**
 	 * 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.
@@ -477,10 +476,10 @@ public class MonetConnection extends Mon
 	 * ResultSet.CONCUR_UPDATABLE
 	 * @param resultSetHoldability one of the following ResultSet
 	 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
-	 * ResultSet.CLOSE_CURSORS_AT_COMMIT 
+	 * ResultSet.CLOSE_CURSORS_AT_COMMIT
 	 *
 	 * @return a new Statement      object that will generate ResultSet
-	 * objects with the given type, concurrency, and holdability 
+	 * 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
@@ -511,89 +510,6 @@ public class MonetConnection extends Mon
 	}
 
 	/**
-	 * 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
-	 */
-	@Override
-	public Clob createClob() throws SQLException {
-		throw new SQLFeatureNotSupportedException("createClob() not supported", "0A000");
-	}
-
-	/**
-	 * 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
-	 */
-	@Override
-	public Blob createBlob() throws SQLException {
-		throw new SQLFeatureNotSupportedException("createBlob() 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 MonetClob objects that can be filled in
-	 */
-	@Override
-	public 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
-	 */
-	@Override
-	public 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
-	 */
-	@Override
-	public SQLXML createSQLXML() throws SQLException {
-		throw new SQLFeatureNotSupportedException("createSQLXML() not supported", "0A000");
-	}
-
-	/**
 	 * Retrieves the current auto-commit mode for this Connection
 	 * object.
 	 *
@@ -620,37 +536,13 @@ public class MonetConnection extends Mon
 	}
 	
 	/**
-	 * Not implemented by MonetDB's JDBC driver.
-	 *
-	 * @param name The name of the client info property to retrieve
-	 * @return The value of the client info property specified
-	 */
-	@Override
-	public String getClientInfo(String name) {
-		// This method will also return null if the specified client
-		// info property name is not supported by the driver.
-		return null;
-	}
-
-	/**
-	 * Not implemented by MonetDB's JDBC driver.
-	 *
-	 * @return A Properties object that contains the name and current
-	 *         value of each of the client info properties supported by
-	 *         the driver.
-	 */
-	@Override
-	public Properties getClientInfo() {
-		return new Properties();
-	}
-
-	/**
 	 * 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
+	 * @see #setHoldability()
 	 */
 	@Override
 	public int getHoldability() {
@@ -708,10 +600,10 @@ public class MonetConnection extends Mon
 	 * 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
@@ -734,7 +626,7 @@ public class MonetConnection extends Mon
 	 * 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
@@ -761,66 +653,26 @@ public class MonetConnection extends Mon
 		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
-	 */
 	@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 select 1;
-		Statement stmt = null;
-		try {
-			stmt = createStatement();
-			// the timeout parameter is ignored here, since
-			// MonetStatement.setQueryTimeout(timeout) is not supported.
-			stmt.executeQuery("SELECT 1");
-			stmt.close();
-			return true;
-		} catch (Exception e) {
-			if (stmt != null) {
-				try {
-					stmt.close();
-				} catch (Exception e2) {}
-			}
-		}
-		return false;
-	}
+	public String nativeSQL(String sql) {return sql;}
 
 	@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) {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
@@ -829,7 +681,7 @@ public class MonetConnection extends Mon
 	 * 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.
@@ -888,7 +740,7 @@ public class MonetConnection extends Mon
 	/**
 	 * 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.
@@ -903,10 +755,10 @@ public class MonetConnection extends Mon
 	 * ResultSet.CONCUR_UPDATABLE
 	 * @param resultSetHoldability one of the following ResultSet
 	 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
-	 * ResultSet.CLOSE_CURSORS_AT_COMMIT 
+	 * 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 
+	 * 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
@@ -943,7 +795,7 @@ public class MonetConnection extends Mon
 	 * 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
@@ -952,7 +804,7 @@ public class MonetConnection extends Mon
 	 * 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.
@@ -991,6 +843,7 @@ public class MonetConnection extends Mon
 
 	@Override
 	public PreparedStatement prepareStatement(String sql, int[] columnIndexes) {return null;}
+
 	@Override
 	public PreparedStatement prepareStatement(String sql, String[] columnNames) {return null;}
 
@@ -1006,8 +859,8 @@ public class MonetConnection extends Mon
 	 */
 	@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");
+		if (!(savepoint instanceof MonetSavepoint))
+			throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
 
 		MonetSavepoint sp = (MonetSavepoint)savepoint;
 
@@ -1031,9 +884,8 @@ public class MonetConnection extends Mon
 
 	/**
 	 * 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.
+	 * 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
@@ -1061,9 +913,8 @@ public class MonetConnection extends Mon
 
 	/**
 	 * Undoes all changes made after the given Savepoint object was set.
-	 * 
-	 * This method should be used only when auto-commit has been
-	 * disabled.
+	 *
+	 * 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
@@ -1072,8 +923,8 @@ public class MonetConnection extends Mon
 	 */
 	@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");
+		if (!(savepoint instanceof MonetSavepoint))
+			throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
 
 		MonetSavepoint sp = (MonetSavepoint)savepoint;
 
@@ -1101,9 +952,8 @@ public class MonetConnection extends Mon
 	 * 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.
-	 * 
+	 * 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
@@ -1112,7 +962,7 @@ public class MonetConnection extends Mon
 	 * 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.
 	 *
@@ -1131,7 +981,7 @@ public class MonetConnection extends Mon
 	/**
 	 * 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. 
+	 * does not support catalogs, it will silently ignore this request.
 	 */
 	@Override
 	public void setCatalog(String catalog) throws SQLException {
@@ -1139,35 +989,23 @@ public class MonetConnection extends Mon
 	}
 
 	/**
-	 * Not implemented by MonetDB's JDBC driver.
+	 * 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 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.
+	 * @param holdability - a ResultSet holdability constant; one of
+	 *	ResultSet.HOLD_CURSORS_OVER_COMMIT or
+	 *	ResultSet.CLOSE_CURSORS_AT_COMMIT
+	 * @see #getHoldability()
 	 */
 	@Override
-	public void setClientInfo(String name, String value) {
-		addWarning("clientInfo: " + name + "is not a recognised property", "01M07");
+	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");
 	}
 
 	/**
-	 * Not implemented by MonetDB's JDBC driver.
-	 *
-	 * @param props The list of client info properties to set
-	 */
-	@Override
-	public void setClientInfo(Properties props) {
-		for (Entry<Object, Object> entry : props.entrySet()) {
-			setClientInfo(entry.getKey().toString(),
-					entry.getValue().toString());
-		}
-	}
-
-	@Override
-	public void setHoldability(int holdability) {}
-
-	/**
 	 * 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
@@ -1217,9 +1055,8 @@ public class MonetConnection extends Mon
 	}
 
 	/**
-	 * Creates a savepoint with the given name in the current
-	 * transaction and returns the new Savepoint object that represents
-	 * it.
+	 * 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
@@ -1259,8 +1096,7 @@ public class MonetConnection extends Mon
 	/**
 	 * 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.
+	 * interface Connection are the possible transaction isolation levels.
 	 *
 	 * @param level one of the following Connection constants:
 	 *        Connection.TRANSACTION_READ_UNCOMMITTED,
@@ -1272,8 +1108,8 @@ public class MonetConnection extends Mon
 	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");
+				"transactions, continuing with transaction level " +
+				"raised to TRANSACTION_SERIALIZABLE", "01M09");
 		}
 	}
 
@@ -1291,18 +1127,335 @@ public class MonetConnection extends Mon
 	}
 
 	/**
-	 * Returns a string identifying this Connection to the MonetDB
-	 * server.
+	 * Returns a string identifying this Connection to the MonetDB server.
 	 *
 	 * @return a String representing this Object
 	 */
 	@Override
 	public String toString() {
-		return "MonetDB Connection (" + getJDBCURL() + ") " + 
+		return "MonetDB Connection (" + getJDBCURL() + ") " +
 				(closed ? "connected" : "disconnected");
 	}
 
-	//== 1.7 methods (JDBC 4.1)
+	//== Java 1.6 methods (JDBC 4.0)
+
+	/**
+	 * 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");
+	}
+
+
+	/**
+	 * 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 {
+		byte[] buf = new byte[1];
+		return new MonetBlob(buf);
+	}
+
+	/**
+	 * 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");
+	}
+
+	/**
+	 * 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;
+
+		// 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 e2) {}
+			}
+			if (stmt != null) {
+				try {
+					stmt.close();
+				} catch (Exception e2) {}
+			}
+		}
+		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);
+	}
+
+	/**
+	 * 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("debug") ||
+		    name.equals("hash") ||
+		    name.equals("treat_blob_as_binary")) {
+			conn_props.setProperty(name, value);
+		} else {
+			addWarning("setClientInfo: " + name + "is not a recognised property", "01M07");
+		}
+		return;
+	}
+
+	/**
+	 * 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 {
+		for (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.
@@ -1310,13 +1463,21 @@ public class MonetConnection extends Mon
 	 * @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)
-			createStatement().execute("SET SCHEMA \"" + schema + "\"");
+		if (schema == null)
+			throw new SQLException("Missing schema name", "M1M05");
+
+		Statement st = createStatement();
+		try {
+			st.execute("SET SCHEMA \"" + schema + "\"");
+		} finally {
+			st.close();
+		}
 	}
 
 	/**
@@ -1325,6 +1486,7 @@ public class MonetConnection extends Mon
 	 * @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
+	 * @since 1.7
 	 */
 	@Override
 	public String getSchema() throws SQLException {
@@ -1354,9 +1516,9 @@ public class MonetConnection extends Mon
 	 *  * 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. 
+	 *    SQLException.
 	 * Calling abort marks the connection closed and releases any
-	 * resources. Calling abort on a closed connection is a no-op. 
+	 * resources. Calling abort on a closed connection is a no-op.
 	 *
 	 * @param executor The Executor implementation which will be used by
 	 *        abort
@@ -1364,6 +1526,7 @@ public class MonetConnection extends Mon
 	 *         executor is null
 	 * @throws SecurityException if a security manager exists and
 	 *         its checkPermission method denies calling abort
+	 * @since 1.7
 	 */
 	@Override
 	public void abort(Executor executor) throws SQLException {
@@ -1393,6 +1556,7 @@ public class MonetConnection extends Mon
 	 * @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.
+	 * @since 1.7
 	 */
 	@Override
 	public void setNetworkTimeout(Executor executor, int millis)
@@ -1421,6 +1585,7 @@ public class MonetConnection extends Mon
 	 *         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 {
@@ -1434,8 +1599,14 @@ public class MonetConnection extends Mon
 		}
 	}
 
-	//== end methods of interface Connection
+
+	//== end methods of interface java.sql.Connection
+
 
+	/**
+	 * Returns the MonetDB JDBC Connection URL (without user name and password).
+	 * Defined as public because it is called from: MonetDatabaseMetaData.java getURL()
+	 */
 	public String getJDBCURL() {
 		String language = "";
 		if (lang == LANG_MAL)
@@ -1542,7 +1713,7 @@ public class MonetConnection extends Mon
 	interface Response {
 		/**
 		 * Adds a line to the underlying Response implementation.
-		 * 
+		 *
 		 * @param line the header line as String
 		 * @param linetype the line type according to the MAPI protocol
 		 * @return a non-null String if the line is invalid,
@@ -1561,7 +1732,7 @@ public class MonetConnection extends Mon
 		/**
 		 * Indicates that no more header lines will be added to this
 		 * Response implementation.
-		 * 
+		 *
 		 * @throws SQLException if the contents of the Response is not
 		 *         consistent or sufficient.
 		 */
@@ -1808,10 +1979,10 @@ public class MonetConnection extends Mon
 		@Override
 		public void complete() throws SQLException {
 			String error = "";
-			if (!isSet[NAMES]) error += "name header missing\n";
-			if (!isSet[TYPES]) error += "type header missing\n";
+			if (!isSet[NAMES])  error += "name header missing\n";
+			if (!isSet[TYPES])  error += "type header missing\n";
 			if (!isSet[TABLES]) error += "table name header missing\n";
-			if (!isSet[LENS]) error += "column width header missing\n";
+			if (!isSet[LENS])   error += "column width header missing\n";
 			if (error != "") throw new SQLException(error, "M0M10");
 		}
 
@@ -1954,12 +2125,12 @@ public class MonetConnection extends Mon
 
 				// ok, need to fetch cache block first
 				parent.executeQuery(
-						commandTempl, 
-						"export " + id + " " + ((block * cacheSize) + blockOffset) + " " + cacheSize 
+						commandTempl,
+						"export " + id + " " + ((block * cacheSize) + blockOffset) + " " + cacheSize
 				);
 				rawr = resultBlocks[block];
-				if (rawr == null) throw
-					new AssertionError("block " + block + " should have been fetched by now :(");
+				if (rawr == null)
+					throw new AssertionError("block " + block + " should have been fetched by now :(");
 			}
 
 			return rawr.getRow(blockLine);
@@ -1972,11 +2143,13 @@ public class MonetConnection extends Mon
 		@Override
 		public void close() {
 			if (closed) return;
+
 			// send command to server indicating we're done with this
 			// result only if we had an ID in the header and this result
 			// was larger than the reply size
 			try {
-				if (destroyOnClose) sendControlCommand("close " + id);
+				if (destroyOnClose)
+					sendControlCommand("close " + id);
 			} catch (SQLException e) {
 				// probably a connection error...
 			}
@@ -1984,7 +2157,8 @@ public class MonetConnection extends Mon
 			// close the data block associated with us
 			for (int i = 1; i < resultBlocks.length; i++) {
 				DataBlockResponse r = resultBlocks[i];
-				if (r != null) r.close();
+				if (r != null)
+					r.close();
 			}
 
 			closed = true;
@@ -2012,7 +2186,7 @@ public class MonetConnection extends Mon
 	 * by brackets ("[" and "]").  A DataBlockResponse object holds the
 	 * raw data as read from the server, in a parsed manner, ready for
 	 * easy retrieval.
-	 * 
+	 *
 	 * This object is not intended to be queried by multiple threads
 	 * synchronously. It is designed to work for one thread retrieving
 	 * rows from it.  When multiple threads will retrieve rows from this
@@ -2044,7 +2218,7 @@ public class MonetConnection extends Mon
 		 * Note that an IndexOutOfBoundsException can be thrown when an
 		 * attempt is made to add more than the original construction size
 		 * specified.
-		 * 
+		 *
 		 * @param line the header line as String
 		 * @param linetype the line type according to the MAPI protocol
 		 * @return a non-null String if the line is invalid,
@@ -2083,8 +2257,9 @@ public class MonetConnection extends Mon
 		 */
 		@Override
 		public void complete() throws SQLException {
-			if ((pos + 1) != data.length) throw
-				new SQLException("Inconsistent state detected!  Current block capacity: " + data.length + ", block usage: " + (pos + 1) + ".  Did MonetDB send what it promised to?", "M0M10");
+			if ((pos + 1) != data.length)
+				throw new SQLException("Inconsistent state detected!  Current block capacity: "
+					+ data.length + ", block usage: " + (pos + 1) + ".  Did MonetDB send what it promised to?", "M0M10");
 		}
 
 		/**
@@ -2480,7 +2655,7 @@ public class MonetConnection extends Mon
 										case StartOfHeaderParser.Q_BLOCK: {
 											// a new block of results for a
 											// response...
-											int id = sohp.getNextAsInt(); 
+											int id = sohp.getNextAsInt();
 											sohp.getNextAsInt();	// columncount
 											int rowcount = sohp.getNextAsInt();
 											int offset = sohp.getNextAsInt();
@@ -2648,7 +2823,7 @@ public class MonetConnection extends Mon
 		private int state = WAIT;
 		
 		final Lock sendLock = new ReentrantLock();
-		final Condition queryAvailable = sendLock.newCondition(); 
+		final Condition queryAvailable = sendLock.newCondition();
 		final Condition waiting = sendLock.newCondition();
 
 		/**
@@ -2711,7 +2886,7 @@ public class MonetConnection extends Mon
 		public void runQuery(String[] templ, String query) throws SQLException {
 			sendLock.lock();
 			try {
-				if (state != WAIT) 
+				if (state != WAIT)
 					throw new SQLException("SendThread already in use or shutting down!", "M0M03");
 
 				this.templ = templ;
@@ -2750,7 +2925,7 @@ public class MonetConnection extends Mon
 		}
 
 		/**
-		 * Requests this SendThread to stop. 
+		 * Requests this SendThread to stop.
 		 */
 		public void shutdown() {
 			sendLock.lock();
@@ -2761,4 +2936,3 @@ public class MonetConnection extends Mon
 	}
 	// }}}
 }
-