diff --git a/src/adql/db/DBChecker.java b/src/adql/db/DBChecker.java
index dd8c2b9f40d1de448d6c15ac4a5604a8154fedf6..082e4a34bbc0fc8379208e45131b2ef100900293 100644
--- a/src/adql/db/DBChecker.java
+++ b/src/adql/db/DBChecker.java
@@ -16,7 +16,7 @@ package adql.db;
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  *
- * Copyright 2011-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2011-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -70,49 +70,69 @@ import adql.search.SimpleReplaceHandler;
 import adql.search.SimpleSearchHandler;
 
 /**
- * This {@link QueryChecker} implementation is able to do the following verifications on an ADQL query:
+ * This {@link QueryChecker} implementation is able to do the following
+ * verifications on an ADQL query:
  * <ol>
- * 	<li>Check the existence of all table and column references found in a query</li>
- * 	<li>Resolve all unknown functions as supported User Defined Functions (UDFs)</li>
- * 	<li>Check whether all used geometrical functions are supported</li>
+ * 	<li>Check the existence of all table and column references found in a
+ * 		query</li>
+ * 	<li>Resolve all unknown functions as supported User Defined Functions
+ * 		(UDFs)</li>
  * 	<li>Check whether all used coordinate systems are supported</li>
  * 	<li>Check that types of columns and UDFs match with their context</li>
  * </ol>
  *
+ * <p><i><b>IMPORTANT note:</b>
+ * 	Since v2.0, the check of supported geometrical functions is performed
+ * 	directly in ADQLParser through the notion of Optional Features.
+ * 	The declaration of supported geometrical functions must now be done
+ * 	with {@link adql.parser.ADQLParser#getSupportedFeatures() ADQLParser.getSupportedFeatures()}
+ * 	(see also {@link adql.parser.feature.FeatureSet FeatureSet}).
+ * </i></p>
+ *
  * <h3>Check tables and columns</h3>
  * <p>
- * 	In addition to check the existence of tables and columns referenced in the query,
- * 	this checked will also attach database metadata on these references ({@link ADQLTable}
- * 	and {@link ADQLColumn} instances when they are resolved.
+ * 	In addition to check the existence of tables and columns referenced in the
+ * 	query, this checked will also attach database metadata on these references
+ * 	({@link ADQLTable} and {@link ADQLColumn} instances when they are resolved.
  * </p>
  *
  * <p>These information are:</p>
  * <ul>
- * 	<li>the corresponding {@link DBTable} or {@link DBColumn} (see getter and setter for DBLink in {@link ADQLTable} and {@link ADQLColumn})</li>
+ * 	<li>the corresponding {@link DBTable} or {@link DBColumn} (see getter and
+ * 		setter for DBLink in {@link ADQLTable} and {@link ADQLColumn})</li>
  * 	<li>the link between an {@link ADQLColumn} and its {@link ADQLTable}</li>
  * </ul>
  *
  * <p><i><u>Note:</u>
- * 	Knowing DB metadata of {@link ADQLTable} and {@link ADQLColumn} is particularly useful for the translation of the ADQL query to SQL,
- * 	because the ADQL name of columns and tables can be replaced in SQL by their DB name, if different. This mapping is done automatically
- * 	by {@link adql.translator.JDBCTranslator}.
+ * 	Knowing DB metadata of {@link ADQLTable} and {@link ADQLColumn} is
+ * 	particularly useful for the translation of the ADQL query to SQL, because
+ * 	the ADQL name of columns and tables can be replaced in SQL by their DB name,
+ * 	if different. This mapping is done automatically by
+ * 	{@link adql.translator.JDBCTranslator}.
  * </i></p>
  *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.4 (11/2017)
+ * @version 2.0 (07/2019)
  */
 public class DBChecker implements QueryChecker {
 
 	/** List of all available tables ({@link DBTable}). */
 	protected SearchTableApi lstTables;
 
-	/** <p>List of all allowed geometrical functions (i.e. CONTAINS, REGION, POINT, COORD2, ...).</p>
+	/** List of all allowed geometrical functions (i.e. CONTAINS, REGION, POINT,
+	 * COORD2, ...).
+	 *
 	 * <p>
 	 * 	If this list is NULL, all geometrical functions are allowed.
-	 * 	However, if not, all items of this list must be the only allowed geometrical functions.
-	 * 	So, if the list is empty, no such function is allowed.
+	 * 	However, if not, all items of this list must be the only allowed
+	 * 	geometrical functions. So, if the list is empty, no such function is
+	 * 	allowed.
 	 * </p>
-	 * @since 1.3 */
+	 *
+	 * @since 1.3
+	 * @deprecated Since v2.0, supported geometrical functions must be declared
+	 *             in ADQLParser. */
+	@Deprecated
 	protected String[] allowedGeo = null;
 
 	/** <p>List of all allowed coordinate systems.</p>
@@ -156,11 +176,10 @@ public class DBChecker implements QueryChecker {
 	 * <ul>
 	 * 	<li>Existence of tables and columns:            <b>NO <i>(even unknown or fake tables and columns are allowed)</i></b></li>
 	 * 	<li>Existence of User Defined Functions (UDFs): <b>NO <i>(any "unknown" function is allowed)</i></b></li>
-	 * 	<li>Support of geometrical functions:           <b>NO <i>(all valid geometrical functions are allowed)</i></b></li>
 	 * 	<li>Support of coordinate systems:              <b>NO <i>(all valid coordinate systems are allowed)</i></b></li>
 	 * </ul>
 	 */
-	public DBChecker(){
+	public DBChecker() {
 		this(null, null);
 	}
 
@@ -171,13 +190,12 @@ public class DBChecker implements QueryChecker {
 	 * <ul>
 	 * 	<li>Existence of tables and columns:            <b>OK</b></li>
 	 * 	<li>Existence of User Defined Functions (UDFs): <b>NO <i>(any "unknown" function is allowed)</i></b></li>
-	 * 	<li>Support of geometrical functions:           <b>NO <i>(all valid geometrical functions are allowed)</i></b></li>
 	 * 	<li>Support of coordinate systems:              <b>NO <i>(all valid coordinate systems are allowed)</i></b></li>
 	 * </ul>
 	 *
 	 * @param tables	List of all available tables.
 	 */
-	public DBChecker(final Collection<? extends DBTable> tables){
+	public DBChecker(final Collection<? extends DBTable> tables) {
 		this(tables, null);
 	}
 
@@ -188,7 +206,6 @@ public class DBChecker implements QueryChecker {
 	 * <ul>
 	 * 	<li>Existence of tables and columns:            <b>OK</b></li>
 	 * 	<li>Existence of User Defined Functions (UDFs): <b>OK</b></li>
-	 * 	<li>Support of geometrical functions:           <b>NO <i>(all valid geometrical functions are allowed)</i></b></li>
 	 * 	<li>Support of coordinate systems:              <b>NO <i>(all valid coordinate systems are allowed)</i></b></li>
 	 * </ul>
 	 *
@@ -200,7 +217,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	public DBChecker(final Collection<? extends DBTable> tables, final Collection<? extends FunctionDef> allowedUdfs){
+	public DBChecker(final Collection<? extends DBTable> tables, final Collection<? extends FunctionDef> allowedUdfs) {
 		// Sort and store the given tables:
 		setTables(tables);
 
@@ -208,11 +225,11 @@ public class DBChecker implements QueryChecker {
 		int cnt;
 
 		// Store all allowed UDFs in a sorted array:
-		if (allowedUdfs != null){
+		if (allowedUdfs != null) {
 			// Remove all NULL and empty strings:
 			tmp = new FunctionDef[allowedUdfs.size()];
 			cnt = 0;
-			for(FunctionDef udf : allowedUdfs){
+			for(FunctionDef udf : allowedUdfs) {
 				if (udf != null && udf.name.trim().length() > 0)
 					tmp[cnt++] = udf;
 			}
@@ -251,8 +268,13 @@ public class DBChecker implements QueryChecker {
 	 *                       	If it is empty, no coordinate system is allowed (except the default values - generally expressed by an empty string: '').
 	 *
 	 * @since 1.3
+	 * @deprecated	Since v2.0, the check of geometrical functions support is
+	 *            	performed in ADQLParser. It must now be done with
+	 *            	{@link adql.parser.ADQLParser#getSupportedFeatures() ADQLParser.getSupportedFeatures()}
+	 * 	          	(see also {@link adql.parser.feature.FeatureSet FeatureSet}).
 	 */
-	public DBChecker(final Collection<? extends DBTable> tables, final Collection<String> allowedGeoFcts, final Collection<String> allowedCoordSys) throws ParseException{
+	@Deprecated
+	public DBChecker(final Collection<? extends DBTable> tables, final Collection<String> allowedGeoFcts, final Collection<String> allowedCoordSys) throws ParseException {
 		this(tables, null, allowedGeoFcts, allowedCoordSys);
 	}
 
@@ -263,10 +285,17 @@ public class DBChecker implements QueryChecker {
 	 * <ul>
 	 * 	<li>Existence of tables and columns:            <b>OK</b></li>
 	 * 	<li>Existence of User Defined Functions (UDFs): <b>OK</b></li>
-	 * 	<li>Support of geometrical functions:           <b>OK</b></li>
 	 * 	<li>Support of coordinate systems:              <b>OK</b></li>
 	 * </ul>
 	 *
+	 * <p><i><b>IMPORTANT note:</b>
+	 * 	Since v2.0, the check of supported geometrical functions is performed
+	 * 	directly in ADQLParser through the notion of Optional Features.
+	 * 	The declaration of supported geometrical functions must now be done
+	 * 	with {@link adql.parser.ADQLParser#getSupportedFeatures() ADQLParser.getSupportedFeatures()}
+	 * 	(see also {@link adql.parser.feature.FeatureSet FeatureSet}).
+	 * </i></p>
+	 *
 	 * @param tables			List of all available tables.
 	 * @param allowedUdfs		List of all allowed user defined functions.
 	 *                   		If NULL, no verification will be done (and so, all UDFs are allowed).
@@ -284,9 +313,14 @@ public class DBChecker implements QueryChecker {
 	 *                       	If the given list is NULL, no verification will be done (and so, all coordinate systems are allowed).
 	 *                       	If it is empty, no coordinate system is allowed (except the default values - generally expressed by an empty string: '').
 	 *
-	 * @since 1.3
+	 * @since 2.0
+	 * @deprecated	Since v2.0, the check of geometrical functions support is
+	 *            	performed in ADQLParser. It must now be done with
+	 *            	{@link adql.parser.ADQLParser#getSupportedFeatures() ADQLParser.getSupportedFeatures()}
+	 * 	          	(see also {@link adql.parser.feature.FeatureSet FeatureSet}).
 	 */
-	public DBChecker(final Collection<? extends DBTable> tables, final Collection<? extends FunctionDef> allowedUdfs, final Collection<String> allowedGeoFcts, final Collection<String> allowedCoordSys) throws ParseException{
+	@Deprecated
+	public DBChecker(final Collection<? extends DBTable> tables, final Collection<? extends FunctionDef> allowedUdfs, final Collection<String> allowedGeoFcts, final Collection<String> allowedCoordSys) throws ParseException {
 		// Set the list of available tables + Set the list of all known UDFs:
 		this(tables, allowedUdfs);
 
@@ -308,7 +342,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected final static String[] specialSort(final Collection<String> items){
+	protected final static String[] specialSort(final Collection<String> items) {
 		// Nothing to do if the array is NULL:
 		if (items == null)
 			return null;
@@ -316,7 +350,7 @@ public class DBChecker implements QueryChecker {
 		// Keep only valid items (not NULL and not empty string):
 		String[] tmp = new String[items.size()];
 		int cnt = 0;
-		for(String item : items){
+		for(String item : items) {
 			if (item != null && item.trim().length() > 0)
 				tmp[cnt++] = item;
 		}
@@ -345,7 +379,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @param tables	List of {@link DBTable}s.
 	 */
-	public final void setTables(final Collection<? extends DBTable> tables){
+	public final void setTables(final Collection<? extends DBTable> tables) {
 		if (tables == null)
 			lstTables = new SearchTableList();
 		else if (tables instanceof SearchTableApi)
@@ -372,7 +406,7 @@ public class DBChecker implements QueryChecker {
 	 * @see #check(ADQLQuery, Stack)
 	 */
 	@Override
-	public final void check(final ADQLQuery query) throws ParseException{
+	public final void check(final ADQLQuery query) throws ParseException {
 		check(query, null);
 	}
 
@@ -404,7 +438,7 @@ public class DBChecker implements QueryChecker {
 	 * @see #checkGeometries(ADQLQuery, UnresolvedIdentifiersException)
 	 * @see #checkTypes(ADQLQuery, UnresolvedIdentifiersException)
 	 */
-	protected void check(final ADQLQuery query, final Stack<SearchColumnList> fathersList) throws UnresolvedIdentifiersException{
+	protected void check(final ADQLQuery query, final Stack<SearchColumnList> fathersList) throws UnresolvedIdentifiersException {
 		UnresolvedIdentifiersException errors = new UnresolvedIdentifiersException();
 
 		// A. Check DB items (tables and columns):
@@ -456,15 +490,15 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected SearchColumnList checkDBItems(final ADQLQuery query, final Stack<SearchColumnList> fathersList, final UnresolvedIdentifiersException errors){
+	protected SearchColumnList checkDBItems(final ADQLQuery query, final Stack<SearchColumnList> fathersList, final UnresolvedIdentifiersException errors) {
 		// a. Resolve all tables:
-		Map<DBTable,ADQLTable> mapTables = resolveTables(query, fathersList, errors);
+		Map<DBTable, ADQLTable> mapTables = resolveTables(query, fathersList, errors);
 
 		// b. Get the list of all columns made available in the clause FROM:
 		SearchColumnList availableColumns;
-		try{
+		try {
 			availableColumns = query.getFrom().getDBColumns();
-		}catch(ParseException pe){
+		} catch(ParseException pe) {
 			errors.addException(pe);
 			availableColumns = new SearchColumnList();
 		}
@@ -526,25 +560,25 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @return	An associative map of all the resolved tables.
 	 */
-	protected Map<DBTable,ADQLTable> resolveTables(final ADQLQuery query, final Stack<SearchColumnList> fathersList, final UnresolvedIdentifiersException errors){
-		HashMap<DBTable,ADQLTable> mapTables = new HashMap<DBTable,ADQLTable>();
+	protected Map<DBTable, ADQLTable> resolveTables(final ADQLQuery query, final Stack<SearchColumnList> fathersList, final UnresolvedIdentifiersException errors) {
+		HashMap<DBTable, ADQLTable> mapTables = new HashMap<DBTable, ADQLTable>();
 		ISearchHandler sHandler;
 
 		// Check the existence of all tables:
 		sHandler = new SearchTableHandler();
 		sHandler.search(query.getFrom());
-		for(ADQLObject result : sHandler){
-			try{
+		for(ADQLObject result : sHandler) {
+			try {
 				ADQLTable table = (ADQLTable)result;
 
 				// resolve the table:
 				DBTable dbTable = null;
-				if (table.isSubQuery()){
+				if (table.isSubQuery()) {
 					// check the sub-query tables:
 					check(table.getSubQuery(), fathersList);
 					// generate its DBTable:
 					dbTable = generateDBTable(table.getSubQuery(), table.getAlias());
-				}else{
+				} else {
 					dbTable = resolveTable(table);
 					// wrap this table metadata if an alias should be used:
 					if (dbTable != null && table.hasAlias())
@@ -554,7 +588,7 @@ public class DBChecker implements QueryChecker {
 				// link with the matched DBTable:
 				table.setDBLink(dbTable);
 				mapTables.put(dbTable, table);
-			}catch(ParseException pe){
+			} catch(ParseException pe) {
 				errors.addException(pe);
 			}
 		}
@@ -566,14 +600,14 @@ public class DBChecker implements QueryChecker {
 		 *       in sub-queries).*/
 		sHandler = new SearchWildCardHandler();
 		sHandler.search(query.getSelect());
-		for(ADQLObject result : sHandler){
-			try{
+		for(ADQLObject result : sHandler) {
+			try {
 				SelectAllColumns wildcard = (SelectAllColumns)result;
 				ADQLTable table = wildcard.getAdqlTable();
 				DBTable dbTable = null;
 
 				// first, try to resolve the table by table alias:
-				if (table.getTableName() != null && table.getSchemaName() == null){
+				if (table.getTableName() != null && table.getSchemaName() == null) {
 					List<ADQLTable> tables = query.getFrom().getTablesByAlias(table.getTableName(), table.isCaseSensitive(IdentifierField.TABLE));
 					if (tables.size() == 1)
 						dbTable = tables.get(0).getDBLink();
@@ -585,7 +619,7 @@ public class DBChecker implements QueryChecker {
 
 				// set the corresponding tables among the list of resolved tables:
 				wildcard.setAdqlTable(mapTables.get(dbTable));
-			}catch(ParseException pe){
+			} catch(ParseException pe) {
 				errors.addException(pe);
 			}
 		}
@@ -602,7 +636,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @throws ParseException	An {@link UnresolvedTableException} if the given table can't be resolved.
 	 */
-	protected DBTable resolveTable(final ADQLTable table) throws ParseException{
+	protected DBTable resolveTable(final ADQLTable table) throws ParseException {
 		List<DBTable> tables = lstTables.search(table);
 
 		// good if only one table has been found:
@@ -640,21 +674,21 @@ public class DBChecker implements QueryChecker {
 	 * @param list			List of column metadata to complete in this function each time a column reference is resolved.
 	 * @param errors		List of errors to complete in this function each time an unknown table or column is encountered.
 	 */
-	protected void resolveColumns(final ADQLQuery query, final Stack<SearchColumnList> fathersList, final Map<DBTable,ADQLTable> mapTables, final SearchColumnList list, final UnresolvedIdentifiersException errors){
+	protected void resolveColumns(final ADQLQuery query, final Stack<SearchColumnList> fathersList, final Map<DBTable, ADQLTable> mapTables, final SearchColumnList list, final UnresolvedIdentifiersException errors) {
 		ISearchHandler sHandler;
 
 		// Check the existence of all columns:
 		sHandler = new SearchColumnOutsideGroupByHandler();
 		sHandler.search(query);
-		for(ADQLObject result : sHandler){
-			try{
+		for(ADQLObject result : sHandler) {
+			try {
 				ADQLColumn adqlColumn = (ADQLColumn)result;
 				// resolve the column:
 				DBColumn dbColumn = resolveColumn(adqlColumn, list, fathersList);
 				// link with the matched DBColumn:
 				adqlColumn.setDBLink(dbColumn);
 				adqlColumn.setAdqlTable(mapTables.get(dbColumn.getTable()));
-			}catch(ParseException pe){
+			} catch(ParseException pe) {
 				errors.addException(pe);
 			}
 		}
@@ -663,17 +697,17 @@ public class DBChecker implements QueryChecker {
 		ClauseSelect select = query.getSelect();
 		sHandler = new SearchColumnHandler();
 		sHandler.search(query.getGroupBy());
-		for(ADQLObject result : sHandler){
-			try{
+		for(ADQLObject result : sHandler) {
+			try {
 				ADQLColumn adqlColumn = (ADQLColumn)result;
 				// resolve the column:
 				DBColumn dbColumn = checkGroupByItem(adqlColumn, select, list);
 				// link with the matched DBColumn:
-				if (dbColumn != null){
+				if (dbColumn != null) {
 					adqlColumn.setDBLink(dbColumn);
 					adqlColumn.setAdqlTable(mapTables.get(dbColumn.getTable()));
 				}
-			}catch(ParseException pe){
+			} catch(ParseException pe) {
 				errors.addException(pe);
 			}
 		}
@@ -683,8 +717,8 @@ public class DBChecker implements QueryChecker {
 		 *       because no father column can be used in ORDER BY. */
 		sHandler = new SearchColReferenceHandler();
 		sHandler.search(query);
-		for(ADQLObject result : sHandler){
-			try{
+		for(ADQLObject result : sHandler) {
+			try {
 				ColumnReference colRef = (ColumnReference)result;
 				// resolve the column reference:
 				DBColumn dbColumn = checkColumnReference(colRef, select, list);
@@ -692,7 +726,7 @@ public class DBChecker implements QueryChecker {
 				colRef.setDBLink(dbColumn);
 				if (dbColumn != null)
 					colRef.setAdqlTable(mapTables.get(dbColumn.getTable()));
-			}catch(ParseException pe){
+			} catch(ParseException pe) {
 				errors.addException(pe);
 			}
 		}
@@ -718,23 +752,23 @@ public class DBChecker implements QueryChecker {
 	 * @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, Stack<SearchColumnList> fathersList) throws ParseException{
+	protected DBColumn resolveColumn(final ADQLColumn column, final SearchColumnList dbColumns, Stack<SearchColumnList> fathersList) throws ParseException {
 		List<DBColumn> foundColumns = dbColumns.search(column);
 
 		// good if only one column has been found:
 		if (foundColumns.size() == 1)
 			return foundColumns.get(0);
 		// but if more than one: ambiguous table reference !
-		else if (foundColumns.size() > 1){
+		else if (foundColumns.size() > 1) {
 			if (column.getTableName() == null)
 				throw new UnresolvedColumnException(column, (foundColumns.get(0).getTable() == null) ? "<NULL>" : (foundColumns.get(0).getTable().getADQLName() + "." + foundColumns.get(0).getADQLName()), (foundColumns.get(1).getTable() == null) ? "<NULL>" : (foundColumns.get(1).getTable().getADQLName() + "." + foundColumns.get(1).getADQLName()));
 			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{
+		else {
 			if (fathersList == null || fathersList.isEmpty())
 				throw new UnresolvedColumnException(column);
-			else{
+			else {
 				Stack<SearchColumnList> subStack = new Stack<SearchColumnList>();
 				subStack.addAll(fathersList.subList(0, fathersList.size() - 1));
 				return resolveColumn(column, fathersList.peek(), subStack);
@@ -760,11 +794,11 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.4
 	 */
-	protected DBColumn checkGroupByItem(final ADQLColumn col, final ClauseSelect select, final SearchColumnList dbColumns) throws ParseException{
+	protected DBColumn checkGroupByItem(final ADQLColumn col, final ClauseSelect select, final SearchColumnList dbColumns) throws ParseException {
 		/* If the column name is not qualified, it may be a SELECT-item's alias.
 		 * So, try resolving the name as an alias.
 		 * If it fails, perform the normal column resolution.*/
-		if (col.getTableName() == null){
+		if (col.getTableName() == null) {
 			List<SelectItem> founds = select.searchByAlias(col.getColumnName(), col.isCaseSensitive(IdentifierField.COLUMN));
 			if (founds.size() == 1)
 				return null;
@@ -790,18 +824,18 @@ public class DBChecker implements QueryChecker {
 	 * @see ClauseSelect#searchByAlias(String)
 	 * @see #resolveColumn(ADQLColumn, SearchColumnList, Stack)
 	 */
-	protected DBColumn checkColumnReference(final ColumnReference colRef, final ClauseSelect select, final SearchColumnList dbColumns) throws ParseException{
-		if (colRef.isIndex()){
+	protected DBColumn checkColumnReference(final ColumnReference colRef, final ClauseSelect select, final SearchColumnList dbColumns) throws ParseException {
+		if (colRef.isIndex()) {
 			int index = colRef.getColumnIndex();
-			if (index > 0 && index <= select.size()){
+			if (index > 0 && index <= select.size()) {
 				SelectItem item = select.get(index - 1);
 				if (item.getOperand() instanceof ADQLColumn)
 					return ((ADQLColumn)item.getOperand()).getDBLink();
 				else
 					return null;
-			}else
+			} else
 				throw new ParseException("Column index out of bounds: " + index + " (must be between 1 and " + select.size() + ") !", colRef.getPosition());
-		}else{
+		} else {
 			ADQLColumn col = new ADQLColumn(null, colRef.getColumnName());
 			col.setCaseSensitive(colRef.isCaseSensitive());
 			col.setPosition(colRef.getPosition());
@@ -829,7 +863,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @throws ParseException	Can be used to explain why the table has not been found. <i>Note: not used by default.</i>
 	 */
-	public static DBTable generateDBTable(final ADQLQuery subQuery, final String tableName) throws ParseException{
+	public static DBTable generateDBTable(final ADQLQuery subQuery, final String tableName) throws ParseException {
 		DefaultDBTable dbTable = new DefaultDBTable(tableName);
 
 		DBColumn[] columns = subQuery.getResultingColumns();
@@ -862,24 +896,24 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void checkUDFs(final ADQLQuery query, final UnresolvedIdentifiersException errors){
+	protected void checkUDFs(final ADQLQuery query, final UnresolvedIdentifiersException errors) {
 		// 1. Search all UDFs:
 		ISearchHandler sHandler = new SearchUDFHandler();
 		sHandler.search(query);
 
 		// If no UDF are allowed, throw immediately an error:
-		if (allowedUdfs.length == 0){
+		if (allowedUdfs.length == 0) {
 			for(ADQLObject result : sHandler)
 				errors.addException(new UnresolvedFunctionException((UserDefinedFunction)result));
 		}
 		// 2. Try to resolve all of them:
-		else{
+		else {
 			ArrayList<UserDefinedFunction> toResolveLater = new ArrayList<UserDefinedFunction>();
 			UserDefinedFunction udf;
 			int match;
-			BinarySearch<FunctionDef,UserDefinedFunction> binSearch = new BinarySearch<FunctionDef,UserDefinedFunction>(){
+			BinarySearch<FunctionDef, UserDefinedFunction> binSearch = new BinarySearch<FunctionDef, UserDefinedFunction>() {
 				@Override
-				protected int compare(UserDefinedFunction searchItem, FunctionDef arrayItem){
+				protected int compare(UserDefinedFunction searchItem, FunctionDef arrayItem) {
 					return arrayItem.compareTo(searchItem) * -1;
 				}
 			};
@@ -888,13 +922,13 @@ public class DBChecker implements QueryChecker {
 			/* Note: at this stage, it can happen that UDFs can not be yet resolved because the building of
 			 *       their signature depends of other UDFs. That's why, these special cases should be kept
 			 *       for a later resolution try. */
-			for(ADQLObject result : sHandler){
+			for(ADQLObject result : sHandler) {
 				udf = (UserDefinedFunction)result;
 				// if the type of not all parameters are resolved, postpone the resolution:
 				if (!isAllParamTypesResolved(udf))
 					toResolveLater.add(udf);
 				// otherwise:
-				else{
+				else {
 					// search for a match:
 					match = binSearch.search(udf, allowedUdfs);
 					// if no match...
@@ -909,7 +943,7 @@ public class DBChecker implements QueryChecker {
 			// Try to resolve UDFs whose some parameter types are depending of other UDFs:
 			/* Note: we need to iterate from the end in order to resolve first the most wrapped functions
 			 *       (e.g. fct1(fct2(...)) ; fct2 must be resolved before fct1). */
-			for(int i = toResolveLater.size() - 1; i >= 0; i--){
+			for(int i = toResolveLater.size() - 1; i >= 0; i--) {
 				udf = toResolveLater.get(i);
 				// search for a match:
 				match = binSearch.search(udf, allowedUdfs);
@@ -943,8 +977,8 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected final boolean isAllParamTypesResolved(final ADQLFunction fct){
-		for(ADQLOperand op : fct.getParameters()){
+	protected final boolean isAllParamTypesResolved(final ADQLFunction fct) {
+		for(ADQLOperand op : fct.getParameters()) {
 			if (op.isGeometry() == op.isNumeric() && op.isNumeric() == op.isString())
 				return false;
 		}
@@ -960,38 +994,40 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * <p>Operations done in this function:</p>
 	 * <ol>
-	 * 	<li>Check that all geometrical functions are supported</li>
 	 * 	<li>Check that all explicit (string constant) coordinate system definitions are supported</i></li>
 	 * 	<li>Check all STC-S expressions (only in {@link RegionFunction} for the moment) and
 	 * 	    Apply the 2 previous checks on them</li>
 	 * </ol>
 	 *
+	 * <p><i><b>IMPORTANT note:</b>
+	 * 	Since v2.0, the check of supported geometrical functions is performed
+	 * 	directly in ADQLParser through the notion of Optional Features.
+	 * 	The declaration of supported geometrical functions must now be done
+	 * 	with {@link adql.parser.ADQLParser#getSupportedFeatures() ADQLParser.getSupportedFeatures()}
+	 * 	(see also {@link adql.parser.feature.FeatureSet FeatureSet}).
+	 * </i></p>
+	 *
 	 * @param query		Query in which geometries must be checked.
 	 * @param errors	List of errors to complete in this function each time a geometry item is not supported.
 	 *
-	 * @see #resolveGeometryFunctions(ADQLQuery, BinarySearch, UnresolvedIdentifiersException)
 	 * @see #resolveCoordinateSystems(ADQLQuery, UnresolvedIdentifiersException)
 	 * @see #resolveSTCSExpressions(ADQLQuery, BinarySearch, UnresolvedIdentifiersException)
 	 *
 	 * @since 1.3
 	 */
-	protected void checkGeometries(final ADQLQuery query, final UnresolvedIdentifiersException errors){
-		BinarySearch<String,String> binSearch = new BinarySearch<String,String>(){
+	protected void checkGeometries(final ADQLQuery query, final UnresolvedIdentifiersException errors) {
+		BinarySearch<String, String> binSearch = new BinarySearch<String, String>() {
 			@Override
-			protected int compare(String searchItem, String arrayItem){
+			protected int compare(String searchItem, String arrayItem) {
 				return searchItem.compareToIgnoreCase(arrayItem);
 			}
 		};
 
-		// a. Ensure that all used geometry functions are allowed:
-		if (allowedGeo != null)
-			resolveGeometryFunctions(query, binSearch, errors);
-
-		// b. Check whether the coordinate systems are allowed:
+		// a. Check whether the coordinate systems are allowed:
 		if (allowedCoordSys != null)
 			resolveCoordinateSystems(query, errors);
 
-		// c. Check all STC-S expressions (in RegionFunctions only) + the used coordinate systems (if StringConstant only):
+		// b. Check all STC-S expressions (in RegionFunctions only) + the used coordinate systems (if StringConstant only):
 		if (allowedGeo == null || (allowedGeo.length > 0 && binSearch.search("REGION", allowedGeo) >= 0))
 			resolveSTCSExpressions(query, binSearch, errors);
 	}
@@ -1005,13 +1041,19 @@ public class DBChecker implements QueryChecker {
 	 * @see #checkGeometryFunction(String, ADQLFunction, BinarySearch, UnresolvedIdentifiersException)
 	 *
 	 * @since 1.3
+	 * @deprecated	No more used since v2.0. Check of the geometric functions is
+	 *            	now performed directly in ADQLParser. Geometric functions
+	 *            	are optional features and should be declared as such in the
+	 *            	ADQLParser if they are supported (see
+	 *            	{@link adql.parser.ADQLParser#getSupportedFeatures() ADQLParser.getSupportedFeatures()}).
 	 */
-	protected void resolveGeometryFunctions(final ADQLQuery query, final BinarySearch<String,String> binSearch, final UnresolvedIdentifiersException errors){
+	@Deprecated
+	protected final void resolveGeometryFunctions(final ADQLQuery query, final BinarySearch<String, String> binSearch, final UnresolvedIdentifiersException errors) {
 		ISearchHandler sHandler = new SearchGeometryHandler();
 		sHandler.search(query);
 
 		String fctName;
-		for(ADQLObject result : sHandler){
+		for(ADQLObject result : sHandler) {
 			fctName = result.getName();
 			checkGeometryFunction(fctName, (ADQLFunction)result, binSearch, errors);
 		}
@@ -1034,8 +1076,14 @@ public class DBChecker implements QueryChecker {
 	 * @param errors		List of errors to complete in this function each time a geometrical function is not supported.
 	 *
 	 * @since 1.3
+	 * @deprecated	No more used since v2.0. Check of the geometric functions is
+	 *            	now performed directly in ADQLParser. Geometric functions
+	 *            	are optional features and should be declared as such in the
+	 *            	ADQLParser if they are supported (see
+	 *            	{@link adql.parser.ADQLParser#getSupportedFeatures() ADQLParser.getSupportedFeatures()}).
 	 */
-	protected void checkGeometryFunction(final String fctName, final ADQLFunction fct, final BinarySearch<String,String> binSearch, final UnresolvedIdentifiersException errors){
+	@Deprecated
+	protected final void checkGeometryFunction(final String fctName, final ADQLFunction fct, final BinarySearch<String, String> binSearch, final UnresolvedIdentifiersException errors) {
 		int match = -1;
 		if (allowedGeo.length != 0)
 			match = binSearch.search(fctName, allowedGeo);
@@ -1059,7 +1107,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void resolveCoordinateSystems(final ADQLQuery query, final UnresolvedIdentifiersException errors){
+	protected void resolveCoordinateSystems(final ADQLQuery query, final UnresolvedIdentifiersException errors) {
 		ISearchHandler sHandler = new SearchCoordSysHandler();
 		sHandler.search(query);
 		for(ADQLObject result : sHandler)
@@ -1077,11 +1125,11 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void checkCoordinateSystem(final StringConstant adqlCoordSys, final UnresolvedIdentifiersException errors){
+	protected void checkCoordinateSystem(final StringConstant adqlCoordSys, final UnresolvedIdentifiersException errors) {
 		String coordSysStr = adqlCoordSys.getValue();
-		try{
+		try {
 			checkCoordinateSystem(STCS.parseCoordSys(coordSysStr), adqlCoordSys, errors);
-		}catch(ParseException pe){
+		} catch(ParseException pe) {
 			errors.addException(new ParseException(pe.getMessage(), adqlCoordSys.getPosition()));
 		}
 	}
@@ -1095,11 +1143,11 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void checkCoordinateSystem(final CoordSys coordSys, final ADQLOperand operand, final UnresolvedIdentifiersException errors){
-		if (coordSysRegExp != null && coordSys != null && !coordSys.toFullSTCS().matches(coordSysRegExp)){
+	protected void checkCoordinateSystem(final CoordSys coordSys, final ADQLOperand operand, final UnresolvedIdentifiersException errors) {
+		if (coordSysRegExp != null && coordSys != null && !coordSys.toFullSTCS().matches(coordSysRegExp)) {
 			StringBuffer buf = new StringBuffer();
-			if (allowedCoordSys != null){
-				for(String cs : allowedCoordSys){
+			if (allowedCoordSys != null) {
+				for(String cs : allowedCoordSys) {
 					if (buf.length() > 0)
 						buf.append(", ");
 					buf.append(cs);
@@ -1133,7 +1181,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void resolveSTCSExpressions(final ADQLQuery query, final BinarySearch<String,String> binSearch, final UnresolvedIdentifiersException errors){
+	protected void resolveSTCSExpressions(final ADQLQuery query, final BinarySearch<String, String> binSearch, final UnresolvedIdentifiersException errors) {
 		// Search REGION functions:
 		ISearchHandler sHandler = new SearchRegionHandler();
 		sHandler.search(query);
@@ -1141,8 +1189,8 @@ public class DBChecker implements QueryChecker {
 		// Parse and check their STC-S expression:
 		String stcs;
 		Region region;
-		for(ADQLObject result : sHandler){
-			try{
+		for(ADQLObject result : sHandler) {
+			try {
 				// get the STC-S expression:
 				stcs = ((StringConstant)((RegionFunction)result).getParameter(0)).getValue();
 
@@ -1151,7 +1199,7 @@ public class DBChecker implements QueryChecker {
 
 				// check whether the regions (this one + the possible inner ones) and the coordinate systems are allowed:
 				checkRegion(region, (RegionFunction)result, binSearch, errors);
-			}catch(ParseException pe){
+			} catch(ParseException pe) {
 				errors.addException(new ParseException(pe.getMessage(), result.getPosition()));
 			}
 		}
@@ -1177,7 +1225,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void checkRegion(final Region r, final RegionFunction fct, final BinarySearch<String,String> binSearch, final UnresolvedIdentifiersException errors){
+	protected void checkRegion(final Region r, final RegionFunction fct, final BinarySearch<String, String> binSearch, final UnresolvedIdentifiersException errors) {
 		if (r == null)
 			return;
 
@@ -1186,7 +1234,7 @@ public class DBChecker implements QueryChecker {
 			checkCoordinateSystem(r.coordSys, fct, errors);
 
 		// Check that the region type is allowed:
-		if (allowedGeo != null){
+		if (allowedGeo != null) {
 			if (allowedGeo.length == 0)
 				errors.addException(new UnresolvedFunctionException("The region type \"" + r.type + "\" is not available in this implementation!", fct));
 			else
@@ -1194,7 +1242,7 @@ public class DBChecker implements QueryChecker {
 		}
 
 		// Check all the inner regions:
-		if (r.regions != null){
+		if (r.regions != null) {
 			for(Region innerR : r.regions)
 				checkRegion(innerR, fct, binSearch, errors);
 		}
@@ -1234,16 +1282,16 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void checkTypes(final ADQLQuery query, final UnresolvedIdentifiersException errors){
+	protected void checkTypes(final ADQLQuery query, final UnresolvedIdentifiersException errors) {
 		// Search all unknown types:
 		ISearchHandler sHandler = new SearchUnknownTypeHandler();
 		sHandler.search(query);
 
 		// Check whether their type matches the expected one:
 		UnknownType unknown;
-		for(ADQLObject result : sHandler){
+		for(ADQLObject result : sHandler) {
 			unknown = (UnknownType)result;
-			switch(unknown.getExpectedType()){
+			switch(unknown.getExpectedType()) {
 				case 'G':
 				case 'g':
 					if (!unknown.isGeometry())
@@ -1294,11 +1342,11 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected void checkSubQueries(final ADQLQuery query, Stack<SearchColumnList> fathersList, final SearchColumnList availableColumns, final UnresolvedIdentifiersException errors){
+	protected void checkSubQueries(final ADQLQuery query, Stack<SearchColumnList> fathersList, final SearchColumnList availableColumns, final UnresolvedIdentifiersException errors) {
 		// Check sub-queries outside the clause FROM:
 		ISearchHandler sHandler = new SearchSubQueryHandler();
 		sHandler.search(query);
-		if (sHandler.getNbMatch() > 0){
+		if (sHandler.getNbMatch() > 0) {
 
 			// Push the list of columns into the father columns stack:
 			if (fathersList == null)
@@ -1306,10 +1354,10 @@ public class DBChecker implements QueryChecker {
 			fathersList.push(availableColumns);
 
 			// Check each found sub-query:
-			for(ADQLObject result : sHandler){
-				try{
+			for(ADQLObject result : sHandler) {
+				try {
 					check((ADQLQuery)result, fathersList);
-				}catch(UnresolvedIdentifiersException uie){
+				} catch(UnresolvedIdentifiersException uie) {
 					Iterator<ParseException> itPe = uie.getErrors();
 					while(itPe.hasNext())
 						errors.addException(itPe.next());
@@ -1339,7 +1387,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchColumnOutsideGroupByHandler extends SearchColumnHandler {
 		@Override
-		protected boolean goInto(final ADQLObject obj){
+		protected boolean goInto(final ADQLObject obj) {
 			return !(obj instanceof ClauseADQL<?> && ((ClauseADQL<?>)obj).getName() != null && ((ClauseADQL<?>)obj).getName().equalsIgnoreCase("GROUP BY")) && super.goInto(obj);
 		}
 	}
@@ -1352,7 +1400,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchTableHandler extends SimpleSearchHandler {
 		@Override
-		public boolean match(final ADQLObject obj){
+		public boolean match(final ADQLObject obj) {
 			return obj instanceof ADQLTable;
 		}
 	}
@@ -1365,7 +1413,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchWildCardHandler extends SimpleSearchHandler {
 		@Override
-		public boolean match(final ADQLObject obj){
+		public boolean match(final ADQLObject obj) {
 			return (obj instanceof SelectAllColumns) && (((SelectAllColumns)obj).getAdqlTable() != null);
 		}
 	}
@@ -1378,7 +1426,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchColReferenceHandler extends SimpleSearchHandler {
 		@Override
-		public boolean match(final ADQLObject obj){
+		public boolean match(final ADQLObject obj) {
 			return (obj instanceof ColumnReference);
 		}
 	}
@@ -1397,18 +1445,18 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchSubQueryHandler extends SimpleSearchHandler {
 		@Override
-		protected void addMatch(ADQLObject matchObj, ADQLIterator it){
+		protected void addMatch(ADQLObject matchObj, ADQLIterator it) {
 			if (it != null)
 				super.addMatch(matchObj, it);
 		}
 
 		@Override
-		protected boolean goInto(ADQLObject obj){
+		protected boolean goInto(ADQLObject obj) {
 			return super.goInto(obj) && !(obj instanceof FromContent);
 		}
 
 		@Override
-		protected boolean match(ADQLObject obj){
+		protected boolean match(ADQLObject obj) {
 			return (obj instanceof ADQLQuery);
 		}
 	}
@@ -1422,7 +1470,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchUDFHandler extends SimpleSearchHandler {
 		@Override
-		protected boolean match(ADQLObject obj){
+		protected boolean match(ADQLObject obj) {
 			return (obj instanceof UserDefinedFunction);
 		}
 	}
@@ -1441,12 +1489,12 @@ public class DBChecker implements QueryChecker {
 	private static class ReplaceDefaultUDFHandler extends SimpleReplaceHandler {
 		private final UnresolvedIdentifiersException errors;
 
-		public ReplaceDefaultUDFHandler(final UnresolvedIdentifiersException errorsContainer){
+		public ReplaceDefaultUDFHandler(final UnresolvedIdentifiersException errorsContainer) {
 			errors = errorsContainer;
 		}
 
 		@Override
-		protected boolean match(ADQLObject obj){
+		protected boolean match(ADQLObject obj) {
 			return (obj.getClass().getName().equals(DefaultUDF.class.getName())) && (((DefaultUDF)obj).getDefinition() != null) && (((DefaultUDF)obj).getDefinition().getUDFClass() != null);
 			/* Note: detection of DefaultUDF is done on the exact class name rather than using "instanceof" in order to have only direct instances of DefaultUDF,
 			 * and not extensions of it. Indeed, DefaultUDFs are generally created automatically by the ADQLQueryFactory ; so, extensions of it can only be custom
@@ -1454,15 +1502,15 @@ public class DBChecker implements QueryChecker {
 		}
 
 		@Override
-		protected ADQLObject getReplacer(ADQLObject objToReplace) throws UnsupportedOperationException{
-			try{
+		protected ADQLObject getReplacer(ADQLObject objToReplace) throws UnsupportedOperationException {
+			try {
 				// get the associated UDF class:
 				Class<? extends UserDefinedFunction> udfClass = ((DefaultUDF)objToReplace).getDefinition().getUDFClass();
 				// get the constructor with a single parameter of type ADQLOperand[]:
 				Constructor<? extends UserDefinedFunction> constructor = udfClass.getConstructor(ADQLOperand[].class);
 				// create a new instance of this UDF class with the operands stored in the object to replace:
 				return constructor.newInstance((Object)(((DefaultUDF)objToReplace).getParameters())); /* note: without this class, each item of the given array will be considered as a single parameter. */
-			}catch(Exception ex){
+			} catch(Exception ex) {
 				// IF NO INSTANCE CAN BE CREATED...
 				// ...keep the error for further report:
 				errors.addException(new UnresolvedFunctionException("Impossible to represent the function \"" + ((DefaultUDF)objToReplace).getName() + "\": the following error occured while creating this representation: \"" + ((ex instanceof InvocationTargetException) ? "[" + ex.getCause().getClass().getSimpleName() + "] " + ex.getCause().getMessage() : ex.getMessage()) + "\"", (DefaultUDF)objToReplace));
@@ -1481,7 +1529,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchGeometryHandler extends SimpleSearchHandler {
 		@Override
-		protected boolean match(ADQLObject obj){
+		protected boolean match(ADQLObject obj) {
 			return (obj instanceof GeometryFunction);
 		}
 	}
@@ -1501,11 +1549,11 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchUnknownTypeHandler extends SimpleSearchHandler {
 		@Override
-		protected boolean match(ADQLObject obj){
-			if (obj instanceof UnknownType){
+		protected boolean match(ADQLObject obj) {
+			if (obj instanceof UnknownType) {
 				char expected = ((UnknownType)obj).getExpectedType();
 				return (expected == 'G' || expected == 'g' || expected == 'S' || expected == 's' || expected == 'N' || expected == 'n');
-			}else
+			} else
 				return false;
 		}
 	}
@@ -1520,7 +1568,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchCoordSysHandler extends SimpleSearchHandler {
 		@Override
-		protected boolean match(ADQLObject obj){
+		protected boolean match(ADQLObject obj) {
 			if (obj instanceof PointFunction || obj instanceof BoxFunction || obj instanceof CircleFunction || obj instanceof PolygonFunction)
 				return (((GeometryFunction)obj).getCoordinateSystem() instanceof StringConstant);
 			else
@@ -1528,7 +1576,7 @@ public class DBChecker implements QueryChecker {
 		}
 
 		@Override
-		protected void addMatch(ADQLObject matchObj, ADQLIterator it){
+		protected void addMatch(ADQLObject matchObj, ADQLIterator it) {
 			results.add(((GeometryFunction)matchObj).getCoordinateSystem());
 		}
 
@@ -1543,7 +1591,7 @@ public class DBChecker implements QueryChecker {
 	 */
 	private static class SearchRegionHandler extends SimpleSearchHandler {
 		@Override
-		protected boolean match(ADQLObject obj){
+		protected boolean match(ADQLObject obj) {
 			if (obj instanceof RegionFunction)
 				return (((RegionFunction)obj).getParameter(0) instanceof StringConstant);
 			else
@@ -1573,7 +1621,7 @@ public class DBChecker implements QueryChecker {
 	 *
 	 * @since 1.3
 	 */
-	protected static abstract class BinarySearch< T, S > {
+	protected static abstract class BinarySearch<T, S> {
 		private int s, e, m, comp;
 
 		/**
@@ -1590,10 +1638,10 @@ public class DBChecker implements QueryChecker {
 		 *
 		 * @return	The array index of the first item of all matches.
 		 */
-		public int search(final S searchItem, final T[] array){
+		public int search(final S searchItem, final T[] array) {
 			s = 0;
 			e = array.length - 1;
-			while(s < e){
+			while(s < e) {
 				// middle of the sorted array:
 				m = s + ((e - s) / 2);
 				// compare the fct with the middle item of the array:
diff --git a/src/adql/parser/ADQLParser200.java b/src/adql/parser/ADQLParser200.java
index 9d003955df00c2ab584cac6180043f74d8d52bda..42126da635909d306e010f7bdacbcd74c6a3304d 100644
--- a/src/adql/parser/ADQLParser200.java
+++ b/src/adql/parser/ADQLParser200.java
@@ -26,10 +26,14 @@ import java.util.ArrayList;
 import java.util.Stack;
 import java.util.Vector;
 
+import adql.db.exception.UnresolvedIdentifiersException;
+import adql.db.exception.UnsupportedFeatureException;
 import adql.parser.ADQLParserFactory.ADQLVersion;
 import adql.parser.ADQLQueryFactory.JoinType;
 import adql.parser.IdentifierItems.IdentifierItem;
 import adql.parser.feature.FeatureSet;
+import adql.parser.feature.LanguageFeature;
+import adql.query.ADQLObject;
 import adql.query.ADQLOrder;
 import adql.query.ADQLQuery;
 import adql.query.ClauseADQL;
@@ -67,6 +71,7 @@ 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.search.SearchOptionalFeaturesHandler;
 
 /**
 * Parses an ADQL-2.0 query thanks to the {@link ADQLParser200#Query() Query()} function.
@@ -117,6 +122,12 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 	/** Tools to build the object representation of the ADQL query. */
 	private ADQLQueryFactory queryFactory = new ADQLQueryFactory();
 
+	/** Default set of supported language features.
+	* <p><i><b>Note:</b>
+	* 	By default, all optional features are supported.
+	* </i></p> */
+	private FeatureSet supportedFeatures = new FeatureSet(false);
+
 	/** The stack of queries (because there may be some sub-queries). */
 	private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();
 
@@ -137,6 +148,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 	*/
 	public ADQLParser200() {
 		this(new java.io.ByteArrayInputStream("".getBytes()));
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 		setDebug(false);
 	}
 
@@ -188,7 +200,8 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 	*/
 	public ADQLParser200(java.io.InputStream stream, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream);
-		setDebug(false);
+
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 
 		setDebug(false);
 
@@ -230,6 +243,9 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 	*/
 	public ADQLParser200(java.io.InputStream stream, String encoding, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream, encoding);
+
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
+
 		setDebug(false);
 
 		queryChecker = checker;
@@ -271,7 +287,8 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 	*/
 	public ADQLParser200(java.io.Reader reader, QueryChecker checker, ADQLQueryFactory factory) {
 		this(reader);
-		setDebug(false);
+
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 
 		setDebug(false);
 
@@ -312,7 +329,8 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 	*/
 	public ADQLParser200(ADQLParser200TokenManager tm, QueryChecker checker, ADQLQueryFactory factory) {
 		this(tm);
-		setDebug(false);
+
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 
 		setDebug(false);
 
@@ -380,15 +398,13 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 
 	@Override
 	public final FeatureSet getSupportedFeatures() {
-		FeatureSet languageFeatures = new FeatureSet();
-		languageFeatures.unsupportAll();
-		return languageFeatures;
+		return supportedFeatures;
 	}
 
 	@Override
-	public final void setSupportedFeatures(final FeatureSet languageFeatures) {
-		/* Nothing to do here for ADQL-2.0 because no optional feature can be
-		* supported)! */
+	public void setSupportedFeatures(final FeatureSet features) {
+		if (features != null)
+			supportedFeatures = features;
 	}
 
 	/* EXCEPTION HELPER FUNCTION */
@@ -533,7 +549,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a SELECT clause:
 			Select();
@@ -555,7 +571,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a FROM clause:
 			From();
@@ -577,7 +593,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a WHERE clause:
 			Where();
@@ -599,7 +615,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a ORDER BY clause:
 			OrderBy();
@@ -621,7 +637,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a GROUP BY clause:
 			GroupBy();
@@ -972,6 +988,21 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 					jj_consume_token(-1);
 					throw new ParseException();
 			}
+			/* check the optional features before any other check:
+					 * (note: this check is very close to grammar check...hence its higher
+					 *        priority) */
+			UnresolvedIdentifiersException exUnsupportedFeatures = new UnresolvedIdentifiersException("unsupported expression");
+			SearchOptionalFeaturesHandler sFeaturesHandler = new SearchOptionalFeaturesHandler(true, false);
+			sFeaturesHandler.search(q);
+			for(ADQLObject obj : sFeaturesHandler) {
+				if (!supportedFeatures.isSupporting(obj.getFeatureDescription()))
+					exUnsupportedFeatures.addException(new UnsupportedFeatureException(obj));
+			}
+			if (exUnsupportedFeatures.getNbErrors() > 0) {
+				if (true)
+					throw exUnsupportedFeatures;
+			}
+
 			// check the query:
 			if (queryChecker != null)
 				queryChecker.check(q);
@@ -992,7 +1023,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 			TextPosition endPos = null;
 			try {
 				// create the query:
-				query = queryFactory.createQuery();
+				query = queryFactory.createQuery(ADQLVersion.V2_0);
 				stackQuery.push(query);
 			} catch(Exception ex) {
 				{
@@ -4428,65 +4459,6 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 		}
 	}
 
-	private boolean jj_3_18() {
-		if (jj_3R_16())
-			return true;
-		return false;
-	}
-
-	private boolean jj_3R_55() {
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_scan_token(25)) {
-			jj_scanpos = xsp;
-			if (jj_3R_74())
-				return true;
-		}
-		return false;
-	}
-
-	private boolean jj_3R_35() {
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_3R_55())
-			jj_scanpos = xsp;
-		if (jj_scan_token(JOIN))
-			return true;
-		if (jj_3R_56())
-			return true;
-		return false;
-	}
-
-	private boolean jj_3R_34() {
-		if (jj_scan_token(NATURAL))
-			return true;
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_3R_54())
-			jj_scanpos = xsp;
-		if (jj_scan_token(JOIN))
-			return true;
-		return false;
-	}
-
-	private boolean jj_3R_28() {
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_scan_token(36))
-			jj_scanpos = xsp;
-		if (jj_scan_token(BETWEEN))
-			return true;
-		if (jj_3R_51())
-			return true;
-		return false;
-	}
-
-	private boolean jj_3_15() {
-		if (jj_3R_28())
-			return true;
-		return false;
-	}
-
 	private boolean jj_3R_17() {
 		Token xsp;
 		xsp = jj_scanpos;
@@ -6155,6 +6127,65 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 		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;
+		if (jj_scan_token(25)) {
+			jj_scanpos = xsp;
+			if (jj_3R_74())
+				return true;
+		}
+		return false;
+	}
+
+	private boolean jj_3R_35() {
+		Token xsp;
+		xsp = jj_scanpos;
+		if (jj_3R_55())
+			jj_scanpos = xsp;
+		if (jj_scan_token(JOIN))
+			return true;
+		if (jj_3R_56())
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_34() {
+		if (jj_scan_token(NATURAL))
+			return true;
+		Token xsp;
+		xsp = jj_scanpos;
+		if (jj_3R_54())
+			jj_scanpos = xsp;
+		if (jj_scan_token(JOIN))
+			return true;
+		return false;
+	}
+
+	private boolean jj_3R_28() {
+		Token xsp;
+		xsp = jj_scanpos;
+		if (jj_scan_token(36))
+			jj_scanpos = xsp;
+		if (jj_scan_token(BETWEEN))
+			return true;
+		if (jj_3R_51())
+			return true;
+		return false;
+	}
+
+	private boolean jj_3_15() {
+		if (jj_3R_28())
+			return true;
+		return false;
+	}
+
 	/** Generated Token Manager. */
 	public ADQLParser200TokenManager token_source;
 	SimpleCharStream jj_input_stream;
diff --git a/src/adql/parser/ADQLParser200TokenManager.java b/src/adql/parser/ADQLParser200TokenManager.java
index 48f66b8b0551fb5f7947df65e552bc9bb036e685..3e87d17eb1df94451d18b4555352debede0f65b4 100644
--- a/src/adql/parser/ADQLParser200TokenManager.java
+++ b/src/adql/parser/ADQLParser200TokenManager.java
@@ -27,10 +27,12 @@ import java.util.Collection;
 import java.io.FileReader;
 import java.io.IOException;
 import adql.db.exception.UnresolvedIdentifiersException;
+import adql.db.exception.UnsupportedFeatureException;
 import adql.parser.ADQLParserFactory.ADQLVersion;
 import adql.parser.IdentifierItems.IdentifierItem;
 import adql.parser.ADQLQueryFactory.JoinType;
 import adql.parser.feature.FeatureSet;
+import adql.parser.feature.LanguageFeature;
 import adql.query.*;
 import adql.query.from.*;
 import adql.query.constraint.*;
@@ -38,6 +40,7 @@ import adql.query.operand.*;
 import adql.query.operand.function.*;
 import adql.query.operand.function.geometry.*;
 import adql.query.operand.function.geometry.GeometryFunction.GeometryValue;
+import adql.search.SearchOptionalFeaturesHandler;
 import adql.translator.PostgreSQLTranslator;
 import adql.translator.TranslationException;
 
diff --git a/src/adql/parser/ADQLParser201.java b/src/adql/parser/ADQLParser201.java
index 3ad21c96346dcbba44ff5a189e9000cfff7a5b17..189eefb4c3dd005b768b11aaed1c2447ca885af4 100644
--- a/src/adql/parser/ADQLParser201.java
+++ b/src/adql/parser/ADQLParser201.java
@@ -542,7 +542,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a SELECT clause:
 			Select();
@@ -564,7 +564,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a FROM clause:
 			From();
@@ -586,7 +586,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a WHERE clause:
 			Where();
@@ -608,7 +608,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a ORDER BY clause:
 			OrderBy();
@@ -630,7 +630,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a GROUP BY clause:
 			GroupBy();
@@ -1016,7 +1016,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 			TextPosition endPos = null;
 			try {
 				// create the query:
-				query = queryFactory.createQuery();
+				query = queryFactory.createQuery(ADQLVersion.V2_1);
 				stackQuery.push(query);
 			} catch(Exception ex) {
 				{
diff --git a/src/adql/parser/ADQLQueryFactory.java b/src/adql/parser/ADQLQueryFactory.java
index 655b32fd125f04772bef8e4ddb16acfaa11060ea..a75c3c493958eb8eba8f2fa8240f2e247df747de 100644
--- a/src/adql/parser/ADQLQueryFactory.java
+++ b/src/adql/parser/ADQLQueryFactory.java
@@ -23,6 +23,7 @@ package adql.parser;
 import java.util.Collection;
 
 import adql.db.FunctionDef;
+import adql.parser.ADQLParserFactory.ADQLVersion;
 import adql.parser.IdentifierItems.IdentifierItem;
 import adql.query.ADQLOrder;
 import adql.query.ADQLQuery;
@@ -88,7 +89,7 @@ import adql.query.operand.function.string.LowerFunction;
  * </p>
  *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (04/2019)
+ * @version 2.0 (07/2019)
  *
  * @see ADQLParser
  */
@@ -111,10 +112,30 @@ public class ADQLQueryFactory {
 		;
 	}
 
-	public ADQLQuery createQuery() throws Exception {
+	/**
+	 * @deprecated Since v2.0, {@link #createQuery(ADQLVersion)} must be
+	 *             used/extended instead. */
+	@Deprecated
+	public final ADQLQuery createQuery() throws Exception {
 		return new ADQLQuery();
 	}
 
+	/**
+	 * Create an instance of {@link ADQLQuery}.
+	 *
+	 * @param version	The version of the ADQL grammar followed by the query to
+	 *               	create.
+	 *
+	 * @return	A new {@link ADQLQuery}.
+	 *
+	 * @throws Exception	If any error occurs while creating a new query.
+	 *
+	 * @since 2.0
+	 */
+	public ADQLQuery createQuery(final ADQLVersion version) throws Exception {
+		return new ADQLQuery(version);
+	}
+
 	public ADQLTable createTable(final IdentifierItems idItems, final IdentifierItem alias) throws Exception {
 		ADQLTable t = new ADQLTable(idItems.getCatalog(), idItems.getSchema(), idItems.getTable());
 
diff --git a/src/adql/parser/adqlGrammar200.jj b/src/adql/parser/adqlGrammar200.jj
index 19129a3f75a7f7071f04c54d92e680674b298c39..36cffe7ed9bee43888462074da1bc4b2bbe6da81 100644
--- a/src/adql/parser/adqlGrammar200.jj
+++ b/src/adql/parser/adqlGrammar200.jj
@@ -79,6 +79,7 @@ import java.io.FileReader;
 import java.io.IOException;
 
 import adql.db.exception.UnresolvedIdentifiersException;
+import adql.db.exception.UnsupportedFeatureException;
 
 import adql.parser.ADQLParserFactory.ADQLVersion;
 
@@ -87,6 +88,7 @@ import adql.parser.IdentifierItems.IdentifierItem;
 import adql.parser.ADQLQueryFactory.JoinType;
 
 import adql.parser.feature.FeatureSet;
+import adql.parser.feature.LanguageFeature;
 
 import adql.query.*;
 import adql.query.from.*;
@@ -99,6 +101,8 @@ import adql.query.operand.function.*;
 import adql.query.operand.function.geometry.*;
 import adql.query.operand.function.geometry.GeometryFunction.GeometryValue;
 
+import adql.search.SearchOptionalFeaturesHandler;
+
 import adql.translator.PostgreSQLTranslator;
 import adql.translator.TranslationException;
 
@@ -151,6 +155,12 @@ public class ADQLParser200 implements ADQLParser {
 	/** Tools to build the object representation of the ADQL query. */
 	private ADQLQueryFactory queryFactory = new ADQLQueryFactory();
 
+	/** Default set of supported language features.
+	 * <p><i><b>Note:</b>
+	 * 	By default, all optional features are supported.
+	 * </i></p> */
+	private FeatureSet supportedFeatures = new FeatureSet(false);
+
 	/** The stack of queries (because there may be some sub-queries). */
 	private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();
 	
@@ -171,6 +181,7 @@ public class ADQLParser200 implements ADQLParser {
 	*/
 	public ADQLParser200(){
 		this(new java.io.ByteArrayInputStream("".getBytes()));
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 		setDebug(false);
 	}
 	
@@ -222,7 +233,8 @@ public class ADQLParser200 implements ADQLParser {
 	*/
 	public ADQLParser200(java.io.InputStream stream, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream);
-		setDebug(false);
+		
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 		
 		setDebug(false);
 		
@@ -264,6 +276,9 @@ public class ADQLParser200 implements ADQLParser {
 	*/
 	public ADQLParser200(java.io.InputStream stream, String encoding, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream, encoding);
+		
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
+		
 		setDebug(false);
 		
 		queryChecker = checker;
@@ -305,7 +320,8 @@ public class ADQLParser200 implements ADQLParser {
 	*/
 	public ADQLParser200(java.io.Reader reader, QueryChecker checker, ADQLQueryFactory factory) {
 		this(reader);
-		setDebug(false);
+		
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 		
 		setDebug(false);
 		
@@ -346,7 +362,8 @@ public class ADQLParser200 implements ADQLParser {
 	*/
 	public ADQLParser200(ADQLParser200TokenManager tm, QueryChecker checker, ADQLQueryFactory factory) {
 		this(tm);
-		setDebug(false);
+		
+		supportedFeatures.supportAll(LanguageFeature.TYPE_ADQL_GEO);
 		
 		setDebug(false);
 		
@@ -405,14 +422,12 @@ public class ADQLParser200 implements ADQLParser {
 	}
 
 	public final FeatureSet getSupportedFeatures() {
-		FeatureSet languageFeatures = new FeatureSet();
-		languageFeatures.unsupportAll();
-		return languageFeatures;
+		return supportedFeatures;
 	}
 
-	public final void setSupportedFeatures(final FeatureSet languageFeatures) {
-		/* Nothing to do here for ADQL-2.0 because no optional feature can be
-		 * supported)! */
+	public void setSupportedFeatures(final FeatureSet features) {
+		if (features != null)
+			supportedFeatures = features;
 	}
 
 	/* EXCEPTION HELPER FUNCTION */
@@ -552,7 +567,7 @@ public class ADQLParser200 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a SELECT clause:
 			Select();
@@ -574,7 +589,7 @@ public class ADQLParser200 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a FROM clause:
 			From();
@@ -596,7 +611,7 @@ public class ADQLParser200 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a WHERE clause:
 			Where();
@@ -618,7 +633,7 @@ public class ADQLParser200 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a ORDER BY clause:
 			OrderBy();
@@ -640,7 +655,7 @@ public class ADQLParser200 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 
 			// Parse the string as a GROUP BY clause:
 			GroupBy();
@@ -1201,6 +1216,19 @@ TOKEN : {
 ADQLQuery Query(): {ADQLQuery q = null;}{
 	q=QueryExpression() (<EOF> | <EOQ>)
 	{
+		/* check the optional features before any other check:
+		 * (note: this check is very close to grammar check...hence its higher
+		 *        priority) */
+		UnresolvedIdentifiersException exUnsupportedFeatures = new UnresolvedIdentifiersException("unsupported expression");
+		SearchOptionalFeaturesHandler sFeaturesHandler = new SearchOptionalFeaturesHandler(true, false);
+		sFeaturesHandler.search(q);
+		for(ADQLObject obj : sFeaturesHandler) {
+			if (!supportedFeatures.isSupporting(obj.getFeatureDescription()))
+				exUnsupportedFeatures.addException(new UnsupportedFeatureException(obj));
+		}
+		if (exUnsupportedFeatures.getNbErrors() > 0)
+			throw exUnsupportedFeatures;
+	  
 		// check the query:
 		if (queryChecker != null)
 			queryChecker.check(q);
@@ -1213,7 +1241,7 @@ ADQLQuery QueryExpression(): {TextPosition endPos = null;} {
 	{
 		try{
 			// create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_0);
 			stackQuery.push(query);
 		}catch(Exception ex){
 			throw generateParseException(ex);
diff --git a/src/adql/parser/adqlGrammar201.jj b/src/adql/parser/adqlGrammar201.jj
index 3506da9c616935a79691cf256006bcfc2be3202c..2ca25408bb39e8f16ead1837971f4c8c4bd2467c 100644
--- a/src/adql/parser/adqlGrammar201.jj
+++ b/src/adql/parser/adqlGrammar201.jj
@@ -563,7 +563,7 @@ public class ADQLParser201 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a SELECT clause:
 			Select();
@@ -585,7 +585,7 @@ public class ADQLParser201 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a FROM clause:
 			From();
@@ -607,7 +607,7 @@ public class ADQLParser201 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a WHERE clause:
 			Where();
@@ -629,7 +629,7 @@ public class ADQLParser201 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a ORDER BY clause:
 			OrderBy();
@@ -651,7 +651,7 @@ public class ADQLParser201 implements ADQLParser {
 		
 		try {
 			// Create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 
 			// Parse the string as a GROUP BY clause:
 			GroupBy();
@@ -1245,7 +1245,7 @@ ADQLQuery QueryExpression(): {TextPosition endPos = null;} {
 	{
 		try{
 			// create the query:
-			query = queryFactory.createQuery();
+			query = queryFactory.createQuery(ADQLVersion.V2_1);
 			stackQuery.push(query);
 		}catch(Exception ex){
 			throw generateParseException(ex);
diff --git a/src/adql/query/ADQLQuery.java b/src/adql/query/ADQLQuery.java
index fc679f378ca6321dc21e05dca8e4ac8fd0ad6463..1d280337d221af9a997fc4df66ba5c355985b572 100644
--- a/src/adql/query/ADQLQuery.java
+++ b/src/adql/query/ADQLQuery.java
@@ -29,6 +29,8 @@ import adql.db.DBType;
 import adql.db.DBType.DBDatatype;
 import adql.db.DefaultDBColumn;
 import adql.parser.ADQLParser;
+import adql.parser.ADQLParserFactory;
+import adql.parser.ADQLParserFactory.ADQLVersion;
 import adql.parser.ParseException;
 import adql.parser.feature.LanguageFeature;
 import adql.query.from.FromContent;
@@ -59,6 +61,10 @@ public class ADQLQuery implements ADQLObject {
 	 * @since 2.0 */
 	public static final LanguageFeature FEATURE = new LanguageFeature(null, "QUERY", false, "An entire ADQL (sub-)query.");
 
+	/** Version of the ADQL grammar in which this query is written.
+	 * @since 2.0 */
+	private final ADQLVersion adqlVersion;
+
 	/** The ADQL clause SELECT. */
 	private ClauseSelect select;
 
@@ -86,6 +92,21 @@ public class ADQLQuery implements ADQLObject {
 	 * Builds an empty ADQL query.
 	 */
 	public ADQLQuery() {
+		this(ADQLParserFactory.DEFAULT_VERSION);
+	}
+
+	/**
+	 * Builds an empty ADQL query following the specified ADQL grammar.
+	 *
+	 * @param version	Followed version of the ADQL grammar.
+	 *               	<i>If NULL, the
+	 *               	{@link ADQLParserFactory#DEFAULT_VERSION default version}
+	 *               	will be set.</i>
+	 *
+	 * @since 2.0
+	 */
+	public ADQLQuery(final ADQLVersion version) {
+		this.adqlVersion = (version == null ? ADQLParserFactory.DEFAULT_VERSION : version);
 		select = new ClauseSelect();
 		from = null;
 		where = new ClauseConstraints("WHERE");
@@ -103,6 +124,7 @@ public class ADQLQuery implements ADQLObject {
 	 */
 	@SuppressWarnings("unchecked")
 	public ADQLQuery(ADQLQuery toCopy) throws Exception {
+		adqlVersion = toCopy.adqlVersion;
 		select = (ClauseSelect)toCopy.select.getCopy();
 		from = (FromContent)toCopy.from.getCopy();
 		where = (ClauseConstraints)toCopy.where.getCopy();
@@ -117,6 +139,15 @@ public class ADQLQuery implements ADQLObject {
 		return FEATURE;
 	}
 
+	/**
+	 * Get the followed version of the ADQL grammar.
+	 *
+	 * @return	The followed ADQL grammar version.
+	 */
+	public final ADQLVersion getADQLVersion() {
+		return adqlVersion;
+	}
+
 	/**
 	 * Clear all the clauses.
 	 */
diff --git a/test/adql/db/TestDBChecker.java b/test/adql/db/TestDBChecker.java
index 27cace648390def8b5358ba9eec82c8aba1118a9..cb602976ef94ef22bef51634f5fa430ee3e9b437 100644
--- a/test/adql/db/TestDBChecker.java
+++ b/test/adql/db/TestDBChecker.java
@@ -32,6 +32,10 @@ import adql.query.operand.ADQLOperand;
 import adql.query.operand.StringConstant;
 import adql.query.operand.function.DefaultUDF;
 import adql.query.operand.function.UserDefinedFunction;
+import adql.query.operand.function.geometry.CircleFunction;
+import adql.query.operand.function.geometry.ContainsFunction;
+import adql.query.operand.function.geometry.PointFunction;
+import adql.query.operand.function.geometry.RegionFunction;
 import adql.search.SimpleSearchHandler;
 import adql.translator.ADQLTranslator;
 import adql.translator.PostgreSQLTranslator;
@@ -399,7 +403,11 @@ public class TestDBChecker {
 		// Test with several geometries while only the allowed ones:
 		try {
 			parser = parserFactory.createParser();
-			parser.setQueryChecker(new DBChecker(tables, new ArrayList<FunctionDef>(0), Arrays.asList(new String[]{ "CONTAINS", "POINT", "CIRCLE" }), null));
+			parser.getSupportedFeatures().unsupportAll(LanguageFeature.TYPE_ADQL_GEO);
+			parser.getSupportedFeatures().support(ContainsFunction.FEATURE);
+			parser.getSupportedFeatures().support(PointFunction.FEATURE);
+			parser.getSupportedFeatures().support(CircleFunction.FEATURE);
+
 			assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;"));
 		} catch(ParseException pe) {
 			pe.printStackTrace();
@@ -412,18 +420,24 @@ public class TestDBChecker {
 			assertTrue(pe instanceof UnresolvedIdentifiersException);
 			UnresolvedIdentifiersException ex = (UnresolvedIdentifiersException)pe;
 			assertEquals(1, ex.getNbErrors());
-			assertEquals("The geometrical function \"INTERSECTS\" is not available in this implementation!", ex.getErrors().next().getMessage());
+			assertEquals("Unsupported ADQL feature: \"INTERSECTS\" (of type 'ivo://ivoa.net/std/TAPRegExt#features-adql-geo')!", ex.getErrors().next().getMessage());
 		}
 
 		// Test by adding REGION:
 		try {
 			parser = parserFactory.createParser();
-			parser.setQueryChecker(new DBChecker(tables, new ArrayList<FunctionDef>(0), Arrays.asList(new String[]{ "CONTAINS", "POINT", "CIRCLE", "REGION" }), null));
+			parser.getSupportedFeatures().unsupportAll(LanguageFeature.TYPE_ADQL_GEO);
+			parser.getSupportedFeatures().support(ContainsFunction.FEATURE);
+			parser.getSupportedFeatures().support(PointFunction.FEATURE);
+			parser.getSupportedFeatures().support(CircleFunction.FEATURE);
+			parser.getSupportedFeatures().support(RegionFunction.FEATURE);
+
 			assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(REGION('Position 12.3 45.6'), REGION('circle 1.2 2.3 5')) = 1;"));
 		} catch(ParseException pe) {
 			pe.printStackTrace();
 			fail("This query contains several geometries, and all are theoretically allowed: this test should have succeeded!");
 		}
+		// TODO Deal with un/supported Regions inside STC-S!
 		try {
 			parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(REGION('Position 12.3 45.6'), REGION('BOX 1.2 2.3 5 9')) = 1;");
 			fail("This query contains a not-allowed geometry function (BOX): this test should have failed!");
@@ -437,7 +451,8 @@ public class TestDBChecker {
 		// Test with several geometries while none geometry is allowed:
 		try {
 			parser = parserFactory.createParser();
-			parser.setQueryChecker(new DBChecker(tables, new ArrayList<FunctionDef>(0), new ArrayList<String>(0), null));
+			parser.getSupportedFeatures().unsupportAll(LanguageFeature.TYPE_ADQL_GEO);
+
 			parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;");
 			fail("This query contains geometries while they are all forbidden: this test should have failed!");
 		} catch(ParseException pe) {
@@ -445,9 +460,9 @@ public class TestDBChecker {
 			UnresolvedIdentifiersException ex = (UnresolvedIdentifiersException)pe;
 			assertEquals(3, ex.getNbErrors());
 			Iterator<ParseException> itErrors = ex.getErrors();
-			assertEquals("The geometrical function \"CONTAINS\" is not available in this implementation!", itErrors.next().getMessage());
-			assertEquals("The geometrical function \"POINT\" is not available in this implementation!", itErrors.next().getMessage());
-			assertEquals("The geometrical function \"CIRCLE\" is not available in this implementation!", itErrors.next().getMessage());
+			assertEquals("Unsupported ADQL feature: \"CONTAINS\" (of type 'ivo://ivoa.net/std/TAPRegExt#features-adql-geo')!", itErrors.next().getMessage());
+			assertEquals("Unsupported ADQL feature: \"POINT\" (of type 'ivo://ivoa.net/std/TAPRegExt#features-adql-geo')!", itErrors.next().getMessage());
+			assertEquals("Unsupported ADQL feature: \"CIRCLE\" (of type 'ivo://ivoa.net/std/TAPRegExt#features-adql-geo')!", itErrors.next().getMessage());
 		}
 	}
 
diff --git a/test/adql/parser/TestADQLParser.java b/test/adql/parser/TestADQLParser.java
index c955962471bc61846c15dcdba9793cecadeb6193..1e6893cf6d68e5fa945b5c4457283ad6be3d3330 100644
--- a/test/adql/parser/TestADQLParser.java
+++ b/test/adql/parser/TestADQLParser.java
@@ -19,6 +19,7 @@ import adql.query.ADQLQuery;
 import adql.query.from.ADQLJoin;
 import adql.query.from.ADQLTable;
 import adql.query.operand.StringConstant;
+import adql.query.operand.function.geometry.PointFunction;
 import adql.query.operand.function.string.LowerFunction;
 
 public class TestADQLParser {
@@ -427,6 +428,45 @@ public class TestADQLParser {
 			assertEquals(UnsupportedFeatureException.class, err.getClass());
 			assertEquals("Unsupported ADQL feature: \"LOWER\" (of type '" + LanguageFeature.TYPE_ADQL_STRING + "')!", err.getMessage());
 		}
+
+		/* ***************************************************************** */
+		/* NOTE: Geometrical functions are the only optional features in 2.0 */
+		/* ***************************************************************** */
+
+		parser = parserFactory.createParser(ADQLVersion.V2_0);
+
+		// CASE: By default all geometries are supported so if one is used => OK
+		try {
+			assertNotNull(parser.parseQuery("SELECT POINT('', ra, dec) FROM aTable"));
+		} catch(Throwable t) {
+			t.printStackTrace();
+			fail("Unexpected error! This query should have passed. (see console for more details)");
+		}
+
+		// unsupport all features:
+		parser.getSupportedFeatures().unsupportAll();
+
+		// CASE: No geometry supported so if one is used => ERROR
+		try {
+			parser.parseQuery("SELECT POINT('', ra, dec) FROM aTable");
+			fail("The geometrical function \"POINT\" is not declared. This query should not pass.");
+		} catch(Throwable t) {
+			assertEquals(UnresolvedIdentifiersException.class, t.getClass());
+			UnresolvedIdentifiersException allErrors = (UnresolvedIdentifiersException)t;
+			assertEquals(1, allErrors.getNbErrors());
+			assertEquals("Unsupported ADQL feature: \"POINT\" (of type 'ivo://ivoa.net/std/TAPRegExt#features-adql-geo')!", allErrors.getErrors().next().getMessage());
+		}
+
+		// now support only POINT:
+		assertTrue(parser.getSupportedFeatures().support(PointFunction.FEATURE));
+
+		// CASE: Just supporting the only used geometry => OK
+		try {
+			assertNotNull(parser.parseQuery("SELECT POINT('', ra, dec) FROM aTable"));
+		} catch(Throwable t) {
+			t.printStackTrace();
+			fail("Unexpected error! This query should have passed. (see console for more details)");
+		}
 	}
 
 }