From 19026c1b408e0742ae50bea8bfef379bc77455c9 Mon Sep 17 00:00:00 2001
From: gmantele <gmantele@ari.uni-heidelberg.de>
Date: Wed, 13 Jul 2016 15:54:01 +0200
Subject: [PATCH] [TAP] Fix interpretation of quoted and/or qualified names for
 schema, table and column in TAP_SCHEMA. Such names are normalized (without
 any prefix and without double quotes) when getADQLName() is called, but are
 returned just trimmed by getRawName(). This latter is just used by
 TAPMetadata when writing the XML description of all TAP tables.

---
 src/adql/db/DBColumn.java                |   6 +-
 src/adql/db/DBTable.java                 |   6 +-
 src/tap/db/JDBCConnection.java           |  18 +-
 src/tap/metadata/TAPColumn.java          | 373 +++++++++++++------
 src/tap/metadata/TAPMetadata.java        |  48 +--
 src/tap/metadata/TAPSchema.java          | 161 ++++++--
 src/tap/metadata/TAPTable.java           | 196 +++++++---
 test/tap/metadata/TestMetadataNames.java | 452 +++++++++++++++++++++++
 8 files changed, 1023 insertions(+), 237 deletions(-)
 create mode 100644 test/tap/metadata/TestMetadataNames.java

diff --git a/src/adql/db/DBColumn.java b/src/adql/db/DBColumn.java
index c987e06..89f48b6 100644
--- a/src/adql/db/DBColumn.java
+++ b/src/adql/db/DBColumn.java
@@ -16,7 +16,7 @@ package adql.db;
  * 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,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2011-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -29,12 +29,12 @@ package adql.db;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.3 (10/2014)
