diff --git a/build.gradle b/build.gradle
index 9954559ff87a4596adf6a795de9b4ab7a593ec69..4ff3b0ded54db31428a4cb62bcfef0958eb6a392 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,7 +18,7 @@ dependencies {
 
     testCompile 'junit:junit:4.12'
     testCompile 'com.h2database:h2:1.4.193'
-    testCompile fileTree(dir: 'lib', include: 'astroh2-0.3.jar')
+    testCompile fileTree(dir: 'lib', include: 'astroh2-0.4.jar')
     testCompile 'org.slf4j:slf4j-simple:1.7.25'
     
     testRuntime 'simple-jndi:simple-jndi:0.11.4.1'
diff --git a/lib/astroh2-0.3.jar b/lib/astroh2-0.3.jar
deleted file mode 100644
index a79ab71479dcd4a521e9243bd63f5c7bd47911d8..0000000000000000000000000000000000000000
Binary files a/lib/astroh2-0.3.jar and /dev/null differ
diff --git a/lib/astroh2-0.4.jar b/lib/astroh2-0.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..e84fe823837af2b0a9a8954da777f99d460c9f11
Binary files /dev/null and b/lib/astroh2-0.4.jar differ
diff --git a/src/adql/db/DBColumn.java b/src/adql/db/DBColumn.java
index 89f48b6a4f0d763e79463038bc9cdf05b672ea77..07988bfd0830e5c65002c5d233f10f30fceca177 100644
--- a/src/adql/db/DBColumn.java
+++ b/src/adql/db/DBColumn.java
@@ -2,78 +2,91 @@ package adql.db;
 
 /*
  * 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 2011-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ *
+ * Copyright 2011-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
 /**
- * <p>Definition of a valid target column.</p>
- * 
+ * Definition of a valid target column.
+ *
  * <p>
- * 	This column can be used in an ADQL query with its ADQL name ({@link #getADQLName()})
- * 	and corresponds to a real column in the "database" with its DB name ({@link #getDBName()}).
+ * 	This column can be used in an ADQL query with its ADQL name
+ * 	({@link #getADQLName()}) and corresponds to a real column in the "database"
+ * 	with its DB name ({@link #getDBName()}).
  * </p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.4 (07/2016)
+ * @version 2.0 (09/2019)
  */
 public interface DBColumn {
 
 	/**
 	 * Gets the name of this column (without any prefix and double-quotes).
-	 * 
+	 *
 	 * @return	Its ADQL name.
 	 */
 	public String getADQLName();
 
+	/**
+	 * Tell whether the column name used in ADQL queries must be delimited
+	 * (i.e. surrounded by <code>"</code>). In such case, it will be case
+	 * sensitive.
+	 *
+	 * @return	<code>true</code> if the ADQL column name is case sensitive,
+	 *        	<code>false</code> otherwise.
+	 *
+	 * @since 2.0
+	 */
+	public boolean isCaseSensitive();
+
 	/**
 	 * Gets the name of this column in the "database".
-	 * 
+	 *
 	 * @return	Its DB name.
 	 */
 	public String getDBName();
 
 	/**
 	 * <p>Get the type of this column (as closed as possible from the "database" type).</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	The returned type should be as closed as possible from a type listed by the IVOA in the TAP protocol description into the section UPLOAD.
 	 * </i></p>
-	 * 
+	 *
 	 * @return	Its type.
-	 * 
+	 *
 	 * @since 1.3
 	 */
 	public DBType getDatatype();
 
 	/**
 	 * Gets the table which contains this {@link DBColumn}.
-	 * 
+	 *
 	 * @return	Its table or <i>null</i> if no table is specified.
 	 */
 	public DBTable getTable();
 
 	/**
 	 * Makes a copy of this instance of {@link DBColumn}.
-	 * 
+	 *
 	 * @param dbName	Its new DB name.
 	 * @param adqlName	Its new ADQL name.
 	 * @param dbTable	Its new table.
-	 * 
+	 *
 	 * @return			A modified copy of this {@link DBColumn}.
 	 */
 	public DBColumn copy(final String dbName, final String adqlName, final DBTable dbTable);
diff --git a/src/adql/db/DBCommonColumn.java b/src/adql/db/DBCommonColumn.java
index 44c6642ad34a01ddf654ec1d99c018136650d3d5..f86ca9f2d782f5e9efb74f47a17ee1ff9528e1b4 100644
--- a/src/adql/db/DBCommonColumn.java
+++ b/src/adql/db/DBCommonColumn.java
@@ -2,21 +2,22 @@ package adql.db;
 
 /*
  * 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 2014-2015 - Astronomisches Rechen Institut (ARI)
+ *
+ * Copyright 2014-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ *                       Astronomisches Rechen Institut (ARI)
  */
 
 import java.util.ArrayList;
@@ -26,15 +27,19 @@ import adql.db.exception.UnresolvedJoinException;
 import adql.query.ADQLQuery;
 
 /**
- * This is a special column which exists only after a NATURAL JOIN or a JOIN ... USING between two tables.
- * It lets unify several columns of the joined tables in a single column.
- * 
- * Thus, the writer of an ADQL query can use the column name without table prefix (since after the join there will be only one)
- * or with a prefix table of the joined tables. The list of all covered tables is stored in this object and can be extended
- * in case of several JOINs.
- * 
- * @author Gr&eacute;gory Mantelet (ARI) - gmantele@ari.uni-heidelberg.de
- * @version 1.3 (05/2015)
+ * This is a special column which exists only after a NATURAL JOIN or
+ * a JOIN ... USING between two tables. It lets unify several columns of the
+ * joined tables in a single column.
+ *
+ * <p>
+ * 	Thus, the writer of an ADQL query can use the column name without table
+ * 	prefix (since after the join there will be only one) or with a prefix table
+ * 	of the joined tables. The list of all covered tables is stored in this
+ * 	object and can be extended in case of several JOINs.
+ * </p>
+ *
+ * @author Gr&eacute;gory Mantelet (CDS;ARI)
+ * @version 2.0 (09/2019)
  * @since 1.2
  */
 public class DBCommonColumn implements DBColumn {
@@ -44,27 +49,42 @@ public class DBCommonColumn implements DBColumn {
 
 	/**
 	 * Create a column which merges both of the given columns.
-	 * 
-	 * This special {@link DBColumn} implementation is not associated with one table,
-	 * and can be listed in a {@link DBTable} ONLY IF the latter is the result of a sub-query (see {@link ADQLQuery#getResultingColumns()}).
-	 * 
-	 * A column resulting from a tables join is common only to the joined tables. That's why a list of all tables covered
-	 * by this column is created or update at each merge. It can be accessed thanks to {@link #getCoveredTables()}.
-	 * 
-	 * Note: In the case one or both of the columns to join are {@link DBCommonColumn}, the list of their covered tables are also merged.
-	 * 
-	 * @param leftCol	Column of the left join table. May be a {@link DBCommonColumn}.
-	 * @param rightCol	Column of the right join table. May be a {@link DBCommonColumn}.
-	 * 
-	 * @throws UnresolvedJoinException	If the type of the two given columns are not roughly (just testing numeric, string or geometry) compatible.
+	 *
+	 * <p>
+	 * 	This special {@link DBColumn} implementation is not associated with one
+	 * 	table, and can be listed in a {@link DBTable} ONLY IF the latter is the
+	 * 	result of a sub-query (see {@link ADQLQuery#getResultingColumns()}).
+	 * </p>
+	 *
+	 * <p>
+	 * 	A column resulting from a tables join is common only to the joined
+	 * 	tables. That's why a list of all tables covered by this column is
+	 * 	created or update at each merge. It can be accessed thanks to
+	 * 	{@link #getCoveredTables()}.
+	 * </p>
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	In the case one or both of the columns to join are
+	 * 	{@link DBCommonColumn}, the list of their covered tables are also
+	 * 	merged.
+	 * </i></p>
+	 *
+	 * @param leftCol	Column of the left join table.
+	 *               	May be a {@link DBCommonColumn}.
+	 * @param rightCol	Column of the right join table.
+	 *               	May be a {@link DBCommonColumn}.
+	 *
+	 * @throws UnresolvedJoinException	If the type of the two given columns are
+	 *                                	not roughly (just testing numeric,
+	 *                                	string or geometry) compatible.
 	 */
-	public DBCommonColumn(final DBColumn leftCol, final DBColumn rightCol) throws UnresolvedJoinException{
+	public DBCommonColumn(final DBColumn leftCol, final DBColumn rightCol) throws UnresolvedJoinException {
 		// Test whether type of both columns are compatible:
 		if (leftCol.getDatatype() != null && rightCol.getDatatype() != null && !leftCol.getDatatype().isCompatible(rightCol.getDatatype()))
 			throw new UnresolvedJoinException("JOIN impossible: incompatible column types when trying to join the columns " + leftCol.getADQLName() + " (" + leftCol.getDatatype() + ") and " + rightCol.getADQLName() + " (" + rightCol.getDatatype() + ")!");
 
 		// LEFT COLUMN:
-		if (leftCol instanceof DBCommonColumn){
+		if (leftCol instanceof DBCommonColumn) {
 			// set the general column description:
 			generalColumnDesc = ((DBCommonColumn)leftCol).generalColumnDesc;
 
@@ -72,7 +92,7 @@ public class DBCommonColumn implements DBColumn {
 			Iterator<DBTable> it = ((DBCommonColumn)leftCol).getCoveredTables();
 			while(it.hasNext())
 				addCoveredTable(it.next());
-		}else{
+		} else {
 			// set the general column description:
 			generalColumnDesc = leftCol.copy(leftCol.getDBName(), leftCol.getADQLName(), null);
 			// add the table to cover:
@@ -80,12 +100,12 @@ public class DBCommonColumn implements DBColumn {
 		}
 
 		// RIGHT COLUMN:
-		if (rightCol instanceof DBCommonColumn){
+		if (rightCol instanceof DBCommonColumn) {
 			// add all covered tables of the left common column:
 			Iterator<DBTable> it = ((DBCommonColumn)rightCol).getCoveredTables();
 			while(it.hasNext())
 				addCoveredTable(it.next());
-		}else{
+		} else {
 			// add the table to cover:
 			addCoveredTable(rightCol.getTable());
 		}
@@ -94,76 +114,93 @@ public class DBCommonColumn implements DBColumn {
 	/**
 	 * Constructor by copy.
 	 * It returns a copy of this instance of {@link DBCommonColumn}.
-	 * 
-	 * Note: The list of covered tables is NOT deeply copied!
-	 * 
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The list of covered tables is NOT deeply copied!
+	 * </i></p>
+	 *
 	 * @param toCopy	The {@link DBCommonColumn} to copy.
 	 * @param dbName	The new DB name of this {@link DBCommonColumn}.
 	 * @param adqlName	The new ADQL name of this {@link DBCommonColumn}.
 	 */
 	@SuppressWarnings("unchecked")
-	public DBCommonColumn(final DBCommonColumn toCopy, final String dbName, final String adqlName){
+	public DBCommonColumn(final DBCommonColumn toCopy, final String dbName, final String adqlName) {
 		generalColumnDesc = toCopy.generalColumnDesc.copy(dbName, adqlName, null);
 		lstCoveredTables = (ArrayList<DBTable>)toCopy.lstCoveredTables.clone();
 	}
 
 	@Override
-	public final String getADQLName(){
+	public final String getADQLName() {
 		return generalColumnDesc.getADQLName();
 	}
 
 	@Override
-	public final String getDBName(){
+	public final boolean isCaseSensitive() {
+		return generalColumnDesc.isCaseSensitive();
+	}
+
+	@Override
+	public final String getDBName() {
 		return generalColumnDesc.getDBName();
 	}
 
 	@Override
-	public final DBType getDatatype(){
+	public final DBType getDatatype() {
 		return generalColumnDesc.getDatatype();
 	}
 
 	@Override
-	public final DBTable getTable(){
+	public final DBTable getTable() {
 		return null;
 	}
 
 	/**
-	 * Get an iterator over the list of all tables covered by this common column.
-	 * 
+	 * Get an iterator over the list of all tables covered by this common
+	 * column.
+	 *
 	 * @return	Iterator over all covered tables.
 	 */
-	public final Iterator<DBTable> getCoveredTables(){
+	public final Iterator<DBTable> getCoveredTables() {
 		return lstCoveredTables.iterator();
 	}
 
 	/**
 	 * Add a table that this common column must cover from now.
-	 * 
-	 * Warning: no unicity check is never done !
-	 * 
+	 *
+	 * <p><i><b>Warning:</b>
+	 * 	No unicity check is never done!
+	 * </i></p>
+	 *
 	 * @param table	Table to add in the covered tables list.
 	 */
-	protected void addCoveredTable(final DBTable table){
+	protected void addCoveredTable(final DBTable table) {
 		if (table != null)
 			lstCoveredTables.add(table);
 	}
 
 	/**
-	 * WARNING: This copy function does not make a real copy of this DBCommonColumn !
-	 *          It returns a modified copy of the general column description it contains.
-	 * 
-	 * Note: To make a real copy of this DBCommonColumn use the Constructor by copy {@link #DBCommonColumn(DBCommonColumn, String, String)}.
-	 * 
+	 * <p><i><b>WARNING:</b>
+	 * 	This copy function does not make a real copy of this DBCommonColumn!
+	 * 	It returns a modified copy of the general column description it
+	 * 	contains.
+	 * </i></p>
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	To make a real copy of this DBCommonColumn use the Constructor by copy
+	 * 	{@link #DBCommonColumn(DBCommonColumn, String, String)}.
+	 * </i></p>
+	 *
 	 * @param dbName	Its new DB name.
 	 * @param adqlName	Its new ADQL name.
 	 * @param dbTable	Its new DBTable
-	 * 
-	 * @return			A modified copy of the general column description this common column represents.
-	 * 
+	 *
+	 * @return	A modified copy of the general column description this common
+	 *        	column represents.
+	 *
 	 * @see adql.db.DBColumn#copy(java.lang.String, java.lang.String, adql.db.DBTable)
 	 */
 	@Override
-	public DBColumn copy(final String dbName, final String adqlName, final DBTable dbTable){
+	public DBColumn copy(final String dbName, final String adqlName, final DBTable dbTable) {
 		return generalColumnDesc.copy(dbName, adqlName, dbTable);
 	}
 
diff --git a/src/adql/db/DBTable.java b/src/adql/db/DBTable.java
index 9f5c25c1797cc999ada5092d270a81fd35f6cc3b..8ff8dea37d38b85578fefeca7c40bcea2827cc50 100644
--- a/src/adql/db/DBTable.java
+++ b/src/adql/db/DBTable.java
@@ -2,93 +2,106 @@ package adql.db;
 
 /*
  * 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 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ *
+ * Copyright 2012-2019- UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
 /**
- * <p>Definition of a valid target table.</p>
- * 
+ * Definition of a valid target table.
+ *
  * <p>
- * 	This table can be used in an ADQL query with its ADQL name ({@link #getADQLName()})
- * 	and corresponds to a real table in the "database" with its DB name ({@link #getDBName()}).
+ * 	This table can be used in an ADQL query with its ADQL name
+ * 	({@link #getADQLName()}) and corresponds to a real table in the "database"
+ * 	with its DB name ({@link #getDBName()}).
  * </p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.4 (07/2016)
+ * @version 2.0 (09/2019)
  */
 public interface DBTable extends Iterable<DBColumn> {
 
 	/**
 	 * Gets the name of this table (without any prefix and double-quotes).
-	 * 
+	 *
 	 * @return	Its ADQL name.
 	 */
 	public String getADQLName();
 
+	/**
+	 * Tell whether the table name used in ADQL queries must be delimited
+	 * (i.e. surrounded by <code>"</code>). In such case, it will be case
+	 * sensitive.
+	 *
+	 * @return	<code>true</code> if the ADQL table name is case sensitive,
+	 *        	<code>false</code> otherwise.
+	 *
+	 * @since 2.0
+	 */
+	public boolean isCaseSensitive();
+
 	/**
 	 * Gets the name of this table in the "database".
-	 * 
+	 *
 	 * @return	Its DB name.
 	 */
 	public String getDBName();
 
 	/**
 	 * Gets the ADQL name of the schema which contains this table.
-	 * 
+	 *
 	 * @return	ADQL name of its schema.
 	 */
 	public String getADQLSchemaName();
 
 	/**
 	 * Gets the DB name of the schema which contains this table.
-	 * 
+	 *
 	 * @return	DB name of its schema.
 	 */
 	public String getDBSchemaName();
 
 	/**
 	 * Gets the ADQL name of the catalog which contains this table.
-	 * 
+	 *
 	 * @return	ADQL name of its catalog.
 	 */
 	public String getADQLCatalogName();
 
 	/**
 	 * Gets the DB name of the catalog which contains this table.
-	 * 
+	 *
 	 * @return	DB name of its catalog.
 	 */
 	public String getDBCatalogName();
 
 	/**
 	 * Gets the definition of the specified column if it exists in this table.
-	 * 
+	 *
 	 * @param colName		Name of the column <i>(may be the ADQL or DB name depending of the second parameter)</i>.
 	 * @param adqlName		<i>true</i> means the given name is the ADQL name of the column and that the research must be done on the ADQL name of columns,
 	 * 						<i>false</i> means the same thing but with the DB name.
-	 * 
+	 *
 	 * @return				The corresponding column, or <i>null</i> if the specified column had not been found.
 	 */
 	public DBColumn getColumn(String colName, boolean adqlName);
 
 	/**
 	 * <p>Makes a copy of this instance of {@link DBTable}, with the possibility to change the DB and ADQL names.</p>
-	 * 
+	 *
 	 * <p><b>IMPORTANT:</b>
 	 * 	<b>The given DB and ADQL name may be NULL.</b> If NULL, the copy will contain exactly the same full name (DB and/or ADQL).<br/>
 	 * 	<b>And they may be qualified</b> (that's to say: prefixed by the schema name or by the catalog and schema name). It means that it is possible to
@@ -99,14 +112,14 @@ public interface DBTable extends Iterable<DBColumn> {
 	 * 	<li><i>.copy(null, "foo") =></i> a copy with the same full DB name, but with no ADQL catalog and schema name and with an ADQL table name equals to "foo"</li>
 	 * 	<li><i>.copy("schema.table", ) =></i> a copy with the same full ADQL name, but with no DB catalog name, with a DB schema name equals to "schema" and with a DB table name equals to "table"</li>
 	 * </ul>
-	 * 
+	 *
 	 * @param dbName	Its new DB name.
 	 *              	It may be qualified.
 	 *              	It may also be NULL ; if so, the full DB name won't be different in the copy.
 	 * @param adqlName	Its new ADQL name.
 	 *              	It may be qualified.
 	 *              	It may also be NULL ; if so, the full DB name won't be different in the copy.
-	 * 
+	 *
 	 * @return			A modified copy of this {@link DBTable}.
 	 */
 	public DBTable copy(final String dbName, final String adqlName);
diff --git a/src/adql/db/DefaultDBColumn.java b/src/adql/db/DefaultDBColumn.java
index 0336e24b865132c42460295f9ec2452f2eeac28c..f262b6f5d74a148acd00dcb602d96ebf262e8624 100644
--- a/src/adql/db/DefaultDBColumn.java
+++ b/src/adql/db/DefaultDBColumn.java
@@ -2,27 +2,27 @@ package adql.db;
 
 /*
  * 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 2012,2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
 /**
  * Default implementation of {@link DBColumn}.
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
  * @version 1.4 (08/2015)
  */
@@ -39,23 +39,28 @@ public class DefaultDBColumn implements DBColumn {
 	/** Name that this column must have in ADQL queries. */
 	protected String adqlName = null;
 
+	/** Indicate whether the ADQL column name should be considered as case
+	 * sensitive.
+	 * @since 2.0 */
+	protected boolean columnCaseSensitive = false;
+
 	/**
 	 * Builds a default {@link DBColumn} with the given DB name and DB table.
-	 * 
+	 *
 	 * @param dbName	Database column name (it will be also used for the ADQL name).
 	 * 					<b>Only the column name is expected. Contrary to {@link DefaultDBTable},
 	 * 					if a whole column reference is given, no split will be done.</b>
 	 * @param table		DB table which contains this column.
-	 * 
+	 *
 	 * @see #DefaultDBColumn(String, String, DBType, DBTable)
 	 */
-	public DefaultDBColumn(final String dbName, final DBTable table){
+	public DefaultDBColumn(final String dbName, final DBTable table) {
 		this(dbName, dbName, null, table);
 	}
 
 	/**
 	 * Builds a default {@link DBColumn} with the given DB name and DB table.
-	 * 
+	 *
 	 * @param dbName	Database column name (it will be also used for the ADQL name).
 	 * 					<b>Only the column name is expected. Contrary to {@link DefaultDBTable},
 	 * 					if a whole column reference is given, no split will be done.</b>
@@ -64,18 +69,18 @@ public class DefaultDBColumn implements DBColumn {
 	 *            		the type should be considered as unknown. It means that any comparison with
 	 *            		any type will always return 'true'.</i>
 	 * @param table		DB table which contains this column.
-	 * 
+	 *
 	 * @see #DefaultDBColumn(String, String, DBType, DBTable)
-	 * 
+	 *
 	 * @since 1.3
 	 */
-	public DefaultDBColumn(final String dbName, final DBType type, final DBTable table){
+	public DefaultDBColumn(final String dbName, final DBType type, final DBTable table) {
 		this(dbName, dbName, type, table);
 	}
 
 	/**
 	 * Builds a default {@link DBColumn} with the given DB name, DB table and ADQL name.
-	 * 
+	 *
 	 * @param dbName	Database column name.
 	 * 					<b>Only the column name is expected. Contrary to {@link DefaultDBTable},
 	 * 					if a whole column reference is given, no split will be done.</b>
@@ -83,20 +88,20 @@ public class DefaultDBColumn implements DBColumn {
 	 * 					<b>Only the column name is expected. Contrary to {@link DefaultDBTable},
 	 * 					if a whole column reference is given, no split will be done.</b>
 	 * @param table		DB table which contains this column.
-	 * 
+	 *
 	 * @see #DefaultDBColumn(String, String, DBType, DBTable)
 	 */
-	public DefaultDBColumn(final String dbName, final String adqlName, final DBTable table){
+	public DefaultDBColumn(final String dbName, final String adqlName, final DBTable table) {
 		this(dbName, adqlName, null, table);
 	}
 
 	/**
 	 * Builds a default {@link DBColumn} with the given DB name, DB table and ADQL name.
-	 * 
+	 *
 	 * @param dbName	Database column name.
 	 * 					<b>Only the column name is expected. Contrary to {@link DefaultDBTable},
 	 * 					if a whole column reference is given, no split will be done.</b>
-	 *              	<b>REQUIRED parameter: it must be not NULL.</b> 
+	 *              	<b>REQUIRED parameter: it must be not NULL.</b>
 	 * @param adqlName	Column name used in ADQL queries.
 	 * 					<b>Only the column name is expected. Contrary to {@link DefaultDBTable},
 	 * 					if a whole column reference is given, no split will be done.</b>
@@ -106,73 +111,103 @@ public class DefaultDBColumn implements DBColumn {
 	 *            		the type should be considered as unknown. It means that any comparison with
 	 *            		any type will always return 'true'.</i>
 	 * @param table		DB table which contains this column.
-	 * 
+	 *
 	 * @since 1.3
 	 */
-	public DefaultDBColumn(final String dbName, final String adqlName, final DBType type, final DBTable table){
+	public DefaultDBColumn(final String dbName, final String adqlName, final DBType type, final DBTable table) {
 
 		if (dbName == null || dbName.length() == 0)
 			throw new NullPointerException("Missing DB name!");
 
 		this.dbName = dbName;
-		this.adqlName = (adqlName == null) ? dbName : adqlName;
+		setADQLName(adqlName);
 
 		this.type = type;
 		this.table = table;
 	}
 
 	@Override
-	public final String getADQLName(){
+	public final String getADQLName() {
 		return adqlName;
 	}
 
-	public final void setADQLName(final String adqlName){
-		if (adqlName != null)
-			this.adqlName = adqlName;
+	public final void setADQLName(String name) {
+		if (name != null) {
+
+			// Remove leading and trailing space characters:
+			name = name.trim();
+
+			// Detect automatically case sensitivity:
+			boolean caseSensitive = DefaultDBTable.isDelimited(name);
+			if (caseSensitive)
+				name = name.substring(1, name.length() - 1).replaceAll("\"\"", "\"");
+
+			// ONLY if the final name is NOT empty:
+			if (name.trim().length() > 0) {
+				adqlName = name;
+				columnCaseSensitive = caseSensitive;
+			}
+		}
+	}
+
+	@Override
+	public boolean isCaseSensitive() {
+		return columnCaseSensitive;
+	}
+
+	/**
+	 * Change the case sensitivity of the ADQL column name.
+	 *
+	 * @param sensitive	<code>true</code> to consider the current ADQL name as
+	 *                 	case sensitive,
+	 *                 	<code>false</code> otherwise.
+	 */
+	public void setCaseSensitive(final boolean sensitive) {
+		columnCaseSensitive = sensitive;
 	}
 
 	@Override
-	public final DBType getDatatype(){
+	public final DBType getDatatype() {
 		return type;
 	}
 
 	/**
 	 * <p>Set the type of this column.</p>
-	 * 
+	 *
 	 * <p><i>Note 1:
 	 * 	The given type should be as closed as possible from a type listed by the IVOA in the TAP protocol description into the section UPLOAD.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note 2:
 	 * 	there is no default value. Consequently if this parameter is NULL,
 	 * 	the type should be considered as unknown. It means that any comparison with
 	 * 	any type will always return 'true'.
 	 * </i></p>
-	 * 
+	 *
 	 * @param type	New type of this column.
-	 * 
+	 *
 	 * @since 1.3
 	 */
-	public final void setDatatype(final DBType type){
+	public final void setDatatype(final DBType type) {
 		this.type = type;
 	}
 
 	@Override
-	public final String getDBName(){
+	public final String getDBName() {
 		return dbName;
 	}
 
 	@Override
-	public final DBTable getTable(){
+	public final DBTable getTable() {
 		return table;
 	}
 
-	public final void setTable(final DBTable table){
+	public final void setTable(final DBTable table) {
 		this.table = table;
 	}
 
 	@Override
-	public DBColumn copy(final String dbName, final String adqlName, final DBTable dbTable){
+	public DBColumn copy(final String dbName, final String adqlName, final DBTable dbTable) {
 		return new DefaultDBColumn(dbName, adqlName, type, dbTable);
 	}
 
diff --git a/src/adql/db/DefaultDBTable.java b/src/adql/db/DefaultDBTable.java
index 19762a9c4ef943dae965202d8d322ffc4268a99a..fb89c046c08d46a2eb5a314a158fcb607195e92a 100644
--- a/src/adql/db/DefaultDBTable.java
+++ b/src/adql/db/DefaultDBTable.java
@@ -2,21 +2,21 @@ package adql.db;
 
 /*
  * 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 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ *
+ * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -27,163 +27,282 @@ import java.util.Map;
 
 /**
  * Default implementation of {@link DBTable}.
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.4 (08/2015)
+ * @version 2.0 (09/2019)
  */
 public class DefaultDBTable implements DBTable {
 
-	protected String dbCatalogName;
-	protected String dbSchemaName;
+	protected String dbCatalogName = null;
+	protected String dbSchemaName = null;
 	protected String dbName;
 
 	protected String adqlCatalogName = null;
 	protected String adqlSchemaName = null;
 	protected String adqlName = null;
 
-	protected Map<String,DBColumn> columns = new LinkedHashMap<String,DBColumn>();
+	protected boolean tableCaseSensitive = false;
+
+	protected Map<String, DBColumn> columns = new LinkedHashMap<String, DBColumn>();
 
 	/**
-	 * <p>Builds a default {@link DBTable} with the given DB name.</p>
-	 * 
+	 * Builds a default {@link DBTable} with the given DB name.
+	 *
 	 * <p>With this constructor: ADQL name = DB name.</p>
-	 * 
-	 * <p><i><u>Note:</u> The table name can be prefixed by a schema and a catalog: t1 or schema1.t1 or cat1.schema1.t2</i></p>
-	 * 
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The ADQL/DB schema and catalog names are set to NULL.
+	 * </i></p>
+	 *
+	 * <p><i><b>WARNING:</b>
+	 * 	The ADQL table name MUST NOT be qualified (i.e. prefixed by a schema
+	 * 	and/or a catalog)! For instance, <code>t1</code> is ok, but not
+	 * 	<code>schema1.t1</code> or <code>cat1.schema1.t2</code> which won't be
+	 * 	split but instead, considered as the whole ADQL name.
+	 * </i></p>
+	 *
+	 * <p><i><b>Important note:</b>
+	 * 	The ADQL table name can be delimited (i.e. surrounded by double quotes).
+	 * 	In such case, the surrounded name would be considered as case-sensitive.
+	 * </i></p>
+	 *
 	 * @param dbName	Database name (it will be also used as ADQL table name).
-	 * 
+	 *
 	 * @see #DefaultDBTable(String, String)
 	 */
-	public DefaultDBTable(final String dbName){
+	public DefaultDBTable(final String dbName) {
 		this(dbName, null);
 	}
 
 	/**
-	 * <p>Builds a default {@link DBTable} with the given DB and ADQL names.</p>
-	 * 
-	 * <p><i><u>Note:</u> The table names can be prefixed by a schema and a catalog: t1 or schema1.t1 or cat1.schema1.t2</i></p>
-	 * 
+	 * Builds a default {@link DBTable} with the given DB and ADQL names.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The ADQL/DB schema and catalog names are set to NULL.
+	 * </i></p>
+	 *
+	 * <p><i><b>WARNING:</b>
+	 * 	The ADQL table name MUST NOT be qualified (i.e. prefixed by a schema
+	 * 	and/or a catalog)! For instance, <code>t1</code> is ok, but not
+	 * 	<code>schema1.t1</code> or <code>cat1.schema1.t2</code> which won't be
+	 * 	split but instead, considered as the whole ADQL name.
+	 * </i></p>
+	 *
+	 * <p><i><b>Important note:</b>
+	 * 	The ADQL table name can be delimited (i.e. surrounded by double quotes).
+	 * 	In such case, the surrounded name would be considered as case-sensitive.
+	 * </i></p>
+	 *
 	 * @param dbName	Database name.
 	 * @param adqlName	Name used in ADQL queries.
+	 *                	<i>If NULL, dbName will be used instead.</i>
 	 */
-	public DefaultDBTable(final String dbName, final String adqlName){
-		// DB names:
-		String[] names = splitTableName(dbName);
-		if (names[2] == null || names[2].length() == 0)
-			throw new NullPointerException("Missing DB name !");
-		else
-			this.dbName = names[2];
-		this.dbSchemaName = names[1];
-		this.dbCatalogName = names[0];
-
-		// ADQL names:
-		names = splitTableName(adqlName);
-		if (names[2] == null || names[2].length() == 0){
-			this.adqlName = this.dbName;
-			this.adqlSchemaName = this.dbSchemaName;
-			this.adqlCatalogName = this.dbCatalogName;
-		}else{
-			this.adqlName = names[2];
-			this.adqlSchemaName = names[1];
-			this.adqlCatalogName = names[0];
-		}
+	public DefaultDBTable(final String dbName, final String adqlName) {
+		if (dbName == null || dbName.trim().length() == 0)
+			throw new NullPointerException("Missing DB name!");
+		this.dbName = dbName;
+		setADQLName(adqlName);
 	}
 
 	/**
 	 * Builds default {@link DBTable} with a DB catalog, schema and table names.
-	 * 
-	 * @param dbCatName		Database catalog name (it will be also used as ADQL catalog name).
-	 * @param dbSchemName	Database schema name (it will be also used as ADQL schema name).
-	 * @param dbName		Database table name (it will be also used as ADQL table name).
-	 * 
+	 *
+	 * <p><i><b>WARNING:</b>
+	 * 	The ADQL table name MUST NOT be qualified (i.e. prefixed by a schema
+	 * 	and/or a catalog)! For instance, <code>t1</code> is ok, but not
+	 * 	<code>schema1.t1</code> or <code>cat1.schema1.t2</code> which won't be
+	 * 	split but instead, considered as the whole ADQL name.
+	 * </i></p>
+	 *
+	 * <p><i><b>Important note:</b>
+	 * 	The ADQL table name can be delimited (i.e. surrounded by double quotes).
+	 * 	In such case, the surrounded name would be considered as case-sensitive.
+	 * </i></p>
+	 *
+	 * @param dbCatName		Database catalog name (it will be also used as ADQL
+	 *                 		catalog name).
+	 * @param dbSchemaName	Database schema name (it will be also used as ADQL
+	 *                   	schema name).
+	 * @param dbName		Database table name (it will be also used as ADQL
+	 *              		table name).
+	 *                 		<em>MUST NOT be NULL!</em>
+	 *
 	 * @see #DefaultDBTable(String, String, String, String, String, String)
 	 */
-	public DefaultDBTable(final String dbCatName, final String dbSchemName, final String dbName){
-		this(dbCatName, null, dbSchemName, null, dbName, null);
+	public DefaultDBTable(final String dbCatName, final String dbSchemaName, final String dbName) {
+		this(dbCatName, null, dbSchemaName, null, dbName, null);
 	}
 
 	/**
-	 * Builds default {@link DBTable} with the DB and ADQL names for the catalog, schema and table.
-	 * 
-	 * @param dbCatName		Database catalog name.
-	 * @param adqlCatName	Catalog name used in ADQL queries.
-	 *                   	<em>If NULL, it will be set to dbCatName.</em>
-	 * @param dbSchemName	Database schema name.
-	 * @param adqlSchemName	Schema name used in ADQL queries.
-	 *                   	<em>If NULL, it will be set to dbSchemName.</em>
-	 * @param dbName		Database table name.
-	 * @param adqlName		Table name used in ADQL queries.
-	 *                   	<em>If NULL, it will be set to dbName.</em>
+	 * Builds default {@link DBTable} with the DB and ADQL names for the
+	 * catalog, schema and table.
+	 *
+	 * <p><i><b>WARNING:</b>
+	 * 	The ADQL table name MUST NOT be qualified (i.e. prefixed by a schema
+	 * 	and/or a catalog)! For instance, <code>t1</code> is ok, but not
+	 * 	<code>schema1.t1</code> or <code>cat1.schema1.t2</code> which won't be
+	 * 	split but instead, considered as the whole ADQL name.
+	 * </i></p>
+	 *
+	 * <p><i><b>Important note:</b>
+	 * 	The ADQL table name can be delimited (i.e. surrounded by double quotes).
+	 * 	In such case, the surrounded name would be considered as case-sensitive.
+	 * </i></p>
+	 *
+	 * @param dbCatName			Database catalog name.
+	 * @param adqlCatName		Catalog name used in ADQL queries.
+	 *                   		<em>If NULL, it will be set to dbCatName.</em>
+	 * @param dbSchemaName		Database schema name.
+	 * @param adqlSchemaName	Schema name used in ADQL queries.
+	 *                   		<em>If NULL, it will be set to dbSchemName.</em>
+	 * @param dbName			Database table name.
+	 *                 			<em>MUST NOT be NULL!</em>
+	 * @param adqlName			Table name used in ADQL queries.
+	 *                   		<em>If NULL, it will be set to dbName.</em>
 	 */
-	public DefaultDBTable(final String dbCatName, final String adqlCatName, final String dbSchemName, final String adqlSchemName, final String dbName, final String adqlName){
-
-		if (dbName == null || dbName.length() == 0)
-			throw new NullPointerException("Missing DB name !");
+	public DefaultDBTable(final String dbCatName, final String adqlCatName, final String dbSchemaName, final String adqlSchemaName, final String dbName, final String adqlName) {
+		if (dbName == null || dbName.trim().length() == 0)
+			throw new NullPointerException("Missing DB name!");
 
 		this.dbName = dbName;
-		this.adqlName = (adqlName == null) ? dbName : adqlName;
+		setADQLName(adqlName);
 
-		dbSchemaName = dbSchemName;
-		adqlSchemaName = (adqlSchemName == null) ? dbSchemName : adqlSchemName;
+		this.dbSchemaName = dbSchemaName;
+		this.adqlSchemaName = (adqlSchemaName == null) ? dbSchemaName : adqlSchemaName;
 
-		dbCatalogName = dbCatName;
-		adqlCatalogName = (adqlCatName == null) ? dbCatName : adqlCatName;
+		this.dbCatalogName = dbCatName;
+		this.adqlCatalogName = (adqlCatName == null) ? dbCatName : adqlCatName;
 	}
 
 	@Override
-	public final String getDBName(){
+	public final String getDBName() {
 		return dbName;
 	}
 
 	@Override
-	public final String getDBSchemaName(){
+	public final String getDBSchemaName() {
 		return dbSchemaName;
 	}
 
 	@Override
-	public final String getDBCatalogName(){
+	public final String getDBCatalogName() {
 		return dbCatalogName;
 	}
 
 	@Override
-	public final String getADQLName(){
+	public final String getADQLName() {
 		return adqlName;
 	}
 
-	public void setADQLName(final String name){
+	/**
+	 * Change the ADQL name of this table.
+	 *
+	 * <p>
+	 * 	The case sensitivity is automatically set. The table name will be
+	 * 	considered as case sensitive if the given name is surrounded by double
+	 * 	quotes (<code>"</code>). In such case, the table name is stored and then
+	 * 	returned WITHOUT these double quotes.
+	 * </p>
+	 *
+	 * <p><i><b>WARNING:</b>
+	 * 	If the name without the double quotes (and then trimmed) is an empty
+	 * 	string, the ADQL name will be set to the {@link #getDBName()} as such.
+	 * 	Then the case sensitivity will be set to <code>false</code>.
+	 * </i></p>
+	 *
+	 * @param name	New ADQL name of this table.
+	 */
+	public void setADQLName(final String name) {
+		// Set the new table name (only if not NULL, otherwise use the DB name):
 		adqlName = (name != null) ? name : dbName;
+
+		// Detect automatically case sensitivity:
+		if ((tableCaseSensitive = isDelimited(adqlName)))
+			adqlName = adqlName.substring(1, adqlName.length() - 1).replaceAll("\"\"", "\"");
+
+		// If the final name is empty, no case sensitivity and use the DB name:
+		if (adqlName.trim().length() == 0) {
+			adqlName = dbName;
+			tableCaseSensitive = false;
+		}
+	}
+
+	/**
+	 * Tell whether the given identifier is delimited (i.e. within the same pair
+	 * of double quotes - <code>"</code>).
+	 *
+	 * <i>
+	 * <p>The following identifiers ARE delimited:</p>
+	 * <ul>
+	 * 	<li><code>"a"</code></li>
+	 * 	<li><code>" "</code> (string with spaces ; but won't be considered as a
+	 * 	                      valid ADQL name)</li>
+	 * 	<li><code>"foo.bar"</code></li>
+	 * 	<li><code>"foo"".""bar"</code> (with escaped double quotes)</li>
+	 * 	<li><code>""""</code> (idem)</li>
+	 * </ul>
+	 * </i>
+	 *
+	 * <i>
+	 * <p>The following identifiers are NOT considered as delimited:</p>
+	 * <ul>
+	 * 	<li><code>""</code> (empty string)</li>
+	 * 	<li><code>"foo</code> (missing ending double quote)</li>
+	 * 	<li><code>foo"</code> (missing leading double quote)</li>
+	 * 	<li><code>"foo"."bar"</code> (not the same pair of double quotes)</li>
+	 * </ul>
+	 * </i>
+	 *
+	 * @param name	Identifier that may be delimited.
+	 *
+	 * @return	<code>true</code> if the given identifier is delimited,
+	 *        	<code>false</code> otherwise.
+	 *
+	 * @since 2.0
+	 */
+	public static final boolean isDelimited(final String name) {
+		return name != null && name.matches("\"(\"\"|[^\"])*\"");
+	}
+
+	@Override
+	public boolean isCaseSensitive() {
+		return tableCaseSensitive;
+	}
+
+	public void setCaseSensitive(final boolean sensitive) {
+		tableCaseSensitive = sensitive;
 	}
 
 	@Override
-	public final String getADQLSchemaName(){
+	public final String getADQLSchemaName() {
 		return adqlSchemaName;
 	}
 
-	public void setADQLSchemaName(final String name){
+	public void setADQLSchemaName(final String name) {
 		adqlSchemaName = (name != null) ? name : dbSchemaName;
 	}
 
 	@Override
-	public final String getADQLCatalogName(){
+	public final String getADQLCatalogName() {
 		return adqlCatalogName;
 	}
 
-	public void setADQLCatalogName(final String name){
+	public void setADQLCatalogName(final String name) {
 		adqlName = (name != null) ? null : dbName;
 	}
 
 	/**
 	 * <p>Case sensitive !</p>
 	 * <p>Research optimized for researches by ADQL name.</p>
-	 * 
+	 *
 	 * @see adql.db.DBTable#getColumn(java.lang.String, boolean)
 	 */
 	@Override
-	public DBColumn getColumn(String colName, boolean byAdqlName){
+	public DBColumn getColumn(String colName, boolean byAdqlName) {
 		if (byAdqlName)
 			return columns.get(colName);
-		else{
-			for(DBColumn col : columns.values()){
+		else {
+			for(DBColumn col : columns.values()) {
 				if (col.getDBName().equals(colName))
 					return col;
 			}
@@ -191,22 +310,22 @@ public class DefaultDBTable implements DBTable {
 		}
 	}
 
-	public boolean hasColumn(String colName, boolean byAdqlName){
+	public boolean hasColumn(String colName, boolean byAdqlName) {
 		return (getColumn(colName, byAdqlName) != null);
 	}
 
 	@Override
-	public Iterator<DBColumn> iterator(){
+	public Iterator<DBColumn> iterator() {
 		return columns.values().iterator();
 	}
 
-	public void addColumn(DBColumn column){
+	public void addColumn(DBColumn column) {
 		if (column != null)
 			columns.put(column.getADQLName(), column);
 	}
 
-	public void addAllColumns(Collection<DBColumn> colList){
-		if (colList != null){
+	public void addAllColumns(Collection<DBColumn> colList) {
+		if (colList != null) {
 			for(DBColumn column : colList)
 				addColumn(column);
 		}
@@ -214,19 +333,23 @@ public class DefaultDBTable implements DBTable {
 
 	/**
 	 * Splits the given table name in 3 parts: catalog, schema, table.
-	 * 
+	 *
 	 * @param table	The table name to split.
-	 * 
+	 *
 	 * @return	A String array of 3 items: [0]=catalog, [1]=schema, [0]=table.
+	 *
+	 * @deprecated	Since v2.0, the table name is not any more split
+	 *            	automatically.
 	 */
-	public static final String[] splitTableName(final String table){
-		String[] splitRes = new String[]{null,null,null};
+	@Deprecated
+	public static final String[] splitTableName(final String table) {
+		String[] splitRes = new String[]{ null, null, null };
 
 		if (table == null || table.trim().length() == 0)
 			return splitRes;
 
 		String[] names = table.trim().split("\\.");
-		switch(names.length){
+		switch(names.length) {
 			case 1:
 				splitRes[2] = table.trim();
 				break;
@@ -254,38 +377,43 @@ public class DefaultDBTable implements DBTable {
 	/**
 	 * <p>Join the last 3 items of the given string array with a dot ('.').
 	 * These three parts should be: [0]=catalog name, [1]=schema name, [2]=table name.</p>
-	 * 
+	 *
 	 * <p>
 	 * 	If the array contains less than 3 items, all the given items will be though joined.
 	 * 	However, if it contains more than 3 items, only the three last items will be.
 	 * </p>
-	 * 
+	 *
 	 * <p>A null item will be written as an empty string (string of length 0 ; "").</p>
-	 * 
+	 *
 	 * <p>
 	 * 	In the case the first and the third items are not null, but the second is null, the final string will contain in the middle two dots.
 	 * 	Example: if the array is {"cat", NULL, "table"}, then the joined string will be: "cat..table".
 	 * </p>
-	 * 
+	 *
 	 * @param nameParts	String items to join.
-	 * 
+	 *
 	 * @return	A string joining the 3 last string items of the given array,
 	 *        	or an empty string if the given array is NULL.
-	 * 
+	 *
 	 * @since 1.3
+	 *
+	 * @deprecated	Since v2.0, the table name is not any more split
+	 *            	automatically. So, it is not any more needed to join all its
+	 *            	parts.
 	 */
-	public static final String joinTableName(final String[] nameParts){
+	@Deprecated
+	public static final String joinTableName(final String[] nameParts) {
 		if (nameParts == null)
 			return "";
 
 		StringBuffer str = new StringBuffer();
 		boolean empty = true;
-		for(int i = (nameParts.length <= 3) ? 0 : (nameParts.length - 3); i < nameParts.length; i++){
+		for(int i = (nameParts.length <= 3) ? 0 : (nameParts.length - 3); i < nameParts.length; i++) {
 			if (!empty)
 				str.append('.');
 
 			String part = (nameParts[i] == null) ? null : nameParts[i].trim();
-			if (part != null && part.length() > 0){
+			if (part != null && part.length() > 0) {
 				str.append(part);
 				empty = false;
 			}
@@ -294,11 +422,10 @@ public class DefaultDBTable implements DBTable {
 	}
 
 	@Override
-	public DBTable copy(String dbName, String adqlName){
-		dbName = (dbName == null) ? joinTableName(new String[]{dbCatalogName,dbSchemaName,this.dbName}) : dbName;
-		adqlName = (adqlName == null) ? joinTableName(new String[]{adqlCatalogName,adqlSchemaName,this.adqlName}) : adqlName;
-		DefaultDBTable copy = new DefaultDBTable(dbName, adqlName);
-		for(DBColumn col : this){
+	public DBTable copy(String dbName, String adqlName) {
+		DefaultDBTable copy = new DefaultDBTable(dbCatalogName, adqlCatalogName, dbSchemaName, adqlSchemaName, dbName, adqlName);
+		copy.tableCaseSensitive = tableCaseSensitive;
+		for(DBColumn col : this) {
 			if (col instanceof DBCommonColumn)
 				copy.addColumn(new DBCommonColumn((DBCommonColumn)col, col.getDBName(), col.getADQLName()));
 			else
diff --git a/src/tap/db/JDBCConnection.java b/src/tap/db/JDBCConnection.java
index 4e4f17ec235698ea782eca8575803e5898b3771c..6f2ac2fe38acd0edeadcfbdf5de597f7f86dbafd 100644
--- a/src/tap/db/JDBCConnection.java
+++ b/src/tap/db/JDBCConnection.java
@@ -16,7 +16,7 @@ package tap.db;
  * 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-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -65,123 +65,166 @@ import uws.ISO8601Format;
 import uws.service.log.UWSLog.LogLevel;
 
 /**
- * <p>This {@link DBConnection} implementation is theoretically able to deal with any DBMS JDBC connection.</p>
+ * This {@link DBConnection} implementation is theoretically able to deal with
+ * any DBMS JDBC connection.
  *
- * <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.
+ * <p><i><b>Note:</b>
+ * 	"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
- * 	one {@link Statement}. Indeed, only a {@link Statement} has a cancel function able to stop any query execution on the database.
- * 	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).
+ * 	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 one {@link Statement}.
+ * 	Indeed, only a {@link Statement} has a cancel function able to stop any
+ * 	query execution on the database. 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)},
+ * 	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
- * 	running function is checking this flag and may then stop immediately by throwing a {@link DBCancelledException} as soon as
- * 	the flag turns <code>true</code>. It should be the case for {@link #addUploadedTable(TAPTable, TableIterator)},
+ * 	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 running function is checking this
+ * 	flag and may then stop immediately by throwing a
+ * 	{@link DBCancelledException} as soon as 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>
+ * <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>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>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>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>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>
+ * 	<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)}).
+ * 	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}).
+ * 	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.
+ * 	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.
+ * 	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)}.
+ * 	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.
+ * 	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.
+ * <p><i><b>Note 1:</b>
+ * 	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.
+ * <p><i><b>Note 2:</b>
+ * 	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).
+ * <p><i><b>Note 3:</b>
+ * 	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.3 (10/2018)
+ * @version 2.4 (09/2019)
  * @since 2.0
  */
 public class JDBCConnection implements DBConnection {
@@ -341,7 +384,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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{
+	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 {
 		this(createConnection(driverPath, dbUrl, dbUser, dbPassword), translator, connID, logger);
 	}
 
@@ -353,7 +396,7 @@ public class JDBCConnection implements DBConnection {
 	 * @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>
 	 */
-	public JDBCConnection(final Connection conn, final JDBCTranslator translator, final String connID, final TAPLog logger) throws DBException{
+	public JDBCConnection(final Connection conn, final JDBCTranslator translator, final String connID, final TAPLog logger) throws DBException {
 		if (conn == null)
 			throw new NullPointerException("Missing SQL connection! => can not create a JDBCConnection object.");
 		if (translator == null)
@@ -365,7 +408,7 @@ public class JDBCConnection implements DBConnection {
 		this.logger = logger;
 
 		// Set the supporting features' flags + DBMS type:
-		try{
+		try {
 			DatabaseMetaData dbMeta = connection.getMetaData();
 			dbms = (dbMeta.getDatabaseProductName() != null ? dbMeta.getDatabaseProductName().toLowerCase() : null);
 			supportsTransaction = dbMeta.supportsTransactions();
@@ -380,7 +423,7 @@ public class JDBCConnection implements DBConnection {
 			upperCaseQuoted = dbMeta.storesUpperCaseQuotedIdentifiers();
 			supportsMixedCaseQuotedIdentifier = dbMeta.supportsMixedCaseQuotedIdentifiers();
 
-		}catch(SQLException se){
+		} 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!");
 		}
 	}
@@ -397,7 +440,7 @@ public class JDBCConnection implements DBConnection {
 	 * @deprecated (since 2.1) Should be replaced by <code>{@link java.sql.DatabaseMetaData#getDatabaseProductName()}.toLowerCase()</code>.
 	 */
 	@Deprecated
-	protected static final String getDBMSName(String dbUrl) throws DBException{
+	protected static final String getDBMSName(String dbUrl) throws DBException {
 		if (dbUrl == null)
 			throw new DBException("Missing database URL!");
 
@@ -428,31 +471,31 @@ public class JDBCConnection implements DBConnection {
 	 * @see DriverManager#getDriver(String)
 	 * @see Driver#connect(String, Properties)
 	 */
-	private final static Connection createConnection(final String driverPath, final String dbUrl, final String dbUser, final String dbPassword) throws DBException{
+	private final static Connection createConnection(final String driverPath, final String dbUrl, final String dbUser, final String dbPassword) throws DBException {
 		// Normalize the DB URL:
 		String url = dbUrl.startsWith(JDBC_PREFIX) ? dbUrl : (JDBC_PREFIX + dbUrl);
 
 		// Select the JDBDC driver:
 		Driver d;
-		try{
+		try {
 			d = DriverManager.getDriver(url);
-		}catch(SQLException e){
-			try{
+		} catch(SQLException e) {
+			try {
 				// ...load it, if necessary:
 				if (driverPath == null)
 					throw new DBException("Missing JDBC driver path! Since the required JDBC driver is not yet loaded, this path is needed to load it.");
 				Class.forName(driverPath);
 				// ...and try again:
 				d = DriverManager.getDriver(url);
-			}catch(ClassNotFoundException cnfe){
+			} catch(ClassNotFoundException cnfe) {
 				throw new DBException("Impossible to find the JDBC driver \"" + driverPath + "\" !", cnfe);
-			}catch(SQLException se){
+			} catch(SQLException se) {
 				throw new DBException("No suitable JDBC driver found for the database URL \"" + url + "\" and the driver path \"" + driverPath + "\"!", se);
 			}
 		}
 
 		// Build a connection to the specified database:
-		try{
+		try {
 			Properties p = new Properties();
 			if (dbUser != null)
 				p.setProperty("user", dbUser);
@@ -460,13 +503,13 @@ public class JDBCConnection implements DBConnection {
 				p.setProperty("password", dbPassword);
 			Connection con = d.connect(url, p);
 			return con;
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			throw new DBException("Impossible to establish a connection to the database \"" + url + "\"!", se);
 		}
 	}
 
 	@Override
-	public final String getID(){
+	public final String getID() {
 		return ID;
 	}
 
@@ -479,7 +522,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @return	The wrapped JDBC connection.
 	 */
-	public final Connection getInnerConnection(){
+	public final Connection getInnerConnection() {
 		return connection;
 	}
 
@@ -493,7 +536,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected boolean hasStatement() throws SQLException{
+	protected boolean hasStatement() throws SQLException {
 		return (stmt != null && !stmt.isClosed());
 	}
 
@@ -511,7 +554,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected Statement getStatement() throws SQLException{
+	protected Statement getStatement() throws SQLException {
 		if (hasStatement())
 			return stmt;
 		else
@@ -523,7 +566,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected void closeStatement(){
+	protected void closeStatement() {
 		close(stmt);
 		stmt = null;
 	}
@@ -567,8 +610,8 @@ public class JDBCConnection implements DBConnection {
 	 * @since 2.1
 	 */
 	@Override
-	public final void cancel(final boolean rollback){
-		synchronized(cancelled){
+	public final void cancel(final boolean rollback) {
+		synchronized (cancelled) {
 			cancelled = true;
 			boolean effectivelyCancelled = cancel(stmt, rollback);
 			// Log the success of the cancellation:
@@ -603,16 +646,16 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected boolean cancel(final Statement stmt, final boolean rollback){
-		try{
+	protected boolean cancel(final Statement stmt, final boolean rollback) {
+		try {
 			// If the statement is not already closed, cancel its current query execution:
-			if (supportsCancel && stmt != null && !stmt.isClosed()){
+			if (supportsCancel && stmt != null && !stmt.isClosed()) {
 				stmt.cancel();
 				return true;
-			}else
+			} else
 				return false;
 
-		}catch(SQLFeatureNotSupportedException sfnse){
+		} catch(SQLFeatureNotSupportedException sfnse) {
 			// prevent further cancel attempts:
 			supportsCancel = false;
 			// log a warning:
@@ -620,13 +663,13 @@ public class JDBCConnection implements DBConnection {
 				logger.logDB(LogLevel.WARNING, this, "CANCEL", "This JDBC driver does not support Statement.cancel(). No further cancel attempt will be performed with this JDBCConnection instance.", sfnse);
 			return false;
 
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (logger != null)
 				logger.logDB(LogLevel.ERROR, this, "CANCEL", "Abortion of the current query apparently fails! The query may still run on the database server.", se);
 			return false;
 		}
 		// Whatever happens, rollback all executed operations (only if rollback=true and if in a transaction ; that's to say if AutoCommit = false):
-		finally{
+		finally {
 			if (rollback && supportsTransaction)
 				rollback((stmt != null && stmt == this.stmt));
 		}
@@ -645,8 +688,8 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected final boolean isCancelled(){
-		synchronized(cancelled){
+	protected final boolean isCancelled() {
+		synchronized (cancelled) {
 			return cancelled;
 		}
 	}
@@ -661,14 +704,14 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected final void resetCancel(){
-		synchronized(cancelled){
+	protected final void resetCancel() {
+		synchronized (cancelled) {
 			cancelled = false;
 		}
 	}
 
 	@Override
-	public void endQuery(){
+	public void endQuery() {
 		// Cancel the last query processing, if still running:
 		cancel(stmt, false);  // note: this function is called instead of cancel(false) in order to avoid a log message about the cancellation operation result.
 		// Close the statement, if still opened:
@@ -683,24 +726,24 @@ public class JDBCConnection implements DBConnection {
 	/* INTERROGATION METHODS */
 	/* ********************* */
 	@Override
-	public synchronized TableIterator executeQuery(final ADQLQuery adqlQuery) throws DBException{
+	public synchronized TableIterator executeQuery(final ADQLQuery adqlQuery) throws DBException {
 		// Starting of new query execution => disable the cancel flag:
 		resetCancel();
 
 		String sql = null;
 		ResultSet result = null;
-		try{
+		try {
 			// 1. Translate the ADQL query into SQL:
 			if (logger != null)
 				logger.logDB(LogLevel.INFO, this, "TRANSLATE", "Translating ADQL: " + adqlQuery.toADQL().replaceAll("(\t|\r?\n)+", " "), null);
 			sql = translator.translate(adqlQuery);
 
 			// 2. Create the statement and if needed, configure it for the given fetch size:
-			if (supportsTransaction && supportsFetchSize && fetchSize > 0){
-				try{
+			if (supportsTransaction && supportsFetchSize && fetchSize > 0) {
+				try {
 					connection.setAutoCommit(false);
-				}catch(SQLException se){
-					if (!isCancelled()){
+				} catch(SQLException se) {
+					if (!isCancelled()) {
 						supportsFetchSize = false;
 						if (logger != null)
 							logger.logDB(LogLevel.WARNING, this, "RESULT", "Fetch size unsupported!", null);
@@ -716,11 +759,11 @@ public class JDBCConnection implements DBConnection {
 			getStatement();
 
 			// Adjust the fetching size of this statement:
-			if (supportsFetchSize){
-				try{
+			if (supportsFetchSize) {
+				try {
 					stmt.setFetchSize(fetchSize);
-				}catch(SQLException se){
-					if (!isCancelled()){
+				} catch(SQLException se) {
+					if (!isCancelled()) {
 						supportsFetchSize = false;
 						if (logger != null)
 							logger.logDB(LogLevel.WARNING, this, "RESULT", "Fetch size unsupported!", null);
@@ -742,7 +785,7 @@ public class JDBCConnection implements DBConnection {
 				logger.logDB(LogLevel.INFO, this, "RESULT", "Returning result (" + (supportsFetchSize ? "fetch size = " + fetchSize : "all in once") + ").", null);
 			return createTableIterator(result, adqlQuery.getResultingColumns());
 
-		}catch(Exception ex){
+		} catch(Exception ex) {
 			// Close the ResultSet, if one was open:
 			close(result);
 			// End properly the query:
@@ -751,14 +794,14 @@ public class JDBCConnection implements DBConnection {
 			if (ex instanceof DBCancelledException)
 				throw (DBCancelledException)ex;
 			// Otherwise propagate the exception with an appropriate error message:
-			else if (ex instanceof SQLException){
+			else if (ex instanceof SQLException) {
 				/* ...except if the query has been aborted:
 				 * then, it is normal to receive an SQLException: */
 				if (isCancelled())
 					throw new DBCancelledException();
 				else
 					throw new DBException("Unexpected error while executing a SQL query: " + ex.getMessage(), ex);
-			}else if (ex instanceof TranslationException)
+			} else if (ex instanceof TranslationException)
 				throw new DBException("Unexpected error while translating ADQL into SQL: " + ex.getMessage(), ex);
 			else if (ex instanceof DataReadException)
 				throw new DBException("Impossible to read the query result, because: " + ex.getMessage(), ex);
@@ -788,10 +831,10 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @see ResultSetTableIterator#ResultSetTableIterator(DBConnection, ResultSet, DBColumn[], JDBCTranslator, String)
 	 */
-	protected TableIterator createTableIterator(final ResultSet rs, final DBColumn[] resultingColumns) throws DataReadException{
-		try{
+	protected TableIterator createTableIterator(final ResultSet rs, final DBColumn[] resultingColumns) throws DataReadException {
+		try {
 			return new ResultSetTableIterator(this, rs, resultingColumns, translator, dbms);
-		}catch(Throwable t){
+		} catch(Throwable t) {
 			throw (t instanceof DataReadException) ? (DataReadException)t : new DataReadException(t);
 		}
 	}
@@ -808,11 +851,11 @@ public class JDBCConnection implements DBConnection {
 	 * @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.
 	 */
-	protected int getCreationOrder(final STDTable table){
+	protected int getCreationOrder(final STDTable table) {
 		if (table == null)
 			return -1;
 
-		switch(table){
+		switch(table) {
 			case SCHEMAS:
 				return 0;
 			case TABLES:
@@ -850,10 +893,10 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	public void setDBMapping(final Map<String, String> mapping){
+	public void setDBMapping(final Map<String, String> mapping) {
 		if (mapping == null)
 			dbMapping = null;
-		else{
+		else {
 			if (dbMapping == null)
 				dbMapping = new HashMap<String, String>(mapping.size());
 			else
@@ -871,23 +914,23 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected TAPSchema getStdSchema(){
+	protected TAPSchema getStdSchema() {
 		TAPSchema tap_schema = TAPMetadata.getStdSchema(supportsSchema);
 
-		if (dbMapping != null){
+		if (dbMapping != null) {
 			// Update the TAP_SCHEMA DB name, if needed:
 			if (dbMapping.containsKey(tap_schema.getADQLName()))
 				tap_schema.setDBName(dbMapping.get(tap_schema.getADQLName()));
 
 			// For each table...
-			for(TAPTable t : tap_schema){
+			for(TAPTable t : tap_schema) {
 				// ...update the table DB name, if needed:
 				if (dbMapping.containsKey(t.getFullName()))
 					t.setDBName(dbMapping.get(t.getFullName()));
 
 				// For each column...
 				String fullName;
-				for(DBColumn c : t){
+				for(DBColumn c : t) {
 					fullName = t.getFullName() + "." + c.getADQLName();
 					// ...update the column DB name, if needed:
 					if (dbMapping.containsKey(fullName))
@@ -922,7 +965,7 @@ public class JDBCConnection implements DBConnection {
 	 * @see tap.db.DBConnection#getTAPSchema()
 	 */
 	@Override
-	public synchronized TAPMetadata getTAPSchema() throws DBException{
+	public synchronized TAPMetadata getTAPSchema() throws DBException {
 		// Starting of new query execution => disable the cancel flag:
 		resetCancel();
 
@@ -933,7 +976,7 @@ public class JDBCConnection implements DBConnection {
 		TAPSchema tap_schema = getStdSchema();
 
 		// LOAD ALL METADATA FROM THE STANDARD TAP TABLES:
-		try{
+		try {
 			// create a common statement for all loading functions:
 			getStatement();
 
@@ -949,7 +992,7 @@ public class JDBCConnection implements DBConnection {
 
 			// load all coordinate systems from TAP_SCHEMA.coosys: [non standard]
 			Map<String, TAPCoosys> mapCoosys = null;
-			if (isTableExisting(tap_schema.getDBName(), "coosys", stmt.getConnection().getMetaData())){
+			if (isTableExisting(tap_schema.getDBName(), "coosys", stmt.getConnection().getMetaData())) {
 				if (logger != null)
 					logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.coosys.", null);
 				// create the TAP_SCHEMA.coosys table:
@@ -970,11 +1013,11 @@ public class JDBCConnection implements DBConnection {
 				logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.keys and TAP_SCHEMA.key_columns.", null);
 			loadKeys(tap_schema.getTable(STDTable.KEYS.label), tap_schema.getTable(STDTable.KEY_COLUMNS.label), lstTables, stmt);
 
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to create a Statement!", se);
 			throw new DBException("Can not create a Statement!", se);
-		}finally{
+		} finally {
 			cancel(stmt, true); // note: this function is called instead of cancel(true) in order to avoid a log message about the cancellation operation result.
 			closeStatement();
 		}
@@ -999,9 +1042,9 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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{
+	protected void loadSchemas(final TAPTable tableDef, final TAPMetadata metadata, final Statement stmt) throws DBException {
 		ResultSet rs = null;
-		try{
+		try {
 			// Determine whether the dbName column exists:
 			/* note: if the schema notion is not supported by this DBMS, the column "dbname" is ignored. */
 			boolean hasDBName = supportsSchema && isColumnExisting(tableDef.getDBSchemaName(), tableDef.getDBName(), DB_NAME_COLUMN, connection.getMetaData());
@@ -1016,7 +1059,7 @@ public class JDBCConnection implements DBConnection {
 			sqlBuf.append(", ").append(translator.getColumnName(tableDef.getColumn("utype")));
 			if (hasSchemaIndex)
 				sqlBuf.append(", ").append(translator.getColumnName(tableDef.getColumn("schema_index")));
-			if (hasDBName){
+			if (hasDBName) {
 				sqlBuf.append(", ");
 				translator.appendIdentifier(sqlBuf, DB_NAME_COLUMN, IdentifierField.COLUMN);
 			}
@@ -1030,7 +1073,7 @@ public class JDBCConnection implements DBConnection {
 			rs = stmt.executeQuery(sqlBuf.toString());
 
 			// Create all schemas:
-			while(rs.next()){
+			while(rs.next()) {
 				String schemaName = rs.getString(1),
 						description = rs.getString(2), utype = rs.getString(3),
 						dbName = (hasDBName ? (hasSchemaIndex ? rs.getString(5) : rs.getString(4)) : null);
@@ -1049,11 +1092,11 @@ public class JDBCConnection implements DBConnection {
 				// add the new schema inside the given metadata:
 				metadata.addSchema(newSchema);
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load schemas from TAP_SCHEMA.schemas!", se);
 			throw new DBException("Impossible to load schemas from TAP_SCHEMA.schemas!", se);
-		}finally{
+		} finally {
 			close(rs);
 		}
 	}
@@ -1084,9 +1127,9 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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{
+	protected List<TAPTable> loadTables(final TAPTable tableDef, final TAPMetadata metadata, final Statement stmt) throws DBException {
 		ResultSet rs = null;
-		try{
+		try {
 			// Determine whether the dbName column exists:
 			boolean hasDBName = isColumnExisting(tableDef.getDBSchemaName(), tableDef.getDBName(), DB_NAME_COLUMN, connection.getMetaData());
 
@@ -1102,7 +1145,7 @@ public class JDBCConnection implements DBConnection {
 			sqlBuf.append(", ").append(translator.getColumnName(tableDef.getColumn("utype")));
 			if (hasTableIndex)
 				sqlBuf.append(", ").append(translator.getColumnName(tableDef.getColumn("table_index")));
-			if (hasDBName){
+			if (hasDBName) {
 				sqlBuf.append(", ");
 				translator.appendIdentifier(sqlBuf, DB_NAME_COLUMN, IdentifierField.COLUMN);
 			}
@@ -1117,7 +1160,7 @@ public class JDBCConnection implements DBConnection {
 
 			// Create all tables:
 			ArrayList<TAPTable> lstTables = new ArrayList<TAPTable>();
-			while(rs.next()){
+			while(rs.next()) {
 				String schemaName = rs.getString(1),
 						tableName = rs.getString(2), typeStr = rs.getString(3),
 						description = rs.getString(4), utype = rs.getString(5),
@@ -1126,15 +1169,15 @@ public class JDBCConnection implements DBConnection {
 
 				// get the schema:
 				TAPSchema schema = metadata.getSchema(schemaName);
-				if (schema == null){
+				if (schema == null) {
 					if (logger != null)
 						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the schema of the table \"" + tableName + "\": \"" + schemaName + "\"!", null);
 					throw new DBException("Impossible to find the schema of the table \"" + tableName + "\": \"" + schemaName + "\"!");
 				}
 
-				// If the table name is qualified, check its prefix (it must match to the schema name):
+				/*// If the table name is qualified, check its prefix (it must match to the schema name):
 				int endPrefix = tableName.indexOf('.');
-				if (endPrefix >= 0){
+				if (endPrefix >= 0) {
 					if (endPrefix == 0)
 						throw new DBException("Incorrect table name syntax: \"" + tableName + "\"! Missing schema name (before '.').");
 					else if (endPrefix == tableName.length() - 1)
@@ -1143,14 +1186,14 @@ public class JDBCConnection implements DBConnection {
 						throw new DBException("Incorrect schema prefix for the table \"" + tableName.substring(endPrefix + 1) + "\": this table is not in a schema, according to the column \"schema_name\" of TAP_SCHEMA.tables!");
 					else if (!tableName.substring(0, endPrefix).trim().equalsIgnoreCase(schemaName))
 						throw new DBException("Incorrect schema prefix for the table \"" + schemaName + "." + tableName.substring(tableName.indexOf('.') + 1) + "\": " + tableName + "! Mismatch between the schema specified in prefix of the column \"table_name\" and in the column \"schema_name\".");
-				}
+				}*/
 
 				// resolve the table type (if any) ; by default, it will be "table":
 				TableType type = TableType.table;
-				if (typeStr != null){
-					try{
+				if (typeStr != null) {
+					try {
 						type = TableType.valueOf(typeStr.toLowerCase());
-					}catch(IllegalArgumentException iae){
+					} catch(IllegalArgumentException iae) {
 					}
 				}
 
@@ -1160,10 +1203,9 @@ public class JDBCConnection implements DBConnection {
 				newTable.setIndex(tableIndex);
 
 				// force the dbName of TAP_SCHEMA table to be the same as the used one:
-				if (STDSchema.TAPSCHEMA.label.equalsIgnoreCase(schemaName)){
-					String simpleTableName = (endPrefix > 0) ? tableName.substring(endPrefix + 1) : tableName;
-					if (tableDef.getSchema() != null && tableDef.getSchema().getTable(simpleTableName) != null)
-						newTable.setDBName(tableDef.getSchema().getTable(simpleTableName).getDBName());
+				if (STDSchema.TAPSCHEMA.label.equalsIgnoreCase(schemaName)) {
+					if (tableDef.getSchema() != null && tableDef.getSchema().getTable(newTable.getADQLName()) != null)
+						newTable.setDBName(tableDef.getSchema().getTable(newTable.getADQLName()).getDBName());
 				}
 
 				// add the new table inside its corresponding schema:
@@ -1172,11 +1214,11 @@ public class JDBCConnection implements DBConnection {
 			}
 
 			return lstTables;
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load tables from TAP_SCHEMA.tables!", se);
 			throw new DBException("Impossible to load tables from TAP_SCHEMA.tables!", se);
-		}finally{
+		} finally {
 			close(rs);
 		}
 	}
@@ -1195,9 +1237,9 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected Map<String, TAPCoosys> loadCoosys(final TAPTable tableDef, final TAPMetadata metadata, final Statement stmt) throws DBException{
+	protected Map<String, TAPCoosys> loadCoosys(final TAPTable tableDef, final TAPMetadata metadata, final Statement stmt) throws DBException {
 		ResultSet rs = null;
-		try{
+		try {
 			// Build the SQL query:
 			StringBuffer sqlBuf = new StringBuffer("SELECT ");
 			sqlBuf.append(translator.getColumnName(tableDef.getColumn("id")));
@@ -1212,7 +1254,7 @@ public class JDBCConnection implements DBConnection {
 
 			// Create all coosys:
 			HashMap<String, TAPCoosys> mapCoosys = new HashMap<String, TAPCoosys>();
-			while(rs.next()){
+			while(rs.next()) {
 				String coosysId = rs.getString(1), system = rs.getString(2),
 						equinox = rs.getString(3), epoch = rs.getString(4);
 
@@ -1225,11 +1267,11 @@ public class JDBCConnection implements DBConnection {
 			}
 
 			return mapCoosys;
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load coordinate systems from TAP_SCHEMA.coosys!", se);
 			throw new DBException("Impossible to load coordinate systems from TAP_SCHEMA.coosys!", se);
-		}finally{
+		} finally {
 			close(rs);
 		}
 	}
@@ -1257,7 +1299,7 @@ public class JDBCConnection implements DBConnection {
 	 *            	the list of declared coordinate systems.
 	 */
 	@Deprecated
-	protected void loadColumns(final TAPTable tableDef, final List<TAPTable> lstTables, final Statement stmt) throws DBException{
+	protected void loadColumns(final TAPTable tableDef, final List<TAPTable> lstTables, final Statement stmt) throws DBException {
 		loadColumns(tableDef, lstTables, null, stmt);
 	}
 
@@ -1283,9 +1325,9 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected void loadColumns(final TAPTable tableDef, final List<TAPTable> lstTables, final Map<String, TAPCoosys> mapCoosys, final Statement stmt) throws DBException{
+	protected void loadColumns(final TAPTable tableDef, final List<TAPTable> lstTables, final Map<String, TAPCoosys> mapCoosys, final Statement stmt) throws DBException {
 		ResultSet rs = null;
-		try{
+		try {
 			// Determine whether the dbName column exists:
 			boolean hasArraysize = isColumnExisting(tableDef.getDBSchemaName(), tableDef.getDBName(), "arraysize", connection.getMetaData());
 
@@ -1316,11 +1358,11 @@ public class JDBCConnection implements DBConnection {
 			sqlBuf.append(", ").append(translator.getColumnName(tableDef.getColumn("std")));
 			if (hasColumnIndex)
 				sqlBuf.append(", ").append(translator.getColumnName(tableDef.getColumn("column_index")));
-			if (hasDBName){
+			if (hasDBName) {
 				sqlBuf.append(", ");
 				translator.appendIdentifier(sqlBuf, DB_NAME_COLUMN, IdentifierField.COLUMN);
 			}
-			if (hasCoosys){
+			if (hasCoosys) {
 				sqlBuf.append(", ");
 				translator.appendIdentifier(sqlBuf, COOSYS_ID_COLUMN, IdentifierField.COLUMN);
 			}
@@ -1334,7 +1376,7 @@ public class JDBCConnection implements DBConnection {
 			rs = stmt.executeQuery(sqlBuf.toString());
 
 			// Create all tables:
-			while(rs.next()){
+			while(rs.next()) {
 				String tableName = rs.getString(1),
 						columnName = rs.getString(2),
 						description = rs.getString(3), unit = rs.getString(4),
@@ -1349,7 +1391,7 @@ public class JDBCConnection implements DBConnection {
 
 				// get the table:
 				TAPTable table = searchTable(tableName, lstTables.iterator());
-				if (table == null){
+				if (table == null) {
 					if (logger != null)
 						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the table of the column \"" + columnName + "\": \"" + tableName + "\"!", null);
 					throw new DBException("Impossible to find the table of the column \"" + columnName + "\": \"" + tableName + "\"!");
@@ -1358,10 +1400,10 @@ public class JDBCConnection implements DBConnection {
 				// resolve the column type (if any) ; by default, it will be "VARCHAR" if unknown or missing:
 				DBDatatype tapDatatype = null;
 				// ...try to resolve the datatype in function of all datatypes declared by the TAP standard.
-				if (datatype != null){
-					try{
+				if (datatype != null) {
+					try {
 						tapDatatype = DBDatatype.valueOf(datatype.toUpperCase());
-					}catch(IllegalArgumentException iae){
+					} catch(IllegalArgumentException iae) {
 					}
 				}
 				// ...build the column type:
@@ -1380,14 +1422,14 @@ public class JDBCConnection implements DBConnection {
 				newColumn.setIndex(colIndex);
 
 				// set the coordinate system if any is specified:
-				if (hasCoosys){
+				if (hasCoosys) {
 					int indCoosys = 12;
 					if (hasColumnIndex)
 						indCoosys++;
 					if (hasDBName)
 						indCoosys++;
 					String coosysId = rs.getString(indCoosys);
-					if (coosysId != null){
+					if (coosysId != null) {
 						newColumn.setCoosys(mapCoosys.get(coosysId));
 						if (logger != null && newColumn.getCoosys() == null)
 							logger.logDB(LogLevel.WARNING, this, "LOAD_TAP_SCHEMA", "No coordinate system for the column \"" + columnName + "\"! Cause: unknown coordinate system: \"" + coosysId + "\".", null);
@@ -1401,11 +1443,11 @@ public class JDBCConnection implements DBConnection {
 				// add the new column inside its corresponding table:
 				table.addColumn(newColumn);
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load columns from TAP_SCHEMA.columns!", se);
 			throw new DBException("Impossible to load columns from TAP_SCHEMA.columns!", se);
-		}finally{
+		} finally {
 			close(rs);
 		}
 	}
@@ -1430,10 +1472,10 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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{
+	protected void loadKeys(final TAPTable keysDef, final TAPTable keyColumnsDef, final List<TAPTable> lstTables, final Statement stmt) throws DBException {
 		ResultSet rs = null;
 		PreparedStatement keyColumnsStmt = null;
-		try{
+		try {
 			// Prepare the query to get the columns of each key:
 			StringBuffer sqlBuf = new StringBuffer("SELECT ");
 			sqlBuf.append(translator.getColumnName(keyColumnsDef.getColumn("from_column")));
@@ -1457,20 +1499,20 @@ public class JDBCConnection implements DBConnection {
 			rs = stmt.executeQuery(sqlBuf.toString());
 
 			// Create all foreign keys:
-			while(rs.next()){
+			while(rs.next()) {
 				String key_id = rs.getString(1), from_table = rs.getString(2),
 						target_table = rs.getString(3),
 						description = rs.getString(4), utype = rs.getString(5);
 
 				// get the two tables (source and target):
 				TAPTable sourceTable = searchTable(from_table, lstTables.iterator());
-				if (sourceTable == null){
+				if (sourceTable == null) {
 					if (logger != null)
 						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the source table of the foreign key \"" + key_id + "\": \"" + from_table + "\"!", null);
 					throw new DBException("Impossible to find the source table of the foreign key \"" + key_id + "\": \"" + from_table + "\"!");
 				}
 				TAPTable targetTable = searchTable(target_table, lstTables.iterator());
-				if (targetTable == null){
+				if (targetTable == null) {
 					if (logger != null)
 						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the target table of the foreign key \"" + key_id + "\": \"" + target_table + "\"!", null);
 					throw new DBException("Impossible to find the target table of the foreign key \"" + key_id + "\": \"" + target_table + "\"!");
@@ -1479,33 +1521,33 @@ public class JDBCConnection implements DBConnection {
 				// get the list of columns joining the two tables of the foreign key:
 				HashMap<String, String> columns = new HashMap<String, String>();
 				ResultSet rsKeyCols = null;
-				try{
+				try {
 					keyColumnsStmt.setString(1, key_id);
 					rsKeyCols = keyColumnsStmt.executeQuery();
 					while(rsKeyCols.next())
 						columns.put(rsKeyCols.getString(1), rsKeyCols.getString(2));
-				}catch(SQLException se){
+				} catch(SQLException se) {
 					if (!isCancelled() && logger != null)
 						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load key columns from TAP_SCHEMA.key_columns for the foreign key: \"" + key_id + "\"!", se);
 					throw new DBException("Impossible to load key columns from TAP_SCHEMA.key_columns for the foreign key: \"" + key_id + "\"!", se);
-				}finally{
+				} finally {
 					close(rsKeyCols);
 				}
 
 				// create and add the new foreign key inside the source table:
-				try{
+				try {
 					sourceTable.addForeignKey(key_id, targetTable, columns, nullifyIfNeeded(description), nullifyIfNeeded(utype));
-				}catch(Exception ex){
+				} catch(Exception ex) {
 					if ((ex instanceof SQLException && !isCancelled()) && logger != null)
 						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to create the foreign key \"" + key_id + "\" because: " + ex.getMessage(), ex);
 					throw new DBException("Impossible to create the foreign key \"" + key_id + "\" because: " + ex.getMessage(), ex);
 				}
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load columns from TAP_SCHEMA.columns!", se);
 			throw new DBException("Impossible to load columns from TAP_SCHEMA.columns!", se);
-		}finally{
+		} finally {
 			close(rs);
 			close(keyColumnsStmt);
 		}
@@ -1536,11 +1578,11 @@ public class JDBCConnection implements DBConnection {
 	 * @see tap.db.DBConnection#setTAPSchema(tap.metadata.TAPMetadata)
 	 */
 	@Override
-	public synchronized void setTAPSchema(final TAPMetadata metadata) throws DBCancelledException, DBException{
+	public synchronized void setTAPSchema(final TAPMetadata metadata) throws DBCancelledException, DBException {
 		// Starting of new query execution => disable the cancel flag:
 		resetCancel();
 
-		try{
+		try {
 			// A. GET THE DEFINITION OF ALL STANDARD TAP TABLES:
 			TAPTable[] stdTables = mergeTAPSchemaDefs(metadata);
 
@@ -1561,7 +1603,7 @@ public class JDBCConnection implements DBConnection {
 			// 2. Create all standard TAP tables:
 			if (logger != null)
 				logger.logDB(LogLevel.INFO, this, "CREATE_TAP_SCHEMA", "Creating TAP_SCHEMA tables.", null);
-			for(TAPTable table : stdTables){
+			for(TAPTable table : stdTables) {
 				createTAPSchemaTable(table, stmt);
 				if (isCancelled())
 					throw new DBCancelledException();
@@ -1579,10 +1621,10 @@ public class JDBCConnection implements DBConnection {
 				createTAPTableIndexes(table, stmt);
 
 			commit();
-		}catch(DBCancelledException dce){
+		} catch(DBCancelledException dce) {
 			rollback();
 			throw dce;
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "CREATE_TAP_SCHEMA", "Impossible to SET TAP_SCHEMA in DB!", se);
 			rollback();
@@ -1590,7 +1632,7 @@ public class JDBCConnection implements DBConnection {
 				throw new DBCancelledException();
 			else
 				throw new DBException("Impossible to SET TAP_SCHEMA in DB!", se);
-		}finally{
+		} finally {
 			closeStatement();
 			endTransaction();
 		}
@@ -1629,11 +1671,11 @@ public class JDBCConnection implements DBConnection {
 	 * @see TAPMetadata#getStdSchema(boolean)
 	 * @see TAPMetadata#getStdTable(STDTable)
 	 */
-	protected TAPTable[] mergeTAPSchemaDefs(final TAPMetadata metadata){
+	protected TAPTable[] mergeTAPSchemaDefs(final TAPMetadata metadata) {
 		// 1. Get the TAP_SCHEMA schema from the given metadata:
 		TAPSchema tapSchema = null;
 		Iterator<TAPSchema> itSchema = metadata.iterator();
-		while(tapSchema == null && itSchema.hasNext()){
+		while(tapSchema == null && itSchema.hasNext()) {
 			TAPSchema schema = itSchema.next();
 			if (schema.getADQLName().equalsIgnoreCase(STDSchema.TAPSCHEMA.label))
 				tapSchema = schema;
@@ -1641,7 +1683,7 @@ public class JDBCConnection implements DBConnection {
 
 		// 2. Get the provided definition of the standard TAP tables:
 		TAPTable[] customStdTables = new TAPTable[5];
-		if (tapSchema != null){
+		if (tapSchema != null) {
 
 			/* if the schemas are not supported with this DBMS,
 			 * remove its DB name: */
@@ -1650,7 +1692,7 @@ public class JDBCConnection implements DBConnection {
 
 			// retrieve only the standard TAP tables:
 			Iterator<TAPTable> itTable = tapSchema.iterator();
-			while(itTable.hasNext()){
+			while(itTable.hasNext()) {
 				TAPTable table = itTable.next();
 				int indStdTable = getCreationOrder(TAPMetadata.resolveStdTable(table.getADQLName()));
 				if (indStdTable > -1)
@@ -1659,7 +1701,7 @@ public class JDBCConnection implements DBConnection {
 		}
 
 		// 3. Build a common TAPSchema, if needed:
-		if (tapSchema == null){
+		if (tapSchema == null) {
 
 			// build a new TAP_SCHEMA definition based on the standard definition:
 			tapSchema = TAPMetadata.getStdSchema(supportsSchema);
@@ -1670,10 +1712,10 @@ public class JDBCConnection implements DBConnection {
 
 		// 4. Finally, build the join between the standard tables and the custom ones:
 		TAPTable[] stdTables = new TAPTable[]{ TAPMetadata.getStdTable(STDTable.SCHEMAS), TAPMetadata.getStdTable(STDTable.TABLES), TAPMetadata.getStdTable(STDTable.COLUMNS), TAPMetadata.getStdTable(STDTable.KEYS), TAPMetadata.getStdTable(STDTable.KEY_COLUMNS) };
-		for(int i = 0; i < stdTables.length; i++){
+		for(int i = 0; i < stdTables.length; i++) {
 
 			// CASE: no custom definition:
-			if (customStdTables[i] == null){
+			if (customStdTables[i] == null) {
 				// add the table to the fetched or built-in schema:
 				tapSchema.addTable(stdTables[i]);
 			}
@@ -1699,7 +1741,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @throws SQLException	If any error occurs while querying or updating the database.
 	 */
-	protected void resetTAPSchema(final Statement stmt, final TAPTable[] stdTables) throws SQLException{
+	protected void resetTAPSchema(final Statement stmt, final TAPTable[] stdTables) throws SQLException {
 		DatabaseMetaData dbMeta = connection.getMetaData();
 
 		// 1. Get the qualified DB schema name:
@@ -1707,7 +1749,7 @@ public class JDBCConnection implements DBConnection {
 
 		/* 2. Test whether the schema TAP_SCHEMA exists
 		 *    and if it does not, create it: */
-		if (dbSchemaName != null){
+		if (dbSchemaName != null) {
 			// test whether the schema TAP_SCHEMA exists:
 			boolean hasTAPSchema = isSchemaExisting(dbSchemaName, dbMeta);
 
@@ -1737,11 +1779,11 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @see JDBCTranslator#isCaseSensitive(IdentifierField)
 	 */
-	private void dropTAPSchemaTables(final TAPTable[] stdTables, final Statement stmt, final DatabaseMetaData dbMeta) throws SQLException{
+	private void dropTAPSchemaTables(final TAPTable[] stdTables, final Statement stmt, final DatabaseMetaData dbMeta) throws SQLException {
 		String[] stdTablesToDrop = new String[]{ null, null, null, null, null };
 
 		ResultSet rs = null;
-		try{
+		try {
 			// Retrieve only the schema name and determine whether the search should be case sensitive:
 			String tapSchemaName = stdTables[0].getDBSchemaName();
 			boolean schemaCaseSensitive = translator.isCaseSensitive(IdentifierField.SCHEMA);
@@ -1749,23 +1791,23 @@ public class JDBCConnection implements DBConnection {
 
 			// Identify which standard TAP tables must be dropped:
 			rs = dbMeta.getTables(null, null, null, null);
-			while(rs.next()){
+			while(rs.next()) {
 				String rsSchema = nullifyIfNeeded(rs.getString(2)),
 						rsTable = rs.getString(3);
-				if (!supportsSchema || (tapSchemaName == null && rsSchema == null) || equals(rsSchema, tapSchemaName, schemaCaseSensitive)){
+				if (!supportsSchema || (tapSchemaName == null && rsSchema == null) || equals(rsSchema, tapSchemaName, schemaCaseSensitive)) {
 					int indStdTable;
 					indStdTable = getCreationOrder(isStdTable(rsTable, stdTables, tableCaseSensitive));
-					if (indStdTable > -1){
+					if (indStdTable > -1) {
 						stdTablesToDrop[indStdTable] = (rsSchema != null ? "\"" + rsSchema + "\"." : "") + "\"" + rsTable + "\"";
 					}
 				}
 			}
-		}finally{
+		} finally {
 			close(rs);
 		}
 
 		// Drop the existing tables (in the reverse order of creation):
-		for(int i = stdTablesToDrop.length - 1; i >= 0; i--){
+		for(int i = stdTablesToDrop.length - 1; i >= 0; i--) {
 			if (stdTablesToDrop[i] != null)
 				stmt.executeUpdate("DROP TABLE " + stdTablesToDrop[i]);
 		}
@@ -1792,7 +1834,7 @@ public class JDBCConnection implements DBConnection {
 	 * @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.
 	 */
-	protected void createTAPSchemaTable(final TAPTable table, final Statement stmt) throws DBException, SQLException{
+	protected void createTAPSchemaTable(final TAPTable table, final Statement stmt) throws DBException, SQLException {
 		// 1. ENSURE THE GIVEN TABLE IS REALLY A TAP_SCHEMA TABLE (according to the ADQL names):
 		if (!table.getADQLSchemaName().equalsIgnoreCase(STDSchema.TAPSCHEMA.label) || TAPMetadata.resolveStdTable(table.getADQLName()) == null)
 			throw new DBException("Forbidden table creation: " + table + " is not a standard table of TAP_SCHEMA!");
@@ -1806,7 +1848,7 @@ public class JDBCConnection implements DBConnection {
 		// b. List all the columns:
 		sql.append('(');
 		Iterator<TAPColumn> it = table.getColumns();
-		while(it.hasNext()){
+		while(it.hasNext()) {
 			TAPColumn col = it.next();
 
 			// column name:
@@ -1846,13 +1888,13 @@ public class JDBCConnection implements DBConnection {
 	 * @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.
 	 */
-	private String getPrimaryKeyDef(final String tableName){
+	private String getPrimaryKeyDef(final String tableName) {
 		STDTable stdTable = TAPMetadata.resolveStdTable(tableName);
 		if (stdTable == null)
 			return null;
 
 		boolean caseSensitive = translator.isCaseSensitive(IdentifierField.COLUMN);
-		switch(stdTable){
+		switch(stdTable) {
 			case SCHEMAS:
 				return " PRIMARY KEY(" + (caseSensitive ? "\"schema_name\"" : "schema_name") + ")";
 			case TABLES:
@@ -1884,7 +1926,7 @@ public class JDBCConnection implements DBConnection {
 	 * @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.
 	 */
-	protected void createTAPTableIndexes(final TAPTable table, final Statement stmt) throws DBCancelledException, DBException, SQLException{
+	protected void createTAPTableIndexes(final TAPTable table, final Statement stmt) throws DBCancelledException, DBException, SQLException {
 		// 1. Ensure the given table is really a TAP_SCHEMA table (according to the ADQL names):
 		if (!table.getADQLSchemaName().equalsIgnoreCase(STDSchema.TAPSCHEMA.label) || TAPMetadata.resolveStdTable(table.getADQLName()) == null)
 			throw new DBException("Forbidden index creation: " + table + " is not a standard table of TAP_SCHEMA!");
@@ -1896,7 +1938,7 @@ public class JDBCConnection implements DBConnection {
 		final String indexNamePrefix = "INDEX_" + ((table.getADQLSchemaName() != null) ? (table.getADQLSchemaName() + "_") : "") + table.getADQLName() + "_";
 
 		Iterator<TAPColumn> it = table.getColumns();
-		while(it.hasNext()){
+		while(it.hasNext()) {
 			TAPColumn col = it.next();
 			// Create an index only for columns that have the 'indexed' flag:
 			if (col.isIndexed() && !isPartOfPrimaryKey(col.getADQLName()))
@@ -1915,7 +1957,7 @@ public class JDBCConnection implements DBConnection {
 	 * @return	<i>true</i> if the specified column is part of the primary key,
 	 *          <i>false</i> otherwise.
 	 */
-	private boolean isPartOfPrimaryKey(final String adqlName){
+	private boolean isPartOfPrimaryKey(final String adqlName) {
 		if (adqlName == null)
 			return false;
 		else
@@ -1939,7 +1981,7 @@ public class JDBCConnection implements DBConnection {
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
 	 */
-	protected void fillTAPSchema(final TAPMetadata meta) throws SQLException, DBCancelledException, DBException{
+	protected void fillTAPSchema(final TAPMetadata meta) throws SQLException, DBCancelledException, DBException {
 		TAPTable metaTable;
 
 		// 1. Fill SCHEMAS:
@@ -1979,7 +2021,7 @@ public class JDBCConnection implements DBConnection {
 	 * @throws DBException	If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException	If any other SQL exception occurs.
 	 */
-	private Iterator<TAPTable> fillSchemas(final TAPTable metaTable, final Iterator<TAPSchema> itSchemas) throws SQLException, DBCancelledException, DBException{
+	private Iterator<TAPTable> fillSchemas(final TAPTable metaTable, final Iterator<TAPSchema> itSchemas) throws SQLException, DBCancelledException, DBException {
 		List<TAPTable> allTables = new ArrayList<TAPTable>();
 
 		// Build the SQL update query:
@@ -1988,20 +2030,20 @@ public class JDBCConnection implements DBConnection {
 		sql.append(translator.getColumnName(metaTable.getColumn("schema_name")));
 		sql.append(", ").append(translator.getColumnName(metaTable.getColumn("description")));
 		sql.append(", ").append(translator.getColumnName(metaTable.getColumn("utype")));
-		if (supportsSchema){
+		if (supportsSchema) {
 			sql.append(", ").append(DB_NAME_COLUMN);
 			sql.append(") VALUES (?, ?, ?, ?)");
-		}else
+		} else
 			sql.append(") VALUES (?, ?, ?)");
 
 		// Prepare the statement:
 		PreparedStatement stmt = null;
-		try{
+		try {
 			stmt = connection.prepareStatement(sql.toString());
 
 			// Execute the query for each schema:
 			int nbRows = 0;
-			while(itSchemas.hasNext()){
+			while(itSchemas.hasNext()) {
 				TAPSchema schema = itSchemas.next();
 				nbRows++;
 
@@ -2026,7 +2068,7 @@ public class JDBCConnection implements DBConnection {
 				throw new DBCancelledException();
 			else
 				executeBatchUpdates(stmt, nbRows);
-		}finally{
+		} finally {
 			close(stmt);
 		}
 
@@ -2050,7 +2092,7 @@ public class JDBCConnection implements DBConnection {
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
 	 */
-	private Iterator<TAPColumn> fillTables(final TAPTable metaTable, final Iterator<TAPTable> itTables) throws SQLException, DBCancelledException, DBException{
+	private Iterator<TAPColumn> fillTables(final TAPTable metaTable, final Iterator<TAPTable> itTables) throws SQLException, DBCancelledException, DBException {
 		List<TAPColumn> allColumns = new ArrayList<TAPColumn>();
 
 		// Build the SQL update query:
@@ -2067,12 +2109,12 @@ public class JDBCConnection implements DBConnection {
 
 		// Prepare the statement:
 		PreparedStatement stmt = null;
-		try{
+		try {
 			stmt = connection.prepareStatement(sql.toString());
 
 			// Execute the query for each table:
 			int nbRows = 0;
-			while(itTables.hasNext()){
+			while(itTables.hasNext()) {
 				TAPTable table = itTables.next();
 				nbRows++;
 
@@ -2102,7 +2144,7 @@ public class JDBCConnection implements DBConnection {
 				throw new DBCancelledException();
 			else
 				executeBatchUpdates(stmt, nbRows);
-		}finally{
+		} finally {
 			close(stmt);
 		}
 
@@ -2126,7 +2168,7 @@ public class JDBCConnection implements DBConnection {
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
 	 */
-	private Iterator<TAPForeignKey> fillColumns(final TAPTable metaTable, final Iterator<TAPColumn> itColumns) throws SQLException, DBCancelledException, DBException{
+	private Iterator<TAPForeignKey> fillColumns(final TAPTable metaTable, final Iterator<TAPColumn> itColumns) throws SQLException, DBCancelledException, DBException {
 		List<TAPForeignKey> allKeys = new ArrayList<TAPForeignKey>();
 
 		// Build the SQL update query:
@@ -2150,12 +2192,12 @@ public class JDBCConnection implements DBConnection {
 
 		// Prepare the statement:
 		PreparedStatement stmt = null;
-		try{
+		try {
 			stmt = connection.prepareStatement(sql.toString());
 
 			// Execute the query for each column:
 			int nbRows = 0;
-			while(itColumns.hasNext()){
+			while(itColumns.hasNext()) {
 				TAPColumn col = itColumns.next();
 				nbRows++;
 
@@ -2192,7 +2234,7 @@ public class JDBCConnection implements DBConnection {
 				throw new DBCancelledException();
 			else
 				executeBatchUpdates(stmt, nbRows);
-		}finally{
+		} finally {
 			close(stmt);
 		}
 
@@ -2215,7 +2257,7 @@ public class JDBCConnection implements DBConnection {
 	 * @throws DBException			If rows can not be inserted because the SQL update query has failed.
 	 * @throws SQLException			If any other SQL exception occurs.
 	 */
-	private void fillKeys(final TAPTable metaKeys, final TAPTable metaKeyColumns, final Iterator<TAPForeignKey> itKeys) throws SQLException, DBCancelledException, DBException{
+	private void fillKeys(final TAPTable metaKeys, final TAPTable metaKeyColumns, final Iterator<TAPForeignKey> itKeys) throws SQLException, DBCancelledException, DBException {
 		// Build the SQL update query for KEYS:
 		StringBuffer sqlKeys = new StringBuffer("INSERT INTO ");
 		sqlKeys.append(translator.getTableName(metaKeys, supportsSchema)).append(" (");
@@ -2227,7 +2269,7 @@ public class JDBCConnection implements DBConnection {
 		sqlKeys.append(") VALUES (?, ?, ?, ?, ?)");
 
 		PreparedStatement stmtKeys = null, stmtKeyCols = null;
-		try{
+		try {
 			// Prepare the statement for KEYS:
 			stmtKeys = connection.prepareStatement(sqlKeys.toString());
 
@@ -2244,7 +2286,7 @@ public class JDBCConnection implements DBConnection {
 
 			// Execute the query for each column:
 			int nbKeys = 0, nbKeyColumns = 0;
-			while(itKeys.hasNext()){
+			while(itKeys.hasNext()) {
 				TAPForeignKey key = itKeys.next();
 				nbKeys++;
 
@@ -2269,7 +2311,7 @@ public class JDBCConnection implements DBConnection {
 
 				// add the key columns into KEY_COLUMNS:
 				Iterator<Map.Entry<String, String>> itAssoc = key.iterator();
-				while(itAssoc.hasNext()){
+				while(itAssoc.hasNext()) {
 					nbKeyColumns++;
 					Map.Entry<String, String> assoc = itAssoc.next();
 					stmtKeyCols.setString(1, key.getKeyId());
@@ -2287,11 +2329,11 @@ public class JDBCConnection implements DBConnection {
 			// If the query has been aborted, return immediately:
 			if (isCancelled())
 				throw new DBCancelledException();
-			else{
+			else {
 				executeBatchUpdates(stmtKeys, nbKeys);
 				executeBatchUpdates(stmtKeyCols, nbKeyColumns);
 			}
-		}finally{
+		} finally {
 			close(stmtKeys);
 			close(stmtKeyCols);
 		}
@@ -2321,7 +2363,7 @@ public class JDBCConnection implements DBConnection {
 	 * @see #checkUploadedTableDef(TAPTable)
 	 */
 	@Override
-	public synchronized boolean addUploadedTable(TAPTable tableDef, TableIterator data) throws DBException, DataReadException{
+	public synchronized boolean addUploadedTable(TAPTable tableDef, TableIterator data) throws DBException, DataReadException {
 		// If no table to upload, consider it has been dropped and return TRUE:
 		if (tableDef == null)
 			return true;
@@ -2332,7 +2374,7 @@ public class JDBCConnection implements DBConnection {
 		// Check the table is well defined (and particularly the schema is well set with an ADQL name = TAP_UPLOAD):
 		checkUploadedTableDef(tableDef);
 
-		try{
+		try {
 
 			// Start a transaction:
 			startTransaction();
@@ -2342,13 +2384,13 @@ public class JDBCConnection implements DBConnection {
 			DatabaseMetaData dbMeta = connection.getMetaData();
 
 			// 1. Create the upload schema, if it does not already exist:
-			if (!isSchemaExisting(tableDef.getDBSchemaName(), dbMeta)){
+			if (!isSchemaExisting(tableDef.getDBSchemaName(), dbMeta)) {
 				stmt.executeUpdate("CREATE SCHEMA " + translator.getQualifiedSchemaName(tableDef));
 				if (logger != null)
 					logger.logDB(LogLevel.INFO, this, "SCHEMA_CREATED", "Schema \"" + tableDef.getADQLSchemaName() + "\" (in DB: " + translator.getQualifiedSchemaName(tableDef) + ") created.", null);
 			}
 			// 1bis. Ensure the table does not already exist and if it is the case, throw an understandable exception:
-			else if (isTableExisting(tableDef.getDBSchemaName(), tableDef.getDBName(), dbMeta)){
+			else if (isTableExisting(tableDef.getDBSchemaName(), tableDef.getDBName(), dbMeta)) {
 				DBException de = new DBException("Impossible to create the user uploaded table in the database: " + translator.getTableName(tableDef, supportsSchema) + "! This table already exists.");
 				if (logger != null)
 					logger.logDB(LogLevel.ERROR, this, "ADD_UPLOAD_TABLE", de.getMessage(), de);
@@ -2364,7 +2406,7 @@ public class JDBCConnection implements DBConnection {
 			StringBuffer sqlBuf = new StringBuffer("CREATE TABLE ");
 			sqlBuf.append(translator.getTableName(tableDef, supportsSchema)).append(" (");
 			Iterator<TAPColumn> it = tableDef.getColumns();
-			while(it.hasNext()){
+			while(it.hasNext()) {
 				TAPColumn col = it.next();
 				// column name:
 				sqlBuf.append(translator.getColumnName(col));
@@ -2397,20 +2439,20 @@ public class JDBCConnection implements DBConnection {
 
 			return true;
 
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			rollback();
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.WARNING, this, "ADD_UPLOAD_TABLE", "Impossible to create the uploaded table: " + translator.getTableName(tableDef, supportsSchema) + "!", se);
 			throw new DBException("Impossible to create the uploaded table: " + translator.getTableName(tableDef, supportsSchema) + "!", se);
-		}catch(DBException de){
+		} catch(DBException de) {
 			rollback();
 			if (logger != null && (de instanceof DBCancelledException || isCancelled()))
 				logger.logDB(LogLevel.INFO, this, "ADD_UPLOAD_TABLE", "Upload of the table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getTableName(tableDef, supportsSchema) + ") canceled!", null);
 			throw de;
-		}catch(DataReadException dre){
+		} catch(DataReadException dre) {
 			rollback();
 			throw dre;
-		}finally{
+		} finally {
 			closeStatement();
 			endTransaction();
 		}
@@ -2438,7 +2480,7 @@ public class JDBCConnection implements DBConnection {
 	 * @throws SQLException			If any other SQL exception occurs.
 	 * @throws DataReadException	If there is any error while reading the data from the given {@link TableIterator} (and particularly if a limit - in byte or row - has been reached).
 	 */
-	protected int fillUploadedTable(final TAPTable metaTable, final TableIterator data) throws SQLException, DBCancelledException, DBException, DataReadException{
+	protected int fillUploadedTable(final TAPTable metaTable, final TableIterator data) throws SQLException, DBCancelledException, DBException, DataReadException {
 		// 1. Build the SQL update query:
 		StringBuffer sql = new StringBuffer("INSERT INTO ");
 		StringBuffer varParam = new StringBuffer();
@@ -2446,8 +2488,8 @@ public class JDBCConnection implements DBConnection {
 		sql.append(translator.getTableName(metaTable, supportsSchema)).append(" (");
 		// ...list of columns:
 		TAPColumn[] cols = data.getMetadata();
-		for(int c = 0; c < cols.length; c++){
-			if (c > 0){
+		for(int c = 0; c < cols.length; c++) {
+			if (c > 0) {
 				sql.append(", ");
 				varParam.append(", ");
 			}
@@ -2460,41 +2502,41 @@ public class JDBCConnection implements DBConnection {
 		// 2. Prepare the statement:
 		PreparedStatement stmt = null;
 		int nbRows = 0;
-		try{
+		try {
 			stmt = connection.prepareStatement(sql.toString());
 
 			// 3. Execute the query for each given row:
-			while(data.nextRow()){
+			while(data.nextRow()) {
 				nbRows++;
 				int c = 1;
-				while(data.hasNextCol()){
+				while(data.hasNextCol()) {
 					Object val = data.nextCol();
-					if (val != null && cols[c - 1] != null){
+					if (val != null && cols[c - 1] != null) {
 						/* TIMESTAMP FORMATTING */
-						if (cols[c - 1].getDatatype().type == DBDatatype.TIMESTAMP){
-							try{
+						if (cols[c - 1].getDatatype().type == DBDatatype.TIMESTAMP) {
+							try {
 								val = new Timestamp(ISO8601Format.parse(val.toString()));
-							}catch(ParseException pe){
+							} catch(ParseException pe) {
 								if (logger != null)
 									logger.logDB(LogLevel.ERROR, this, "UPLOAD", "[l. " + nbRows + ", c. " + c + "] Unexpected date format for the value: \"" + val + "\"! A date formatted in ISO8601 was expected.", pe);
 								throw new DBException("[l. " + nbRows + ", c. " + c + "] Unexpected date format for the value: \"" + val + "\"! A date formatted in ISO8601 was expected.", pe);
 							}
 						}
 						/* GEOMETRY FORMATTING */
-						else if (cols[c - 1].getDatatype().type == DBDatatype.POINT || cols[c - 1].getDatatype().type == DBDatatype.REGION){
+						else if (cols[c - 1].getDatatype().type == DBDatatype.POINT || cols[c - 1].getDatatype().type == DBDatatype.REGION) {
 							Region region;
 							// parse the region as an STC-S expression:
-							try{
+							try {
 								region = STCS.parseRegion(val.toString());
-							}catch(adql.parser.grammar.ParseException e){
+							} catch(adql.parser.grammar.ParseException e) {
 								if (logger != null)
 									logger.logDB(LogLevel.ERROR, this, "UPLOAD", "[l. " + nbRows + ", c. " + c + "] Incorrect STC-S syntax for the geometrical value \"" + val + "\"! " + e.getMessage(), e);
 								throw new DataReadException("[l. " + nbRows + ", c. " + c + "] Incorrect STC-S syntax for the geometrical value \"" + val + "\"! " + e.getMessage(), e);
 							}
 							// translate this STC region into the corresponding column value:
-							try{
+							try {
 								val = translator.translateGeometryToDB(region);
-							}catch(adql.parser.grammar.ParseException e){
+							} catch(adql.parser.grammar.ParseException e) {
 								if (logger != null)
 									logger.logDB(LogLevel.ERROR, this, "UPLOAD", "[l. " + nbRows + ", c. " + c + "] Impossible to import the ADQL geometry \"" + val + "\" into the database! " + e.getMessage(), e);
 								throw new DataReadException("[l. " + nbRows + ", c. " + c + "] Impossible to import the ADQL geometry \"" + val + "\" into the database! " + e.getMessage(), e);
@@ -2530,7 +2572,7 @@ public class JDBCConnection implements DBConnection {
 
 			return nbRows;
 
-		}finally{
+		} finally {
 			close(stmt);
 		}
 	}
@@ -2556,7 +2598,7 @@ public class JDBCConnection implements DBConnection {
 	 * @see #checkUploadedTableDef(TAPTable)
 	 */
 	@Override
-	public synchronized boolean dropUploadedTable(final TAPTable tableDef) throws DBException{
+	public synchronized boolean dropUploadedTable(final TAPTable tableDef) throws DBException {
 		// If no table to upload, consider it has been dropped and return TRUE:
 		if (tableDef == null)
 			return true;
@@ -2567,7 +2609,7 @@ public class JDBCConnection implements DBConnection {
 		// Check the table is well defined (and particularly the schema is well set with an ADQL name = TAP_UPLOAD):
 		checkUploadedTableDef(tableDef);
 
-		try{
+		try {
 
 			// Check the existence of the table to drop:
 			if (!isTableExisting(tableDef.getDBSchemaName(), tableDef.getDBName(), connection.getMetaData()))
@@ -2577,7 +2619,7 @@ public class JDBCConnection implements DBConnection {
 			int cnt = getStatement().executeUpdate("DROP TABLE " + translator.getTableName(tableDef, supportsSchema));
 
 			// Log the end:
-			if (logger != null){
+			if (logger != null) {
 				if (cnt >= 0)
 					logger.logDB(LogLevel.INFO, this, "TABLE_DROPPED", "Table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getTableName(tableDef, supportsSchema) + ") dropped.", null);
 				else
@@ -2587,11 +2629,11 @@ public class JDBCConnection implements DBConnection {
 			// Ensure the update is successful:
 			return (cnt >= 0);
 
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (!isCancelled() && logger != null)
 				logger.logDB(LogLevel.WARNING, this, "DROP_UPLOAD_TABLE", "Impossible to drop the uploaded table: " + translator.getTableName(tableDef, supportsSchema) + "!", se);
 			throw new DBException("Impossible to drop the uploaded table: " + translator.getTableName(tableDef, supportsSchema) + "!", se);
-		}finally{
+		} finally {
 			cancel(true);
 			closeStatement();
 		}
@@ -2617,12 +2659,12 @@ public class JDBCConnection implements DBConnection {
 	 * @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").
 	 */
-	protected void checkUploadedTableDef(final TAPTable tableDef) throws DBException{
+	protected void checkUploadedTableDef(final TAPTable tableDef) throws DBException {
 		// If the table has no defined schema or if the ADQL name of the schema is not TAP_UPLOAD, throw an exception:
 		if (tableDef.getSchema() == null || !tableDef.getSchema().getADQLName().equals(STDSchema.UPLOADSCHEMA.label))
 			throw new DBException("Missing upload schema! An uploaded table must be inside a schema whose the ADQL name is strictly equals to \"" + STDSchema.UPLOADSCHEMA.label + "\" (but the DB name may be different).");
 
-		if (!supportsSchema){
+		if (!supportsSchema) {
 			if (tableDef.getADQLSchemaName() != null && tableDef.getADQLSchemaName().trim().length() > 0 && !tableDef.getDBName().startsWith(tableDef.getADQLSchemaName() + "_"))
 				tableDef.setDBName(tableDef.getADQLSchemaName() + "_" + tableDef.getDBName());
 			if (tableDef.getSchema() != null)
@@ -2650,7 +2692,7 @@ public class JDBCConnection implements DBConnection {
 	 * @see JDBCTranslator#convertTypeToDB(DBType)
 	 * @see #defaultTypeConversion(DBType)
 	 */
-	protected String convertTypeToDB(final DBType type){
+	protected String convertTypeToDB(final DBType type) {
 		String dbmsType = translator.convertTypeToDB(type);
 		return (dbmsType == null) ? defaultTypeConversion(type) : dbmsType;
 	}
@@ -2677,11 +2719,11 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @return	The corresponding DB type, or VARCHAR if the given type is not managed or is NULL.
 	 */
-	protected String defaultTypeConversion(DBType datatype){
+	protected String defaultTypeConversion(DBType datatype) {
 		if (datatype == null)
 			datatype = new DBType(DBDatatype.VARCHAR);
 
-		switch(datatype.type){
+		switch(datatype.type) {
 
 			case SMALLINT:
 				return dbms.equals("sqlite") ? "INTEGER" : "SMALLINT";
@@ -2783,14 +2825,14 @@ public class JDBCConnection implements DBConnection {
 	 * @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.
 	 */
-	protected void startTransaction() throws DBException{
-		try{
-			if (supportsTransaction){
+	protected void startTransaction() throws DBException {
+		try {
+			if (supportsTransaction) {
 				connection.setAutoCommit(false);
 				if (logger != null)
 					logger.logDB(LogLevel.INFO, this, "START_TRANSACTION", "Transaction STARTED.", null);
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			supportsTransaction = false;
 			if (logger != null)
 				logger.logDB(LogLevel.ERROR, this, "START_TRANSACTION", "Transaction STARTing impossible!", se);
@@ -2816,14 +2858,14 @@ public class JDBCConnection implements DBConnection {
 	 * @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.
 	 */
-	protected void commit() throws DBException{
-		try{
-			if (supportsTransaction){
+	protected void commit() throws DBException {
+		try {
+			if (supportsTransaction) {
 				connection.commit();
 				if (logger != null)
 					logger.logDB(LogLevel.INFO, this, "COMMIT", "Transaction COMMITED.", null);
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			supportsTransaction = false;
 			if (logger != null)
 				logger.logDB(LogLevel.ERROR, this, "COMMIT", "Transaction COMMIT impossible!", se);
@@ -2852,7 +2894,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @see #rollback(boolean)
 	 */
-	protected final void rollback(){
+	protected final void rollback() {
 		rollback(true);
 	}
 
@@ -2879,14 +2921,14 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected void rollback(final boolean log){
-		try{
-			if (supportsTransaction && !connection.getAutoCommit()){
+	protected void rollback(final boolean log) {
+		try {
+			if (supportsTransaction && !connection.getAutoCommit()) {
 				connection.rollback();
 				if (log && logger != null)
 					logger.logDB(LogLevel.INFO, this, "ROLLBACK", "Transaction ROLLBACKED.", null);
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			supportsTransaction = false;
 			if (log && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "ROLLBACK", "Transaction ROLLBACK impossible!", se);
@@ -2913,7 +2955,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @see #endTransaction(boolean)
 	 */
-	protected final void endTransaction(){
+	protected final void endTransaction() {
 		endTransaction(true);
 	}
 
@@ -2939,14 +2981,14 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected void endTransaction(final boolean log){
-		try{
-			if (supportsTransaction){
+	protected void endTransaction(final boolean log) {
+		try {
+			if (supportsTransaction) {
 				connection.setAutoCommit(true);
 				if (log && logger != null)
 					logger.logDB(LogLevel.INFO, this, "END_TRANSACTION", "Transaction ENDED.", null);
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			supportsTransaction = false;
 			if (log && logger != null)
 				logger.logDB(LogLevel.ERROR, this, "END_TRANSACTION", "Transaction ENDing impossible!", se);
@@ -2966,11 +3008,11 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @param rs	{@link ResultSet} to close.
 	 */
-	protected final void close(final ResultSet rs){
-		try{
+	protected final void close(final ResultSet rs) {
+		try {
 			if (rs != null)
 				rs.close();
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (logger != null)
 				logger.logDB(LogLevel.WARNING, this, "CLOSE", "Can not close a ResultSet!", null);
 		}
@@ -3002,13 +3044,13 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @see #cancel(Statement, boolean)
 	 */
-	protected final void close(final Statement stmt){
-		try{
-			if (stmt != null){
+	protected final void close(final Statement stmt) {
+		try {
+			if (stmt != null) {
 				cancel(stmt, false);
 				stmt.close();
 			}
-		}catch(SQLException se){
+		} catch(SQLException se) {
 			if (logger != null)
 				logger.logDB(LogLevel.WARNING, this, "CLOSE", "Can not close a Statement!", null);
 		}
@@ -3033,7 +3075,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @return	Its corresponding boolean value.
 	 */
-	protected final boolean toBoolean(final Object colValue){
+	protected final boolean toBoolean(final Object colValue) {
 		// NULL => false:
 		if (colValue == null)
 			return false;
@@ -3043,19 +3085,19 @@ public class JDBCConnection implements DBConnection {
 			return ((Boolean)colValue).booleanValue();
 
 		// Integer value => cast in integer and return true only if the value is positive and not null:
-		else if (colValue instanceof Integer){
+		else if (colValue instanceof Integer) {
 			int intFlag = ((Integer)colValue).intValue();
 			return (intFlag > 0);
 		}
 		// Otherwise => get the string representation and:
 		//     1/ try to cast it into an integer and apply the same test as before
 		//     2/ if the cast fails, return true only if the value is "t" or "true" (case insensitively):
-		else{
+		else {
 			String strFlag = colValue.toString().trim();
-			try{
+			try {
 				int intFlag = Integer.parseInt(strFlag);
 				return (intFlag > 0);
-			}catch(NumberFormatException nfe){
+			} catch(NumberFormatException nfe) {
 				return strFlag.equalsIgnoreCase("t") || strFlag.equalsIgnoreCase("true");
 			}
 		}
@@ -3069,38 +3111,26 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @return	NULL if the given string is NULL or empty, otherwise the given value.
 	 */
-	protected final String nullifyIfNeeded(final String dbValue){
+	protected final String nullifyIfNeeded(final String dbValue) {
 		return (dbValue != null && dbValue.trim().length() <= 0) ? null : dbValue;
 	}
 
 	/**
-	 * Search a {@link TAPTable} instance whose the ADQL name matches (case sensitively) to the given one.
+	 * Search a {@link TAPTable} instance whose the ADQL name matches exactly
+	 * (and 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.
+	 * @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){
-		// Get the schema name, if any prefix the given table name:
-		String schemaName = null;
-		int indSep = tableName.indexOf('.');
-		if (indSep > 0){
-			schemaName = tableName.substring(0, indSep);
-			tableName = tableName.substring(indSep + 1);
-		}
-
+	private TAPTable searchTable(String tableName, final Iterator<TAPTable> itTables) {
 		// Search by schema name (if any) and then by table name:
-		while(itTables.hasNext()){
+		while(itTables.hasNext()) {
 			// get the table:
 			TAPTable table = itTables.next();
-			// test the schema name (if one was prefixing the table name) (case sensitively):
-			if (schemaName != null){
-				if (table.getADQLSchemaName() == null || !schemaName.equals(table.getADQLSchemaName()))
-					continue;
-			}
-			// test the table name (case sensitively):
-			if (tableName.equals(table.getADQLName()))
+			if (tableName.equals(table.getRawName()))
 				return table;
 		}
 
@@ -3123,7 +3153,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected int getTableSchemaIndexInMetadata(){
+	protected int getTableSchemaIndexInMetadata() {
 		return dbms.equalsIgnoreCase(DBMS_MYSQL) ? 1 : 2;
 	}
 
@@ -3139,7 +3169,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected ResultSet getDBMetaSchemas(final DatabaseMetaData dbMeta) throws SQLException{
+	protected ResultSet getDBMetaSchemas(final DatabaseMetaData dbMeta) throws SQLException {
 		return (dbms.equalsIgnoreCase(DBMS_MYSQL) ? dbMeta.getCatalogs() : dbMeta.getSchemas());
 	}
 
@@ -3161,7 +3191,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected ResultSet getDBMetaTables(final DatabaseMetaData dbMeta, final String schemaPattern, final String tablePattern) throws SQLException{
+	protected ResultSet getDBMetaTables(final DatabaseMetaData dbMeta, final String schemaPattern, final String tablePattern) throws SQLException {
 		if (dbms.equalsIgnoreCase(DBMS_MYSQL))
 			return dbMeta.getTables(schemaPattern, null, tablePattern, null);
 		else
@@ -3190,7 +3220,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @since 2.1
 	 */
-	protected ResultSet getDBMetaColumns(final DatabaseMetaData dbMeta, final String schemaPattern, final String tablePattern, final String columnPattern) throws SQLException{
+	protected ResultSet getDBMetaColumns(final DatabaseMetaData dbMeta, final String schemaPattern, final String tablePattern, final String columnPattern) throws SQLException {
 		if (dbms.equalsIgnoreCase(DBMS_MYSQL))
 			return dbMeta.getColumns(schemaPattern, null, tablePattern, columnPattern);
 		else
@@ -3221,7 +3251,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @throws SQLException	If any error occurs while interrogating the database about existing schema.
 	 */
-	protected boolean isSchemaExisting(String schemaName, final DatabaseMetaData dbMeta) throws SQLException{
+	protected boolean isSchemaExisting(String schemaName, final DatabaseMetaData dbMeta) throws SQLException {
 		if (!supportsSchema || schemaName == null || schemaName.length() == 0)
 			return true;
 
@@ -3229,15 +3259,15 @@ public class JDBCConnection implements DBConnection {
 		boolean caseSensitive = translator.isCaseSensitive(IdentifierField.SCHEMA);
 
 		ResultSet rs = null;
-		try{
+		try {
 			// List all schemas available and stop when a schema name matches ignoring the case:
 			rs = getDBMetaSchemas(dbMeta);
 			boolean hasSchema = false;
-			while(!hasSchema && rs.next()){
+			while(!hasSchema && rs.next()) {
 				hasSchema = equals(rs.getString(1), schemaName, caseSensitive);
 			}
 			return hasSchema;
-		}finally{
+		} finally {
 			close(rs);
 		}
 	}
@@ -3269,7 +3299,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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{
+	protected boolean isTableExisting(String schemaName, String tableName, final DatabaseMetaData dbMeta) throws DBException, SQLException {
 		if (tableName == null || tableName.length() == 0)
 			return true;
 
@@ -3278,30 +3308,30 @@ public class JDBCConnection implements DBConnection {
 		boolean tableCaseSensitive = translator.isCaseSensitive(IdentifierField.TABLE);
 
 		ResultSet rs = null;
-		try{
+		try {
 
 			// List all matching tables:
-			if (supportsSchema){
+			if (supportsSchema) {
 				String schemaPattern = schemaCaseSensitive ? schemaName : null;
 				String tablePattern = tableCaseSensitive ? tableName : null;
 				rs = getDBMetaTables(dbMeta, schemaPattern, tablePattern);
-			}else{
+			} else {
 				String tablePattern = tableCaseSensitive ? tableName : null;
 				rs = getDBMetaTables(dbMeta, null, tablePattern);
 			}
 
 			// Stop on the first table which match completely (schema name + table name in function of their respective case sensitivity):
 			int cnt = 0;
-			while(rs.next()){
+			while(rs.next()) {
 				String rsSchema = nullifyIfNeeded(rs.getString(getTableSchemaIndexInMetadata()));
 				String rsTable = rs.getString(3);
-				if (!supportsSchema || schemaName == null || equals(rsSchema, schemaName, schemaCaseSensitive)){
+				if (!supportsSchema || schemaName == null || equals(rsSchema, schemaName, schemaCaseSensitive)) {
 					if (equals(rsTable, tableName, tableCaseSensitive))
 						cnt++;
 				}
 			}
 
-			if (cnt > 1){
+			if (cnt > 1) {
 				if (logger != null)
 					logger.logDB(LogLevel.ERROR, this, "TABLE_EXIST", "More than one table match to these criteria (schema=" + schemaName + " (case sensitive?" + schemaCaseSensitive + ") && table=" + tableName + " (case sensitive?" + tableCaseSensitive + "))!", null);
 				throw new DBException("More than one table match to these criteria (schema=" + schemaName + " (case sensitive?" + schemaCaseSensitive + ") && table=" + tableName + " (case sensitive?" + tableCaseSensitive + "))!");
@@ -3309,7 +3339,7 @@ public class JDBCConnection implements DBConnection {
 
 			return cnt == 1;
 
-		}finally{
+		} finally {
 			close(rs);
 		}
 	}
@@ -3343,7 +3373,7 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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{
+	protected boolean isColumnExisting(String schemaName, String tableName, String columnName, final DatabaseMetaData dbMeta) throws DBException, SQLException {
 		if (columnName == null || columnName.length() == 0)
 			return true;
 
@@ -3353,7 +3383,7 @@ public class JDBCConnection implements DBConnection {
 		boolean columnCaseSensitive = translator.isCaseSensitive(IdentifierField.COLUMN);
 
 		ResultSet rsT = null, rsC = null;
-		try{
+		try {
 			/* Note:
 			 *
 			 *     The DatabaseMetaData.getColumns(....) function does not work properly
@@ -3365,11 +3395,11 @@ public class JDBCConnection implements DBConnection {
 			 */
 
 			// List all matching tables:
-			if (supportsSchema){
+			if (supportsSchema) {
 				String schemaPattern = schemaCaseSensitive ? schemaName : null;
 				String tablePattern = tableCaseSensitive ? tableName : null;
 				rsT = getDBMetaTables(dbMeta, schemaPattern, tablePattern);
-			}else{
+			} else {
 				String tablePattern = tableCaseSensitive ? tableName : null;
 				rsT = getDBMetaTables(dbMeta, null, tablePattern);
 			}
@@ -3377,17 +3407,17 @@ public class JDBCConnection implements DBConnection {
 			// For each matching table:
 			int cnt = 0;
 			String columnPattern = columnCaseSensitive ? columnName : null;
-			while(rsT.next()){
+			while(rsT.next()) {
 				String rsSchema = nullifyIfNeeded(rsT.getString(getTableSchemaIndexInMetadata()));
 				String rsTable = rsT.getString(3);
 				// test the schema name:
-				if (!supportsSchema || schemaName == null || equals(rsSchema, schemaName, schemaCaseSensitive)){
+				if (!supportsSchema || schemaName == null || equals(rsSchema, schemaName, schemaCaseSensitive)) {
 					// test the table name:
-					if ((tableName == null || equals(rsTable, tableName, tableCaseSensitive))){
+					if ((tableName == null || equals(rsTable, tableName, tableCaseSensitive))) {
 						// list its columns:
 						rsC = getDBMetaColumns(dbMeta, rsSchema, rsTable, columnPattern);
 						// count all matching columns:
-						while(rsC.next()){
+						while(rsC.next()) {
 							String rsColumn = rsC.getString(4);
 							if (equals(rsColumn, columnName, columnCaseSensitive))
 								cnt++;
@@ -3397,7 +3427,7 @@ public class JDBCConnection implements DBConnection {
 				}
 			}
 
-			if (cnt > 1){
+			if (cnt > 1) {
 				if (logger != null)
 					logger.logDB(LogLevel.ERROR, this, "COLUMN_EXIST", "More than one column match to these criteria (schema=" + schemaName + " (case sensitive?" + schemaCaseSensitive + ") && table=" + tableName + " (case sensitive?" + tableCaseSensitive + ") && column=" + columnName + " (case sensitive?" + columnCaseSensitive + "))!", null);
 				throw new DBException("More than one column match to these criteria (schema=" + schemaName + " (case sensitive?" + schemaCaseSensitive + ") && table=" + tableName + " (case sensitive?" + tableCaseSensitive + ") && column=" + columnName + " (case sensitive?" + columnCaseSensitive + "))!");
@@ -3405,7 +3435,7 @@ public class JDBCConnection implements DBConnection {
 
 			return cnt == 1;
 
-		}finally{
+		} finally {
 			close(rsT);
 			close(rsC);
 		}
@@ -3450,9 +3480,9 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @see TAPMetadata#resolveStdTable(String)
 	 */
-	protected final STDTable isStdTable(final String dbTableName, final TAPTable[] stdTables, final boolean caseSensitive){
-		if (dbTableName != null){
-			for(TAPTable t : stdTables){
+	protected final STDTable isStdTable(final String dbTableName, final TAPTable[] stdTables, final boolean caseSensitive) {
+		if (dbTableName != null) {
+			for(TAPTable t : stdTables) {
 				if (equals(dbTableName, t.getDBName(), caseSensitive))
 					return TAPMetadata.resolveStdTable(t.getADQLName());
 			}
@@ -3496,13 +3526,13 @@ public class JDBCConnection implements DBConnection {
 	 * @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.
 	 */
-	protected final void executeUpdate(final PreparedStatement stmt, int indRow) throws SQLException, DBException{
+	protected final void executeUpdate(final PreparedStatement stmt, int indRow) throws SQLException, DBException {
 		// BATCH INSERTION: (the query is queued and will be executed later)
-		if (supportsBatchUpdates){
+		if (supportsBatchUpdates) {
 			// Add the prepared query in the batch queue of the statement:
-			try{
+			try {
 				stmt.addBatch();
-			}catch(SQLException se){
+			} catch(SQLException se) {
 				if (!isCancelled())
 					supportsBatchUpdates = false;
 				/*
@@ -3512,10 +3542,10 @@ public class JDBCConnection implements DBConnection {
 				 * Otherwise, it is impossible to insert the previous batched rows ; an exception must be thrown
 				 * and must stop the whole TAP_SCHEMA initialization.
 				 */
-				if (indRow == 1){
+				if (indRow == 1) {
 					if (!isCancelled() && logger != null)
 						logger.logDB(LogLevel.WARNING, this, "EXEC_UPDATE", "BATCH query impossible => TRYING AGAIN IN A NORMAL EXECUTION (executeUpdate())!", se);
-				}else{
+				} else {
 					if (!isCancelled() && logger != null)
 						logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "BATCH query impossible!", se);
 					throw new DBException("BATCH query impossible!", se);
@@ -3524,13 +3554,13 @@ public class JDBCConnection implements DBConnection {
 		}
 
 		// NORMAL INSERTION: (immediate insertion)
-		if (!supportsBatchUpdates){
+		if (!supportsBatchUpdates) {
 
 			// Insert the row prepared in the given statement:
 			int nbRowsWritten = stmt.executeUpdate();
 
 			// Check the row has been inserted with success:
-			if (nbRowsWritten != 1){
+			if (nbRowsWritten != 1) {
 				if (logger != null)
 					logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "ROW " + indRow + " not inserted!", null);
 				throw new DBException("ROW " + indRow + " not inserted!");
@@ -3562,14 +3592,14 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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{
-		if (supportsBatchUpdates){
+	protected final void executeBatchUpdates(final PreparedStatement stmt, int nbRows) throws DBException {
+		if (supportsBatchUpdates) {
 			// Execute all the batch queries:
 			int[] rows;
-			try{
+			try {
 				rows = stmt.executeBatch();
-			}catch(SQLException se){
-				if (!isCancelled()){
+			} catch(SQLException se) {
+				if (!isCancelled()) {
 					supportsBatchUpdates = false;
 					if (logger != null)
 						logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "BATCH execution impossible!", se);
@@ -3578,9 +3608,9 @@ public class JDBCConnection implements DBConnection {
 			}
 
 			// Remove executed queries from the statement:
-			try{
+			try {
 				stmt.clearBatch();
-			}catch(SQLException se){
+			} catch(SQLException se) {
 				if (!isCancelled() && logger != null)
 					logger.logDB(LogLevel.WARNING, this, "EXEC_UPDATE", "CLEAR BATCH impossible!", se);
 			}
@@ -3591,7 +3621,7 @@ public class JDBCConnection implements DBConnection {
 				nbRowsUpdated += rows[i];
 
 			// Check all given rows have been inserted with success:
-			if (nbRowsUpdated != nbRows){
+			if (nbRowsUpdated != nbRows) {
 				if (logger != null)
 					logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "ROWS not all update (" + nbRows + " to update ; " + nbRowsUpdated + " updated)!", null);
 				throw new DBException("ROWS not all updated (" + nbRows + " to update ; " + nbRowsUpdated + " updated)!");
@@ -3605,7 +3635,7 @@ public class JDBCConnection implements DBConnection {
 	 * @param lst	List to update.
 	 * @param it	All items to append inside the list.
 	 */
-	private <T> void appendAllInto(final List<T> lst, final Iterator<T> it){
+	private <T> void appendAllInto(final List<T> lst, final Iterator<T> it) {
 		while(it.hasNext())
 			lst.add(it.next());
 	}
@@ -3629,11 +3659,11 @@ public class JDBCConnection implements DBConnection {
 	 *
 	 * @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){
+	protected final boolean equals(final String dbName, final String metaName, final boolean caseSensitive) {
 		if (dbName == null || metaName == null)
 			return false;
 
-		if (caseSensitive){
+		if (caseSensitive) {
 			if (supportsMixedCaseQuotedIdentifier || mixedCaseQuoted)
 				return dbName.equals(metaName);
 			else if (lowerCaseQuoted)
@@ -3642,7 +3672,7 @@ public class JDBCConnection implements DBConnection {
 				return dbName.equals(metaName.toUpperCase());
 			else
 				return dbName.equalsIgnoreCase(metaName);
-		}else{
+		} else {
 			if (supportsMixedCaseUnquotedIdentifier)
 				return dbName.equalsIgnoreCase(metaName);
 			else if (lowerCaseUnquoted)
@@ -3655,7 +3685,7 @@ public class JDBCConnection implements DBConnection {
 	}
 
 	@Override
-	public void setFetchSize(final int size){
+	public void setFetchSize(final int size) {
 		supportsFetchSize = true;
 		fetchSize = (size > 0) ? size : IGNORE_FETCH_SIZE;
 	}
diff --git a/src/tap/metadata/TAPColumn.java b/src/tap/metadata/TAPColumn.java
index 936909f0340d824fdfe90512e75ca070bb1730bb..6516976426b494eb8936357b95b132c9acfac054 100644
--- a/src/tap/metadata/TAPColumn.java
+++ b/src/tap/metadata/TAPColumn.java
@@ -2,21 +2,21 @@ package tap.metadata;
 
 /*
  * 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),
+ *
+ * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -29,171 +29,216 @@ import adql.db.DBColumn;
 import adql.db.DBTable;
 import adql.db.DBType;
 import adql.db.DBType.DBDatatype;
+import adql.db.DefaultDBTable;
 
 /**
- * <p>Represent a column as described by the IVOA standard in the TAP protocol definition.</p>
- * 
+ * Represent a column as described by the IVOA standard in the TAP protocol
+ * definition.
+ *
  * <p>
- * 	This object representation has exactly the same fields as the column of the table TAP_SCHEMA.columns.
- * 	But it also provides a way to add other data. For instance, if information not listed in the standard
- * 	may be stored here, they can be using the function {@link #setOtherData(Object)}. This object can be
- * 	a single value (integer, string, ...), but also a {@link Map}, {@link List}, etc...
+ * 	This object representation has exactly the same fields as the column of the
+ * 	table TAP_SCHEMA.columns. But it also provides a way to add other data. For
+ * 	instance, if information not listed in the standard may be stored here, they
+ * 	can be using the function {@link #setOtherData(Object)}. This object can be
+ * 	a single value (integer, string, ...), but also a {@link Map}, {@link List},
+ * 	etc...
  * </p>
- * 
- * <p><i><b>Important note:</b>
- * 	A {@link TAPColumn} object MUST always have a DB name. That's why, {@link #getDBName()} returns
- * 	what {@link #getADQLName()} returns when no DB name is set. After creation, it is possible to set
- * 	the DB name with {@link #setDBName(String)}.
- * 	<br/>
- * 	This DB name MUST be UNqualified and without double quotes. If a NULL or empty value is provided,
- * 	{@link #getDBName()} returns what {@link #getADQLName()} returns.
- * </i></p>
- * 
+ *
+ * <i>
+ * <p><b>Important note:</b>
+ * 	A {@link TAPColumn} object MUST always have a DB name. That's why,
+ * 	{@link #getDBName()} returns what {@link #getADQLName()} returns when no DB
+ * 	name is set. After creation, it is possible to set the DB name with
+ * 	{@link #setDBName(String)}.
+ * </p>
+ * <p>
+ * 	This DB name MUST be UNqualified and without double quotes. If a NULL or
+ * 	empty value is provided, {@link #getDBName()} returns what
+ * 	{@link #getADQLName()} returns.
+ * </p>
+ * </i>
+ *
  * <h3>Set a table</h3>
- * 
+ *
  * <p>
- *	By default a column is detached (not part of a table). To specify the table in which this column is,
- *	you must use {@link TAPTable#addColumn(TAPColumn)}. By doing this, the table link inside this column
- *	will be set automatically and you will be able to get the table with {@link #getTable()}.
+ *	By default a column is detached (not part of a table). To specify the table
+ *	in which this column is, you must use {@link TAPTable#addColumn(TAPColumn)}.
+ *	By doing this, the table link inside this column will be set automatically
+ *	and you will be able to get the table with {@link #getTable()}.
  * </p>
- * 
+ *
  * <h3>Foreign keys</h3>
- * 
+ *
  * <p>
- * 	In case this column is linked to one or several of other tables, it will be possible to list all
- * 	foreign keys where the target columns is with {@link #getTargets()}. In the same way, it will be
- * 	possible to list all foreign keys in which this column is a target with {@link #getSources()}.
- * 	However, in order to ensure the consistency between all metadata, these foreign key's links are
- * 	set at the table level by the table itself using {@link #addSource(TAPForeignKey)} and
- * 	{@link #addTarget(TAPForeignKey)}.
+ * 	In case this column is linked to one or several of other tables, it will be
+ * 	possible to list all foreign keys where the target columns is with
+ * 	{@link #getTargets()}. In the same way, it will be possible to list all
+ * 	foreign keys in which this column is a target with {@link #getSources()}.
+ * 	However, in order to ensure the consistency between all metadata, these
+ * 	foreign key's links are set at the table level by the table itself using
+ * 	{@link #addSource(TAPForeignKey)} and {@link #addTarget(TAPForeignKey)}.
  * </p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.1 (07/2017)
+ * @version 2.4 (09/2019)
  */
 public class TAPColumn implements DBColumn {
 
-	/** Name that this column MUST have in ADQL queries. */
+	/** ADQL name of this column. */
 	private final String adqlName;
 
-	/** Indicates whether the given ADQL name must be simplified by {@link #getADQLName()}.
-	 * <p>Here, "simplification" means removing the surrounding double quotes and the table prefix if any.</p>
-	 * @since 2.1 */
-	private final boolean simplificationNeeded;
+	/** Indicate whether the ADQL column name is case sensitive. In such case,
+	 * this name will be put between double quotes in ADQL.
+	 * @since 2.4 */
+	private boolean columnCaseSensitive = false;
 
 	/** Name that this column have in the database.
-	 * <i>Note: It CAN NOT be NULL. By default, it is the ADQL name.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	It CAN NOT be NULL. By default, it is the ADQL name.
+	 * </i></p> */
 	private String dbName = null;
 
 	/** Table which owns this column.
-	 * <i>Note: It should be NULL only at the construction or for a quick representation of a column.
-	 * 	Then, this attribute is automatically set by a {@link TAPTable} when adding this column inside it
-	 * 	with {@link TAPTable#addColumn(TAPColumn)}.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	It should be NULL only at the construction or for a quick representation
+	 * 	of a column. Then, this attribute is automatically set by a
+	 * 	{@link TAPTable} when adding this column inside it with
+	 * 	{@link TAPTable#addColumn(TAPColumn)}.
+	 * </i></p> */
 	private DBTable table = null;
 
 	/** Description of this column.
-	 * <i>Note: Standard TAP column field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; MAY be NULL.
+	 * </i></p> */
 	private String description = null;
 
 	/** Unit of this column's values.
-	 * <i>Note: Standard TAP column field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; MAY be NULL.
+	 * </i></p> */
 	private String unit = null;
 
 	/** UCD describing the scientific content of this column.
-	 * <i>Note: Standard TAP column field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; MAY be NULL.
+	 * </i></p> */
 	private String ucd = null;
 
 	/** UType associating this column with a data-model.
-	 * <i>Note: Standard TAP column field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; MAY be NULL.
+	 * </i></p> */
 	private String utype = null;
 
 	/** Type of this column.
-	 * <i>Note: Standard TAP column field ; CAN'T be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; CAN'T be NULL.
+	 * </i></p> */
 	private DBType datatype = new DBType(DBDatatype.UNKNOWN);
 
-	/** Flag indicating whether this column is one of those that should be returned by default.
-	 * <i>Note: Standard TAP column field ; FALSE by default.</i> */
+	/** Flag indicating whether this column is one of those that should be
+	 * returned by default.
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; FALSE by default.
+	 * </i></p> */
 	private boolean principal = false;
 
 	/** Flag indicating whether this column is indexed in the database.
-	 * <i>Note: Standard TAP column field ; FALSE by default.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; FALSE by default.
+	 * </i></p> */
 	private boolean indexed = false;
 
 	/** Flag indicating whether this column can be set to NULL in the database.
-	 * <i>Note: Standard TAP column field ; FALSE by default.</i>
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; FALSE by default.
+	 * </i></p>
 	 * @since 2.0 */
 	private boolean nullable = false;
 
 	/** Flag indicating whether this column is defined by a standard.
-	 * <i>Note: Standard TAP column field ; FALSE by default.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field ; FALSE by default.
+	 * </i></p> */
 	private boolean std = false;
 
 	/** Ordering index of this column inside its table.
-	 * <i>Note: Standard TAP column field since TAP 1.1.</i>
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP column field since TAP 1.1.
+	 * </i></p>
 	 * @since 2.1 */
 	private int index = -1;
-	
+
 	/** Coordinate system used by this column values.
-	 * <i>Note: Of course, this attribute has to be set only on coordinate columns.</i>
+	 * <p><i><b>Note:</b>
+	 * 	Of course, this attribute has to be set only on coordinate columns.
+	 * </i></p>
 	 * @since 2.1 */
 	private TAPCoosys coosys = null;
 
 	/** Let add some information in addition of the ones of the TAP protocol.
-	 * <i>Note: This object can be anything: an {@link Integer}, a {@link String}, a {@link Map}, a {@link List}, ...
-	 * Its content is totally free and never used or checked.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	This object can be anything: an {@link Integer}, a {@link String}, a
+	 * 	{@link Map}, a {@link List}, ... Its content is totally free and never
+	 * 	used or checked.
+	 * </i></p> */
 	protected Object otherData = null;
 
 	/** List all foreign keys in which this column is a source.
-	 * <p><b>CAUTION: For consistency consideration, this attribute SHOULD never be modified!
-	 * 	It is set by the constructor and filled ONLY by the table.</b></p> */
+	 * <p><i><b>CAUTION:</b>
+	 * 	For consistency consideration, this attribute SHOULD never be modified!
+	 * 	It is set by the constructor and filled ONLY by the table.
+	 * </i></p> */
 	protected final ArrayList<TAPForeignKey> lstTargets;
 
 	/** List all foreign keys in which this column is a target.
-	 * <p><b>CAUTION: For consistency consideration, this attribute SHOULD never be modified!
-	 * 	It is set by the constructor and filled ONLY by the table.</b></p> */
+	 * <p><i><b>CAUTION:</b>
+	 * 	For consistency consideration, this attribute SHOULD never be modified!
+	 * 	It is set by the constructor and filled ONLY by the table.
+	 * </i></p> */
 	protected final ArrayList<TAPForeignKey> lstSources;
 
 	/**
-	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given ADQL name.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a VARCHAR {@link TAPColumn} instance with the given ADQL name.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
+	 *
+	 * <p><i><b>Note 2:</b>
 	 * 	The datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 */
-	public TAPColumn(String columnName) throws NullPointerException{
+	 *
+	 * @param columnName	ADQL name of this column.
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
+	 */
+	public TAPColumn(String columnName) throws NullPointerException {
 		if (columnName == null)
 			throw new NullPointerException("Missing column name!");
 
-		adqlName = columnName.trim();
-		simplificationNeeded = (adqlName.indexOf('.') > 0 || adqlName.indexOf('"') >= 0);
+		columnName = columnName.trim();
+		columnCaseSensitive = DefaultDBTable.isDelimited(columnName);
+		adqlName = (columnCaseSensitive ? columnName.substring(1, columnName.length() - 1).replaceAll("\"\"", "\"") : columnName);
 
-		if (getADQLName().length() == 0)
+		if (adqlName.trim().length() == 0)
 			throw new NullPointerException("Missing column name!");
 
 		dbName = null;
@@ -203,287 +248,287 @@ public class TAPColumn implements DBColumn {
 	}
 
 	/**
-	 * <p>Build a {@link TAPColumn} instance with the given ADQL name and datatype.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a {@link TAPColumn} instance with the given ADQL name and datatype.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 * 	The datatype is set by default to VARCHAR.
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param type			Datatype of this column. <i>If NULL, VARCHAR will be the datatype of this column</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 * 
+	 *
+	 * @param columnName	ADQL name of this column.
+	 * @param type			Datatype of this column.
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
+	 *
 	 * @see #setDatatype(DBType)
 	 */
-	public TAPColumn(String columnName, DBType type) throws NullPointerException{
+	public TAPColumn(String columnName, DBType type) throws NullPointerException {
 		this(columnName);
 		setDatatype(type);
 	}
 
 	/**
-	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given ADQL name and description.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a VARCHAR {@link TAPColumn} instance with the given ADQL name and
+	 * description.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 * 	The datatype is set by default to VARCHAR.
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param description	Description of the column's content. <i>May be NULL</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 */
-	public TAPColumn(String columnName, String description) throws NullPointerException{
+	 *
+	 * @param columnName	ADQL name of this column.
+	 * @param description	Description of the column's content.
+	 *                   	<i>May be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
+	 */
+	public TAPColumn(String columnName, String description) throws NullPointerException {
 		this(columnName, (DBType)null, description);
 	}
 
 	/**
-	 * <p>Build a {@link TAPColumn} instance with the given ADQL name, datatype and description.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a {@link TAPColumn} instance with the given ADQL name, datatype and
+	 * description.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does not do
-	 *	anything if the given datatype is NULL.
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param type			Datatype of this column. <i>If NULL, VARCHAR will be the datatype of this column</i>
-	 * @param description	Description of the column's content. <i>May be NULL</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 */
-	public TAPColumn(String columnName, DBType type, String description) throws NullPointerException{
+	 *
+	 * @param columnName	ADQL name of this column.
+	 * @param type			Datatype of this column.
+	 * @param description	Description of the column's content.
+	 *                   	<i>May be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
+	 */
+	public TAPColumn(String columnName, DBType type, String description) throws NullPointerException {
 		this(columnName, type);
 		this.description = description;
 	}
 
 	/**
-	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given ADQL name, description and unit.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a VARCHAR {@link TAPColumn} instance with the given ADQL name,
+	 * description and unit.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 * 	The datatype is set by default to VARCHAR.
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param description	Description of the column's content. <i>May be NULL</i>
-	 * @param unit			Unit of the column's values. <i>May be NULL</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 */
-	public TAPColumn(String columnName, String description, String unit) throws NullPointerException{
+	 *
+	 * @param columnName	ADQL name of this column.
+	 * @param description	Description of the column's content.
+	 *                   	<i>May be NULL</i>
+	 * @param unit			Unit of the column's values.
+	 *            			<i>May be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
+	 */
+	public TAPColumn(String columnName, String description, String unit) throws NullPointerException {
 		this(columnName, null, description, unit);
 	}
 
 	/**
-	 * <p>Build a {@link TAPColumn} instance with the given ADQL name, type, description and unit.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a {@link TAPColumn} instance with the given ADQL name, type, description and unit.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does not do
-	 *	anything if the given datatype is NULL.
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param type			Datatype of this column. <i>If NULL, VARCHAR will be the datatype of this column</i>
-	 * @param description	Description of the column's content. <i>May be NULL</i>
-	 * @param unit			Unit of the column's values. <i>May be NULL</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 */
-	public TAPColumn(String columnName, DBType type, String description, String unit) throws NullPointerException{
+	 *
+	 * @param columnName	ADQL name of this column.
+	 * @param type			Datatype of this column.
+	 * @param description	Description of the column's content.
+	 *                   	<i>May be NULL</i>
+	 * @param unit			Unit of the column's values.
+	 *            			<i>May be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
+	 */
+	public TAPColumn(String columnName, DBType type, String description, String unit) throws NullPointerException {
 		this(columnName, type, description);
 		this.unit = unit;
 	}
 
 	/**
-	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given fields.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a VARCHAR {@link TAPColumn} instance with the given fields.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 * 	The datatype is set by default to VARCHAR.
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param description	Description of the column's content. <i>May be NULL</i>
-	 * @param unit			Unit of the column's values. <i>May be NULL</i>
+	 *
+	 * @param columnName	ADQL name of this column.
+	 * @param description	Description of the column's content.
+	 *                   	<i>May be NULL</i>
+	 * @param unit			Unit of the column's values.
+	 *            			<i>May be NULL</i>
 	 * @param ucd			UCD describing the scientific content of this column.
+	 *            			<i>May be NULL</i>
 	 * @param utype			UType associating this column with a data-model.
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
+	 *            			<i>May be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
 	 */
-	public TAPColumn(String columnName, String description, String unit, String ucd, String utype) throws NullPointerException{
+	public TAPColumn(String columnName, String description, String unit, String ucd, String utype) throws NullPointerException {
 		this(columnName, null, description, unit, ucd, utype);
 	}
 
 	/**
-	 * <p>Build a {@link TAPColumn} instance with the given fields.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a {@link TAPColumn} instance with the given fields.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does not do
-	 *	anything if the given datatype is NULL.
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the datatype is set by default to VARCHAR.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the column name is prefixed by its table name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the table name must be exactly the same
-	 * 		as what the function {@link TAPTable#getRawName()} of the set table returns.
+	 * 		The column name MUST NOT be prefixed by its table name.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} but will
+	 * 		Double quotes may surround the column name. In such case, they
+	 * 		indicate that the column name must be considered as case sensitive.
+	 * 		If present, these double quotes will be removed but will
 	 * 		still appear in the result of {@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param type			Datatype of this column. <i>If NULL, VARCHAR will be the datatype of this column</i>
-	 * @param description	Description of the column's content. <i>May be NULL</i>
-	 * @param unit			Unit of the column's values. <i>May be NULL</i>
+	 *
+	 * @param columnName	ADQL name of this column.
+	 * @param type			Datatype of this column.
+	 * @param description	Description of the column's content.
+	 *                   	<i>May be NULL</i>
+	 * @param unit			Unit of the column's values.
+	 *                   	<i>May be NULL</i>
 	 * @param ucd			UCD describing the scientific content of this column.
+	 *                   	<i>May be NULL</i>
 	 * @param utype			UType associating this column with a data-model.
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
+	 *                   	<i>May be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
 	 */
-	public TAPColumn(String columnName, DBType type, String description, String unit, String ucd, String utype) throws NullPointerException{
+	public TAPColumn(String columnName, DBType type, String description, String unit, String ucd, String utype) throws NullPointerException {
 		this(columnName, type, description, unit);
 		this.ucd = ucd;
 		this.utype = utype;
@@ -491,61 +536,55 @@ public class TAPColumn implements DBColumn {
 
 	/**
 	 * Get the ADQL name (the name this column MUST have in ADQL queries).
-	 * 
+	 *
 	 * @return	Its ADQL name.
 	 * @see #getADQLName()
 	 * @deprecated	Does not do anything special: just call {@link #getADQLName()}.
 	 */
 	@Deprecated
-	public final String getName(){
+	public final String getName() {
 		return getADQLName();
 	}
 
 	@Override
-	public final String getADQLName(){
-		if (simplificationNeeded){
-			String tmp = adqlName;
-			// Remove the table prefix if any:
-			if (table != null){
-				String tablePrefix = ((table instanceof TAPTable) ? ((TAPTable)table).getRawName() : table.getADQLName()) + ".";
-				if (tmp.startsWith(tablePrefix))
-					tmp = tmp.substring(tablePrefix.length()).trim();
-			}
-			// Remove the surrounding double-quotes if any:
-			if (tmp.matches("\"[^\"]*\""))
-				tmp = tmp.substring(1, tmp.length() - 1);
-			// Finally, return the result:
-			return tmp;
-		}else
-			return adqlName;
-	}
-
-	/**
-	 * Get the full ADQL name of this table, as it has been provided at initialization.
-	 * 
+	public final String getADQLName() {
+		return adqlName;
+	}
+
+	/**
+	 * Get the ADQL name of this column, as it has been provided at
+	 * initialization.
+	 *
 	 * @return	Get the original ADQL name.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final String getRawName(){
-		return adqlName;
+	public final String getRawName() {
+		return (columnCaseSensitive ? "\"" + adqlName.replaceAll("\"", "\"\"") + "\"" : adqlName);
+	}
+
+	@Override
+	public final boolean isCaseSensitive() {
+		return columnCaseSensitive;
 	}
 
 	@Override
-	public final String getDBName(){
+	public final String getDBName() {
 		return (dbName == null) ? getADQLName() : dbName;
 	}
 
 	/**
-	 * <p>Change the name that this column MUST have in the database (i.e. in SQL queries).</p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given value is NULL or an empty string, nothing is done ; the DB name keeps is former value.
+	 * Change the name that this column MUST have in the database (i.e. in SQL
+	 * queries).
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	If the given value is NULL or an empty string, nothing is done ; the DB
+	 * 	name keeps is former value.
 	 * </i></p>
-	 * 
+	 *
 	 * @param name	The new database name of this column.
 	 */
-	public final void setDBName(String name){
+	public final void setDBName(String name) {
 		name = (name != null) ? name.trim() : name;
 		if (name != null && name.length() > 0)
 			dbName = name;
@@ -554,26 +593,27 @@ public class TAPColumn implements DBColumn {
 	}
 
 	@Override
-	public final DBTable getTable(){
+	public final DBTable getTable() {
 		return table;
 	}
 
 	/**
-	 * <p>Set the table in which this column is.</p>
-	 * 
+	 * Set the table in which this column is.
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPTable}
-	 * 	that owns this column.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPTable} that owns this column.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
-	 * 	If this column was already linked with another {@link TAPTable} object, the previous link is removed
-	 * 	here, but also in the table (by calling {@link TAPTable#removeColumn(String)}).
+	 * 	If this column was already linked with another {@link TAPTable} object,
+	 * 	the previous link is removed here, but also in the table (by calling
+	 * 	{@link TAPTable#removeColumn(String)}).
 	 * </i></p>
-	 * 
+	 *
 	 * @param table	The table that owns this column.
 	 */
-	protected final void setTable(final DBTable table){
+	protected final void setTable(final DBTable table) {
 		if (this.table != null && this.table instanceof TAPTable && (table == null || !table.equals(this.table)))
 			((TAPTable)this.table).removeColumn(adqlName);
 		this.table = table;
@@ -581,96 +621,97 @@ public class TAPColumn implements DBColumn {
 
 	/**
 	 * Get the description of this column.
-	 * 
+	 *
 	 * @return	Its description. <i>MAY be NULL</i>
 	 */
-	public final String getDescription(){
+	public final String getDescription() {
 		return description;
 	}
 
 	/**
 	 * Set the description of this column.
-	 * 
+	 *
 	 * @param description	Its new description. <i>MAY be NULL</i>
 	 */
-	public final void setDescription(String description){
+	public final void setDescription(String description) {
 		this.description = description;
 	}
 
 	/**
 	 * Get the unit of the column's values.
-	 * 
+	 *
 	 * @return	Its unit. <i>MAY be NULL</i>
 	 */
-	public final String getUnit(){
+	public final String getUnit() {
 		return unit;
 	}
 
 	/**
 	 * Set the unit of the column's values.
-	 * 
+	 *
 	 * @param unit	Its new unit. <i>MAY be NULL</i>
 	 */
-	public final void setUnit(String unit){
+	public final void setUnit(String unit) {
 		this.unit = unit;
 	}
 
 	/**
 	 * Get the UCD describing the scientific content of this column.
-	 * 
+	 *
 	 * @return	Its UCD. <i>MAY be NULL</i>
 	 */
-	public final String getUcd(){
+	public final String getUcd() {
 		return ucd;
 	}
 
 	/**
 	 * Set the UCD describing the scientific content of this column.
-	 * 
+	 *
 	 * @param ucd	Its new UCD. <i>MAY be NULL</i>
 	 */
-	public final void setUcd(String ucd){
+	public final void setUcd(String ucd) {
 		this.ucd = ucd;
 	}
 
 	/**
 	 * Get the UType associating this column with a data-model.
-	 * 
+	 *
 	 * @return	Its UType. <i>MAY be NULL</i>
 	 */
-	public final String getUtype(){
+	public final String getUtype() {
 		return utype;
 	}
 
 	/**
 	 * Set the UType associating this column with a data-model.
-	 * 
+	 *
 	 * @param utype	Its new UType. <i>MAY be NULL</i>
 	 */
-	public final void setUtype(String utype){
+	public final void setUtype(String utype) {
 		this.utype = utype;
 	}
 
 	/**
 	 * Get the type of the column's values.
-	 * 
+	 *
 	 * @return	Its datatype. <i>CAN'T be NULL</i>
 	 */
 	@Override
-	public final DBType getDatatype(){
+	public final DBType getDatatype() {
 		return datatype;
 	}
 
 	/**
-	 * <p>Set the type of the column's values.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given type is NULL, an {@link DBDatatype#UNKNOWN UNKNOWN} type will be set instead.
+	 * Set the type of the column's values.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	If the given type is NULL, an {@link DBDatatype#UNKNOWN UNKNOWN} type
+	 * 	will be set instead.
 	 * </i></p>
-	 * 
+	 *
 	 * @param type	Its new datatype.
 	 */
-	public final void setDatatype(final DBType type){
+	public final void setDatatype(final DBType type) {
 		if (type != null)
 			datatype = type;
 		else
@@ -679,299 +720,321 @@ public class TAPColumn implements DBColumn {
 
 	/**
 	 * Tell whether this column is one of those returned by default.
-	 * 
-	 * @return	<i>true</i> if this column should be returned by default, <i>false</i> otherwise.
+	 *
+	 * @return	<code>true</code> if this column should be returned by default,
+	 *        	<code>false</code> otherwise.
 	 */
-	public final boolean isPrincipal(){
+	public final boolean isPrincipal() {
 		return principal;
 	}
 
 	/**
 	 * Set whether this column should be one of those returned by default.
-	 * 
-	 * @param  principal	<i>true</i> if this column should be returned by default, <i>false</i> otherwise.
+	 *
+	 * @param principal	<code>true</code> if this column should be returned by
+	 *                 	default,
+	 *                 	<code>false</code> otherwise.
 	 */
-	public final void setPrincipal(boolean principal){
+	public final void setPrincipal(boolean principal) {
 		this.principal = principal;
 	}
 
 	/**
 	 * Tell whether this column is indexed.
-	 * 
-	 * @return	<i>true</i> if this column is indexed, <i>false</i> otherwise.
+	 *
+	 * @return	<code>true</code> if this column is indexed,
+	 *        	<code>false</code> otherwise.
 	 */
-	public final boolean isIndexed(){
+	public final boolean isIndexed() {
 		return indexed;
 	}
 
 	/**
 	 * Set whether this column is indexed or not.
-	 * 
-	 * @param  indexed	<i>true</i> if this column is indexed, <i>false</i> otherwise.
+	 *
+	 * @param indexed	<code>true</code> if this column is indexed,
+	 *               	<code>false</code> otherwise.
 	 */
-	public final void setIndexed(boolean indexed){
+	public final void setIndexed(boolean indexed) {
 		this.indexed = indexed;
 	}
 
 	/**
 	 * Tell whether this column is nullable.
-	 * 
-	 * @return	<i>true</i> if this column is nullable, <i>false</i> otherwise.
-	 * 
+	 *
+	 * @return	<code>true</code> if this column is nullable,
+	 *        	<code>false</code> otherwise.
+	 *
 	 * @since 2.0
 	 */
-	public final boolean isNullable(){
+	public final boolean isNullable() {
 		return nullable;
 	}
 
 	/**
 	 * Set whether this column is nullable or not.
-	 * 
-	 * @param  nullable	<i>true</i> if this column is nullable, <i>false</i> otherwise.
-	 * 
+	 *
+	 * @param nullable	<code>true</code> if this column is nullable,
+	 *                	<code>false</code> otherwise.
+	 *
 	 * @since 2.0
 	 */
-	public final void setNullable(boolean nullable){
+	public final void setNullable(boolean nullable) {
 		this.nullable = nullable;
 	}
 
 	/**
 	 * Tell whether this column is defined by a standard.
-	 * 
-	 * @return	<i>true</i> if this column is defined by a standard, <i>false</i> otherwise.
+	 *
+	 * @return	<code>true</code> if this column is defined by a standard,
+	 *        	<code>false</code> otherwise.
 	 */
-	public final boolean isStd(){
+	public final boolean isStd() {
 		return std;
 	}
 
 	/**
 	 * Set whether this column is defined by a standard.
-	 * 
-	 * @param  std	<i>true</i> if this column is defined by a standard, <i>false</i> otherwise.
+	 *
+	 * @param std	<code>true</code> if this column is defined by a standard,
+	 *            	<code>false</code> otherwise.
 	 */
-	public final void setStd(boolean std){
+	public final void setStd(boolean std) {
 		this.std = std;
 	}
 
 	/**
 	 * Get the ordering index of this column inside its table.
-	 * 
+	 *
 	 * @return	Its ordering index.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final int getIndex(){
+	public final int getIndex() {
 		return index;
 	}
 
 	/**
 	 * Set the ordering index of this column inside its table.
-	 * 
+	 *
 	 * @param columnIndex	Its new ordering index.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final void setIndex(int columnIndex){
+	public final void setIndex(int columnIndex) {
 		this.index = columnIndex;
 	}
 
 	/**
 	 * Get the used coordinate system.
-	 * 
+	 *
 	 * @return	Its coordinate system.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final TAPCoosys getCoosys(){
+	public final TAPCoosys getCoosys() {
 		return coosys;
 	}
 
 	/**
 	 * Set the the coordinate system to use.
-	 * 
+	 *
 	 * @param newCoosys	Its new coordinate system.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final void setCoosys(final TAPCoosys newCoosys){
+	public final void setCoosys(final TAPCoosys newCoosys) {
 		this.coosys = newCoosys;
 	}
 
 	/**
-	 * <p>Get the other (piece of) information associated with this column.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	By default, NULL is returned, but it may be any kind of value ({@link Integer},
-	 * 	{@link String}, {@link Map}, {@link List}, ...).
+	 * Get the other (piece of) information associated with this column.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	By default, NULL is returned, but it may be any kind of value
+	 * 	({@link Integer}, {@link String}, {@link Map}, {@link List}, ...).
 	 * </i></p>
-	 * 
+	 *
 	 * @return	The other (piece of) information. <i>MAY be NULL</i>
 	 */
-	public Object getOtherData(){
+	public Object getOtherData() {
 		return otherData;
 	}
 
 	/**
 	 * Set the other (piece of) information associated with this column.
-	 * 
+	 *
 	 * @param data	Another information about this column. <i>MAY be NULL</i>
 	 */
-	public void setOtherData(Object data){
+	public void setOtherData(Object data) {
 		otherData = data;
 	}
 
 	/**
-	 * <p>Let add a foreign key in which this column is a source (= which is targeting another column).</p>
-	 * 
-	 * <p><i>Note:
+	 * Let add a foreign key in which this column is a source (= which is
+	 * targeting another column).
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	Nothing is done if the given value is NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPTable}
-	 * 	that owns this column or that is part of the foreign key.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPTable} that owns this column or that is part of the foreign
+	 * 	key.
 	 * </i></p>
-	 * 
+	 *
 	 * @param key	A foreign key.
 	 */
-	protected void addTarget(TAPForeignKey key){
+	protected void addTarget(TAPForeignKey key) {
 		if (key != null)
 			lstTargets.add(key);
 	}
 
 	/**
 	 * Get the number of times this column is targeting another column.
-	 * 
+	 *
 	 * @return	How many this column is source in a foreign key.
 	 */
-	public int getNbTargets(){
+	public int getNbTargets() {
 		return lstTargets.size();
 	}
 
 	/**
-	 * Get the list of foreign keys in which this column is a source (= is targeting another column).
-	 * 
+	 * Get the list of foreign keys in which this column is a source
+	 * (= is targeting another column).
+	 *
 	 * @return	List of foreign keys in which this column is a source.
 	 */
-	public Iterator<TAPForeignKey> getTargets(){
+	public Iterator<TAPForeignKey> getTargets() {
 		return lstTargets.iterator();
 	}
 
 	/**
-	 * <p>Remove the fact that this column is a source (= is targeting another column)
-	 * in the given foreign key.</p>
-	 * 
-	 * <p><i>Note:
+	 * Remove the fact that this column is a source (= is targeting another
+	 * column) in the given foreign key.
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	Nothing is done if the given value is NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPTable}
-	 * 	that owns this column or that is part of the foreign key.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPTable} that owns this column or that is part of the foreign
+	 * 	key.
 	 * </i></p>
-	 * 
-	 * @param key	Foreign key in which this column was targeting another column.
+	 *
+	 * @param key	Foreign key in which this column was targeting another
+	 *           	column.
 	 */
-	protected void removeTarget(TAPForeignKey key){
+	protected void removeTarget(TAPForeignKey key) {
 		if (key != null)
 			lstTargets.remove(key);
 	}
 
 	/**
-	 * <p>Remove the fact that this column is a source (= is targeting another column)
-	 * in any foreign key in which it was.</p>
-	 * 
+	 * Remove the fact that this column is a source (= is targeting another
+	 * column) in any foreign key in which it was.
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPTable}
-	 * 	that owns this column or that is part of the foreign key.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPTable} that owns this column or that is part of the foreign
+	 * 	key.
 	 * </i></p>
 	 */
-	protected void removeAllTargets(){
+	protected void removeAllTargets() {
 		lstTargets.clear();
 	}
 
 	/**
-	 * <p>Let add a foreign key in which this column is a target (= which is targeted by another column).</p>
-	 * 
-	 * <p><i>Note:
+	 * Let add a foreign key in which this column is a target (= which is
+	 * targeted by another column).
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	Nothing is done if the given value is NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPTable}
-	 * 	that owns this column or that is part of the foreign key.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPTable} that owns this column or that is part of the foreign
+	 * 	key.
 	 * </i></p>
-	 * 
+	 *
 	 * @param key	A foreign key.
 	 */
-	protected void addSource(TAPForeignKey key){
+	protected void addSource(TAPForeignKey key) {
 		if (key != null)
 			lstSources.add(key);
 	}
 
 	/**
 	 * Get the number of times this column is targeted by another column.
-	 * 
+	 *
 	 * @return	How many this column is target in a foreign key.
 	 */
-	public int getNbSources(){
+	public int getNbSources() {
 		return lstSources.size();
 	}
 
 	/**
-	 * Get the list of foreign keys in which this column is a target (= is targeted another column).
-	 * 
+	 * Get the list of foreign keys in which this column is a target (= is
+	 * targeted another column).
+	 *
 	 * @return	List of foreign keys in which this column is a target.
 	 */
-	public Iterator<TAPForeignKey> getSources(){
+	public Iterator<TAPForeignKey> getSources() {
 		return lstSources.iterator();
 	}
 
 	/**
-	 * <p>Remove the fact that this column is a target (= is targeted by another column)
-	 * in the given foreign key.</p>
-	 * 
-	 * <p><i>Note:
+	 * Remove the fact that this column is a target (= is targeted by another
+	 * column) in the given foreign key.
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	Nothing is done if the given value is NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPTable}
-	 * 	that owns this column or that is part of the foreign key.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPTable} that owns this column or that is part of the foreign
+	 * 	key.
 	 * </i></p>
-	 * 
-	 * @param key	Foreign key in which this column was targeted by another column.
+	 *
+	 * @param key	Foreign key in which this column was targeted by another
+	 *           	column.
 	 */
-	protected void removeSource(TAPForeignKey key){
+	protected void removeSource(TAPForeignKey key) {
 		lstSources.remove(key);
 	}
 
 	/**
-	 * <p>Remove the fact that this column is a target (= is targeted by another column)
-	 * in any foreign key in which it was.</p>
-	 * 
+	 * Remove the fact that this column is a target (= is targeted by
+	 * another column) in any foreign key in which it was.
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPTable}
-	 * 	that owns this column or that is part of the foreign key.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPTable} that owns this column or that is part of the foreign
+	 * 	key.
 	 * </i></p>
 	 */
-	protected void removeAllSources(){
+	protected void removeAllSources() {
 		lstSources.clear();
 	}
 
 	/**
 	 * <p><i><b>Warning:</b>
 	 * 	Since the type of the other data is not known, the copy of its value
-	 * 	can not be done properly. So, this column and its copy will share the same other data object.
-	 * 	If it is also needed to make a deep copy of this other data object, this function MUST be
-	 * 	overridden.
+	 * 	can not be done properly. So, this column and its copy will share the
+	 * 	same other data object. If it is also needed to make a deep copy of this
+	 * 	other data object, this function MUST be overridden.
 	 * </i></b>
-	 * 
+	 *
 	 * @see adql.db.DBColumn#copy(java.lang.String, java.lang.String, adql.db.DBTable)
 	 */
 	@Override
-	public DBColumn copy(final String dbName, final String adqlName, final DBTable dbTable){
+	public DBColumn copy(final String dbName, final String adqlName, final DBTable dbTable) {
 		TAPColumn copy = new TAPColumn((adqlName == null) ? this.adqlName : adqlName, datatype, description, unit, ucd, utype);
+		copy.columnCaseSensitive = this.columnCaseSensitive;
 		copy.setDBName((dbName == null) ? this.getDBName() : dbName);
 		copy.setTable(dbTable);
 
@@ -984,19 +1047,20 @@ public class TAPColumn implements DBColumn {
 	}
 
 	/**
-	 * <p>Provide a deep copy (included the other data) of this column.</p>
-	 * 
+	 * Provide a deep copy (included the other data) of this column.
+	 *
 	 * <p><i><b>Warning:</b>
 	 * 	Since the type of the other data is not known, the copy of its value
-	 * 	can not be done properly. So, this column and its copy will share the same other data object.
-	 * 	If it is also needed to make a deep copy of this other data object, this function MUST be
-	 * 	overridden.
+	 * 	can not be done properly. So, this column and its copy will share the
+	 * 	same other data object. If it is also needed to make a deep copy of this
+	 * 	other data object, this function MUST be overridden.
 	 * </i></b>
-	 * 
+	 *
 	 * @return	The deep copy of this column.
 	 */
-	public DBColumn copy(){
+	public DBColumn copy() {
 		TAPColumn copy = new TAPColumn(adqlName, datatype, description, unit, ucd, utype);
+		copy.columnCaseSensitive = this.columnCaseSensitive;
 		copy.setDBName(dbName);
 		copy.setTable(table);
 		copy.setIndexed(indexed);
@@ -1007,17 +1071,17 @@ public class TAPColumn implements DBColumn {
 	}
 
 	@Override
-	public boolean equals(Object obj){
+	public boolean equals(Object obj) {
 		if (!(obj instanceof TAPColumn))
 			return false;
 
 		TAPColumn col = (TAPColumn)obj;
-		return col.getTable().equals(table) && col.getADQLName().equals(adqlName);
+		return col.getTable().equals(table) && col.getADQLName().equals(adqlName) && col.columnCaseSensitive == this.columnCaseSensitive;
 	}
 
 	@Override
-	public String toString(){
-		return ((table != null) ? (((table.getADQLSchemaName() != null) ? table.getADQLSchemaName() : "") + table.getADQLName() + ".") : "") + getADQLName();
+	public String toString() {
+		return (table != null ? table.toString() : "") + getRawName();
 	}
 
 }
diff --git a/src/tap/metadata/TAPSchema.java b/src/tap/metadata/TAPSchema.java
index e22514159eb80ca97b7a314499dc18a113588440..f1e6e0c3c33f721f6096be44d6ea392f511f4430 100644
--- a/src/tap/metadata/TAPSchema.java
+++ b/src/tap/metadata/TAPSchema.java
@@ -2,21 +2,21 @@ package tap.metadata;
 
 /*
  * 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-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
+ *
+ * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -25,176 +25,200 @@ import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+import adql.db.DefaultDBTable;
 import tap.metadata.TAPTable.TableType;
 
 /**
- * <p>Represent a schema as described by the IVOA standard in the TAP protocol definition.</p>
- * 
+ * Represent a schema as described by the IVOA standard in the TAP protocol
+ * definition.
+ *
  * <p>
- * 	This object representation has exactly the same fields as the column of the table TAP_SCHEMA.schemas.
- * 	But it also provides a way to add other data. For instance, if information not listed in the standard
- * 	may be stored here, they can be using the function {@link #setOtherData(Object)}. This object can be
- * 	a single value (integer, string, ...), but also a {@link Map}, {@link List}, etc...
+ * 	This object representation has exactly the same fields as the column of the
+ * 	table TAP_SCHEMA.schemas. But it also provides a way to add other data. For
+ * 	instance, if information not listed in the standard may be stored here, they
+ * 	can be using the function {@link #setOtherData(Object)}. This object can be
+ * 	a single value (integer, string, ...), but also a {@link Map}, {@link List},
+ * 	etc...
  * </p>
- * 
- * <p><i>Note:
- * 	On the contrary to {@link TAPColumn} and {@link TAPTable}, a {@link TAPSchema} object MAY have no DB name.
- * 	But by default, at the creation the DB name is the simplified ADQL name (i.e. as it is returned by {@link #getADQLName()}).
- * 	Once created, it is possible to set the DB name with {@link #setDBName(String)}. This DB name MAY be qualified,
- * 	BUT MUST BE without double quotes.
+ *
+ * <p><i><b>Note:</b>
+ * 	On the contrary to {@link TAPColumn} and {@link TAPTable}, a
+ * 	{@link TAPSchema} object MAY have no DB name. But by default, at the
+ * 	creation the DB name is the simplified ADQL name (i.e. as it is returned by
+ * 	{@link #getADQLName()}). Once created, it is possible to set the DB name
+ * 	with {@link #setDBName(String)}. This DB name MAY be qualified, BUT MUST BE
+ * 	without double quotes.
  * </i></p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.1 (07/2016)
+ * @version 2.4 (09/2019)
  */
 public class TAPSchema implements Iterable<TAPTable> {
 
 	/** Name that this schema MUST have in ADQL queries. */
 	private final String adqlName;
 
-	/** Indicates whether the given ADQL name must be simplified by {@link #getADQLName()}.
-	 * <p>Here, "simplification" means removing the surrounding double quotes.
-	 * Since there is no information on the catalog name, none can be detected and so removed.</p>
-	 * @since 2.1 */
-	private final boolean simplificationNeeded;
+	/** Indicate whether the ADQL schema name must be considered as case
+	 * sensitive. In such case, it should be provided between double quotes in
+	 * the constructor parameter.
+	 * @since 2.4 */
+	private boolean schemaCaseSensitive;
 
 	/** Name that this schema have in the database.
-	 * <i>Note: NULL by default. When NULL, {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	NULL by default. When NULL, {@link #getDBName()} returns exactly what
+	 * 	{@link #getADQLName()} returns.
+	 * </i></p> */
 	private String dbName = null;
 
 	/** Descriptive, human-interpretable name of the schema.
-	 * <i>Note: Standard TAP schema field ; MAY be NULL.</i>
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP schema field ; MAY be NULL.
+	 * </i></p>
 	 * @since 2.0 */
 	private String title = null;
 
 	/** Description of this schema.
-	 * <i>Note: Standard TAP schema field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP schema field ; MAY be NULL.
+	 * </i></p> */
 	private String description = null;
 
 	/** UType describing the scientific content of this schema.
-	 * <i>Note: Standard TAP schema field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP schema field ; MAY be NULL.
+	 * </i></p> */
 	private String utype = null;
 
 	/** Ordering index of this schema inside its whole schema set.
-	 * <i>Note: SHOULD be a standard TAP schema field in TAP 1.1, as table_index and column_index are resp. in TAP_SCHEMA.tables and TAP_SCHEMA.columns.</i>
+	 * <p><i><b>Note:</b>
+	 * 	SHOULD be a standard TAP schema field in TAP 1.1, as table_index and
+	 * 	column_index are resp. in TAP_SCHEMA.tables and TAP_SCHEMA.columns.
+	 * </i></p>
 	 * @since 2.1 */
 	private int index = -1;
 
 	/** Let add some information in addition of the ones of the TAP protocol.
-	 * <i>Note: This object can be anything: an {@link Integer}, a {@link String}, a {@link Map}, a {@link List}, ...
-	 * Its content is totally free and never used or checked.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	This object can be anything: an {@link Integer}, a {@link String}, a
+	 * 	{@link Map}, a {@link List}, ... Its content is totally free and never
+	 * 	used or checked.
+	 * </i></p> */
 	protected Object otherData = null;
 
 	/** List all tables contained inside this schema. */
-	protected final Map<String,TAPTable> tables;
+	protected final Map<String, TAPTable> tables;
 
 	/**
-	 * <p>Build a {@link TAPSchema} instance with the given ADQL name.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default to the ADQL name (as returned by {@link #getADQLName()}).
-	 * 	To set the DB name, you MUST call then {@link #setDBName(String)}.
+	 * Build a {@link TAPSchema} instance with the given ADQL name.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The DB name is set by default to the ADQL name (as returned by
+	 * 	{@link #getADQLName()}). To set the DB name, you MUST call then
+	 * 	{@link #setDBName(String)}.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		No catalog prefix is supported. <i>For instance: <code>myCatalog.mySchema</code> will be considered
-	 * 		as the schema name instead of <code>mySchema</code>.</i>
+	 * 		No catalog prefix is supported. <i>For instance:
+	 * 		<code>myCatalog.mySchema</code> will be considered as the schema
+	 * 		name instead of <code>mySchema</code>.</i>
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the ADQL name. They will be removed by {@link #getADQLName()} but will
-	 * 		still appear in the result of {@link #getRawName()}.
+	 * 		Double quotes may surround the ADQL name. They will be removed by
+	 * 		{@link #getADQLName()} but will still appear in the result of
+	 * 		{@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param schemaName	Name that this schema MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
+	 *
+	 * @param schemaName	ADQL name of this schema.
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
 	 */
-	public TAPSchema(String schemaName) throws NullPointerException{
+	public TAPSchema(String schemaName) throws NullPointerException {
 		if (schemaName == null)
 			throw new NullPointerException("Missing schema name!");
 
-		adqlName = schemaName.trim();
-		simplificationNeeded = adqlName.matches("\"[^\"]*\"");
+		schemaName = schemaName.trim();
+		schemaCaseSensitive = DefaultDBTable.isDelimited(schemaName);
+		adqlName = (schemaCaseSensitive ? schemaName.substring(1, schemaName.length() - 1).replaceAll("\"\"", "\"") : schemaName);
 
-		if (getADQLName().length() == 0)
+		if (getADQLName().trim().length() == 0)
 			throw new NullPointerException("Missing schema name!");
 
 		dbName = getADQLName();
 
-		tables = new LinkedHashMap<String,TAPTable>();
+		tables = new LinkedHashMap<String, TAPTable>();
 	}
 
 	/**
-	 * <p>Build a {@link TAPSchema} instance with the given ADQL name and description.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default to the ADQL name (as returned by {@link #getADQLName()}).
-	 * 	To set the DB name, you MUST call then {@link #setDBName(String)}.
+	 * Build a {@link TAPSchema} instance with the given ADQL name and
+	 * description.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The DB name is set by default to the ADQL name (as returned by
+	 * 	{@link #getADQLName()}). To set the DB name, you MUST call then
+	 * 	{@link #setDBName(String)}.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		No catalog prefix is supported. <i>For instance: <code>myCatalog.mySchema</code> will be considered
-	 * 		as the schema name instead of <code>mySchema</code>.</i>
+	 * 		No catalog prefix is supported. <i>For instance:
+	 * 		<code>myCatalog.mySchema</code> will be considered as the schema
+	 * 		name instead of <code>mySchema</code>.</i>
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the ADQL name. They will be removed by {@link #getADQLName()} but will
-	 * 		still appear in the result of {@link #getRawName()}.
+	 * 		Double quotes may surround the ADQL name. They will be removed by
+	 * 		{@link #getADQLName()} but will still appear in the result of
+	 * 		{@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param schemaName	Name that this schema MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
+	 *
+	 * @param schemaName	ADQL name of this schema.
 	 * @param description	Description of this schema. <i>MAY be NULL</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
 	 */
-	public TAPSchema(String schemaName, String description) throws NullPointerException{
+	public TAPSchema(final String schemaName, final String description) throws NullPointerException {
 		this(schemaName, description, null);
 	}
 
 	/**
-	 * <p>Build a {@link TAPSchema} instance with the given ADQL name, description and UType.</p>
-	 * 
-	 * <p><i>Note:
+	 * Build a {@link TAPSchema} instance with the given ADQL name,
+	 * description and UType.
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	The DB name is set by default to the ADQL name (as returned by {@link #getADQLName()}).
 	 * 	To set the DB name, you MUST call then {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		No catalog prefix is supported. <i>For instance: <code>myCatalog.mySchema</code> will be considered
-	 * 		as the schema name instead of <code>mySchema</code>.</i>
+	 * 		No catalog prefix is supported. <i>For instance:
+	 * 		<code>myCatalog.mySchema</code> will be considered as the schema
+	 * 		name instead of <code>mySchema</code>.</i>
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the ADQL name. They will be removed by {@link #getADQLName()} but will
-	 * 		still appear in the result of {@link #getRawName()}.
+	 * 		Double quotes may surround the ADQL name. They will be removed by
+	 * 		{@link #getADQLName()} but will still appear in the result of
+	 * 		{@link #getRawName()}.
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param schemaName	Name that this schema MUST have in ADQL queries.
-	 *                  	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
+	 *
+	 * @param schemaName	ADQL name of this schema.
 	 * @param description	Description of this schema. <i>MAY be NULL</i>
-	 * @param utype			UType associating this schema with a data-model. <i>MAY be NULL</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
+	 * @param utype			UType associating this schema with a data-model.
+	 *             			<i>MAY be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
 	 */
-	public TAPSchema(String schemaName, String description, String utype) throws NullPointerException{
+	public TAPSchema(final String schemaName, final String description, final String utype) throws NullPointerException {
 		this(schemaName);
 		this.description = description;
 		this.utype = utype;
@@ -202,191 +226,214 @@ public class TAPSchema implements Iterable<TAPTable> {
 
 	/**
 	 * Get the ADQL name (the name this schema MUST have in ADQL queries).
-	 * 
+	 *
 	 * @return	Its ADQL name.
 	 * @see #getADQLName()
 	 * @deprecated	Does not do anything special: just call {@link #getADQLName()}.
 	 */
 	@Deprecated
-	public final String getName(){
+	public final String getName() {
 		return getADQLName();
 	}
 
 	/**
-	 * Get the name of this schema.
-	 * 
-	 * <p><i>Note:
-	 * 	If a simplification is needed, the double quotes surrounding the ADQL name, will be removed.
-	 * </i></p>
-	 * 
-	 * @return	Its ADQL name. <i>CAN'T be NULL</i>
+	 * Get the (non delimited) ADQL name of this schema.
+	 *
+	 * @return	Its ADQL name.
 	 */
-	public final String getADQLName(){
-		return simplificationNeeded ? adqlName.substring(1, adqlName.length() - 1) : adqlName;
+	public final String getADQLName() {
+		return adqlName;
 	}
 
 	/**
-	 * Get the full ADQL name of this schema, as it has been provided at initialization.
-	 * 
+	 * Get the full ADQL name of this schema, as it has been provided at
+	 * initialization (i.e. delimited if {@link #isCaseSensitive() case sensitive}).
+	 *
 	 * @return	Get the original ADQL name.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final String getRawName(){
-		return adqlName;
+	public final String getRawName() {
+		return toString();
+	}
+
+	/**
+	 * Tell whether the ADQL name of this schema should be considered as case
+	 * sensitive or not.
+	 *
+	 * @return	<code>true</code> if the ADQL name is case sensitive,
+	 *        	<code>false</code> otherwise.
+	 */
+	public final boolean isCaseSensitive() {
+		return schemaCaseSensitive;
+	}
+
+	/**
+	 * Let specify whether the ADQL name of this schema should be considered as
+	 * case sensitive or not.
+	 *
+	 * @param sensitive	<code>true</code> to make the ADQL name case sensitive,
+	 *                 	<code>false</code> otherwise.
+	 */
+	public final void setCaseSensitive(final boolean sensitive) {
+		schemaCaseSensitive = sensitive;
 	}
 
 	/**
 	 * Get the name this schema MUST have in the database.
-	 * 
+	 *
 	 * @return	Its DB name. <i>MAY be NULL</i>
 	 */
-	public final String getDBName(){
+	public final String getDBName() {
 		return dbName;
 	}
 
 	/**
 	 * Set the name this schema MUST have in the database.
-	 * 
-	 * <p>Notes:</p>
+	 *
+	 * <i>
+	 * <p><b>Notes:</b></p>
 	 * <ul>
-	 * 	<li>The given name may be NULL. In such case {@link #getDBName()} will then return NULL.</li>
+	 * 	<li>The given name may be NULL. In such case {@link #getDBName()} will
+	 * 		then return NULL.</li>
 	 * 	<li>It may be prefixed by a catalog name.</li>
 	 * 	<li>
-	 * 		It MUST be NON delimited/double-quoted. Otherwise an SQL error will be raised when
-	 * 		querying any item of this schema because the library double-quotes systematically the
-	 * 		DB name of schemas, tables and columns.
+	 * 		It MUST be NON delimited/double-quoted. Otherwise an SQL error will
+	 * 		be raised when querying any item of this schema because the library
+	 * 		double-quotes systematically the DB name of schemas, tables and
+	 * 		columns.
 	 *	</li>
 	 * </ul>
-	 * 
+	 * </i>
+	 *
 	 * @param name	Its new DB name. <i>MAY be NULL</i>
 	 */
-	public final void setDBName(String name){
+	public final void setDBName(String name) {
 		name = (name != null) ? name.trim() : name;
 		dbName = name;
 	}
 
 	/**
 	 * Get the title of this schema.
-	 * 
+	 *
 	 * @return	Its title. <i>MAY be NULL</i>
-	 * 
+	 *
 	 * @since 2.0
 	 */
-	public final String getTitle(){
+	public final String getTitle() {
 		return title;
 	}
 
 	/**
 	 * Set the title of this schema.
-	 * 
+	 *
 	 * @param title	Its new title. <i>MAY be NULL</i>
-	 * 
+	 *
 	 * @since 2.0
 	 */
-	public final void setTitle(final String title){
+	public final void setTitle(final String title) {
 		this.title = title;
 	}
 
 	/**
 	 * Get the description of this schema.
-	 * 
+	 *
 	 * @return	Its description. <i>MAY be NULL</i>
 	 */
-	public final String getDescription(){
+	public final String getDescription() {
 		return description;
 	}
 
 	/**
 	 * Set the description of this schema.
-	 * 
+	 *
 	 * @param description	Its new description. <i>MAY be NULL</i>
 	 */
-	public final void setDescription(String description){
+	public final void setDescription(String description) {
 		this.description = description;
 	}
 
 	/**
 	 * Get the UType associating this schema with a data-model.
-	 * 
+	 *
 	 * @return	Its UType. <i>MAY be NULL</i>
 	 */
-	public final String getUtype(){
+	public final String getUtype() {
 		return utype;
 	}
 
 	/**
 	 * Set the UType associating this schema with a data-model.
-	 * 
+	 *
 	 * @param utype	Its new UType. <i>MAY be NULL</i>
 	 */
-	public final void setUtype(String utype){
+	public final void setUtype(String utype) {
 		this.utype = utype;
 	}
 
 	/**
 	 * Get the ordering index of this schema inside its whole schema set.
-	 * 
+	 *
 	 * @return	Its ordering index.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final int getIndex(){
+	public final int getIndex() {
 		return index;
 	}
 
 	/**
 	 * Set the ordering index of this schema inside its whole schema set.
-	 * 
+	 *
 	 * @param schemaIndex	Its new ordering index.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final void setIndex(int schemaIndex){
+	public final void setIndex(int schemaIndex) {
 		this.index = schemaIndex;
 	}
 
 	/**
 	 * <p>Get the other (piece of) information associated with this schema.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	By default, NULL is returned, but it may be any kind of value ({@link Integer},
 	 * 	{@link String}, {@link Map}, {@link List}, ...).
 	 * </i></p>
-	 * 
+	 *
 	 * @return	The other (piece of) information. <i>MAY be NULL</i>
 	 */
-	public Object getOtherData(){
+	public Object getOtherData() {
 		return otherData;
 	}
 
 	/**
 	 * Set the other (piece of) information associated with this schema.
-	 * 
+	 *
 	 * @param data	Another information about this schema. <i>MAY be NULL</i>
 	 */
-	public void setOtherData(Object data){
+	public void setOtherData(Object data) {
 		otherData = data;
 	}
 
 	/**
 	 * <p>Add the given table inside this schema.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	If the given table is NULL, nothing will be done.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	By adding the given table inside this schema, it
 	 * 	will be linked with this schema using {@link TAPTable#setSchema(TAPSchema)}.
 	 * 	In this function, if the table was already linked with another {@link TAPSchema},
 	 * 	the former link is removed using {@link TAPSchema#removeTable(String)}.
 	 * </i></p>
-	 * 
+	 *
 	 * @param newTable	Table to add inside this schema.
 	 */
-	public final void addTable(TAPTable newTable){
-		if (newTable != null && newTable.getADQLName() != null){
+	public final void addTable(TAPTable newTable) {
+		if (newTable != null && newTable.getADQLName() != null) {
 			newTable.setSchema(this);
 			tables.put(newTable.getADQLName(), newTable);
 		}
@@ -395,20 +442,20 @@ public class TAPSchema implements Iterable<TAPTable> {
 	/**
 	 * <p>Build a {@link TAPTable} object whose the ADQL and DB name will the given one.
 	 * Then, add this table inside this schema.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	The built {@link TAPTable} object is returned, so that being modified afterwards if needed.
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableName	ADQL name (and indirectly also the DB name) of the table to create and add.
-	 * 
+	 *
 	 * @return	The created and added {@link TAPTable} object,
 	 *        	or NULL if the given name is NULL or an empty string.
-	 * 
+	 *
 	 * @see TAPTable#TAPTable(String)
 	 * @see #addTable(TAPTable)
 	 */
-	public TAPTable addTable(String tableName){
+	public TAPTable addTable(String tableName) {
 		if (tableName == null)
 			return null;
 
@@ -420,23 +467,23 @@ public class TAPSchema implements Iterable<TAPTable> {
 	/**
 	 * <p>Build a {@link TAPTable} object whose the ADQL and DB name will the given one.
 	 * Then, add this table inside this schema.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	The built {@link TAPTable} object is returned, so that being modified afterwards if needed.
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableName		ADQL name (and indirectly also the DB name) of the table to create and add.
 	 * @param tableType		Type of the new table. <i>If NULL, "table" will be the type of the created table.</i>
 	 * @param description	Description of the new table. <i>MAY be NULL</i>
 	 * @param utype			UType associating the new column with a data-model. <i>MAY be NULL</i>
-	 * 
+	 *
 	 * @return	The created and added {@link TAPTable} object,
 	 *        	or NULL if the given name is NULL or an empty string.
-	 * 
+	 *
 	 * @see TAPTable#TAPTable(String, TableType, String, String)
 	 * @see #addTable(TAPTable)
 	 */
-	public TAPTable addTable(String tableName, TableType tableType, String description, String utype){
+	public TAPTable addTable(String tableName, TableType tableType, String description, String utype) {
 		if (tableName == null)
 			return null;
 
@@ -448,16 +495,16 @@ public class TAPSchema implements Iterable<TAPTable> {
 
 	/**
 	 * <p>Tell whether this schema contains a table having the given ADQL name.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function is case sensitive!
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableName	Name of the table whose the existence in this schema must be checked.
-	 * 
+	 *
 	 * @return	<i>true</i> if a table with the given ADQL name exists, <i>false</i> otherwise.
 	 */
-	public final boolean hasTable(String tableName){
+	public final boolean hasTable(String tableName) {
 		if (tableName == null)
 			return false;
 		else
@@ -466,17 +513,17 @@ public class TAPSchema implements Iterable<TAPTable> {
 
 	/**
 	 * <p>Search for a table having the given ADQL name.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function is case sensitive!
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableName	ADQL name of the table to search.
-	 * 
+	 *
 	 * @return	The table having the given ADQL name,
 	 *        	or NULL if no such table can be found.
 	 */
-	public final TAPTable getTable(String tableName){
+	public final TAPTable getTable(String tableName) {
 		if (tableName == null)
 			return null;
 		else
@@ -485,47 +532,47 @@ public class TAPSchema implements Iterable<TAPTable> {
 
 	/**
 	 * Get the number of all tables contained inside this schema.
-	 * 
+	 *
 	 * @return	Number of its tables.
 	 */
-	public final int getNbTables(){
+	public final int getNbTables() {
 		return tables.size();
 	}
 
 	/**
 	 * Tell whether this schema contains no table.
-	 * 
+	 *
 	 * @return	<i>true</i> if this schema contains no table,
 	 *        	<i>false</i> if it has at least one table.
 	 */
-	public final boolean isEmpty(){
+	public final boolean isEmpty() {
 		return tables.isEmpty();
 	}
 
 	/**
 	 * <p>Remove the table having the given ADQL name.</p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function is case sensitive!
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	If the specified table is removed, its schema link is also deleted.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>WARNING:</b>
 	 * 	If the goal of this function's call is to delete definitely the specified table
 	 * 	from the metadata, you SHOULD also call {@link TAPTable#removeAllForeignKeys()}.
 	 * 	Indeed, foreign keys of the table would still link the removed table with other tables
 	 * 	AND columns of the whole metadata set.
 	 * </i></p>
-	 * 
+	 *
 	 * @param tableName	ADQL name of the table to remove from this schema.
-	 * 
+	 *
 	 * @return	The removed table,
 	 *        	or NULL if no table with the given ADQL name can be found.
 	 */
-	public final TAPTable removeTable(String tableName){
+	public final TAPTable removeTable(String tableName) {
 		if (tableName == null)
 			return null;
 
@@ -537,11 +584,11 @@ public class TAPSchema implements Iterable<TAPTable> {
 
 	/**
 	 * <p>Remove all the tables contained inside this schema.</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	When a table is removed, its schema link is also deleted.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>CAUTION:
 	 * 	If the goal of this function's call is to delete definitely all the tables of this schema
 	 * 	from the metadata, you SHOULD also call {@link TAPTable#removeAllForeignKeys()}
@@ -550,23 +597,23 @@ public class TAPSchema implements Iterable<TAPTable> {
 	 * 	AND columns of the whole metadata set.
 	 * </b></p>
 	 */
-	public final void removeAllTables(){
-		Iterator<Map.Entry<String,TAPTable>> it = tables.entrySet().iterator();
-		while(it.hasNext()){
-			Map.Entry<String,TAPTable> entry = it.next();
+	public final void removeAllTables() {
+		Iterator<Map.Entry<String, TAPTable>> it = tables.entrySet().iterator();
+		while(it.hasNext()) {
+			Map.Entry<String, TAPTable> entry = it.next();
 			it.remove();
 			entry.getValue().setSchema(null);
 		}
 	}
 
 	@Override
-	public Iterator<TAPTable> iterator(){
+	public Iterator<TAPTable> iterator() {
 		return tables.values().iterator();
 	}
 
 	@Override
-	public String toString(){
-		return getADQLName();
+	public String toString() {
+		return (schemaCaseSensitive ? "\"" + adqlName.replaceAll("\"", "\"\"") + "\"" : adqlName);
 	}
 
 }
diff --git a/src/tap/metadata/TAPTable.java b/src/tap/metadata/TAPTable.java
index 02a24027388125c2bfda39483f4d0be583f1c79e..312905ae4da8a0699b6c05e1b95d3a91ee87f6bc 100644
--- a/src/tap/metadata/TAPTable.java
+++ b/src/tap/metadata/TAPTable.java
@@ -2,21 +2,21 @@ package tap.metadata;
 
 /*
  * 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-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
+ *
+ * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -30,352 +30,385 @@ import java.util.Map;
 import adql.db.DBColumn;
 import adql.db.DBTable;
 import adql.db.DBType;
+import adql.db.DefaultDBTable;
 import tap.TAPException;
 
 /**
- * <p>Represent a table as described by the IVOA standard in the TAP protocol definition.</p>
- * 
+ * Represent a table as described by the IVOA standard in the TAP protocol
+ * definition.
+ *
  * <p>
- * 	This object representation has exactly the same fields as the column of the table TAP_SCHEMA.tables.
- * 	But it also provides a way to add other data. For instance, if information not listed in the standard
- * 	may be stored here, they can be using the function {@link #setOtherData(Object)}. This object can be
- * 	a single value (integer, string, ...), but also a {@link Map}, {@link List}, etc...
+ * 	This object representation has exactly the same fields as the column of the
+ * 	table TAP_SCHEMA.tables. But it also provides a way to add other data. For
+ * 	instance, if information not listed in the standard may be stored here, they
+ * 	can be using the function {@link #setOtherData(Object)}. This object can be
+ * 	a single value (integer, string, ...), but also a {@link Map}, {@link List},
+ * 	etc...
  * </p>
- * 
- * <p><i><b>Important note:</b>
- * 	A {@link TAPTable} object MUST always have a DB name. That's why, {@link #getDBName()} returns
- * 	what {@link #getADQLName()} returns when no DB name is set. After creation, it is possible to set
- * 	the DB name with {@link #setDBName(String)}.
- * 	<br/>
- * 	This DB name MUST be UNqualified and without double quotes. If a NULL or empty value is provided,
- * 	{@link #getDBName()} returns what {@link #getADQLName()} returns.
- * </i></p>
- * 
+ *
+ * <i>
+ * <p><b>Important note:</b>
+ * 	A {@link TAPTable} object MUST always have a DB name. That's why,
+ * 	{@link #getDBName()} returns what {@link #getADQLName()} returns when no DB
+ * 	name is set. After creation, it is possible to set the DB name with
+ * 	{@link #setDBName(String)}.
+ * </p>
+ * <p>
+ * 	This DB name MUST be UNqualified and without double quotes. If a NULL or
+ * 	empty value is provided, {@link #getDBName()} returns what
+ * 	{@link #getADQLName()} returns.
+ * </p>
+ * </i>
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.1 (07/2016)
+ * @version 2.4 (09/2019)
  */
 public class TAPTable implements DBTable {
 
 	/**
 	 * Different types of table according to the TAP protocol.
 	 * The default one should be "table".
-	 * 
+	 *
 	 * @author Gr&eacute;gory Mantelet (ARI)
 	 * @version 2.0 (08/2014)
-	 * 
+	 *
 	 * @since 2.0
 	 */
-	public enum TableType{
+	public enum TableType {
 		output, table, view;
 	}
 
-	/** Name that this table MUST have in ADQL queries. */
-	private final String adqlName;
+	/** ADQL name of this table.
+	 * <p><i>This name is neither qualified nor delimited.</i></p> */
+	private String adqlName;
 
-	/** Indicates whether the given ADQL name must be simplified by {@link #getADQLName()}.
-	 * <p>Here, "simplification" means removing the surrounding double quotes and the schema prefix if any.</p>
-	 * @since 2.1 */
-	private final boolean simplificationNeeded;
+	/** Name of this table as provided at creation.
+	 * <p><i>This name may be qualified and/or delimited.</i></p>
+	 * @since 2.4 */
+	private final String rawName;
 
-	/** <p>Indicate whether the ADQL name has been given at creation with a schema prefix or not.</p>
-	 * <p><i>Note: This information is used only when writing TAP_SCHEMA.tables or when writing the output of the resource /tables.</i></p>
-	 * @since 2.0
-	 * @deprecated See {@link #simplificationNeeded}, {@link #getRawName()} and {@link #getADQLName()}. */
-	@Deprecated
-	private boolean isInitiallyQualified;
+	/** Indicate whether the ADQL table name is case sensitive. In such case,
+	 * this name will be put between double quotes in ADQL.
+	 * @since 2.4 */
+	private boolean tableNameCaseSensitive = false;
 
 	/** Name that this table have in the database.
-	 * <i>Note: If NULL, {@link #getDBName()} returns what {@link #getADQLName()} returns.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	If NULL, {@link #getDBName()} returns what {@link #getADQLName()}
+	 * 	returns.
+	 * </i></p> */
 	private String dbName = null;
 
 	/** The schema which owns this table.
-	 *  <i>Note: It is NULL only at the construction.
-	 * 	Then, this attribute is automatically set by a {@link TAPSchema} when adding this table inside it
-	 * 	with {@link TAPSchema#addTable(TAPTable)}.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	It is NULL only at the construction. Then, this attribute is
+	 * 	automatically set by a {@link TAPSchema} when adding this table inside
+	 * 	it with {@link TAPSchema#addTable(TAPTable)}.
+	 * </i></p> */
 	private TAPSchema schema = null;
 
 	/** Type of this table.
-	 * <i>Note: Standard TAP table field ; CAN NOT be NULL ; by default, it is "table".</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP table field ; CAN NOT be NULL ; by default, it is "table".
+	 * </i></p> */
 	private TableType type = TableType.table;
 
 	/** Descriptive, human-interpretable name of the table.
-	 * <i>Note: Standard TAP table field ; MAY be NULL.</i>
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP table field ; MAY be NULL.
+	 * </i></p>
 	 * @since 2.0 */
 	private String title = null;
 
 	/** Description of this table.
-	 * <i>Note: Standard TAP table field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP table field ; MAY be NULL.
+	 * </i></p> */
 	private String description = null;
 
 	/** UType associating this table with a data-model.
-	 * <i>Note: Standard TAP table field ; MAY be NULL.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP table field ; MAY be NULL.
+	 * </i></p> */
 	private String utype = null;
 
 	/** Ordering index of this table inside its schema.
-	 * <i>Note: Standard TAP table field since TAP 1.1.</i>
+	 * <p><i><b>Note:</b>
+	 * 	Standard TAP table field since TAP 1.1.
+	 * </i></p>
 	 * @since 2.1 */
 	private int index = -1;
 
 	/** List of columns composing this table.
-	 * <i>Note: all columns of this list are linked to this table from the moment they are added inside it.</i> */
-	protected final Map<String,TAPColumn> columns;
+	 * <p><i><b>Note:</b>
+	 * 	All columns of this list are linked to this table from the moment they
+	 * 	are added inside it.
+	 * </i></p> */
+	protected final Map<String, TAPColumn> columns;
 
 	/** List of all foreign keys linking this table to others. */
 	protected final ArrayList<TAPForeignKey> foreignKeys;
 
 	/** Let add some information in addition of the ones of the TAP protocol.
-	 * <i>Note: This object can be anything: an {@link Integer}, a {@link String}, a {@link Map}, a {@link List}, ...
-	 * Its content is totally free and never used or checked.</i> */
+	 * <p><i><b>Note:</b>
+	 * 	This object can be anything: an {@link Integer}, a {@link String}, a
+	 * 	{@link Map}, a {@link List}, ... Its content is totally free and never
+	 * 	used or checked.
+	 * </i></p> */
 	protected Object otherData = null;
 
 	/**
-	 * <p>Build a {@link TAPTable} instance with the given ADQL name.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a {@link TAPTable} instance with the given ADQL name.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
+	 *
+	 * <p><i><b>Note 2:</b>
 	 * 	The table type is set by default to "table".
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the table name is prefixed by its schema name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the schema name must be exactly the same
-	 * 		as what the function {@link TAPSchema#getRawName()} of the set schema returns.
+	 * 		The schema prefix will not be removed until
+	 * 		{@link #setSchema(TAPSchema)}.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single table name. They will be removed by {@link #getADQLName()} but will
-	 * 		still appear in the result of {@link #getRawName()}.
+	 * 		Double quotes may surround the table name. In such case, the ADQL
+	 * 		name of this table will be considered as case sensitive and these
+	 * 		double quotes will be automatically removed.
+	 * 		<em>Note that this case sensitivity may not be identified just after
+	 * 		this constructor ; you may have to specify the schema
+	 * 		(see {@link #setSchema(TAPSchema)}) so that the schema prefix is
+	 * 		removed first.</em>
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param tableName	Name that this table MUST have in ADQL queries.
-	 *                 	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
+	 *
+	 * @param tableName		ADQL name of this table.
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
 	 */
-	public TAPTable(String tableName) throws NullPointerException{
+	public TAPTable(final String tableName) throws NullPointerException {
 		if (tableName == null)
 			throw new NullPointerException("Missing table name!");
 
-		adqlName = tableName.trim();
-		simplificationNeeded = (adqlName.indexOf('.') > 0 || adqlName.indexOf('"') >= 0);
-		isInitiallyQualified = (adqlName.indexOf('.') > 0);
+		rawName = tableName.trim();
+		updateADQLName();
 
-		if (getADQLName().length() == 0)
+		if (adqlName.trim().length() == 0)
 			throw new NullPointerException("Missing table name!");
 
 		dbName = null;
 
-		columns = new LinkedHashMap<String,TAPColumn>();
+		columns = new LinkedHashMap<String, TAPColumn>();
 		foreignKeys = new ArrayList<TAPForeignKey>();
 	}
 
 	/**
-	 * <p>Build a {@link TAPTable} instance with the given ADQL name and table type.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a {@link TAPTable} instance with the given ADQL name and table
+	 * type.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 * 	The table type is set by default to "table".
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the table type is set by default to "table".
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the table name is prefixed by its schema name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the schema name must be exactly the same
-	 * 		as what the function {@link TAPSchema#getRawName()} of the set schema returns.
+	 * 		The schema prefix will not be removed until
+	 * 		{@link #setSchema(TAPSchema)}.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single table name. They will be removed by {@link #getADQLName()} but will
-	 * 		still appear in the result of {@link #getRawName()}.
+	 * 		Double quotes may surround the table name. In such case, the ADQL
+	 * 		name of this table will be considered as case sensitive and these
+	 * 		double quotes will be automatically removed.
+	 * 		<em>Note that this case sensitivity may not be identified just after
+	 * 		this constructor ; you may have to specify the schema
+	 * 		(see {@link #setSchema(TAPSchema)}) so that the schema prefix is
+	 * 		removed first.</em>
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param tableName	Name that this table MUST have in ADQL queries.
-	 *                 	<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param tableType	Type of this table. <i>If NULL, "table" will be the type of this table.</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 * 
+	 *
+	 * @param tableName		ADQN name of this table.
+	 * @param tableType		Type of this table.
+	 *                 		<i>If NULL, "table" will be set by default.</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
+	 *
 	 * @see #setType(TableType)
 	 */
-	public TAPTable(String tableName, TableType tableType) throws NullPointerException{
+	public TAPTable(final String tableName, final TableType tableType) throws NullPointerException {
 		this(tableName);
 		setType(tableType);
 	}
 
 	/**
-	 * <p>Build a {@link TAPTable} instance with the given ADQL name, table type, description and UType.</p>
-	 * 
-	 * <p><i>Note 1:
-	 * 	The DB name is set by default to NULL so that {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.
-	 * 	To set a specific DB name, you MUST call {@link #setDBName(String)}.
+	 * Build a {@link TAPTable} instance with the given ADQL name, table type,
+	 * description and UType.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The DB name is set by default to NULL so that {@link #getDBName()}
+	 * 	returns exactly what {@link #getADQLName()} returns. To set a specific
+	 * 	DB name, you MUST call {@link #setDBName(String)}.
 	 * </i></p>
-	 * 
-	 * <p><i>Note 2:
-	 * 	The table type is set by default to "table".
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If omitted, the table type is set by default to "table".
 	 * </i></p>
-	 * 
+	 *
 	 * <p><b>Important notes on the given ADQL name:</b></p>
 	 * <ul>
 	 * 	<li>Any leading or trailing space is immediately deleted.</li>
 	 * 	<li>
-	 * 		If the table name is prefixed by its schema name, this prefix is removed by {@link #getADQLName()}
-	 * 		but will be still here when using {@link #getRawName()}. To work, the schema name must be exactly the same
-	 * 		as what the function {@link TAPSchema#getRawName()} of the set schema returns.
+	 * 		The schema prefix will not be removed until
+	 * 		{@link #setSchema(TAPSchema)}.
 	 *	</li>
 	 * 	<li>
-	 * 		Double quotes may surround the single table name. They will be removed by {@link #getADQLName()} but will
-	 * 		still appear in the result of {@link #getRawName()}.
+	 * 		Double quotes may surround the table name. In such case, the ADQL
+	 * 		name of this table will be considered as case sensitive and these
+	 * 		double quotes will be automatically removed.
+	 * 		<em>Note that this case sensitivity may not be identified just after
+	 * 		this constructor ; you may have to specify the schema
+	 * 		(see {@link #setSchema(TAPSchema)}) so that the schema prefix is
+	 * 		removed first.</em>
 	 *	</li>
 	 * </ul>
-	 * 
-	 * @param tableName		Name that this table MUST have in ADQL queries.
-	 *                 		<i>CAN'T be NULL ; this name can never be changed after initialization.</i>
-	 * @param tableType		Type of this table. <i>If NULL, "table" will be the type of this table.</i>
-	 * @param description	Description of this table. <i>MAY be NULL.</i>
-	 * @param utype			UType associating this table with a data-model. <i>MAY be NULL</i>
-	 * 
-	 * @throws NullPointerException	If the given name is <code>null</code>,
-	 *                             	or if the given string is empty after simplification
-	 *                             	(i.e. without the surrounding double quotes).
-	 * 
-	 * @see #setType(TableType)
+	 *
+	 * @param tableName		ADQL name of this table.
+	 * @param tableType		Type of this table.
+	 *                 		<i>If NULL, "table" will be set by default.</i>
+	 * @param description	Description of this table.
+	 *                   	<i>MAY be NULL.</i>
+	 * @param utype			UType associating this table with a data-model.
+	 *             			<i>MAY be NULL</i>
+	 *
+	 * @throws NullPointerException	If the given name is NULL or an empty string.
 	 */
-	public TAPTable(String tableName, TableType tableType, String description, String utype) throws NullPointerException{
+	public TAPTable(final String tableName, final TableType tableType, final String description, final String utype) throws NullPointerException {
 		this(tableName, tableType);
 		this.description = description;
 		this.utype = utype;
 	}
 
 	/**
-	 * <p>Get the qualified name of this table.</p>
-	 * 
-	 * <p><i><b>Warning:</b>
-	 * 	The part of the returned full name won't be double quoted!
+	 * Get the qualified and delimited (if case sensitive) name of this table.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	If this table is not attached to a schema, this function will just
+	 * 	return the ADQL name of this table.
 	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If this table is not attached to a schema, this function will just return
-	 * 	the ADQL name of this table.
-	 * </i></p>
-	 * 
-	 * @return	Qualified ADQL name of this table.
+	 *
+	 * @return	Qualified and delimited (if needed) ADQL name of this table.
 	 */
-	public final String getFullName(){
-		if (schema != null)
-			return schema.getADQLName() + "." + getADQLName();
-		else
-			return adqlName;
+	public final String getFullName() {
+		return (schema != null ? schema.getADQLName() + "." : "") + (tableNameCaseSensitive ? "\"" + getADQLName().replaceAll("\"", "\"\"") + "\"" : getADQLName());
 	}
 
 	/**
 	 * Get the ADQL name (the name this table MUST have in ADQL queries).
-	 * 
+	 *
 	 * @return	Its ADQL name.
+	 *
 	 * @see #getADQLName()
+	 *
 	 * @deprecated	Does not do anything special: just call {@link #getADQLName()}.
 	 */
 	@Deprecated
-	public final String getName(){
+	public final String getName() {
 		return getADQLName();
 	}
 
 	@Override
-	public final String getADQLName(){
-		if (simplificationNeeded){
-			String tmp = adqlName;
-			// Remove the schema prefix if any:
-			if (schema != null && tmp.startsWith(schema.getRawName() + "."))
-				tmp = tmp.substring((schema.getRawName() + ".").length()).trim();
-			// Remove the surrounding double-quotes if any:
-			if (tmp.matches("\"[^\"]*\""))
-				tmp = tmp.substring(1, tmp.length() - 1);
-			// Finally, return the result:
-			return tmp;
-		}else
-			return adqlName;
+	public final String getADQLName() {
+		return adqlName;
 	}
 
 	/**
-	 * Get the full ADQL name of this table, as it has been provided at initialization.
-	 * 
+	 * Get the full ADQL name of this table, as it has been provided at
+	 * initialization.
+	 *
 	 * @return	Get the original ADQL name.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final String getRawName(){
-		return adqlName;
+	public final String getRawName() {
+		return rawName;
 	}
 
 	/**
-	 * <p>Tells whether the ADQL name of this table must be qualified in the "table_name" column of TAP_SCHEMA.tables
-	 * and in the /schema/table/name field of the resource /tables.</p>
-	 * 
-	 * <p><i>Note: this value is set automatically by the constructor: "true" if the table name was qualified,
-	 * "false" otherwise. It can be changed with the function {@link #setInitiallyQualifed(boolean)}, BUT by doing so
-	 * you may generate a mismatch between the table name of TAP_SCHEMA.tables and the one of /tables.</i></p>
-	 * 
-	 * @return	<i>true</i> if the table name must be qualified in TAP_SCHEMA.tables and in /tables, <i>false</i> otherwise.
-	 * 
-	 * @since 2.0
-	 * @deprecated	To get name of the table as it should be used: {@link #getRawName()}.
-	 *            	To get just the table name (with no prefix and surrounding double quotes): {@link #getADQLName()}.
+	 * Simplify the original ADQL name and set {@link #adqlName} with the
+	 * simplified version.
+	 *
+	 * <p>
+	 * 	The simplification consists in removing the schema prefix (if any)
+	 * 	and to detect case sensitivity (i.e. surrounded by double quotes). In
+	 * 	this last case, the detected double quotes are automatically removed.
+	 * </p>
+	 *
+	 * @since 2.4
 	 */
-	@Deprecated
-	public final boolean isInitiallyQualified(){
-		return isInitiallyQualified;
+	private void updateADQLName() {
+		String tmp = rawName;
+
+		// If a schema is specified, remove the schema prefix (if any):
+		if (schema != null) {
+			// strict comparison if schema is case sensitive:
+			if (schema.isCaseSensitive()) {
+				if (tmp.startsWith(schema.getRawName() + "."))
+					tmp = tmp.substring(schema.getRawName().length() + 1).trim();
+			}
+			// if no case sensitivity...
+			else {
+				// ...search not-case-sensitively for a prefix:
+				if (tmp.toLowerCase().startsWith(schema.getADQLName().toLowerCase() + "."))
+					tmp = tmp.substring(schema.getADQLName().length() + 1).trim();
+				// ...otherwise, try with a strict comparison (as if schema was case sensitive):
+				else if (tmp.toLowerCase().startsWith("\"" + schema.getADQLName().toLowerCase().replaceAll("\"", "\"\"") + "\"."))
+					tmp = tmp.substring(schema.getADQLName().replaceAll("\"", "\"\"").length() + 3).trim();
+			}
+		}
+
+		// Detect if delimited (i.e. case sensitive):
+		if ((tableNameCaseSensitive = DefaultDBTable.isDelimited(tmp)))
+			tmp = tmp.substring(1, tmp.length() - 1).replaceAll("\"\"", "\"");
+
+		// Finally, set the ADQL name:
+		adqlName = tmp;
 	}
 
-	/**
-	 * <p>Let specifying whether the table name must be qualified in TAP_SCHEMA.tables and in the resource /tables.</p>
-	 * 
-	 * <p><b>WARNING: Calling this function may generate a mismatch between the table name of TAP_SCHEMA.tables and
-	 * the one of the resource /tables. So, be sure to change this flag before setting the content of TAP_SCHEMA.tables
-	 * using {@link tap.db.JDBCConnection#setTAPSchema(TAPMetadata)}.</b></p>
-	 * 
-	 * @param mustBeQualified	<i>true</i> if the table name in TAP_SCHEMA.tables and in the resource /tables must be qualified by the schema name,
-	 *                       	<i>false</i> otherwise.
-	 * 
-	 * @since 2.0
-	 * @deprecated	To get name of the table as it should be used: {@link #getRawName()}.
-	 *            	To get just the table name (with no prefix and surrounding double quotes): {@link #getADQLName()}.
-	 */
-	@Deprecated
-	public final void setInitiallyQualifed(final boolean mustBeQualified){
-		isInitiallyQualified = mustBeQualified;
+	@Override
+	public final boolean isCaseSensitive() {
+		return tableNameCaseSensitive;
 	}
 
 	@Override
-	public final String getDBName(){
+	public final String getDBName() {
 		return (dbName == null) ? getADQLName() : dbName;
 	}
 
 	/**
-	 * <p>Change the name that this table MUST have in the database (i.e. in SQL queries).</p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given value is NULL or an empty string, {@link #getDBName()} will return exactly what {@link #getADQLName()} returns.
+	 * Change the name that this table MUST have in the database (i.e. in SQL
+	 * queries).
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	If the given value is NULL or an empty string, {@link #getDBName()} will
+	 * 	return exactly what {@link #getADQLName()} returns.
 	 * </i></p>
-	 * 
+	 *
 	 * @param name	The new database name of this table.
 	 */
-	public final void setDBName(String name){
+	public final void setDBName(String name) {
 		name = (name != null) ? name.trim() : name;
 		if (name != null && name.length() > 0)
 			dbName = name;
@@ -384,221 +417,233 @@ public class TAPTable implements DBTable {
 	}
 
 	@Override
-	public String getADQLCatalogName(){
+	public String getADQLCatalogName() {
 		return null;
 	}
 
 	@Override
-	public String getDBCatalogName(){
+	public String getDBCatalogName() {
 		return null;
 	}
 
 	@Override
-	public final String getADQLSchemaName(){
+	public final String getADQLSchemaName() {
 		return schema == null ? null : schema.getADQLName();
 	}
 
 	@Override
-	public final String getDBSchemaName(){
+	public final String getDBSchemaName() {
 		return schema == null ? null : schema.getDBName();
 	}
 
 	/**
 	 * Get the schema that owns this table.
-	 * 
+	 *
 	 * @return Its schema. <i>MAY be NULL</i>
 	 */
-	public final TAPSchema getSchema(){
+	public final TAPSchema getSchema() {
 		return schema;
 	}
 
 	/**
-	 * <p>Set the schema in which this schema is.</p>
-	 * 
+	 * Set the schema in which this schema is.
+	 *
 	 * <p><i><b>Warning:</b>
-	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPSchema}
-	 * 	that owns this table.
+	 * 	For consistency reasons, this function SHOULD be called only by the
+	 * 	{@link TAPSchema} that owns this table.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
-	 * 	If this table was already linked with another {@link TAPSchema} object, the previous link is removed
-	 * 	here, but also in the schema (by calling {@link TAPSchema#removeTable(String)}).
+	 * 	If this table was already linked with another {@link TAPSchema} object,
+	 * 	the previous link is removed here, but also in the schema (by calling
+	 * 	{@link TAPSchema#removeTable(String)}).
 	 * </i></p>
-	 * 
+	 *
 	 * @param schema	The schema that owns this table.
 	 */
-	protected final void setSchema(final TAPSchema schema){
+	protected final void setSchema(final TAPSchema schema) {
+		// Update the former TAPSchema, if any:
 		if (this.schema != null && (schema == null || !schema.equals(this.schema)))
 			this.schema.removeTable(adqlName);
+
+		// Set the new schema:
 		this.schema = schema;
+
+		/* Update the ADQL name of this table:
+		 * (i.e. whether or not schema prefix should be removed) */
+		updateADQLName();
 	}
 
 	/**
 	 * Get the type of this table.
-	 * 
+	 *
 	 * @return	Its type.
 	 */
-	public final TableType getType(){
+	public final TableType getType() {
 		return type;
 	}
 
 	/**
 	 * <p>Set the type of this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given type is NULL, nothing will be done ; the type of this table won't be changed.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	If the given type is NULL, nothing will be done ; the type of this table
+	 * 	won't be changed.
 	 * </i></p>
-	 * 
+	 *
 	 * @param type	Its new type.
 	 */
-	public final void setType(TableType type){
+	public final void setType(TableType type) {
 		if (type != null)
 			this.type = type;
 	}
 
 	/**
 	 * Get the title of this table.
-	 * 
+	 *
 	 * @return	Its title. <i>MAY be NULL</i>
-	 * 
+	 *
 	 * @since 2.0
 	 */
-	public final String getTitle(){
+	public final String getTitle() {
 		return title;
 	}
 
 	/**
 	 * Set the title of this table.
-	 * 
+	 *
 	 * @param title	Its new title. <i>MAY be NULL</i>
-	 * 
+	 *
 	 * @since 2.0
 	 */
-	public final void setTitle(final String title){
+	public final void setTitle(final String title) {
 		this.title = title;
 	}
 
 	/**
 	 * Get the description of this table.
-	 * 
+	 *
 	 * @return	Its description. <i>MAY be NULL</i>
 	 */
-	public final String getDescription(){
+	public final String getDescription() {
 		return description;
 	}
 
 	/**
 	 * Set the description of this table.
-	 * 
+	 *
 	 * @param description	Its new description. <i>MAY be NULL</i>
 	 */
-	public final void setDescription(String description){
+	public final void setDescription(String description) {
 		this.description = description;
 	}
 
 	/**
 	 * Get the UType associating this table with a data-model.
-	 * 
+	 *
 	 * @return	Its UType. <i>MAY be NULL</i>
 	 */
-	public final String getUtype(){
+	public final String getUtype() {
 		return utype;
 	}
 
 	/**
 	 * Set the UType associating this table with a data-model.
-	 * 
+	 *
 	 * @param utype	Its new UType. <i>MAY be NULL</i>
 	 */
-	public final void setUtype(String utype){
+	public final void setUtype(String utype) {
 		this.utype = utype;
 	}
 
 	/**
 	 * Get the ordering index of this table inside its schema.
-	 * 
+	 *
 	 * @return	Its ordering index.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final int getIndex(){
+	public final int getIndex() {
 		return index;
 	}
 
 	/**
 	 * Set the ordering index of this table inside its schema.
-	 * 
+	 *
 	 * @param tableIndex	Its new ordering index.
-	 * 
+	 *
 	 * @since 2.1
 	 */
-	public final void setIndex(int tableIndex){
+	public final void setIndex(int tableIndex) {
 		this.index = tableIndex;
 	}
 
 	/**
-	 * <p>Get the other (piece of) information associated with this table.</p>
-	 * 
+	 * Get the other (piece of) information associated with this table.
+	 *
 	 * <p><i>Note:
-	 * 	By default, NULL is returned, but it may be any kind of value ({@link Integer},
-	 * 	{@link String}, {@link Map}, {@link List}, ...).
+	 * 	By default, NULL is returned, but it may be any kind of value
+	 * 	({@link Integer}, {@link String}, {@link Map}, {@link List}, ...).
 	 * </i></p>
-	 * 
+	 *
 	 * @return	The other (piece of) information. <i>MAY be NULL</i>
 	 */
-	public Object getOtherData(){
+	public Object getOtherData() {
 		return otherData;
 	}
 
 	/**
 	 * Set the other (piece of) information associated with this table.
-	 * 
+	 *
 	 * @param data	Another information about this table. <i>MAY be NULL</i>
 	 */
-	public void setOtherData(Object data){
+	public void setOtherData(Object data) {
 		otherData = data;
 	}
 
 	/**
-	 * <p>Add a column to this table.</p>
-	 * 
-	 * <p><i>Note:
+	 * Add a column to this table.
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	If the given column is NULL, nothing will be done.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	By adding the given column inside this table, it
 	 * 	will be linked with this table using {@link TAPColumn#setTable(DBTable)}.
-	 * 	In this function, if the column was already linked with another {@link TAPTable},
-	 * 	the former link is removed using {@link TAPTable#removeColumn(String)}.
+	 * 	In this function, if the column was already linked with another
+	 * 	{@link TAPTable}, the former link is removed using
+	 * 	{@link TAPTable#removeColumn(String)}.
 	 * </i></p>
-	 * 
+	 *
 	 * @param newColumn	Column to add inside this table.
 	 */
-	public final void addColumn(final TAPColumn newColumn){
-		if (newColumn != null && newColumn.getADQLName() != null){
+	public final void addColumn(final TAPColumn newColumn) {
+		if (newColumn != null && newColumn.getADQLName() != null) {
 			newColumn.setTable(this);
 			columns.put(newColumn.getADQLName(), newColumn);
 		}
 	}
 
 	/**
-	 * <p>Build a {@link TAPColumn} object whose the ADQL and DB name will the given one.
-	 * Then, add this column inside this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	The built {@link TAPColumn} object is returned, so that being modified afterwards if needed.
+	 * Build a {@link TAPColumn} object whose the ADQL and DB name will the
+	 * given one. Then, add this column inside this table.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The built {@link TAPColumn} object is returned, so that being modified
+	 * 	afterwards if needed.
 	 * </i></p>
-	 * 
-	 * @param columnName	ADQL name (and indirectly also the DB name) of the column to create and add.
-	 * 
+	 *
+	 * @param columnName	ADQL name (and indirectly also the DB name) of the
+	 *                  	column to create and add.
+	 *
 	 * @return	The created and added {@link TAPColumn} object,
 	 *        	or NULL if the given name is NULL or an empty string.
-	 * 
+	 *
 	 * @see TAPColumn#TAPColumn(String)
 	 * @see #addColumn(TAPColumn)
 	 */
-	public final TAPColumn addColumn(String columnName){
+	public final TAPColumn addColumn(String columnName) {
 		if (columnName == null || columnName.trim().length() <= 0)
 			return null;
 
@@ -608,27 +653,32 @@ public class TAPTable implements DBTable {
 	}
 
 	/**
-	 * <p>Build a {@link TAPColumn} object whose the ADQL and DB name will the given one.
-	 * Then, add this column inside this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	The built {@link TAPColumn} object is returned, so that being modified afterwards if needed.
+	 * Build a {@link TAPColumn} object whose the ADQL and DB name will the given one.
+	 * Then, add this column inside this table.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The built {@link TAPColumn} object is returned, so that being modified
+	 * 	afterwards if needed.
 	 * </i></p>
-	 * 
-	 * @param columnName	ADQL name (and indirectly also the DB name) of the column to create and add.
-	 * @param datatype		Type of the new column's values. <i>If NULL, VARCHAR will be the type of the created column.</i>
+	 *
+	 * @param columnName	ADQL name (and indirectly also the DB name) of the
+	 *                  	column to create and add.
+	 * @param datatype		Type of the new column's values. <i>If NULL, VARCHAR
+	 *                		will be the type of the created column.</i>
 	 * @param description	Description of the new column. <i>MAY be NULL</i>
 	 * @param unit			Unit of the new column's values. <i>MAY be NULL</i>
-	 * @param ucd			UCD describing the scientific content of the new column. <i>MAY be NULL</i>
-	 * @param utype			UType associating the new column with a data-model. <i>MAY be NULL</i>
-	 * 
+	 * @param ucd			UCD describing the scientific content of the new
+	 *           			column. <i>MAY be NULL</i>
+	 * @param utype			UType associating the new column with a data-model.
+	 *             			<i>MAY be NULL</i>
+	 *
 	 * @return	The created and added {@link TAPColumn} object,
 	 *        	or NULL if the given name is NULL or an empty string.
-	 * 
+	 *
 	 * @see TAPColumn#TAPColumn(String, DBType, String, String, String, String)
 	 * @see #addColumn(TAPColumn)
 	 */
-	public TAPColumn addColumn(String columnName, DBType datatype, String description, String unit, String ucd, String utype){
+	public TAPColumn addColumn(String columnName, DBType datatype, String description, String unit, String ucd, String utype) {
 		if (columnName == null || columnName.trim().length() <= 0)
 			return null;
 
@@ -638,33 +688,41 @@ public class TAPTable implements DBTable {
 	}
 
 	/**
-	 * <p>Build a {@link TAPColumn} object whose the ADQL and DB name will the given one.
-	 * Then, add this column inside this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	The built {@link TAPColumn} object is returned, so that being modified afterwards if needed.
+	 * Build a {@link TAPColumn} object whose the ADQL and DB name will the
+	 * given one. Then, add this column inside this table.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	The built {@link TAPColumn} object is returned, so that being modified
+	 * 	afterwards if needed.
 	 * </i></p>
-	 * 
-	 * @param columnName	ADQL name (and indirectly also the DB name) of the column to create and add.
-	 * @param datatype		Type of the new column's values. <i>If NULL, VARCHAR will be the type of the created column.</i>
+	 *
+	 * @param columnName	ADQL name (and indirectly also the DB name) of the
+	 *                  	column to create and add.
+	 * @param datatype		Type of the new column's values. <i>If NULL, VARCHAR
+	 *                		will be the type of the created column.</i>
 	 * @param description	Description of the new column. <i>MAY be NULL</i>
 	 * @param unit			Unit of the new column's values. <i>MAY be NULL</i>
-	 * @param ucd			UCD describing the scientific content of the new column. <i>MAY be NULL</i>
-	 * @param utype			UType associating the new column with a data-model. <i>MAY be NULL</i>
-	 * @param principal		<i>true</i> if the new column should be returned by default, <i>false</i> otherwise.
-	 * @param indexed		<i>true</i> if the new column is indexed, <i>false</i> otherwise.
-	 * @param std			<i>true</i> if the new column is defined by a standard, <i>false</i> otherwise.
-	 * 
+	 * @param ucd			UCD describing the scientific content of the new
+	 *           			column. <i>MAY be NULL</i>
+	 * @param utype			UType associating the new column with a data-model.
+	 *             			<i>MAY be NULL</i>
+	 * @param principal		<code>true</code> if the new column should be
+	 *                 		returned by default, <code>false</code> otherwise.
+	 * @param indexed		<code>true</code> if the new column is indexed,
+	 *               		<code>false</code> otherwise.
+	 * @param std			<code>true</code> if the new column is defined by a
+	 *           			standard, <code>false</code> otherwise.
+	 *
 	 * @return	The created and added {@link TAPColumn} object,
 	 *        	or NULL if the given name is NULL or an empty string.
-	 * 
+	 *
 	 * @see TAPColumn#TAPColumn(String, DBType, String, String, String, String)
 	 * @see TAPColumn#setPrincipal(boolean)
 	 * @see TAPColumn#setIndexed(boolean)
 	 * @see TAPColumn#setStd(boolean)
 	 * @see #addColumn(TAPColumn)
 	 */
-	public TAPColumn addColumn(String columnName, DBType datatype, String description, String unit, String ucd, String utype, boolean principal, boolean indexed, boolean std){
+	public TAPColumn addColumn(String columnName, DBType datatype, String description, String unit, String ucd, String utype, boolean principal, boolean indexed, boolean std) {
 		if (columnName == null || columnName.trim().length() <= 0)
 			return null;
 
@@ -677,17 +735,20 @@ public class TAPTable implements DBTable {
 	}
 
 	/**
-	 * <p>Tell whether this table contains a column with the given ADQL name.</p>
-	 * 
+	 * Tell whether this table contains a column with the given ADQL name.
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function is case sensitive.
 	 * </i></p>
-	 * 
-	 * @param columnName	ADQL name (case sensitive) of the column whose the existence must be checked.
-	 * 
-	 * @return	<i>true</i> if a column having the given ADQL name exists in this table, <i>false</i> otherwise.
+	 *
+	 * @param columnName	ADQL name (case sensitive) of the column whose the
+	 *                  	existence must be checked.
+	 *
+	 * @return	<code>true</code> if a column having the given ADQL name exists
+	 *        	in this table,
+	 *        	<code>false</code> otherwise.
 	 */
-	public final boolean hasColumn(String columnName){
+	public final boolean hasColumn(String columnName) {
 		if (columnName == null)
 			return false;
 		else
@@ -696,21 +757,21 @@ public class TAPTable implements DBTable {
 
 	/**
 	 * Get the list of all columns contained in this table.
-	 * 
+	 *
 	 * @return	An iterator over the list of this table's columns.
 	 */
-	public Iterator<TAPColumn> getColumns(){
+	public Iterator<TAPColumn> getColumns() {
 		return columns.values().iterator();
 	}
 
 	@Override
-	public DBColumn getColumn(String colName, boolean byAdqlName){
+	public DBColumn getColumn(String colName, boolean byAdqlName) {
 		if (byAdqlName)
 			return getColumn(colName);
-		else{
-			if (colName != null && colName.length() > 0){
+		else {
+			if (colName != null && colName.length() > 0) {
 				Collection<TAPColumn> collColumns = columns.values();
-				for(TAPColumn column : collColumns){
+				for(TAPColumn column : collColumns) {
 					if (column.getDBName().equals(colName))
 						return column;
 				}
@@ -720,18 +781,18 @@ public class TAPTable implements DBTable {
 	}
 
 	/**
-	 * <p>Search a column inside this table having the given ADQL name.</p>
-	 * 
+	 * Search a column inside this table having the given ADQL name.
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function is case sensitive.
 	 * </i></p>
-	 * 
+	 *
 	 * @param columnName	ADQL name of the column to search.
-	 * 
+	 *
 	 * @return	The matching column,
 	 *        	or NULL if no column with this ADQL name has been found.
 	 */
-	public final TAPColumn getColumn(String columnName){
+	public final TAPColumn getColumn(String columnName) {
 		if (columnName == null)
 			return null;
 		else
@@ -739,64 +800,67 @@ public class TAPTable implements DBTable {
 	}
 
 	/**
-	 * <p>Tell whether this table contains a column with the given ADQL or DB name.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	This functions is just calling {@link #getColumn(String, boolean)} and compare its result
-	 * 	with NULL in order to check the existence of the specified column.
+	 * Tell whether this table contains a column with the given ADQL or DB name.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	This functions is just calling {@link #getColumn(String, boolean)} and
+	 * 	compare its result with NULL in order to check the existence of the
+	 * 	specified column.
 	 * </i></p>
-	 * 
+	 *
 	 * @param colName		ADQL or DB name that the column to search must have.
-	 * @param byAdqlName	<i>true</i> to search the column by ADQL name, <i>false</i> to search by DB name.
-	 * 
-	 * @return	<i>true</i> if a column has been found inside this table with the given ADQL or DB name,
-	 *        	<i>false</i> otherwise.
-	 * 
+	 * @param byAdqlName	<code>true</code> to search the column by ADQL name,
+	 *                  	<code>false</code> to search by DB name.
+	 *
+	 * @return	<code>true</code> if a column has been found inside this table
+	 *        	with the given ADQL or DB name,
+	 *        	<code>false</code> otherwise.
+	 *
 	 * @see #getColumn(String, boolean)
 	 */
-	public boolean hasColumn(String colName, boolean byAdqlName){
+	public boolean hasColumn(String colName, boolean byAdqlName) {
 		return (getColumn(colName, byAdqlName) != null);
 	}
 
 	/**
 	 * Get the number of columns composing this table.
-	 * 
+	 *
 	 * @return	Number of its columns.
 	 */
-	public final int getNbColumns(){
+	public final int getNbColumns() {
 		return columns.size();
 	}
 
 	/**
 	 * Tell whether this table contains no column.
-	 * 
-	 * @return	<i>true</i> if this table is empty (no column),
-	 *        	<i>false</i> if it contains at least one column.
+	 *
+	 * @return	<code>true</code> if this table is empty (no column),
+	 *        	<code>false</code> if it contains at least one column.
 	 */
-	public final boolean isEmpty(){
+	public final boolean isEmpty() {
 		return columns.isEmpty();
 	}
 
 	/**
-	 * <p>Remove the specified column.</p>
-	 * 
+	 * Remove the specified column.
+	 *
 	 * <p><i><b>Important note:</b>
 	 * 	This function is case sensitive!
 	 * </i></p>
-	 * 
-	 * <p><i>Note:
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	If some foreign keys were associating the column to remove,
 	 * 	they will be also deleted.
 	 * </i></p>
-	 * 
+	 *
 	 * @param columnName	ADQL name of the column to remove.
-	 * 
+	 *
 	 * @return	The removed column,
 	 *        	or NULL if no column with the given ADQL name has been found.
-	 * 
+	 *
 	 * @see #deleteColumnRelations(TAPColumn)
 	 */
-	public final TAPColumn removeColumn(String columnName){
+	public final TAPColumn removeColumn(String columnName) {
 		if (columnName == null)
 			return null;
 
@@ -808,11 +872,12 @@ public class TAPTable implements DBTable {
 	}
 
 	/**
-	 * Delete all foreign keys having the given column in the sources or the targets list.
-	 * 
+	 * Delete all foreign keys having the given column in the sources or the
+	 * targets list.
+	 *
 	 * @param col	A column.
 	 */
-	protected final void deleteColumnRelations(TAPColumn col){
+	protected final void deleteColumnRelations(TAPColumn col) {
 		// Remove the relation between the column and this table:
 		col.setTable(null);
 
@@ -822,7 +887,7 @@ public class TAPTable implements DBTable {
 			removeForeignKey(it.next());
 
 		it = col.getSources();
-		while(it.hasNext()){
+		while(it.hasNext()) {
 			TAPForeignKey key = it.next();
 			key.getFromTable().removeForeignKey(key);
 		}
@@ -832,40 +897,43 @@ public class TAPTable implements DBTable {
 	 * Remove all columns composing this table.
 	 * Foreign keys will also be deleted.
 	 */
-	public final void removeAllColumns(){
-		Iterator<Map.Entry<String,TAPColumn>> it = columns.entrySet().iterator();
-		while(it.hasNext()){
-			Map.Entry<String,TAPColumn> entry = it.next();
+	public final void removeAllColumns() {
+		Iterator<Map.Entry<String, TAPColumn>> it = columns.entrySet().iterator();
+		while(it.hasNext()) {
+			Map.Entry<String, TAPColumn> entry = it.next();
 			it.remove();
 			deleteColumnRelations(entry.getValue());
 		}
 	}
 
 	/**
-	 * <p>Add the given foreign key to this table.</p>
-	 * 
-	 * <p><i>Note:
+	 * Add the given foreign key to this table.
+	 *
+	 * <p><i><b>Note:</b>
 	 * 	This function will do nothing if the given foreign key is NULL.
 	 * </i></p>
-	 * 
+	 *
 	 * <p><i><b>WARNING:</b>
-	 * 	The source table ({@link TAPForeignKey#getFromTable()}) of the given foreign key MUST be this table
-	 * 	and the foreign key MUST be completely defined.
-	 * 	If not, an exception will be thrown and the key won't be added.
+	 * 	The source table ({@link TAPForeignKey#getFromTable()}) of the given
+	 * 	foreign key MUST be this table and the foreign key MUST be completely
+	 * 	defined. If not, an exception will be thrown and the key won't be added.
 	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given foreign key is added to this table, all the columns of this key will be
-	 * 	linked to the foreign key using either {@link TAPColumn#addSource(TAPForeignKey)} or
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	If the given foreign key is added to this table, all the columns of this
+	 * 	key will be linked to the foreign key using either
+	 * 	{@link TAPColumn#addSource(TAPForeignKey)} or
 	 * 	{@link TAPColumn#addTarget(TAPForeignKey)}.
 	 * </i></p>
-	 * 
-	 * @param key	Foreign key (whose the FROM table is this table) to add inside this table.
-	 * 
-	 * @throws TAPException	If the source table of the given foreign key is not this table
-	 *                     	or if the given key is not completely defined.
+	 *
+	 * @param key	Foreign key (whose the FROM table is this table) to add
+	 *           	inside this table.
+	 *
+	 * @throws TAPException	If the source table of the given foreign key is not
+	 *                     	this table or if the given key is not completely
+	 *                     	defined.
 	 */
-	public final void addForeignKey(TAPForeignKey key) throws TAPException{
+	public final void addForeignKey(TAPForeignKey key) throws TAPException {
 		if (key == null)
 			return;
 
@@ -873,31 +941,31 @@ public class TAPTable implements DBTable {
 		final String errorMsgPrefix = "Impossible to add the foreign key \"" + keyId + "\" because ";
 
 		if (key.getFromTable() == null)
-			throw new TAPException(errorMsgPrefix + "no source table is specified !");
+			throw new TAPException(errorMsgPrefix + "no source table is specified!");
 
 		if (!this.equals(key.getFromTable()))
 			throw new TAPException(errorMsgPrefix + "the source table is not \"" + getADQLName() + "\"");
 
 		if (key.getTargetTable() == null)
-			throw new TAPException(errorMsgPrefix + "no target table is specified !");
+			throw new TAPException(errorMsgPrefix + "no target table is specified!");
 
 		if (key.isEmpty())
-			throw new TAPException(errorMsgPrefix + "it defines no relation !");
+			throw new TAPException(errorMsgPrefix + "it defines no relation!");
 
-		if (foreignKeys.add(key)){
-			try{
+		if (foreignKeys.add(key)) {
+			try {
 				TAPTable targetTable = key.getTargetTable();
-				for(Map.Entry<String,String> relation : key){
+				for(Map.Entry<String, String> relation : key) {
 					if (!hasColumn(relation.getKey()))
-						throw new TAPException(errorMsgPrefix + "the source column \"" + relation.getKey() + "\" doesn't exist in \"" + getADQLName() + "\" !");
+						throw new TAPException(errorMsgPrefix + "the source column \"" + relation.getKey() + "\" doesn't exist in \"" + getADQLName() + "\"!");
 					else if (!targetTable.hasColumn(relation.getValue()))
-						throw new TAPException(errorMsgPrefix + "the target column \"" + relation.getValue() + "\" doesn't exist in \"" + targetTable.getADQLName() + "\" !");
-					else{
+						throw new TAPException(errorMsgPrefix + "the target column \"" + relation.getValue() + "\" doesn't exist in \"" + targetTable.getADQLName() + "\"!");
+					else {
 						getColumn(relation.getKey()).addTarget(key);
 						targetTable.getColumn(relation.getValue()).addSource(key);
 					}
 				}
-			}catch(TAPException ex){
+			} catch(TAPException ex) {
 				foreignKeys.remove(key);
 				throw ex;
 			}
@@ -905,52 +973,59 @@ public class TAPTable implements DBTable {
 	}
 
 	/**
-	 * <p>Build a foreign key using the ID, the target table and the given list of columns.
-	 * Then, add the created foreign key to this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	The source table of the created foreign key ({@link TAPForeignKey#getFromTable()}) will be this table.
+	 * Build a foreign key using the ID, the target table and the given list of
+	 * columns. Then, add the created foreign key to this table.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The source table of the created foreign key
+	 * 	({@link TAPForeignKey#getFromTable()}) will be this table.
 	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given foreign key is added to this table, all the columns of this key will be
-	 * 	linked to the foreign key using either {@link TAPColumn#addSource(TAPForeignKey)} or
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If the given foreign key is added to this table, all the columns of this
+	 * 	key will be linked to the foreign key using either
+	 * 	{@link TAPColumn#addSource(TAPForeignKey)} or
 	 * 	{@link TAPColumn#addTarget(TAPForeignKey)}.
 	 * </i></p>
-	 * 
+	 *
 	 * @return	The created and added foreign key.
-	 * 
-	 * @throws TAPException	If the specified key is not completely or correctly defined.
-	 * 
+	 *
+	 * @throws TAPException	If the specified key is not completely or correctly
+	 *                     	defined.
+	 *
 	 * @see TAPForeignKey#TAPForeignKey(String, TAPTable, TAPTable, Map)
 	 */
-	public TAPForeignKey addForeignKey(String keyId, TAPTable targetTable, Map<String,String> columns) throws TAPException{
+	public TAPForeignKey addForeignKey(String keyId, TAPTable targetTable, Map<String, String> columns) throws TAPException {
 		TAPForeignKey key = new TAPForeignKey(keyId, this, targetTable, columns);
 		addForeignKey(key);
 		return key;
 	}
 
 	/**
-	 * <p>Build a foreign key using the ID, the target table, the given list of columns, the given description and the given UType.
-	 * Then, add the created foreign key to this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	The source table of the created foreign key ({@link TAPForeignKey#getFromTable()}) will be this table.
+	 * Build a foreign key using the ID, the target table, the given list of
+	 * columns, the given description and the given UType. Then, add the created
+	 * foreign key to this table.
+	 *
+	 * <p><i><b>Note 1:</b>
+	 * 	The source table of the created foreign key
+	 * 	({@link TAPForeignKey#getFromTable()}) will be this table.
 	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given foreign key is added to this table, all the columns of this key will be
-	 * 	linked to the foreign key using either {@link TAPColumn#addSource(TAPForeignKey)} or
+	 *
+	 * <p><i><b>Note 2:</b>
+	 * 	If the given foreign key is added to this table, all the columns of this
+	 * 	key will be linked to the foreign key using either
+	 * 	{@link TAPColumn#addSource(TAPForeignKey)} or
 	 * 	{@link TAPColumn#addTarget(TAPForeignKey)}.
 	 * </i></p>
-	 * 
+	 *
 	 * @return	The created and added foreign key.
-	 * 
-	 * @throws TAPException	If the specified key is not completely or correctly defined.
-	 * 
+	 *
+	 * @throws TAPException	If the specified key is not completely or correctly
+	 *                     	defined.
+	 *
 	 * @see TAPForeignKey#TAPForeignKey(String, TAPTable, TAPTable, Map, String, String)
 	 */
-	public TAPForeignKey addForeignKey(String keyId, TAPTable targetTable, Map<String,String> columns, String description, String utype) throws TAPException{
+	public TAPForeignKey addForeignKey(String keyId, TAPTable targetTable, Map<String, String> columns, String description, String utype) throws TAPException {
 		TAPForeignKey key = new TAPForeignKey(keyId, this, targetTable, columns, description, utype);
 		addForeignKey(key);
 		return key;
@@ -958,54 +1033,56 @@ public class TAPTable implements DBTable {
 
 	/**
 	 * Get the list of all foreign keys associated whose the source is this table.
-	 * 
+	 *
 	 * @return	An iterator over all its foreign keys.
 	 */
-	public final Iterator<TAPForeignKey> getForeignKeys(){
+	public final Iterator<TAPForeignKey> getForeignKeys() {
 		return foreignKeys.iterator();
 	}
 
 	/**
 	 * Get the number of all foreign keys whose the source is this table
-	 * 
+	 *
 	 * @return	Number of all its foreign keys.
 	 */
-	public final int getNbForeignKeys(){
+	public final int getNbForeignKeys() {
 		return foreignKeys.size();
 	}
 
 	/**
-	 * <p>Remove the given foreign key from this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	This function will also delete the link between the columns of the foreign key
-	 * 	and the foreign key, using {@link #deleteRelations(TAPForeignKey)}.
+	 * Remove the given foreign key from this table.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	This function will also delete the link between the columns of the
+	 * 	foreign key and the foreign key, using
+	 * 	{@link #deleteRelations(TAPForeignKey)}.
 	 * </i></p>
-	 * 
+	 *
 	 * @param keyToRemove	Foreign key to removed from this table.
-	 * 
-	 * @return	<i>true</i> if the key has been successfully removed,
-	 *        	<i>false</i> otherwise.
+	 *
+	 * @return	<code>true</code> if the key has been successfully removed,
+	 *        	<code>false</code> otherwise.
 	 */
-	public final boolean removeForeignKey(TAPForeignKey keyToRemove){
-		if (foreignKeys.remove(keyToRemove)){
+	public final boolean removeForeignKey(TAPForeignKey keyToRemove) {
+		if (foreignKeys.remove(keyToRemove)) {
 			deleteRelations(keyToRemove);
 			return true;
-		}else
+		} else
 			return false;
 	}
 
 	/**
-	 * <p>Remove all the foreign keys whose the source is this table.</p>
-	 * 
-	 * <p><i>Note:
-	 * 	This function will also delete the link between the columns of all the removed foreign keys
-	 * 	and the foreign keys, using {@link #deleteRelations(TAPForeignKey)}.
+	 * Remove all the foreign keys whose the source is this table.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	This function will also delete the link between the columns of all the
+	 * 	removed foreign keys and the foreign keys, using
+	 * 	{@link #deleteRelations(TAPForeignKey)}.
 	 * </i></p>
 	 */
-	public final void removeAllForeignKeys(){
+	public final void removeAllForeignKeys() {
 		Iterator<TAPForeignKey> it = foreignKeys.iterator();
-		while(it.hasNext()){
+		while(it.hasNext()) {
 			deleteRelations(it.next());
 			it.remove();
 		}
@@ -1013,13 +1090,13 @@ public class TAPTable implements DBTable {
 
 	/**
 	 * Delete the link between all columns of the given foreign key
-	 * and this foreign key. Thus, these columns won't be anymore source or target
-	 * of this foreign key.
-	 * 
+	 * and this foreign key. Thus, these columns won't be anymore source or
+	 * target of this foreign key.
+	 *
 	 * @param key	A foreign key whose links with its columns must be deleted.
 	 */
-	protected final void deleteRelations(TAPForeignKey key){
-		for(Map.Entry<String,String> relation : key){
+	protected final void deleteRelations(TAPForeignKey key) {
+		for(Map.Entry<String, String> relation : key) {
 			TAPColumn col = key.getFromTable().getColumn(relation.getKey());
 			if (col != null)
 				col.removeTarget(key);
@@ -1031,35 +1108,35 @@ public class TAPTable implements DBTable {
 	}
 
 	@Override
-	public Iterator<DBColumn> iterator(){
-		return new Iterator<DBColumn>(){
+	public Iterator<DBColumn> iterator() {
+		return new Iterator<DBColumn>() {
 			private final Iterator<TAPColumn> it = getColumns();
 
 			@Override
-			public boolean hasNext(){
+			public boolean hasNext() {
 				return it.hasNext();
 			}
 
 			@Override
-			public DBColumn next(){
+			public DBColumn next() {
 				return it.next();
 			}
 
 			@Override
-			public void remove(){
+			public void remove() {
 				it.remove();
 			}
 		};
 	}
 
 	@Override
-	public String toString(){
-		return ((schema != null) ? (schema.getADQLName() + ".") : "") + getADQLName();
+	public String toString() {
+		return ((schema != null) ? (schema.toString() + ".") : "") + (tableNameCaseSensitive ? "\"" + adqlName.replaceAll("\"", "\"\"") + "\"" : getADQLName());
 	}
 
 	@Override
-	public DBTable copy(final String dbName, final String adqlName){
-		TAPTable copy = new TAPTable((adqlName == null) ? this.adqlName : adqlName);
+	public DBTable copy(final String dbName, final String adqlName) {
+		TAPTable copy = new TAPTable((adqlName == null) ? this.rawName : adqlName);
 		copy.setDBName((dbName == null) ? this.getDBName() : dbName);
 		copy.setSchema(schema);
 		Collection<TAPColumn> collColumns = columns.values();
diff --git a/tap_schema_requirements.md b/tap_schema_requirements.md
new file mode 100644
index 0000000000000000000000000000000000000000..04c1805be34e9d14126bd21f8b7ad7f809b149c9
--- /dev/null
+++ b/tap_schema_requirements.md
@@ -0,0 +1,55 @@
+
+# TAP_SCHEMA.schemas
+
+`db_name`
+
+:  - optional
+   - never qualified nor delimited
+   - if `NULL`, exactly equals to undelimited `schema_name`
+
+# TAP_SCHEMA.tables
+
+`schema_name`
+
+:  exactly equals to `TAP_SCHEMA.schemas.schema_name`
+
+`table_name`
+
+:  - may be qualified (by schema name which can be be delimited or
+     not ; it does not have to be exactly equals to
+   `TAP_SCHEMA.schemas.schema_name`)
+   - delimited if case sensitive (or not an    ADQL regular identifier)
+
+`db_name`
+
+:  - optional
+   - never qualified nor delimited
+   - if `NULL`, exactly equals to undelimited `table_name`
+
+# TAP_SCHEMA.columns
+
+`table_name`
+
+:  exactly equals to `TAP_SCHEMA.tables.table_name`
+
+`column_name`
+
+:  - delimited if case sensitive (or if not an ADQL regular identifier)
+   - never qualified
+
+`db_name`
+
+:  - optional
+   - never qualified nor delimited
+   - if `NULL`, exactly equals to undelimited `column_name`
+
+# TAP_SCHEMA.keys
+
+`from_table`
+
+:  exactly equals to `TAP_SCHEMA.tables.table_name`
+
+`target_table`
+
+:  exactly equals to `TAP_SCHEMA.tables.table_name`
+
diff --git a/test/adql/db/TestDefaultDBTable.java b/test/adql/db/TestDefaultDBTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..016ee2bade4a7be8c80011b3aa4dca14ae739aa3
--- /dev/null
+++ b/test/adql/db/TestDefaultDBTable.java
@@ -0,0 +1,70 @@
+package adql.db;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TestDefaultDBTable {
+
+	@Test
+	public void testIsDelimited() {
+		// CASE: All correctly delimited names
+		assertTrue(DefaultDBTable.isDelimited("\"\""));
+		assertTrue(DefaultDBTable.isDelimited("\" \""));
+		assertTrue(DefaultDBTable.isDelimited("\"a\""));
+		assertTrue(DefaultDBTable.isDelimited("\"\"\"\""));
+		assertTrue(DefaultDBTable.isDelimited("\"foo.bar\""));
+		assertTrue(DefaultDBTable.isDelimited("\"foo\"\".\"\"bar\""));
+
+		// CASE: NOT delimited names
+		assertFalse(DefaultDBTable.isDelimited(null));
+		assertFalse(DefaultDBTable.isDelimited(""));
+		assertFalse(DefaultDBTable.isDelimited("foo"));
+		assertFalse(DefaultDBTable.isDelimited("\"foo"));
+		assertFalse(DefaultDBTable.isDelimited("foo\""));
+		assertFalse(DefaultDBTable.isDelimited("\"foo\".\"bar\""));
+	}
+
+	@Test
+	public void testSetADQLName() {
+
+		DefaultDBTable table = new DefaultDBTable("dbName");
+		assertEquals(table.getDBName(), table.getADQLName());
+		assertFalse(table.isCaseSensitive());
+
+		// CASE: undelimited name => OK
+		table.setADQLName("myTable");
+		assertEquals("myTable", table.getADQLName());
+		assertFalse(table.isCaseSensitive());
+
+		// CASE: No name => use the DBName
+		table.setADQLName(null);
+		assertEquals(table.getDBName(), table.getADQLName());
+		assertFalse(table.isCaseSensitive());
+
+		// CASE: delimited name => stored undelimited
+		table.setADQLName("\"MyTable\"");
+		assertEquals("MyTable", table.getADQLName());
+		assertTrue(table.isCaseSensitive());
+
+		// CASE: Empty string => use the DBName (as name=NULL)
+		table.setADQLName("");
+		assertEquals(table.getDBName(), table.getADQLName());
+		assertFalse(table.isCaseSensitive());
+
+		// CASE: dbName delimited and no ADQL name => adqlName = undelimited dbName
+		table = new DefaultDBTable("\"DBName\"");
+		table.setADQLName(null);
+		assertEquals("DBName", table.getADQLName());
+		assertTrue(table.isCaseSensitive());
+
+		// CASE: dbName delimited but empty and no ADQL name => adqlName = delimited dbName
+		table = new DefaultDBTable("\"  \"");
+		table.setADQLName(null);
+		assertEquals(table.getDBName(), table.getADQLName());
+		assertFalse(table.isCaseSensitive());
+	}
+
+}
diff --git a/test/tap/metadata/TestMetadataNames.java b/test/tap/metadata/TestMetadataNames.java
index 1e95f5c46492a02aad6bb60ce7690c41f26bba2c..4fdb9c9e98555cba22cee1f9c0b8f94b9d10f7cc 100644
--- a/test/tap/metadata/TestMetadataNames.java
+++ b/test/tap/metadata/TestMetadataNames.java
@@ -1,6 +1,8 @@
 package tap.metadata;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.PrintWriter;
@@ -17,81 +19,97 @@ public class TestMetadataNames {
 
 	/** TEST SCHEMA NAME */
 	@Test
-	public void testSchemaName(){
+	public void testSchemaName() {
 		TAPSchema schema;
 
 		// NULL
-		try{
+		try {
 			new TAPSchema(null);
 			fail("It should be impossible to create a TAPSchema with a NULL name.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing schema name!", npe.getMessage());
 		}
 
 		// Empty string (not a single character):
-		try{
+		try {
 			new TAPSchema("");
 			fail("It should be impossible to create a TAPSchema with an empty name.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing schema name!", npe.getMessage());
 		}
 
 		// String with only space characters:
-		try{
+		try {
 			new TAPSchema(" 	");
 			fail("It should be impossible to create a TAPSchema with a name just composed of space characters.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing schema name!", npe.getMessage());
 		}
 
-		// Empty quoted string:
-		try{
+		// Empty quoted string I:
+		try {
 			new TAPSchema("\"\"");
 			fail("It should be impossible to create a TAPSchema with a empty name even if quoted.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
+			assertEquals("Missing schema name!", npe.getMessage());
+		}
+
+		// Empty quoted string II:
+		try {
+			new TAPSchema("\" \"");
+			fail("It should be impossible to create a TAPSchema with a empty name even if quoted.");
+		} catch(NullPointerException npe) {
 			assertEquals("Missing schema name!", npe.getMessage());
 		}
 
 		// Non quoted names => ADQL_NAME = RAW_NAME = TRIMMED(GIVEN_NAME)
-		try{
+		try {
 			schema = new TAPSchema("foo");
 			assertEquals("foo", schema.getADQLName());
+			assertFalse(schema.isCaseSensitive());
 			assertEquals("foo", schema.getRawName());
+			assertEquals(schema.getRawName(), schema.toString());
 
 			schema = new TAPSchema("	foo ");
 			assertEquals("foo", schema.getADQLName());
+			assertFalse(schema.isCaseSensitive());
 			assertEquals("foo", schema.getRawName());
+			assertEquals(schema.getRawName(), schema.toString());
 
 			// Qualified name => Not supported as a catalog name!
 			schema = new TAPSchema("myCat.foo");
 			assertEquals("myCat.foo", schema.getADQLName());
+			assertFalse(schema.isCaseSensitive());
 			assertEquals("myCat.foo", schema.getRawName());
+			assertEquals(schema.getRawName(), schema.toString());
 
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			npe.printStackTrace(System.err);
 			fail("Unexpected error! The schema name is not empty or NULL. (see console for more details)");
 		}
 
 		// Quoted names => ADQL_NAME <> RAW_NAME = TRIMMED(GIVEN_NAME)
-		try{
-			schema = new TAPSchema("\" 	\"");
-			assertEquals(" 	", schema.getADQLName());
-			assertEquals("\" 	\"", schema.getRawName());
-
+		try {
 			schema = new TAPSchema("\"foo\"");
 			assertEquals("foo", schema.getADQLName());
+			assertTrue(schema.isCaseSensitive());
 			assertEquals("\"foo\"", schema.getRawName());
+			assertEquals(schema.getRawName(), schema.toString());
 
 			schema = new TAPSchema(" \"	foo \"	");
 			assertEquals("	foo ", schema.getADQLName());
+			assertTrue(schema.isCaseSensitive());
 			assertEquals("\"	foo \"", schema.getRawName());
+			assertEquals(schema.getRawName(), schema.toString());
 
 			// Qualified name => Not supported as a catalog name!
 			schema = new TAPSchema("myCat.\"foo\"");
 			assertEquals("myCat.\"foo\"", schema.getADQLName());
+			assertFalse(schema.isCaseSensitive());
 			assertEquals("myCat.\"foo\"", schema.getRawName());
+			assertEquals(schema.getRawName(), schema.toString());
 
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			npe.printStackTrace(System.err);
 			fail("Unexpected error! The schema name is not empty or NULL. (see console for more details)");
 		}
@@ -99,119 +117,137 @@ public class TestMetadataNames {
 
 	/** TEST TABLE NAME */
 	@Test
-	public void testTableName(){
+	public void testTableName() {
 		TAPTable table, table2, table3;
 
 		// NULL
-		try{
+		try {
 			new TAPTable(null);
 			fail("It should be impossible to create a TAPTable with a NULL name.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing table name!", npe.getMessage());
 		}
 
 		// Empty string (not a single character):
-		try{
+		try {
 			new TAPTable("");
 			fail("It should be impossible to create a TAPTable with an empty name.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing table name!", npe.getMessage());
 		}
 
 		// String with only space characters:
-		try{
+		try {
 			new TAPTable(" 	");
 			fail("It should be impossible to create a TAPTable with a name just composed of space characters.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing table name!", npe.getMessage());
 		}
 
-		// Empty quoted string:
-		try{
+		// Empty quoted string I:
+		try {
 			new TAPTable("\"\"");
 			fail("It should be impossible to create a TAPTable with a empty name even if quoted.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
+			assertEquals("Missing table name!", npe.getMessage());
+		}
+
+		// Empty quoted string II:
+		try {
+			new TAPTable("\" \"");
+			fail("It should be impossible to create a TAPTable with a empty name even if quoted.");
+		} catch(NullPointerException npe) {
 			assertEquals("Missing table name!", npe.getMessage());
 		}
 
 		// Non quoted names => ADQL_NAME = RAW_NAME = TRIMMED(GIVEN_NAME)
-		try{
+		try {
 			table = new TAPTable("foo");
 			assertEquals("foo", table.getADQLName());
+			assertFalse(table.isCaseSensitive());
 			assertEquals("foo", table.getRawName());
 
 			table = new TAPTable("	foo ");
 			assertEquals("foo", table.getADQLName());
+			assertFalse(table.isCaseSensitive());
 			assertEquals("foo", table.getRawName());
 
-			// Qualified name => Without a schema link, no prefix can be removed!
+			// Qualified name => Without a schema link, a default cut is done:
 			table = new TAPTable("mySchema.foo");
-			assertEquals("mySchema.foo", table.getADQLName());
 			assertEquals("mySchema.foo", table.getRawName());
+			assertEquals(table.getRawName(), table.getADQLName());
+			assertFalse(table.isCaseSensitive());
 
 			// Qualified name + Schema with the WRONG name:
 			table.setSchema(new TAPSchema("Blabla"));
 			assertEquals("mySchema.foo", table.getADQLName());
+			assertFalse(table.isCaseSensitive());
 			assertEquals("mySchema.foo", table.getRawName());
 
 			// Qualified name + Schema with the RIGHT name:
 			table.setSchema(new TAPSchema("mySchema"));
 			assertEquals("foo", table.getADQLName());
+			assertFalse(table.isCaseSensitive());
 			assertEquals("mySchema.foo", table.getRawName());
 
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			npe.printStackTrace(System.err);
 			fail("Unexpected error! The table name is not empty or NULL. (see console for more details)");
 		}
 
 		// Quoted names => ADQL_NAME <> RAW_NAME = TRIMMED(GIVEN_NAME)
-		try{
-			table = new TAPTable("\" 	\"");
-			assertEquals(" 	", table.getADQLName());
-			assertEquals("\" 	\"", table.getRawName());
-
+		try {
 			table = new TAPTable("\"foo\"");
 			assertEquals("foo", table.getADQLName());
+			assertTrue(table.isCaseSensitive());
 			assertEquals("\"foo\"", table.getRawName());
 
 			table = new TAPTable(" \"	foo \"	");
 			assertEquals("	foo ", table.getADQLName());
+			assertTrue(table.isCaseSensitive());
 			assertEquals("\"	foo \"", table.getRawName());
 
-			// Qualified name => Without a schema link, no prefix can be removed!
+			// Qualified name => a default cut is done:
 			table = new TAPTable("mySchema.\"foo\"");
-			assertEquals("mySchema.\"foo\"", table.getADQLName());
 			assertEquals("mySchema.\"foo\"", table.getRawName());
+			assertEquals(table.getRawName(), table.getADQLName());
+			assertFalse(table.isCaseSensitive());
 			table2 = new TAPTable(" \"mySchema\". \"foo\"");
-			assertEquals("\"mySchema\". \"foo\"", table2.getADQLName());
 			assertEquals("\"mySchema\". \"foo\"", table2.getRawName());
+			assertEquals(table2.getRawName(), table2.getADQLName());
+			assertFalse(table2.isCaseSensitive());
 			table3 = new TAPTable(" \"mySchema\". foo");
-			assertEquals("\"mySchema\". foo", table3.getADQLName());
 			assertEquals("\"mySchema\". foo", table3.getRawName());
+			assertEquals(table3.getRawName(), table3.getADQLName());
+			assertFalse(table3.isCaseSensitive());
 
 			// Qualified name + Schema with the WRONG name:
 			table.setSchema(new TAPSchema("Blabla"));
-			assertEquals("mySchema.\"foo\"", table.getADQLName());
 			assertEquals("mySchema.\"foo\"", table.getRawName());
-			table2.setSchema(new TAPSchema("mySchema"));
-			assertEquals("\"mySchema\". \"foo\"", table2.getADQLName());
-			assertEquals("\"mySchema\". \"foo\"", table2.getRawName());
-			table3.setSchema(new TAPSchema("mySchema"));
-			assertEquals("\"mySchema\". foo", table3.getADQLName());
-			assertEquals("\"mySchema\". foo", table3.getRawName());
+			assertEquals(table.getRawName(), table.getADQLName());
+			assertFalse(table.isCaseSensitive());
 
-			// Qualified name + Schema with the RIGHT name:
-			table.setSchema(new TAPSchema("mySchema"));
+			// Qualified name + Schema with the RIGHT name (not case sensitive):
+			table.setSchema(new TAPSchema("MYSchema"));
 			assertEquals("foo", table.getADQLName());
+			assertTrue(table.isCaseSensitive());
 			assertEquals("mySchema.\"foo\"", table.getRawName());
-			table2.setSchema(new TAPSchema("\"mySchema\""));
+			table2.setSchema(new TAPSchema("MYSchema"));
 			assertEquals("foo", table2.getADQLName());
+			assertTrue(table2.isCaseSensitive());
 			assertEquals("\"mySchema\". \"foo\"", table2.getRawName());
+
+			// Qualified name + Schema with the RIGHT name (case sensitive):
 			table3.setSchema(new TAPSchema("\"mySchema\""));
 			assertEquals("foo", table3.getADQLName());
+			assertFalse(table3.isCaseSensitive());
 			assertEquals("\"mySchema\". foo", table3.getRawName());
+			table3.setSchema(new TAPSchema("\"MYSchema\""));
+			assertEquals("\"mySchema\". foo", table3.getRawName());
+			assertEquals(table3.getRawName(), table3.getADQLName());
+			assertFalse(table3.isCaseSensitive());
 
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			npe.printStackTrace(System.err);
 			fail("Unexpected error! The table name is not empty or NULL. (see console for more details)");
 		}
@@ -219,145 +255,166 @@ public class TestMetadataNames {
 
 	/** TEST COLUMN NAME */
 	@Test
-	public void testColumnName(){
+	public void testColumnName() {
 		TAPColumn column, column2, column3, column4, column5;
 
 		// NULL
-		try{
+		try {
 			new TAPColumn(null);
 			fail("It should be impossible to create a TAPColumn with a NULL name.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing column name!", npe.getMessage());
 		}
 
 		// Empty string (not a single character):
-		try{
+		try {
 			new TAPColumn("");
 			fail("It should be impossible to create a TAPColumn with an empty name.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing column name!", npe.getMessage());
 		}
 
 		// String with only space characters:
-		try{
+		try {
 			new TAPColumn(" 	");
 			fail("It should be impossible to create a TAPColumn with a name just composed of space characters.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			assertEquals("Missing column name!", npe.getMessage());
 		}
 
-		// Empty quoted string:
-		try{
+		// Empty quoted string I:
+		try {
 			new TAPColumn("\"\"");
 			fail("It should be impossible to create a TAPColumn with a empty name even if quoted.");
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
+			assertEquals("Missing column name!", npe.getMessage());
+		}
+
+		// Empty quoted string II:
+		try {
+			new TAPColumn("\" \"");
+			fail("It should be impossible to create a TAPColumn with a empty name even if quoted.");
+		} catch(NullPointerException npe) {
 			assertEquals("Missing column name!", npe.getMessage());
 		}
 
 		// Non quoted names => ADQL_NAME = RAW_NAME = TRIMMED(GIVEN_NAME)
-		try{
+		try {
 			column = new TAPColumn("foo");
-			assertEquals("foo", column.getADQLName());
 			assertEquals("foo", column.getRawName());
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
 
 			column = new TAPColumn("	foo ");
-			assertEquals("foo", column.getADQLName());
 			assertEquals("foo", column.getRawName());
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
 
-			// Qualified name => Without a table link, no prefix can be removed!
+			// Qualified => Not supported
 			column = new TAPColumn("myTable.foo");
-			assertEquals("myTable.foo", column.getADQLName());
 			assertEquals("myTable.foo", column.getRawName());
-
-			// Qualified name + Table with the WRONG name:
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
+			// ...even with a DB link, still not supported:
 			column.setTable(new TAPTable("Blabla"));
-			assertEquals("myTable.foo", column.getADQLName());
 			assertEquals("myTable.foo", column.getRawName());
-
-			// Qualified name + Table with the RIGHT name:
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
 			column.setTable(new TAPTable("myTable"));
-			assertEquals("foo", column.getADQLName());
 			assertEquals("myTable.foo", column.getRawName());
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
 
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			npe.printStackTrace(System.err);
 			fail("Unexpected error! The column name is not empty or NULL. (see console for more details)");
 		}
 
 		// Quoted names => ADQL_NAME <> RAW_NAME = TRIMMED(GIVEN_NAME)
-		try{
-			column = new TAPColumn("\" 	\"");
-			assertEquals(" 	", column.getADQLName());
-			assertEquals("\" 	\"", column.getRawName());
-
+		try {
 			column = new TAPColumn("\"foo\"");
 			assertEquals("foo", column.getADQLName());
+			assertTrue(column.isCaseSensitive());
 			assertEquals("\"foo\"", column.getRawName());
 
 			column = new TAPColumn(" \"	foo \"	");
 			assertEquals("	foo ", column.getADQLName());
+			assertTrue(column.isCaseSensitive());
 			assertEquals("\"	foo \"", column.getRawName());
 
-			// Qualified name => Without a table link, no prefix can be removed!
+			// Qualified name => not supported
 			column = new TAPColumn("myTable.\"foo\"");
-			assertEquals("myTable.\"foo\"", column.getADQLName());
 			assertEquals("myTable.\"foo\"", column.getRawName());
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
 			column2 = new TAPColumn(" \"myTable\". \"foo\"");
-			assertEquals("\"myTable\". \"foo\"", column2.getADQLName());
 			assertEquals("\"myTable\". \"foo\"", column2.getRawName());
+			assertEquals(column2.getRawName(), column2.getADQLName());
+			assertFalse(column2.isCaseSensitive());
 			column3 = new TAPColumn(" \"myTable\". foo");
-			assertEquals("\"myTable\". foo", column3.getADQLName());
 			assertEquals("\"myTable\". foo", column3.getRawName());
+			assertEquals(column3.getRawName(), column3.getADQLName());
+			assertFalse(column3.isCaseSensitive());
 			column4 = new TAPColumn(" mySchema.\"myTable\". foo");
-			assertEquals("mySchema.\"myTable\". foo", column4.getADQLName());
 			assertEquals("mySchema.\"myTable\". foo", column4.getRawName());
+			assertEquals(column4.getRawName(), column4.getADQLName());
+			assertFalse(column4.isCaseSensitive());
 			column5 = new TAPColumn(" \"mySchema\".\"myTable\". foo");
-			assertEquals("\"mySchema\".\"myTable\". foo", column5.getADQLName());
 			assertEquals("\"mySchema\".\"myTable\". foo", column5.getRawName());
+			assertEquals(column5.getRawName(), column5.getADQLName());
+			assertFalse(column5.isCaseSensitive());
 
-			// Qualified name + Table with the WRONG name:
+			// ...even with a DB link, still not supported:
 			column.setTable(new TAPTable("Blabla"));
-			assertEquals("myTable.\"foo\"", column.getADQLName());
 			assertEquals("myTable.\"foo\"", column.getRawName());
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
 			column2.setTable(new TAPTable("myTable"));
-			assertEquals("\"myTable\". \"foo\"", column2.getADQLName());
 			assertEquals("\"myTable\". \"foo\"", column2.getRawName());
+			assertEquals(column2.getRawName(), column2.getADQLName());
+			assertFalse(column2.isCaseSensitive());
 			column3.setTable(new TAPTable("myTable"));
-			assertEquals("\"myTable\". foo", column3.getADQLName());
 			assertEquals("\"myTable\". foo", column3.getRawName());
+			assertEquals(column3.getRawName(), column3.getADQLName());
+			assertFalse(column3.isCaseSensitive());
 			TAPTable t = new TAPTable("mySchema.myTable");
 			t.setSchema(new TAPSchema("mySchema"));
 			column4.setTable(t);
-			assertEquals("mySchema.\"myTable\". foo", column4.getADQLName());
 			assertEquals("mySchema.\"myTable\". foo", column4.getRawName());
+			assertEquals(column4.getRawName(), column4.getADQLName());
+			assertFalse(column4.isCaseSensitive());
 			t = new TAPTable("\"mySchema\".myTable");
 			t.setSchema(new TAPSchema("\"mySchema\""));
 			column5.setTable(t);
-			assertEquals("\"mySchema\".\"myTable\". foo", column5.getADQLName());
 			assertEquals("\"mySchema\".\"myTable\". foo", column5.getRawName());
-
-			// Qualified name + Table with the RIGHT name:
+			assertEquals(column5.getRawName(), column5.getADQLName());
+			assertFalse(column5.isCaseSensitive());
 			column.setTable(new TAPTable("myTable"));
-			assertEquals("foo", column.getADQLName());
 			assertEquals("myTable.\"foo\"", column.getRawName());
+			assertEquals(column.getRawName(), column.getADQLName());
+			assertFalse(column.isCaseSensitive());
 			column2.setTable(new TAPTable("\"myTable\""));
-			assertEquals("foo", column2.getADQLName());
 			assertEquals("\"myTable\". \"foo\"", column2.getRawName());
+			assertEquals(column2.getRawName(), column2.getADQLName());
+			assertFalse(column2.isCaseSensitive());
 			column3.setTable(new TAPTable("\"myTable\""));
-			assertEquals("foo", column3.getADQLName());
 			assertEquals("\"myTable\". foo", column3.getRawName());
+			assertEquals(column3.getRawName(), column3.getADQLName());
+			assertFalse(column3.isCaseSensitive());
 			t = new TAPTable("mySchema.\"myTable\"");
 			t.setSchema(new TAPSchema("mySchema"));
 			column4.setTable(t);
-			assertEquals("foo", column4.getADQLName());
 			assertEquals("mySchema.\"myTable\". foo", column4.getRawName());
+			assertEquals(column4.getRawName(), column4.getADQLName());
+			assertFalse(column4.isCaseSensitive());
 			t = new TAPTable("\"mySchema\".\"myTable\"");
 			t.setSchema(new TAPSchema("\"mySchema\""));
 			column5.setTable(t);
-			assertEquals("foo", column5.getADQLName());
 			assertEquals("\"mySchema\".\"myTable\". foo", column5.getRawName());
+			assertEquals(column5.getRawName(), column5.getADQLName());
+			assertFalse(column5.isCaseSensitive());
 
-		}catch(NullPointerException npe){
+		} catch(NullPointerException npe) {
 			npe.printStackTrace(System.err);
 			fail("Unexpected error! The column name is not empty or NULL. (see console for more details)");
 		}
@@ -365,7 +422,7 @@ public class TestMetadataNames {
 
 	/** TEST XML METADATA */
 	@Test
-	public void testXMLMetadata(){
+	public void testXMLMetadata() {
 		TAPMetadata metadata = new TAPMetadata();
 
 		TAPSchema schema = new TAPSchema("blabla");
@@ -383,11 +440,8 @@ public class TestMetadataNames {
 		Iterator<TAPColumn> itCol = table.getColumns();
 		assertEquals("col1", itCol.next().getADQLName());
 		assertEquals("col2", itCol.next().getADQLName());
-		assertEquals("col3", itCol.next().getADQLName());
+		assertEquals("foo.col3", itCol.next().getADQLName());
 		assertEquals("blabla.foo.col4", itCol.next().getADQLName());
-		/* Note for below:
-		 * Only ADQL allows schema.table.column. Here, the table name MUST be exactly
-		 * the same as the one written in the TAP_SCHEMA.tables (so, the trimmed raw name). */
 		assertEquals("foo2.col5", itCol.next().getADQLName());
 
 		table = new TAPTable(" \"foo.bar\"");
@@ -400,7 +454,7 @@ public class TestMetadataNames {
 		assertEquals("foo.bar", table.getADQLName());
 		itCol = table.getColumns();
 		assertEquals("foo.bar.col1", itCol.next().getADQLName());
-		assertEquals("col2", itCol.next().getADQLName());
+		assertEquals("\"foo.bar\".col2", itCol.next().getADQLName());
 		assertEquals("blabla.foo.bar.col3", itCol.next().getADQLName());
 		assertEquals("blabla.\"foo.bar\".col4", itCol.next().getADQLName());
 		/* Note for below:
@@ -427,7 +481,7 @@ public class TestMetadataNames {
 		/* Note for below:
 		 * Same as for the 4th column of the table "foo". */
 		assertEquals("bloblo.bar.col4", itCol.next().getADQLName());
-		assertEquals("col5", itCol.next().getADQLName());
+		assertEquals("myCat.bloblo.bar.col5", itCol.next().getADQLName());
 
 		metadata.addSchema(schema);
 
@@ -435,12 +489,12 @@ public class TestMetadataNames {
 		assertEquals("Mon Super Schema", schema.getADQLName());
 		metadata.addSchema(schema);
 
-		try{
+		try {
 			StringWriter str = new StringWriter();
 			metadata.write(new PrintWriter(str));
 			//System.out.println(str.toString());
 			assertEquals(expectedXMLMetadata, str.toString());
-		}catch(Exception ex){
+		} catch(Exception ex) {
 			ex.printStackTrace(System.err);
 			fail("Unexpected error when writing TAP metadata into an XML format! (see console for more details)");
 		}