Skip to content
Snippets Groups Projects
Commit 475fcb65 authored by gmantele's avatar gmantele
Browse files

[ADQL] Fix identification of UDFs using a list of function definitions.

Functions whose some parameters are another function were not correctly
identified: since the inner functions were not yet identified, their type
was UNKNOWN and so it makes the identification of the parent function
much easier since an UNKNOWN parameter is not checked. But, it was a
problem if the parameter occurs to be finally of the wrong type.
parent 09e81ed7
No related branches found
No related tags found
No related merge requests found
...@@ -16,8 +16,8 @@ package adql.db; ...@@ -16,8 +16,8 @@ package adql.db;
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>.
* *
* Copyright 2011,2013-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Copyright 2011-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI) * Astronomisches Rechen Institut (ARI)
*/ */
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
...@@ -97,7 +97,7 @@ import adql.search.SimpleSearchHandler; ...@@ -97,7 +97,7 @@ import adql.search.SimpleSearchHandler;
* </i></p> * </i></p>
* *
* @author Gr&eacute;gory Mantelet (CDS;ARI) * @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 1.4 (08/2015) * @version 1.4 (03/2016)
*/ */
public class DBChecker implements QueryChecker { public class DBChecker implements QueryChecker {
...@@ -813,24 +813,26 @@ public class DBChecker implements QueryChecker { ...@@ -813,24 +813,26 @@ public class DBChecker implements QueryChecker {
* for a later resolution try. */ * for a later resolution try. */
for(ADQLObject result : sHandler){ for(ADQLObject result : sHandler){
udf = (UserDefinedFunction)result; udf = (UserDefinedFunction)result;
// search for a match: // if the type of not all parameters are resolved, postpone the resolution:
match = binSearch.search(udf, allowedUdfs); if (!isAllParamTypesResolved(udf))
// if no match... toResolveLater.add(udf);
if (match < 0){ // otherwise:
// ...if the type of all parameters is resolved, add an error (no match is possible): else{
if (isAllParamTypesResolved(udf)) // search for a match:
match = binSearch.search(udf, allowedUdfs);
// if no match...
if (match < 0)
errors.addException(new UnresolvedFunctionException(udf)); errors.addException(new UnresolvedFunctionException(udf));
// ...otherwise, try to resolved it later (when other UDFs will be mostly resolved): // if there is a match, metadata may be attached (particularly if the function is built automatically by the syntactic parser):
else else if (udf instanceof DefaultUDF)
toResolveLater.add(udf); ((DefaultUDF)udf).setDefinition(allowedUdfs[match]);
} }
// if there is a match, metadata may be attached (particularly if the function is built automatically by the syntactic parser):
else if (udf instanceof DefaultUDF)
((DefaultUDF)udf).setDefinition(allowedUdfs[match]);
} }
// Try to resolve UDFs whose some parameter types are depending of other UDFs: // Try to resolve UDFs whose some parameter types are depending of other UDFs:
for(int i = 0; i < toResolveLater.size(); i++){ /* 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--){
udf = toResolveLater.get(i); udf = toResolveLater.get(i);
// search for a match: // search for a match:
match = binSearch.search(udf, allowedUdfs); match = binSearch.search(udf, allowedUdfs);
...@@ -866,7 +868,7 @@ public class DBChecker implements QueryChecker { ...@@ -866,7 +868,7 @@ public class DBChecker implements QueryChecker {
*/ */
protected final boolean isAllParamTypesResolved(final ADQLFunction fct){ protected final boolean isAllParamTypesResolved(final ADQLFunction fct){
for(ADQLOperand op : fct.getParameters()){ for(ADQLOperand op : fct.getParameters()){
if (op.isNumeric() == op.isString()) if (op.isGeometry() == op.isNumeric() && op.isNumeric() == op.isString())
return false; return false;
} }
return true; return true;
......
...@@ -675,6 +675,31 @@ public class TestDBChecker { ...@@ -675,6 +675,31 @@ public class TestDBChecker {
assertEquals("Type mismatch! A numeric value was expected instead of \"titi()\".", ex.getErrors().next().getMessage()); assertEquals("Type mismatch! A numeric value was expected instead of \"titi()\".", ex.getErrors().next().getMessage());
} }
// Try with functions wrapped on 2 levels:
// i.e. fct1('blabla', fct2(fct3('blabla')))
FunctionDef[] complexFcts = new FunctionDef[3];
complexFcts[0] = new FunctionDef("fct1", new DBType(DBDatatype.VARCHAR), new FunctionParam[]{new FunctionParam("str", new DBType(DBDatatype.VARCHAR)),new FunctionParam("num", new DBType(DBDatatype.INTEGER))});
complexFcts[1] = new FunctionDef("fct2", new DBType(DBDatatype.INTEGER), new FunctionParam[]{new FunctionParam("str", new DBType(DBDatatype.VARCHAR))});
complexFcts[2] = new FunctionDef("fct3", new DBType(DBDatatype.VARCHAR), new FunctionParam[]{new FunctionParam("str", new DBType(DBDatatype.VARCHAR))});
parser = new ADQLParser(new DBChecker(tables, Arrays.asList(complexFcts)));
// With parameters of the good type:
try{
assertNotNull(parser.parseQuery("SELECT fct1('blabla', fct2(fct3('blabla'))) FROM foo"));
}catch(ParseException pe){
pe.printStackTrace();
fail("Types are matching: this test should have succeeded!");
}
// With parameters of the bad type:
try{
parser.parseQuery("SELECT fct2(fct1('blabla', fct3('blabla'))) FROM foo");
fail("Parameters types are not matching: the parsing should have failed!");
}catch(ParseException pe){
assertEquals(UnresolvedIdentifiersException.class, pe.getClass());
assertEquals(1, ((UnresolvedIdentifiersException)pe).getNbErrors());
ParseException innerPe = ((UnresolvedIdentifiersException)pe).getErrors().next();
assertEquals("Unresolved function: \"fct1('blabla', fct3('blabla'))\"! No UDF has been defined or found with the signature: fct1(STRING, STRING).", innerPe.getMessage());
}
// CLEAR ALL UDFs AND ALLOW UNKNOWN FUNCTION: // CLEAR ALL UDFs AND ALLOW UNKNOWN FUNCTION:
parser = new ADQLParser(new DBChecker(tables, null)); parser = new ADQLParser(new DBChecker(tables, null));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment