From 03d03c503e11a5923ba657e2bb83b036b101761a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gr=C3=A9gory=20Mantelet?=
 <gregory.mantelet@astro.unistra.fr>
Date: Tue, 10 Sep 2019 15:22:57 +0200
Subject: [PATCH] [ADQL,TAP] + isCaseSensitive() in DBSchema, DBTable and
 DBColumn + Change rules about TAP_SCHEMA columns `schema_name`, `table_name`
 and `column_name` (see tap_schema_requirements.md for more details).

---
 build.gradle                             |   2 +-
 lib/astroh2-0.3.jar                      | Bin 16330 -> 0 bytes
 lib/astroh2-0.4.jar                      | Bin 0 -> 17132 bytes
 src/adql/db/DBColumn.java                |  51 +-
 src/adql/db/DBCommonColumn.java          | 149 ++--
 src/adql/db/DBTable.java                 |  57 +-
 src/adql/db/DefaultDBColumn.java         | 103 ++-
 src/adql/db/DefaultDBTable.java          | 339 +++++---
 src/tap/db/JDBCConnection.java           | 750 +++++++++---------
 src/tap/metadata/TAPColumn.java          | 952 +++++++++++-----------
 src/tap/metadata/TAPSchema.java          | 411 +++++-----
 src/tap/metadata/TAPTable.java           | 965 ++++++++++++-----------
 tap_schema_requirements.md               |  55 ++
 test/adql/db/TestDefaultDBTable.java     |  70 ++
 test/tap/metadata/TestMetadataNames.java | 270 ++++---
 15 files changed, 2398 insertions(+), 1776 deletions(-)
 delete mode 100644 lib/astroh2-0.3.jar
 create mode 100644 lib/astroh2-0.4.jar
 create mode 100644 tap_schema_requirements.md
 create mode 100644 test/adql/db/TestDefaultDBTable.java

diff --git a/build.gradle b/build.gradle
index 9954559..4ff3b0d 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
GIT binary patch
literal 0
HcmV?d00001

literal 16330
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
QG4L^*VrF1?Wews10Go==#{d8T

diff --git a/lib/astroh2-0.4.jar b/lib/astroh2-0.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..e84fe823837af2b0a9a8954da777f99d460c9f11
GIT binary patch
literal 17132
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

literal 0
HcmV?d00001

diff --git a/src/adql/db/DBColumn.java b/src/adql/db/DBColumn.java
index 89f48b6..07988bf 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 44c6642..f86ca9f 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 9f5c25c..8ff8dea 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 0336e24..f262b6f 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 19762a9..fb89c04 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 4e4f17e..6f2ac2f 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 936909f..6516976 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 e225141..f1e6e0c 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 02a2402..312905a 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 0000000..04c1805
--- /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 0000000..016ee2b
--- /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 1e95f5c..4fdb9c9 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)");
 		}
-- 
GitLab