From cf721ff298be72c1bf1651692beebe5351086a52 Mon Sep 17 00:00:00 2001
From: gmantele <gmantele@ari.uni-heidelberg.de>
Date: Wed, 2 Aug 2017 19:33:11 +0200
Subject: [PATCH] [ADQL,TAP] Basic MySQL support.

On the contrary to other DBMS, MySQL supports schemas, but as databases.
Which means that JDBCConnection gets from the JDBC driver that MySQL does
not support schemas and so it tries to access TAP_SCHEMA tables with a
'TAP_SCHEMA_' prefix instead of 'TAP_SCHEMA.' one. Since MySQL does
behave like it supports schemas, JDBCConnection.supportsSchema must be
set to 'true' if the DBMS is MySQL.

Besides, since no schemas are returned by the JDBC driver
(cf DatabaseMetadata.listSchema(...)), the function
JDBCConnection.isSchemaExisting(String, DatabaseMetaData) must always assume
that the specified schema exists if the DBMS is MySQL. This is particularly
important when the existence of 'TAP_UPLOAD' must be checked, because if the
function returns 'false' the library will attempt to create the database/schema
'TAP_UPLOAD' and will obviously fail due to a lack of permissions. Of course,
it means that the TAP implementor must create manually the schema/database
'TAP_UPLOAD' him-/her-self.

