diff --git a/src/adql/parser/ADQLParser200.java b/src/adql/parser/ADQLParser200.java
index 42126da635909d306e010f7bdacbcd74c6a3304d..a4b1e1d4843b957b4f85e0c80a2a09b02c6b1f08 100644
--- a/src/adql/parser/ADQLParser200.java
+++ b/src/adql/parser/ADQLParser200.java
@@ -126,7 +126,7 @@ public class ADQLParser200 implements ADQLParser, ADQLParser200Constants {
 	* <p><i><b>Note:</b>
 	* 	By default, all optional features are supported.
 	* </i></p> */
-	private FeatureSet supportedFeatures = new FeatureSet(false);
+	private FeatureSet supportedFeatures = new FeatureSet(false, true);
 
 	/** The stack of queries (because there may be some sub-queries). */
 	private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();
diff --git a/src/adql/parser/ADQLParser201.java b/src/adql/parser/ADQLParser201.java
index 189eefb4c3dd005b768b11aaed1c2447ca885af4..29691f2f4c47d0a2de4f3b755b9b0fedd9371783 100644
--- a/src/adql/parser/ADQLParser201.java
+++ b/src/adql/parser/ADQLParser201.java
@@ -130,7 +130,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 	* <p><i><b>Note:</b>
 	* 	By default, all optional features are supported.
 	* </i></p> */
-	private FeatureSet supportedFeatures = new FeatureSet(true);
+	private FeatureSet supportedFeatures = new FeatureSet(true, true);
 
 	/** The stack of queries (because there may be some sub-queries). */
 	private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();
@@ -199,7 +199,6 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 	*/
 	public ADQLParser201(java.io.InputStream stream, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream);
-		setDebug(false);
 
 		setDebug(false);
 
@@ -241,6 +240,7 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 	*/
 	public ADQLParser201(java.io.InputStream stream, String encoding, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream, encoding);
+
 		setDebug(false);
 
 		queryChecker = checker;
@@ -282,7 +282,6 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 	*/
 	public ADQLParser201(java.io.Reader reader, QueryChecker checker, ADQLQueryFactory factory) {
 		this(reader);
-		setDebug(false);
 
 		setDebug(false);
 
@@ -323,7 +322,6 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 	*/
 	public ADQLParser201(ADQLParser201TokenManager tm, QueryChecker checker, ADQLQueryFactory factory) {
 		this(tm);
-		setDebug(false);
 
 		setDebug(false);
 
@@ -4478,6 +4476,17 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 		}
 	}
 
+	private boolean jj_3R_17() {
+		Token xsp;
+		xsp = jj_scanpos;
+		if (jj_3R_34()) {
+			jj_scanpos = xsp;
+			if (jj_3R_35())
+				return true;
+		}
+		return false;
+	}
+
 	private boolean jj_3_17() {
 		if (jj_3R_29())
 			return true;
@@ -6203,17 +6212,6 @@ public class ADQLParser201 implements ADQLParser, ADQLParser201Constants {
 		return false;
 	}
 
-	private boolean jj_3R_17() {
-		Token xsp;
-		xsp = jj_scanpos;
-		if (jj_3R_34()) {
-			jj_scanpos = xsp;
-			if (jj_3R_35())
-				return true;
-		}
-		return false;
-	}
-
 	/** Generated Token Manager. */
 	public ADQLParser201TokenManager token_source;
 	SimpleCharStream jj_input_stream;
diff --git a/src/adql/parser/adqlGrammar200.jj b/src/adql/parser/adqlGrammar200.jj
index 36cffe7ed9bee43888462074da1bc4b2bbe6da81..a0ac86cdded0645a81ac6381e89239fe7717b6ef 100644
--- a/src/adql/parser/adqlGrammar200.jj
+++ b/src/adql/parser/adqlGrammar200.jj
@@ -159,7 +159,7 @@ public class ADQLParser200 implements ADQLParser {
 	 * <p><i><b>Note:</b>
 	 * 	By default, all optional features are supported.
 	 * </i></p> */
-	private FeatureSet supportedFeatures = new FeatureSet(false);
+	private FeatureSet supportedFeatures = new FeatureSet(false, true);
 
 	/** The stack of queries (because there may be some sub-queries). */
 	private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();
diff --git a/src/adql/parser/adqlGrammar201.jj b/src/adql/parser/adqlGrammar201.jj
index 2ca25408bb39e8f16ead1837971f4c8c4bd2467c..a5db23ba57f97af40297ea223ffc6fbcd64343a9 100644
--- a/src/adql/parser/adqlGrammar201.jj
+++ b/src/adql/parser/adqlGrammar201.jj
@@ -166,7 +166,7 @@ public class ADQLParser201 implements ADQLParser {
 	 * <p><i><b>Note:</b>
 	 * 	By default, all optional features are supported.
 	 * </i></p> */
-	private FeatureSet supportedFeatures = new FeatureSet(true);
+	private FeatureSet supportedFeatures = new FeatureSet(true, true);
 	
 	/** The stack of queries (because there may be some sub-queries). */
 	private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();
@@ -235,7 +235,6 @@ public class ADQLParser201 implements ADQLParser {
 	*/
 	public ADQLParser201(java.io.InputStream stream, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream);
-		setDebug(false);
 		
 		setDebug(false);
 		
@@ -277,6 +276,7 @@ public class ADQLParser201 implements ADQLParser {
 	*/
 	public ADQLParser201(java.io.InputStream stream, String encoding, QueryChecker checker, ADQLQueryFactory factory) {
 		this(stream, encoding);
+		
 		setDebug(false);
 		
 		queryChecker = checker;
@@ -318,7 +318,6 @@ public class ADQLParser201 implements ADQLParser {
 	*/
 	public ADQLParser201(java.io.Reader reader, QueryChecker checker, ADQLQueryFactory factory) {
 		this(reader);
-		setDebug(false);
 		
 		setDebug(false);
 		
@@ -359,7 +358,6 @@ public class ADQLParser201 implements ADQLParser {
 	*/
 	public ADQLParser201(ADQLParser201TokenManager tm, QueryChecker checker, ADQLQueryFactory factory) {
 		this(tm);
-		setDebug(false);
 		
 		setDebug(false);
 		
diff --git a/src/adql/parser/feature/FeatureSet.java b/src/adql/parser/feature/FeatureSet.java
index 022e389b9820782e760afccf7908cec42ce12967..e857e2dc569794361aeb1fdb26e21d3a9de49433 100644
--- a/src/adql/parser/feature/FeatureSet.java
+++ b/src/adql/parser/feature/FeatureSet.java
@@ -110,7 +110,37 @@ import adql.query.operand.function.string.LowerFunction;
  * <p><i><b>Warning:</b>
  * 	Both functions will not work for User Defined Functions that has to be
  * 	added individually in the {@link FeatureSet}.
- * <i></p>
+ * </i></p>
+ *
+ * <h3>Special case of User Defined Functions (UDFs)</h3>
+ *
+ * <p>
+ * 	UDFs are also optional features. However, it is not possible to have a list
+ * 	of available UDFs....indeed, by definition they are <i>user defined</i>.
+ * 	Consequently, supported UDFs must be explicitly declared.
+ * </p>
+ *
+ * <p>
+ * 	However, it is often useful (e.g. when just checking the ADQL syntax
+ * 	of a query) to not raise errors when non-declared UDFs are encountered.
+ * 	For that reason, there is a special option inside this {@link FeatureSet} to
+ * 	allow/forbid non-declared UDFs. This option/flag has just an impact on the
+ * 	result of the function {@link #isSupporting(LanguageFeature)} ; it is not
+ * 	visible in any of the {@link #getSupportedFeatures()} functions.
+ * </p>
+ *
+ * <p>
+ * 	This flag can be checked with {@link #isAnyUdfAllowed()} and can be changed
+ * 	with any of the following functions:
+ * </p>
+ * <ul>
+ * 	<li>{@link #allowAnyUdf(boolean)},</li>
+ * 	<li>{@link #supportAll()},</li>
+ * 	<li>{@link #supportAll(String)} with {@link LanguageFeature#TYPE_UDF},</li>
+ * 	<li>{@link #unsupportAll()},</li>
+ * 	<li>{@link #unsupportAll(String)} with {@link LanguageFeature#TYPE_UDF},</li>
+ * 	<li>and any of the constructors.</li>
+ * </ul>
  *
  * @author Gr&eacute;gory Mantelet (CDS)
  * @version 2.0 (07/2019)
@@ -121,8 +151,16 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	/** Set of all supported features. */
 	protected final Map<String, Set<LanguageFeature>> supportedFeatures;
 
+	/** Indicate whether any UDF (even if not declared) should be considered as
+	 * supported. */
+	protected boolean anyUdfAllowed = false;
+
 	/**
 	 * Create a feature set with all available features supported by default.
+	 *
+	 * <p><i><b>Note:</b>
+	 * 	With this constructor, non-declared UDFs will be considered as supported.
+	 * </i></p>
 	 */
 	public FeatureSet() {
 		this(true);
@@ -132,16 +170,70 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	 * Create a feature set will all available features supported or not,
 	 * depending of the given boolean parameter.
 	 *
+	 * <i>
+	 * <p><b>Note:</b>
+	 * 	With this constructor, non-declared UDFs will be considered as supported
+	 * 	or not depending on the given parameter:
+	 * </p>
+	 * <ul>
+	 * 	<li><code>true</code> will support all available features and will allow
+	 * 		non-declared UDFs,</li>
+	 * 	<li><code>false</code> will un-support all available features and will
+	 * 		forbid non-declared UDFs.</li>
+	 * </ul>
+	 * </i>
+	 *
 	 * @param allSupported	<code>true</code> to support all available features,
 	 *                    	<code>false</code> to not support any.
 	 */
 	public FeatureSet(final boolean allSupported) {
+		this(allSupported, allSupported);
+	}
+
+	/**
+	 * Create a feature set will all available features supported or not,
+	 * depending of the given boolean parameter.
+	 *
+	 * @param allSupported	<code>true</code> to support all available features,
+	 *                    	<code>false</code> to not support any.
+	 * @param allowAnyUdf	<code>true</code> to support any UDF (even if not
+	 *                   	declared),
+	 *                   	<code>false</code> to force declaration of supported
+	 *                   	UDFs.
+	 */
+	public FeatureSet(final boolean allSupported, final boolean allowAnyUdf) {
 		// Init. the list of supported features:
 		supportedFeatures = new HashMap<>();
 
 		// If asked, support all available features:
 		if (allSupported)
 			supportAll();
+
+		// If asked, allow any UDF:
+		this.anyUdfAllowed = allowAnyUdf;
+	}
+
+	/**
+	 * Let specify whether any UDF (even if not declared) should be considered
+	 * as supported or not. If not, UDFs must be explicitly declared to be
+	 * considered as supported (as any other optional language feature).
+	 *
+	 * @param allowed	<code>true</code> to support any UDF,
+	 *               	<code>false</code> to force the declaration of supported
+	 *               	UDFs.
+	 */
+	public void allowAnyUdf(final boolean allowed) {
+		this.anyUdfAllowed = allowed;
+	}
+
+	/**
+	 * Tell whether UDFs are considered as supported even if undeclared.
+	 *
+	 * @return	<code>true</code> if any UDF is considered as supported,
+	 *        	<code>false</code> if supported UDFs must be explicitly declared.
+	 */
+	public boolean isAnyUdfAllowed() {
+		return anyUdfAllowed;
 	}
 
 	/**
@@ -191,6 +283,11 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	/**
 	 * Support all the features of the given type.
 	 *
+	 * <p><i><b>Note:</b>
+	 * 	If the given type is {@link LanguageFeature#TYPE_UDF}, then any
+	 * 	UDF (event if not declared) is considered as supported.
+	 * </i></p>
+	 *
 	 * @param type	The type of language features to support.
 	 *
 	 * @return	<code>true</code> if all the available features of the given
@@ -203,9 +300,17 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	public final boolean supportAll(final String type) {
 		boolean done = false;
 		if (type != null) {
-			for(LanguageFeature feature : availableFeatures) {
-				if (feature.type == type)
-					done = support(feature) || done;
+
+			// CASE: UDF
+			if (LanguageFeature.TYPE_UDF == type)
+				done = anyUdfAllowed = true;
+
+			// OTHERWISE
+			else {
+				for(LanguageFeature feature : availableFeatures) {
+					if (feature.type == type)
+						done = support(feature) || done;
+				}
 			}
 		}
 		return done;
@@ -214,11 +319,19 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	/**
 	 * Support all available features.
 	 *
+	 * <p><i><b>Note:</b>
+	 * 	This function also allows non-declared UDFs.
+	 * </i></p>
+	 *
 	 * @see #getAvailableFeatures()
 	 */
 	public final void supportAll() {
+		// support all available features:
 		for(LanguageFeature feature : availableFeatures)
 			support(feature);
+
+		// also allow non-declared UDFs:
+		anyUdfAllowed = true;
 	}
 
 	/**
@@ -271,6 +384,11 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	/**
 	 * Un-support all the features of the given type.
 	 *
+	 * <p><i><b>Note:</b>
+	 * 	If the given type is {@link LanguageFeature#TYPE_UDF}, then supported
+	 * 	UDFs must be explicitly declared.
+	 * </i></p>
+	 *
 	 * @param type	The type of language features to un-support.
 	 *
 	 * @return	<code>true</code> if all the available features of the given
@@ -283,9 +401,17 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	public final boolean unsupportAll(final String type) {
 		boolean done = false;
 		if (type != null) {
-			for(LanguageFeature feature : availableFeatures) {
-				if (feature.type == type)
-					done = unsupport(feature) || done;
+
+			// CASE: UDF
+			if (LanguageFeature.TYPE_UDF == type)
+				done = !(anyUdfAllowed = false);
+
+			// OTHERWISE
+			else {
+				for(LanguageFeature feature : availableFeatures) {
+					if (feature.type == type)
+						done = unsupport(feature) || done;
+				}
 			}
 		}
 		return done;
@@ -294,11 +420,19 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 	/**
 	 * Un-support all available features.
 	 *
+	 * <p><i><b>Note:</b>
+	 * 	This function also forbids non-declared UDFs.
+	 * </i></p>
+	 *
 	 * @see #getAvailableFeatures()
 	 */
 	public final void unsupportAll() {
+		// unsupport all available features:
 		for(LanguageFeature feature : availableFeatures)
 			unsupport(feature);
+
+		// also unsupport any UDF:
+		anyUdfAllowed = false;
 	}
 
 	/**
@@ -329,10 +463,17 @@ public class FeatureSet implements Iterable<LanguageFeature> {
 		if (feature == null || feature.type == null || !feature.optional)
 			return false;
 
-		// Get the corresponding Set of features:
-		Set<LanguageFeature> features = supportedFeatures.get(feature.type);
+		// CASE: ANY UDF
+		if (anyUdfAllowed && LanguageFeature.TYPE_UDF == feature.type)
+			return true;
+
+		// OTHERWISE
+		else {
+			// Get the corresponding Set of features:
+			Set<LanguageFeature> features = supportedFeatures.get(feature.type);
 
-		return (features != null && features.contains(feature));
+			return (features != null && features.contains(feature));
+		}
 	}
 
 	/**
diff --git a/test/adql/parser/feature/TestFeatureSet.java b/test/adql/parser/feature/TestFeatureSet.java
index 0e57a9d43993b7581b229481b4781c92d85de5ec..1c273f017109f3d42f004446708fe1437cb8bbcc 100644
--- a/test/adql/parser/feature/TestFeatureSet.java
+++ b/test/adql/parser/feature/TestFeatureSet.java
@@ -40,6 +40,7 @@ public class TestFeatureSet {
 			assertTrue(set.supportedFeatures.containsKey(feat.type));
 			assertTrue(set.supportedFeatures.get(feat.type).contains(feat));
 		}
+		assertTrue(set.anyUdfAllowed);
 
 		// With this constructor, none of the available features are supported:
 		set = new FeatureSet(false);
@@ -47,6 +48,48 @@ public class TestFeatureSet {
 			assertNotNull(feat);
 			assertFalse(set.supportedFeatures.containsKey(feat.type));
 		}
+		assertFalse(set.anyUdfAllowed);
+	}
+
+	@Test
+	public void testFeatureSetBooleanBoolean() {
+		/* With this constructor, all available features and non-declared UDFs
+		 * must be already supported: */
+		FeatureSet set = new FeatureSet(true, true);
+		for(LanguageFeature feat : FeatureSet.availableFeatures) {
+			assertNotNull(feat);
+			assertTrue(set.supportedFeatures.containsKey(feat.type));
+			assertTrue(set.supportedFeatures.get(feat.type).contains(feat));
+		}
+		assertTrue(set.anyUdfAllowed);
+
+		/* With this constructor, all available features must be already
+		 * supported BUT NOT non-declared UDFs: */
+		set = new FeatureSet(true, false);
+		for(LanguageFeature feat : FeatureSet.availableFeatures) {
+			assertNotNull(feat);
+			assertTrue(set.supportedFeatures.containsKey(feat.type));
+			assertTrue(set.supportedFeatures.get(feat.type).contains(feat));
+		}
+		assertFalse(set.anyUdfAllowed);
+
+		/* With this constructor, none of the available features are supported,
+		 * as well as non-declared UDFs: */
+		set = new FeatureSet(false, false);
+		for(LanguageFeature feat : FeatureSet.availableFeatures) {
+			assertNotNull(feat);
+			assertFalse(set.supportedFeatures.containsKey(feat.type));
+		}
+		assertFalse(set.anyUdfAllowed);
+
+		/* With this constructor, none of the available features are supported,
+		 * BUT non-declared UDFs are allowed: */
+		set = new FeatureSet(false, true);
+		for(LanguageFeature feat : FeatureSet.availableFeatures) {
+			assertNotNull(feat);
+			assertFalse(set.supportedFeatures.containsKey(feat.type));
+		}
+		assertTrue(set.anyUdfAllowed);
 	}
 
 	@Test
@@ -93,6 +136,11 @@ public class TestFeatureSet {
 				assertTrue(geoSet.contains(feat));
 			}
 		}
+
+		// CASE: UDF => non-declared UDFs are allowed
+		assertFalse(set.isAnyUdfAllowed());
+		assertTrue(set.supportAll(LanguageFeature.TYPE_UDF));
+		assertTrue(set.isAnyUdfAllowed());
 	}
 
 	@Test
@@ -105,6 +153,7 @@ public class TestFeatureSet {
 			assertTrue(set.supportedFeatures.containsKey(feat.type));
 			assertTrue(set.supportedFeatures.get(feat.type).contains(feat));
 		}
+		assertTrue(set.isAnyUdfAllowed());
 	}
 
 	@Test
@@ -155,6 +204,11 @@ public class TestFeatureSet {
 		assertTrue(set.supportedFeatures.containsKey(LanguageFeature.TYPE_ADQL_GEO));
 		assertTrue(set.unsupportAll(LanguageFeature.TYPE_ADQL_GEO));
 		assertFalse(set.supportedFeatures.containsKey(LanguageFeature.TYPE_ADQL_GEO));
+
+		// CASE: UDF => non-declared UDFs are forbidden
+		assertTrue(set.isAnyUdfAllowed());
+		assertTrue(set.unsupportAll(LanguageFeature.TYPE_UDF));
+		assertFalse(set.isAnyUdfAllowed());
 	}
 
 	@Test
@@ -166,6 +220,7 @@ public class TestFeatureSet {
 			assertNotNull(feat);
 			assertFalse(set.supportedFeatures.containsKey(feat.type));
 		}
+		assertFalse(set.isAnyUdfAllowed());
 	}
 
 	@Test