From fc38da51053847d3dd5369bb2bf4f84e4e854cc1 Mon Sep 17 00:00:00 2001
From: gmantele <gmantele@ari.uni-heidelberg.de>
Date: Wed, 9 Apr 2014 17:44:27 +0200
Subject: [PATCH] ADQL: Fix an ADQL bug (raised by Dave Morris) in the
 management of subqueries: before, it was impossible to use (in a clause
 different from the FROM) columns of a father query inside a subquery.

---
 src/adql/db/DBChecker.java                  | 133 +++++-
 src/adql/parser/ADQLParser.java             | 473 ++++++++++----------
 src/adql/parser/ADQLParserConstants.java    |   1 -
 src/adql/parser/ADQLParserTokenManager.java |   1 -
 src/adql/parser/QueryChecker.java           |  15 +-
 src/adql/parser/adqlGrammar.jj              |  23 +-
 src/adql/query/ClauseADQL.java              |  10 +-
 7 files changed, 392 insertions(+), 264 deletions(-)

diff --git a/src/adql/db/DBChecker.java b/src/adql/db/DBChecker.java
index 26de9e1..458e9b1 100644
--- a/src/adql/db/DBChecker.java
+++ b/src/adql/db/DBChecker.java
@@ -17,18 +17,21 @@ package adql.db;
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  * 
  * Copyright 2011,2013-2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
- *                       Astronomishes Rechen Institute (ARI)
+ *                            Astronomishes Rechen Institute (ARI)
  */
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Stack;
 
 import adql.db.exception.UnresolvedColumnException;
 import adql.db.exception.UnresolvedIdentifiersException;
 import adql.db.exception.UnresolvedTableException;
 import adql.parser.ParseException;
 import adql.parser.QueryChecker;
+import adql.query.ADQLIterator;
 import adql.query.ADQLObject;
 import adql.query.ADQLQuery;
 import adql.query.ClauseSelect;
@@ -37,6 +40,7 @@ import adql.query.IdentifierField;
 import adql.query.SelectAllColumns;
 import adql.query.SelectItem;
 import adql.query.from.ADQLTable;
+import adql.query.from.FromContent;
 import adql.query.operand.ADQLColumn;
 import adql.search.ISearchHandler;
 import adql.search.SearchColumnHandler;
@@ -60,7 +64,7 @@ import adql.search.SimpleSearchHandler;
  * </i></p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.1 (11/2013)