+ * @version 1.4 (07/2016)
  */
 public interface DBColumn {
 
 	/**
-	 * Gets the name of this column which must be used in an ADQL query.
+	 * Gets the name of this column (without any prefix and double-quotes).
 	 * 
 	 * @return	Its ADQL name.
 	 */
diff --git a/src/adql/db/DBTable.java b/src/adql/db/DBTable.java
index f72389f..9f5c25c 100644
--- a/src/adql/db/DBTable.java
+++ b/src/adql/db/DBTable.java
@@ -16,7 +16,7 @@ package adql.db;
  * 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,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -29,12 +29,12 @@ package adql.db;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.3 (09/2014)
+ * @version 1.4 (07/2016)
  */
 public interface DBTable extends Iterable<DBColumn> {
 
 	/**
-	 * Gets the name of this table which must be used in an ADQL query.
+	 * Gets the name of this table (without any prefix and double-quotes).
 	 * 
 	 * @return	Its ADQL name.
 	 */
diff --git a/src/tap/db/JDBCConnection.java b/src/tap/db/JDBCConnection.java
index 7d50a58..281718d 100644
--- a/src/tap/db/JDBCConnection.java
+++ b/src/tap/db/JDBCConnection.java
@@ -177,7 +177,7 @@ import uws.service.log.UWSLog.LogLevel;
  * </i></p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.1 (06/2016)
+ * @version 2.1 (07/2016)
  * @since 2.0
  */
 public class JDBCConnection implements DBConnection {
@@ -1750,8 +1750,8 @@ public class JDBCConnection implements DBConnection {
 
 				// add the table entry into the DB:
 				stmt.setString(1, table.getADQLSchemaName());
-				if (table.isInitiallyQualified())
-					stmt.setString(2, table.getADQLSchemaName() + "." + table.getADQLName());
+				if (table instanceof TAPTable)
+					stmt.setString(2, ((TAPTable)table).getRawName());
 				else
 					stmt.setString(2, table.getADQLName());
 				stmt.setString(3, table.getType().toString());
@@ -1819,8 +1819,8 @@ public class JDBCConnection implements DBConnection {
 				appendAllInto(allKeys, col.getTargets());
 
 				// add the column entry into the DB:
-				if (!(col.getTable() instanceof TAPTable) || ((TAPTable)col.getTable()).isInitiallyQualified())
-					stmt.setString(1, col.getTable().getADQLSchemaName() + "." + col.getTable().getADQLName());
+				if (col.getTable() instanceof TAPTable)
+					stmt.setString(1, ((TAPTable)col.getTable()).getRawName());
 				else
 					stmt.setString(1, col.getTable().getADQLName());
 				stmt.setString(2, col.getADQLName());
@@ -1894,12 +1894,12 @@ public class JDBCConnection implements DBConnection {
 
 				// add the key entry into KEYS:
 				stmtKeys.setString(1, key.getKeyId());
-				if (key.getFromTable().isInitiallyQualified())
-					stmtKeys.setString(2, key.getFromTable().getADQLSchemaName() + "." + key.getFromTable().getADQLName());
+				if (key.getFromTable() instanceof TAPTable)
+					stmtKeys.setString(2, ((TAPTable)key.getFromTable()).getRawName());
 				else
 					stmtKeys.setString(2, key.getFromTable().getADQLName());
-				if (key.getTargetTable().isInitiallyQualified())
-					stmtKeys.setString(3, key.getTargetTable().getADQLSchemaName() + "." + key.getTargetTable().getADQLName());
+				if (key.getTargetTable() instanceof TAPTable)
+					stmtKeys.setString(3, ((TAPTable)key.getTargetTable()).getRawName());
 				else
 					stmtKeys.setString(3, key.getTargetTable().getADQLName());
 				stmtKeys.setString(4, key.getDescription());
diff --git a/src/tap/metadata/TAPColumn.java b/src/tap/metadata/TAPColumn.java
index 3365cc6..406af80 100644
--- a/src/tap/metadata/TAPColumn.java
+++ b/src/tap/metadata/TAPColumn.java
@@ -16,7 +16,7 @@ package tap.metadata;
  * 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-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -41,10 +41,12 @@ import adql.db.DBType.DBDatatype;
  * </p>
  * 
  * <p><i><b>Important note:</b>
- * 	A {@link TAPColumn} object MUST always have a DB name. That's why by default, at the creation
- * 	the DB name is the ADQL name. Once created, it is possible to set the DB name with {@link #setDBName(String)}.
+ * 	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,
- * 	nothing is done and the object keeps its former DB name.
+ * 	{@link #getDBName()} returns what {@link #getADQLName()} returns.
  * </i></p>
  * 
  * <h3>Set a table</h3>
@@ -52,7 +54,7 @@ import adql.db.DBType.DBDatatype;
  * <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()}. 
+ *	will be set automatically and you will be able to get the table with {@link #getTable()}.
  * </p>
  * 
  * <h3>Foreign keys</h3>
@@ -67,13 +69,18 @@ import adql.db.DBType.DBDatatype;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.1 (07/2015)
+ * @version 2.1 (07/2016)
  */
 public class TAPColumn implements DBColumn {
 
 	/** Name that this column 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 and the table prefix if any.</p>
+	 * @since 2.1 */
+	private final boolean simplificationNeeded;
+
 	/** Name that this column have in the database.
 	 * <i>Note: It CAN NOT be NULL. By default, it is the ADQL name.</i> */
 	private String dbName = null;
@@ -139,25 +146,48 @@ public class TAPColumn implements DBColumn {
 	/**
 	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given ADQL name.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
-	 * 	The datatype is set by default to VARCHAR.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <p><i>Note 2:
+	 * 	The datatype is set by default to VARCHAR.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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){
-		if (columnName == null || columnName.trim().length() == 0)
-			throw new NullPointerException("Missing column name !");
-		int indPrefix = columnName.lastIndexOf('.');
-		adqlName = (indPrefix >= 0) ? columnName.substring(indPrefix + 1).trim() : columnName.trim();
-		dbName = adqlName;
+	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);
+
+		if (getADQLName().length() == 0)
+			throw new NullPointerException("Missing column name!");
+
+		dbName = null;
+
 		lstTargets = new ArrayList<TAPForeignKey>(1);
 		lstSources = new ArrayList<TAPForeignKey>(1);
 	}
@@ -165,27 +195,40 @@ public class TAPColumn implements DBColumn {
 	/**
 	 * <p>Build a {@link TAPColumn} instance with the given ADQL name and datatype.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
-	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does not do
-	 *	anything if the given datatype is NULL.
+	 * <p><i>Note 2:
+	 * 	The datatype is set by default to VARCHAR.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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).
+	 * 
 	 * @see #setDatatype(DBType)
 	 */
-	public TAPColumn(String columnName, DBType type){
+	public TAPColumn(String columnName, DBType type) throws NullPointerException{
 		this(columnName);
 		setDatatype(type);
 	}
@@ -193,46 +236,78 @@ public class TAPColumn implements DBColumn {
 	/**
 	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given ADQL name and description.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <p><i>Note 2:
+	 * 	The datatype is set by default to VARCHAR.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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){
+	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:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
-	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does do
+	 * <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.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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){
+	public TAPColumn(String columnName, DBType type, String description) throws NullPointerException{
 		this(columnName, type);
 		this.description = description;
 	}
@@ -240,48 +315,80 @@ public class TAPColumn implements DBColumn {
 	/**
 	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given ADQL name, description and unit.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <p><i>Note 2:
+	 * 	The datatype is set by default to VARCHAR.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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){
+	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:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
-	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does do
+	 * <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.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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){
+	public TAPColumn(String columnName, DBType type, String description, String unit) throws NullPointerException{
 		this(columnName, type, description);
 		this.unit = unit;
 	}
@@ -289,57 +396,84 @@ public class TAPColumn implements DBColumn {
 	/**
 	 * <p>Build a VARCHAR {@link TAPColumn} instance with the given fields.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
-	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does do
-	 *	anything if the given datatype is NULL.
+	 * <p><i>Note 2:
+	 * 	The datatype is set by default to VARCHAR.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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 ucd			UCD describing the scientific content of this column.
 	 * @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).
 	 */
-	public TAPColumn(String columnName, String description, String unit, String ucd, String utype){
+	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:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
-	 * </i></p>
-	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the column name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 *	The datatype is set by calling the function {@link #setDatatype(DBType)} which does do
+	 * <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.
 	 * </i></p>
 	 * 
-	 * @param columnName	Name that this column MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</li>
+	 * 	<li>
+	 * 		Double quotes may surround the single column name. They will be removed by {@link #getADQLName()} 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 ucd			UCD describing the scientific content of this column.
 	 * @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).
 	 */
-	public TAPColumn(String columnName, DBType type, String description, String unit, String ucd, String utype){
+	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;
@@ -359,12 +493,37 @@ public class TAPColumn implements DBColumn {
 
 	@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.
+	 * 
+	 * @return	Get the original ADQL name.
+	 * 
+	 * @since 2.1
+	 */
+	public final String getRawName(){
 		return adqlName;
 	}
 
 	@Override
 	public final String getDBName(){
-		return dbName;
+		return (dbName == null) ? getADQLName() : dbName;
 	}
 
 	/**
@@ -380,6 +539,8 @@ public class TAPColumn implements DBColumn {
 		name = (name != null) ? name.trim() : name;
 		if (name != null && name.length() > 0)
 			dbName = name;
+		else
+			dbName = null;
 	}
 
 	@Override
@@ -614,7 +775,7 @@ public class TAPColumn implements DBColumn {
 	 * 
 	 * <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. 
+	 * 	that owns this column or that is part of the foreign key.
 	 * </i></p>
 	 * 
 	 * @param key	A foreign key.
@@ -652,7 +813,7 @@ public class TAPColumn implements DBColumn {
 	 * 
 	 * <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. 
+	 * 	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.
@@ -668,7 +829,7 @@ public class TAPColumn implements DBColumn {
 	 * 
 	 * <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. 
+	 * 	that owns this column or that is part of the foreign key.
 	 * </i></p>
 	 */
 	protected void removeAllTargets(){
@@ -684,7 +845,7 @@ public class TAPColumn implements DBColumn {
 	 * 
 	 * <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. 
+	 * 	that owns this column or that is part of the foreign key.
 	 * </i></p>
 	 * 
 	 * @param key	A foreign key.
@@ -722,7 +883,7 @@ public class TAPColumn implements DBColumn {
 	 * 
 	 * <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. 
+	 * 	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.
@@ -737,7 +898,7 @@ public class TAPColumn implements DBColumn {
 	 * 
 	 * <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. 
+	 * 	that owns this column or that is part of the foreign key.
 	 * </i></p>
 	 */
 	protected void removeAllSources(){
@@ -802,7 +963,7 @@ public class TAPColumn implements DBColumn {
 
 	@Override
 	public String toString(){
-		return ((table != null) ? (table.getADQLName() + ".") : "") + adqlName;
+		return ((table != null) ? (((table.getADQLSchemaName() != null) ? table.getADQLSchemaName() : "") + table.getADQLName() + ".") : "") + getADQLName();
 	}
 
 }
diff --git a/src/tap/metadata/TAPMetadata.java b/src/tap/metadata/TAPMetadata.java
index 8173e3f..d0d10f9 100644
--- a/src/tap/metadata/TAPMetadata.java
+++ b/src/tap/metadata/TAPMetadata.java
@@ -16,7 +16,7 @@ package tap.metadata;
  * 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-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -33,6 +33,9 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import adql.db.DBTable;
+import adql.db.DBType;
+import adql.db.DBType.DBDatatype;
 import tap.metadata.TAPTable.TableType;
 import tap.resource.Capabilities;
 import tap.resource.TAPResource;
@@ -40,9 +43,6 @@ import tap.resource.VOSIResource;
 import uk.ac.starlink.votable.VOSerializer;
 import uws.ClientAbortException;
 import uws.UWSToolBox;
-import adql.db.DBTable;
-import adql.db.DBType;
-import adql.db.DBType.DBDatatype;
 
 /**
  * <p>Let listing all schemas, tables and columns available in a TAP service.
@@ -64,7 +64,7 @@ import adql.db.DBType.DBDatatype;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.1 (10/2015)
+ * @version 2.1 (07/2016)
  */
 public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResource {
 
@@ -99,7 +99,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 	 * 	Otherwise, if you want customize just some part of this schema, you can also use the function
 	 * 	{@link #getStdTable(STDTable)} to get just the standard definition of some of its tables, either
 	 * 	to customize them or to merely get them and keep them like they are.
-	 * </i></p> 
+	 * </i></p>
 	 */
 	public TAPMetadata(){
 		schemas = new LinkedHashMap<String,TAPSchema>();
@@ -518,7 +518,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 		final String prefix = "\t\t";
 		writer.println("\t<schema>");
 
-		writeAtt(prefix, "name", s.getADQLName(), false, writer);
+		writeAtt(prefix, "name", s.getRawName(), false, writer);
 		writeAtt(prefix, "title", s.getTitle(), true, writer);
 		writeAtt(prefix, "description", s.getDescription(), true, writer);
 		writeAtt(prefix, "utype", s.getUtype(), true, writer);
@@ -587,10 +587,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 		}
 		writer.println(">");
 
-		if (t.isInitiallyQualified())
-			writeAtt(prefix, "name", t.getADQLSchemaName() + "." + t.getADQLName(), false, writer);
-		else
-			writeAtt(prefix, "name", t.getADQLName(), false, writer);
+		writeAtt(prefix, "name", t.getRawName(), false, writer);
 		writeAtt(prefix, "title", t.getTitle(), true, writer);
 		writeAtt(prefix, "description", t.getDescription(), true, writer);
 		writeAtt(prefix, "utype", t.getUtype(), true, writer);
@@ -643,7 +640,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 			writer.print(" std=\"true\"");
 		writer.println(">");
 
-		writeAtt(prefix, "name", c.getADQLName(), false, writer);
+		writeAtt(prefix, "name", c.getRawName(), false, writer);
 		writeAtt(prefix, "description", c.getDescription(), true, writer);
 		writeAtt(prefix, "unit", c.getUnit(), true, writer);
 		writeAtt(prefix, "ucd", c.getUcd(), true, writer);
@@ -701,7 +698,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 
 		writer.println("\t\t\t<foreignKey>");
 
-		writeAtt(prefix, "targetTable", fk.getTargetTable().getFullName(), false, writer);
+		writeAtt(prefix, "targetTable", fk.getTargetTable().getRawName(), false, writer);
 		writeAtt(prefix, "description", fk.getDescription(), true, writer);
 		writeAtt(prefix, "utype", fk.getUtype(), true, writer);
 
@@ -724,8 +721,8 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 	 * @param prefix			Prefix of the XML node. (generally, space characters)
 	 * @param attributeName		Name of the metadata attribute to write (= Name of the XML node).
 	 * @param attributeValue	Value of the metadata attribute (= Value of the XML node).
-	 * @param isOptionalAttr	<i>true</i> if the attribute to write is optional (in this case, if the value is NULL or an empty string, the whole attribute item won't be written), 
-	 *                      	<i>false</i> otherwise (here, if the value is NULL or an empty string, the XML item will be written with an empty string as value). 
+	 * @param isOptionalAttr	<i>true</i> if the attribute to write is optional (in this case, if the value is NULL or an empty string, the whole attribute item won't be written),
+	 *                      	<i>false</i> otherwise (here, if the value is NULL or an empty string, the XML item will be written with an empty string as value).
 	 * @param writer			Output in which the XML node must be written.
 	 */
 	protected final void writeAtt(String prefix, String attributeName, String attributeValue, boolean isOptionalAttr, PrintWriter writer){
@@ -763,9 +760,9 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 			tap_schema.setDBName(null);
 		for(STDTable t : STDTable.values()){
 			TAPTable table = getStdTable(t);
+			tap_schema.addTable(table);
 			if (!isSchemaSupported)
 				table.setDBName(STDSchema.TAPSCHEMA.label + "_" + table.getADQLName());
-			tap_schema.addTable(table);
 		}
 		return tap_schema;
 	}
@@ -792,16 +789,14 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 		switch(tableId){
 
 			case SCHEMAS:
-				TAPTable schemas = new TAPTable(STDTable.SCHEMAS.toString(), TableType.table, "List of schemas published in this TAP service.", null);
-				schemas.setInitiallyQualifed(true);
+				TAPTable schemas = new TAPTable(STDSchema.TAPSCHEMA + "." + STDTable.SCHEMAS, TableType.table, "List of schemas published in this TAP service.", null);
 				schemas.addColumn("schema_name", new DBType(DBDatatype.VARCHAR), "schema name, possibly qualified", null, null, null, true, true, true);
 				schemas.addColumn("description", new DBType(DBDatatype.VARCHAR), "brief description of schema", null, null, null, false, false, true);
 				schemas.addColumn("utype", new DBType(DBDatatype.VARCHAR), "UTYPE if schema corresponds to a data model", null, null, null, false, false, true);
 				return schemas;
 
 			case TABLES:
-				TAPTable tables = new TAPTable(STDTable.TABLES.toString(), TableType.table, "List of tables published in this TAP service.", null);
-				tables.setInitiallyQualifed(true);
+				TAPTable tables = new TAPTable(STDSchema.TAPSCHEMA + "." + STDTable.TABLES, TableType.table, "List of tables published in this TAP service.", null);
 				tables.addColumn("schema_name", new DBType(DBDatatype.VARCHAR), "the schema name from TAP_SCHEMA.schemas", null, null, null, true, true, true);
 				tables.addColumn("table_name", new DBType(DBDatatype.VARCHAR), "table name as it should be used in queries", null, null, null, true, true, true);
 				tables.addColumn("table_type", new DBType(DBDatatype.VARCHAR), "one of: table, view", null, null, null, false, false, true);
@@ -810,8 +805,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 				return tables;
 
 			case COLUMNS:
-				TAPTable columns = new TAPTable(STDTable.COLUMNS.toString(), TableType.table, "List of columns of all tables listed in TAP_SCHEMA.TABLES and published in this TAP service.", null);
-				columns.setInitiallyQualifed(true);
+				TAPTable columns = new TAPTable(STDSchema.TAPSCHEMA + "." + STDTable.COLUMNS, TableType.table, "List of columns of all tables listed in TAP_SCHEMA.TABLES and published in this TAP service.", null);
 				columns.addColumn("table_name", new DBType(DBDatatype.VARCHAR), "table name from TAP_SCHEMA.tables", null, null, null, true, true, true);
 				columns.addColumn("column_name", new DBType(DBDatatype.VARCHAR), "column name", null, null, null, true, true, true);
 				columns.addColumn("description", new DBType(DBDatatype.VARCHAR), "brief description of column", null, null, null, false, false, true);
@@ -826,8 +820,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 				return columns;
 
 			case KEYS:
-				TAPTable keys = new TAPTable(STDTable.KEYS.toString(), TableType.table, "List all foreign keys but provides just the tables linked by the foreign key. To know which columns of these tables are linked, see in TAP_SCHEMA.key_columns using the key_id.", null);
-				keys.setInitiallyQualifed(true);
+				TAPTable keys = new TAPTable(STDSchema.TAPSCHEMA + "." + STDTable.KEYS, TableType.table, "List all foreign keys but provides just the tables linked by the foreign key. To know which columns of these tables are linked, see in TAP_SCHEMA.key_columns using the key_id.", null);
 				keys.addColumn("key_id", new DBType(DBDatatype.VARCHAR), "unique key identifier", null, null, null, true, true, true);
 				keys.addColumn("from_table", new DBType(DBDatatype.VARCHAR), "fully qualified table name", null, null, null, false, false, true);
 				keys.addColumn("target_table", new DBType(DBDatatype.VARCHAR), "fully qualified table name", null, null, null, false, false, true);
@@ -836,8 +829,7 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 				return keys;
 
 			case KEY_COLUMNS:
-				TAPTable key_columns = new TAPTable(STDTable.KEY_COLUMNS.toString(), TableType.table, "List all foreign keys but provides just the columns linked by the foreign key. To know the table of these columns, see in TAP_SCHEMA.keys using the key_id.", null);
-				key_columns.setInitiallyQualifed(true);
+				TAPTable key_columns = new TAPTable(STDSchema.TAPSCHEMA + "." + STDTable.KEY_COLUMNS, TableType.table, "List all foreign keys but provides just the columns linked by the foreign key. To know the table of these columns, see in TAP_SCHEMA.keys using the key_id.", null);
 				key_columns.addColumn("key_id", new DBType(DBDatatype.VARCHAR), "unique key identifier", null, null, null, true, true, true);
 				key_columns.addColumn("from_column", new DBType(DBDatatype.VARCHAR), "key column name in the from_table", null, null, null, false, false, true);
 				key_columns.addColumn("target_column", new DBType(DBDatatype.VARCHAR), "key column name in the target_table", null, null, null, false, false, true);
@@ -853,11 +845,11 @@ public class TAPMetadata implements Iterable<TAPSchema>, VOSIResource, TAPResour
 	 * 
 	 * <p><i>Note:
 	 *	This function is case sensitive. Indeed TAP_SCHEMA tables are defined by the TAP standard by a given case.
-	 *	Thus, this case is expected here.  
+	 *	Thus, this case is expected here.
 	 * </i></p>
 	 * 
 	 * @param tableName	Unqualified table name.
-	 *  
+	 * 
 	 * @return	The corresponding {@link STDTable} or NULL if the given table is not part of the TAP standard.
 	 * 
 	 * @since 2.0
diff --git a/src/tap/metadata/TAPSchema.java b/src/tap/metadata/TAPSchema.java
index 182c421..cac4049 100644
--- a/src/tap/metadata/TAPSchema.java
+++ b/src/tap/metadata/TAPSchema.java
@@ -16,7 +16,7 @@ package tap.metadata;
  * 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,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
+ * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -39,20 +39,27 @@ import tap.metadata.TAPTable.TableType;
  * 
  * <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 ADQL name. 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.
+ * 	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.0 (02/2015)
+ * @version 2.1 (07/2016)
  */
 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;
+
 	/** Name that this schema have in the database.
-	 * <i>Note: It MAY be NULL. By default, it is the ADQL name.</i> */
+	 * <i>Note: NULL by default. When NULL, {@link #getDBName()} returns exactly what {@link #getADQLName()} returns.</i> */
 	private String dbName = null;
 
 	/** Descriptive, human-interpretable name of the schema.
@@ -80,23 +87,42 @@ public class TAPSchema implements Iterable<TAPTable> {
 	 * <p>Build a {@link TAPSchema} instance with the given ADQL name.</p>
 	 * 
 	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
+	 * 	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><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the schema name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
-	 * </i></p>
-	 * 
-	 * @param schemaName	Name that this schema MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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>
+	 *	</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()}.
+	 *	</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).
 	 */
-	public TAPSchema(String schemaName){
-		if (schemaName == null || schemaName.trim().length() == 0)
+	public TAPSchema(String schemaName) throws NullPointerException{
+		if (schemaName == null)
 			throw new NullPointerException("Missing schema name!");
-		int indPrefix = schemaName.lastIndexOf('.');
-		adqlName = (indPrefix >= 0) ? schemaName.substring(indPrefix + 1).trim() : schemaName.trim();
-		dbName = adqlName;
+
+		adqlName = schemaName.trim();
+		simplificationNeeded = adqlName.matches("\"[^\"]*\"");
+
+		if (getADQLName().length() == 0)
+			throw new NullPointerException("Missing schema name!");
+
+		dbName = getADQLName();
+
 		tables = new LinkedHashMap<String,TAPTable>();
 	}
 
@@ -104,19 +130,32 @@ public class TAPSchema implements Iterable<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 with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
+	 * 	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><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the schema name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
-	 * </i></p>
-	 * 
-	 * @param schemaName	Name that this schema MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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>
+	 *	</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()}.
+	 *	</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 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).
 	 */
-	public TAPSchema(String schemaName, String description){
+	public TAPSchema(String schemaName, String description) throws NullPointerException{
 		this(schemaName, description, null);
 	}
 
@@ -124,20 +163,33 @@ public class TAPSchema implements Iterable<TAPTable> {
 	 * <p>Build a {@link TAPSchema} instance with the given ADQL name, description and UType.</p>
 	 * 
 	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
+	 * 	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><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the schema name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
-	 * </i></p>
-	 * 
-	 * @param schemaName	Name that this schema MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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>
+	 *	</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()}.
+	 *	</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 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).
 	 */
-	public TAPSchema(String schemaName, String description, String utype){
+	public TAPSchema(String schemaName, String description, String utype) throws NullPointerException{
 		this(schemaName);
 		this.description = description;
 		this.utype = utype;
@@ -156,11 +208,26 @@ public class TAPSchema implements Iterable<TAPTable> {
 	}
 
 	/**
-	 * Get the name this schema MUST have in ADQL queries.
+	 * 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>
 	 */
 	public final String getADQLName(){
+		return simplificationNeeded ? adqlName.substring(1, adqlName.length() - 1) : adqlName;
+	}
+
+	/**
+	 * Get the full ADQL name of this schema, as it has been provided at initialization.
+	 * 
+	 * @return	Get the original ADQL name.
+	 * 
+	 * @since 2.1
+	 */
+	public final String getRawName(){
 		return adqlName;
 	}
 
@@ -176,6 +243,17 @@ public class TAPSchema implements Iterable<TAPTable> {
 	/**
 	 * Set the name this schema MUST have in the database.
 	 * 
+	 * <p>Notes:</p>
+	 * <ul>
+	 * 	<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.
+	 *	</li>
+	 * </ul>
+	 * 
 	 * @param name	Its new DB name. <i>MAY be NULL</i>
 	 */
 	public final void setDBName(String name){
@@ -282,8 +360,8 @@ public class TAPSchema implements Iterable<TAPTable> {
 	 */
 	public final void addTable(TAPTable newTable){
 		if (newTable != null && newTable.getADQLName() != null){
-			tables.put(newTable.getADQLName(), newTable);
 			newTable.setSchema(this);
+			tables.put(newTable.getADQLName(), newTable);
 		}
 	}
 
@@ -416,7 +494,7 @@ public class TAPSchema implements Iterable<TAPTable> {
 	 * </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.
 	 */
@@ -459,4 +537,9 @@ public class TAPSchema implements Iterable<TAPTable> {
 		return tables.values().iterator();
 	}
 
+	@Override
+	public String toString(){
+		return getADQLName();
+	}
+
 }
diff --git a/src/tap/metadata/TAPTable.java b/src/tap/metadata/TAPTable.java
index f3030d0..905394c 100644
--- a/src/tap/metadata/TAPTable.java
+++ b/src/tap/metadata/TAPTable.java
@@ -16,7 +16,7 @@ package tap.metadata;
  * 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,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
+ * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -27,10 +27,10 @@ import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import tap.TAPException;
 import adql.db.DBColumn;
 import adql.db.DBTable;
 import adql.db.DBType;
+import tap.TAPException;
 
 /**
  * <p>Represent a table as described by the IVOA standard in the TAP protocol definition.</p>
@@ -43,14 +43,16 @@ import adql.db.DBType;
  * </p>
  * 
  * <p><i><b>Important note:</b>
- * 	A {@link TAPTable} object MUST always have a DB name. That's why by default, at the creation
- * 	the DB name is the ADQL name. Once created, it is possible to set the DB name with {@link #setDBName(String)}.
+ * 	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,
- * 	nothing is done and the object keeps its former DB name.
+ * 	{@link #getDBName()} returns what {@link #getADQLName()} returns.
  * </i></p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (02/2015)
+ * @version 2.1 (07/2016)
  */
 public class TAPTable implements DBTable {
 
@@ -70,13 +72,20 @@ public class TAPTable implements DBTable {
 	/** Name that this table 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 and the schema prefix if any.</p>
+	 * @since 2.1 */
+	private final boolean simplificationNeeded;
+
 	/** <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 */
+	 * @since 2.0
+	 * @deprecated See {@link #simplificationNeeded}, {@link #getRawName()} and {@link #getADQLName()}. */
+	@Deprecated
 	private boolean isInitiallyQualified;
 
 	/** Name that this table have in the database.
-	 * <i>Note: It CAN'T be NULL. By default, it is the ADQL name.</i> */
+	 * <i>Note: If NULL, {@link #getDBName()} returns what {@link #getADQLName()} returns.</i> */
 	private String dbName = null;
 
 	/** The schema which owns this table.
@@ -117,26 +126,49 @@ public class TAPTable implements DBTable {
 	/**
 	 * <p>Build a {@link TAPTable} instance with the given ADQL name.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
-	 * 	The table type is set by default to "table".
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 * 	If the given ADQL name is prefixed (= it has some text separated by a '.' before the table name),
-	 * 	this prefix will be removed. Only the part after the '.' character will be kept.
+	 * <p><i>Note 2:
+	 * 	The table type is set by default to "table".
 	 * </i></p>
 	 * 
-	 * @param tableName	Name that this table MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</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()}.
+	 *	</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).
 	 */
-	public TAPTable(String tableName){
-		if (tableName == null || tableName.trim().length() == 0)
-			throw new NullPointerException("Missing table name !");
-		int indPrefix = tableName.lastIndexOf('.');
-		adqlName = (indPrefix >= 0) ? tableName.substring(indPrefix + 1).trim() : tableName.trim();
-		isInitiallyQualified = (indPrefix >= 0);
-		dbName = adqlName;
+	public TAPTable(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);
+
+		if (getADQLName().length() == 0)
+			throw new NullPointerException("Missing table name!");
+
+		dbName = null;
+
 		columns = new LinkedHashMap<String,TAPColumn>();
 		foreignKeys = new ArrayList<TAPForeignKey>();
 	}
@@ -144,22 +176,40 @@ public class TAPTable implements DBTable {
 	/**
 	 * <p>Build a {@link TAPTable} instance with the given ADQL name and table type.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 *	The table type is set by calling the function {@link #setType(TableType)} which does not do
-	 *	anything if the given table type is NULL.
+	 * <p><i>Note 2:
+	 * 	The table type is set by default to "table".
 	 * </i></p>
 	 * 
-	 * @param tableName	Name that this table MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</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()}.
+	 *	</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).
+	 * 
 	 * @see #setType(TableType)
 	 */
-	public TAPTable(String tableName, TableType tableType){
+	public TAPTable(String tableName, TableType tableType) throws NullPointerException{
 		this(tableName);
 		setType(tableType);
 	}
@@ -167,24 +217,42 @@ public class TAPTable implements DBTable {
 	/**
 	 * <p>Build a {@link TAPTable} instance with the given ADQL name, table type, description and UType.</p>
 	 * 
-	 * <p><i>Note:
-	 * 	The DB name is set by default with the ADQL name. To set the DB name,
-	 * 	you MUST call then {@link #setDBName(String)}.
+	 * <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)}.
 	 * </i></p>
 	 * 
-	 * <p><i>Note:
-	 *	The table type is set by calling the function {@link #setType(TableType)} which does not do
-	 *	anything if the given table type is NULL.
+	 * <p><i>Note 2:
+	 * 	The table type is set by default to "table".
 	 * </i></p>
 	 * 
-	 * @param tableName		Name that this table MUST have in ADQL queries. <i>CAN'T be NULL ; this name can never be changed after.</i>
+	 * <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.
+	 *	</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()}.
+	 *	</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)
 	 */
-	public TAPTable(String tableName, TableType tableType, String description, String utype){
+	public TAPTable(String tableName, TableType tableType, String description, String utype) throws NullPointerException{
 		this(tableName, tableType);
 		this.description = description;
 		this.utype = utype;
@@ -206,7 +274,7 @@ public class TAPTable implements DBTable {
 	 */
 	public final String getFullName(){
 		if (schema != null)
-			return schema.getADQLName() + "." + adqlName;
+			return schema.getADQLName() + "." + getADQLName();
 		else
 			return adqlName;
 	}
@@ -225,6 +293,28 @@ public class TAPTable implements DBTable {
 
 	@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;
+	}
+
+	/**
+	 * 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;
 	}
 
@@ -239,7 +329,10 @@ public class TAPTable implements DBTable {
 	 * @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()}.
 	 */
+	@Deprecated
 	public final boolean isInitiallyQualified(){
 		return isInitiallyQualified;
 	}
@@ -255,21 +348,24 @@ public class TAPTable implements DBTable {
 	 *                       	<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 String getDBName(){
-		return dbName;
+		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, nothing is done ; the DB name keeps is former value.
+	 * 	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.
@@ -278,6 +374,8 @@ public class TAPTable implements DBTable {
 		name = (name != null) ? name.trim() : name;
 		if (name != null && name.length() > 0)
 			dbName = name;
+		else
+			dbName = null;
 	}
 
 	@Override
@@ -314,7 +412,7 @@ public class TAPTable implements DBTable {
 	 * 
 	 * <p><i><b>Warning:</b>
 	 * 	For consistency reasons, this function SHOULD be called only by the {@link TAPSchema}
-	 * 	that owns this table. 
+	 * 	that owns this table.
 	 * </i></p>
 	 * 
 	 * <p><i><b>Important note:</b>
@@ -452,8 +550,8 @@ public class TAPTable implements DBTable {
 	 */
 	public final void addColumn(final TAPColumn newColumn){
 		if (newColumn != null && newColumn.getADQLName() != null){
-			columns.put(newColumn.getADQLName(), newColumn);
 			newColumn.setTable(this);
+			columns.put(newColumn.getADQLName(), newColumn);
 		}
 	}
 
@@ -668,7 +766,7 @@ public class TAPTable implements DBTable {
 	 * 
 	 * @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){
@@ -764,9 +862,9 @@ public class TAPTable implements DBTable {
 				TAPTable targetTable = key.getTargetTable();
 				for(Map.Entry<String,String> relation : key){
 					if (!hasColumn(relation.getKey()))
-						throw new TAPException(errorMsgPrefix + "the source column \"" + relation.getKey() + "\" doesn't exist in \"" + getName() + "\" !");
+						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.getName() + "\" !");
+						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);
@@ -929,7 +1027,7 @@ public class TAPTable implements DBTable {
 
 	@Override
 	public String toString(){
-		return ((schema != null) ? (schema.getADQLName() + ".") : "") + adqlName;
+		return ((schema != null) ? (schema.getADQLName() + ".") : "") + getADQLName();
 	}
 
 	@Override
@@ -939,7 +1037,7 @@ public class TAPTable implements DBTable {
 		copy.setSchema(schema);
 		Collection<TAPColumn> collColumns = columns.values();
 		for(TAPColumn col : collColumns)
-			copy.addColumn((TAPColumn)col.copy(col.getDBName(), col.getADQLName(), null));
+			copy.addColumn((TAPColumn)col.copy(col.getDBName(), col.getADQLName(), copy));
 		copy.setDescription(description);
 		copy.setOtherData(otherData);
 		copy.setType(type);
diff --git a/test/tap/metadata/TestMetadataNames.java b/test/tap/metadata/TestMetadataNames.java
new file mode 100644
index 0000000..1e95f5c
--- /dev/null
+++ b/test/tap/metadata/TestMetadataNames.java
@@ -0,0 +1,452 @@
+package tap.metadata;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Iterator;
+
+import org.junit.Test;
+
+/**
+ * This class aims to ensure schema, table and column names are interpreted correctly
+ * when quoted and/or qualified (with a schema or table prefix).
+ */
+public class TestMetadataNames {
+
+	/** TEST SCHEMA NAME */
+	@Test
+	public void testSchemaName(){
+		TAPSchema schema;
+
+		// NULL
+		try{
+			new TAPSchema(null);
+			fail("It should be impossible to create a TAPSchema with a NULL name.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing schema name!", npe.getMessage());
+		}
+
+		// Empty string (not a single character):
+		try{
+			new TAPSchema("");
+			fail("It should be impossible to create a TAPSchema with an empty name.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing schema name!", npe.getMessage());
+		}
+
+		// String with only space characters:
+		try{
+			new TAPSchema(" 	");
+			fail("It should be impossible to create a TAPSchema with a name just composed of space characters.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing schema name!", npe.getMessage());
+		}
+
+		// Empty quoted string:
+		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{
+			schema = new TAPSchema("foo");
+			assertEquals("foo", schema.getADQLName());
+			assertEquals("foo", schema.getRawName());
+
+			schema = new TAPSchema("	foo ");
+			assertEquals("foo", schema.getADQLName());
+			assertEquals("foo", schema.getRawName());
+
+			// Qualified name => Not supported as a catalog name!
+			schema = new TAPSchema("myCat.foo");
+			assertEquals("myCat.foo", schema.getADQLName());
+			assertEquals("myCat.foo", schema.getRawName());
+
+		}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());
+
+			schema = new TAPSchema("\"foo\"");
+			assertEquals("foo", schema.getADQLName());
+			assertEquals("\"foo\"", schema.getRawName());
+
+			schema = new TAPSchema(" \"	foo \"	");
+			assertEquals("	foo ", schema.getADQLName());
+			assertEquals("\"	foo \"", schema.getRawName());
+
+			// Qualified name => Not supported as a catalog name!
+			schema = new TAPSchema("myCat.\"foo\"");
+			assertEquals("myCat.\"foo\"", schema.getADQLName());
+			assertEquals("myCat.\"foo\"", schema.getRawName());
+
+		}catch(NullPointerException npe){
+			npe.printStackTrace(System.err);
+			fail("Unexpected error! The schema name is not empty or NULL. (see console for more details)");
+		}
+	}
+
+	/** TEST TABLE NAME */
+	@Test
+	public void testTableName(){
+		TAPTable table, table2, table3;
+
+		// NULL
+		try{
+			new TAPTable(null);
+			fail("It should be impossible to create a TAPTable with a NULL name.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing table name!", npe.getMessage());
+		}
+
+		// Empty string (not a single character):
+		try{
+			new TAPTable("");
+			fail("It should be impossible to create a TAPTable with an empty name.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing table name!", npe.getMessage());
+		}
+
+		// String with only space characters:
+		try{
+			new TAPTable(" 	");
+			fail("It should be impossible to create a TAPTable with a name just composed of space characters.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing table name!", npe.getMessage());
+		}
+
+		// Empty quoted string:
+		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{
+			table = new TAPTable("foo");
+			assertEquals("foo", table.getADQLName());
+			assertEquals("foo", table.getRawName());
+
+			table = new TAPTable("	foo ");
+			assertEquals("foo", table.getADQLName());
+			assertEquals("foo", table.getRawName());
+
+			// Qualified name => Without a schema link, no prefix can be removed!
+			table = new TAPTable("mySchema.foo");
+			assertEquals("mySchema.foo", table.getADQLName());
+			assertEquals("mySchema.foo", table.getRawName());
+
+			// Qualified name + Schema with the WRONG name:
+			table.setSchema(new TAPSchema("Blabla"));
+			assertEquals("mySchema.foo", table.getADQLName());
+			assertEquals("mySchema.foo", table.getRawName());
+
+			// Qualified name + Schema with the RIGHT name:
+			table.setSchema(new TAPSchema("mySchema"));
+			assertEquals("foo", table.getADQLName());
+			assertEquals("mySchema.foo", table.getRawName());
+
+		}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());
+
+			table = new TAPTable("\"foo\"");
+			assertEquals("foo", table.getADQLName());
+			assertEquals("\"foo\"", table.getRawName());
+
+			table = new TAPTable(" \"	foo \"	");
+			assertEquals("	foo ", table.getADQLName());
+			assertEquals("\"	foo \"", table.getRawName());
+
+			// Qualified name => Without a schema link, no prefix can be removed!
+			table = new TAPTable("mySchema.\"foo\"");
+			assertEquals("mySchema.\"foo\"", table.getADQLName());
+			assertEquals("mySchema.\"foo\"", table.getRawName());
+			table2 = new TAPTable(" \"mySchema\". \"foo\"");
+			assertEquals("\"mySchema\". \"foo\"", table2.getADQLName());
+			assertEquals("\"mySchema\". \"foo\"", table2.getRawName());
+			table3 = new TAPTable(" \"mySchema\". foo");
+			assertEquals("\"mySchema\". foo", table3.getADQLName());
+			assertEquals("\"mySchema\". foo", table3.getRawName());
+
+			// 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());
+
+			// Qualified name + Schema with the RIGHT name:
+			table.setSchema(new TAPSchema("mySchema"));
+			assertEquals("foo", table.getADQLName());
+			assertEquals("mySchema.\"foo\"", table.getRawName());
+			table2.setSchema(new TAPSchema("\"mySchema\""));
+			assertEquals("foo", table2.getADQLName());
+			assertEquals("\"mySchema\". \"foo\"", table2.getRawName());
+			table3.setSchema(new TAPSchema("\"mySchema\""));
+			assertEquals("foo", table3.getADQLName());
+			assertEquals("\"mySchema\". foo", table3.getRawName());
+
+		}catch(NullPointerException npe){
+			npe.printStackTrace(System.err);
+			fail("Unexpected error! The table name is not empty or NULL. (see console for more details)");
+		}
+	}
+
+	/** TEST COLUMN NAME */
+	@Test
+	public void testColumnName(){
+		TAPColumn column, column2, column3, column4, column5;
+
+		// NULL
+		try{
+			new TAPColumn(null);
+			fail("It should be impossible to create a TAPColumn with a NULL name.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing column name!", npe.getMessage());
+		}
+
+		// Empty string (not a single character):
+		try{
+			new TAPColumn("");
+			fail("It should be impossible to create a TAPColumn with an empty name.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing column name!", npe.getMessage());
+		}
+
+		// String with only space characters:
+		try{
+			new TAPColumn(" 	");
+			fail("It should be impossible to create a TAPColumn with a name just composed of space characters.");
+		}catch(NullPointerException npe){
+			assertEquals("Missing column name!", npe.getMessage());
+		}
+
+		// Empty quoted string:
+		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{
+			column = new TAPColumn("foo");
+			assertEquals("foo", column.getADQLName());
+			assertEquals("foo", column.getRawName());
+
+			column = new TAPColumn("	foo ");
+			assertEquals("foo", column.getADQLName());
+			assertEquals("foo", column.getRawName());
+
+			// Qualified name => Without a table link, no prefix can be removed!
+			column = new TAPColumn("myTable.foo");
+			assertEquals("myTable.foo", column.getADQLName());
+			assertEquals("myTable.foo", column.getRawName());
+
+			// Qualified name + Table with the WRONG name:
+			column.setTable(new TAPTable("Blabla"));
+			assertEquals("myTable.foo", column.getADQLName());
+			assertEquals("myTable.foo", column.getRawName());
+
+			// Qualified name + Table with the RIGHT name:
+			column.setTable(new TAPTable("myTable"));
+			assertEquals("foo", column.getADQLName());
+			assertEquals("myTable.foo", column.getRawName());
+
+		}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());
+
+			column = new TAPColumn("\"foo\"");
+			assertEquals("foo", column.getADQLName());
+			assertEquals("\"foo\"", column.getRawName());
+
+			column = new TAPColumn(" \"	foo \"	");
+			assertEquals("	foo ", column.getADQLName());
+			assertEquals("\"	foo \"", column.getRawName());
+
+			// Qualified name => Without a table link, no prefix can be removed!
+			column = new TAPColumn("myTable.\"foo\"");
+			assertEquals("myTable.\"foo\"", column.getADQLName());
+			assertEquals("myTable.\"foo\"", column.getRawName());
+			column2 = new TAPColumn(" \"myTable\". \"foo\"");
+			assertEquals("\"myTable\". \"foo\"", column2.getADQLName());
+			assertEquals("\"myTable\". \"foo\"", column2.getRawName());
+			column3 = new TAPColumn(" \"myTable\". foo");
+			assertEquals("\"myTable\". foo", column3.getADQLName());
+			assertEquals("\"myTable\". foo", column3.getRawName());
+			column4 = new TAPColumn(" mySchema.\"myTable\". foo");
+			assertEquals("mySchema.\"myTable\". foo", column4.getADQLName());
+			assertEquals("mySchema.\"myTable\". foo", column4.getRawName());
+			column5 = new TAPColumn(" \"mySchema\".\"myTable\". foo");
+			assertEquals("\"mySchema\".\"myTable\". foo", column5.getADQLName());
+			assertEquals("\"mySchema\".\"myTable\". foo", column5.getRawName());
+
+			// Qualified name + Table with the WRONG name:
+			column.setTable(new TAPTable("Blabla"));
+			assertEquals("myTable.\"foo\"", column.getADQLName());
+			assertEquals("myTable.\"foo\"", column.getRawName());
+			column2.setTable(new TAPTable("myTable"));
+			assertEquals("\"myTable\". \"foo\"", column2.getADQLName());
+			assertEquals("\"myTable\". \"foo\"", column2.getRawName());
+			column3.setTable(new TAPTable("myTable"));
+			assertEquals("\"myTable\". foo", column3.getADQLName());
+			assertEquals("\"myTable\". foo", column3.getRawName());
+			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());
+			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:
+			column.setTable(new TAPTable("myTable"));
+			assertEquals("foo", column.getADQLName());
+			assertEquals("myTable.\"foo\"", column.getRawName());
+			column2.setTable(new TAPTable("\"myTable\""));
+			assertEquals("foo", column2.getADQLName());
+			assertEquals("\"myTable\". \"foo\"", column2.getRawName());
+			column3.setTable(new TAPTable("\"myTable\""));
+			assertEquals("foo", column3.getADQLName());
+			assertEquals("\"myTable\". foo", column3.getRawName());
+			t = new TAPTable("mySchema.\"myTable\"");
+			t.setSchema(new TAPSchema("mySchema"));
+			column4.setTable(t);
+			assertEquals("foo", column4.getADQLName());
+			assertEquals("mySchema.\"myTable\". foo", column4.getRawName());
+			t = new TAPTable("\"mySchema\".\"myTable\"");
+			t.setSchema(new TAPSchema("\"mySchema\""));
+			column5.setTable(t);
+			assertEquals("foo", column5.getADQLName());
+			assertEquals("\"mySchema\".\"myTable\". foo", column5.getRawName());
+
+		}catch(NullPointerException npe){
+			npe.printStackTrace(System.err);
+			fail("Unexpected error! The column name is not empty or NULL. (see console for more details)");
+		}
+	}
+
+	/** TEST XML METADATA */
+	@Test
+	public void testXMLMetadata(){
+		TAPMetadata metadata = new TAPMetadata();
+
+		TAPSchema schema = new TAPSchema("blabla");
+		assertEquals("blabla", schema.getADQLName());
+
+		TAPTable table = new TAPTable("foo");
+		table.addColumn(new TAPColumn("col1"));
+		table.addColumn(new TAPColumn("col2"));
+		table.addColumn(new TAPColumn("foo.col3"));
+		table.addColumn(new TAPColumn("blabla.foo.col4"));
+		table.addColumn(new TAPColumn("foo2.col5"));
+		schema.addTable(table);
+
+		assertEquals("foo", table.getADQLName());
+		Iterator<TAPColumn> itCol = table.getColumns();
+		assertEquals("col1", itCol.next().getADQLName());
+		assertEquals("col2", itCol.next().getADQLName());
+		assertEquals("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\"");
+		table.addColumn(new TAPColumn("foo.bar.col1"));
+		table.addColumn(new TAPColumn("\"foo.bar\".col2"));
+		table.addColumn(new TAPColumn("blabla.foo.bar.col3"));
+		table.addColumn(new TAPColumn("blabla.\"foo.bar\".col4"));
+		schema.addTable(table);
+
+		assertEquals("foo.bar", table.getADQLName());
+		itCol = table.getColumns();
+		assertEquals("foo.bar.col1", itCol.next().getADQLName());
+		assertEquals("col2", itCol.next().getADQLName());
+		assertEquals("blabla.foo.bar.col3", itCol.next().getADQLName());
+		assertEquals("blabla.\"foo.bar\".col4", itCol.next().getADQLName());
+		/* Note for below:
+		 * Same as for the 4th column of the table "foo". */
+
+		metadata.addSchema(schema);
+
+		schema = new TAPSchema("myCat.bloblo");
+		assertEquals("myCat.bloblo", schema.getADQLName());
+
+		table = new TAPTable("myCat.bloblo.bar");
+		table.addColumn(new TAPColumn("col1"));
+		table.addColumn(new TAPColumn("bloblo.col2"));
+		table.addColumn(new TAPColumn("bar.col3"));
+		table.addColumn(new TAPColumn("bloblo.bar.col4"));
+		table.addColumn(new TAPColumn("myCat.bloblo.bar.col5"));
+		schema.addTable(table);
+
+		assertEquals("bar", table.getADQLName());
+		itCol = table.getColumns();
+		assertEquals("col1", itCol.next().getADQLName());
+		assertEquals("bloblo.col2", itCol.next().getADQLName());
+		assertEquals("bar.col3", itCol.next().getADQLName());
+		/* 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());
+
+		metadata.addSchema(schema);
+
+		schema = new TAPSchema("\"Mon Super Schema\"");
+		assertEquals("Mon Super Schema", schema.getADQLName());
+		metadata.addSchema(schema);
+
+		try{
+			StringWriter str = new StringWriter();
+			metadata.write(new PrintWriter(str));
+			//System.out.println(str.toString());
+			assertEquals(expectedXMLMetadata, str.toString());
+		}catch(Exception ex){
+			ex.printStackTrace(System.err);
+			fail("Unexpected error when writing TAP metadata into an XML format! (see console for more details)");
+		}
+
+	}
+
+	public final static String expectedXMLMetadata = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vosi:tableset xmlns:vosi=\"http://www.ivoa.net/xml/VOSITables/v1.0\" xmlns:vod=\"http://www.ivoa.net/xml/VODataService/v1.1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.ivoa.net/xml/VODataService/v1.1 http://www.ivoa.net/xml/VODataService/v1.1 http://www.ivoa.net/xml/VOSITables/v1.0 http://vo.ari.uni-heidelberg.de/docs/schemata/VOSITables-v1.0.xsd\">\n\t<schema>\n\t\t<name>blabla</name>\n\t\t<table>\n\t\t\t<name>foo</name>\n\t\t\t<column>\n\t\t\t\t<name>col1</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>col2</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>foo.col3</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>blabla.foo.col4</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>foo2.col5</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t</table>\n\t\t<table>\n\t\t\t<name>\"foo.bar\"</name>\n\t\t\t<column>\n\t\t\t\t<name>foo.bar.col1</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>\"foo.bar\".col2</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>blabla.foo.bar.col3</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>blabla.\"foo.bar\".col4</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t</table>\n\t</schema>\n\t<schema>\n\t\t<name>myCat.bloblo</name>\n\t\t<table>\n\t\t\t<name>myCat.bloblo.bar</name>\n\t\t\t<column>\n\t\t\t\t<name>col1</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>bloblo.col2</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>bar.col3</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>bloblo.bar.col4</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t\t<column>\n\t\t\t\t<name>myCat.bloblo.bar.col5</name>\n\t\t\t\t<dataType xsi:type=\"vod:TAPType\">UNKNOWN</dataType>\n\t\t\t</column>\n\t\t</table>\n\t</schema>\n\t<schema>\n\t\t<name>\"Mon Super Schema\"</name>\n\t</schema>\n</vosi:tableset>\n";
+
+}
-- 
GitLab