diff --git a/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java b/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java index 352a7428f2007fc59cbf0b3fb7f067d1198857c1..5c9f4c2ca13f8481d075117cb34dec41e5aeeab8 100644 --- a/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java +++ b/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java @@ -46,7 +46,7 @@ public class ExecuteQuery extends FlagJob { try { queryInstance.execute(getTransaction().getAccess()); } catch (final ParsingException e) { - getContainer().addError(ServerMessages.QUERY_PARSING_ERROR); + getContainer().addError(ServerMessages.QUERY_PARSING_ERROR(e.getMessage())); } catch (final UnsupportedOperationException e) { getContainer().addError(ServerMessages.QUERY_EXCEPTION); getContainer() diff --git a/src/main/java/org/caosdb/server/query/CQLParser.g4 b/src/main/java/org/caosdb/server/query/CQLParser.g4 index f4d4e50dd3fe0f35e36fe81c178354bf7f90ae46..eb43e17be1fc7b4161a72124ceb3b583588ca5e1 100644 --- a/src/main/java/org/caosdb/server/query/CQLParser.g4 +++ b/src/main/java/org/caosdb/server/query/CQLParser.g4 @@ -610,7 +610,7 @@ value returns [String str] */ number_with_unit : - ( UNSIGNED_INT | DECIMAL_NUMBER ) + ( UNSIGNED_INT | DECIMAL_NUMBER | HYPHEN WHITE_SPACE? UNSIGNED_INT) (WHITE_SPACE? unit)? ; diff --git a/src/main/java/org/caosdb/server/query/POV.java b/src/main/java/org/caosdb/server/query/POV.java index 7fa1f59021e16a6a3816778811256312ad5d95ea..bdbda62edec341b75e085fb92046fccd685eb42e 100644 --- a/src/main/java/org/caosdb/server/query/POV.java +++ b/src/main/java/org/caosdb/server/query/POV.java @@ -52,7 +52,8 @@ import org.slf4j.LoggerFactory; public class POV implements EntityFilterInterface { public static final Pattern NUMBER_PATTERN = - Pattern.compile("^((?:-\\s*)?[0-9]+(?:\\.[0-9]+)?(?:\\s*[eE]\\s*[+-]?[0-9]+)?)\\s*([^-]*)$"); + Pattern.compile( + "^((?:-\\s*)?[0-9]+(?:\\.[0-9]+)?(?:\\s*[eE]\\s*[+-]?\\s*[0-9]+)?)\\s*([^-]*)$"); private SubProperty subp = null; public static int retry = 10; private int retry_count = 0; @@ -118,12 +119,21 @@ public class POV implements EntityFilterInterface { // try and parse as integer try { - final Matcher m = NUMBER_PATTERN.matcher(value); + final Matcher m = NUMBER_PATTERN.matcher(this.value); if (!m.matches()) { throw new NumberFormatException(); } final String vIntStr = m.group(1); this.vInt = Integer.parseInt(vIntStr.replaceAll("\\s", "")); + if (vIntStr.matches(".*\\s.*")) { + // empty space in scientific notation is a common typo + throw new Query.ParsingException( + "You typed \"" + + vIntStr + + "\". Empty spaces are not allowed in numbers. Did you mean \"" + + vIntStr.replaceAll("\\s", "") + + "\"?"); + } this.unitStr = m.group(2); } catch (final NumberFormatException e) { this.vInt = null; @@ -133,13 +143,22 @@ public class POV implements EntityFilterInterface { if (this.vInt == null) { try { // Doubles are allowed without dots, for example when the integer overflows. - final Matcher m = NUMBER_PATTERN.matcher(value); + final Matcher m = NUMBER_PATTERN.matcher(this.value); if (!m.matches()) { throw new NumberFormatException(); } final String vDoubleStr = m.group(1); this.vDouble = Double.parseDouble(vDoubleStr.replaceAll("\\s", "")); + if (vDoubleStr.matches(".*\\s.*")) { + // empty space in scientific notation is a common typo + throw new Query.ParsingException( + "You typed \"" + + vDoubleStr + + "\". Empty spaces are not allowed in numbers. Did you mean \"" + + vDoubleStr.replaceAll("\\s", "") + + "\"?"); + } this.unitStr = m.group(2); } catch (final NumberFormatException e) { this.vDouble = null; @@ -153,7 +172,7 @@ public class POV implements EntityFilterInterface { this.unit = getUnit(this.unitStr); } catch (final ParserException e) { e.printStackTrace(); - throw new UnsupportedOperationException("Could not parse the unit."); + throw new UnsupportedOperationException("Could not parse the unit:"); } this.stdUnitSig = this.unit.normalize().getSignature(); diff --git a/src/main/java/org/caosdb/server/utils/ServerMessages.java b/src/main/java/org/caosdb/server/utils/ServerMessages.java index 835087ce8825de6c136dabd746534bc42f3240d5..9e18ca9065ec407d2dfc795d173e8d97f11682be 100644 --- a/src/main/java/org/caosdb/server/utils/ServerMessages.java +++ b/src/main/java/org/caosdb/server/utils/ServerMessages.java @@ -617,4 +617,8 @@ public class ServerMessages { return new Message( MessageType.Error, MessageCode.MESSAGE_CODE_UNKNOWN, "You cannot delete yourself."); } + + public static Message QUERY_PARSING_ERROR(String message) { + return new Message(MessageType.Error, MessageCode.MESSAGE_CODE_QUERY_PARSING_ERROR, message); + } } diff --git a/src/test/java/org/caosdb/server/query/POVTest.java b/src/test/java/org/caosdb/server/query/POVTest.java index def9cc65d50d280003eb99c14134db1d4a2afbd9..ac7fcc9bdb1023a8a2a62eed5ad7cc8d3093f52e 100644 --- a/src/test/java/org/caosdb/server/query/POVTest.java +++ b/src/test/java/org/caosdb/server/query/POVTest.java @@ -52,6 +52,7 @@ class POVTest { "-1.2", "2e-323", "2E-323", + "2E- 323", "2 e -323" }) void testNumberPatternMatchDouble(String doubleValue) { diff --git a/src/test/java/org/caosdb/server/query/TestCQL.java b/src/test/java/org/caosdb/server/query/TestCQL.java index 0c6307a53820f202c9b012b0d9da4aee8c24fb99..50f96f6f8bdd856313c5923ffcac1c2e220028dd 100644 --- a/src/test/java/org/caosdb/server/query/TestCQL.java +++ b/src/test/java/org/caosdb/server/query/TestCQL.java @@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -7028,7 +7029,6 @@ public class TestCQL { "2E-323", "-123", "-1e23", - "2 e -23", "3E15m^2", "-3e15m", "-3e15 1/s", @@ -7053,4 +7053,15 @@ public class TestCQL { assertEquals("POV(pname,=," + scientific_notation + ")", pov.toString()); assertTrue(pov.getVDouble() != null || pov.getVInt() != null); } + + @ParameterizedTest + @ValueSource(strings = {"- 123", "- 1e23", "2 e -23", "2E- 323"}) + public void testIssue144WhiteSpaceInNumber(String number) { + CQLLexer lexer; + lexer = new CQLLexer(CharStreams.fromString(this.issue144 + number)); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + + final CQLParser parser = new CQLParser(tokens); + assertThrowsExactly(Query.ParsingException.class, () -> parser.cq()); + } }