diff --git a/src/adql/parser/grammar/ADQLGrammarBase.java b/src/adql/parser/grammar/ADQLGrammarBase.java index eecb0cb18154f02da96863f76f39e7ee830e93e9..71d1ee562ba4914fd1a8ae1fe5684600841f67cd 100644 --- a/src/adql/parser/grammar/ADQLGrammarBase.java +++ b/src/adql/parser/grammar/ADQLGrammarBase.java @@ -133,7 +133,11 @@ public abstract class ADQLGrammarBase implements ADQLGrammar { @Override public final ParseException generateParseException(Exception ex) { if (!(ex instanceof ParseException)) { - ParseException pex = new ParseException("[" + ex.getClass().getName() + "] " + ex.getMessage()); + ParseException pex; + if (ex instanceof IllegalArgumentException) + pex = new ParseException("Incorrect argument: " + ex.getMessage()); + else + pex = new ParseException("[" + ex.getClass().getName() + "] " + ex.getMessage()); pex.setStackTrace(ex.getStackTrace()); return pex; } else diff --git a/src/adql/parser/grammar/adqlGrammar201.jj b/src/adql/parser/grammar/adqlGrammar201.jj index 8568988ea0e5f6cb8b9fefaef22330d1311a8315..9567045d11061f0899b5881ca73e24744e0a7d47 100644 --- a/src/adql/parser/grammar/adqlGrammar201.jj +++ b/src/adql/parser/grammar/adqlGrammar201.jj @@ -892,14 +892,16 @@ ADQLOperand ValueExpression(): {ADQLOperand valueExpr = null; Token left, right; | LOOKAHEAD(3) valueExpr=Factor() /* At this position in this switch, all possibilities (including - * Column()) have already been tested and failed. + * Column() and NumericFunction) have already been tested and failed. * - * So, this final choice actually aims to throw an error set with the + * So, these final choices actually aim to throw an error set with the * current token and with an error message implying that a column name - * was expected (which is generally the case in an ADQL query). - * - * Note: This choice will generally be reached if an unexpected ADQL/SQL - * word is ending the query. */ + * was expected (which is generally the case in an ADQL query) or that + * the parameters of the numeric function are incorrect. */ + | LOOKAHEAD(2) valueExpr=NumericFunction() + /* + * Note: Besides, this particular choice will generally be reached if an + * unexpected ADQL/SQL word is ending the query. */ | valueExpr=Column() ) {return valueExpr;} }catch(Exception ex){ @@ -1003,6 +1005,8 @@ ADQLOperand StringExpression(): {ADQLOperand leftOp; ADQLOperand rightOp = null; if (leftOp instanceof Concatenation){ Concatenation concat = (Concatenation)leftOp; concat.setPosition(new TextPosition(concat.get(0).getPosition(), concat.get(concat.size()-1).getPosition())); + }else if (leftOp instanceof ADQLColumn){ + ((ADQLColumn)leftOp).setExpectedType('S'); } return leftOp; } diff --git a/test/adql/parser/TestADQLParser.java b/test/adql/parser/TestADQLParser.java index f46d1e1d1e862f0350d6a53430153833deb9dbcb..6e3a76c537efbbc71441603746fac215439dddf8 100644 --- a/test/adql/parser/TestADQLParser.java +++ b/test/adql/parser/TestADQLParser.java @@ -55,6 +55,32 @@ public class TestADQLParser { public void tearDown() throws Exception { } + @Test + public void testNumericFunctionParams() { + + ADQLParser parser = new ADQLParser(ADQLVersion.V2_1); + + /* CASE: LOWER can only take a string in parameter, but according to the + * grammar (and BNF), an unsigned numeric is a string (??). + * In such case, an error should be raised: */ + try { + parser.parseQuery("SELECT LOWER(123) FROM foo"); + fail("LOWER can not take a numeric in parameter."); + } catch(Exception ex) { + assertEquals(ParseException.class, ex.getClass()); + assertEquals("Incorrect argument: The ADQL function LOWER must have one parameter of type VARCHAR (i.e. a String)!", ex.getMessage()); + } + + // CASE: Idem for a second parameter: + try { + parser.parseQuery("SELECT IN_UNIT(12.3, 123) FROM foo"); + fail("IN_UNIT can not take a numeric in 2nd parameter."); + } catch(Exception ex) { + assertEquals(ParseException.class, ex.getClass()); + assertEquals("Incorrect argument: The 2nd argument of the ADQL function IN_UNIT (i.e. target unit) must be of type VARCHAR (i.e. a string)!", ex.getMessage()); + } + } + @Test public void testOperatorsPrecedence() {