+ * @version 1.2 (04/2014)
  */
 public class DBChecker implements QueryChecker {
 
@@ -111,6 +115,26 @@ public class DBChecker implements QueryChecker {
 	/* ************* */
 	/* CHECK METHODS */
 	/* ************* */
+	/**
+	 * <p>Check all the columns, tables and UDFs references inside the given query.</p>
+	 * 
+	 * <p><i>
+	 * 	<u>Note:</u> This query has already been parsed ; thus it is already syntactically correct.
+	 * 	Only the consistency with the published tables, columns and all the defined UDFs must be checked.
+	 * </i></p>
+	 * 
+	 * @param query			The query to check.
+	 * @param fatherColumns	List of all columns available in the father query.
+	 * 
+	 * @throws ParseException	An {@link UnresolvedIdentifiersException} if some tables or columns can not be resolved.
+	 * 
+	 * @see #check(ADQLQuery, Stack)
+	 */
+	@Override
+	public void check(final ADQLQuery query) throws ParseException{
+		check(query, null);
+	}
+
 	/**
 	 * Followed algorithm:
 	 * <pre>
@@ -150,17 +174,19 @@ public class DBChecker implements QueryChecker {
 	 * End
 	 * </pre>
 	 * 
-	 * @param query				The query to check.
+	 * @param query			The query to check.
+	 * @param fathersList	List of all columns available in the father query.
 	 * 
-	 * @throws ParseException	An {@link UnresolvedIdentifiersException} if some tables or columns can not be resolved.
+	 * @throws UnresolvedIdentifiersException	An {@link UnresolvedIdentifiersException} if some tables or columns can not be resolved.
+	 * 
+	 * @since 1.2
 	 * 
 	 * @see #resolveTable(ADQLTable)
 	 * @see #generateDBTable(ADQLQuery, String)
 	 * @see #resolveColumn(ADQLColumn, SearchColumnList)
 	 * @see #checkColumnReference(ColumnReference, ClauseSelect, SearchColumnList)
 	 */
-	@Override
-	public void check(final ADQLQuery query) throws ParseException{
+	protected void check(final ADQLQuery query, Stack<SearchColumnList> fathersList) throws UnresolvedIdentifiersException{
 		UnresolvedIdentifiersException errors = new UnresolvedIdentifiersException();
 		HashMap<DBTable,ADQLTable> mapTables = new HashMap<DBTable,ADQLTable>();
 		ISearchHandler sHandler;
@@ -171,15 +197,20 @@ public class DBChecker implements QueryChecker {
 		for(ADQLObject result : sHandler){
 			try{
 				ADQLTable table = (ADQLTable)result;
+
 				// resolve the table:
 				DBTable dbTable = null;
 				if (table.isSubQuery()){
+					// check the subquery tables:
+					check(table.getSubQuery(), fathersList);
+					// generate its DBTable:
 					dbTable = generateDBTable(table.getSubQuery(), table.getAlias());
 				}else{
 					dbTable = resolveTable(table);
 					if (table.hasAlias())
 						dbTable = dbTable.copy(dbTable.getDBName(), table.getAlias());
 				}
+
 				// link with the matched DBTable:
 				table.setDBLink(dbTable);
 				mapTables.put(dbTable, table);
@@ -189,6 +220,10 @@ public class DBChecker implements QueryChecker {
 		}
 
 		// Attach table information on wildcards with the syntax "{tableName}.*" of the SELECT clause:
+		/* Note: no need to check the table name among the father tables, because there is
+		 *       no interest to select a father column in a subquery
+		 *       (which can return only one column ; besides, no aggregate is not allowed
+		 *       in subqueries).*/
 		sHandler = new SearchWildCardHandler();
 		sHandler.search(query.getSelect());
 		for(ADQLObject result : sHandler){
@@ -213,6 +248,7 @@ public class DBChecker implements QueryChecker {
 			}
 		}
 
+		// Get the list of all columns made available in the clause FROM:
 		SearchColumnList list;
 		try{
 			list = query.getFrom().getDBColumns();
@@ -228,7 +264,7 @@ public class DBChecker implements QueryChecker {
 			try{
 				ADQLColumn adqlColumn = (ADQLColumn)result;
 				// resolve the column:
-				DBColumn dbColumn = resolveColumn(adqlColumn, list);
+				DBColumn dbColumn = resolveColumn(adqlColumn, list, fathersList);
 				// link with the matched DBColumn:
 				adqlColumn.setDBLink(dbColumn);
 				adqlColumn.setAdqlTable(mapTables.get(dbColumn.getTable()));
@@ -238,6 +274,8 @@ public class DBChecker implements QueryChecker {
 		}
 
 		// Check the correctness of all column references:
+		/* Note: no need to provide the father tables when resolving column references,
+		 *       because no father column can be used in ORDER BY and/or GROUP BY. */
 		sHandler = new SearchColReferenceHandler();
 		sHandler.search(query);
 		ClauseSelect select = query.getSelect();
@@ -255,6 +293,32 @@ public class DBChecker implements QueryChecker {
 			}
 		}
 
+		// Check subqueries outside the clause FROM:
+		sHandler = new SearchSubQueryHandler();
+		sHandler.search(query);
+		if (sHandler.getNbMatch() > 0){
+
+			// Push the list of columns in the father columns stack:
+			if (fathersList == null)
+				fathersList = new Stack<SearchColumnList>();
+			fathersList.push(list);
+
+			// Check each found subquery (except the first one because it is the current query):
+			for(ADQLObject result : sHandler){
+				try{
+					check((ADQLQuery)result, fathersList);
+				}catch(UnresolvedIdentifiersException uie){
+					Iterator<ParseException> itPe = uie.getErrors();
+					while(itPe.hasNext())
+						errors.addException(itPe.next());
+				}
+			}
+
+			// Pop the list of columns from the father columns stack:
+			fathersList.pop();
+
+		}
+
 		// Throw all errors if any:
 		if (errors.getNbErrors() > 0)
 			throw errors;
@@ -284,17 +348,21 @@ public class DBChecker implements QueryChecker {
 	}
 
 	/**
-	 * Resolves the given column, that's to say searches for the corresponding {@link DBColumn}.
+	 * <p>Resolves the given column, that's to say searches for the corresponding {@link DBColumn}.</p>
+	 * <p>The third parameter is used only if this function is called inside a subquery. In this case,
+	 * column is tried to be resolved with the first list (dbColumns). If no match is found,
+	 * the resolution is tried with the father columns list (fatherColumns).</p>
 	 * 
 	 * @param column		The column to resolve.
 	 * @param dbColumns		List of all available {@link DBColumn}s.
+	 * @param fathersList	List of all columns available in the father query ; a list for each father-level.
 	 * 
-	 * @return				The corresponding {@link DBColumn} if found, <i>null</i> otherwise.
+	 * @return 				The corresponding {@link DBColumn} if found. Otherwise an exception is thrown.
 	 * 
 	 * @throws ParseException	An {@link UnresolvedColumnException} if the given column can't be resolved
 	 * 							or an {@link UnresolvedTableException} if its table reference can't be resolved.
 	 */
-	protected DBColumn resolveColumn(final ADQLColumn column, final SearchColumnList dbColumns) throws ParseException{
+	protected DBColumn resolveColumn(final ADQLColumn column, final SearchColumnList dbColumns, Stack<SearchColumnList> fathersList) throws ParseException{
 		ArrayList<DBColumn> foundColumns = dbColumns.search(column);
 
 		// good if only one column has been found:
@@ -307,8 +375,15 @@ public class DBChecker implements QueryChecker {
 			else
 				throw new UnresolvedTableException(column, (foundColumns.get(0).getTable() == null) ? "<NULL>" : foundColumns.get(0).getTable().getADQLName(), (foundColumns.get(1).getTable() == null) ? "<NULL>" : foundColumns.get(1).getTable().getADQLName());
 		}// otherwise (no match): unknown column !
-		else
-			throw new UnresolvedColumnException(column);
+		else{
+			if (fathersList == null || fathersList.isEmpty())
+				throw new UnresolvedColumnException(column);
+			else{
+				Stack<SearchColumnList> subStack = new Stack<SearchColumnList>();
+				subStack.addAll(fathersList.subList(0, fathersList.size() - 1));
+				return resolveColumn(column, fathersList.peek(), subStack);
+			}
+		}
 	}
 
 	/**
@@ -325,7 +400,7 @@ public class DBChecker implements QueryChecker {
 	 * 							or an {@link UnresolvedTableException} if its table reference can't be resolved.
 	 * 
 	 * @see ClauseSelect#searchByAlias(String)
-	 * @see #resolveColumn(ADQLColumn, SearchColumnList)
+	 * @see #resolveColumn(ADQLColumn, SearchColumnList, SearchColumnList)
 	 */
 	protected DBColumn checkColumnReference(final ColumnReference colRef, final ClauseSelect select, final SearchColumnList dbColumns) throws ParseException{
 		if (colRef.isIndex()){
@@ -352,7 +427,7 @@ public class DBChecker implements QueryChecker {
 			}
 
 			// check the corresponding column:
-			return resolveColumn(col, dbColumns);
+			return resolveColumn(col, dbColumns, null);
 		}
 	}
 
@@ -422,4 +497,34 @@ public class DBChecker implements QueryChecker {
 		}
 	}
 
+	/**
+	 * <p>Lets searching subqueries in every clause except the FROM one (hence the modification of the {@link #goInto(ADQLObject)}.</p>
+	 * 
+	 * <p><i>
+	 * 	<u>Note:</u> The function {@link #addMatch(ADQLObject, ADQLIterator)} has been modified in order to
+	 * 	not have the root search object (here: the main query) in the list of results.
+	 * </i></p>
+	 * 
+	 * @author Gr&eacute;gory Mantelet (ARI)
+	 * @version 1.2 (12/2013)
+	 * @since 1.2
+	 */
+	private static class SearchSubQueryHandler extends SimpleSearchHandler {
+		@Override
+		protected void addMatch(ADQLObject matchObj, ADQLIterator it){
+			if (it != null)
+				super.addMatch(matchObj, it);
+		}
+
+		@Override
+		protected boolean goInto(ADQLObject obj){
+			return super.goInto(obj) && !(obj instanceof FromContent);
+		}
+
+		@Override
+		protected boolean match(ADQLObject obj){
+			return (obj instanceof ADQLQuery);
+		}
+	}
+
 }
diff --git a/src/adql/parser/ADQLParser.java b/src/adql/parser/ADQLParser.java
index cd0c151..e7e2a66 100644
--- a/src/adql/parser/ADQLParser.java
+++ b/src/adql/parser/ADQLParser.java
@@ -1,53 +1,68 @@
 /* Generated By:JavaCC: Do not edit this line. ADQLParser.java */
 package adql.parser;
 
-import java.util.Stack;
-import java.util.Vector;
-import java.util.ArrayList;
-import java.util.Collection;
-
 import java.io.FileReader;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Stack;
+import java.util.Vector;
 
 import adql.db.exception.UnresolvedIdentifiersException;
-
-import adql.parser.IdentifierItems.IdentifierItem;
-
 import adql.parser.ADQLQueryFactory.JoinType;
-
-import adql.query.*;
-import adql.query.from.*;
-import adql.query.constraint.*;
-
-import adql.query.operand.*;
-
-import adql.query.operand.function.*;
-
-import adql.query.operand.function.geometry.*;
+import adql.parser.IdentifierItems.IdentifierItem;
+import adql.query.ADQLOrder;
+import adql.query.ADQLQuery;
+import adql.query.ClauseADQL;
+import adql.query.ClauseConstraints;
+import adql.query.ClauseSelect;
+import adql.query.ColumnReference;
+import adql.query.SelectAllColumns;
+import adql.query.SelectItem;
+import adql.query.TextPosition;
+import adql.query.constraint.ADQLConstraint;
+import adql.query.constraint.Between;
+import adql.query.constraint.Comparison;
+import adql.query.constraint.ComparisonOperator;
+import adql.query.constraint.ConstraintsGroup;
+import adql.query.constraint.In;
+import adql.query.from.ADQLJoin;
+import adql.query.from.FromContent;
+import adql.query.operand.ADQLColumn;
+import adql.query.operand.ADQLOperand;
+import adql.query.operand.Concatenation;
+import adql.query.operand.OperationType;
+import adql.query.operand.StringConstant;
+import adql.query.operand.function.ADQLFunction;
+import adql.query.operand.function.MathFunction;
+import adql.query.operand.function.MathFunctionType;
+import adql.query.operand.function.SQLFunction;
+import adql.query.operand.function.SQLFunctionType;
+import adql.query.operand.function.UserDefinedFunction;
+import adql.query.operand.function.geometry.GeometryFunction;
 import adql.query.operand.function.geometry.GeometryFunction.GeometryValue;
-
+import adql.query.operand.function.geometry.PointFunction;
 import adql.translator.PostgreSQLTranslator;
 import adql.translator.TranslationException;
 
 /**
- * <p>Parses an ADQL query thanks to the {@link ADQLParser#Query()} function. </p>
- * 
- * <p>This parser is able, thanks to a {@link QueryChecker} object, to check each ADQLQuery just after its generation.
- * It could be used to check the consistency between the ADQL query to parse and the "database" on which the query must be executed.
- * By default, there is no {@link QueryChecker}. Thus 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 (ie. CONTAINS) of this representation
- * you just have to extend the corresponding default object (ie. ContainsFunction) and to extend the 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 it with JavaCC.</b></p>
- *
- * @see QueryChecker
- * @see ADQLQueryFactory
- *
- * @author Gr&eacute;gory Mantelet (CDS) - gregory.mantelet@astro.unistra.fr
- * @version January 2012
- */
-@SuppressWarnings("all")
+* <p>Parses an ADQL query thanks to the {@link ADQLParser#Query()} function. </p>
+* 
+* <p>This parser is able, thanks to a {@link QueryChecker} object, to check each ADQLQuery just after its generation.
+* It could be used to check the consistency between the ADQL query to parse and the "database" on which the query must be executed.
+* By default, there is no {@link QueryChecker}. Thus 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 (ie. CONTAINS) of this representation
+* you just have to extend the corresponding default object (ie. ContainsFunction) and to extend the 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 it with JavaCC.</b></p>
+*
+* @see QueryChecker
+* @see ADQLQueryFactory
+*
+* @author Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
+* @version 1.2 (12/2013)
+*/
 public class ADQLParser implements ADQLParserConstants {
 
 	/** Tools to build the object representation of the ADQL query. */
@@ -69,18 +84,18 @@ public class ADQLParser implements ADQLParserConstants {
 	private ArrayList<String> allowedCoordSys = new ArrayList<String>();
 
 	/**
-	 * Builds an ADQL parser without a query to parse.
-	 */
+	* Builds an ADQL parser without a query to parse.
+	*/
 	public ADQLParser(){
 		this(new java.io.ByteArrayInputStream("".getBytes()));
 	}
 
 	/**
-	 * Builds an ADQL parser without a query to parse but with a QueryChecker and a ADQLQueryFactory.
-	 *
-	 * @param checker	The object to use to check each ADQLQuery.
-	 * @param factory	The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds an ADQL parser without a query to parse but with a QueryChecker and a ADQLQueryFactory.
+	*
+	* @param checker	The object to use to check each ADQLQuery.
+	* @param factory	The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(QueryChecker checker, ADQLQueryFactory factory){
 		this();
 
@@ -91,30 +106,30 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	/**
-	 * Builds an ADQL parser without a query to parse but with a QueryChecker.
-	 *
-	 * @param checker	The object to use to check each ADQLQuery.
-	 */
+	* Builds an ADQL parser without a query to parse but with a QueryChecker.
+	*
+	* @param checker	The object to use to check each ADQLQuery.
+	*/
 	public ADQLParser(QueryChecker checker){
 		this(checker, null);
 	}
 
 	/**
-	 * Builds an ADQL parser without a query to parse but with a ADQLQueryFactory.
-	 *
-	 * @param factory	The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds an ADQL parser without a query to parse but with a ADQLQueryFactory.
+	*
+	* @param factory	The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(ADQLQueryFactory factory){
 		this((QueryChecker)null, factory);
 	}
 
 	/**
-	 * Builds a parser with a stream containing the query to parse.
-	 *
-	 * @param stream		The stream in which the ADQL query to parse is given.
-	 * @param checker	The object to use to check each ADQLQuery.
-	 * @param factory	The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with a stream containing the query to parse.
+	*
+	* @param stream		The stream in which the ADQL query to parse is given.
+	* @param checker	The object to use to check each ADQLQuery.
+	* @param factory	The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(java.io.InputStream stream, QueryChecker checker, ADQLQueryFactory factory){
 		this(stream);
 
@@ -125,33 +140,33 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	/**
-	 * Builds a parser with a stream containing the query to parse.
-	 *
-	 * @param stream		The stream in which the ADQL query to parse is given.
-	 * @param checker	The object to use to check each ADQLQuery.
-	 */
+	* Builds a parser with a stream containing the query to parse.
+	*
+	* @param stream		The stream in which the ADQL query to parse is given.
+	* @param checker	The object to use to check each ADQLQuery.
+	*/
 	public ADQLParser(java.io.InputStream stream, QueryChecker checker){
 		this(stream, checker, null);
 	}
 
 	/**
-	 * Builds a parser with a stream containing the query to parse.
-	 *
-	 * @param stream		The stream in which the ADQL query to parse is given.
-	 * @param factory	The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with a stream containing the query to parse.
+	*
+	* @param stream		The stream in which the ADQL query to parse is given.
+	* @param factory	The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(java.io.InputStream stream, ADQLQueryFactory factory){
 		this(stream, (QueryChecker)null, factory);
 	}
 
 	/**
-	 * Builds a parser with a stream containing the query to parse.
-	 *
-	 * @param stream			The stream in which the ADQL query to parse is given.
-	 * @param encoding		The supplied encoding.
-	 * @param checker		The object to use to check each ADQLQuery.
-	 * @param factory		The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with a stream containing the query to parse.
+	*
+	* @param stream			The stream in which the ADQL query to parse is given.
+	* @param encoding		The supplied encoding.
+	* @param checker		The object to use to check each ADQLQuery.
+	* @param factory		The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(java.io.InputStream stream, String encoding, QueryChecker checker, ADQLQueryFactory factory){
 		this(stream, encoding);
 
@@ -162,34 +177,34 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	/**
-	 * Builds a parser with a stream containing the query to parse.
-	 *
-	 * @param stream			The stream in which the ADQL query to parse is given.
-	 * @param encoding		The supplied encoding.
-	 * @param checker		The object to use to check each ADQLQuery.
-	 */
+	* Builds a parser with a stream containing the query to parse.
+	*
+	* @param stream			The stream in which the ADQL query to parse is given.
+	* @param encoding		The supplied encoding.
+	* @param checker		The object to use to check each ADQLQuery.
+	*/
 	public ADQLParser(java.io.InputStream stream, String encoding, QueryChecker checker){
 		this(stream, encoding, checker, null);
 	}
 
 	/**
-	 * Builds a parser with a stream containing the query to parse.
-	 *
-	 * @param stream			The stream in which the ADQL query to parse is given.
-	 * @param encoding		The supplied encoding.
-	 * @param factory		The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with a stream containing the query to parse.
+	*
+	* @param stream			The stream in which the ADQL query to parse is given.
+	* @param encoding		The supplied encoding.
+	* @param factory		The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(java.io.InputStream stream, String encoding, ADQLQueryFactory factory){
 		this(stream, encoding, null, factory);
 	}
 
 	/**
-	 * Builds a parser with a reader containing the query to parse.
-	 *
-	 * @param reader			The reader in which the ADQL query to parse is given.
-	 * @param checker		The object to use to check each ADQLQuery.
-	 * @param factory		The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with a reader containing the query to parse.
+	*
+	* @param reader			The reader in which the ADQL query to parse is given.
+	* @param checker		The object to use to check each ADQLQuery.
+	* @param factory		The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(java.io.Reader reader, QueryChecker checker, ADQLQueryFactory factory){
 		this(reader);
 
@@ -200,32 +215,32 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	/**
-	 * Builds a parser with a reader containing the query to parse.
-	 *
-	 * @param reader			The reader in which the ADQL query to parse is given.
-	 * @param checker		The object to use to check each ADQLQuery.
-	 */
+	* Builds a parser with a reader containing the query to parse.
+	*
+	* @param reader			The reader in which the ADQL query to parse is given.
+	* @param checker		The object to use to check each ADQLQuery.
+	*/
 	public ADQLParser(java.io.Reader reader, QueryChecker checker){
 		this(reader, checker, null);
 	}
 
 	/**
-	 * Builds a parser with a reader containing the query to parse.
-	 *
-	 * @param reader		The reader in which the ADQL query to parse is given.
-	 * @param factory		The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with a reader containing the query to parse.
+	*
+	* @param reader		The reader in which the ADQL query to parse is given.
+	* @param factory		The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(java.io.Reader reader, ADQLQueryFactory factory){
 		this(reader, null, factory);
 	}
 
 	/**
-	 * Builds a parser with another token manager.
-	 *
-	 * @param tm				The manager which associates a token to a numeric code.
-	 * @param checker		The object to use to check each ADQLQuery.
-	 * @param factory		The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with another token manager.
+	*
+	* @param tm				The manager which associates a token to a numeric code.
+	* @param checker		The object to use to check each ADQLQuery.
+	* @param factory		The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(ADQLParserTokenManager tm, QueryChecker checker, ADQLQueryFactory factory){
 		this(tm);
 
@@ -236,33 +251,33 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	/**
-	 * Builds a parser with another token manager.
-	 *
-	 * @param tm				The manager which associates a token to a numeric code.
-	 * @param checker		The object to use to check each ADQLQuery.
-	 */
+	* Builds a parser with another token manager.
+	*
+	* @param tm				The manager which associates a token to a numeric code.
+	* @param checker		The object to use to check each ADQLQuery.
+	*/
 	public ADQLParser(ADQLParserTokenManager tm, QueryChecker checker){
 		this(tm, checker, null);
 	}
 
 	/**
-	 * Builds a parser with another token manager.
-	 *
-	 * @param tm				The manager which associates a token to a numeric code.
-	 * @param factory		The object to use to build an object representation of the given ADQL query.
-	 */
+	* Builds a parser with another token manager.
+	*
+	* @param tm				The manager which associates a token to a numeric code.
+	* @param factory		The object to use to build an object representation of the given ADQL query.
+	*/
 	public ADQLParser(ADQLParserTokenManager tm, ADQLQueryFactory factory){
 		this(tm, null, factory);
 	}
 
 	/**
-	 * Parses the query given at the creation of this parser or in the <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()
-	 */
+	* Parses the query given at the creation of this parser or in the <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()
+	*/
 	public final ADQLQuery parseQuery() throws ParseException{
 		stackQuery.clear();
 		query = null;
@@ -270,16 +285,16 @@ 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)
-	 * @see ADQLParser#setDebug(boolean)
-	 * @see ADQLParser#Query()
-	 */
+	* 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)
+	* @see ADQLParser#setDebug(boolean)
+	* @see ADQLParser#Query()
+	*/
 	public final ADQLQuery parseQuery(String q) throws ParseException{
 		stackQuery.clear();
 		query = null;
@@ -288,16 +303,16 @@ 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)
-	 * @see ADQLParser#setDebug(boolean)
-	 * @see ADQLParser#Query()
-	 */
+	* 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)
+	* @see ADQLParser#setDebug(boolean)
+	* @see ADQLParser#Query()
+	*/
 	public final ADQLQuery parseQuery(java.io.InputStream stream) throws ParseException{
 		stackQuery.clear();
 		query = null;
@@ -356,13 +371,13 @@ public class ADQLParser implements ADQLParserConstants {
 	}
 
 	/**
-	 * <p>Gets the specified ADQL query and parses the given ADQL query. The SQL translation is then printed if the syntax is correct.</p>
-	 * <p><b>ONLY the syntax is checked: the query is NOT EXECUTED !</b></p>
-	 * <p>Supplied parameters are: <ul><li>[-debug] -url http://...</li><li>[-debug] -file ...</li><li>[-debug] -query SELECT...</li></ul></p>
-	 *
-	 * @param args
-	 * @throws Exception
-	 */
+	* <p>Gets the specified ADQL query and parses the given ADQL query. The SQL translation is then printed if the syntax is correct.</p>
+	* <p><b>ONLY the syntax is checked: the query is NOT EXECUTED !</b></p>
+	* <p>Supplied parameters are: <ul><li>[-debug] -url http://...</li><li>[-debug] -file ...</li><li>[-debug] -query SELECT...</li></ul></p>
+	*
+	* @param args
+	* @throws Exception
+	*/
 	public static final void main(String[] args) throws Exception{
 		final String USAGE = "Usage:\u005cn\u005ctadqlParser.jar [-d] [-v] [-e] [-a|-s] [<FILE>|<URL>]\u005cn\u005cnNOTE: If no file or URL is given, the ADQL query is expected in the standard input. This query must end with a ';' !\u005cn\u005cnParameters:\u005cn\u005ct-v or --verbose : Print the main steps of the parsing\u005cn\u005ct-d or --debug   : Print stack traces when a grave error occurs\u005cn\u005ct-e or --explain : Explain the ADQL parsing (or Expand the parsing tree)\u005cn\u005ct-a or --adql    : Display the understood ADQL query\u005cn\u005ct-s or --sql     : Ask the SQL translation of the given ADQL query (SQL compatible with PostgreSQL)\u005cn\u005cnReturn:\u005cn\u005ctBy default: nothing if the query is correct. Otherwise a message explaining why the query is not correct is displayed.\u005cn\u005ctWith the -s option, the SQL translation of the given ADQL query will be returned.\u005cn\u005ctWith the -a option, the ADQL query is returned as it has been understood.\u005cn\u005cnExit status:\u005cn\u005ct0\u005ctOK !\u005cn\u005ct1\u005ctParameter error (missing or incorrect parameter)\u005cn\u005ct2\u005ctFile error (incorrect file/url, reading error, ...)\u005cn\u005ct3\u005ctParsing error (syntactic or semantic error)\u005cn\u005ct4\u005ctTranslation error (a problem has occurred during the translation of the given ADQL query in SQL).";
 
@@ -471,12 +486,12 @@ public class ADQLParser implements ADQLParserConstants {
 	/* GENERAL ADQL SYNTAX */
 	/* ******************* */
 	/**
-	 * Parses the ADQL query given at the parser creation or in the {@link ADQLParser#ReInit(java.io.InputStream)}
-	 * or in the <i>parseQuery</i> functions.
-	 *
-	 * @return					The object representation of the query.
-	 * @throws ParseException	If the query syntax is incorrect.
-	 */
+	* Parses the ADQL query given at the parser creation or in the {@link ADQLParser#ReInit(java.io.InputStream)}
+	* or in the <i>parseQuery</i> functions.
+	*
+	* @return					The object representation of the query.
+	* @throws ParseException	If the query syntax is incorrect.
+	*/
 	final public ADQLQuery Query() throws ParseException{
 		trace_call("Query");
 		try{
@@ -494,6 +509,10 @@ public class ADQLParser implements ADQLParserConstants {
 					jj_consume_token(-1);
 					throw new ParseException();
 			}
+			// check the query:
+			if (queryChecker != null)
+				queryChecker.check(q);
+
 			{
 				if (true)
 					return q;
@@ -551,10 +570,6 @@ public class ADQLParser implements ADQLParserConstants {
 					jj_la1[4] = jj_gen;
 					;
 			}
-			// check the query:
-			if (queryChecker != null)
-				queryChecker.check(query);
-
 			// get the previous query (!= null if the current query is a sub-query):
 			ADQLQuery previousQuery = stackQuery.pop();
 			if (stackQuery.isEmpty())
@@ -3549,34 +3564,6 @@ public class ADQLParser implements ADQLParserConstants {
 		}
 	}
 
-	private boolean jj_3R_165(){
-		if (jj_scan_token(NOT))
-			return true;
-		return false;
-	}
-
-	private boolean jj_3R_44(){
-		if (jj_scan_token(SELECT))
-			return true;
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_3R_136())
-			jj_scanpos = xsp;
-		xsp = jj_scanpos;
-		if (jj_3R_137())
-			jj_scanpos = xsp;
-		if (jj_3R_138())
-			return true;
-		while(true){
-			xsp = jj_scanpos;
-			if (jj_3R_139()){
-				jj_scanpos = xsp;
-				break;
-			}
-		}
-		return false;
-	}
-
 	private boolean jj_3R_16(){
 		if (jj_scan_token(LEFT_PAR))
 			return true;
@@ -3616,20 +3603,32 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_111(){
-		if (jj_3R_23())
+	private boolean jj_3R_120(){
+		if (jj_3R_143())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_163(){
-		if (jj_3R_49())
+	private boolean jj_3R_119(){
+		if (jj_3R_142())
 			return true;
 		return false;
 	}
 
-	private boolean jj_3R_120(){
-		if (jj_3R_143())
+	private boolean jj_3R_118(){
+		if (jj_3R_141())
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_111(){
+		if (jj_3R_23())
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_163(){
+		if (jj_3R_49())
 			return true;
 		return false;
 	}
@@ -3645,18 +3644,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_119(){
-		if (jj_3R_142())
-			return true;
-		return false;
-	}
-
-	private boolean jj_3R_118(){
-		if (jj_3R_141())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_32(){
 		if (jj_3R_49())
 			return true;
@@ -3689,20 +3676,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3R_65(){
-		if (jj_3R_41())
-			return true;
-		Token xsp;
-		while(true){
-			xsp = jj_scanpos;
-			if (jj_3R_113()){
-				jj_scanpos = xsp;
-				break;
-			}
-		}
-		return false;
-	}
-
 	private boolean jj_3R_28(){
 		if (jj_3R_44())
 			return true;
@@ -3724,6 +3697,20 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3R_65(){
+		if (jj_3R_41())
+			return true;
+		Token xsp;
+		while(true){
+			xsp = jj_scanpos;
+			if (jj_3R_113()){
+				jj_scanpos = xsp;
+				break;
+			}
+		}
+		return false;
+	}
+
 	private boolean jj_3R_183(){
 		if (jj_scan_token(COMMA))
 			return true;
@@ -4857,6 +4844,12 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3_3(){
+		if (jj_3R_17())
+			return true;
+		return false;
+	}
+
 	private boolean jj_3R_100(){
 		Token xsp;
 		xsp = jj_scanpos;
@@ -4880,12 +4873,6 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
-	private boolean jj_3_3(){
-		if (jj_3R_17())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_150(){
 		if (jj_3R_41())
 			return true;
@@ -5711,6 +5698,34 @@ public class ADQLParser implements ADQLParserConstants {
 		return false;
 	}
 
+	private boolean jj_3R_165(){
+		if (jj_scan_token(NOT))
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_44(){
+		if (jj_scan_token(SELECT))
+			return true;
+		Token xsp;
+		xsp = jj_scanpos;
+		if (jj_3R_136())
+			jj_scanpos = xsp;
+		xsp = jj_scanpos;
+		if (jj_3R_137())
+			jj_scanpos = xsp;
+		if (jj_3R_138())
+			return true;
+		while(true){
+			xsp = jj_scanpos;
+			if (jj_3R_139()){
+				jj_scanpos = xsp;
+				break;
+			}
+		}
+		return false;
+	}
+
 	/** Generated Token Manager. */
 	public ADQLParserTokenManager token_source;
 	SimpleCharStream jj_input_stream;
diff --git a/src/adql/parser/ADQLParserConstants.java b/src/adql/parser/ADQLParserConstants.java
index ee79a43..cf75565 100644
--- a/src/adql/parser/ADQLParserConstants.java
+++ b/src/adql/parser/ADQLParserConstants.java
@@ -5,7 +5,6 @@ package adql.parser;
  * Token literal values and constants.
  * Generated by org.javacc.parser.OtherFilesGen#start()
  */
-@SuppressWarnings("all")
 public interface ADQLParserConstants {
 
 	/** End of File. */
diff --git a/src/adql/parser/ADQLParserTokenManager.java b/src/adql/parser/ADQLParserTokenManager.java
index b6efe77..4e4d9cc 100644
--- a/src/adql/parser/ADQLParserTokenManager.java
+++ b/src/adql/parser/ADQLParserTokenManager.java
@@ -21,7 +21,6 @@ import adql.translator.PostgreSQLTranslator;
 import adql.translator.TranslationException;
 
 /** Token Manager. */
-@SuppressWarnings("all")
 public class ADQLParserTokenManager implements ADQLParserConstants {
 
 	/** Debug output. */
diff --git a/src/adql/parser/QueryChecker.java b/src/adql/parser/QueryChecker.java
index de5e496..0c15a16 100644
--- a/src/adql/parser/QueryChecker.java
+++ b/src/adql/parser/QueryChecker.java
@@ -16,7 +16,8 @@ package adql.parser;
  * 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 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
+ * Copyright 2012-2013 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ *                       Astronomisches Rechen Institute (ARI)
  */
 
 import adql.db.DBChecker;
@@ -27,13 +28,19 @@ import adql.query.ADQLQuery;
  * 
  * <p>Usually, it consists to check the existence of referenced columns and tables. In this case, one default implementation of this interface can be used: {@link DBChecker}</p>
  * 
- * @author Gr&eacute;gory Mantelet (CDS)
- * @version 08/2011
+ * @author Gr&eacute;gory Mantelet (CDS;ARI)
+ * @version 1.2 (12/2013)
  */
 public interface QueryChecker {
 
 	/**
-	 * <p>Checks (non-recursively in sub-queries) the given {@link ADQLQuery}.</p>
+	 * <p>Checks the given {@link ADQLQuery}.</p>
+	 * 
+	 * <p><b>
+	 * 	<u>Important note:</u>
+	 * 	All subqueries must also be checked when calling this function!
+	 * </b></p>
+	 * 
 	 * <p>If the query is correct, nothing happens. However at the first detected error, a {@link ParseException} is thrown.</p>
 	 * 
 	 * @param query				The query to check.
diff --git a/src/adql/parser/adqlGrammar.jj b/src/adql/parser/adqlGrammar.jj
index 1f93d62..256eb74 100644
--- a/src/adql/parser/adqlGrammar.jj
+++ b/src/adql/parser/adqlGrammar.jj
@@ -14,7 +14,8 @@
  * 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 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
+ * Copyright 2012-2013 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ *                       Astronomisches Rechen Institute (ARI)
  */
 
 /*
@@ -24,8 +25,8 @@
 *  The generated parser checks the syntax of the given ADQL query and generates an object representation but no coherence with any database is done.
 *  If the syntax is not conform to the ADQL definition an error message is printed else it will be the message "Correct syntax".
 *
-*  Author:  Gregory Mantelet (CDS) - gregory.mantelet@astro.unistra.fr
-*  Version: January 2012
+*  Author:  Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
+*  Version: 1.2 (12/2013)
 */
 
 							/* ########### */
@@ -87,8 +88,8 @@ import adql.translator.TranslationException;
 * @see QueryChecker
 * @see ADQLQueryFactory
 *
-* @author Gr&eacute;gory Mantelet (CDS) - gregory.mantelet@astro.unistra.fr
-* @version January 2012
+* @author Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
+* @version 1.2 (12/2013)
 */
 public class ADQLParser {
 	
@@ -711,7 +712,13 @@ TOKEN : {
 */
 ADQLQuery Query(): {ADQLQuery q = null;}{
 	q=QueryExpression() (<EOF> | <EOQ>)
-	{ return q; }
+	{
+		// check the query:
+		if (queryChecker != null)
+			queryChecker.check(q);
+			
+		return q;
+	}
 }
 
 ADQLQuery QueryExpression(): {} {
@@ -731,10 +738,6 @@ ADQLQuery QueryExpression(): {} {
 	[Having()]
 	[OrderBy()]
 	{
-		// check the query:
-		if (queryChecker != null)
-			queryChecker.check(query);
-			
 		// get the previous query (!= null if the current query is a sub-query):
 		ADQLQuery previousQuery = stackQuery.pop();
 		if (stackQuery.isEmpty())
diff --git a/src/adql/query/ClauseADQL.java b/src/adql/query/ClauseADQL.java
index 1c3c90a..7116b41 100644
--- a/src/adql/query/ClauseADQL.java
+++ b/src/adql/query/ClauseADQL.java
@@ -16,14 +16,15 @@ package adql.query;
  * 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 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
+ * Copyright 2012-2013 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ *                       Astronomisches Rechen Institute (ARI)
  */
 
 /**
  * Represents an ADQL clause (i.e. SELECT, FROM, WHERE, ...).
  * 
- * @author Gr&eacute;gory Mantelet (CDS)
- * @version 11/2010
+ * @author Gr&eacute;gory Mantelet (CDS;ARI)
+ * @version 1.2 (12/2013)
  */
 public class ClauseADQL< T extends ADQLObject > extends ADQLList<T> {
 
@@ -53,10 +54,9 @@ public class ClauseADQL< T extends ADQLObject > extends ADQLList<T> {
 		super(toCopy);
 	}
 
-	@SuppressWarnings("unchecked")
 	@Override
 	public ADQLObject getCopy() throws Exception{
-		return new ClauseADQL(this);
+		return new ClauseADQL<T>(this);
 	}
 
 	/**
-- 
GitLab