From e4f38c951321c95897069fb26b0ad126a0dc8ed6 Mon Sep 17 00:00:00 2001
From: gmantele <gmantele@ari.uni-heidelberg.de>
Date: Fri, 12 Jan 2018 16:14:12 +0100
Subject: [PATCH] [ADQL] Fix the parsing and translation of a concatenation
 expression.

* The parsing did not allow unsigned numerics and SQL SET functions as
  specified in the ADQL 2.0 grammar

* It was even forbidden to put a column whose the type is not String.

* The translation of a concatenation expression was always prefixed by the
  ADQLList's name: CONCAT_STR. Of course, no database likes that...

Regarding this last point, this commit fixes the GitHub issue #54
---
 src/adql/parser/ADQLParser.java               | 396 ++++++++++--------
 src/adql/parser/adqlGrammar.jj                |  14 +-
 src/adql/translator/JDBCTranslator.java       | 116 +++--
 src/adql/translator/PgSphereTranslator.java   | 101 ++---
 src/adql/translator/PostgreSQLTranslator.java |  40 +-
 test/adql/db/TestDBChecker.java               |  29 +-
 6 files changed, 394 insertions(+), 302 deletions(-)

diff --git a/src/adql/parser/ADQLParser.java b/src/adql/parser/ADQLParser.java
index 7ca0e58..f32d90b 100644
--- a/src/adql/parser/ADQLParser.java
+++ b/src/adql/parser/ADQLParser.java
@@ -53,7 +53,7 @@ import adql.translator.TranslationException;
 
 /**
 * Parses an ADQL query thanks to the {@link ADQLParser#Query()} function.
-* 
+*
 * <p>
 *   This parser is able, thanks to a {@link QueryChecker} object, to check each
 *   {@link ADQLQuery} just after its generation. It could be used to check the
@@ -62,7 +62,7 @@ import adql.translator.TranslationException;
 *   you must extend {@link QueryChecker} to check semantically all generated
 *   ADQLQuery objects.
 * </p>
-* 
+*
 * <p>
 *   To create an object representation of the given ADQL query, this parser uses
 *   a {@link ADQLQueryFactory} object. So if you want customize some object
@@ -71,7 +71,7 @@ import adql.translator.TranslationException;
 *   corresponding function of {@link ADQLQueryFactory}
 *   (ie. createContains(...)).
 * </p>
-* 
+*
 * <p><b><u>WARNING:</u>
 *   To modify this class it's strongly encouraged to modify the .jj file in the
 *   section between <i>PARSER_BEGIN</i> and <i>PARSER_END</i> and to re-compile
@@ -82,7 +82,7 @@ import adql.translator.TranslationException;
 * @see ADQLQueryFactory
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
-* @version 1.4 (09/2017)
+* @version 1.4 (01/2018)
 */
 public class ADQLParser implements ADQLParserConstants {
 
@@ -320,7 +320,7 @@ public class ADQLParser implements ADQLParserConstants {
 	* <i>ReInit</i> functions.
 	*
 	* @return 	The object representation of the given ADQL query.
-	* 
+	*
 	* @throws ParseException	If there is at least one syntactic error.
 	*
 	* @see ADQLParser#Query()
@@ -339,9 +339,9 @@ public class ADQLParser implements ADQLParserConstants {
 	* Parses the query given in parameter.
 	*
 	* @param q	The ADQL query to parse.
-	* 
+	*
 	* @return	The object representation of the given ADQL query.
-	* 
+	*
 	* @throws ParseException	If there is at least one syntactic error.
 	*
 	* @see ADQLParser#ReInit(java.io.InputStream)
@@ -363,9 +363,9 @@ public class ADQLParser implements ADQLParserConstants {
 	* Parses the query contained in the stream given in parameter.
 	*
 	* @param stream		The stream which contains the ADQL query to parse.
-	* 
+	*
 	* @return	The object representation of the given ADQL query.
-	* 
+	*
 	* @throws ParseException	If there is at least one syntactic error.
 	*
 	* @see ADQLParser#ReInit(java.io.InputStream)
@@ -418,11 +418,11 @@ public class ADQLParser implements ADQLParserConstants {
 	/**
 	* Gets the specified ADQL query and parses the given ADQL query. The SQL
 	* translation is then printed if the syntax is correct.
-	* 
+	*
 	* <p>
 	*     <b>ONLY the syntax is checked: the query is NOT EXECUTED !</b>
 	* </p>
-	* 
+	*
 	* <p>Supplied parameters are:
 	*     <ul>
 	*       <li>[-debug] -url http://...</li>
@@ -432,7 +432,7 @@ public class ADQLParser implements ADQLParserConstants {
 	* </p>
 	*
 	* @param args
-	
+
 	* @throws Exception
 	*/
 	public static final void main(String[] args) throws Exception{
@@ -1847,10 +1847,32 @@ public class ADQLParser implements ADQLParserConstants {
 						}
 						break;
 					}
+					case SCIENTIFIC_NUMBER:
+					case UNSIGNED_FLOAT:
+					case UNSIGNED_INTEGER:{
+						op = UnsignedNumeric();
+						{
+							if ("" != null)
+								return op;
+						}
+						break;
+					}
+					case AVG:
+					case MAX:
+					case MIN:
+					case SUM:
+					case COUNT:{
+						op = SqlFunction();
+						{
+							if ("" != null)
+								return op;
+						}
+						break;
+					}
 					case DELIMITED_IDENTIFIER:
 					case REGULAR_IDENTIFIER:{
 						column = Column();
-						column.setExpectedType('S');
+						column.setExpectedType('*');
 						{
 							if ("" != null)
 								return column;
@@ -1859,7 +1881,7 @@ public class ADQLParser implements ADQLParserConstants {
 					}
 					case LEFT_PAR:{
 						left = jj_consume_token(LEFT_PAR);
-						op = StringExpression();
+						op = ValueExpression();
 						right = jj_consume_token(RIGHT_PAR);
 						WrappedOperand wop = queryFactory.createWrappedOperand(op);
 						wop.setPosition(new TextPosition(left, right));
@@ -2190,9 +2212,17 @@ public class ADQLParser implements ADQLParserConstants {
 					}else{
 						switch((jj_ntk == -1) ? jj_ntk_f() : jj_ntk){
 							case LEFT_PAR:
+							case AVG:
+							case MAX:
+							case MIN:
+							case SUM:
+							case COUNT:
 							case STRING_LITERAL:
 							case DELIMITED_IDENTIFIER:
-							case REGULAR_IDENTIFIER:{
+							case REGULAR_IDENTIFIER:
+							case SCIENTIFIC_NUMBER:
+							case UNSIGNED_FLOAT:
+							case UNSIGNED_INTEGER:{
 								op = StringValueExpressionPrimary();
 								break;
 							}
@@ -3948,7 +3978,7 @@ public class ADQLParser implements ADQLParserConstants {
 		}
 	}
 
-	private boolean jj_3R_126(){
+	private boolean jj_3R_128(){
 		Token xsp;
 		xsp = jj_scanpos;
 		if (jj_scan_token(99)){
@@ -3962,6 +3992,17 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3R_129(){
+		Token xsp;
+		xsp = jj_scanpos;
+		if (jj_3R_135()){
+			jj_scanpos = xsp;
+			if (jj_3R_136())
+				return true;
+		}
+		return false;
+	}
+
 	private boolean jj_3R_113(){
 		if (jj_scan_token(LEFT))
 			return true;
@@ -3982,17 +4023,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_127(){
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_3R_133()){
-			jj_scanpos = xsp;
-			if (jj_3R_134())
-				return true;
-		}
-		return false;
-	}
-
 	private boolean jj_3R_54(){
 		Token xsp;
 		xsp = jj_scanpos;
@@ -4047,6 +4077,12 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3_18(){
+		if (jj_3R_16())
+			return true;
+		return false;
+	}
+
 	private boolean jj_3R_55(){
 		Token xsp;
 		xsp = jj_scanpos;
@@ -4058,12 +4094,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3_18(){
-		if (jj_3R_16())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_35(){
 		Token xsp;
 		xsp = jj_scanpos;
@@ -4161,7 +4191,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_132(){
+	private boolean jj_3R_134(){
 		if (jj_scan_token(COMMA))
 			return true;
 		if (jj_3R_51())
@@ -4208,19 +4238,13 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_22(){
-		if (jj_3R_43())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_120(){
 		if (jj_3R_51())
 			return true;
 		Token xsp;
 		while(true){
 			xsp = jj_scanpos;
-			if (jj_3R_132()){
+			if (jj_3R_134()){
 				jj_scanpos = xsp;
 				break;
 			}
@@ -4228,18 +4252,24 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_148(){
+	private boolean jj_3R_22(){
+		if (jj_3R_43())
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_150(){
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_151())
+		if (jj_3R_153())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_147(){
+	private boolean jj_3R_149(){
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_151())
+		if (jj_3R_153())
 			return true;
 		return false;
 	}
@@ -4254,7 +4284,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_125(){
+	private boolean jj_3R_127(){
 		if (jj_scan_token(DOT))
 			return true;
 		if (jj_3R_14())
@@ -4262,7 +4292,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_124(){
+	private boolean jj_3R_126(){
 		if (jj_scan_token(DOT))
 			return true;
 		if (jj_3R_14())
@@ -4275,10 +4305,10 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_124())
+		if (jj_3R_126())
 			jj_scanpos = xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_125())
+		if (jj_3R_127())
 			jj_scanpos = xsp;
 		return false;
 	}
@@ -4289,14 +4319,14 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_30(){
-		if (jj_scan_token(REGULAR_IDENTIFIER))
+	private boolean jj_3R_133(){
+		if (jj_3R_21())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_131(){
-		if (jj_3R_21())
+	private boolean jj_3R_30(){
+		if (jj_scan_token(REGULAR_IDENTIFIER))
 			return true;
 		return false;
 	}
@@ -4315,7 +4345,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_139(){
+	private boolean jj_3R_141(){
 		if (jj_3R_112())
 			return true;
 		return false;
@@ -4332,7 +4362,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_130(){
+	private boolean jj_3R_132(){
 		if (jj_3R_22())
 			return true;
 		return false;
@@ -4341,9 +4371,9 @@ public class ADQLParser implements ADQLParserConstants {
 	private boolean jj_3R_119(){
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_130()){
+		if (jj_3R_132()){
 			jj_scanpos = xsp;
-			if (jj_3R_131())
+			if (jj_3R_133())
 				return true;
 		}
 		return false;
@@ -4373,12 +4403,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_58(){
-		if (jj_3R_78())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_104(){
 		if (jj_scan_token(COT))
 			return true;
@@ -4391,6 +4415,12 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3R_58(){
+		if (jj_3R_78())
+			return true;
+		return false;
+	}
+
 	private boolean jj_3_13(){
 		if (jj_3R_26())
 			return true;
@@ -4525,7 +4555,7 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_148())
+		if (jj_3R_150())
 			jj_scanpos = xsp;
 		if (jj_scan_token(RIGHT_PAR))
 			return true;
@@ -4553,7 +4583,7 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_147())
+		if (jj_3R_149())
 			jj_scanpos = xsp;
 		if (jj_scan_token(RIGHT_PAR))
 			return true;
@@ -4567,7 +4597,7 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_139())
+		if (jj_3R_141())
 			jj_scanpos = xsp;
 		if (jj_scan_token(RIGHT_PAR))
 			return true;
@@ -4808,14 +4838,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_32(){
-		if (jj_3R_14())
-			return true;
-		if (jj_scan_token(DOT))
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_47(){
 		if (jj_3R_63())
 			return true;
@@ -4839,6 +4861,14 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3R_32(){
+		if (jj_3R_14())
+			return true;
+		if (jj_scan_token(DOT))
+			return true;
+		return false;
+	}
+
 	private boolean jj_3_12(){
 		if (jj_3R_25())
 			return true;
@@ -4868,7 +4898,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_135(){
+	private boolean jj_3R_137(){
 		Token xsp;
 		xsp = jj_scanpos;
 		if (jj_scan_token(11)){
@@ -4876,7 +4906,7 @@ public class ADQLParser implements ADQLParserConstants {
 			if (jj_scan_token(12))
 				return true;
 		}
-		if (jj_3R_128())
+		if (jj_3R_130())
 			return true;
 		return false;
 	}
@@ -4907,27 +4937,27 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_143(){
+	private boolean jj_3R_145(){
 		if (jj_3R_22())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_141(){
+	private boolean jj_3R_143(){
 		if (jj_3R_22())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_138(){
+	private boolean jj_3R_140(){
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_137())
+		if (jj_3R_139())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_129(){
+	private boolean jj_3R_131(){
 		Token xsp;
 		xsp = jj_scanpos;
 		if (jj_scan_token(9)){
@@ -4945,23 +4975,23 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		if (jj_scan_token(LEFT_PAR))
 			return true;
-		if (jj_3R_136())
+		if (jj_3R_138())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_137())
+		if (jj_3R_139())
 			return true;
 		if (jj_scan_token(RIGHT_PAR))
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_128(){
+	private boolean jj_3R_130(){
 		if (jj_3R_24())
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_135())
+		if (jj_3R_137())
 			jj_scanpos = xsp;
 		return false;
 	}
@@ -4978,20 +5008,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3_1(){
-		if (jj_3R_14())
-			return true;
-		if (jj_scan_token(DOT))
-			return true;
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_3R_15())
-			jj_scanpos = xsp;
-		if (jj_scan_token(ASTERISK))
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_19(){
 		if (jj_3R_24())
 			return true;
@@ -5011,6 +5027,20 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3_1(){
+		if (jj_3R_14())
+			return true;
+		if (jj_scan_token(DOT))
+			return true;
+		Token xsp;
+		xsp = jj_scanpos;
+		if (jj_3R_15())
+			jj_scanpos = xsp;
+		if (jj_scan_token(ASTERISK))
+			return true;
+		return false;
+	}
+
 	private boolean jj_3R_20(){
 		if (jj_3R_36())
 			return true;
@@ -5024,24 +5054,24 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		if (jj_scan_token(LEFT_PAR))
 			return true;
-		if (jj_3R_136())
+		if (jj_3R_138())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_137())
+		if (jj_3R_139())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_137())
+		if (jj_3R_139())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_137())
+		if (jj_3R_139())
 			return true;
 		Token xsp;
 		while(true){
 			xsp = jj_scanpos;
-			if (jj_3R_138()){
+			if (jj_3R_140()){
 				jj_scanpos = xsp;
 				break;
 			}
@@ -5070,11 +5100,11 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	private boolean jj_3R_112(){
-		if (jj_3R_128())
+		if (jj_3R_130())
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_129())
+		if (jj_3R_131())
 			jj_scanpos = xsp;
 		return false;
 	}
@@ -5104,11 +5134,11 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		if (jj_scan_token(LEFT_PAR))
 			return true;
-		if (jj_3R_136())
+		if (jj_3R_138())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_137())
+		if (jj_3R_139())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
@@ -5209,11 +5239,11 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		if (jj_scan_token(LEFT_PAR))
 			return true;
-		if (jj_3R_136())
+		if (jj_3R_138())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
-		if (jj_3R_137())
+		if (jj_3R_139())
 			return true;
 		if (jj_scan_token(COMMA))
 			return true;
@@ -5234,48 +5264,40 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_53(){
-		if (jj_scan_token(SELECT))
+	private boolean jj_3R_66(){
+		if (jj_3R_112())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_66(){
-		if (jj_3R_112())
+	private boolean jj_3R_152(){
+		if (jj_3R_22())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_150(){
-		if (jj_3R_22())
+	private boolean jj_3R_53(){
+		if (jj_scan_token(SELECT))
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_123(){
+	private boolean jj_3R_125(){
 		if (jj_scan_token(LEFT_PAR))
 			return true;
-		if (jj_3R_29())
+		if (jj_3R_51())
 			return true;
 		if (jj_scan_token(RIGHT_PAR))
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_142(){
+	private boolean jj_3R_144(){
 		if (jj_3R_59())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_16(){
-		if (jj_scan_token(LEFT_PAR))
-			return true;
-		if (jj_3R_33())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_21(){
 		Token xsp;
 		xsp = jj_scanpos;
@@ -5299,19 +5321,19 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_146(){
+	private boolean jj_3R_148(){
 		if (jj_3R_51())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_140(){
+	private boolean jj_3R_142(){
 		if (jj_3R_59())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_122(){
+	private boolean jj_3R_124(){
 		if (jj_3R_22())
 			return true;
 		return false;
@@ -5349,36 +5371,62 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_145(){
+	private boolean jj_3R_147(){
 		if (jj_3R_22())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_121(){
-		if (jj_3R_23())
+	private boolean jj_3R_123(){
+		if (jj_3R_129())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_149(){
+	private boolean jj_3R_151(){
 		if (jj_3R_59())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_136(){
+	private boolean jj_3R_16(){
+		if (jj_scan_token(LEFT_PAR))
+			return true;
+		if (jj_3R_33())
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_138(){
 		if (jj_3R_29())
 			return true;
 		return false;
 	}
 
+	private boolean jj_3R_122(){
+		if (jj_3R_128())
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_121(){
+		if (jj_3R_23())
+			return true;
+		return false;
+	}
+
 	private boolean jj_3R_115(){
 		if (jj_scan_token(FULL))
 			return true;
 		return false;
 	}
 
+	private boolean jj_3R_146(){
+		if (jj_3R_59())
+			return true;
+		return false;
+	}
+
 	private boolean jj_3R_83(){
 		if (jj_scan_token(LEFT_PAR))
 			return true;
@@ -5389,14 +5437,8 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_144(){
-		if (jj_3R_59())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_82(){
-		if (jj_3R_127())
+		if (jj_3R_129())
 			return true;
 		return false;
 	}
@@ -5408,8 +5450,14 @@ public class ADQLParser implements ADQLParserConstants {
 			jj_scanpos = xsp;
 			if (jj_3R_122()){
 				jj_scanpos = xsp;
-				if (jj_3R_123())
-					return true;
+				if (jj_3R_123()){
+					jj_scanpos = xsp;
+					if (jj_3R_124()){
+						jj_scanpos = xsp;
+						if (jj_3R_125())
+							return true;
+					}
+				}
 			}
 		}
 		return false;
@@ -5422,13 +5470,7 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	private boolean jj_3R_80(){
-		if (jj_3R_126())
-			return true;
-		return false;
-	}
-
-	private boolean jj_3R_118(){
-		if (jj_scan_token(FULL))
+		if (jj_3R_128())
 			return true;
 		return false;
 	}
@@ -5440,17 +5482,17 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_144()){
+		if (jj_3R_146()){
 			jj_scanpos = xsp;
-			if (jj_3R_145())
+			if (jj_3R_147())
 				return true;
 		}
 		if (jj_scan_token(COMMA))
 			return true;
 		xsp = jj_scanpos;
-		if (jj_3R_149()){
+		if (jj_3R_151()){
 			jj_scanpos = xsp;
-			if (jj_3R_150())
+			if (jj_3R_152())
 				return true;
 		}
 		if (jj_scan_token(RIGHT_PAR))
@@ -5465,9 +5507,9 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_142()){
+		if (jj_3R_144()){
 			jj_scanpos = xsp;
-			if (jj_3R_143())
+			if (jj_3R_145())
 				return true;
 		}
 		if (jj_scan_token(RIGHT_PAR))
@@ -5482,9 +5524,9 @@ public class ADQLParser implements ADQLParserConstants {
 			return true;
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_140()){
+		if (jj_3R_142()){
 			jj_scanpos = xsp;
-			if (jj_3R_141())
+			if (jj_3R_143())
 				return true;
 		}
 		if (jj_scan_token(RIGHT_PAR))
@@ -5504,6 +5546,12 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3R_118(){
+		if (jj_scan_token(FULL))
+			return true;
+		return false;
+	}
+
 	private boolean jj_3R_62(){
 		Token xsp;
 		xsp = jj_scanpos;
@@ -5554,7 +5602,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_152(){
+	private boolean jj_3R_154(){
 		Token xsp;
 		xsp = jj_scanpos;
 		if (jj_scan_token(9)){
@@ -5565,10 +5613,10 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_151(){
+	private boolean jj_3R_153(){
 		Token xsp;
 		xsp = jj_scanpos;
-		if (jj_3R_152())
+		if (jj_3R_154())
 			jj_scanpos = xsp;
 		if (jj_scan_token(UNSIGNED_INTEGER))
 			return true;
@@ -5595,7 +5643,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_137(){
+	private boolean jj_3R_139(){
 		if (jj_3R_112())
 			return true;
 		if (jj_scan_token(COMMA))
@@ -5605,7 +5653,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_134(){
+	private boolean jj_3R_136(){
 		Token xsp;
 		xsp = jj_scanpos;
 		if (jj_scan_token(49)){
@@ -5631,13 +5679,7 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_117(){
-		if (jj_scan_token(RIGHT))
-			return true;
-		return false;
-	}
-
-	private boolean jj_3R_133(){
+	private boolean jj_3R_135(){
 		if (jj_scan_token(COUNT))
 			return true;
 		if (jj_scan_token(LEFT_PAR))
@@ -5649,7 +5691,7 @@ public class ADQLParser implements ADQLParserConstants {
 		xsp = jj_scanpos;
 		if (jj_scan_token(11)){
 			jj_scanpos = xsp;
-			if (jj_3R_146())
+			if (jj_3R_148())
 				return true;
 		}
 		if (jj_scan_token(RIGHT_PAR))
@@ -5657,6 +5699,12 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3R_117(){
+		if (jj_scan_token(RIGHT))
+			return true;
+		return false;
+	}
+
 	/** Generated Token Manager. */
 	public ADQLParserTokenManager token_source;
 	SimpleCharStream jj_input_stream;
@@ -5685,7 +5733,7 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	private static void jj_la1_init_1(){
-		jj_la1_1 = new int[]{0x0,0x2,0x1000,0x2000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000,0x18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x0,0x0,0x0,0xfc00000,0x10,0xc,0xc,0x10,0x0,0x10,0x10,0x0,0x210,0x400,0xfffe0000,0x0,0x10,0x10,0x0,0x0,0x0,0xfffe0000,0x1e0000,0x0,0x3e0000,0x30000000,0x2000000,0x2000000,0x2000000,0x2000000,0xf0000000,0x0,0xfc00000,0xf0000000,0xf03e0000,0x0,0x0,0x0,0x0,0x0,0xfffe0000,};
+		jj_la1_1 = new int[]{0x0,0x2,0x1000,0x2000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000,0x18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x3e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,0x0,0x0,0x3e0000,0xfc00000,0x10,0xc,0xc,0x10,0x0,0x10,0x10,0x0,0x210,0x400,0xfffe0000,0x0,0x10,0x10,0x0,0x0,0x0,0xfffe0000,0x1e0000,0x0,0x3e0000,0x30000000,0x2000000,0x2000000,0x2000000,0x2000000,0xf0000000,0x0,0xfc00000,0xf0000000,0xf03e0000,0x0,0x0,0x0,0x0,0x0,0xfffe0000,};
 	}
 
 	private static void jj_la1_init_2(){
@@ -5693,7 +5741,7 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	private static void jj_la1_init_3(){
-		jj_la1_3 = new int[]{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x3,0x0,0x3,0x0,0x3b,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x23,0x0,0x0,0x0,0x3,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38,0x30,0x0,0x0,0x3b,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x3,0x3,0x3,0x3,0x0,0x0,0x0,0x2,0x3b,0x0,0x0,0x0,0x0,0x0,0x3b,};
+		jj_la1_3 = new int[]{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x3,0x0,0x3,0x0,0x3b,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x23,0x0,0x0,0x0,0x3,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38,0x30,0x0,0x0,0x3b,0x3b,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x3b,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x3b,0x0,0x0,0x0,0x0,0x3,0x3,0x3,0x3,0x0,0x0,0x0,0x2,0x3b,0x0,0x0,0x0,0x0,0x0,0x3b,};
 	}
 
 	final private JJCalls[] jj_2_rtns = new JJCalls[18];
diff --git a/src/adql/parser/adqlGrammar.jj b/src/adql/parser/adqlGrammar.jj
index 7e41e7a..72bd887 100644
--- a/src/adql/parser/adqlGrammar.jj
+++ b/src/adql/parser/adqlGrammar.jj
@@ -14,7 +14,7 @@
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  * 
- * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2018 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institute (ARI)
  */
 
@@ -31,7 +31,7 @@
 * printed else it will be the message "Correct syntax".
 *
 *  Author:  Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
-*  Version: 1.4 (09/2017)
+*  Version: 1.4 (01/2018)
 */
 
 							/* ########### */
@@ -109,7 +109,7 @@ import adql.translator.TranslationException;
 * @see ADQLQueryFactory
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
-* @version 1.4 (09/2017)
+* @version 1.4 (01/2018)
 */
 public class ADQLParser {
 	
@@ -1191,10 +1191,14 @@ ADQLOperand StringValueExpressionPrimary(): {StringConstant expr; ADQLColumn col
 	try{
 		(// string
 		  expr=String() {return expr;}
+		// unsigned numeric
+		| op=UnsignedNumeric() {return op;}
+		// set_function_specification
+		| op=SqlFunction() {return op;}
 		// column_reference
-		| column=Column() {column.setExpectedType('S'); return column;}
+		| column=Column() {column.setExpectedType('*'); return column;}
 		// LEFT_PAR value_expression RIGHT_PAR
-		| (left=<LEFT_PAR> (op=StringExpression()) right=<RIGHT_PAR>) { WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); return wop; })
+		| (left=<LEFT_PAR> (op=ValueExpression()) right=<RIGHT_PAR>) { WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); return wop; })
 	}catch(Exception ex){
 		throw generateParseException(ex);
 	}
diff --git a/src/adql/translator/JDBCTranslator.java b/src/adql/translator/JDBCTranslator.java
index 063299f..b78a757 100644
--- a/src/adql/translator/JDBCTranslator.java
+++ b/src/adql/translator/JDBCTranslator.java
@@ -16,7 +16,7 @@ package adql.translator;
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  *
- * Copyright 2017 - Astronomisches Rechen Institut (ARI)
+ * Copyright 2017-2018 - Astronomisches Rechen Institut (ARI)
  */
 
 import java.util.Iterator;
@@ -78,55 +78,47 @@ import adql.query.operand.function.geometry.PolygonFunction;
 import adql.query.operand.function.geometry.RegionFunction;
 
 /**
- * <p>Implementation of {@link ADQLTranslator} which translates ADQL queries in SQL queries.</p>
+ * Implementation of {@link ADQLTranslator} which translates ADQL queries in
+ * SQL queries.
  *
  * <p>
- * 	It is already able to translate all SQL standard features, but lets abstract the translation of all
- * 	geometrical functions. So, this translator must be extended as {@link PostgreSQLTranslator} and
- * 	{@link PgSphereTranslator} are doing.
+ * 	It is already able to translate all SQL standard features, but lets abstract
+ * 	the translation of all geometrical functions. So, this translator must be
+ * 	extended as {@link PostgreSQLTranslator}, {@link PgSphereTranslator},
+ * 	{@link MySQLTranslator} and {@link SQLServerTranslator} are doing.
  * </p>
  *
  * <p><i>Note:
- * 	Its default implementation of the SQL syntax has been inspired by the PostgreSQL one.
- * 	However, it should work also with SQLite and MySQL, but some translations might be needed
- * 	(as it is has been done for PostgreSQL about the mathematical functions).
+ * 	Its default implementation of the SQL syntax has been inspired by the
+ * 	PostgreSQL one. However, it should work also with other DBMS, although some
+ * 	translations might be needed (as it is has been done for PostgreSQL about
+ * 	the mathematical functions).
  * </i></p>
  *
- * <h3>PostgreSQLTranslator and PgSphereTranslator</h3>
- *
- * <p>
- * 	{@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>
- * 	{@link PostgreSQLTranslator} overwrites the translation of mathematical functions whose some have
- * 	a different name or signature. Besides, it is also implementing the translation of the geometrical
- * 	functions. However, it does not really translate them. It is just returning the ADQL expression
- * 	(by calling {@link #getDefaultADQLFunction(ADQLFunction)}).
- * 	And so, of course, the execution of a SQL query containing geometrical functions and translated
- * 	using this translator will not work. It is just a default implementation in case there is no interest
- * 	of these geometrical functions.
- * </p>
- *
  * <h3>SQL with or without case sensitivity?</h3>
  *
  * <p>
- * 	In ADQL and in SQL, it is possible to tell the parser to respect the exact case or not of an identifier (schema, table or column name)
- * 	by surrounding it with double quotes. However ADQL identifiers and SQL ones may be different. In that way, the case sensitivity specified
- * 	in ADQL on the different identifiers can not be kept in SQL. That's why this translator lets specify a general rule on which types of
- * 	SQL identifier must be double quoted. This can be done by implementing the abstract function {@link #isCaseSensitive(IdentifierField)}.
- * 	The functions translating column and table names will call this function in order to surround the identifiers by double quotes or not.
- * 	So, <b>be careful if you want to override the functions translating columns and tables!</b>
+ * 	In ADQL and in SQL, it is possible to tell the parser to respect the exact
+ * 	case or not of an identifier (schema, table or column name) by surrounding
+ * 	it with double quotes. However ADQL identifiers and SQL ones may be
+ * 	different. In that way, the case sensitivity specified in ADQL on the
+ * 	different identifiers can not be kept in SQL. That's why this translator
+ * 	lets specify a general rule on which types of SQL identifier must be double
+ * 	quoted. This can be done by implementing the abstract function
+ * 	{@link #isCaseSensitive(IdentifierField)}. The functions translating column
+ * 	and table names will call this function in order to surround the identifiers
+ * 	by double quotes or not. So, <b>be careful if you want to override the
+ * 	functions translating columns and tables!</b>
  * </p>
  *
  * <h3>Translation of "SELECT TOP"</h3>
  *
  * <p>
- * 	The default behavior of this translator is to translate the ADQL "TOP" into the SQL "LIMIT" at the end of the query.
- * 	This is ok for some DBMS, but not all. So, if your DBMS does not know the "LIMIT" keyword, you should override the function
- * 	translating the whole query: {@link #translate(ADQLQuery)}. Here is its current implementation:
+ * 	The default behavior of this translator is to translate the ADQL "TOP" into
+ * 	the SQL "LIMIT" at the end of the query. This is ok for some DBMS, but not
+ * 	all. So, if your DBMS does not know the "LIMIT" keyword, you should override
+ * 	the function translating the whole query: {@link #translate(ADQLQuery)}.
+ * 	Here is its current implementation:
  * </p>
  * <pre>
  * 	StringBuffer sql = new StringBuffer(translate(query.getSelect()));
@@ -147,29 +139,35 @@ import adql.query.operand.function.geometry.RegionFunction;
  * <h3>Translation of ADQL functions</h3>
  *
  * <p>
- * 	All ADQL functions are by default not translated. Consequently, the SQL translation is
- * 	actually the ADQL expression. Generally the ADQL expression is generic enough. However some mathematical functions may need
- * 	to be translated differently. For instance {@link PostgreSQLTranslator} is translating differently: LOG, LOG10, RAND and TRUNC.
+ * 	All ADQL functions are by default not translated. Consequently, the SQL
+ * 	translation is actually the ADQL expression. Generally the ADQL expression
+ * 	is generic enough. However some mathematical functions may need to be
+ * 	translated differently. For instance {@link PostgreSQLTranslator} is
+ * 	translating differently: LOG, LOG10, RAND and TRUNC.
  * </p>
  *
  * <p><i>Note:
- * 	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.
+ * 	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>
  *
  * <p>
- * 	The FROM clause is translated into SQL as written in ADQL. There is no differences except the identifiers that are replaced.
- * 	The tables' aliases and their case sensitivity are kept like in ADQL.
+ * 	The FROM clause is translated into SQL as written in ADQL. There is no
+ * 	differences except the identifiers that are replaced. The tables' aliases
+ * 	and their case sensitivity are kept like in ADQL.
  * </p>
  *
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 1.4 (11/2017)
+ * @version 1.4 (01/2018)
  * @since 1.4
  *
  * @see PostgreSQLTranslator
  * @see PgSphereTranslator
+ * @see MySQLTranslator
+ * @see SQLServerTranslator
  */
 public abstract class JDBCTranslator implements ADQLTranslator {
 
@@ -389,6 +387,8 @@ public abstract class JDBCTranslator implements ADQLTranslator {
 			return translate((ClauseSelect)list);
 		else if (list instanceof ClauseConstraints)
 			return translate((ClauseConstraints)list);
+		else if (list instanceof Concatenation)
+			return getDefaultADQLList(list, false);
 		else
 			return getDefaultADQLList(list);
 	}
@@ -396,14 +396,40 @@ public abstract class JDBCTranslator implements ADQLTranslator {
 	/**
 	 * Gets the default SQL output for a list of ADQL objects.
 	 *
+	 * <p><i>Implementation note:</i>
+	 * 	This function just calls {@link #getDefaultADQLList(ADQLList, boolean)}
+	 * 	with the given list in first parameter and <code>true</code> in second
+	 * 	one. In other words, this function always prefixes the list items by
+	 * 	the list name.
+	 * </p>
+	 *
 	 * @param list	List to format into SQL.
 	 *
 	 * @return		The corresponding SQL.
 	 *
 	 * @throws TranslationException If there is an error during the translation.
+	 *
+	 * @see #getDefaultADQLList(ADQLList, boolean)
+	 */
+	protected final String getDefaultADQLList(ADQLList<? extends ADQLObject> list) throws TranslationException{
+		return getDefaultADQLList(list, true);
+	}
+
+	/**
+	 * Gets the default SQL output for a list of ADQL objects.
+	 *
+	 * @param list				List to format into SQL.
+	 * @param withNamePrefix	Prefix the list by its name or not.
+	 *                      	(e.g. 'false' for a Concatenation)
+	 *
+	 * @return	The corresponding SQL.
+	 *
+	 * @throws TranslationException If there is an error during the translation.
+	 *
+	 * @since 1.4
 	 */
-	protected String getDefaultADQLList(ADQLList<? extends ADQLObject> list) throws TranslationException{
-		String sql = (list.getName() == null) ? "" : (list.getName() + " ");
+	protected String getDefaultADQLList(ADQLList<? extends ADQLObject> list, final boolean withNamePrefix) throws TranslationException{
+		String sql = (list.getName() == null || !withNamePrefix) ? "" : (list.getName() + " ");
 
 		for(int i = 0; i < list.size(); i++)
 			sql += ((i == 0) ? "" : (" " + list.getSeparator(i) + " ")) + translate(list.get(i));
diff --git a/src/adql/translator/PgSphereTranslator.java b/src/adql/translator/PgSphereTranslator.java
index 358d79d..afc5a89 100644
--- a/src/adql/translator/PgSphereTranslator.java
+++ b/src/adql/translator/PgSphereTranslator.java
@@ -2,20 +2,20 @@ package adql.translator;
 
 /*
  * This file is part of ADQLLibrary.
- * 
+ *
  * ADQLLibrary is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- * 
+ *
  * ADQLLibrary is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
+ *
  * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
@@ -44,10 +44,13 @@ import adql.query.operand.function.geometry.PointFunction;
 import adql.query.operand.function.geometry.PolygonFunction;
 
 /**
- * <p>Translates all ADQL objects into the SQL adaptation of Postgres+PgSphere.
- * Actually only the geometrical functions are translated in this class.
- * The other functions are managed by {@link PostgreSQLTranslator}.</p>
- * 
+ * Translates all ADQL objects into the SQL adaptation of Postgres+PgSphere.
+ *
+ * <p>
+ * 	Actually only the geometrical functions and types are translated in this
+ * 	class. The other functions are managed by {@link PostgreSQLTranslator}.
+ * </p>
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
  * @version 1.4 (07/2017)
  */
@@ -62,7 +65,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 	/**
 	 * 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.
-	 * 
+	 *
 	 * @see PostgreSQLTranslator#PostgreSQLTranslator()
 	 */
 	public PgSphereTranslator(){
@@ -72,9 +75,9 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 	/**
 	 * Builds a PgSphereTranslator which always translates in SQL all identifiers (schema, table and column) in the specified case sensitivity ;
 	 * in other words, schema, table and column names will all be surrounded or not by double quotes in the SQL translation.
-	 * 
+	 *
 	 * @param allCaseSensitive	<i>true</i> to translate all identifiers in a case sensitive manner (surrounded by double quotes), <i>false</i> for case insensitivity.
-	 * 
+	 *
 	 * @see PostgreSQLTranslator#PostgreSQLTranslator(boolean)
 	 */
 	public PgSphereTranslator(boolean allCaseSensitive){
@@ -83,12 +86,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 	/**
 	 * Builds a PgSphereTranslator which will always translate in SQL identifiers with the defined case sensitivity.
-	 * 
+	 *
 	 * @param catalog	<i>true</i> to translate catalog names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise.
 	 * @param schema	<i>true</i> to translate schema names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise.
 	 * @param table		<i>true</i> to translate table names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise.
 	 * @param column	<i>true</i> to translate column names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise.
-	 * 
+	 *
 	 * @see PostgreSQLTranslator#PostgreSQLTranslator(boolean, boolean, boolean, boolean)
 	 */
 	public PgSphereTranslator(boolean catalog, boolean schema, boolean table, boolean column){
@@ -330,16 +333,16 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 	/**
 	 * <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){
@@ -358,13 +361,13 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 	/**
 	 * <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>
@@ -372,12 +375,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 	 * 	<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
@@ -407,7 +410,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 		/**
 		 * 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
@@ -428,7 +431,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * 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){
@@ -441,7 +444,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 		/**
 		 * 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{
@@ -469,12 +472,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 		/**
 		 * <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{
@@ -504,12 +507,12 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * <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){
@@ -519,9 +522,9 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 		/**
 		 * 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{
@@ -544,11 +547,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * 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{
@@ -564,11 +567,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * 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)
 		 */
@@ -583,11 +586,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * 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{
@@ -610,11 +613,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * 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{
@@ -640,11 +643,11 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * 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{
@@ -676,7 +679,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 
 		/**
 		 * <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>
@@ -684,9 +687,9 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 		 * 	<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{
diff --git a/src/adql/translator/PostgreSQLTranslator.java b/src/adql/translator/PostgreSQLTranslator.java
index e20690d..68d740a 100644
--- a/src/adql/translator/PostgreSQLTranslator.java
+++ b/src/adql/translator/PostgreSQLTranslator.java
@@ -2,20 +2,20 @@ package adql.translator;
 
 /*
  * This file is part of ADQLLibrary.
- * 
+ *
  * ADQLLibrary is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- * 
+ *
  * ADQLLibrary is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
+ *
  * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
@@ -26,6 +26,7 @@ import adql.db.STCS.Region;
 import adql.parser.ParseException;
 import adql.query.IdentifierField;
 import adql.query.operand.StringConstant;
+import adql.query.operand.function.ADQLFunction;
 import adql.query.operand.function.MathFunction;
 import adql.query.operand.function.geometry.AreaFunction;
 import adql.query.operand.function.geometry.BoxFunction;
@@ -41,23 +42,36 @@ import adql.query.operand.function.geometry.PolygonFunction;
 import adql.query.operand.function.geometry.RegionFunction;
 
 /**
- * <p>Translates all ADQL objects into an SQL interrogation query designed for PostgreSQL.</p>
- * 
+ * Translates all ADQL objects into an SQL interrogation query designed for
+ * PostgreSQL.
+ *
+ * <p>
+ * 	It overwrites the translation of mathematical functions whose some have
+ * 	a different name or signature. Besides, it is also implementing the
+ * 	translation of the geometrical functions. However, it does not really
+ * 	translate them. It is just returning the ADQL expression (by calling
+ * 	{@link #getDefaultADQLFunction(ADQLFunction)}). And so, of course, the
+ * 	execution of a SQL query containing geometrical functions and translated
+ * 	using this translator will not work. It is just a default implementation in
+ * 	case there is no interest of these geometrical functions.
+ * </p>
+ *
  * <p><i><b>Important</b>:
  * 	The geometrical functions are translated exactly as in ADQL.
- * 	You will probably need to extend this translator to correctly manage the geometrical functions.
- * 	An extension is already available for PgSphere: {@link PgSphereTranslator}.
+ * 	You will probably need to extend this translator to correctly manage the
+ * 	geometrical functions. An extension is already available for PgSphere:
+ * 	{@link PgSphereTranslator}.
  * </i></p>
- * 
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
  * @version 1.4 (08/2016)
- * 
+ *
  * @see PgSphereTranslator
  */
 public class PostgreSQLTranslator extends JDBCTranslator {
 
 	/** <p>Indicate the case sensitivity to apply to each SQL identifier (only SCHEMA, TABLE and COLUMN).</p>
-	 * 
+	 *
 	 * <p><i>Note:
 	 * 	In this implementation, this field is set by the constructor and never modified elsewhere.
 	 * 	It would be better to never modify it after the construction in order to keep a certain consistency.
@@ -76,7 +90,7 @@ public class PostgreSQLTranslator extends JDBCTranslator {
 	/**
 	 * Builds a PostgreSQLTranslator which always translates in SQL all identifiers (schema, table and column) in the specified case sensitivity ;
 	 * in other words, schema, table and column names will all be surrounded or not by double quotes in the SQL translation.
-	 * 
+	 *
 	 * @param allCaseSensitive	<i>true</i> to translate all identifiers in a case sensitive manner (surrounded by double quotes), <i>false</i> for case insensitivity.
 	 */
 	public PostgreSQLTranslator(final boolean allCaseSensitive){
@@ -85,7 +99,7 @@ public class PostgreSQLTranslator extends JDBCTranslator {
 
 	/**
 	 * Builds a PostgreSQLTranslator which will always translate in SQL identifiers with the defined case sensitivity.
-	 * 
+	 *
 	 * @param catalog	<i>true</i> to translate catalog names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise.
 	 * @param schema	<i>true</i> to translate schema names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise.
 	 * @param table		<i>true</i> to translate table names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise.
diff --git a/test/adql/db/TestDBChecker.java b/test/adql/db/TestDBChecker.java
index 685eaaf..3e675ae 100644
--- a/test/adql/db/TestDBChecker.java
+++ b/test/adql/db/TestDBChecker.java
@@ -101,7 +101,7 @@ public class TestDBChecker {
 		/* The name of an ADQLClause is got in DBChecker by SearchColumnOutsideGroupByHandler.goInto(...)
 		 * and possibly in other locations in the future. If this name is NULL, no NullPointerException
 		 * should be thrown.
-		 * 
+		 *
 		 * This issue can be tested by creating a ConstraintsGroup (i.e. in a constraints location like WHERE or JOIN...ON,
 		 * a constraint (or more) between parenthesis). */
 		ADQLParser parser = new ADQLParser(new DBChecker(tables, new ArrayList<FunctionDef>(0)));
@@ -212,6 +212,9 @@ public class TestDBChecker {
 			assertNotNull(parser.parseQuery("SELECT toto FROM foo;"));
 			assertNotNull(parser.parseQuery("SELECT toto * 3 FROM foo;"));
 			assertNotNull(parser.parseQuery("SELECT toto || 'blabla' FROM foo;"));
+			assertNotNull(parser.parseQuery("SELECT 'toto' || 1 FROM foo;"));
+			assertNotNull(parser.parseQuery("SELECT 1 || 'toto' FROM foo;"));
+			assertNotNull(parser.parseQuery("SELECT 'toto' || (-1) FROM foo;"));
 		}catch(ParseException pe){
 			pe.printStackTrace();
 			fail();
@@ -221,15 +224,15 @@ public class TestDBChecker {
 			fail();
 		}catch(ParseException pe){}
 		try{
-			parser.parseQuery("SELECT ABS(('toto' || 'blabla')) FROM foo;");
+			parser.parseQuery("SELECT 'toto' || -1 FROM foo;");
 			fail();
 		}catch(ParseException pe){}
 		try{
-			parser.parseQuery("SELECT 'toto' || 1 FROM foo;");
+			parser.parseQuery("SELECT -1 || 'toto' FROM foo;");
 			fail();
 		}catch(ParseException pe){}
 		try{
-			parser.parseQuery("SELECT 1 || 'toto' FROM foo;");
+			parser.parseQuery("SELECT ABS(('toto' || 'blabla')) FROM foo;");
 			fail();
 		}catch(ParseException pe){}
 		try{
@@ -582,22 +585,16 @@ public class TestDBChecker {
 			fail("This query contains a concatenation between 2 strings: this test should have succeeded!");
 		}
 		try{
-			parser.parseQuery("SELECT colI || 'blabla' FROM foo;");
-			fail("This query contains a concatenation between an integer and a string: this test should have failed!");
+			assertNotNull(parser.parseQuery("SELECT colI || 'blabla' FROM foo;"));
 		}catch(ParseException e){
-			assertTrue(e instanceof UnresolvedIdentifiersException);
-			UnresolvedIdentifiersException ex = (UnresolvedIdentifiersException)e;
-			assertEquals(1, ex.getNbErrors());
-			assertEquals("Type mismatch! A string value was expected instead of \"colI\".", ex.getErrors().next().getMessage());
+			e.printStackTrace();
+			fail("This query contains a concatenation between a column (whatever its type) and a string: this test should have succeeded!");
 		}
 		try{
-			parser.parseQuery("SELECT colG || 'blabla' FROM foo;");
-			fail("This query contains a concatenation between a geometry and a string: this test should have failed!");
+			assertNotNull(parser.parseQuery("SELECT colG || 'blabla' FROM foo;"));
 		}catch(ParseException e){
-			assertTrue(e instanceof UnresolvedIdentifiersException);
-			UnresolvedIdentifiersException ex = (UnresolvedIdentifiersException)e;
-			assertEquals(1, ex.getNbErrors());
-			assertEquals("Type mismatch! A string value was expected instead of \"colG\".", ex.getErrors().next().getMessage());
+			e.printStackTrace();
+			fail("This query contains a concatenation between a column (whatever its type) and a string: this test should have succeeded!");
 		}
 
 		// Test the expected type - GEOMETRY - generated by the parser:
-- 
GitLab