diff --git a/src/adql/db/STCS.java b/src/adql/db/STCS.java
index c4a34e9eb4e3a64dfb08e62a10db0a123e742789..2f1f4f3f20a1f3c63124736e18ee584714690cee 100644
--- a/src/adql/db/STCS.java
+++ b/src/adql/db/STCS.java
@@ -1236,7 +1236,7 @@ public final class STCS {
 	 * Let parse any STC-S expression.
 	 * 
 	 * @author Grégory Mantelet (ARI)
-	 * @version 1.3 (10/2014)
+	 * @version 1.3 (11/2014)
 	 * @since 1.3
 	 */
 	private static class STCSParser {
@@ -1318,7 +1318,7 @@ public final class STCS {
 		 * @param newStcs	New STC-S expression to parse from now.
 		 */
 		private void init(final String newStcs){
-			stcs = (newStcs == null) ? "" : newStcs.replaceAll("\\s", " ");
+			stcs = (newStcs == null) ? "" : newStcs;
 			token = null;
 			buffer = new StringBuffer();
 			pos = 0;
@@ -1351,7 +1351,7 @@ public final class STCS {
 		 * Tool function which skip all next space characters until the next meaningful characters. 
 		 */
 		private void skipSpaces(){
-			while(pos < stcs.length() && stcs.charAt(pos) == ' ')
+			while(pos < stcs.length() && Character.isWhitespace(stcs.charAt(pos)))
 				pos++;
 		}
 
@@ -1371,7 +1371,7 @@ public final class STCS {
 			skipSpaces();
 
 			// Fetch all characters until word separator (a space or a open/close parenthesis):
-			while(pos < stcs.length() && stcs.charAt(pos) != ' ' && stcs.charAt(pos) != '(' && stcs.charAt(pos) != ')')
+			while(pos < stcs.length() && !Character.isWhitespace(stcs.charAt(pos)) && stcs.charAt(pos) != '(' && stcs.charAt(pos) != ')')
 				buffer.append(stcs.charAt(pos++));
 
 			// If no character has been fetched while at least one was expected, throw an exception:
diff --git a/src/adql/translator/JDBCTranslator.java b/src/adql/translator/JDBCTranslator.java
index 346d0278956c6625d685805a813521c4bac94bd0..6ea5ae34cf0004bff883ad533d3e344de516f3ff 100644
--- a/src/adql/translator/JDBCTranslator.java
+++ b/src/adql/translator/JDBCTranslator.java
@@ -23,9 +23,13 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 
+import tap.data.DataReadException;
 import adql.db.DBColumn;
 import adql.db.DBTable;
+import adql.db.DBType;
+import adql.db.STCS.Region;
 import adql.db.exception.UnresolvedJoin;
+import adql.parser.ParseException;
 import adql.query.ADQLList;
 import adql.query.ADQLObject;
 import adql.query.ADQLOrder;
@@ -93,8 +97,9 @@ import adql.query.operand.function.geometry.RegionFunction;
  * <h3>PostgreSQLTranslator and PgSphereTranslator</h3>
  * 
  * <p>
- * 	{@link PgSphereTranslator} extends {@link PostgreSQLTranslator} and is just translating geometrical
- * 	functions according to the syntax given by PgSphere.
+ * 	{@link PgSphereTranslator} extends {@link PostgreSQLTranslator} and is able to translate geometrical
+ * 	functions according to the syntax given by PgSphere. But it can also convert geometrical types
+ * 	(from and toward the database), translate PgSphere regions into STC expression and vice-versa.
  * </p>
  * 
  * <p>
@@ -150,8 +155,8 @@ import adql.query.operand.function.geometry.RegionFunction;
  * </p>
  * 
  * <p><i>Note:
- * 	Geometrical function have not been translated here. They stay abstract because it is obviously impossible to have a generic
- * 	translation ; it totally depends from the database system.
+ * 	Geometrical regions and types have not been managed here. They stay abstract because it is obviously impossible to have a generic
+ * 	translation and conversion ; it totally depends from the database system.
  * </i></p>
  * 
  * <h3>Translation of "FROM" with JOINs</h3>
@@ -162,8 +167,8 @@ import adql.query.operand.function.geometry.RegionFunction;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 1.3 (09/2014)
- * @since 2.0
+ * @version 1.3 (11/2014)
+ * @since 1.3
  * 
  * @see PostgreSQLTranslator
  * @see PgSphereTranslator
@@ -802,4 +807,77 @@ public abstract class JDBCTranslator implements ADQLTranslator {
 		return translate(geomValue.getValue());
 	}
 
+	/**
+	 * Convert any type provided by a JDBC driver into a type understandable by the ADQL/TAP library.
+	 * 
+	 * @param dbmsType			Type returned by a JDBC driver. <i>Note: this value is returned by ResultSetMetadata.getColumnType(int) and correspond to a type of java.sql.Types</i>
+	 * @param rawDbmsTypeName	Full name of the type returned by a JDBC driver. <i>Note: this name is returned by ResultSetMetadata.getColumnTypeName(int) ; this name may contain parameters</i>
+	 * @param dbmsTypeName		Name of type, without the eventual parameters. <i>Note: this name is extracted from rawDbmsTypeName.</i>
+	 * @param typeParams		The eventual type parameters (e.g. char string length). <i>Note: these parameters are extracted from rawDbmsTypeName.</i>
+	 * 
+	 * @return	The corresponding ADQL/TAP type or NULL if the specified type is unknown.
+	 */
+	public abstract DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, final String dbmsTypeName, final String[] typeParams);
+
+	/**
+	 * <p>Convert any type provided by the ADQL/TAP library into a type understandable by a JDBC driver.</p>
+	 * 
+	 * <p><i>Note:
+	 * 	The returned DBMS type may contain some parameters between brackets.
+	 * </i></p>
+	 * 
+	 * @param type	The ADQL/TAP library's type to convert.
+	 * 
+	 * @return	The corresponding DBMS type or NULL if the specified type is unknown.
+	 */
+	public abstract String convertTypeToDB(final DBType type);
+
+	/**
+	 * <p>Parse the given JDBC column value as a geometry object and convert it into a {@link Region}.</p>
+	 * 
+	 * <p><i>Note:
+	 * 	Generally the returned object will be used to get its STC-S expression.
+	 * </i></p>
+	 * 
+	 * <p><i>Note:
+	 * 	If the given column value is NULL, NULL will be returned.
+	 * </i></p>
+	 * 
+	 * <p><i><b>Important note:</b>
+	 * 	This function is called ONLY for value of columns flagged as geometries by
+	 * 	{@link #convertTypeFromDB(int, String, String, String[])}. So the value should always
+	 * 	be of the expected type and format. However, if it turns out that the type is wrong
+	 * 	and that the conversion is finally impossible, this function SHOULD throw a
+	 * 	{@link DataReadException}.
+	 * </i></p>
+	 * 
+	 * @param jdbcColValue	A JDBC column value (returned by ResultSet.getObject(int)).
+	 * 
+	 * @return	The corresponding {@link Region} if the given value is a geometry.
+	 * 
+	 * @throws ParseException	If the given object is not a geometrical object
+	 *                       	or can not be transformed into a {@link Region} object.
+	 */
+	public abstract Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException;
+
+	/**
+	 * <p>Convert the given STC region into a DB column value.</p>
+	 * 
+	 * <p><i>Note:
+	 * 	This function is used only by the UPLOAD feature, to import geometries provided as STC-S expression in
+	 * 	a VOTable document inside a DB column.
+	 * </i></p>
+	 * 
+	 * <p><i>Note:
+	 * 	If the given region is NULL, NULL will be returned.
+	 * </i></p>
+	 * 
+	 * @param stcs	The region to store in the DB.
+	 * 
+	 * @return	The corresponding DB column object.
+	 * 
+	 * @throws ParseException	If the given STC Region can not be converted into a DB object.
+	 */
+	public abstract Object translateGeometryToDB(final Region region) throws ParseException;
+
 }
diff --git a/src/adql/translator/PgSphereTranslator.java b/src/adql/translator/PgSphereTranslator.java
index 8a6a197c5179f01d836705573bb9ee2bfeea6d9b..96c509c52744219b63c7560a82988cd06a72d720 100644
--- a/src/adql/translator/PgSphereTranslator.java
+++ b/src/adql/translator/PgSphereTranslator.java
@@ -20,6 +20,16 @@ package adql.translator;
  *                       Astronomisches Rechen Institut (ARI)
  */
 
+import java.sql.SQLException;
+import java.util.ArrayList;
+
+import org.postgresql.util.PGobject;
+
+import adql.db.DBType;
+import adql.db.DBType.DBDatatype;
+import adql.db.STCS.Region;
+import adql.parser.ParseException;
+import adql.query.TextPosition;
 import adql.query.constraint.Comparison;
 import adql.query.constraint.ComparisonOperator;
 import adql.query.operand.function.geometry.AreaFunction;
@@ -38,10 +48,16 @@ import adql.query.operand.function.geometry.PolygonFunction;
  * The other functions are managed by {@link PostgreSQLTranslator}.</p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.3 (08/2014)
+ * @version 1.3 (11/2014)
  */
 public class PgSphereTranslator extends PostgreSQLTranslator {
 
+	/** Angle between two points generated while transforming a circle into a polygon.
+	 * This angle is computed by default to get at the end a polygon of 32 points.
+	 * @see #circleToPolygon(double[], double)
+	 * @since 1.3 */
+	protected static double ANGLE_CIRCLE_TO_POLYGON = 2 * Math.PI / 32;
+
 	/**
 	 * Builds a PgSphereTranslator which always translates in SQL all identifiers (schema, table and column) in a case sensitive manner ;
 	 * in other words, schema, table and column names will be surrounded by double quotes in the SQL translation.
@@ -99,11 +115,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 	public String translate(BoxFunction box) throws TranslationException{
 		StringBuffer str = new StringBuffer("sbox(");
 
+		str.append("spoint(").append("radians(").append(translate(box.getCoord1())).append("-(").append(translate(box.getWidth())).append("/2.0)),");
+		str.append("radians(").append(translate(box.getCoord2())).append("-(").append(translate(box.getHeight())).append("/2.0))),");
+
 		str.append("spoint(").append("radians(").append(translate(box.getCoord1())).append("+(").append(translate(box.getWidth())).append("/2.0)),");
-		str.append("radians(").append(translate(box.getCoord2())).append("+(").append(translate(box.getHeight())).append("/2.0))),");
+		str.append("radians(").append(translate(box.getCoord2())).append("+(").append(translate(box.getHeight())).append("/2.0))))");
 
-		str.append("spoint(").append("radians(").append(translate(box.getCoord1())).append("-(").append(translate(box.getWidth())).append("/2.0)),");
-		str.append("radians(").append(translate(box.getCoord2())).append("-(").append(translate(box.getHeight())).append("/2.0))))");
 		return str.toString();
 	}
 
@@ -152,8 +169,8 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 	@Override
 	public String translate(AreaFunction areaFunction) throws TranslationException{
-		StringBuffer str = new StringBuffer("degrees(area(");
-		str.append(translate(areaFunction.getParameter())).append("))");
+		StringBuffer str = new StringBuffer("degrees(degrees(area(");
+		str.append(translate(areaFunction.getParameter())).append(")))");
 		return str.toString();
 	}
 
@@ -181,4 +198,534 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 			return super.translate(comp);
 	}
 
+	@Override
+	public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params){
+		// If no type is provided return VARCHAR:
+		if (dbmsTypeName == null || dbmsTypeName.trim().length() == 0)
+			return new DBType(DBDatatype.VARCHAR, DBType.NO_LENGTH);
+
+		// Put the dbmsTypeName in lower case for the following comparisons:
+		dbmsTypeName = dbmsTypeName.toLowerCase();
+
+		if (dbmsTypeName.equals("spoint"))
+			return new DBType(DBDatatype.POINT);
+		else if (dbmsTypeName.equals("scircle") || dbmsTypeName.equals("sbox") || dbmsTypeName.equals("spoly"))
+			return new DBType(DBDatatype.REGION);
+		else
+			return super.convertTypeFromDB(dbmsType, rawDbmsTypeName, dbmsTypeName, params);
+	}
+
+	@Override
+	public String convertTypeToDB(final DBType type){
+		if (type != null){
+			if (type.type == DBDatatype.POINT)
+				return "spoint";
+			else if (type.type == DBDatatype.REGION)
+				return "spoly";
+		}
+		return super.convertTypeToDB(type);
+	}
+
+	@Override
+	public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException{
+		// A NULL value stays NULL:
+		if (jdbcColValue == null)
+			return null;
+		// Only a special object is expected:
+		else if (!(jdbcColValue instanceof PGobject))
+			throw new ParseException("Incompatible type! The column value \"" + jdbcColValue.toString() + "\" was supposed to be a geometrical object.");
+
+		PGobject pgo = (PGobject)jdbcColValue;
+
+		// In case one or both of the fields of the given object are NULL:
+		if (pgo == null || pgo.getType() == null || pgo.getValue() == null || pgo.getValue().length() == 0)
+			return null;
+
+		// Extract the object type and its value:
+		String objType = pgo.getType().toLowerCase();
+		String geomStr = pgo.getValue();
+
+		/* Only spoint, scircle, sbox and spoly are supported ; 
+		 * these geometries are parsed and transformed in Region instances:*/
+		if (objType.equals("spoint"))
+			return (new PgSphereGeometryParser()).parsePoint(geomStr);
+		else if (objType.equals("scircle"))
+			return (new PgSphereGeometryParser()).parseCircle(geomStr);
+		else if (objType.equals("sbox"))
+			return (new PgSphereGeometryParser()).parseBox(geomStr);
+		else if (objType.equals("spoly"))
+			return (new PgSphereGeometryParser()).parsePolygon(geomStr);
+		else
+			throw new ParseException("Unsupported PgSphere type: \"" + objType + "\"! Impossible to convert the column value \"" + geomStr + "\" into a Region.");
+	}
+
+	@Override
+	public Object translateGeometryToDB(final Region region) throws ParseException{
+		// A NULL value stays NULL:
+		if (region == null)
+			return null;
+
+		try{
+			PGobject dbRegion = new PGobject();
+			StringBuffer buf;
+
+			// Build the PgSphere expression from the given geometry in function of its type:
+			switch(region.type){
+
+				case POSITION:
+					dbRegion.setType("spoint");
+					dbRegion.setValue("(" + region.coordinates[0][0] + "d," + region.coordinates[0][1] + "d)");
+					break;
+
+				case POLYGON:
+					dbRegion.setType("spoly");
+					buf = new StringBuffer("{");
+					for(int i = 0; i < region.coordinates.length; i++){
+						if (i > 0)
+							buf.append(',');
+						buf.append('(').append(region.coordinates[i][0]).append("d,").append(region.coordinates[i][1]).append("d)");
+					}
+					buf.append('}');
+					dbRegion.setValue(buf.toString());
+					break;
+
+				case BOX:
+					dbRegion.setType("spoly");
+					buf = new StringBuffer("{");
+					// south west
+					buf.append('(').append(region.coordinates[0][0] - region.width / 2).append("d,").append(region.coordinates[0][1] - region.height / 2).append("d),");
+					// north west
+					buf.append('(').append(region.coordinates[0][0] - region.width / 2).append("d,").append(region.coordinates[0][1] + region.height / 2).append("d),");
+					// north east
+					buf.append('(').append(region.coordinates[0][0] + region.width / 2).append("d,").append(region.coordinates[0][1] + region.height / 2).append("d),");
+					// south east
+					buf.append('(').append(region.coordinates[0][0] + region.width / 2).append("d,").append(region.coordinates[0][1] - region.height / 2).append("d)");
+					buf.append('}');
+					dbRegion.setValue(buf.toString());
+					break;
+
+				case CIRCLE:
+					dbRegion.setType("spoly");
+					dbRegion.setValue(circleToPolygon(region.coordinates[0], region.radius));
+					break;
+
+				default:
+					throw new ParseException("Unsupported geometrical region: \"" + region.type + "\"!");
+			}
+			return dbRegion;
+		}catch(SQLException e){
+			/* This error could never happen! */
+			return null;
+		}
+	}
+
+	/**
+	 * <p>Convert the specified circle into a polygon.
+	 * The generated polygon is formatted using the PgSphere syntax.</p>
+	 * 
+	 * <p><i>Note:
+	 * 	The center coordinates and the radius are expected in degrees.
+	 * </i></p>
+	 * 
+	 * @param center	Center of the circle ([0]=ra and [1]=dec).
+	 * @param radius	Radius of the circle.
+	 * 
+	 * @return	The PgSphere serialization of the corresponding polygon.
+	 * 
+	 * @since 1.3
+	 */
+	protected String circleToPolygon(final double[] center, final double radius){
+		double angle = 0, x, y;
+		StringBuffer buf = new StringBuffer();
+		while(angle < 2 * Math.PI){
+			x = center[0] + radius * Math.cos(angle);
+			y = center[1] + radius * Math.sin(angle);
+			if (buf.length() > 0)
+				buf.append(',');
+			buf.append('(').append(x).append("d,").append(y).append("d)");
+			angle += ANGLE_CIRCLE_TO_POLYGON;
+		}
+		return "{" + buf + "}";
+	}
+
+	/**
+	 * <p>Let parse a geometry serialized with the PgSphere syntax.</p>
+	 * 
+	 * <p>
+	 * 	There is one function parseXxx(String) for each supported geometry.
+	 * 	These functions always return a {@link Region} object,
+	 * 	which is the object representation of an STC region.
+	 * </p>
+	 * 
+	 * <p>Only the following geometries are supported:</p>
+	 * <ul>
+	 * 	<li>spoint =&gt; Position</li>
+	 * 	<li>scircle =&gt; Circle</li>
+	 * 	<li>sbox =&gt; Box</li>
+	 * 	<li>spoly =&gt; Polygon</li>
+	 * </ul>
+	 * 
+	 * <p>
+	 * 	This parser supports all the known PgSphere representations of an angle.
+	 * 	However, it always returns angle (coordinates, radius, width and height) in degrees.
+	 * </p>
+	 * 
+	 * @author Gr&eacute;gory Mantelet (ARI)
+	 * @version 1.3 (11/2014)
+	 * @since 1.3
+	 */
+	protected static class PgSphereGeometryParser {
+		/** Position of the next characters to read in the PgSphere expression to parse. */
+		private int pos;
+		/** Full PgSphere expression to parse. */
+		private String expr;
+		/** Last read token (either a string/numeric or a separator). */
+		private String token;
+		/** Buffer used to read tokens. */
+		private StringBuffer buffer;
+
+		private static final char OPEN_PAR = '(';
+		private static final char CLOSE_PAR = ')';
+		private static final char COMMA = ',';
+		private static final char LESS_THAN = '<';
+		private static final char GREATER_THAN = '>';
+		private static final char OPEN_BRACE = '{';
+		private static final char CLOSE_BRACE = '}';
+		private static final char DEGREE = 'd';
+		private static final char HOUR = 'h';
+		private static final char MINUTE = 'm';
+		private static final char SECOND = 's';
+
+		/**
+		 * Exception sent when the end of the expression
+		 * (EOE = End Of Expression) is reached.
+		 * 
+		 * @author Gr&eacute;gory Mantelet (ARI)
+		 * @version 1.3 (11/2014)
+		 * @since 1.3
+		 */
+		private static class EOEException extends ParseException {
+			private static final long serialVersionUID = 1L;
+
+			/** Build a simple EOEException. */
+			public EOEException(){
+				super("Unexpected End Of PgSphere Expression!");
+			}
+		}
+
+		/**
+		 * Build the PgSphere parser.
+		 */
+		public PgSphereGeometryParser(){}
+
+		/**
+		 * Prepare the parser in order to read the given PgSphere expression.
+		 * 
+		 * @param newStcs	New PgSphere expression to parse from now.
+		 */
+		private void init(final String newExpr){
+			expr = (newExpr == null) ? "" : newExpr;
+			token = null;
+			buffer = new StringBuffer();
+			pos = 0;
+		}
+
+		/**
+		 * Finalize the parsing.
+		 * No more characters (except eventually some space characters) should remain in the PgSphere expression to parse.
+		 * 
+		 * @throws ParseException	If other non-space characters remains. 
+		 */
+		private void end() throws ParseException{
+			// Skip all spaces:
+			skipSpaces();
+
+			// If there is still some characters, they are not expected, and so throw an exception:
+			if (expr.length() > 0 && pos < expr.length())
+				throw new ParseException("Unexpected end of PgSphere region expression: \"" + expr.substring(pos) + "\" was unexpected!", new TextPosition(1, pos, 1, expr.length()));
+
+			// Reset the buffer, token and the PgSphere expression to parse:
+			buffer = null;
+			expr = null;
+			token = null;
+		}
+
+		/**
+		 * Tool function which skips all next space characters until the next meaningful characters. 
+		 */
+		private void skipSpaces(){
+			while(pos < expr.length() && Character.isWhitespace(expr.charAt(pos)))
+				pos++;
+		}
+
+		/**
+		 * <p>Get the next meaningful word. This word can be a numeric, any string constant or a separator.
+		 * This function returns this token but also stores it in the class attribute {@link #token}.</p>
+		 * 
+		 * <p>
+		 * 	In case the end of the expression is reached before getting any meaningful character,
+		 * 	an {@link EOEException} is thrown.
+		 * </p>
+		 * 
+		 * @return	The full read word/token, or NULL if the end has been reached.
+		 */
+		private String nextToken() throws EOEException{
+			// Skip all spaces:
+			skipSpaces();
+
+			if (pos >= expr.length())
+				throw new EOEException();
+
+			// Fetch all characters until word separator (a space or a open/close parenthesis):
+			buffer.append(expr.charAt(pos++));
+			if (!isSyntaxSeparator(buffer.charAt(0))){
+				while(pos < expr.length() && !isSyntaxSeparator(expr.charAt(pos))){
+					// skip eventual white-spaces:
+					if (!Character.isWhitespace(expr.charAt(pos)))
+						buffer.append(expr.charAt(pos));
+					pos++;
+				}
+			}
+
+			// Save the read token and reset the buffer:
+			token = buffer.toString();
+			buffer.delete(0, token.length());
+
+			return token;
+		}
+
+		/**
+		 * <p>Tell whether the given character is a separator defined in the syntax.</p>
+		 * 
+		 * <p>Here, the following characters are considered as separators/specials:
+		 * ',', 'd', 'h', 'm', 's', '(', ')', '&lt;', '&gt;', '{' and '}'.</p>
+		 * 
+		 * @param c	Character to test.
+		 * 
+		 * @return	<i>true</i> if the given character must be considered as a separator, <i>false</i> otherwise.
+		 */
+		private static boolean isSyntaxSeparator(final char c){
+			return (c == COMMA || c == DEGREE || c == HOUR || c == MINUTE || c == SECOND || c == OPEN_PAR || c == CLOSE_PAR || c == LESS_THAN || c == GREATER_THAN || c == OPEN_BRACE || c == CLOSE_BRACE);
+		}
+
+		/**
+		 * Get the next character and ensure it is the same as the character given in parameter.
+		 * If the read character is not matching the expected one, a {@link ParseException} is thrown.
+		 * 
+		 * @param expected	Expected character.
+		 * 
+		 * @throws ParseException	If the next character is not matching the given one.
+		 */
+		private void nextToken(final char expected) throws ParseException{
+			// Skip all spaces:
+			skipSpaces();
+
+			// Test whether the end is reached:
+			if (pos >= expr.length())
+				throw new EOEException();
+
+			// Fetch the next character:
+			char t = expr.charAt(pos++);
+			token = new String(new char[]{t});
+
+			/* Test the the fetched character with the expected one
+			 * and throw an error if they don't match: */
+			if (t != expected)
+				throw new ParseException("Incorrect syntax for \"" + expr + "\"! \"" + expected + "\" was expected instead of \"" + t + "\".", new TextPosition(1, pos - 1, 1, pos));
+		}
+
+		/**
+		 * Parse the given PgSphere geometry as a point.
+		 * 
+		 * @param pgsphereExpr	The PgSphere expression to parse as a point.
+		 * 
+		 * @return	A {@link Region} implementing a STC Position region.
+		 * 
+		 * @throws ParseException	If the PgSphere syntax of the given expression is wrong or does not correspond to a point.
+		 */
+		public Region parsePoint(final String pgsphereExpr) throws ParseException{
+			// Init the parser:
+			init(pgsphereExpr);
+			// Parse the expression:
+			double[] coord = parsePoint();
+			// No more character should remain after that:
+			end();
+			// Build the STC Position region:
+			return new Region(null, coord);
+		}
+
+		/**
+		 * Internal spoint parsing function. It parses the PgSphere expression stored in this parser as a point. 
+		 * 
+		 * @return	The ra and dec coordinates (in degrees) of the parsed point.
+		 * 
+		 * @throws ParseException	If the PgSphere syntax of the given expression is wrong or does not correspond to a point.
+		 * 
+		 * @see #parseAngle()
+		 * @see #parsePoint(String)
+		 */
+		private double[] parsePoint() throws ParseException{
+			nextToken(OPEN_PAR);
+			double x = parseAngle();
+			nextToken(COMMA);
+			double y = parseAngle();
+			nextToken(CLOSE_PAR);
+			return new double[]{x,y};
+		}
+
+		/**
+		 * Parse the given PgSphere geometry as a circle.
+		 * 
+		 * @param pgsphereExpr	The PgSphere expression to parse as a circle.
+		 * 
+		 * @return	A {@link Region} implementing a STC Circle region.
+		 * 
+		 * @throws ParseException	If the PgSphere syntax of the given expression is wrong or does not correspond to a circle.
+		 */
+		public Region parseCircle(final String pgsphereExpr) throws ParseException{
+			// Init the parser:
+			init(pgsphereExpr);
+
+			// Parse the expression:
+			nextToken(LESS_THAN);
+			double[] center = parsePoint();
+			nextToken(COMMA);
+			double radius = parseAngle();
+			nextToken(GREATER_THAN);
+
+			// No more character should remain after that:
+			end();
+
+			// Build the STC Circle region:
+			return new Region(null, center, radius);
+		}
+
+		/**
+		 * Parse the given PgSphere geometry as a box.
+		 * 
+		 * @param pgsphereExpr	The PgSphere expression to parse as a box.
+		 * 
+		 * @return	A {@link Region} implementing a STC Box region.
+		 * 
+		 * @throws ParseException	If the PgSphere syntax of the given expression is wrong or does not correspond to a box.
+		 */
+		public Region parseBox(final String pgsphereExpr) throws ParseException{
+			// Init the parser:
+			init(pgsphereExpr);
+
+			// Parse the expression:
+			nextToken(OPEN_PAR);
+			double[] southwest = parsePoint();
+			nextToken(COMMA);
+			double[] northeast = parsePoint();
+			nextToken(CLOSE_PAR);
+
+			// No more character should remain after that:
+			end();
+
+			// Build the STC Box region:
+			double width = Math.abs(northeast[0] - southwest[0]), height = Math.abs(northeast[1] - southwest[1]);
+			double[] center = new double[]{northeast[0] - width / 2,northeast[1] - height / 2};
+			return new Region(null, center, width, height);
+		}
+
+		/**
+		 * Parse the given PgSphere geometry as a point.
+		 * 
+		 * @param pgsphereExpr	The PgSphere expression to parse as a point.
+		 * 
+		 * @return	A {@link Region} implementing a STC Position region.
+		 * 
+		 * @throws ParseException	If the PgSphere syntax of the given expression is wrong or does not correspond to a point.
+		 */
+		public Region parsePolygon(final String pgsphereExpr) throws ParseException{
+			// Init the parser:
+			init(pgsphereExpr);
+
+			// Parse the expression:
+			nextToken(OPEN_BRACE);
+			ArrayList<double[]> points = new ArrayList<double[]>(3);
+			// at least 3 points are expected:
+			points.add(parsePoint());
+			nextToken(COMMA);
+			points.add(parsePoint());
+			nextToken(COMMA);
+			points.add(parsePoint());
+			// but if there are more points, parse and keep them:
+			while(nextToken().length() == 1 && token.charAt(0) == COMMA)
+				points.add(parsePoint());
+			// the expression must end with a } :
+			if (token.length() != 1 || token.charAt(0) != CLOSE_BRACE)
+				throw new ParseException("Incorrect syntax for \"" + expr + "\"! \"}\" was expected instead of \"" + token + "\".", new TextPosition(1, pos - token.length(), 1, pos));
+
+			// No more character should remain after that:
+			end();
+
+			// Build the STC Polygon region:
+			return new Region(null, points.toArray(new double[points.size()][2]));
+		}
+
+		/**
+		 * <p>Read the next tokens as an angle expression and returns the corresponding angle in <b>degrees</b>.</p>
+		 * 
+		 * <p>This function supports the 4 following syntaxes:</p>
+		 * <ul>
+		 * 	<li><b>RAD:</b> {number}</li>
+		 * 	<li><b>DEG:</b> {number}d</li>
+		 * 	<li><b>DMS:</b> {number}d {number}m {number}s</li>
+		 * 	<li><b>HMS:</b> {number}h {number}m {number}s</li>
+		 * </ul>
+		 * 
+		 * @return	The corresponding angle in degrees.
+		 * 
+		 * @throws ParseException	If the angle syntax is wrong or not supported.
+		 */
+		private double parseAngle() throws ParseException{
+			int oldPos = pos;
+			String number = nextToken();
+			try{
+				double degrees = Double.parseDouble(number);
+				int sign = (degrees < 0) ? -1 : 1;
+				degrees = Math.abs(degrees);
+
+				oldPos = pos;
+				try{
+					if (nextToken().length() == 1 && token.charAt(0) == HOUR)
+						sign *= 15;
+					else if (token.length() != 1 || token.charAt(0) != DEGREE){
+						degrees = degrees * 180 / Math.PI;
+						pos -= token.length();
+						return degrees * sign;
+					}
+
+					oldPos = pos;
+					number = nextToken();
+					if (nextToken().length() == 1 && token.charAt(0) == MINUTE)
+						degrees += Double.parseDouble(number) / 60;
+					else if (token.length() == 1 && token.charAt(0) == SECOND){
+						degrees += Double.parseDouble(number) / 3600;
+						return degrees * sign;
+					}else{
+						pos = oldPos;
+						return degrees * sign;
+					}
+
+					oldPos = pos;
+					number = nextToken();
+					if (nextToken().length() == 1 && token.charAt(0) == SECOND)
+						degrees += Double.parseDouble(number) / 3600;
+					else
+						pos = oldPos;
+				}catch(EOEException ex){
+					pos = oldPos;
+				}
+
+				return degrees * sign;
+
+			}catch(NumberFormatException nfe){
+				throw new ParseException("Incorrect numeric syntax: \"" + number + "\"!", new TextPosition(1, pos - token.length(), 1, pos));
+			}
+		}
+	}
+
 }
diff --git a/src/adql/translator/PostgreSQLTranslator.java b/src/adql/translator/PostgreSQLTranslator.java
index 4a5b5e9d142349ace142bda4d6b0ab70f424e5f8..4b2d01395a3e049ff05a4901a0ce8b05624c76e9 100644
--- a/src/adql/translator/PostgreSQLTranslator.java
+++ b/src/adql/translator/PostgreSQLTranslator.java
@@ -20,6 +20,10 @@ package adql.translator;
  *                       Astronomisches Rechen Institut (ARI)
  */
 
+import adql.db.DBType;
+import adql.db.DBType.DBDatatype;
+import adql.db.STCS.Region;
+import adql.parser.ParseException;
 import adql.query.IdentifierField;
 import adql.query.operand.StringConstant;
 import adql.query.operand.function.MathFunction;
@@ -46,7 +50,7 @@ import adql.query.operand.function.geometry.RegionFunction;
  * </i></p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.3 (10/2014)
+ * @version 1.3 (11/2014)
  * 
  * @see PgSphereTranslator
  */
@@ -188,4 +192,108 @@ public class PostgreSQLTranslator extends JDBCTranslator {
 		return getDefaultADQLFunction(region);
 	}
 
+	@Override
+	public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params){
+		// If no type is provided return VARCHAR:
+		if (dbmsTypeName == null || dbmsTypeName.trim().length() == 0)
+			return new DBType(DBDatatype.VARCHAR, DBType.NO_LENGTH);
+
+		// Put the dbmsTypeName in lower case for the following comparisons:
+		dbmsTypeName = dbmsTypeName.toLowerCase();
+
+		// Extract the length parameter (always the first one):
+		int lengthParam = DBType.NO_LENGTH;
+		if (params != null && params.length > 0){
+			try{
+				lengthParam = Integer.parseInt(params[0]);
+			}catch(NumberFormatException nfe){}
+		}
+
+		// SMALLINT
+		if (dbmsTypeName.equals("smallint") || dbmsTypeName.equals("int2") || dbmsTypeName.equals("smallserial") || dbmsTypeName.equals("serial2") || dbmsTypeName.equals("boolean") || dbmsTypeName.equals("bool"))
+			return new DBType(DBDatatype.SMALLINT);
+		// INTEGER
+		else if (dbmsTypeName.equals("integer") || dbmsTypeName.equals("int") || dbmsTypeName.equals("int4") || dbmsTypeName.equals("serial") || dbmsTypeName.equals("serial4"))
+			return new DBType(DBDatatype.INTEGER);
+		// BIGINT
+		else if (dbmsTypeName.equals("bigint") || dbmsTypeName.equals("int8") || dbmsTypeName.equals("bigserial") || dbmsTypeName.equals("bigserial8"))
+			return new DBType(DBDatatype.BIGINT);
+		// REAL
+		else if (dbmsTypeName.equals("real") || dbmsTypeName.equals("float4"))
+			return new DBType(DBDatatype.REAL);
+		// DOUBLE
+		else if (dbmsTypeName.equals("double precision") || dbmsTypeName.equals("float8"))
+			return new DBType(DBDatatype.DOUBLE);
+		// BINARY
+		else if (dbmsTypeName.equals("bit"))
+			return new DBType(DBDatatype.BINARY, lengthParam);
+		// VARBINARY
+		else if (dbmsTypeName.equals("bit varying") || dbmsTypeName.equals("varbit"))
+			return new DBType(DBDatatype.VARBINARY, lengthParam);
+		// CHAR
+		else if (dbmsTypeName.equals("char") || dbmsTypeName.equals("character"))
+			return new DBType(DBDatatype.CHAR, lengthParam);
+		// VARCHAR
+		else if (dbmsTypeName.equals("varchar") || dbmsTypeName.equals("character varying"))
+			return new DBType(DBDatatype.VARCHAR, lengthParam);
+		// BLOB
+		else if (dbmsTypeName.equals("bytea"))
+			return new DBType(DBDatatype.BLOB);
+		// CLOB
+		else if (dbmsTypeName.equals("text"))
+			return new DBType(DBDatatype.CLOB);
+		// TIMESTAMP
+		else if (dbmsTypeName.equals("timestamp") || dbmsTypeName.equals("timestamptz") || dbmsTypeName.equals("time") || dbmsTypeName.equals("timetz") || dbmsTypeName.equals("date"))
+			return new DBType(DBDatatype.TIMESTAMP);
+		// Default:
+		else
+			return new DBType(DBDatatype.VARCHAR, DBType.NO_LENGTH);
+	}
+
+	@Override
+	public String convertTypeToDB(final DBType type){
+		if (type == null)
+			return "VARCHAR";
+
+		switch(type.type){
+
+			case SMALLINT:
+			case INTEGER:
+			case REAL:
+			case BIGINT:
+			case CHAR:
+			case VARCHAR:
+			case TIMESTAMP:
+				return type.type.toString();
+
+			case DOUBLE:
+				return "DOUBLE PRECISION";
+
+			case BINARY:
+			case VARBINARY:
+				return "bytea";
+
+			case BLOB:
+				return "bytea";
+
+			case CLOB:
+				return "TEXT";
+
+			case POINT:
+			case REGION:
+			default:
+				return "VARCHAR";
+		}
+	}
+
+	@Override
+	public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException{
+		throw new ParseException("Unsupported geometrical value! The value \"" + jdbcColValue + "\" can not be parsed as a region.");
+	}
+
+	@Override
+	public Object translateGeometryToDB(final Region region) throws ParseException{
+		throw new ParseException("Geometries can not be uploaded in the database in this implementation!");
+	}
+
 }
diff --git a/src/tap/data/ResultSetTableIterator.java b/src/tap/data/ResultSetTableIterator.java
index a580c87fbfec937fb3008eb44504d10bc2a0d1d3..eb51075327e8fbd9d2c18f53fbe2652124f6dd30 100644
--- a/src/tap/data/ResultSetTableIterator.java
+++ b/src/tap/data/ResultSetTableIterator.java
@@ -30,6 +30,9 @@ import uws.ISO8601Format;
 import adql.db.DBColumn;
 import adql.db.DBType;
 import adql.db.DBType.DBDatatype;
+import adql.db.STCS.Region;
+import adql.parser.ParseException;
+import adql.translator.JDBCTranslator;
 
 /**
  * <p>{@link TableIterator} which lets iterate over a SQL {@link ResultSet}.</p>
@@ -39,7 +42,7 @@ import adql.db.DBType.DBDatatype;
  * </i></p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 2.0 (08/2014)
+ * @version 2.0 (11/2014)
  * @since 2.0
  */
 public class ResultSetTableIterator implements TableIterator {
@@ -47,6 +50,11 @@ public class ResultSetTableIterator implements TableIterator {
 	/** ResultSet/Dataset to read. */
 	private final ResultSet data;
 
+	/** Object which has the knowledge of the specific JDBC column types
+	 * and which knows how to deal with geometrical values between the
+	 * library and the database. */
+	private final JDBCTranslator translator;
+
 	/** Number of columns to read. */
 	private final int nbColumns;
 	/** Metadata of all columns identified before the iteration. */
@@ -71,18 +79,11 @@ public class ResultSetTableIterator implements TableIterator {
 	 * 
 	 * <p>
 	 * 	In order to guess a TAP type from a DBMS type, this constructor will call {@link #convertType(String, String)}
-	 * 	which deals with all standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	which deals with the most common standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	This conversion is therefore not as precise as the one expected by a translator. That's why it is recommended
+	 * 	to use one of the constructor having a {@link JDBCTranslator} in parameter.
 	 * </p>
 	 * 
-	 * <p><i><b>Important</b>:
-	 * 	To guess the TAP type from a DBMS type, {@link #convertType(String, String)} may not need to know the DBMS,
-	 * 	except for SQLite. Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know
-	 * 	it is the DBMS from which the ResultSet is coming. Without this information, type guessing will be unpredictable!
-	 * 
-	 * 	<b>So, if your ResultSet is coming from a SQLite connection, you SHOULD really use one of the 2 other constructors</b>
-	 * 	and provide "sqlite" as value for the second parameter. 
-	 * </i></p>
-	 * 
 	 * @param dataSet		Dataset over which this iterator must iterate.
 	 * 
 	 * @throws NullPointerException	If NULL is given in parameter.
@@ -92,7 +93,7 @@ public class ResultSetTableIterator implements TableIterator {
 	 * @see ResultSetTableIterator#ResultSetTableIterator(ResultSet, String, DBColumn[])
 	 */
 	public ResultSetTableIterator(final ResultSet dataSet) throws NullPointerException, DataReadException{
-		this(dataSet, null, null);
+		this(dataSet, null, null, null);
 	}
 
 	/**
@@ -107,14 +108,16 @@ public class ResultSetTableIterator implements TableIterator {
 	 * 
 	 * <p>
 	 * 	In order to guess a TAP type from a DBMS type, this constructor will call {@link #convertType(String, String)}
-	 * 	which deals with all standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	which deals with the most common standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	This conversion is therefore not as precise as the one expected by a translator. That's why it is recommended
+	 * 	to use one of the constructor having a {@link JDBCTranslator} in parameter.
 	 * </p>
 	 * 
 	 * <p><i><b>Important</b>:
 	 * 	The second parameter of this constructor is given as second parameter of {@link #convertType(String, String)}.
-	 * 	<b>This parameter is really used ONLY when the DBMS is SQLite ("sqlite").</b> Indeed, SQLite has so many datatype
-	 * 	restrictions that it is absolutely needed to know it is the DBMS from which the ResultSet is coming. Without this
-	 * 	information, type guessing will be unpredictable! 
+	 * 	<b>This parameter is really used ONLY when the DBMS is SQLite ("sqlite").</b>
+	 * 	Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
+	 * 	ResultSet is coming. Without this information, type guessing will be unpredictable! 
 	 * </i></p>
 	 * 
 	 * @param dataSet		Dataset over which this iterator must iterate.
@@ -124,10 +127,82 @@ public class ResultSetTableIterator implements TableIterator {
 	 * @throws DataReadException	If the given ResultSet is closed or if the metadata (columns count and types) can not be fetched.
 	 * 
 	 * @see #convertType(String, String)
-	 * @see ResultSetTableIterator#ResultSetTableIterator(ResultSet, String)
+	 * @see ResultSetTableIterator#ResultSetTableIterator(ResultSet, JDBCTranslator, String, DBColumn[])
 	 */
 	public ResultSetTableIterator(final ResultSet dataSet, final String dbms) throws NullPointerException, DataReadException{
-		this(dataSet, dbms, null);
+		this(dataSet, null, dbms, null);
+	}
+
+	/**
+	 * <p>Build a TableIterator able to read rows and columns of the given ResultSet.</p>
+	 * 
+	 * <p>
+	 * 	In order to provide the metadata through {@link #getMetadata()}, this constructor is trying to guess the datatype
+	 * 	from the DBMS column datatype (using {@link #convertType(String, String)}).
+	 * </p>
+	 * 
+	 * <h3>Type guessing</h3>
+	 * 
+	 * <p>
+	 * 	In order to guess a TAP type from a DBMS type, this constructor will call {@link #convertType(String, String)}
+	 * 	which will ask to the given translator ({@link JDBCTranslator#convertTypeFromDB(int, String, String, String[])})
+	 * 	if not NULL. However if no translator is provided, this function will proceed to a default conversion
+	 * 	using the most common standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	This conversion is therefore not as precise as the one expected by the translator.
+	 * </p>
+	 * 
+	 * @param dataSet		Dataset over which this iterator must iterate.
+	 * @param translator	The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
+	 *                  	JDBC types and to parse geometrical values. <i>note: MAY be NULL</i> 
+	 * 
+	 * @throws NullPointerException	If NULL is given in parameter.
+	 * @throws DataReadException	If the given ResultSet is closed or if the metadata (columns count and types) can not be fetched.
+	 * 
+	 * @see #convertType(String, String)
+	 * @see ResultSetTableIterator#ResultSetTableIterator(ResultSet, JDBCTranslator, String, DBColumn[])
+	 */
+	public ResultSetTableIterator(final ResultSet dataSet, final JDBCTranslator translator) throws NullPointerException, DataReadException{
+		this(dataSet, translator, null, null);
+	}
+
+	/**
+	 * <p>Build a TableIterator able to read rows and columns of the given ResultSet.</p>
+	 * 
+	 * <p>
+	 * 	In order to provide the metadata through {@link #getMetadata()}, this constructor is trying to guess the datatype
+	 * 	from the DBMS column datatype (using {@link #convertType(String, String)}).
+	 * </p>
+	 * 
+	 * <h3>Type guessing</h3>
+	 * 
+	 * <p>
+	 * 	In order to guess a TAP type from a DBMS type, this constructor will call {@link #convertType(String, String)}
+	 * 	which will ask to the given translator ({@link JDBCTranslator#convertTypeFromDB(int, String, String, String[])})
+	 * 	if not NULL. However if no translator is provided, this function will proceed to a default conversion
+	 * 	using the most common standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	This conversion is therefore not as precise as the one expected by the translator.
+	 * </p>
+	 * 
+	 * <p><i><b>Important</b>:
+	 * 	The third parameter of this constructor is given as second parameter of {@link #convertType(String, String)}.
+	 * 	<b>This parameter is really used ONLY when the translator conversion failed and when the DBMS is SQLite ("sqlite").</b>
+	 * 	Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
+	 * 	ResultSet is coming. Without this information, type guessing will be unpredictable! 
+	 * </i></p>
+	 * 
+	 * @param dataSet		Dataset over which this iterator must iterate.
+	 * @param translator	The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
+	 *                  	JDBC types and to parse geometrical values. <i>note: MAY be NULL</i> 
+	 * @param dbms			Lower-case string which indicates from which DBMS the given ResultSet is coming. <i>note: MAY be NULL.</i>
+	 * 
+	 * @throws NullPointerException	If NULL is given in parameter.
+	 * @throws DataReadException	If the given ResultSet is closed or if the metadata (columns count and types) can not be fetched.
+	 * 
+	 * @see #convertType(String, String)
+	 * @see ResultSetTableIterator#ResultSetTableIterator(ResultSet, JDBCTranslator, String, DBColumn[])
+	 */
+	public ResultSetTableIterator(final ResultSet dataSet, final JDBCTranslator translator, final String dbms) throws NullPointerException, DataReadException{
+		this(dataSet, translator, dbms, null);
 	}
 
 	/**
@@ -158,17 +233,22 @@ public class ResultSetTableIterator implements TableIterator {
 	 * 
 	 * <p>
 	 * 	In order to guess a TAP type from a DBMS type, this constructor will call {@link #convertType(String, String)}
-	 * 	which deals with all standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	which will ask to the given translator ({@link JDBCTranslator#convertTypeFromDB(int, String, String, String[])})
+	 * 	if not NULL. However if no translator is provided, this function will proceed to a default conversion
+	 * 	using the most common standard datatypes known in Postgres, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * 	This conversion is therefore not as precise as the one expected by the translator.
 	 * </p>
 	 * 
 	 * <p><i><b>Important</b>:
-	 * 	The second parameter of this constructor is given as second parameter of {@link #convertType(String, String)}.
-	 * 	<b>This parameter is really used ONLY when the DBMS is SQLite ("sqlite").</b> Indeed, SQLite has so many datatype
-	 * 	restrictions that it is absolutely needed to know it is the DBMS from which the ResultSet is coming. Without this
-	 * 	information, type guessing will be unpredictable! 
+	 * 	The third parameter of this constructor is given as second parameter of {@link #convertType(String, String)}.
+	 * 	<b>This parameter is really used ONLY when the translator conversion failed and when the DBMS is SQLite ("sqlite").</b>
+	 * 	Indeed, SQLite has so many datatype restrictions that it is absolutely needed to know it is the DBMS from which the
+	 * 	ResultSet is coming. Without this information, type guessing will be unpredictable! 
 	 * </i></p>
 	 * 
 	 * @param dataSet		Dataset over which this iterator must iterate.
+	 * @param translator	The {@link JDBCTranslator} used to transform the ADQL query into SQL query. This translator is also able to convert
+	 *                  	JDBC types and to parse geometrical values. <i>note: MAY be NULL</i> 
 	 * @param dbms			Lower-case string which indicates from which DBMS the given ResultSet is coming. <i>note: MAY be NULL.</i>
 	 * @param resultMeta	List of expected columns. <i>note: these metadata are expected to be really {@link TAPColumn} objects ; MAY be NULL.</i>
 	 * 
@@ -177,7 +257,7 @@ public class ResultSetTableIterator implements TableIterator {
 	 * 
 	 * @see #convertType(String, String)
 	 */
-	public ResultSetTableIterator(final ResultSet dataSet, final String dbms, final DBColumn[] resultMeta) throws NullPointerException, DataReadException{
+	public ResultSetTableIterator(final ResultSet dataSet, final JDBCTranslator translator, final String dbms, final DBColumn[] resultMeta) throws NullPointerException, DataReadException{
 		// A dataset MUST BE provided:
 		if (dataSet == null)
 			throw new NullPointerException("Missing ResultSet object over which to iterate!");
@@ -185,6 +265,9 @@ public class ResultSetTableIterator implements TableIterator {
 		// Keep a reference to the ResultSet:
 		data = dataSet;
 
+		// Set the translator to use (if needed):
+		this.translator = translator;
+
 		// Count columns and determine their type:
 		try{
 			// get the metadata:
@@ -198,11 +281,11 @@ public class ResultSetTableIterator implements TableIterator {
 					try{
 						colMeta[i - 1] = (TAPColumn)resultMeta[i - 1];
 					}catch(ClassCastException cce){
-						DBType datatype = convertType(metadata.getColumnTypeName(i), dbms);
+						DBType datatype = convertType(metadata.getColumnType(i), metadata.getColumnTypeName(i), dbms);
 						colMeta[i - 1] = new TAPColumn(resultMeta[i - 1].getADQLName(), datatype);
 					}
 				}else{
-					DBType datatype = convertType(metadata.getColumnTypeName(i), dbms);
+					DBType datatype = convertType(metadata.getColumnType(i), metadata.getColumnTypeName(i), dbms);
 					colMeta[i - 1] = new TAPColumn(metadata.getColumnLabel(i), datatype);
 				}
 			}
@@ -274,12 +357,23 @@ public class ResultSetTableIterator implements TableIterator {
 		// Get the column value:
 		try{
 			Object o = data.getObject(++colIndex);
-			// if the column value is a Timestamp object, format it in ISO8601:
-			if (o != null && o instanceof Timestamp)
-				o = ISO8601Format.format(((Timestamp)o).getTime());
+			if (o != null){
+				DBType colType = getColType();
+				// if the column value is a Timestamp object, format it in ISO8601:
+				if (o instanceof Timestamp)
+					o = ISO8601Format.format(((Timestamp)o).getTime());
+				// if the column value is a geometrical object, it must be serialized in STC-S:
+				else if (translator != null && colType.isGeometry()){
+					Region region = translator.translateGeometryFromDB(o);
+					if (region != null)
+						o = region.toSTCS();
+				}
+			}
 			return o;
 		}catch(SQLException se){
 			throw new DataReadException("Can not read the value of the " + colIndex + "-th column!", se);
+		}catch(ParseException pe){
+			throw new DataReadException(pe.getMessage());
 		}
 	}
 
@@ -298,62 +392,106 @@ public class ResultSetTableIterator implements TableIterator {
 		return colMeta[colIndex - 1].getDatatype();
 	}
 
+	/**
+	 * <p>Convert the given DBMS type into the corresponding {@link DBType} instance.</p>
+	 * 
+	 * <p>
+	 *	This function first tries the conversion using the translator ({@link JDBCTranslator#convertTypeFromDB(int, String, String, String[])}).
+	 * 	If the translator fails, a default conversion is done.
+	 * </p>
+	 * 
+	 * <p><b>Warning:
+	 * 	It is not recommended to rely on the default conversion.
+	 * 	This conversion is just a matter of guessing the better matching {@link DBType}
+	 * 	considering the types of the following DBMS: PostgreSQL, SQLite, MySQL, Oracle and Java/DB/Derby.
+	 * </b></p>
+	 * 
+	 * @param dbmsType	DBMS column data-type name.
+	 * @param dbms		Lower-case string which indicates which DBMS the ResultSet is coming from. <i>note: MAY be NULL.</i>
+	 * 
+	 * @return	The best suited {@link DBType} object.
+	 * 
+	 * @see JDBCTranslator#convertTypeFromDB(int, String, String, String[])
+	 * @see #defaultTypeConversion(String, String[], String)
+	 */
+	protected DBType convertType(final int dbmsType, String dbmsTypeName, final String dbms) throws DataReadException{
+		// If no type is provided return VARCHAR:
+		if (dbmsTypeName == null || dbmsTypeName.trim().length() == 0)
+			return new DBType(DBDatatype.VARCHAR, DBType.NO_LENGTH);
+
+		// Extract the type prefix and lower-case it:
+		int startParamIndex = dbmsTypeName.indexOf('('), endParamIndex = dbmsTypeName.indexOf(')');
+		String dbmsTypePrefix = (startParamIndex <= 0) ? dbmsTypeName : dbmsTypeName.substring(0, endParamIndex);
+		dbmsTypePrefix = dbmsTypePrefix.trim().toLowerCase();
+		String[] typeParams = (startParamIndex <= 0) ? null : dbmsTypeName.substring(startParamIndex + 1, endParamIndex).split(",");
+
+		// Ask first to the translator:
+		DBType dbType = null;
+		if (translator != null)
+			dbType = translator.convertTypeFromDB(dbmsType, dbmsTypeName, dbmsTypePrefix, typeParams);
+
+		// And if unsuccessful, apply a default conversion:
+		if (dbType == null)
+			dbType = defaultTypeConversion(dbmsTypePrefix, typeParams, dbms);
+
+		return dbType;
+	}
+
 	/**
 	 * <p>Convert the given DBMS type into the better matching {@link DBType} instance.
-	 * This function is used to guess the TAP type of a column when it is not provided in the constructor.
+	 * This function is used to <b>guess</b> the TAP type of a column when it is not provided in the constructor.
 	 * It aims not to be exhaustive, but just to provide a type when the given TAP metadata are incomplete.</p>
 	 * 
 	 * <p><i>Note:
-	 * 	Any unknown DBMS datatype will be considered and translated as a VARCHAR.
-	 * 	The same type will be returned if the given parameter is an empty string or NULL.
+	 * 	Any unknown DBMS data-type will be considered and translated as a VARCHAR.
+	 * 	This latter will be also returned if the given parameter is an empty string or NULL.
 	 * </i></p>
 	 * 
 	 * <p><i>Note:
-	 * 	This type conversion function has been designed to work with all standard datatypes of the following DBMS:
+	 * 	This type conversion function has been designed to work with all standard data-types of the following DBMS:
 	 * 	PostgreSQL, SQLite, MySQL, Oracle and JavaDB/Derby.
 	 * </i></p>
 	 * 
 	 * <p><i><b>Important</b>:
-	 * 	<b>The second parameter is REALLY NEEDED when the DBMS is SQLite ("sqlite")!</b>
-	 * 	Indeed, SQLite has a so restrictive list of datatypes that this function can reliably convert its types
+	 * 	<b>The third parameter is REALLY NEEDED when the DBMS is SQLite ("sqlite")!</b>
+	 * 	Indeed, SQLite has a so restrictive list of data-types that this function can reliably convert
 	 * 	only if it knows the DBMS is SQLite. Otherwise, the conversion result would be unpredictable.
 	 * 	</i>In this default implementation of this function, all other DBMS values are ignored.<i>
 	 * </i></p>
 	 * 
 	 * <p><b>Warning</b>:
-	 * 	This function is not translating the geometrical datatypes. If a such datatype is encountered,
+	 * 	This function is not translating the geometrical data-types. If a such data-type is encountered,
 	 * 	it will considered as unknown and so, a VARCHAR TAP type will be returned.
 	 * </p>
 	 * 
-	 * @param dbmsType	DBMS column datatype name.
-	 * @param dbms		Lower-case string which indicates which DBMS the ResultSet is coming from. <i>note: MAY be NULL.</i>
+	 * @param dbmsTypeName	Name of type, without the eventual parameters.
+	 * @param params		The eventual type parameters (e.g. char string length).
+	 * @param dbms			The targeted DBMS.
 	 * 
-	 * @return	The best suited {@link DBType} object.
+	 * @return	The corresponding ADQL/TAP type. <i>NEVER NULL</i>
 	 */
-	protected DBType convertType(String dbmsType, final String dbms){
-		// If no type is provided return VARCHAR:
-		if (dbmsType == null || dbmsType.trim().length() == 0)
-			return new DBType(DBDatatype.VARCHAR, DBType.NO_LENGTH);
-
-		// Extract the type prefix and lower-case it:
-		dbmsType = dbmsType.toLowerCase();
-		int paramIndex = dbmsType.indexOf('(');
-		String dbmsTypePrefix = (paramIndex <= 0) ? dbmsType : dbmsType.substring(0, paramIndex);
-		int firstParam = getLengthParam(dbmsTypePrefix, paramIndex);
+	protected final DBType defaultTypeConversion(final String dbmsTypeName, final String[] params, final String dbms){
+		// Get the length parameter (always in first position):
+		int lengthParam = DBType.NO_LENGTH;
+		if (params != null && params.length > 0){
+			try{
+				lengthParam = Integer.parseInt(params[0]);
+			}catch(NumberFormatException nfe){}
+		}
 
 		// CASE: SQLITE
 		if (dbms != null && dbms.equals("sqlite")){
 			// INTEGER -> SMALLINT, INTEGER, BIGINT
-			if (dbmsTypePrefix.equals("integer"))
+			if (dbmsTypeName.equals("integer"))
 				return new DBType(DBDatatype.BIGINT);
 			// REAL -> REAL, DOUBLE
-			else if (dbmsTypePrefix.equals("real"))
+			else if (dbmsTypeName.equals("real"))
 				return new DBType(DBDatatype.DOUBLE);
 			// TEXT -> CHAR, VARCHAR, CLOB, TIMESTAMP
-			else if (dbmsTypePrefix.equals("text"))
+			else if (dbmsTypeName.equals("text"))
 				return new DBType(DBDatatype.VARCHAR);
 			// BLOB -> BINARY, VARBINARY, BLOB
-			else if (dbmsTypePrefix.equals("blob"))
+			else if (dbmsTypeName.equals("blob"))
 				return new DBType(DBDatatype.BLOB);
 			// Default:
 			else
@@ -362,40 +500,40 @@ public class ResultSetTableIterator implements TableIterator {
 		// CASE: OTHER DBMS
 		else{
 			// SMALLINT
-			if (dbmsTypePrefix.equals("smallint") || dbmsTypePrefix.equals("int2"))
+			if (dbmsTypeName.equals("smallint") || dbmsTypeName.equals("int2") || dbmsTypeName.equals("smallserial") || dbmsTypeName.equals("serial2") || dbmsTypeName.equals("boolean") || dbmsTypeName.equals("bool"))
 				return new DBType(DBDatatype.SMALLINT);
 			// INTEGER
-			else if (dbmsTypePrefix.equals("integer") || dbmsTypePrefix.equals("int") || dbmsTypePrefix.equals("int4"))
+			else if (dbmsTypeName.equals("integer") || dbmsTypeName.equals("int") || dbmsTypeName.equals("int4") || dbmsTypeName.equals("serial") || dbmsTypeName.equals("serial4"))
 				return new DBType(DBDatatype.INTEGER);
 			// BIGINT
-			else if (dbmsTypePrefix.equals("bigint") || dbmsTypePrefix.equals("int8") || dbmsTypePrefix.equals("number"))
+			else if (dbmsTypeName.equals("bigint") || dbmsTypeName.equals("int8") || dbmsTypeName.equals("bigserial") || dbmsTypeName.equals("bigserial8") || dbmsTypeName.equals("number"))
 				return new DBType(DBDatatype.BIGINT);
 			// REAL
-			else if (dbmsTypePrefix.equals("float4") || (dbmsTypePrefix.equals("float") && firstParam <= 63))
+			else if (dbmsTypeName.equals("real") || dbmsTypeName.equals("float4") || (dbmsTypeName.equals("float") && lengthParam <= 63))
 				return new DBType(DBDatatype.REAL);
 			// DOUBLE
-			else if (dbmsTypePrefix.equals("double") || dbmsTypePrefix.equals("double precision") || dbmsTypePrefix.equals("float8") || (dbmsTypePrefix.equals("float") && firstParam > 63))
+			else if (dbmsTypeName.equals("double") || dbmsTypeName.equals("double precision") || dbmsTypeName.equals("float8") || (dbmsTypeName.equals("float") && lengthParam > 63))
 				return new DBType(DBDatatype.DOUBLE);
 			// BINARY
-			else if (dbmsTypePrefix.equals("binary") || dbmsTypePrefix.equals("raw") || ((dbmsTypePrefix.equals("char") || dbmsTypePrefix.equals("character")) && dbmsType.endsWith(" for bit data")))
-				return new DBType(DBDatatype.BINARY, firstParam);
+			else if (dbmsTypeName.equals("bit") || dbmsTypeName.equals("binary") || dbmsTypeName.equals("raw") || ((dbmsTypeName.equals("char") || dbmsTypeName.equals("character")) && dbmsTypeName.endsWith(" for bit data")))
+				return new DBType(DBDatatype.BINARY, lengthParam);
 			// VARBINARY
-			else if (dbmsTypePrefix.equals("varbinary") || dbmsTypePrefix.equals("long raw") || ((dbmsTypePrefix.equals("varchar") || dbmsTypePrefix.equals("character varying")) && dbmsType.endsWith(" for bit data")))
-				return new DBType(DBDatatype.VARBINARY, firstParam);
+			else if (dbmsTypeName.equals("bit varying") || dbmsTypeName.equals("varbit") || dbmsTypeName.equals("varbinary") || dbmsTypeName.equals("long raw") || ((dbmsTypeName.equals("varchar") || dbmsTypeName.equals("character varying")) && dbmsTypeName.endsWith(" for bit data")))
+				return new DBType(DBDatatype.VARBINARY, lengthParam);
 			// CHAR
-			else if (dbmsTypePrefix.equals("char") || dbmsTypePrefix.equals("character"))
-				return new DBType(DBDatatype.CHAR, firstParam);
+			else if (dbmsTypeName.equals("char") || dbmsTypeName.equals("character"))
+				return new DBType(DBDatatype.CHAR, lengthParam);
 			// VARCHAR
-			else if (dbmsTypePrefix.equals("varchar") || dbmsTypePrefix.equals("varchar2") || dbmsTypePrefix.equals("character varying"))
-				return new DBType(DBDatatype.VARBINARY, firstParam);
+			else if (dbmsTypeName.equals("varchar") || dbmsTypeName.equals("varchar2") || dbmsTypeName.equals("character varying"))
+				return new DBType(DBDatatype.VARCHAR, lengthParam);
 			// BLOB
-			else if (dbmsTypePrefix.equals("bytea") || dbmsTypePrefix.equals("blob") || dbmsTypePrefix.equals("binary large object"))
+			else if (dbmsTypeName.equals("bytea") || dbmsTypeName.equals("blob") || dbmsTypeName.equals("binary large object"))
 				return new DBType(DBDatatype.BLOB);
 			// CLOB
-			else if (dbmsTypePrefix.equals("text") || dbmsTypePrefix.equals("clob") || dbmsTypePrefix.equals("character large object"))
+			else if (dbmsTypeName.equals("text") || dbmsTypeName.equals("clob") || dbmsTypeName.equals("character large object"))
 				return new DBType(DBDatatype.CLOB);
 			// TIMESTAMP
-			else if (dbmsTypePrefix.equals("timestamp"))
+			else if (dbmsTypeName.equals("timestamp") || dbmsTypeName.equals("timestamptz") || dbmsTypeName.equals("time") || dbmsTypeName.equals("timetz") || dbmsTypeName.equals("date"))
 				return new DBType(DBDatatype.TIMESTAMP);
 			// Default:
 			else
@@ -403,46 +541,4 @@ public class ResultSetTableIterator implements TableIterator {
 		}
 	}
 
-	/**
-	 * <p>Extract the 'length' parameter of a DBMS type string.</p>
-	 * 
-	 * <p>
-	 * 	If the given type string does not contain any parameter
-	 * 	OR if the first parameter can not be casted into an integer,
-	 * 	{@link DBType#NO_LENGTH} will be returned.
-	 * </p>
-	 * 
-	 * @param dbmsType		DBMS type string (containing the datatype and the 'length' parameter).
-	 * @param paramIndex	Index of the open bracket.
-	 * 
-	 * @return	The 'length' parameter value if found, {@link DBType#NO_LENGTH} otherwise.
-	 */
-	protected final int getLengthParam(final String dbmsType, final int paramIndex){
-		// If no parameter has been previously detected, no length parameter:
-		if (paramIndex <= 0)
-			return DBType.NO_LENGTH;
-
-		// If there is one and that at least ONE parameter is provided....
-		else{
-			int lengthParam = DBType.NO_LENGTH;
-			String paramsStr = dbmsType.substring(paramIndex + 1);
-
-			// ...extract the 'length' parameter:
-			/* note: we suppose here that no other parameter is possible ;
-			 *       but if there are, they are ignored and we try to consider the first parameter
-			 *       as the length */
-			int paramEndIndex = paramsStr.indexOf(',');
-			if (paramEndIndex <= 0)
-				paramEndIndex = paramsStr.indexOf(')');
-
-			// ...cast it into an integer:
-			try{
-				lengthParam = Integer.parseInt(paramsStr.substring(0, paramEndIndex));
-			}catch(Exception ex){}
-
-			// ...and finally return it:
-			return lengthParam;
-		}
-	}
-
 }
diff --git a/src/tap/db/JDBCConnection.java b/src/tap/db/JDBCConnection.java
index 1e1a836f92d422fbf8ed4f89247d203993947a56..437ffdba5399b1b29136ea6263dd668e68630f11 100644
--- a/src/tap/db/JDBCConnection.java
+++ b/src/tap/db/JDBCConnection.java
@@ -49,8 +49,11 @@ import tap.metadata.TAPTable;
 import tap.metadata.TAPTable.TableType;
 import uws.ISO8601Format;
 import uws.service.log.UWSLog.LogLevel;
+import adql.db.DBColumn;
 import adql.db.DBType;
 import adql.db.DBType.DBDatatype;
+import adql.db.STCS;
+import adql.db.STCS.Region;
 import adql.query.ADQLQuery;
 import adql.query.IdentifierField;
 import adql.translator.ADQLTranslator;
@@ -97,25 +100,26 @@ import adql.translator.TranslationException;
  * 
  * <h3>Datatypes</h3>
  * 
- * <p>Column types are converted from DBMS to TAP types with {@link #getTAPType(String)} and from TAP to DBMS types with {@link #getDBMSDatatype(DBType)}.</p>
+ * <p>
+ * 	All datatype conversions done while fetching a query result (via a {@link ResultSet})
+ * 	are done exclusively by the returned {@link TableIterator} (so, here {@link ResultSetTableIterator}).
+ * </p>
  * 
  * <p>
- * 	All typical DBMS datatypes are taken into account, <b>EXCEPT the geometrical types</b> (POINT and REGION). For these types, the only object having this
- * 	information is the translator thanks to {@link JDBCTranslator#isPointType(String)}, {@link JDBCTranslator#isRegionType(String)},
- * 	{@link JDBCTranslator#getPointType()} and {@link JDBCTranslator#getRegionType()}. The two first functions are used to identify a DBMS type as a point or
- * 	a region (note: several DBMS datatypes may be identified as a geometry type). The two others provide the DBMS type corresponding the best to the TAP types
- * 	POINT and REGION.
+ * 	However, datatype conversions done while uploading a table are done here by the function
+ * 	{@link #convertTypeToDB(DBType)}. This function uses first the conversion function of the translator
+ * 	({@link JDBCTranslator#convertTypeToDB(DBType)}), and then {@link #defaultTypeConversion(DBType)}
+ * 	if it fails.
  * </p>
  * 
- * <p><i><b>Warning:</b>
- * 	The TAP type REGION can be either a circle, a box or a polygon. Since several DBMS types correspond to one TAP type, {@link JDBCTranslator#getRegionType()}
- * 	MUST return a type covering all these region datatypes. Generally, it will be a VARCHAR whose the values would be STC-S expressions.
- * 	Note that this function is used ONLY WHEN tables with a geometrical value is uploaded. On the contrary, {@link JDBCTranslator#isRegionType(String)}
- * 	is used much more often: in order to write the metadata part of a query result.
- * </i></p>
+ * <p>
+ * 	In this default conversion, all typical DBMS datatypes are taken into account, <b>EXCEPT the geometrical types</b>
+ * 	(POINT and REGION). That's why it is recommended to use a translator in which the geometrical types are supported
+ * 	and managed.
+ * </p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (09/2014)
+ * @version 2.0 (11/2014)
  * @since 2.0
  */
 public class JDBCConnection implements DBConnection {
@@ -331,33 +335,54 @@ public class JDBCConnection implements DBConnection {
 		ResultSet result = null;
 		try{
 			// 1. Translate the ADQL query into SQL:
-			logger.logDB(LogLevel.INFO, this, "TRANSLATE", "Translating ADQL: " + adqlQuery.toADQL().replaceAll("(\t|\r?\n)+", " "), null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "TRANSLATE", "Translating ADQL: " + adqlQuery.toADQL().replaceAll("(\t|\r?\n)+", " "), null);
 			sql = translator.translate(adqlQuery);
 
 			// 2. Execute the SQL query:
 			Statement stmt = connection.createStatement();
-			logger.logDB(LogLevel.INFO, this, "EXECUTE", "Executing translated query: " + sql.replaceAll("(\t|\r?\n)+", " "), null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "EXECUTE", "Executing translated query: " + sql.replaceAll("(\t|\r?\n)+", " "), null);
 			result = stmt.executeQuery(sql);
 
 			// 3. Return the result through a TableIterator object:
-			logger.logDB(LogLevel.INFO, this, "RESULT", "Returning result", null);
-			return new ResultSetTableIterator(result, dbms, adqlQuery.getResultingColumns());
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "RESULT", "Returning result", null);
+			return createTableIterator(result, adqlQuery.getResultingColumns());
 
 		}catch(SQLException se){
 			close(result);
-			logger.logDB(LogLevel.ERROR, this, "EXECUTE", "Unexpected error while EXECUTING SQL query!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "EXECUTE", "Unexpected error while EXECUTING SQL query!", se);
 			throw new DBException("Unexpected error while executing a SQL query: " + se.getMessage(), se);
 		}catch(TranslationException te){
 			close(result);
-			logger.logDB(LogLevel.ERROR, this, "TRANSLATE", "Unexpected error while TRANSLATING ADQL into SQL!", te);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "TRANSLATE", "Unexpected error while TRANSLATING ADQL into SQL!", te);
 			throw new DBException("Unexpected error while translating ADQL into SQL: " + te.getMessage(), te);
 		}catch(DataReadException dre){
 			close(result);
-			logger.logDB(LogLevel.ERROR, this, "RESULT", "Unexpected error while reading the query result!", dre);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "RESULT", "Unexpected error while reading the query result!", dre);
 			throw new DBException("Impossible to read the query result, because: " + dre.getMessage(), dre);
 		}
 	}
 
+	/**
+	 * Create a {@link TableIterator} instance which lets reading the given result table.
+	 * 
+	 * @param rs				Result of an SQL query.
+	 * @param resultingColumns	Metadata corresponding to each columns of the result.
+	 * 
+	 * @return	A {@link TableIterator} instance.
+	 * 
+	 * @throws DataReadException	If the metadata (columns count and types) can not be fetched
+	 *                          	or if any other error occurs.
+	 */
+	protected TableIterator createTableIterator(final ResultSet rs, final DBColumn[] resultingColumns) throws DataReadException{
+		return new ResultSetTableIterator(rs, translator, dbms, resultingColumns);
+	}
+
 	/* *********************** */
 	/* TAP_SCHEMA MANIPULATION */
 	/* *********************** */
@@ -434,23 +459,28 @@ public class JDBCConnection implements DBConnection {
 			stmt = connection.createStatement();
 
 			// load all schemas from TAP_SCHEMA.schemas:
-			logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.schemas.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.schemas.", null);
 			loadSchemas(tap_schema.getTable(STDTable.SCHEMAS.label), metadata, stmt);
 
 			// load all tables from TAP_SCHEMA.tables:
-			logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.tables.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.tables.", null);
 			List<TAPTable> lstTables = loadTables(tap_schema.getTable(STDTable.TABLES.label), metadata, stmt);
 
 			// load all columns from TAP_SCHEMA.columns:
-			logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.columns.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.columns.", null);
 			loadColumns(tap_schema.getTable(STDTable.COLUMNS.label), lstTables, stmt);
 
 			// load all foreign keys from TAP_SCHEMA.keys and TAP_SCHEMA.key_columns:
-			logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.keys and TAP_SCHEMA.key_columns.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "LOAD_TAP_SCHEMA", "Loading TAP_SCHEMA.keys and TAP_SCHEMA.key_columns.", null);
 			loadKeys(tap_schema.getTable(STDTable.KEYS.label), tap_schema.getTable(STDTable.KEY_COLUMNS.label), lstTables, stmt);
 
 		}catch(SQLException se){
-			logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to create a Statement!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to create a Statement!", se);
 			throw new DBException("Can not create a Statement!", se);
 		}finally{
 			close(stmt);
@@ -500,7 +530,8 @@ public class JDBCConnection implements DBConnection {
 				metadata.addSchema(newSchema);
 			}
 		}catch(SQLException se){
-			logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load schemas from TAP_SCHEMA.schemas!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load schemas from TAP_SCHEMA.schemas!", se);
 			throw new DBException("Impossible to load schemas from TAP_SCHEMA.schemas!", se);
 		}finally{
 			close(rs);
@@ -553,7 +584,8 @@ public class JDBCConnection implements DBConnection {
 				// get the schema:
 				TAPSchema schema = metadata.getSchema(schemaName);
 				if (schema == null){
-					logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the schema of the table \"" + tableName + "\": \"" + schemaName + "\"!", null);
+					if (logger != null)
+						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the schema of the table \"" + tableName + "\": \"" + schemaName + "\"!", null);
 					throw new DBException("Impossible to find the schema of the table \"" + tableName + "\": \"" + schemaName + "\"!");
 				}
 
@@ -579,7 +611,8 @@ public class JDBCConnection implements DBConnection {
 
 			return lstTables;
 		}catch(SQLException se){
-			logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load tables from TAP_SCHEMA.tables!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load tables from TAP_SCHEMA.tables!", se);
 			throw new DBException("Impossible to load tables from TAP_SCHEMA.tables!", se);
 		}finally{
 			close(rs);
@@ -630,7 +663,8 @@ public class JDBCConnection implements DBConnection {
 				// get the table:
 				TAPTable table = searchTable(tableName, lstTables.iterator());
 				if (table == null){
-					logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the table of the column \"" + columnName + "\": \"" + tableName + "\"!", null);
+					if (logger != null)
+						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the table of the column \"" + columnName + "\": \"" + tableName + "\"!", null);
 					throw new DBException("Impossible to find the table of the column \"" + columnName + "\": \"" + tableName + "\"!");
 				}
 
@@ -659,7 +693,8 @@ public class JDBCConnection implements DBConnection {
 				table.addColumn(newColumn);
 			}
 		}catch(SQLException se){
-			logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load columns from TAP_SCHEMA.columns!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load columns from TAP_SCHEMA.columns!", se);
 			throw new DBException("Impossible to load columns from TAP_SCHEMA.columns!", se);
 		}finally{
 			close(rs);
@@ -713,12 +748,14 @@ public class JDBCConnection implements DBConnection {
 				// get the two tables (source and target):
 				TAPTable sourceTable = searchTable(from_table, lstTables.iterator());
 				if (sourceTable == null){
-					logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the source table of the foreign key \"" + key_id + "\": \"" + from_table + "\"!", null);
+					if (logger != null)
+						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the source table of the foreign key \"" + key_id + "\": \"" + from_table + "\"!", null);
 					throw new DBException("Impossible to find the source table of the foreign key \"" + key_id + "\": \"" + from_table + "\"!");
 				}
 				TAPTable targetTable = searchTable(target_table, lstTables.iterator());
 				if (targetTable == null){
-					logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the target table of the foreign key \"" + key_id + "\": \"" + target_table + "\"!", null);
+					if (logger != null)
+						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to find the target table of the foreign key \"" + key_id + "\": \"" + target_table + "\"!", null);
 					throw new DBException("Impossible to find the target table of the foreign key \"" + key_id + "\": \"" + target_table + "\"!");
 				}
 
@@ -731,7 +768,8 @@ public class JDBCConnection implements DBConnection {
 					while(rsKeyCols.next())
 						columns.put(rsKeyCols.getString(1), rsKeyCols.getString(2));
 				}catch(SQLException se){
-					logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load key columns from TAP_SCHEMA.key_columns for the foreign key: \"" + key_id + "\"!", se);
+					if (logger != null)
+						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load key columns from TAP_SCHEMA.key_columns for the foreign key: \"" + key_id + "\"!", se);
 					throw new DBException("Impossible to load key columns from TAP_SCHEMA.key_columns for the foreign key: \"" + key_id + "\"!", se);
 				}finally{
 					close(rsKeyCols);
@@ -741,12 +779,14 @@ public class JDBCConnection implements DBConnection {
 				try{
 					sourceTable.addForeignKey(key_id, targetTable, columns, nullifyIfNeeded(description), nullifyIfNeeded(utype));
 				}catch(Exception ex){
-					logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to create the foreign key \"" + key_id + "\" because: " + ex.getMessage(), ex);
+					if (logger != null)
+						logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to create the foreign key \"" + key_id + "\" because: " + ex.getMessage(), ex);
 					throw new DBException("Impossible to create the foreign key \"" + key_id + "\" because: " + ex.getMessage(), ex);
 				}
 			}
 		}catch(SQLException se){
-			logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load columns from TAP_SCHEMA.columns!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "LOAD_TAP_SCHEMA", "Impossible to load columns from TAP_SCHEMA.columns!", se);
 			throw new DBException("Impossible to load columns from TAP_SCHEMA.columns!", se);
 		}finally{
 			close(rs);
@@ -792,26 +832,31 @@ public class JDBCConnection implements DBConnection {
 			stmt = connection.createStatement();
 
 			// 1. Ensure TAP_SCHEMA exists and drop all its standard TAP tables:
-			logger.logDB(LogLevel.INFO, this, "CLEAN_TAP_SCHEMA", "Cleaning TAP_SCHEMA.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "CLEAN_TAP_SCHEMA", "Cleaning TAP_SCHEMA.", null);
 			resetTAPSchema(stmt, stdTables);
 
 			// 2. Create all standard TAP tables:
-			logger.logDB(LogLevel.INFO, this, "CREATE_TAP_SCHEMA", "Creating TAP_SCHEMA tables.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "CREATE_TAP_SCHEMA", "Creating TAP_SCHEMA tables.", null);
 			for(TAPTable table : stdTables)
 				createTAPSchemaTable(table, stmt);
 
 			// C. FILL THE NEW TABLE USING THE GIVEN DATA ITERATOR:
-			logger.logDB(LogLevel.INFO, this, "CREATE_TAP_SCHEMA", "Filling TAP_SCHEMA tables.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "CREATE_TAP_SCHEMA", "Filling TAP_SCHEMA tables.", null);
 			fillTAPSchema(metadata);
 
 			// D. CREATE THE INDEXES OF ALL STANDARD TAP TABLES:
-			logger.logDB(LogLevel.INFO, this, "CREATE_TAP_SCHEMA", "Creating TAP_SCHEMA tables' indexes.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "CREATE_TAP_SCHEMA", "Creating TAP_SCHEMA tables' indexes.", null);
 			for(TAPTable table : stdTables)
 				createTAPTableIndexes(table, stmt);
 
 			commit();
 		}catch(SQLException se){
-			logger.logDB(LogLevel.ERROR, this, "CREATE_TAP_SCHEMA", "Impossible to SET TAP_SCHEMA in DB!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "CREATE_TAP_SCHEMA", "Impossible to SET TAP_SCHEMA in DB!", se);
 			rollback();
 			throw new DBException("Impossible to SET TAP_SCHEMA in DB!", se);
 		}finally{
@@ -1040,7 +1085,7 @@ public class JDBCConnection implements DBConnection {
 			sql.append(translator.getColumnName(col));
 
 			// column type:
-			sql.append(' ').append(getDBMSDatatype(col.getDatatype()));
+			sql.append(' ').append(convertTypeToDB(col.getDatatype()));
 
 			// last column ?
 			if (it.hasNext())
@@ -1486,12 +1531,14 @@ public class JDBCConnection implements DBConnection {
 			// 1. Create the upload schema, if it does not already exist:
 			if (!isSchemaExisting(tableDef.getDBSchemaName(), dbMeta)){
 				stmt.executeUpdate("CREATE SCHEMA " + translator.getQualifiedSchemaName(tableDef) + ";");
-				logger.logDB(LogLevel.INFO, this, "SCHEMA_CREATED", "Schema \"" + tableDef.getADQLSchemaName() + "\" (in DB: " + translator.getQualifiedSchemaName(tableDef) + ") created.", null);
+				if (logger != null)
+					logger.logDB(LogLevel.INFO, this, "SCHEMA_CREATED", "Schema \"" + tableDef.getADQLSchemaName() + "\" (in DB: " + translator.getQualifiedSchemaName(tableDef) + ") created.", null);
 			}
 			// 1bis. Ensure the table does not already exist and if it is the case, throw an understandable exception:
 			else if (isTableExisting(tableDef.getDBSchemaName(), tableDef.getDBName(), dbMeta)){
 				DBException de = new DBException("Impossible to create the user uploaded table in the database: " + translator.getQualifiedTableName(tableDef) + "! This table already exists.");
-				logger.logDB(LogLevel.ERROR, this, "ADD_UPLOAD_TABLE", de.getMessage(), de);
+				if (logger != null)
+					logger.logDB(LogLevel.ERROR, this, "ADD_UPLOAD_TABLE", de.getMessage(), de);
 				throw de;
 			}
 
@@ -1505,7 +1552,7 @@ public class JDBCConnection implements DBConnection {
 				// column name:
 				sqlBuf.append(translator.getColumnName(col));
 				// column type:
-				sqlBuf.append(' ').append(getDBMSDatatype(col.getDatatype()));
+				sqlBuf.append(' ').append(convertTypeToDB(col.getDatatype()));
 				// last column ?
 				if (it.hasNext())
 					sqlBuf.append(',');
@@ -1521,13 +1568,15 @@ public class JDBCConnection implements DBConnection {
 			commit();
 
 			// Log the end:
-			logger.logDB(LogLevel.INFO, this, "TABLE_CREATED", "Table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getQualifiedTableName(tableDef) + ") created.", null);
+			if (logger != null)
+				logger.logDB(LogLevel.INFO, this, "TABLE_CREATED", "Table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getQualifiedTableName(tableDef) + ") created.", null);
 
 			return true;
 
 		}catch(SQLException se){
 			rollback();
-			logger.logDB(LogLevel.WARNING, this, "ADD_UPLOAD_TABLE", "Impossible to create the uploaded table: " + translator.getQualifiedTableName(tableDef) + "!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.WARNING, this, "ADD_UPLOAD_TABLE", "Impossible to create the uploaded table: " + translator.getQualifiedTableName(tableDef) + "!", se);
 			throw new DBException("Impossible to create the uploaded table: " + translator.getQualifiedTableName(tableDef) + "!", se);
 		}catch(DBException de){
 			rollback();
@@ -1549,6 +1598,10 @@ public class JDBCConnection implements DBConnection {
 	 * 	In case of any failure while using this feature, it will be flagged as unsupported and one-by-one updates will be processed.
 	 * </i></p>
 	 * 
+	 * <p><i>Note:
+	 * 	This function proceeds to a formatting of TIMESTAMP and GEOMETRY (point, circle, box, polygon) values.
+	 * </i></p>
+	 * 
 	 * @param metaTable	Description of the updated table.
 	 * @param data		Iterator over the rows to insert.
 	 * 
@@ -1589,14 +1642,30 @@ public class JDBCConnection implements DBConnection {
 				int c = 1;
 				while(data.hasNextCol()){
 					Object val = data.nextCol();
-					/* If the value is supposed to be a Timestamp, parse it
-					 * and build an appropriate SQL object: */
-					if (val != null && cols[c - 1].getDatatype().type == DBDatatype.TIMESTAMP){
-						try{
-							val = new Timestamp(ISO8601Format.parse(val.toString()));
-						}catch(ParseException pe){
-							logger.logDB(LogLevel.ERROR, this, "UPLOAD", "Unexpected date format for the " + c + "-th column (" + val + ")! A date formatted in ISO8601 was expected.", pe);
-							throw new DBException("Unexpected date format for the " + c + "-th column (" + val + ")! A date formatted in ISO8601 was expected.", pe);
+					if (val != null && cols[c - 1] != null){
+						/* TIMESTAMP FORMATTING */
+						if (cols[c - 1].getDatatype().type == DBDatatype.TIMESTAMP){
+							try{
+								val = new Timestamp(ISO8601Format.parse(val.toString()));
+							}catch(ParseException pe){
+								if (logger != null)
+									logger.logDB(LogLevel.ERROR, this, "UPLOAD", "Unexpected date format for the " + c + "-th column (" + val + ")! A date formatted in ISO8601 was expected.", pe);
+								throw new DBException("Unexpected date format for the " + c + "-th column (" + val + ")! A date formatted in ISO8601 was expected.", pe);
+							}
+						}
+						/* GEOMETRY FORMATTING */
+						else if (cols[c - 1].getDatatype().type == DBDatatype.POINT || cols[c - 1].getDatatype().type == DBDatatype.REGION){
+							Region region;
+							try{
+								// parse the region as an STC-S expression:
+								region = STCS.parseRegion(val.toString());
+								// translate this STC region into the corresponding column value:
+								val = translator.translateGeometryToDB(region);
+							}catch(adql.parser.ParseException e){
+								if (logger != null)
+									logger.logDB(LogLevel.ERROR, this, "UPLOAD", "Incorrect STC-S syntax for the geometrical value \"" + val + "\"!", e);
+								throw new DataReadException("Incorrect STC-S syntax for the geometrical value \"" + val + "\"!", e);
+							}
 						}
 					}
 					stmt.setObject(c++, val);
@@ -1653,16 +1722,19 @@ public class JDBCConnection implements DBConnection {
 			int cnt = stmt.executeUpdate("DROP TABLE " + translator.getQualifiedTableName(tableDef) + ";");
 
 			// Log the end:
-			if (cnt == 0)
-				logger.logDB(LogLevel.INFO, this, "TABLE_DROPPED", "Table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getQualifiedTableName(tableDef) + ") dropped.", null);
-			else
-				logger.logDB(LogLevel.ERROR, this, "TABLE_DROPPED", "Table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getQualifiedTableName(tableDef) + ") NOT dropped.", null);
+			if (logger != null){
+				if (cnt == 0)
+					logger.logDB(LogLevel.INFO, this, "TABLE_DROPPED", "Table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getQualifiedTableName(tableDef) + ") dropped.", null);
+				else
+					logger.logDB(LogLevel.ERROR, this, "TABLE_DROPPED", "Table \"" + tableDef.getADQLName() + "\" (in DB: " + translator.getQualifiedTableName(tableDef) + ") NOT dropped.", null);
+			}
 
 			// Ensure the update is successful:
 			return (cnt == 0);
 
 		}catch(SQLException se){
-			logger.logDB(LogLevel.WARNING, this, "DROP_UPLOAD_TABLE", "Impossible to drop the uploaded table: " + translator.getQualifiedTableName(tableDef) + "!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.WARNING, this, "DROP_UPLOAD_TABLE", "Impossible to drop the uploaded table: " + translator.getQualifiedTableName(tableDef) + "!", se);
 			throw new DBException("Impossible to drop the uploaded table: " + translator.getQualifiedTableName(tableDef) + "!", se);
 		}finally{
 			close(stmt);
@@ -1707,7 +1779,28 @@ public class JDBCConnection implements DBConnection {
 	/* ************** */
 
 	/**
-	 * <p>Get the DBMS compatible datatype corresponding to the given column TAPType.</p>
+	 * <p>Convert the given TAP type into the corresponding DBMS column type.</p>
+	 * 
+	 * <p>
+	 * 	This function tries first the type conversion using the translator ({@link JDBCTranslator#convertTypeToDB(DBType)}).
+	 * 	If it fails, a default conversion is done considering all the known types of the following DBMS:
+	 * 	PostgreSQL, SQLite, MySQL, Oracle and JavaDB/Derby.
+	 * </p>
+	 * 
+	 * @param type	TAP type to convert.
+	 * 
+	 * @return	The corresponding DBMS type.
+	 * 
+	 * @see JDBCTranslator#convertTypeToDB(DBType)
+	 * @see #defaultTypeConversion(DBType)
+	 */
+	protected String convertTypeToDB(final DBType type){
+		String dbmsType = translator.convertTypeToDB(type);
+		return (dbmsType == null) ? defaultTypeConversion(type) : dbmsType;
+	}
+
+	/**
+	 * <p>Get the DBMS compatible datatype corresponding to the given column {@link DBType}.</p>
 	 * 
 	 * <p><i>Note 1:
 	 * 	This function is able to generate a DB datatype compatible with the currently used DBMS.
@@ -1728,7 +1821,7 @@ public class JDBCConnection implements DBConnection {
 	 * 
 	 * @return	The corresponding DB type, or NULL if the given type is not managed or is NULL.
 	 */
-	protected String getDBMSDatatype(DBType datatype){
+	protected String defaultTypeConversion(DBType datatype){
 		if (datatype == null)
 			datatype = new DBType(DBDatatype.VARCHAR);
 
@@ -1838,11 +1931,13 @@ public class JDBCConnection implements DBConnection {
 		try{
 			if (supportsTransaction){
 				connection.setAutoCommit(false);
-				logger.logDB(LogLevel.INFO, this, "START_TRANSACTION", "Transaction STARTED.", null);
+				if (logger != null)
+					logger.logDB(LogLevel.INFO, this, "START_TRANSACTION", "Transaction STARTED.", null);
 			}
 		}catch(SQLException se){
 			supportsTransaction = false;
-			logger.logDB(LogLevel.ERROR, this, "START_TRANSACTION", "Transaction STARTing impossible!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "START_TRANSACTION", "Transaction STARTing impossible!", se);
 			throw new DBException("Transaction STARTing impossible!", se);
 		}
 	}
@@ -1869,11 +1964,13 @@ public class JDBCConnection implements DBConnection {
 		try{
 			if (supportsTransaction){
 				connection.commit();
-				logger.logDB(LogLevel.INFO, this, "COMMIT", "Transaction COMMITED.", null);
+				if (logger != null)
+					logger.logDB(LogLevel.INFO, this, "COMMIT", "Transaction COMMITED.", null);
 			}
 		}catch(SQLException se){
 			supportsTransaction = false;
-			logger.logDB(LogLevel.ERROR, this, "COMMIT", "Transaction COMMIT impossible!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "COMMIT", "Transaction COMMIT impossible!", se);
 			throw new DBException("Transaction COMMIT impossible!", se);
 		}
 	}
@@ -1900,11 +1997,13 @@ public class JDBCConnection implements DBConnection {
 		try{
 			if (supportsTransaction){
 				connection.rollback();
-				logger.logDB(LogLevel.INFO, this, "ROLLBACK", "Transaction ROLLBACKED.", null);
+				if (logger != null)
+					logger.logDB(LogLevel.INFO, this, "ROLLBACK", "Transaction ROLLBACKED.", null);
 			}
 		}catch(SQLException se){
 			supportsTransaction = false;
-			logger.logDB(LogLevel.ERROR, this, "ROLLBACK", "Transaction ROLLBACK impossible!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "ROLLBACK", "Transaction ROLLBACK impossible!", se);
 		}
 	}
 
@@ -1929,11 +2028,13 @@ public class JDBCConnection implements DBConnection {
 		try{
 			if (supportsTransaction){
 				connection.setAutoCommit(true);
-				logger.logDB(LogLevel.INFO, this, "END_TRANSACTION", "Transaction ENDED.", null);
+				if (logger != null)
+					logger.logDB(LogLevel.INFO, this, "END_TRANSACTION", "Transaction ENDED.", null);
 			}
 		}catch(SQLException se){
 			supportsTransaction = false;
-			logger.logDB(LogLevel.ERROR, this, "END_TRANSACTION", "Transaction ENDing impossible!", se);
+			if (logger != null)
+				logger.logDB(LogLevel.ERROR, this, "END_TRANSACTION", "Transaction ENDing impossible!", se);
 		}
 	}
 
@@ -1954,7 +2055,8 @@ public class JDBCConnection implements DBConnection {
 			if (rs != null)
 				rs.close();
 		}catch(SQLException se){
-			logger.logDB(LogLevel.WARNING, this, "CLOSE", "Can not close a ResultSet!", null);
+			if (logger != null)
+				logger.logDB(LogLevel.WARNING, this, "CLOSE", "Can not close a ResultSet!", null);
 		}
 	}
 
@@ -1975,7 +2077,8 @@ public class JDBCConnection implements DBConnection {
 			if (stmt != null)
 				stmt.close();
 		}catch(SQLException se){
-			logger.logDB(LogLevel.WARNING, this, "CLOSE", "Can not close a Statement!", null);
+			if (logger != null)
+				logger.logDB(LogLevel.WARNING, this, "CLOSE", "Can not close a Statement!", null);
 		}
 	}
 
@@ -2180,7 +2283,8 @@ public class JDBCConnection implements DBConnection {
 			}
 
 			if (cnt > 1){
-				logger.logDB(LogLevel.ERROR, this, "TABLE_EXIST", "More than one table match to these criteria (schema=" + schemaName + " (case sensitive?" + schemaCaseSensitive + ") && table=" + tableName + " (case sensitive?" + tableCaseSensitive + "))!", null);
+				if (logger != null)
+					logger.logDB(LogLevel.ERROR, this, "TABLE_EXIST", "More than one table match to these criteria (schema=" + schemaName + " (case sensitive?" + schemaCaseSensitive + ") && table=" + tableName + " (case sensitive?" + tableCaseSensitive + "))!", null);
 				throw new DBException("More than one table match to these criteria (schema=" + schemaName + " (case sensitive?" + schemaCaseSensitive + ") && table=" + tableName + " (case sensitive?" + tableCaseSensitive + "))!");
 			}
 
@@ -2291,10 +2395,12 @@ public class JDBCConnection implements DBConnection {
 				 * Otherwise, it is impossible to insert the previous batched rows ; an exception must be thrown
 				 * and must stop the whole TAP_SCHEMA initialization.
 				 */
-				if (indRow == 1)
-					logger.logDB(LogLevel.WARNING, this, "EXEC_UPDATE", "BATCH query impossible => TRYING AGAIN IN A NORMAL EXECUTION (executeUpdate())!", se);
-				else{
-					logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "BATCH query impossible!", se);
+				if (indRow == 1){
+					if (logger != null)
+						logger.logDB(LogLevel.WARNING, this, "EXEC_UPDATE", "BATCH query impossible => TRYING AGAIN IN A NORMAL EXECUTION (executeUpdate())!", se);
+				}else{
+					if (logger != null)
+						logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "BATCH query impossible!", se);
 					throw new DBException("BATCH query impossible!", se);
 				}
 			}
@@ -2308,7 +2414,8 @@ public class JDBCConnection implements DBConnection {
 
 			// Check the row has been inserted with success:
 			if (nbRowsWritten != 1){
-				logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "ROW " + indRow + " not inserted!", null);
+				if (logger != null)
+					logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "ROW " + indRow + " not inserted!", null);
 				throw new DBException("ROW " + indRow + " not inserted!");
 			}
 		}
@@ -2346,7 +2453,8 @@ public class JDBCConnection implements DBConnection {
 				rows = stmt.executeBatch();
 			}catch(SQLException se){
 				supportsBatchUpdates = false;
-				logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "BATCH execution impossible!", se);
+				if (logger != null)
+					logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "BATCH execution impossible!", se);
 				throw new DBException("BATCH execution impossible!", se);
 			}
 
@@ -2354,7 +2462,8 @@ public class JDBCConnection implements DBConnection {
 			try{
 				stmt.clearBatch();
 			}catch(SQLException se){
-				logger.logDB(LogLevel.WARNING, this, "EXEC_UPDATE", "CLEAR BATCH impossible!", se);
+				if (logger != null)
+					logger.logDB(LogLevel.WARNING, this, "EXEC_UPDATE", "CLEAR BATCH impossible!", se);
 			}
 
 			// Count the updated rows:
@@ -2364,7 +2473,8 @@ public class JDBCConnection implements DBConnection {
 
 			// Check all given rows have been inserted with success:
 			if (nbRowsUpdated != nbRows){
-				logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "ROWS not all update (" + nbRows + " to update ; " + nbRowsUpdated + " updated)!", null);
+				if (logger != null)
+					logger.logDB(LogLevel.ERROR, this, "EXEC_UPDATE", "ROWS not all update (" + nbRows + " to update ; " + nbRowsUpdated + " updated)!", null);
 				throw new DBException("ROWS not all updated (" + nbRows + " to update ; " + nbRowsUpdated + " updated)!");
 			}
 		}
diff --git a/src/tap/formatter/VOTableFormat.java b/src/tap/formatter/VOTableFormat.java
index 7ce1f63abe5fc1bed42e3ffe77db86dad6000c97..d039e630d3e3a2b3bb0d48d98ab414c99cb2ca48 100644
--- a/src/tap/formatter/VOTableFormat.java
+++ b/src/tap/formatter/VOTableFormat.java
@@ -384,7 +384,10 @@ public class VOTableFormat implements OutputFormat {
 			if (logFormatReport)
 				service.getLogger().logTAP(LogLevel.INFO, execReport, "FORMAT", "Result formatted (in VOTable ; " + table.getNbReadRows() + " rows ; " + table.getColumnCount() + " columns) in " + (System.currentTimeMillis() - start) + "ms!", null);
 		}catch(IOException ioe){
-			throw new TAPException("Error while writing a query result in VOTable!", ioe);
+			if (ioe.getCause() != null && ioe.getCause() instanceof DataReadException)
+				throw (DataReadException)ioe.getCause();
+			else
+				throw new TAPException("Error while writing a query result in VOTable!", ioe);
 		}
 	}
 
@@ -432,7 +435,7 @@ public class VOTableFormat implements OutputFormat {
 		 * 	2/ a GROUP item with the STC expression of the coordinate system. 
 		 */
 
-		out.flush();
+		//out.flush();  // TODO DEBUG flush() => commit
 	}
 
 	/**
diff --git a/test/adql/translator/TestPgSphereTranslator.java b/test/adql/translator/TestPgSphereTranslator.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f34471fc7be78303a7945fee526c63fb425e71f
--- /dev/null
+++ b/test/adql/translator/TestPgSphereTranslator.java
@@ -0,0 +1,332 @@
+package adql.translator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.Types;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.postgresql.util.PGobject;
+
+import adql.db.DBType;
+import adql.db.DBType.DBDatatype;
+import adql.db.STCS.Region;
+import adql.parser.ParseException;
+
+public class TestPgSphereTranslator {
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws Exception{}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws Exception{}
+
+	@Before
+	public void setUp() throws Exception{}
+
+	@After
+	public void tearDown() throws Exception{}
+
+	@Test
+	public void testConvertTypeFromDB(){
+		PgSphereTranslator translator = new PgSphereTranslator();
+
+		// POINT
+		DBType type = translator.convertTypeFromDB(Types.OTHER, "spoint", "spoint", null);
+		assertNotNull(type);
+		assertEquals(DBDatatype.POINT, type.type);
+		assertEquals(DBType.NO_LENGTH, type.length);
+
+		// CIRCLE
+		type = translator.convertTypeFromDB(Types.OTHER, "scircle", "scircle", null);
+		assertNotNull(type);
+		assertEquals(DBDatatype.REGION, type.type);
+		assertEquals(DBType.NO_LENGTH, type.length);
+
+		// BOX
+		type = translator.convertTypeFromDB(Types.OTHER, "sbox", "sbox", null);
+		assertNotNull(type);
+		assertEquals(DBDatatype.REGION, type.type);
+		assertEquals(DBType.NO_LENGTH, type.length);
+
+		// POLYGON
+		type = translator.convertTypeFromDB(Types.OTHER, "spoly", "spoly", null);
+		assertNotNull(type);
+		assertEquals(DBDatatype.REGION, type.type);
+		assertEquals(DBType.NO_LENGTH, type.length);
+	}
+
+	@Test
+	public void testConvertTypeToDB(){
+		PgSphereTranslator translator = new PgSphereTranslator();
+
+		// NULL
+		assertEquals("VARCHAR", translator.convertTypeToDB(null));
+
+		// POINT
+		assertEquals("spoint", translator.convertTypeToDB(new DBType(DBDatatype.POINT)));
+
+		// REGION (any other region is transformed into a polygon)
+		assertEquals("spoly", translator.convertTypeToDB(new DBType(DBDatatype.REGION)));
+	}
+
+	@Test
+	public void testTranslateGeometryFromDB(){
+		PgSphereTranslator translator = new PgSphereTranslator();
+		PGobject pgo = new PGobject();
+
+		// NULL
+		try{
+			assertNull(translator.translateGeometryFromDB(null));
+		}catch(Throwable t){
+			t.printStackTrace();
+			fail(t.getMessage());
+		}
+
+		// SPOINT
+		try{
+			pgo.setType("spoint");
+			pgo.setValue("(0.1 , 0.2)");
+			Region r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(11.45915, r.coordinates[0][1], 1e-5);
+
+			pgo.setValue("(5.72957d , 11.45915d)");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(11.45915, r.coordinates[0][1], 1e-5);
+
+			pgo.setValue("(  5d 43m 46.480625s , +11d 27m 32.961249s)");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(11.45915, r.coordinates[0][1], 1e-5);
+
+			pgo.setValue("(  0h 22m 55.098708s , +11d 27m 32.961249s)");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(11.45915, r.coordinates[0][1], 1e-5);
+		}catch(Throwable t){
+			t.printStackTrace();
+			fail(t.getMessage());
+		}
+
+		// SCIRCLE
+		try{
+			pgo.setType("scircle");
+			pgo.setValue("<(0.1,-0.2),1>");
+			Region r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(-11.45915, r.coordinates[0][1], 1e-5);
+			assertEquals(57.29577, r.radius, 1e-5);
+
+			pgo.setValue("<(5.72957d , -11.45915d) , 57.29577d>");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(-11.45915, r.coordinates[0][1], 1e-5);
+			assertEquals(57.29577, r.radius, 1e-5);
+
+			pgo.setValue("<(  5d 43m 46.452s , -11d 27m 32.94s) , 57d 17m 44.772s>");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(-11.45915, r.coordinates[0][1], 1e-5);
+			assertEquals(57.29577, r.radius, 1e-5);
+
+			pgo.setValue("<(  0h 22m 55.0968s , -11d 27m 32.94s) , 57d 17m 44.772s>");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(5.72957, r.coordinates[0][0], 1e-5);
+			assertEquals(-11.45915, r.coordinates[0][1], 1e-5);
+			assertEquals(57.29577, r.radius, 1e-5);
+		}catch(Throwable t){
+			t.printStackTrace();
+			fail(t.getMessage());
+		}
+
+		// SBOX
+		try{
+			pgo.setType("sbox");
+			pgo.setValue("((0.1,0.2),(0.5,0.5))");
+			Region r = translator.translateGeometryFromDB(pgo);
+			assertEquals(17.18873, r.coordinates[0][0], 1e-5);
+			assertEquals(20.05352, r.coordinates[0][1], 1e-5);
+			assertEquals(22.91831, r.width, 1e-5);
+			assertEquals(17.18873, r.height, 1e-5);
+
+			pgo.setValue("((5.72957795130823d , 11.4591559026165d), (28.6478897565412d , 28.6478897565412d))");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(17.18873, r.coordinates[0][0], 1e-5);
+			assertEquals(20.05352, r.coordinates[0][1], 1e-5);
+			assertEquals(22.91831, r.width, 1e-5);
+			assertEquals(17.18873, r.height, 1e-5);
+
+			pgo.setValue("((  5d 43m 46.480625s , +11d 27m 32.961249s), ( 28d 38m 52.403124s , +28d 38m 52.403124s))");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(17.18873, r.coordinates[0][0], 1e-5);
+			assertEquals(20.05352, r.coordinates[0][1], 1e-5);
+			assertEquals(22.91831, r.width, 1e-5);
+			assertEquals(17.18873, r.height, 1e-5);
+
+			pgo.setValue("((  0h 22m 55.098708s , +11d 27m 32.961249s), (  1h 54m 35.493542s , +28d 38m 52.403124s))");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(17.18873, r.coordinates[0][0], 1e-5);
+			assertEquals(20.05352, r.coordinates[0][1], 1e-5);
+			assertEquals(22.91831, r.width, 1e-5);
+			assertEquals(17.18873, r.height, 1e-5);
+		}catch(Throwable t){
+			t.printStackTrace();
+			fail(t.getMessage());
+		}
+
+		// SPOLY
+		try{
+			pgo.setType("spoly");
+			pgo.setValue("{(0.789761486527434 , 0.00436332312998582),(0.789761486527434 , 0.00872664625997165),(0.785398163397448 , 0.00872664625997165),(0.785398163397448 , 0.00436332312998582),(0.781034840267463 , 0.00436332312998582),(0.781034840267463 , 0),(0.785398163397448 , 0)}");
+			Region r = translator.translateGeometryFromDB(pgo);
+			assertEquals(45.25, r.coordinates[0][0], 1e-2);
+			assertEquals(0.25, r.coordinates[0][1], 1e-2);
+			assertEquals(45.25, r.coordinates[1][0], 1e-2);
+			assertEquals(0.5, r.coordinates[1][1], 1e-2);
+			assertEquals(45, r.coordinates[2][0], 1e-2);
+			assertEquals(0.5, r.coordinates[2][1], 1e-2);
+			assertEquals(45, r.coordinates[3][0], 1e-2);
+			assertEquals(0.25, r.coordinates[3][1], 1e-2);
+			assertEquals(44.75, r.coordinates[4][0], 1e-2);
+			assertEquals(0.25, r.coordinates[4][1], 1e-2);
+			assertEquals(44.75, r.coordinates[5][0], 1e-2);
+			assertEquals(0, r.coordinates[5][1], 1e-2);
+			assertEquals(45, r.coordinates[6][0], 1e-2);
+			assertEquals(0, r.coordinates[6][1], 1e-2);
+
+			pgo.setValue("{(45.25d , 0.25d), (45.25d , 0.5d), (45d , 0.5d), (45d , 0.25d), (44.75d , 0.25d), (44.75d , 0d), (45d , 0d)}");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(45.25, r.coordinates[0][0], 1e-2);
+			assertEquals(0.25, r.coordinates[0][1], 1e-2);
+			assertEquals(45.25, r.coordinates[1][0], 1e-2);
+			assertEquals(0.5, r.coordinates[1][1], 1e-2);
+			assertEquals(45, r.coordinates[2][0], 1e-2);
+			assertEquals(0.5, r.coordinates[2][1], 1e-2);
+			assertEquals(45, r.coordinates[3][0], 1e-2);
+			assertEquals(0.25, r.coordinates[3][1], 1e-2);
+			assertEquals(44.75, r.coordinates[4][0], 1e-2);
+			assertEquals(0.25, r.coordinates[4][1], 1e-2);
+			assertEquals(44.75, r.coordinates[5][0], 1e-2);
+			assertEquals(0, r.coordinates[5][1], 1e-2);
+			assertEquals(45, r.coordinates[6][0], 1e-2);
+			assertEquals(0, r.coordinates[6][1], 1e-2);
+
+			pgo.setValue("{( 45d 15m 0s , + 0d 15m 0s),( 45d 15m 0s , + 0d 30m 0s),( 45d  0m 0s , + 0d 30m 0s),( 45d  0m 0s , + 0d 15m 0s),( 44d 45m 0s , + 0d 15m 0s),( 44d 45m 0s , + 0d  0m 0s),( 45d  0m 0s , + 0d  0m 0s)}");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(45.25, r.coordinates[0][0], 1e-2);
+			assertEquals(0.25, r.coordinates[0][1], 1e-2);
+			assertEquals(45.25, r.coordinates[1][0], 1e-2);
+			assertEquals(0.5, r.coordinates[1][1], 1e-2);
+			assertEquals(45, r.coordinates[2][0], 1e-2);
+			assertEquals(0.5, r.coordinates[2][1], 1e-2);
+			assertEquals(45, r.coordinates[3][0], 1e-2);
+			assertEquals(0.25, r.coordinates[3][1], 1e-2);
+			assertEquals(44.75, r.coordinates[4][0], 1e-2);
+			assertEquals(0.25, r.coordinates[4][1], 1e-2);
+			assertEquals(44.75, r.coordinates[5][0], 1e-2);
+			assertEquals(0, r.coordinates[5][1], 1e-2);
+			assertEquals(45, r.coordinates[6][0], 1e-2);
+			assertEquals(0, r.coordinates[6][1], 1e-2);
+
+			pgo.setValue("{(  3h  1m 0s , + 0d 15m 0s),(  3h  1m 0s , + 0d 30m 0s),(  3h  0m 0s , + 0d 30m 0s),(  3h  0m 0s , + 0d 15m 0s),(  2h 59m 0s , + 0d 15m 0s),(  2h 59m 0s , + 0d  0m 0s),(  3h  0m 0s , + 0d  0m 0s)}");
+			r = translator.translateGeometryFromDB(pgo);
+			assertEquals(45.25, r.coordinates[0][0], 1e-2);
+			assertEquals(0.25, r.coordinates[0][1], 1e-2);
+			assertEquals(45.25, r.coordinates[1][0], 1e-2);
+			assertEquals(0.5, r.coordinates[1][1], 1e-2);
+			assertEquals(45, r.coordinates[2][0], 1e-2);
+			assertEquals(0.5, r.coordinates[2][1], 1e-2);
+			assertEquals(45, r.coordinates[3][0], 1e-2);
+			assertEquals(0.25, r.coordinates[3][1], 1e-2);
+			assertEquals(44.75, r.coordinates[4][0], 1e-2);
+			assertEquals(0.25, r.coordinates[4][1], 1e-2);
+			assertEquals(44.75, r.coordinates[5][0], 1e-2);
+			assertEquals(0, r.coordinates[5][1], 1e-2);
+			assertEquals(45, r.coordinates[6][0], 1e-2);
+			assertEquals(0, r.coordinates[6][1], 1e-2);
+		}catch(Throwable t){
+			t.printStackTrace();
+			fail(t.getMessage());
+		}
+
+		// OTHER
+		try{
+			translator.translateGeometryFromDB(new Double(12.3));
+			fail("The translation of a Double as a geometry is not supported!");
+		}catch(Throwable t){
+			assertTrue(t instanceof ParseException);
+			assertEquals("Incompatible type! The column value \"12.3\" was supposed to be a geometrical object.", t.getMessage());
+		}
+		try{
+			pgo.setType("sline");
+			pgo.setValue("( -90d, -20d, 200d, XYZ ), 30d ");
+			translator.translateGeometryFromDB(pgo);
+			fail("The translation of a sline is not supported!");
+		}catch(Throwable t){
+			assertTrue(t instanceof ParseException);
+			assertEquals("Unsupported PgSphere type: \"sline\"! Impossible to convert the column value \"( -90d, -20d, 200d, XYZ ), 30d \" into a Region.", t.getMessage());
+		}
+	}
+
+	@Test
+	public void testTranslateGeometryToDB(){
+		PgSphereTranslator translator = new PgSphereTranslator();
+
+		try{
+			// NULL
+			assertNull(translator.translateGeometryToDB(null));
+
+			// POSITION
+			Region r = new Region(null, new double[]{45,0});
+			PGobject pgo = (PGobject)translator.translateGeometryToDB(r);
+			assertNotNull(pgo);
+			assertEquals("spoint", pgo.getType());
+			assertEquals("(45.0d,0.0d)", pgo.getValue());
+
+			// CIRCLE
+			r = new Region(null, new double[]{45,0}, 1.2);
+			pgo = (PGobject)translator.translateGeometryToDB(r);
+			assertNotNull(pgo);
+			assertEquals("spoly", pgo.getType());
+			assertEquals("{(46.2d,0.0d),(46.176942336483876d,0.2341083864193539d),(46.108655439013546d,0.4592201188381077d),(45.99776353476305d,0.6666842796235226d),(45.848528137423855d,0.8485281374238569d),(45.666684279623524d,0.9977635347630542d),(45.45922011883811d,1.1086554390135441d),(45.23410838641935d,1.1769423364838765d),(45.0d,1.2d),(44.76589161358065d,1.1769423364838765d),(44.54077988116189d,1.1086554390135441d),(44.333315720376476d,0.9977635347630543d),(44.151471862576145d,0.848528137423857d),(44.00223646523695d,0.6666842796235226d),(43.891344560986454d,0.4592201188381073d),(43.823057663516124d,0.23410838641935325d),(43.8d,-9.188564877424678E-16d),(43.823057663516124d,-0.23410838641935505d),(43.891344560986454d,-0.45922011883810904d),(44.00223646523695d,-0.6666842796235241d),(44.151471862576145d,-0.8485281374238584d),(44.333315720376476d,-0.9977635347630555d),(44.540779881161896d,-1.108655439013545d),(44.76589161358065d,-1.176942336483877d),(45.0d,-1.2d),(45.23410838641936d,-1.1769423364838758d),(45.45922011883811d,-1.1086554390135428d),(45.666684279623524d,-0.9977635347630521d),(45.84852813742386d,-0.8485281374238541d),(45.99776353476306d,-0.6666842796235192d),(46.108655439013546d,-0.45922011883810354d),(46.176942336483876d,-0.23410838641934922d)}", pgo.getValue());
+
+			// BOX
+			r = new Region(null, new double[]{45,0}, 1.2, 5);
+			pgo = (PGobject)translator.translateGeometryToDB(r);
+			assertNotNull(pgo);
+			assertEquals("spoly", pgo.getType());
+			assertEquals("{(44.4d,-2.5d),(44.4d,2.5d),(45.6d,2.5d),(45.6d,-2.5d)}", pgo.getValue());
+
+			// POLYGON
+			r = new Region(null, new double[][]{new double[]{45.25,0.25},new double[]{45.25,0.5},new double[]{45,0.5},new double[]{45,0.25},new double[]{44.75,0.25},new double[]{44.75,0},new double[]{45,0}});
+			pgo = (PGobject)translator.translateGeometryToDB(r);
+			assertNotNull(pgo);
+			assertEquals("spoly", pgo.getType());
+			assertEquals("{(45.25d,0.25d),(45.25d,0.5d),(45.0d,0.5d),(45.0d,0.25d),(44.75d,0.25d),(44.75d,0.0d),(45.0d,0.0d)}", pgo.getValue());
+
+			// OTHER
+			try{
+				r = new Region(new Region(null, new double[]{45,0}));
+				translator.translateGeometryToDB(r);
+				fail("The translation of a STC Not region is not supported!");
+			}catch(Throwable ex){
+				assertTrue(ex instanceof ParseException);
+				assertEquals("Unsupported geometrical region: \"" + r.type + "\"!", ex.getMessage());
+			}
+
+		}catch(ParseException t){
+			t.printStackTrace();
+			fail(t.getMessage());
+		}
+	}
+
+}
diff --git a/test/tap/db/JDBCConnectionTest.java b/test/tap/db/JDBCConnectionTest.java
index b645e85800bee3eb0f71d0ad592bce7cec49df76..bd43211f3588f1efc4d473db3a4e6413f9aa2a2d 100644
--- a/test/tap/db/JDBCConnectionTest.java
+++ b/test/tap/db/JDBCConnectionTest.java
@@ -176,11 +176,11 @@ public class JDBCConnectionTest {
 
 	@Test
 	public void testGetDBMSDatatype(){
-		assertEquals("VARCHAR", pgJDBCConnection.getDBMSDatatype(null));
-		assertEquals("TEXT", sqliteJDBCConnection.getDBMSDatatype(null));
+		assertEquals("VARCHAR", pgJDBCConnection.defaultTypeConversion(null));
+		assertEquals("TEXT", sqliteJDBCConnection.defaultTypeConversion(null));
 
-		assertEquals("bytea", pgJDBCConnection.getDBMSDatatype(new DBType(DBDatatype.VARBINARY)));
-		assertEquals("BLOB", sqliteJDBCConnection.getDBMSDatatype(new DBType(DBDatatype.VARBINARY)));
+		assertEquals("bytea", pgJDBCConnection.defaultTypeConversion(new DBType(DBDatatype.VARBINARY)));
+		assertEquals("BLOB", sqliteJDBCConnection.defaultTypeConversion(new DBType(DBDatatype.VARBINARY)));
 	}
 
 	@Test
@@ -379,6 +379,19 @@ public class JDBCConnectionTest {
 				for(TAPColumn c : cols)
 					tableDef.addColumn(c);
 
+				// Test with no schema set:
+				try{
+					conn.addUploadedTable(tableDef, it);
+					fail("The table is not inside a TAPSchema, so this test should have failed!");
+				}catch(Exception ex){
+					assertTrue(ex instanceof DBException);
+					assertEquals("Missing upload schema! An uploaded table must be inside a schema whose the ADQL name is strictly equals to \"" + STDSchema.UPLOADSCHEMA.label + "\" (but the DB name may be different).", ex.getMessage());
+				}
+
+				// Specify the UPLOAD schema for the table to upload:
+				TAPSchema schema = new TAPSchema(STDSchema.UPLOADSCHEMA.label);
+				schema.addTable(tableDef);
+
 				// Prepare the test: no TAP_UPLOAD schema and no table TAP_UPLOAD.UploadExample:
 				dropSchema(STDSchema.UPLOADSCHEMA.label, conn);
 				// Test:
diff --git a/test/tap/db/TestTAPDb.db b/test/tap/db/TestTAPDb.db
index 227549965a7b445848f09562dc48441528f00dfd..d722315944c5da861381aede0e50b8951ae85fb2 100644
Binary files a/test/tap/db/TestTAPDb.db and b/test/tap/db/TestTAPDb.db differ