The second particularity of MySQL is the quote character for identifiers.
It is a back-quote (`) instead of a double quote ("). To reflect this
difference, JDBCTranslator.appendIdentifier(...) has been overwritten in a new
JDBCTranslator extension: MySQLTranslator.

The translation of all SQL types and mathematical functions have been adapted to
MySQL according to the online documentation. Few tests have been done locally
with a tiny database. This seems to work but further testing should be
performed in order to ensure the stability of this implementation.
---
 src/adql/translator/MySQLTranslator.java   | 304 ++++++++++++
 src/tap/config/ConfigurableTAPFactory.java |  46 +-
 src/tap/config/TAPConfiguration.java       |  72 +--
 src/tap/config/tap_configuration_file.html |   4 +-
 src/tap/config/tap_full.properties         |   6 +-
 src/tap/config/tap_min.properties          |   6 +-
 src/tap/db/JDBCConnection.java             | 545 +++++++++++----------
 7 files changed, 654 insertions(+), 329 deletions(-)
 create mode 100644 src/adql/translator/MySQLTranslator.java

diff --git a/src/adql/translator/MySQLTranslator.java b/src/adql/translator/MySQLTranslator.java
new file mode 100644
index 0000000..91a45c7
--- /dev/null
+++ b/src/adql/translator/MySQLTranslator.java
@@ -0,0 +1,304 @@
+package adql.translator;
+
+import adql.db.DBType;
+import adql.db.DBType.DBDatatype;
+import adql.db.STCS.Region;
+import adql.parser.ParseException;
+import adql.query.IdentifierField;
+import adql.query.operand.function.geometry.AreaFunction;
+import adql.query.operand.function.geometry.BoxFunction;
+import adql.query.operand.function.geometry.CentroidFunction;
+import adql.query.operand.function.geometry.CircleFunction;
+import adql.query.operand.function.geometry.ContainsFunction;
+import adql.query.operand.function.geometry.DistanceFunction;
+import adql.query.operand.function.geometry.ExtractCoord;
+import adql.query.operand.function.geometry.ExtractCoordSys;
+import adql.query.operand.function.geometry.IntersectsFunction;
+import adql.query.operand.function.geometry.PointFunction;
+import adql.query.operand.function.geometry.PolygonFunction;
+import adql.query.operand.function.geometry.RegionFunction;
+
+/*
+ * This file is part of ADQLLibrary.
+ *
+ * ADQLLibrary is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * ADQLLibrary is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2017 - Astronomisches Rechen Institut (ARI)
+ */
+
+/**
+ * <p>Translates all ADQL objects into an SQL interrogation query designed for MySQL.</p>
+ *
+ * <p><i><b>Important</b>:
+ * 	The geometrical functions are translated exactly as in ADQL.
+ * 	You will probably need to extend this translator to correctly manage the geometrical functions.
+ * </i></p>
+ *
+ * @author Gr&eacute;gory Mantelet (ARI)
+ * @version 2.1 (08/2017)
+ * @since 2.1
+ */
+public class MySQLTranslator extends JDBCTranslator {
+
+	/** MySQL requires a length for variable-length types such as CHAR, VARCHAR,
+	 * BINARY and VARBINARY. This static attributes is the default value set
+	 * by this translator if no length is specified. */
+	public static int DEFAULT_VARIABLE_LENGTH = 200;
+
+	/** Indicate the case sensitivity to apply to each SQL identifier
+	 * (only SCHEMA, TABLE and COLUMN).
+	 * <p><i>Note:
+	 * 	In this implementation, this field is set by the constructor and never
+	 * 	modified elsewhere. It would be better to never modify it after the
+	 * construction in order to keep a certain consistency.
+	 * </i></p>
+	 */
+	protected byte caseSensitivity = 0x00;
+
+	/**
+	 * Build a MySQLTranslator which always translates in SQL all identifiers
+	 * (schema, table and column) in a case sensitive manner ; in other words,
+	 * schema, table and column names will be surrounded by back-quotes in the
+	 * SQL translation.
+	 */
+	public MySQLTranslator(){
+		caseSensitivity = 0x0F;
+	}
+
+	/**
+	 * Build a MySQLTranslator which will always translate in SQL identifiers
+	 * with the defined case sensitivity.
+	 *
+	 * @param catalog	<i>true</i> to translate catalog names with back-quotes
+	 *               	(case sensitive in the DBMS), <i>false</i> otherwise.
+	 * @param schema	<i>true</i> to translate schema names with back-quotes
+	 *              	(case sensitive in the DBMS), <i>false</i> otherwise.
+	 * @param table		<i>true</i> to translate table names with back-quotes
+	 *             		(case sensitive in the DBMS), <i>false</i> otherwise.
+	 * @param column	<i>true</i> to translate column names with back-quotes
+	 *              	(case sensitive in the DBMS), <i>false</i> otherwise.
+	 */
+	public MySQLTranslator(final boolean allCaseSensitive){
+		caseSensitivity = allCaseSensitive ? (byte)0x0F : (byte)0x00;
+	}
+
+	/**
+	 * Build a MySQLTranslator which always translates in SQL all identifiers
+	 * (schema, table and column) in the specified case sensitivity ; in other
+	 * words, schema, table and column names will all be surrounded or not by
+	 * back-quotes in the SQL translation.
+	 *
+	 * @param allCaseSensitive	<i>true</i> to translate all identifiers in a
+	 *                        	case sensitive manner
+	 *                        	(surrounded by back-quotes),
+	 *                        	<i>false</i> for case insensitivity.
+	 */
+	public MySQLTranslator(final boolean catalog, final boolean schema, final boolean table, final boolean column){
+		caseSensitivity = IdentifierField.CATALOG.setCaseSensitive(caseSensitivity, catalog);
+		caseSensitivity = IdentifierField.SCHEMA.setCaseSensitive(caseSensitivity, schema);
+		caseSensitivity = IdentifierField.TABLE.setCaseSensitive(caseSensitivity, table);
+		caseSensitivity = IdentifierField.COLUMN.setCaseSensitive(caseSensitivity, column);
+	}
+
+	@Override
+	public boolean isCaseSensitive(final IdentifierField field){
+		return field == null ? false : field.isCaseSensitive(caseSensitivity);
+	}
+
+	@Override
+	public StringBuffer appendIdentifier(final StringBuffer str, final String id, final boolean caseSensitive){
+		/* Note: In MySQL the identifier quoting character is a back-quote. */
+		if (caseSensitive && !id.matches("\"[^\"]*\""))
+			return str.append('`').append(id).append('`');
+		else
+			return str.append(id);
+	}
+
+	/* ********************************************************************** */
+	/* *                                                                    * */
+	/* * TYPE MANAGEMENT                                                    * */
+	/* *                                                                    * */
+	/* ********************************************************************** */
+
+	@Override
+	public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params){
+		// If no type is provided return VARCHAR:
+		if (dbmsTypeName == null || dbmsTypeName.trim().length() == 0)
+			return null;
+
+		// Put the dbmsTypeName in lower case for the following comparisons:
+		dbmsTypeName = dbmsTypeName.toLowerCase();
+
+		// Extract the length parameter (always the first one):
+		int lengthParam = DBType.NO_LENGTH;
+		if (params != null && params.length > 0){
+			try{
+				lengthParam = Integer.parseInt(params[0]);
+			}catch(NumberFormatException nfe){}
+		}
+
+		// SMALLINT
+		if (dbmsTypeName.equals("smallint") || dbmsTypeName.equals("tinyint") || dbmsTypeName.equals("bool") || dbmsTypeName.equals("boolean"))
+			return new DBType(DBDatatype.SMALLINT);
+		// INTEGER
+		else if (dbmsTypeName.equals("integer") || dbmsTypeName.equals("int") || dbmsTypeName.equals("mediumint"))
+			return new DBType(DBDatatype.INTEGER);
+		// BIGINT
+		else if (dbmsTypeName.equals("bigint"))
+			return new DBType(DBDatatype.BIGINT);
+		// REAL
+		else if (dbmsTypeName.equals("float") || dbmsTypeName.equals("real"))
+			return new DBType(DBDatatype.REAL);
+		// DOUBLE
+		else if (dbmsTypeName.equals("double") || dbmsTypeName.equals("double precision") || dbmsTypeName.equals("dec") || dbmsTypeName.equals("decimal") || dbmsTypeName.equals("numeric") || dbmsTypeName.equals("fixed"))
+			return new DBType(DBDatatype.DOUBLE);
+		// BINARY
+		else if (dbmsTypeName.equals("bit") || dbmsTypeName.equals("binary") || dbmsTypeName.equals("char byte"))
+			return new DBType(DBDatatype.BINARY, lengthParam);
+		// VARBINARY
+		else if (dbmsTypeName.equals("varbinary"))
+			return new DBType(DBDatatype.VARBINARY, lengthParam);
+		// CHAR
+		else if (dbmsTypeName.equals("char") || dbmsTypeName.equals("character") || dbmsTypeName.equals("nchar") || dbmsTypeName.equals("national char"))
+			return new DBType(DBDatatype.CHAR, lengthParam);
+		// VARCHAR
+		else if (dbmsTypeName.equals("varchar") || dbmsTypeName.equals("character varying") || dbmsTypeName.equals("nvarchar") || dbmsTypeName.equals("national varchar"))
+			return new DBType(DBDatatype.VARCHAR, lengthParam);
+		// BLOB
+		else if (dbmsTypeName.equals("blob") || dbmsTypeName.equals("tinyblob") || dbmsTypeName.equals("mediumblob") || dbmsTypeName.equals("longblob"))
+			return new DBType(DBDatatype.BLOB);
+		// CLOB
+		else if (dbmsTypeName.equals("text") || dbmsTypeName.equals("tinytext") || dbmsTypeName.equals("mediumtext") || dbmsTypeName.equals("longtext"))
+			return new DBType(DBDatatype.CLOB);
+		// TIMESTAMP
+		else if (dbmsTypeName.equals("timestamp") || dbmsTypeName.equals("date") || dbmsTypeName.equals("datetime") || dbmsTypeName.equals("time") || dbmsTypeName.equals("year"))
+			return new DBType(DBDatatype.TIMESTAMP);
+		// Default:
+		else
+			return null;
+	}
+
+	@Override
+	public String convertTypeToDB(final DBType type){
+		if (type == null)
+			return "VARCHAR(" + DEFAULT_VARIABLE_LENGTH + ")";
+
+		switch(type.type){
+
+			case SMALLINT:
+			case INTEGER:
+			case REAL:
+			case BIGINT:
+			case TIMESTAMP:
+				return type.type.toString();
+
+			case DOUBLE:
+				return "DOUBLE PRECISION";
+
+			case CHAR:
+			case VARCHAR:
+			case BINARY:
+			case VARBINARY:
+				return type.type.toString() + "(" + (type.length > 0 ? type.length : DEFAULT_VARIABLE_LENGTH) + ")";
+
+			case BLOB:
+				return "BLOB";
+
+			case CLOB:
+				return "TEXT";
+
+			case POINT:
+			case REGION:
+			default:
+				return "VARCHAR(" + DEFAULT_VARIABLE_LENGTH + ")";
+		}
+	}
+
+	@Override
+	public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException{
+		throw new ParseException("Unsupported geometrical value! The value \"" + jdbcColValue + "\" can not be parsed as a region.");
+	}
+
+	@Override
+	public Object translateGeometryToDB(final Region region) throws ParseException{
+		throw new ParseException("Geometries can not be uploaded in the database in this implementation!");
+	}
+
+	/* ********************************************************************** */
+	/* *                                                                    * */
+	/* * SPATIAL FUNCTIONS TRANSLATION                                      * */
+	/* *                                                                    * */
+	/* ********************************************************************** */
+
+	@Override
+	public String translate(ExtractCoord extractCoord) throws TranslationException{
+		return getDefaultADQLFunction(extractCoord);
+	}
+
+	@Override
+	public String translate(ExtractCoordSys extractCoordSys) throws TranslationException{
+		return getDefaultADQLFunction(extractCoordSys);
+	}
+
+	@Override
+	public String translate(AreaFunction areaFunction) throws TranslationException{
+		return getDefaultADQLFunction(areaFunction);
+	}
+
+	@Override
+	public String translate(CentroidFunction centroidFunction) throws TranslationException{
+		return getDefaultADQLFunction(centroidFunction);
+	}
+
+	@Override
+	public String translate(DistanceFunction fct) throws TranslationException{
+		return getDefaultADQLFunction(fct);
+	}
+
+	@Override
+	public String translate(ContainsFunction fct) throws TranslationException{
+		return getDefaultADQLFunction(fct);
+	}
+
+	@Override
+	public String translate(IntersectsFunction fct) throws TranslationException{
+		return getDefaultADQLFunction(fct);
+	}
+
+	@Override
+	public String translate(BoxFunction box) throws TranslationException{
+		return getDefaultADQLFunction(box);
+	}
+
+	@Override
+	public String translate(CircleFunction circle) throws TranslationException{
+		return getDefaultADQLFunction(circle);
+	}
+
+	@Override
+	public String translate(PointFunction point) throws TranslationException{
+		return getDefaultADQLFunction(point);
+	}
+
+	@Override
+	public String translate(PolygonFunction polygon) throws TranslationException{
+		return getDefaultADQLFunction(polygon);
+	}
+
+	@Override
+	public String translate(RegionFunction region) throws TranslationException{
+		return getDefaultADQLFunction(region);
+	}
+
+}
diff --git a/src/tap/config/ConfigurableTAPFactory.java b/src/tap/config/ConfigurableTAPFactory.java
index 9193255..396f76e 100644
--- a/src/tap/config/ConfigurableTAPFactory.java
+++ b/src/tap/config/ConfigurableTAPFactory.java
@@ -2,21 +2,21 @@ package tap.config;
 
 /*
  * This file is part of TAPLibrary.
- * 
+ *
  * TAPLibrary is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- * 
+ *
  * TAPLibrary is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public License
  * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
- * Copyright 2016 - Astronomisches Rechen Institut (ARI)
+ *
+ * Copyright 2016-2017 - Astronomisches Rechen Institut (ARI)
  */
 
 import static tap.config.TAPConfiguration.DEFAULT_BACKUP_BY_USER;
@@ -33,9 +33,11 @@ import static tap.config.TAPConfiguration.KEY_SQL_TRANSLATOR;
 import static tap.config.TAPConfiguration.VALUE_JDBC;
 import static tap.config.TAPConfiguration.VALUE_JDBC_DRIVERS;
 import static tap.config.TAPConfiguration.VALUE_JNDI;
+import static tap.config.TAPConfiguration.VALUE_MYSQL;
 import static tap.config.TAPConfiguration.VALUE_NEVER;
 import static tap.config.TAPConfiguration.VALUE_PGSPHERE;
 import static tap.config.TAPConfiguration.VALUE_POSTGRESQL;
+import static tap.config.TAPConfiguration.VALUE_SQLSERVER;
 import static tap.config.TAPConfiguration.VALUE_USER_ACTION;
 import static tap.config.TAPConfiguration.getProperty;
 
@@ -50,8 +52,10 @@ import javax.naming.NamingException;
 import javax.sql.DataSource;
 
 import adql.translator.JDBCTranslator;
+import adql.translator.MySQLTranslator;
 import adql.translator.PgSphereTranslator;
 import adql.translator.PostgreSQLTranslator;
+import adql.translator.SQLServerTranslator;
 import tap.AbstractTAPFactory;
 import tap.ServiceConnection;
 import tap.TAPException;
@@ -66,15 +70,15 @@ import uws.service.log.UWSLog.LogLevel;
 
 /**
  * <p>Concrete implementation of a {@link TAPFactory} which is parameterized by a TAP configuration file.</p>
- * 
+ *
  * <p>
  * 	All abstract or NULL-implemented methods/functions left by {@link AbstractTAPFactory} are implemented using values
  *  of a TAP configuration file. The concerned methods are: {@link #getConnection(String)}, {@link #freeConnection(DBConnection)},
  *  {@link #destroy()}, {@link #createADQLTranslator()} and {@link #createUWSBackupManager(UWSService)}.
  * </p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 2.1 (04/2016)
+ * @version 2.1 (08/2017)
  * @since 2.0
  */
 public class ConfigurableTAPFactory extends AbstractTAPFactory {
@@ -111,10 +115,10 @@ public class ConfigurableTAPFactory extends AbstractTAPFactory {
 
 	/**
 	 * Build a {@link TAPFactory} using the given TAP service description and TAP configuration file.
-	 * 
+	 *
 	 * @param service		The TAP service description.
 	 * @param tapConfig		The TAP configuration file containing particularly information about the database access.
-	 * 
+	 *
 	 * @throws NullPointerException	If one of the parameter is NULL.
 	 * @throws TAPException			If some properties of the TAP configuration file are wrong.
 	 */
@@ -200,11 +204,19 @@ public class ConfigurableTAPFactory extends AbstractTAPFactory {
 		else if (sqlTranslator.equalsIgnoreCase(VALUE_PGSPHERE))
 			translator = PgSphereTranslator.class;
 
-		// case d: a client defined ADQLTranslator (with the provided class name)
+		// case d: SQLServer translator
+		else if (sqlTranslator.equalsIgnoreCase(VALUE_SQLSERVER))
+			translator = SQLServerTranslator.class;
+
+		// case e: MySQL translator
+		else if (sqlTranslator.equalsIgnoreCase(VALUE_MYSQL))
+			translator = MySQLTranslator.class;
+
+		// case f: a client defined ADQLTranslator (with the provided class name)
 		else if (TAPConfiguration.isClassName(sqlTranslator))
 			translator = TAPConfiguration.fetchClass(sqlTranslator, KEY_SQL_TRANSLATOR, JDBCTranslator.class);
 
-		// case e: unsupported value
+		// case g: unsupported value
 		else
 			throw new TAPException("Unsupported value for the property " + KEY_SQL_TRANSLATOR + ": \"" + sqlTranslator + "\" !");
 
@@ -244,7 +256,7 @@ public class ConfigurableTAPFactory extends AbstractTAPFactory {
 	 * Build a {@link JDBCTranslator} instance with the given class ({@link #translator} ;
 	 * specified by the property sql_translator). If the instance can not be build,
 	 * whatever is the reason, a TAPException MUST be thrown.
-	 * 
+	 *
 	 * Note: This function is called at the initialization of {@link ConfigurableTAPFactory}
 	 * in order to check that a translator can be created.
 	 */
@@ -262,7 +274,7 @@ public class ConfigurableTAPFactory extends AbstractTAPFactory {
 	/**
 	 * Build a {@link JDBCConnection} thanks to the database parameters specified
 	 * in the TAP configuration file (the properties: jdbc_driver_path, db_url, db_user, db_password).
-	 * 
+	 *
 	 * @see JDBCConnection#JDBCConnection(java.sql.Connection, JDBCTranslator, String, tap.log.TAPLog)
 	 * @see JDBCConnection#JDBCConnection(String, String, String, String, JDBCTranslator, String, tap.log.TAPLog)
 	 */
@@ -317,11 +329,11 @@ public class ConfigurableTAPFactory extends AbstractTAPFactory {
 	/**
 	 * Build an {@link DefaultTAPBackupManager} thanks to the backup manager parameters specified
 	 * in the TAP configuration file (the properties: backup_frequency, backup_by_user).
-	 * 
+	 *
 	 * Note: If the specified backup_frequency is negative, no backup manager is returned.
-	 * 
+	 *
 	 * @return	null if the specified backup frequency is negative, or an instance of {@link DefaultTAPBackupManager} otherwise.
-	 * 
+	 *
 	 * @see tap.AbstractTAPFactory#createUWSBackupManager(uws.service.UWSService)
 	 * @see DefaultTAPBackupManager
 	 */
diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java
index 34fcdb1..00363ce 100644
--- a/src/tap/config/TAPConfiguration.java
+++ b/src/tap/config/TAPConfiguration.java
@@ -2,20 +2,20 @@ package tap.config;
 
 /*
  * This file is part of TAPLibrary.
- * 
+ *
  * TAPLibrary is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- * 
+ *
  * TAPLibrary is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public License
  * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
+ *
  * Copyright 2015-2017 - Astronomisches Rechen Institut (ARI)
  */
 
@@ -31,12 +31,12 @@ import tap.backup.DefaultTAPBackupManager;
 
 /**
  * <p>Utility class gathering tool functions and properties' names useful to deal with a TAP configuration file.</p>
- * 
+ *
  * <p><i>This class implements the Design Pattern "Utility": no instance of this class can be created, it can not be extended,
  * and it must be used only thanks to its static classes and attributes.</i></p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 2.1 (03/2017)
+ * @version 2.1 (08/2017)
  * @since 2.0
  */
 public final class TAPConfiguration {
@@ -134,6 +134,12 @@ public final class TAPConfiguration {
 	public final static String VALUE_POSTGRESQL = "postgres";
 	/** Value of the property {@link #KEY_SQL_TRANSLATOR} to select a PgSphere translator. */
 	public final static String VALUE_PGSPHERE = "pgsphere";
+	/** Value of the property {@link #KEY_SQL_TRANSLATOR} to select an SQLServer translator.
+	 * @since 2.1*/
+	public final static String VALUE_SQLSERVER = "sqlserver";
+	/** Value of the property {@link #KEY_SQL_TRANSLATOR} to select a MySQL translator.
+	 * @since 2.1*/
+	public final static String VALUE_MYSQL = "mysql";
 	/** Name/Key of the property specifying by how many rows the library should fetch a query result from the database.
 	 * This is the fetch size for to apply for synchronous queries. */
 	public final static String KEY_SYNC_FETCH_SIZE = "sync_fetch_size";
@@ -295,10 +301,10 @@ public final class TAPConfiguration {
 	 * 	<li>The returned property value is trimmed (no space at the beginning and at the end of the string).</li>
 	 * 	<li>If the value is empty (length=0), NULL is returned.</li>
 	 * </ul>
-	 * 
+	 *
 	 * @param prop	List of property
 	 * @param key	Property whose the value is requested.
-	 * 
+	 *
 	 * @return		Return property value.
 	 */
 	public final static String getProperty(final Properties prop, final String key){
@@ -317,11 +323,11 @@ public final class TAPConfiguration {
 	/**
 	 * Test whether a property value is a class name.
 	 * Expected syntax: a non-empty string surrounded by brackets ('{' and '}').
-	 * 
+	 *
 	 * Note: The class name itself is not checked!
-	 * 
+	 *
 	 * @param value	Property value.
-	 * 
+	 *
 	 * @return <i>true</i> if the given value is formatted as a class name, <i>false</i> otherwise.
 	 */
 	public final static boolean isClassName(final String value){
@@ -330,16 +336,16 @@ public final class TAPConfiguration {
 
 	/**
 	 * Fetch the class object corresponding to the class name provided between brackets in the given value.
-	 * 
+	 *
 	 * @param value			Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
 	 * @param propertyName	Name of the property associated with the parameter "value".
 	 * @param expectedType	Type of the class expected to be returned ; it is also the type which parameterizes this function: C.
-	 * 
+	 *
 	 * @return	The corresponding Class object.
-	 * 
+	 *
 	 * @throws TAPException	If the class name is incorrect
 	 *                     	or if its type is not compatible with the parameterized type C (represented by the parameter "expectedType").
-	 * 
+	 *
 	 * @see #isClassName(String)
 	 */
 	@SuppressWarnings("unchecked")
@@ -366,18 +372,18 @@ public final class TAPConfiguration {
 
 	/**
 	 * Test whether the specified class has a constructor with the specified parameters.
-	 * 
+	 *
 	 * @param propValue		Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
 	 * @param propName		Name of the property associated with the parameter "propValue".
 	 * @param expectedType	Type of the class expected to be returned ; it is also the type which parameterizes this function: C.
 	 * @param pTypes		List of each constructor parameter type. Each type MUST be exactly the type declared in the class constructor to select. <i>NULL or empty array if no parameter.</i>
-	 * 
+	 *
 	 * @return	<code>true</code> if the specified class has a constructor with the specified parameters,
 	 *        	<code>false</code> otherwise.
-	 * 
+	 *
 	 * @throws TAPException	If the class name is incorrect
 	 *                     	or if its type is not compatible with the parameterized type C (represented by the parameter "expectedType").
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	public final static < C > boolean hasConstructor(final String propValue, final String propName, final Class<C> expectedType, final Class<?>[] pTypes) throws TAPException{
@@ -401,20 +407,20 @@ public final class TAPConfiguration {
 
 	/**
 	 * <p>Create an instance of the specified class. The class name is expected to be surrounded by {} in the given value.</p>
-	 * 
+	 *
 	 * <p>The instance is created using the empty constructor of the specified class.</p>
-	 * 
+	 *
 	 * @param propValue		Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
 	 * @param propName		Name of the property associated with the parameter "propValue".
 	 * @param expectedType	Type of the class expected to be returned ; it is also the type which parameterizes this function: C.
-	 * 
+	 *
 	 * @return	The corresponding instance.
-	 * 
+	 *
 	 * @throws TAPException	If the class name is incorrect
 	 *                     	or if its type is not compatible with the parameterized type C (represented by the parameter "expectedType")
 	 *                     	or if the specified class has no empty constructor
 	 *                     	or if an error occurred while calling this constructor.
-	 * 
+	 *
 	 * @see #isClassName(String)
 	 * @see #fetchClass(String, String, Class)
 	 */
@@ -424,25 +430,25 @@ public final class TAPConfiguration {
 
 	/**
 	 * <p>Create an instance of the specified class. The class name is expected to be surrounded by {} in the given value.</p>
-	 * 
+	 *
 	 * <p><b>IMPORTANT:</b>
 	 * 	The instance is created using the constructor whose the declaration matches exactly with the given list of parameter types.
 	 * 	The number and types of given parameters MUST match exactly to the list of parameter types.
 	 * </p>
-	 * 
+	 *
 	 * @param propValue		Value which is supposed to contain the class name between brackets (see {@link #isClassName(String)} for more details)
 	 * @param propName		Name of the property associated with the parameter "propValue".
 	 * @param expectedType	Type of the class expected to be returned ; it is also the type which parameterizes this function: C.
 	 * @param pTypes		List of each constructor parameter type. Each type MUST be exactly the type declared in the class constructor to select. <i>NULL or empty array if no parameter.</i>
 	 * @param parameters	List of all constructor parameters. The number of object MUST match exactly the number of classes provided in the parameter pTypes. <i>NULL or empty array if no parameter.</i>
-	 * 
+	 *
 	 * @return	The corresponding instance.
-	 * 
+	 *
 	 * @throws TAPException	If the class name is incorrect
 	 *                     	or if its type is not compatible with the parameterized type C (represented by the parameter "expectedType")
 	 *                     	or if the constructor with the specified parameters can not be found
 	 *                     	or if an error occurred while calling this constructor.
-	 * 
+	 *
 	 * @see #isClassName(String)
 	 * @see #fetchClass(String, String, Class)
 	 */
@@ -502,13 +508,13 @@ public final class TAPConfiguration {
 	 * 	If the unit is not specified, it is set by default to ROWS.
 	 * </p>
 	 * <p><i>Note: If the value is strictly less than 0 (whatever is the unit), the returned value will be -1.</i></p>
-	 * 
+	 *
 	 * @param value				Property value (must follow the limit syntax: num_val[unit] ; ex: 20kB or 2000 (for 2000 rows)).
 	 * @param propertyName		Name of the property which specify the limit.
 	 * @param areBytesAllowed	Tells whether the unit BYTES is allowed. If not and a BYTES unit is encountered, then an exception is thrown.
-	 * 
+	 *
 	 * @return	An array with always 2 items: [0]=numeric value (of type Integer), [1]=unit (of type {@link LimitUnit}).
-	 * 
+	 *
 	 * @throws TAPException	If the syntax is incorrect or if a not allowed unit has been used.
 	 */
 	public final static Object[] parseLimit(String value, final String propertyName, final boolean areBytesAllowed) throws TAPException{
diff --git a/src/tap/config/tap_configuration_file.html b/src/tap/config/tap_configuration_file.html
index 31c6a61..1e7c61c 100644
--- a/src/tap/config/tap_configuration_file.html
+++ b/src/tap/config/tap_configuration_file.html
@@ -167,10 +167,10 @@
 				<td>text</td>
 				<td>
 					<p>The translator to use in order to translate ADQL to a SQL compatible with the used DBMS and its spatial extension.</p>
-					<p>The TAP library supports only Postgresql (without spatial extension) and PgSphere for the moment. But you can provide your own SQL translator
+					<p>The TAP library supports only Postgresql (no spatial extension), PostgreSQL+PgSphere, SQLServer (no spatial extension) and MySQL (no spatial extension) for the moment. But you can provide your own SQL translator
 					(even if it does not have spatial features), by providing the name of a class (within brackets: {...}) that implements ADQLTranslator and which have at least an empty constructor.</p>
 				</td>
-				<td><ul><li>postgres</li><li>pgsphere</li><li>{apackage.MyADQLTranslator}</li></ul></td>
+				<td><ul><li>postgres</li><li>pgsphere</li><li>sqlserver</li><li>mysql</li><li>{apackage.MyADQLTranslator}</li></ul></td>
 			</tr>
 			<tr class="optional">
 				<td class="done">sync_fetch_size</td>
diff --git a/src/tap/config/tap_full.properties b/src/tap/config/tap_full.properties
index 937df37..0784203 100644
--- a/src/tap/config/tap_full.properties
+++ b/src/tap/config/tap_full.properties
@@ -2,7 +2,7 @@
 #             FULL TAP CONFIGURATION FILE                #
 #                                                        #
 # TAP Version: 2.1                                       #
-# Date: 03 Feb. 2017                                     #
+# Date: 02 Aug. 2017                                     #
 # Author: Gregory Mantelet (ARI)                         #
 #                                                        #
 ########################################################## 
@@ -62,11 +62,11 @@ database_access =
 # [MANDATORY]
 # The translator to use in order to translate ADQL to a SQL compatible with the used DBMS and its spatial extension.
 # 
-# The TAP library supports only Postgresql (without spatial extension) and PgSphere for the moment. But you can provide your own SQL translator
+# The TAP library supports only Postgresql (no spatial extension), PostgreSQL+PgSphere, SQLServer (no spatial extension) and MySQL (no spatial extension) for the moment. But you can provide your own SQL translator
 # (even if it does not have spatial features), by providing the name of a class (within brackets: {...}) that implements ADQLTranslator (for instance: {apackage.MyADQLTranslator})
 # and which have at least an empty constructor.
 # 
-# Allowed values: postgres, pgsphere, a class name
+# Allowed values: postgres, pgsphere, sqlserver, mysql, a class name
 sql_translator = postgres
 
 # [OPTIONAL]
diff --git a/src/tap/config/tap_min.properties b/src/tap/config/tap_min.properties
index 79e2356..1785ae7 100644
--- a/src/tap/config/tap_min.properties
+++ b/src/tap/config/tap_min.properties
@@ -2,7 +2,7 @@
 #            MINIMUM TAP CONFIGURATION FILE              #
 #                                                        #
 # TAP Version: 2.1                                       #
-# Date: 03 Feb. 2017                                     #
+# Date: 02 Aug. 2017                                     #
 # Author: Gregory Mantelet (ARI)                         #
 #                                                        #
 ########################################################## 
@@ -22,11 +22,11 @@ database_access =
 
 # The translator to use in order to translate ADQL to a SQL compatible with the used DBMS and its spatial extension.
 # 
-# The TAP library supports only Postgresql (without spatial extension) and PgSphere for the moment. But you can provide your own SQL translator
+# The TAP library supports only Postgresql (no spatial extension), PostgreSQL+PgSphere, SQLServer (no spatial extension) and MySQL (no spatial extension) for the moment. But you can provide your own SQL translator
 # (even if it does not have spatial features), by providing the name of a class (within brackets: {...}) that implements ADQLTranslator (for instance: {apackage.MyADQLTranslator})
 # and which have at least an empty constructor.
 # 
-# Allowed values: postgres, pgsphere, a class name
+# Allowed values: postgres, pgsphere, sqlserver, mysql, a class name
 sql_translator = postgres
 
 #############################
diff --git a/src/tap/db/JDBCConnection.java b/src/tap/db/JDBCConnection.java
index 9ce843d..02ef467 100644
--- a/src/tap/db/JDBCConnection.java
+++ b/src/tap/db/JDBCConnection.java
@@ -2,20 +2,20 @@ package tap.db;
 
 /*
  * This file is part of TAPLibrary.
- * 
+ *
  * TAPLibrary is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- * 
+ *
  * TAPLibrary is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public License
  * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
+ *
  * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
@@ -65,15 +65,15 @@ import uws.service.log.UWSLog.LogLevel;
 
 /**
  * <p>This {@link DBConnection} implementation is theoretically able to deal with any DBMS JDBC connection.</p>
- * 
+ *
  * <p><i>Note:
  * 	"Theoretically", because its design has been done using information about Postgres, SQLite, Oracle, MySQL, Java DB (Derby) and H2.
  * 	Then it has been really tested successfully with Postgres, SQLite and H2.
  * </i></p>
- * 
- * 
+ *
+ *
  * <h3>Only one query executed at a time!</h3>
- * 
+ *
  * <p>
  * 	With a single instance of {@link JDBCConnection} it is possible to execute only one query (whatever the type: SELECT, UPDATE, DELETE, ...)
  * 	at a time. This is indeed the simple way chosen with this implementation in order to allow the cancellation of any query by managing only
@@ -81,13 +81,13 @@ import uws.service.log.UWSLog.LogLevel;
  * 	So all queries are executed with the same {@link Statement}. Thus, allowing the execution of one query at a time lets
  * 	abort only one query rather than several in once (though just one should have been stopped).
  * </p>
- * 
+ *
  * <p>
  * 	All the following functions are synchronized in order to prevent parallel execution of them by several threads:
  * 	{@link #addUploadedTable(TAPTable, TableIterator)}, {@link #dropUploadedTable(TAPTable)}, {@link #executeQuery(ADQLQuery)},
  * 	{@link #getTAPSchema()} and {@link #setTAPSchema(TAPMetadata)}.
  * </p>
- * 
+ *
  * <p>
  * 	To cancel a query execution the function {@link #cancel(boolean)} must be called. No error is returned by this function in case
  * 	no query is currently executing. When called, the flag {@link #isCancelled()} is set to <code>true</code>. Any potentially long
@@ -95,92 +95,92 @@ import uws.service.log.UWSLog.LogLevel;
  * 	the flag turns <code>true</code>. It should be the case for {@link #addUploadedTable(TAPTable, TableIterator)},
  * 	{@link #executeQuery(ADQLQuery)} and {@link #setTAPSchema(TAPMetadata)}.
  * </p>
- * 
- * 
+ *
+ *
  * <h3>Deal with different DBMS features</h3>
- * 
+ *
  * <p>Update queries are taking into account whether the following features are supported by the DBMS:</p>
  * <ul>
  * 	<li><b>data definition</b>: when not supported, no update operation will be possible.
  * 	                            All corresponding functions will then throw a {@link DBException} ;
  * 	                            only {@link #executeQuery(ADQLQuery)} will be possibly called.</li>
- * 
+ *
  * 	<li><b>transactions</b>: when not supported, no transaction is started or merely used.
  * 	                         It means that in case of update failure, no rollback will be possible
  * 	                         and that already done modification will remain in the database.</li>
- * 
+ *
  * 	<li><b>schemas</b>: when the DBMS does not have the notion of schema (like SQLite), no schema creation or dropping will be obviously processed.
  * 	                    Besides, if not already done, database name of all tables will be prefixed by the schema name.</li>
- * 
+ *
  * 	<li><b>batch updates</b>: when not supported, updates will just be done, "normally, one by one.
  * 	                          In one word, there will be merely no optimization.
  * 	                          Anyway, this feature concerns only the insertions into tables.</li>
- * 
+ *
  * 	<li><b>case sensitivity of identifiers</b>: the case sensitivity of quoted identifier varies from the used DBMS. This {@link DBConnection}
  * 	                                            implementation is able to adapt itself in function of the way identifiers are stored and
  * 	                                            researched in the database. How the case sensitivity is managed by the DBMS is the problem
  * 	                                            of only one function (which can be overwritten if needed): {@link #equals(String, String, boolean)}.</li>
  * </ul>
- * 
+ *
  * <p><i><b>Warning</b>:
  * 	All these features have no impact at all on ADQL query executions ({@link #executeQuery(ADQLQuery)}).
  * </i></p>
- * 
- * 
+ *
+ *
  * <h3>Datatypes</h3>
- * 
+ *
  * <p>
  * 	All datatype conversions done while fetching a query result (via a {@link ResultSet})
  * 	are done exclusively by the returned {@link TableIterator} (so, here {@link ResultSetTableIterator}).
  * </p>
- * 
+ *
  * <p>
  * 	However, datatype conversions done while uploading a table are done here by the function
  * 	{@link #convertTypeToDB(DBType)}. This function uses first the conversion function of the translator
  * 	({@link JDBCTranslator#convertTypeToDB(DBType)}), and then {@link #defaultTypeConversion(DBType)}
  * 	if it fails.
  * </p>
- * 
+ *
  * <p>
  * 	In this default conversion, all typical DBMS datatypes are taken into account, <b>EXCEPT the geometrical types</b>
  * 	(POINT and REGION). That's why it is recommended to use a translator in which the geometrical types are supported
  * 	and managed.
  * </p>
- * 
- * 
+ *
+ *
  * <h3>Fetch size</h3>
- * 
+ *
  * <p>
  * 	The possibility to specify a "fetch size" to the JDBC driver (and more exactly to a {@link Statement}) may reveal
  * 	very helpful when dealing with large datasets. Thus, it is possible to fetch rows by block of a size represented
  * 	by this "fetch size". This is also possible with this {@link DBConnection} thanks to the function {@link #setFetchSize(int)}.
  * </p>
- * 
+ *
  * <p>
  * 	However, some JDBC driver or DBMS may not support this feature. In such case, it is then automatically disabled by
  * 	{@link JDBCConnection} so that any subsequent queries do not attempt to use it again. The {@link #supportsFetchSize}
  * 	is however reset to <code>true</code> when {@link #setFetchSize(int)} is called.
  * </p>
- * 
+ *
  * <p><i>Note 1:
  * 	The "fetch size" feature is used only for SELECT queries executed by {@link #executeQuery(ADQLQuery)}. In all other functions,
  * 	results of SELECT queries are fetched with the default parameter of the JDBC driver and its {@link Statement} implementation.
  * </i></p>
- * 
+ *
  * <p><i>Note 2:
  * 	By default, this feature is disabled. So the default value of the JDBC driver is used.
  * 	To enable it, a simple call to {@link #setFetchSize(int)} is enough, whatever is the given value.
  * </i></p>
- * 
+ *
  * <p><i>Note 3:
  * 	Generally set a fetch size starts a transaction in the database. So, after the result of the fetched query
  * 	is not needed any more, do not forget to call {@link #endQuery()} in order to end the implicitly opened transaction.
  * 	However, generally closing the returned {@link TableIterator} is fully enough (see the sources of
  * 	{@link ResultSetTableIterator#close()} for more details).
  * </i></p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.1 (04/2017)
+ * @version 2.1 (08/2017)
  * @since 2.0
  */
 public class JDBCConnection implements DBConnection {
@@ -214,7 +214,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>If <code>true</code>, this flag indicates that the function {@link #cancel(boolean)} has been called at least once.</p>
-	 * 
+	 *
 	 * <p>{@link #cancel(boolean)} sets this flag to <code>true</code>.</p>
 	 * <p>
 	 * 	All functions executing any kind of query on the database MUST set this flag to <code>false</code> before doing anything
@@ -315,15 +315,15 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>Creates a JDBC connection to the specified database and with the specified JDBC driver.
 	 * This connection is established using the given user name and password.<p>
-	 * 
+	 *
 	 * <p><i><u>note:</u> the JDBC driver is loaded using <pre>Class.forName(driverPath)</pre> and the connection is created with <pre>DriverManager.getConnection(dbUrl, dbUser, dbPassword)</pre>.</i></p>
-	 * 
+	 *
 	 * <p><i><b>Warning:</b>
 	 * 	This constructor really creates a new SQL connection. Creating a SQL connection is time consuming!
 	 * 	That's why it is recommended to use a pool of connections. When doing so, you should use the other constructor of this class
 	 * 	({@link #JDBCConnection(Connection, JDBCTranslator, String, TAPLog)}).
 	 * </i></p>
-	 * 
+	 *
 	 * @param driverPath	Full class name of the JDBC driver.
 	 * @param dbUrl			URL to the database. <i><u>note</u> This URL may not be prefixed by "jdbc:". If not, the prefix will be automatically added.</i>
 	 * @param dbUser		Name of the database user.
@@ -331,7 +331,7 @@ public class JDBCConnection implements DBConnection {
 	 * @param translator	{@link ADQLTranslator} to use in order to get SQL from an ADQL query and to get qualified DB table names.
 	 * @param connID		ID of this connection. <i>note: may be NULL ; but in this case, logs concerning this connection will be more difficult to localize.</i>
 	 * @param logger		Logger to use in case of need. <i>note: may be NULL ; in this case, error will never be logged, but sometimes DBException may be raised.</i>
-	 * 
+	 *
 	 * @throws DBException	If the driver can not be found or if the connection can not merely be created (usually because DB parameters are wrong).
 	 */
 	public JDBCConnection(final String driverPath, final String dbUrl, final String dbUser, final String dbPassword, final JDBCTranslator translator, final String connID, final TAPLog logger) throws DBException{
@@ -340,7 +340,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Create a JDBC connection by wrapping the given connection.
-	 * 
+	 *
 	 * @param conn			Connection to wrap.
 	 * @param translator	{@link ADQLTranslator} to use in order to get SQL from an ADQL query and to get qualified DB table names.
 	 * @param connID		ID of this connection. <i>note: may be NULL ; but in this case, logs concerning this connection will be more difficult to localize.</i>
@@ -364,7 +364,7 @@ public class JDBCConnection implements DBConnection {
 			supportsTransaction = dbMeta.supportsTransactions();
 			supportsBatchUpdates = dbMeta.supportsBatchUpdates();
 			supportsDataDefinition = dbMeta.supportsDataDefinitionAndDataManipulationTransactions();
-			supportsSchema = dbMeta.supportsSchemasInTableDefinitions();
+			supportsSchema = (DBMS_MYSQL.equalsIgnoreCase(dbms) ? true : dbMeta.supportsSchemasInTableDefinitions());
 			lowerCaseUnquoted = dbMeta.storesLowerCaseIdentifiers();
 			upperCaseUnquoted = dbMeta.storesUpperCaseIdentifiers();
 			supportsMixedCaseUnquotedIdentifier = dbMeta.supportsMixedCaseIdentifiers();
@@ -372,6 +372,7 @@ public class JDBCConnection implements DBConnection {
 			mixedCaseQuoted = dbMeta.storesMixedCaseQuotedIdentifiers();
 			upperCaseQuoted = dbMeta.storesUpperCaseQuotedIdentifiers();
 			supportsMixedCaseQuotedIdentifier = dbMeta.supportsMixedCaseQuotedIdentifiers();
+
 		}catch(SQLException se){
 			throw new DBException("Unable to access to one or several DB metadata (url, supportsTransaction, supportsBatchUpdates, supportsDataDefinitionAndDataManipulationTransactions, supportsSchemasInTableDefinitions, storesLowerCaseIdentifiers, storesUpperCaseIdentifiers, supportsMixedCaseIdentifiers, storesLowerCaseQuotedIdentifiers, storesMixedCaseQuotedIdentifiers, storesUpperCaseQuotedIdentifiers and supportsMixedCaseQuotedIdentifiers) from the given Connection!");
 		}
@@ -379,11 +380,11 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Extract the DBMS name from the given database URL.
-	 * 
+	 *
 	 * @param dbUrl	JDBC URL to access the database. <b>This URL must start with "jdbc:" ; otherwise an exception will be thrown.</b>
-	 * 
+	 *
 	 * @return	The DBMS name as found in the given URL.
-	 * 
+	 *
 	 * @throws DBException	If NULL has been given, if the URL is not a JDBC one (starting with "jdbc:") or if the DBMS name is missing.
 	 *
 	 * @deprecated (since 2.1) Should be replaced by <code>{@link java.sql.DatabaseMetaData#getDatabaseProductName()}.toLowerCase()</code>.
@@ -407,16 +408,16 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * Create a {@link Connection} instance using the given database parameters.
 	 * The path of the JDBC driver will be used to load the adequate driver if none is found by default.
-	 * 
+	 *
 	 * @param driverPath	Path to the JDBC driver.
 	 * @param dbUrl			JDBC URL to connect to the database. <i><u>note</u> This URL may not be prefixed by "jdbc:". If not, the prefix will be automatically added.</i>
 	 * @param dbUser		Name of the user to use to connect to the database.
 	 * @param dbPassword	Password of the user to use to connect to the database.
-	 * 
+	 *
 	 * @return	A new DB connection.
-	 * 
+	 *
 	 * @throws DBException	If the driver can not be found or if the connection can not merely be created (usually because DB parameters are wrong).
-	 * 
+	 *
 	 * @see DriverManager#getDriver(String)
 	 * @see Driver#connect(String, Properties)
 	 */
@@ -464,11 +465,11 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Get the JDBC connection wrapped by this {@link JDBCConnection} object.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This is the best way to get the JDBC connection in order to properly close it.
 	 * </i></p>
-	 * 
+	 *
 	 * @return	The wrapped JDBC connection.
 	 */
 	public final Connection getInnerConnection(){
@@ -477,12 +478,12 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Tell whether this {@link JDBCConnection} is already associated with a {@link Statement}.</p>
-	 * 
+	 *
 	 * @return	<code>true</code> if a {@link Statement} instance is already associated with this {@link JDBCConnection}
 	 *        	<code>false</code> otherwise.
-	 * 
+	 *
 	 * @throws SQLException	In case the open/close status of the current {@link Statement} instance can not be checked.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected boolean hasStatement() throws SQLException{
@@ -491,16 +492,16 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Get the only statement associated with this {@link JDBCConnection}.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	If no {@link Statement} is yet existing, one is created, stored in this {@link JDBCConnection} (for further uses)
 	 * 	and then returned.
 	 * </p>
-	 * 
+	 *
 	 * @return	The {@link Statement} instance associated with this {@link JDBCConnection}. <i>Never NULL</i>
-	 * 
+	 *
 	 * @throws SQLException	In case a {@link Statement} can not be created.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected Statement getStatement() throws SQLException{
@@ -512,7 +513,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Close the only statement associated with this {@link JDBCConnection}.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected void closeStatement(){
@@ -522,7 +523,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Cancel (and rollback when possible) the currently running query of this {@link JDBCConnection} instance.</p>
-	 * 
+	 *
 	 * <p><b>Important note:</b>
 	 * 	This function tries canceling the current JDBC statement. This can work only if the JDBC driver and
 	 * 	the DBMS both support this operation. If the statement cancellation fails, the flag {@link #supportsCancel}
@@ -530,7 +531,7 @@ public class JDBCConnection implements DBConnection {
 	 * 	{@link JDBCConnection} does not try any other cancellation attempt. <b>HOWEVER</b> the rollback will
 	 * 	still continue to be performed if the parameter <code>rollback</code> is set to <code>true</code>.
 	 * </p>
-	 * 
+	 *
 	 * <p>
 	 * 	In any case, this function sets anyway the flag {@link #isCancelled()} to <code>true</code> so that after
 	 * 	a DB processing this {@link DBConnection} can interrupt immediately any potentially long running functions
@@ -538,24 +539,24 @@ public class JDBCConnection implements DBConnection {
 	 * 	{@link #setTAPSchema(TAPMetadata)}). When these functions realize this flag is set, they immediately stop
 	 * 	by throwing a {@link DBCancelledException}.
 	 * </p>
-	 * 
+	 *
 	 * <p><i>Note 1:
 	 * 	A failure of a rollback is not considered as a not supported cancellation feature by the JDBC driver or the DBMS.
 	 * 	So if the cancellation succeeds but a rollback fails, a next call of this function will still try canceling the given statement.
 	 * 	In case of a rollback failure, only a WARNING is written in the log file ; no exception is thrown.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 2:
 	 * 	This function is synchronized on the {@link #cancelled} flag.
 	 * 	Thus, it may block until another synchronized block on this same flag is finished.
 	 * </i></p>
-	 * 
+	 *
 	 * @param rollback	<code>true</code> to cancel the statement AND rollback the current connection transaction,
 	 *                	<code>false</code> to just cancel the statement.
-	 * 
+	 *
 	 * @see DBConnection#cancel(boolean)
 	 * @see #cancel(Statement, boolean)
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	@Override
@@ -571,7 +572,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Cancel (and rollback when asked and if possible) the given statement.</p>
-	 * 
+	 *
 	 * <p><b>Important note:</b>
 	 * 	This function tries canceling the current JDBC statement. This can work only if the JDBC driver and
 	 * 	the DBMS both support this operation. If the statement cancellation fails, the flag {@link #supportsCancel}
@@ -579,20 +580,20 @@ public class JDBCConnection implements DBConnection {
 	 * 	{@link JDBCConnection} does not try any other cancellation attempt. <b>HOWEVER</b> the rollback will
 	 * 	still continue to be performed if the parameter <code>rollback</code> is set to <code>true</code>.
 	 * </p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	A failure of a rollback is not considered as a not supported cancellation feature by the JDBC driver or the DBMS.
 	 * 	So if the cancellation succeeds but a rollback fails, a next call of this function will still try canceling the given statement.
 	 * 	In case of a rollback failure, only a WARNING is written in the log file ; no exception is thrown.
 	 * </i></p>
-	 * 
+	 *
 	 * @param stmt		The statement to cancel. <i>Note: if closed or NULL, no exception will be thrown and only a rollback will be attempted if asked in parameter.</i>
 	 * @param rollback	<code>true</code> to cancel the statement AND rollback the current connection transaction,
 	 *                	<code>false</code> to just cancel the statement.
-	 * 
+	 *
 	 * @return	<code>true</code> if the cancellation succeeded (or none was running),
 	 *        	<code>false</code> otherwise (and especially if the "cancel" operation is not supported).
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected boolean cancel(final Statement stmt, final boolean rollback){
@@ -626,15 +627,15 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Tell whether the last query execution has been canceled.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This function is synchronized on the {@link #cancelled} flag.
 	 * 	Thus, it may block until another synchronized block on this same flag is finished.
 	 * </i></p>
-	 * 
+	 *
 	 * @return	<code>true</code> if the last query execution has been cancelled,
 	 *        	<code>false</code> otherwise.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected final boolean isCancelled(){
@@ -645,12 +646,12 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Reset the {@link #cancelled} flag to <code>false</code>.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This function is synchronized on the {@link #cancelled} flag.
 	 * 	Thus, it may block until another synchronized block on this same flag is finished.
 	 * </i></p>
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected final void resetCancel(){
@@ -761,7 +762,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Create a {@link TableIterator} instance which lets reading the given result table.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	The statement currently opened is not closed by this function. Actually, it is still associated with
 	 * 	this {@link JDBCConnection}. However, this latter is provided to the {@link TableIterator} returned by
@@ -769,15 +770,15 @@ public class JDBCConnection implements DBConnection {
 	 * 	will be called. It will then close the {@link ResultSet}, the {@link Statement} and end any opened
 	 * 	transaction (with rollback). See {@link #endQuery()} for more details.
 	 * </i></p>
-	 * 
+	 *
 	 * @param rs				Result of an SQL query.
 	 * @param resultingColumns	Metadata corresponding to each columns of the result.
-	 * 
+	 *
 	 * @return	A {@link TableIterator} instance.
-	 * 
+	 *
 	 * @throws DataReadException	If the metadata (columns count and types) can not be fetched
 	 *                          	or if any other error occurs.
-	 * 
+	 *
 	 * @see ResultSetTableIterator#ResultSetTableIterator(DBConnection, ResultSet, DBColumn[], JDBCTranslator, String)
 	 */
 	protected TableIterator createTableIterator(final ResultSet rs, final DBColumn[] resultingColumns) throws DataReadException{
@@ -794,9 +795,9 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Tell when, compared to the other TAP standard tables, a given standard TAP table should be created.
-	 * 
+	 *
 	 * @param table	Standard TAP table.
-	 * 
+	 *
 	 * @return	An index between 0 and 4 (included) - 0 meaning the first table to create whereas 4 is the last one.
 	 *          -1 is returned if NULL is given in parameter of if the standard table is not taken into account here.
 	 */
@@ -825,21 +826,21 @@ public class JDBCConnection implements DBConnection {
 	 * <p><i>
 	 * 	For instance: if in the database "TAP_SCHEMA" is called "MY_TAP_SCHEMA".
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>IMPORTANT:</b>
 	 * 	TAP_SCHEMA items (i.e. keys in the map) MUST be fully qualified ADQL names (e.g. TAP_SCHEMA.columns.name).
 	 * 	The values MUST be single database names (i.e. no catalogue, schema or table prefix).
 	 * 	Both keys and values are case sensitive.
 	 * </p>
-	 * 
+	 *
 	 * <p><i>Note:</i>
 	 * 	TAP_SCHEMA items keeping the same name in the database than in ADQL do not need to
 	 * 	be listed in the given map.
 	 * </p>
-	 * 
+	 *
 	 * @param mapping	Mapping between ADQL names and DB names.
 	 *               	If <code>null</code>, DB names will be considered equals to the ADQL names.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	public void setDBMapping(final Map<String,String> mapping){
@@ -858,9 +859,9 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Get the standard definition of TAP_SCHEMA with eventually DB names provided by the set mapping (see {@link #setDBMapping(Map)}).
-	 * 
+	 *
 	 * @return	The standard schema as it should be detected in the database.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected TAPSchema getStdSchema(){
@@ -904,12 +905,12 @@ public class JDBCConnection implements DBConnection {
 	 * 	<li>{@link #loadColumns(TAPTable, List, Statement)}</li>
 	 * 	<li>{@link #loadKeys(TAPTable, TAPTable, List, Statement)}</li>
 	 * </ol>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	If schemas are not supported by this DBMS connection, the DB name of all tables will be set to NULL
 	 * 	and the DB name of all tables will be prefixed by the ADQL name of their respective schema.
 	 * </i></p>
-	 * 
+	 *
 	 * @see tap.db.DBConnection#getTAPSchema()
 	 */
 	@Override
@@ -962,19 +963,19 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Load into the given metadata all schemas listed in TAP_SCHEMA.schemas.</p>
-	 * 
+	 *
 	 * <p><i>Note 1:
 	 * 	If schemas are not supported by this DBMS connection, the DB name of the loaded schemas is set to NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 2:
 	 * 	Schema entries are retrieved ordered by ascending schema_name.
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableDef		Definition of the table TAP_SCHEMA.schemas.
 	 * @param metadata		Metadata to fill with all found schemas.
 	 * @param stmt			Statement to use in order to interact with the database.
-	 * 
+	 *
 	 * @throws DBException	If any error occurs while interacting with the database.
 	 */
 	protected void loadSchemas(final TAPTable tableDef, final TAPMetadata metadata, final Statement stmt) throws DBException{
@@ -1034,28 +1035,28 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Load into the corresponding metadata all tables listed in TAP_SCHEMA.tables.</p>
-	 * 
+	 *
 	 * <p><i>Note 1:
 	 * 	Schemas are searched in the given metadata by their ADQL name and case sensitively.
 	 * 	If they can not be found a {@link DBException} is thrown.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 2:
 	 * 	If schemas are not supported by this DBMS connection, the DB name of the loaded
 	 * 	{@link TAPTable}s is prefixed by the ADQL name of their respective schema.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 3:
 	 * 	If the column table_index exists, table entries are retrieved ordered by ascending schema_name, then table_index, and finally table_name.
 	 * 	If this column does not exist, table entries are retrieved ordered by ascending schema_name and then table_name.
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableDef		Definition of the table TAP_SCHEMA.tables.
 	 * @param metadata		Metadata (containing already all schemas listed in TAP_SCHEMA.schemas).
 	 * @param stmt			Statement to use in order to interact with the database.
-	 * 
+	 *
 	 * @return	The complete list of all loaded tables. <i>note: this list is required by {@link #loadColumns(TAPTable, List, Statement)}.</i>
-	 * 
+	 *
 	 * @throws DBException	If a schema can not be found, or if any other error occurs while interacting with the database.
 	 */
 	protected List<TAPTable> loadTables(final TAPTable tableDef, final TAPMetadata metadata, final Statement stmt) throws DBException{
@@ -1149,21 +1150,21 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Load into the corresponding tables all columns listed in TAP_SCHEMA.columns.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Tables are searched in the given list by their ADQL name and case sensitively.
 	 * 	If they can not be found a {@link DBException} is thrown.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 2:
 	 * 	If the column column_index exists, column entries are retrieved ordered by ascending table_name, then column_index, and finally column_name.
 	 * 	If this column does not exist, column entries are retrieved ordered by ascending table_name and then column_name.
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableDef		Definition of the table TAP_SCHEMA.columns.
 	 * @param lstTables		List of all published tables (= all tables listed in TAP_SCHEMA.tables).
 	 * @param stmt			Statement to use in order to interact with the database.
-	 * 
+	 *
 	 * @throws DBException	If a table can not be found, or if any other error occurs while interacting with the database.
 	 */
 	protected void loadColumns(final TAPTable tableDef, final List<TAPTable> lstTables, final Statement stmt) throws DBException{
@@ -1268,22 +1269,22 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Load into the corresponding tables all keys listed in TAP_SCHEMA.keys and detailed in TAP_SCHEMA.key_columns.</p>
-	 * 
+	 *
 	 * <p><i>Note 1:
 	 * 	Tables and columns are searched in the given list by their ADQL name and case sensitively.
 	 * 	If they can not be found a {@link DBException} is thrown.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 2:
 	 * 	Key entries are retrieved ordered by ascending key_id, then from_table and finally target_table.
 	 * 	Key_Column entries are retrieved ordered by ascending from_column and then target_column.
 	 * </i></p>
-	 * 
+	 *
 	 * @param keysDef		Definition of the table TAP_SCHEMA.keys.
 	 * @param keyColumnsDef	Definition of the table TAP_SCHEMA.key_columns.
 	 * @param lstTables		List of all published tables (= all tables listed in TAP_SCHEMA.tables).
 	 * @param stmt			Statement to use in order to interact with the database.
-	 * 
+	 *
 	 * @throws DBException	If a table or a column can not be found, or if any other error occurs while interacting with the database.
 	 */
 	protected void loadKeys(final TAPTable keysDef, final TAPTable keyColumnsDef, final List<TAPTable> lstTables, final Statement stmt) throws DBException{
@@ -1383,12 +1384,12 @@ public class JDBCConnection implements DBConnection {
 	 * 	<li>{@link #commit()} or {@link #rollback()}</li>
 	 * 	<li>{@link #endTransaction()}</li>
 	 * </ol>
-	 * 
+	 *
 	 * <p><i><b>Important note:
 	 * 	If the connection does not support transactions, then there will be merely no transaction.
 	 * 	Consequently, any failure (exception/error) will not clean the partial modifications done by this function.
 	 * </i></p>
-	 * 
+	 *
 	 * @see tap.db.DBConnection#setTAPSchema(tap.metadata.TAPMetadata)
 	 */
 	@Override
@@ -1454,33 +1455,33 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Merge the definition of TAP_SCHEMA tables given in parameter with the definition provided in the TAP standard.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	The goal is to get in output the list of all standard TAP_SCHEMA tables. But it must take into account the customized
 	 * 	definition given in parameter if there is one. Indeed, if a part of TAP_SCHEMA is not provided, it will be completed here by the
 	 * 	definition provided in the TAP standard. And so, if the whole TAP_SCHEMA is not provided at all, the returned tables will be those
 	 * 	of the IVOA standard.
 	 * </p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	If the TAP_SCHEMA definition is missing or incomplete in the given metadata, it will be added or completed automatically
 	 * 	by this function with the definition provided in the IVOA TAP standard.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Only the standard tables of TAP_SCHEMA are considered. The others are skipped (that's to say: never returned by this function ;
 	 *  however, they will stay in the given metadata).
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	If schemas are not supported by this DBMS connection, the DB name of schemas is set to NULL and
 	 * 	the DB name of tables is prefixed by the schema name.
 	 * </i></p>
-	 * 
+	 *
 	 * @param metadata	Metadata (with or without TAP_SCHEMA schema or some of its table). <i>Must not be NULL</i>
-	 * 
+	 *
 	 * @return	The list of all standard TAP_SCHEMA tables, ordered by creation order (see {@link #getCreationOrder(tap.metadata.TAPMetadata.STDTable)}).
-	 * 
+	 *
 	 * @see TAPMetadata#resolveStdTable(String)
 	 * @see TAPMetadata#getStdSchema(boolean)
 	 * @see TAPMetadata#getStdTable(STDTable)
@@ -1544,15 +1545,15 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>Ensure the TAP_SCHEMA schema exists in the database AND it must especially drop all of its standard tables
 	 * (schemas, tables, columns, keys and key_columns), if they exist.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note</b>:
 	 * 	If TAP_SCHEMA already exists and contains other tables than the standard ones, they will not be dropped and they will stay in place.
 	 * </i></p>
-	 * 
+	 *
 	 * @param stmt			The statement to use in order to interact with the database.
 	 * @param stdTables		List of all standard tables that must be (re-)created.
 	 *                      They will be used just to know the name of the standard tables that should be dropped here.
-	 * 
+	 *
 	 * @throws SQLException	If any error occurs while querying or updating the database.
 	 */
 	protected void resetTAPSchema(final Statement stmt, final TAPTable[] stdTables) throws SQLException{
@@ -1578,19 +1579,19 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Remove/Drop all standard TAP_SCHEMA tables given in parameter.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	To test the existence of tables to drop, {@link DatabaseMetaData#getTables(String, String, String, String[])} is called.
 	 * 	Then the schema and table names are compared with the case sensitivity defined by the translator.
 	 * 	Only tables matching with these comparisons will be dropped.
 	 * </i></p>
-	 * 
+	 *
 	 * @param stdTables	Tables to drop. (they should be provided ordered by their creation order (see {@link #getCreationOrder(STDTable)})).
 	 * @param stmt		Statement to use in order to interact with the database.
 	 * @param dbMeta	Database metadata. Used to list all existing tables.
-	 * 
+	 *
 	 * @throws SQLException	If any error occurs while querying or updating the database.
-	 * 
+	 *
 	 * @see JDBCTranslator#isCaseSensitive(IdentifierField)
 	 */
 	private void dropTAPSchemaTables(final TAPTable[] stdTables, final Statement stmt, final DatabaseMetaData dbMeta) throws SQLException{
@@ -1629,22 +1630,22 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Create the specified standard TAP_SCHEMA tables into the database.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	Only standard TAP_SCHEMA tables (schemas, tables, columns, keys and key_columns) can be created here.
 	 * 	If the given table is not part of the schema TAP_SCHEMA (comparison done on the ADQL name case-sensitively)
 	 * 	and is not a standard TAP_SCHEMA table (comparison done on the ADQL name case-sensitively),
 	 * 	this function will do nothing and will throw an exception.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	An extra column is added in TAP_SCHEMA.schemas, TAP_SCHEMA.tables and TAP_SCHEMA.columns: {@value #DB_NAME_COLUMN}.
 	 * 	This column is particularly used when getting the TAP metadata from the database to alias some schema, table and/or column names in ADQL.
 	 * </i></p>
-	 * 
+	 *
 	 * @param table	Table to create.
 	 * @param stmt	Statement to use in order to interact with the database.
-	 * 
+	 *
 	 * @throws DBException	If the given table is not a standard TAP_SCHEMA table.
 	 * @throws SQLException	If any error occurs while querying or updating the database.
 	 */
@@ -1694,11 +1695,11 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Get the primary key corresponding to the specified table.</p>
-	 * 
+	 *
 	 * <p>If the specified table is not a standard TAP_SCHEMA table, NULL will be returned.</p>
-	 * 
+	 *
 	 * @param tableName	ADQL table name.
-	 * 
+	 *
 	 * @return	The primary key definition (prefixed by a space) corresponding to the specified table (ex: " PRIMARY KEY(schema_name)"),
 	 *          or NULL if the specified table is not a standard TAP_SCHEMA table.
 	 */
@@ -1725,17 +1726,17 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Create the DB indexes corresponding to the given TAP_SCHEMA table.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	Only standard TAP_SCHEMA tables (schemas, tables, columns, keys and key_columns) can be created here.
 	 * 	If the given table is not part of the schema TAP_SCHEMA (comparison done on the ADQL name case-sensitively)
 	 * 	and is not a standard TAP_SCHEMA table (comparison done on the ADQL name case-sensitively),
 	 * 	this function will do nothing and will throw an exception.
 	 * </i></p>
-	 * 
+	 *
 	 * @param table	Table whose indexes must be created here.
 	 * @param stmt	Statement to use in order to interact with the database.
-	 * 
+	 *
 	 * @throws DBCancelledException	If {@link #cancel(boolean)} has been called during the processing,
 	 * @throws DBException			If the given table is not a standard TAP_SCHEMA table.
 	 * @throws SQLException			If any error occurs while querying or updating the database.
@@ -1765,9 +1766,9 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Tell whether the specified column is part of the primary key of its table.
-	 * 
+	 *
 	 * @param adqlName	ADQL name of a column.
-	 * 
+	 *
 	 * @return	<i>true</i> if the specified column is part of the primary key,
 	 *          <i>false</i> otherwise.
 	 */
@@ -1780,7 +1781,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Fill all the standard tables of TAP_SCHEMA (schemas, tables, columns, keys and key_columns).</p>
-	 * 
+	 *
 	 * <p>This function just call the following functions:</p>
 	 * <ol>
 	 * 	<li>{@link #fillSchemas(TAPTable, Iterator)}</li>
@@ -1788,9 +1789,9 @@ public class JDBCConnection implements DBConnection {
 	 * 	<li>{@link #fillColumns(TAPTable, Iterator)}</li>
 	 * 	<li>{@link #fillKeys(TAPTable, TAPTable, Iterator)}</li>
 	 * </ol>
-	 * 
+	 *
 	 * @param meta	All schemas and tables to list inside the TAP_SCHEMA tables.
-	 * 
+	 *
 	 * @throws DBCancelledException	If {@link #cancel(boolean)} has been called during the processing,
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
@@ -1820,17 +1821,17 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Fill the standard table TAP_SCHEMA.schemas with the list of all published schemas.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Batch updates may be done here if its supported by the DBMS connection.
 	 * 	In case of any failure while using this feature, it will be flagged as unsupported and one-by-one updates will be processed.
 	 * </i></p>
-	 * 
+	 *
 	 * @param metaTable	Description of TAP_SCHEMA.schemas.
 	 * @param itSchemas	Iterator over the list of schemas.
-	 * 
+	 *
 	 * @return	Iterator over the full list of all tables (whatever is their schema).
-	 * 
+	 *
 	 * @throws DBCancelledException	If {@link #cancel(boolean)} has been called during the processing,
 	 * @throws DBException	If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException	If any other SQL exception occurs.
@@ -1891,17 +1892,17 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Fill the standard table TAP_SCHEMA.tables with the list of all published tables.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Batch updates may be done here if its supported by the DBMS connection.
 	 * 	In case of any failure while using this feature, it will be flagged as unsupported and one-by-one updates will be processed.
 	 * </i></p>
-	 * 
+	 *
 	 * @param metaTable	Description of TAP_SCHEMA.tables.
 	 * @param itTables	Iterator over the list of tables.
-	 * 
+	 *
 	 * @return	Iterator over the full list of all columns (whatever is their table).
-	 * 
+	 *
 	 * @throws DBCancelledException	If {@link #cancel(boolean)} has been called during the processing,
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
@@ -1967,17 +1968,17 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Fill the standard table TAP_SCHEMA.columns with the list of all published columns.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Batch updates may be done here if its supported by the DBMS connection.
 	 * 	In case of any failure while using this feature, it will be flagged as unsupported and one-by-one updates will be processed.
 	 * </i></p>
-	 * 
+	 *
 	 * @param metaTable	Description of TAP_SCHEMA.columns.
 	 * @param itColumns	Iterator over the list of columns.
-	 * 
+	 *
 	 * @return	Iterator over the full list of all foreign keys.
-	 * 
+	 *
 	 * @throws DBCancelledException	If {@link #cancel(boolean)} has been called during the processing,
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
@@ -2057,16 +2058,16 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Fill the standard tables TAP_SCHEMA.keys and TAP_SCHEMA.key_columns with the list of all published foreign keys.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Batch updates may be done here if its supported by the DBMS connection.
 	 * 	In case of any failure while using this feature, it will be flagged as unsupported and one-by-one updates will be processed.
 	 * </i></p>
-	 * 
+	 *
 	 * @param metaKeys			Description of TAP_SCHEMA.keys.
 	 * @param metaKeyColumns	Description of TAP_SCHEMA.key_columns.
 	 * @param itKeys			Iterator over the list of foreign keys.
-	 * 
+	 *
 	 * @throws DBCancelledException	If {@link #cancel(boolean)} has been called during the processing,
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
@@ -2162,17 +2163,17 @@ public class JDBCConnection implements DBConnection {
 	 * 	Only tables uploaded by users can be created in the database. To ensure that, the schema name of this table MUST be {@link STDSchema#UPLOADSCHEMA} ("TAP_UPLOAD") in ADQL.
 	 * 	If it has another ADQL name, an exception will be thrown. Of course, the DB name of this schema MAY be different.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function may modify the given {@link TAPTable} object if schemas are not supported by this connection.
 	 * 	In this case, this function will prefix the table's DB name by the schema's DB name directly inside the given
 	 * 	{@link TAPTable} object. Then the DB name of the schema will be set to NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	If the upload schema does not already exist in the database, it will be created.
 	 * </i></p>
-	 * 
+	 *
 	 * @see tap.db.DBConnection#addUploadedTable(tap.metadata.TAPTable, tap.data.TableIterator)
 	 * @see #checkUploadedTableDef(TAPTable)
 	 */
@@ -2231,6 +2232,7 @@ public class JDBCConnection implements DBConnection {
 					sqlBuf.append(',');
 			}
 			sqlBuf.append(')');
+
 			// ...execute the update query:
 			stmt.executeUpdate(sqlBuf.toString());
 
@@ -2273,21 +2275,21 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Fill the table uploaded by the user with the given data.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Batch updates may be done here if its supported by the DBMS connection.
 	 * 	In case of any failure while using this feature, it will be flagged as unsupported and one-by-one updates will be processed.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This function proceeds to a formatting of TIMESTAMP and GEOMETRY (point, circle, box, polygon) values.
 	 * </i></p>
-	 * 
+	 *
 	 * @param metaTable	Description of the updated table.
 	 * @param data		Iterator over the rows to insert.
-	 * 
+	 *
 	 * @return	Number of inserted rows.
-	 * 
+	 *
 	 * @throws DBCancelledException	If {@link #cancel(boolean)} has been called during the processing,
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
@@ -2395,18 +2397,18 @@ public class JDBCConnection implements DBConnection {
 	 * 	Only tables uploaded by users can be dropped from the database. To ensure that, the schema name of this table MUST be {@link STDSchema#UPLOADSCHEMA} ("TAP_UPLOAD") in ADQL.
 	 * 	If it has another ADQL name, an exception will be thrown. Of course, the DB name of this schema MAY be different.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function may modify the given {@link TAPTable} object if schemas are not supported by this connection.
 	 * 	In this case, this function will prefix the table's DB name by the schema's DB name directly inside the given
 	 * 	{@link TAPTable} object. Then the DB name of the schema will be set to NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This implementation is able to drop only one uploaded table. So if this function finds more than one table matching to the given one,
 	 * 	an exception will be thrown and no table will be dropped.
 	 * </i></p>
-	 * 
+	 *
 	 * @see tap.db.DBConnection#dropUploadedTable(tap.metadata.TAPTable)
 	 * @see #checkUploadedTableDef(TAPTable)
 	 */
@@ -2454,7 +2456,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Ensures that the given table MUST be inside the upload schema in ADQL.</p>
-	 * 
+	 *
 	 * <p>Thus, the following cases are taken into account:</p>
 	 * <ul>
 	 * 	<li>
@@ -2466,9 +2468,9 @@ public class JDBCConnection implements DBConnection {
 	 * 		inside the given {@link TAPTable} object. Then the DB name of the schema will be set to NULL.
 	 * 	</li>
 	 * </ul>
-	 * 
+	 *
 	 * @param tableDef	Definition of the table to create/drop.
-	 * 
+	 *
 	 * @throws DBException	If the given table is not in a schema
 	 *                    	or if the ADQL name of this schema is not {@link STDSchema#UPLOADSCHEMA} ("TAP_UPLOAD").
 	 */
@@ -2491,17 +2493,17 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Convert the given TAP type into the corresponding DBMS column type.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	This function tries first the type conversion using the translator ({@link JDBCTranslator#convertTypeToDB(DBType)}).
 	 * 	If it fails, a default conversion is done considering all the known types of the following DBMS:
 	 * 	PostgreSQL, SQLite, MySQL, Oracle and JavaDB/Derby.
 	 * </p>
-	 * 
+	 *
 	 * @param type	TAP type to convert.
-	 * 
+	 *
 	 * @return	The corresponding DBMS type.
-	 * 
+	 *
 	 * @see JDBCTranslator#convertTypeToDB(DBType)
 	 * @see #defaultTypeConversion(DBType)
 	 */
@@ -2512,24 +2514,24 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Get the DBMS compatible datatype corresponding to the given column {@link DBType}.</p>
-	 * 
+	 *
 	 * <p><i>Note 1:
 	 * 	This function is able to generate a DB datatype compatible with the currently used DBMS.
 	 * 	In this current implementation, only Postgresql, Oracle, SQLite, MySQL and Java DB/Derby have been considered.
 	 * 	Most of the TAP types have been tested only with Postgresql and SQLite without any problem.
 	 * 	If the DBMS you are using has not been considered, note that this function will return the TAP type expression by default.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 2:
 	 * 	In case the given datatype is NULL or not managed here, the DBMS type corresponding to "VARCHAR" will be returned.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 3:
 	 * 	The special TAP types POINT and REGION are converted into the DBMS type corresponding to "VARCHAR".
 	 * </i></p>
-	 * 
+	 *
 	 * @param datatype	Column TAP type.
-	 * 
+	 *
 	 * @return	The corresponding DB type, or VARCHAR if the given type is not managed or is NULL.
 	 */
 	protected String defaultTypeConversion(DBType datatype){
@@ -2622,19 +2624,19 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Start a transaction.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	Basically, if transactions are supported by this connection, the flag AutoCommit is just turned off.
 	 * 	It will be turned on again when {@link #endTransaction()} is called.
 	 * </p>
-	 * 
+	 *
 	 * <p>If transactions are not supported by this connection, nothing is done.</p>
-	 * 
+	 *
 	 * <p><b><i>Important note:</b>
 	 * 	If any error interrupts the START TRANSACTION operation, transactions will be afterwards considered as not supported by this connection.
 	 * 	So, subsequent call to this function (and any other transaction related function) will never do anything.
 	 * </i></p>
-	 * 
+	 *
 	 * @throws DBException	If it is impossible to start a transaction though transactions are supported by this connection.
 	 *                    	If these are not supported, this error can never be thrown.
 	 */
@@ -2655,19 +2657,19 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Commit the current transaction.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	{@link #startTransaction()} must have been called before. If it's not the case the connection
 	 * 	may throw a {@link SQLException} which will be transformed into a {@link DBException} here.
 	 * </p>
-	 * 
+	 *
 	 * <p>If transactions are not supported by this connection, nothing is done.</p>
-	 * 
+	 *
 	 * <p><b><i>Important note:</b>
 	 * 	If any error interrupts the COMMIT operation, transactions will be afterwards considered as not supported by this connection.
 	 * 	So, subsequent call to this function (and any other transaction related function) will never do anything.
 	 * </i></p>
-	 * 
+	 *
 	 * @throws DBException	If it is impossible to commit a transaction though transactions are supported by this connection..
 	 *                    	If these are not supported, this error can never be thrown.
 	 */
@@ -2689,22 +2691,22 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>Rollback the current transaction.
 	 * The success or the failure of the rollback operation is always logged (except if no logger is available).</p>
-	 * 
+	 *
 	 * <p>
 	 * 	{@link #startTransaction()} must have been called before. If it's not the case the connection
 	 * 	may throw a {@link SQLException} which will be transformed into a {@link DBException} here.
 	 * </p>
-	 * 
+	 *
 	 * <p>If transactions are not supported by this connection, nothing is done.</p>
-	 * 
+	 *
 	 * <p><b><i>Important note:</b>
 	 * 	If any error interrupts the ROLLBACK operation, transactions will considered afterwards as not supported by this connection.
 	 * 	So, subsequent call to this function (and any other transaction related function) will never do anything.
 	 * </i></p>
-	 * 
+	 *
 	 * @throws DBException	If it is impossible to rollback a transaction though transactions are supported by this connection..
 	 *                    	If these are not supported, this error can never be thrown.
-	 * 
+	 *
 	 * @see #rollback(boolean)
 	 */
 	protected final void rollback(){
@@ -2713,25 +2715,25 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Rollback the current transaction.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	{@link #startTransaction()} must have been called before. If it's not the case the connection
 	 * 	may throw a {@link SQLException} which will be transformed into a {@link DBException} here.
 	 * </p>
-	 * 
+	 *
 	 * <p>If transactions are not supported by this connection, nothing is done.</p>
-	 * 
+	 *
 	 * <p><b><i>Important note:</b>
 	 * 	If any error interrupts the ROLLBACK operation, transactions will considered afterwards as not supported by this connection.
 	 * 	So, subsequent call to this function (and any other transaction related function) will never do anything.
 	 * </i></p>
-	 * 
+	 *
 	 * @param log	<code>true</code> to log the success/failure of the rollback operation,
 	 *           	<code>false</code> to be quiet whatever happens.
-	 * 
+	 *
 	 * @throws DBException	If it is impossible to rollback a transaction though transactions are supported by this connection..
 	 *                    	If these are not supported, this error can never be thrown.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected void rollback(final boolean log){
@@ -2751,21 +2753,21 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>End the current transaction.
 	 * The success or the failure of the transaction ending operation is always logged (except if no logger is available).</p>
-	 * 
+	 *
 	 * <p>
 	 * 	Basically, if transactions are supported by this connection, the flag AutoCommit is just turned on.
 	 * </p>
-	 * 
+	 *
 	 * <p>If transactions are not supported by this connection, nothing is done.</p>
-	 * 
+	 *
 	 * <p><b><i>Important note:</b>
 	 * 	If any error interrupts the END TRANSACTION operation, transactions will be afterwards considered as not supported by this connection.
 	 * 	So, subsequent call to this function (and any other transaction related function) will never do anything.
 	 * </i></p>
-	 * 
+	 *
 	 * @throws DBException	If it is impossible to end a transaction though transactions are supported by this connection.
 	 *                    	If these are not supported, this error can never be thrown.
-	 * 
+	 *
 	 * @see #endTransaction(boolean)
 	 */
 	protected final void endTransaction(){
@@ -2774,24 +2776,24 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>End the current transaction.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	Basically, if transactions are supported by this connection, the flag AutoCommit is just turned on.
 	 * </p>
-	 * 
+	 *
 	 * <p>If transactions are not supported by this connection, nothing is done.</p>
-	 * 
+	 *
 	 * <p><b><i>Important note:</b>
 	 * 	If any error interrupts the END TRANSACTION operation, transactions will be afterwards considered as not supported by this connection.
 	 * 	So, subsequent call to this function (and any other transaction related function) will never do anything.
 	 * </i></p>
-	 * 
+	 *
 	 * @param log	<code>true</code> to log the success/failure of the transaction ending operation,
 	 *           	<code>false</code> to be quiet whatever happens.
-	 * 
+	 *
 	 * @throws DBException	If it is impossible to end a transaction though transactions are supported by this connection.
 	 *                    	If these are not supported, this error can never be thrown.
-	 * 
+	 *
 	 * @since 2.1
 	 */
 	protected void endTransaction(final boolean log){
@@ -2810,15 +2812,15 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Close silently the given {@link ResultSet}.</p>
-	 * 
+	 *
 	 * <p>If the given {@link ResultSet} is NULL, nothing (even exception/error) happens.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	If any {@link SQLException} occurs during this operation, it is caught and just logged
 	 * 	(see {@link TAPLog#logDB(uws.service.log.UWSLog.LogLevel, DBConnection, String, String, Throwable)}).
 	 * 	No error is thrown and nothing else is done.
 	 * </p>
-	 * 
+	 *
 	 * @param rs	{@link ResultSet} to close.
 	 */
 	protected final void close(final ResultSet rs){
@@ -2833,28 +2835,28 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Close silently the given {@link Statement}.</p>
-	 * 
+	 *
 	 * <p>If the given {@link Statement} is NULL, nothing (even exception/error) happens.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	The given statement is explicitly canceled by this function before being closed.
 	 * 	Thus the corresponding DBMS process is ensured to be stopped. Of course, this
 	 * 	cancellation is effective only if this operation is supported by the JDBC driver
 	 * 	and the DBMS.
 	 * </p>
-	 * 
+	 *
 	 * <p><b>Important note:</b>
 	 * 	In case of cancellation, <b>NO</b> rollback is performed.
 	 * </p>
-	 * 
+	 *
 	 * <p>
 	 * 	If any {@link SQLException} occurs during this operation, it is caught and just logged
 	 * 	(see {@link TAPLog#logDB(uws.service.log.UWSLog.LogLevel, DBConnection, String, String, Throwable)}).
 	 * 	No error is thrown and nothing else is done.
 	 * </p>
-	 * 
+	 *
 	 * @param stmt	{@link Statement} to close.
-	 * 
+	 *
 	 * @see #cancel(Statement, boolean)
 	 */
 	protected final void close(final Statement stmt){
@@ -2871,21 +2873,21 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Transform the given column value in a boolean value.</p>
-	 * 
+	 *
 	 * <p>The following cases are taken into account in function of the given value's type:</p>
 	 * <ul>
 	 * 	<li><b>NULL</b>: <i>false</i> is always returned.</li>
-	 * 
+	 *
 	 * 	<li><b>{@link Boolean}</b>: the boolean value is returned as provided (but casted in boolean).</li>
-	 * 
+	 *
 	 * 	<li><b>{@link Integer}</b>: <i>true</i> is returned only if the integer value is strictly greater than 0, otherwise <i>false</i> is returned.</li>
-	 * 
+	 *
 	 * 	<li><b>Other</b>: toString().trim() is first called on this object. Then, an integer value is tried to be extracted from it.
 	 *                    If it succeeds, the previous rule is applied. If it fails, <i>true</i> will be returned only if the string is "t" or "true" (case insensitively).</li>
 	 * </ul>
-	 * 
+	 *
 	 * @param colValue	The column value to transform in boolean.
-	 * 
+	 *
 	 * @return	Its corresponding boolean value.
 	 */
 	protected final boolean toBoolean(final Object colValue){
@@ -2919,9 +2921,9 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * Return NULL if the given column value is an empty string (or it just contains space characters) or NULL.
 	 * Otherwise the given string is returned as provided.
-	 * 
+	 *
 	 * @param dbValue	Value to nullify if needed.
-	 * 
+	 *
 	 * @return	NULL if the given string is NULL or empty, otherwise the given value.
 	 */
 	protected final String nullifyIfNeeded(final String dbValue){
@@ -2930,10 +2932,10 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Search a {@link TAPTable} instance whose the ADQL name matches (case sensitively) to the given one.
-	 * 
+	 *
 	 * @param tableName	ADQL name of the table to search.
 	 * @param itTables	Iterator over the set of tables in which the research must be done.
-	 * 
+	 *
 	 * @return	The found table, or NULL if not found.
 	 */
 	private TAPTable searchTable(String tableName, final Iterator<TAPTable> itTables){
@@ -2966,29 +2968,29 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>Tell whether the specified schema exists in the database.
 	 * 	To do so, it is using the given {@link DatabaseMetaData} object to query the database and list all existing schemas.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This function is completely useless if the connection is not supporting schemas.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Test on the schema name is done considering the case sensitivity indicated by the translator
 	 * 	(see {@link JDBCTranslator#isCaseSensitive(IdentifierField)}).
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This functions is used by {@link #addUploadedTable(TAPTable, TableIterator)} and {@link #resetTAPSchema(Statement, TAPTable[])}.
 	 * </i></p>
-	 * 
+	 *
 	 * @param schemaName	DB name of the schema whose the existence must be checked.
 	 * @param dbMeta		Metadata about the database, and mainly the list of all existing schemas.
-	 * 
+	 *
 	 * @return	<i>true</i> if the specified schema exists, <i>false</i> otherwise.
-	 * 
+	 *
 	 * @throws SQLException	If any error occurs while interrogating the database about existing schema.
 	 */
 	protected boolean isSchemaExisting(String schemaName, final DatabaseMetaData dbMeta) throws SQLException{
-		if (!supportsSchema || schemaName == null || schemaName.length() == 0)
+		if (DBMS_MYSQL.equals(dbms) || !supportsSchema || schemaName == null || schemaName.length() == 0)
 			return true;
 
 		// Determine the case sensitivity to use for the equality test:
@@ -2999,8 +3001,9 @@ public class JDBCConnection implements DBConnection {
 			// List all schemas available and stop when a schema name matches ignoring the case:
 			rs = dbMeta.getSchemas();
 			boolean hasSchema = false;
-			while(!hasSchema && rs.next())
+			while(!hasSchema && rs.next()){
 				hasSchema = equals(rs.getString(1), schemaName, caseSensitive);
+			}
 			return hasSchema;
 		}finally{
 			close(rs);
@@ -3010,28 +3013,28 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>Tell whether the specified table exists in the database.
 	 * 	To do so, it is using the given {@link DatabaseMetaData} object to query the database and list all existing tables.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	If schemas are not supported by this connection but a schema name is even though provided in parameter,
 	 * 	the table name will be prefixed by the schema name.
 	 * 	The research will then be done with NULL as schema name and this prefixed table name.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Test on the schema name is done considering the case sensitivity indicated by the translator
 	 * 	(see {@link JDBCTranslator#isCaseSensitive(IdentifierField)}).
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This function is used by {@link #addUploadedTable(TAPTable, TableIterator)} and {@link #dropUploadedTable(TAPTable)}.
 	 * </i></p>
-	 * 
+	 *
 	 * @param schemaName	DB name of the schema in which the table to search is. <i>If NULL, the table is expected in any schema but ONLY one MUST exist.</i>
 	 * @param tableName		DB name of the table to search.
 	 * @param dbMeta		Metadata about the database, and mainly the list of all existing tables.
-	 * 
+	 *
 	 * @return	<i>true</i> if the specified table exists, <i>false</i> otherwise.
-	 * 
+	 *
 	 * @throws SQLException	If any error occurs while interrogating the database about existing tables.
 	 */
 	protected boolean isTableExisting(String schemaName, String tableName, final DatabaseMetaData dbMeta) throws DBException, SQLException{
@@ -3082,30 +3085,30 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>Tell whether the specified column exists in the specified table of the database.
 	 * 	To do so, it is using the given {@link DatabaseMetaData} object to query the database and list all existing columns.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	If schemas are not supported by this connection but a schema name is even though provided in parameter,
 	 * 	the table name will be prefixed by the schema name.
 	 * 	The research will then be done with NULL as schema name and this prefixed table name.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	Test on the schema name is done considering the case sensitivity indicated by the translator
 	 * 	(see {@link JDBCTranslator#isCaseSensitive(IdentifierField)}).
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This function is used by {@link #loadSchemas(TAPTable, TAPMetadata, Statement)}, {@link #loadTables(TAPTable, TAPMetadata, Statement)}
 	 * 	and {@link #loadColumns(TAPTable, List, Statement)}.
 	 * </i></p>
-	 * 
+	 *
 	 * @param schemaName	DB name of the table schema. <i>MAY BE NULL</i>
 	 * @param tableName		DB name of the table containing the column to search. <i>MAY BE NULL</i>
 	 * @param columnName	DB name of the column to search.
 	 * @param dbMeta		Metadata about the database, and mainly the list of all existing tables.
-	 * 
+	 *
 	 * @return	<i>true</i> if the specified column exists, <i>false</i> otherwise.
-	 * 
+	 *
 	 * @throws SQLException	If any error occurs while interrogating the database about existing columns.
 	 */
 	protected boolean isColumnExisting(String schemaName, String tableName, String columnName, final DatabaseMetaData dbMeta) throws DBException, SQLException{
@@ -3120,11 +3123,11 @@ public class JDBCConnection implements DBConnection {
 		ResultSet rsT = null, rsC = null;
 		try{
 			/* Note:
-			 * 
+			 *
 			 *     The DatabaseMetaData.getColumns(....) function does not work properly
 			 * with the SQLite driver: when all parameters are set to null, meaning all columns of the database
 			 * must be returned, absolutely no rows are selected.
-			 * 
+			 *
 			 *     The solution proposed here, is to first search all (matching) tables, and then for each table get
 			 * all its columns and find the matching one(s).
 			 */
@@ -3178,22 +3181,22 @@ public class JDBCConnection implements DBConnection {
 
 	/*
 	 * <p>Build a table prefix with the given schema name.</p>
-	 * 
+	 *
 	 * <p>By default, this function returns: schemaName + "_".</p>
-	 * 
+	 *
 	 * <p><b>CAUTION:
 	 * 	This function is used only when schemas are not supported by the DBMS connection.
 	 * 	It aims to propose an alternative of the schema notion by prefixing the table name by the schema name.
 	 * </b></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	If the given schema is NULL or is an empty string, an empty string will be returned.
 	 * 	Thus, no prefix will be set....which is very useful when the table name has already been prefixed
 	 * 	(in such case, the DB name of its schema has theoretically set to NULL).
 	 * </i></p>
-	 * 
+	 *
 	 * @param schemaName	(DB) Schema name.
-	 * 
+	 *
 	 * @return	The corresponding table prefix, or "" if the given schema name is an empty string or NULL.
 	 *
 	protected String getTablePrefix(final String schemaName){
@@ -3205,14 +3208,14 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Tell whether the specified table (using its DB name only) is a standard one or not.
-	 * 
+	 *
 	 * @param dbTableName	DB (unqualified) table name.
 	 * @param stdTables		List of all tables to consider as the standard ones.
 	 * @param caseSensitive	Indicate whether the equality test must be done case sensitively or not.
-	 * 
+	 *
 	 * @return	The corresponding {@link STDTable} if the specified table is a standard one,
 	 *        	NULL otherwise.
-	 * 
+	 *
 	 * @see TAPMetadata#resolveStdTable(String)
 	 */
 	protected final STDTable isStdTable(final String dbTableName, final TAPTable[] stdTables, final boolean caseSensitive){
@@ -3227,7 +3230,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>"Execute" the query update. <i>This update must concern ONLY ONE ROW.</i></p>
-	 * 
+	 *
 	 * <p>
 	 * 	Note that the "execute" action will be different in function of whether batch update queries are supported or not by this connection:
 	 * </p>
@@ -3241,12 +3244,12 @@ public class JDBCConnection implements DBConnection {
 	 * 		If <b>they are NOT supported</b>, {@link PreparedStatement#executeUpdate()} will merely be called.
 	 * 	</li>
 	 * </ul>
-	 * 
+	 *
 	 * <p>
 	 *	Before returning, and only if batch update queries are not supported, this function is ensuring that exactly one row has been updated.
 	 *	If it is not the case, a {@link DBException} is thrown.
 	 * </p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	If the function {@link PreparedStatement#addBatch()} fails by throwing an {@link SQLException}, batch updates
 	 * 	will be afterwards considered as not supported by this connection. Besides, if this row is the first one in a batch update (parameter indRow=1),
@@ -3254,10 +3257,10 @@ public class JDBCConnection implements DBConnection {
 	 * 	the error will be logged but also thrown as a {@link DBException}. In both cases, a subsequent call to
 	 * 	{@link #executeBatchUpdates(PreparedStatement, int)} will have obviously no effect.
 	 * </i></p>
-	 * 
+	 *
 	 * @param stmt		{@link PreparedStatement} in which the update query has been prepared.
 	 * @param indRow	Index of the row in the whole update process. It is used only for error management purpose.
-	 * 
+	 *
 	 * @throws SQLException	If {@link PreparedStatement#executeUpdate()} fails.</i>
 	 * @throws DBException	If {@link PreparedStatement#addBatch()} fails and this update does not concern the first row, or if the number of updated rows is different from 1.
 	 */
@@ -3273,7 +3276,7 @@ public class JDBCConnection implements DBConnection {
 				/*
 				 * If the error happens for the first row, it is still possible to insert all rows
 				 * with the non-batch function - executeUpdate().
-				 * 
+				 *
 				 * Otherwise, it is impossible to insert the previous batched rows ; an exception must be thrown
 				 * and must stop the whole TAP_SCHEMA initialization.
 				 */
@@ -3305,26 +3308,26 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * <p>Execute all batched queries.</p>
-	 * 
+	 *
 	 * <p>To do so, {@link PreparedStatement#executeBatch()} and then, if the first was successful, {@link PreparedStatement#clearBatch()} is called.</p>
-	 * 
+	 *
 	 * <p>
 	 *	Before returning, this function is ensuring that exactly the given number of rows has been updated.
 	 *	If it is not the case, a {@link DBException} is thrown.
 	 * </p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	This function has no effect if batch queries are not supported.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	In case {@link PreparedStatement#executeBatch()} fails by throwing an {@link SQLException},
 	 * 	batch update queries will be afterwards considered as not supported by this connection.
 	 * </i></p>
-	 * 
+	 *
 	 * @param stmt		{@link PreparedStatement} in which the update query has been prepared.
 	 * @param nbRows	Number of rows that should be updated.
-	 * 
+	 *
 	 * @throws DBException	If {@link PreparedStatement#executeBatch()} fails, or if the number of updated rows is different from the given one.
 	 */
 	protected final void executeBatchUpdates(final PreparedStatement stmt, int nbRows) throws DBException{
@@ -3366,7 +3369,7 @@ public class JDBCConnection implements DBConnection {
 
 	/**
 	 * Append all items of the iterator inside the given list.
-	 * 
+	 *
 	 * @param lst	List to update.
 	 * @param it	All items to append inside the list.
 	 */
@@ -3378,20 +3381,20 @@ public class JDBCConnection implements DBConnection {
 	/**
 	 * <p>Tell whether the given DB name is equals (case sensitively or not, in function of the given parameter)
 	 * 	to the given name coming from a {@link TAPMetadata} object.</p>
-	 * 
+	 *
 	 * <p>If at least one of the given name is NULL, <i>false</i> is returned.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	The comparison will be done in function of the specified case sensitivity BUT ALSO of the case supported and stored by the DBMS.
 	 * 	For instance, if it has been specified a case insensitivity and that mixed case is not supported by unquoted identifier,
 	 * 	the comparison must be done, surprisingly, by considering the case if unquoted identifiers are stored in lower or upper case.
 	 * 	Thus, this special way to evaluate equality should be as closed as possible to the identifier storage and research policies of the used DBMS.
 	 * </i></p>
-	 * 
+	 *
 	 * @param dbName		Name provided by the database.
 	 * @param metaName		Name provided by a {@link TAPMetadata} object.
 	 * @param caseSensitive	<i>true</i> if the equality test must be done case sensitively, <i>false</i> otherwise.
-	 * 
+	 *
 	 * @return	<i>true</i> if both names are equal, <i>false</i> otherwise.
 	 */
 	protected final boolean equals(final String dbName, final String metaName, final boolean caseSensitive){
-- 
GitLab