From 16f3b1feb04fb02b5e060162610165e5a1053f32 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Thu, 13 Apr 2023 21:50:54 +0200
Subject: [PATCH] BUG: fix for server#143

---
 .../java/org/caosdb/server/query/CQLLexer.g4  | 35 ++++++++++++++-----
 .../java/org/caosdb/server/query/CQLParser.g4 | 23 ++++++------
 .../java/org/caosdb/server/query/POV.java     |  6 ++--
 .../java/org/caosdb/server/query/POVTest.java |  2 +-
 .../java/org/caosdb/server/query/TestCQL.java | 24 ++++++++++++-
 5 files changed, 65 insertions(+), 25 deletions(-)

diff --git a/src/main/java/org/caosdb/server/query/CQLLexer.g4 b/src/main/java/org/caosdb/server/query/CQLLexer.g4
index 518d1628..1dc3ad49 100644
--- a/src/main/java/org/caosdb/server/query/CQLLexer.g4
+++ b/src/main/java/org/caosdb/server/query/CQLLexer.g4
@@ -523,30 +523,49 @@ TODAY:
 ;
 
 /** */
-HYPHEN:
-    '-'
+COLON:
+    ':'
+;
+
+/** Matches signed and unsigned numbers with decimal points, also numbers in scientific notation. */
+DECIMAL_NUMBER:
+    (HYPHEN_f WHITE_SPACE_f?)? 
+    ( NUM_f? DOT NUM_f WHITE_SPACE_f? E_NOTATION_f?
+    | NUM_f WHITE_SPACE_f? E_NOTATION_f
+    )
 ;
 
 /** */
-COLON:
-    ':'
+HYPHEN:
+    HYPHEN_f
 ;
 
 /** */
-NUM:
+fragment
+HYPHEN_f:
+	'-'
+;
+
+/** Matches only unsigned integer numbers. */
+UNSIGNED_INT:
     NUM_f
-    | DOT NUM_f
-    | NUM_f DOT NUM_f
 ;
 
 /** */
+fragment
 NUM_f:
     ('0'..'9')+
 ;
 
+/** */
+fragment
+E_NOTATION_f:
+	[Ee] WHITE_SPACE_f? [+-]? WHITE_SPACE_f? NUM_f
+;
+
 /** */
 TXT:
-    ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '-' {_input.LA(1) != '>'}? | '+' | '&' | ';' | ',' | '$' | ':' | '%' | '^' | '~' {_input.LA(1) != '='}? | '`' | '´' | 'ö' | 'ä' | 'ß' | 'ü' | 'Ö' | 'Ä' | 'Ü' | '@' | '[' | ']' | '{' | '}' )+
+    ('a'..'z' | 'A'..'Z' | NUM_f | '_' | '-' {_input.LA(1) != '>'}? | '+' | '&' | ';' | ',' | '$' | ':' | '%' | '^' | '~' {_input.LA(1) != '='}? | '`' | '´' | 'ö' | 'ä' | 'ß' | 'ü' | 'Ö' | 'Ä' | 'Ü' | '@' | '[' | ']' | '{' | '}' )+
 ;
 
 /** */
diff --git a/src/main/java/org/caosdb/server/query/CQLParser.g4 b/src/main/java/org/caosdb/server/query/CQLParser.g4
index bcb4645a..f4d4e50d 100644
--- a/src/main/java/org/caosdb/server/query/CQLParser.g4
+++ b/src/main/java/org/caosdb/server/query/CQLParser.g4
@@ -281,20 +281,20 @@ transaction_time returns [String tqp, String op]
  */
 datetime
 :
-    NUM // year
+    UNSIGNED_INT // year
     (
-        HYPHEN NUM // mon
+        HYPHEN UNSIGNED_INT // mon
         (
-            HYPHEN NUM // day of mon
+            HYPHEN UNSIGNED_INT // day of mon
             (
                 (m=TXT {$m.text.equals("T")}?)?// compliance with iso datetime
-                NUM // hour
+                UNSIGNED_INT // hour
                 (
-                    COLON NUM // minut
+                    COLON UNSIGNED_INT // minut
                     (
-                        COLON NUM // sec
+                        COLON UNSIGNED_INT // sec
                         (
-                            DOT NUM // millisec
+                            DOT UNSIGNED_INT // millisec
                         )?
                     )?
                 )?
@@ -578,7 +578,7 @@ property returns [Query.Pattern pp, String agg]locals [StringBuffer sb]
         | like_pattern {$pp = $like_pattern.ep;}
         | ( double_quoted {$pp = $double_quoted.ep;} )
         | ( single_quoted {$pp = $single_quoted.ep;} )
-        | ((m=TXT | m=NUM | m=REGEXP_MARKER | m=ENTITY){$sb.append($m.text);})+  {$pp = new Query.Pattern($sb.toString(), Query.Pattern.TYPE_NORMAL);}
+        | ((m=TXT | m=UNSIGNED_INT | m=UNSIGNED_DECIMAL_NUMBER | m=REGEXP_MARKER | m=ENTITY){$sb.append($m.text);})+  {$pp = new Query.Pattern($sb.toString(), Query.Pattern.TYPE_NORMAL);}
     )
     WHITE_SPACE?
 ;
@@ -610,9 +610,8 @@ value returns [String str]
  */
 number_with_unit
 :
-    HYPHEN??
-    NUM
-    (WHITE_SPACE?? unit)?
+    ( UNSIGNED_INT | DECIMAL_NUMBER )
+    (WHITE_SPACE? unit)?
 ;
 
 /**
@@ -623,7 +622,7 @@ unit
     (~(WHITE_SPACE | WHICH | HAS_A | WITH_A | WHERE | DOT | AND | OR | RPAREN ))
     (~(WHITE_SPACE))*
     |
-    NUM SLASH (~(WHITE_SPACE))+
+    HYPHEN?? UNSIGNED_INT SLASH (~(WHITE_SPACE))+
 ;
 
 /**
diff --git a/src/main/java/org/caosdb/server/query/POV.java b/src/main/java/org/caosdb/server/query/POV.java
index 7c5176b9..7fa1f590 100644
--- a/src/main/java/org/caosdb/server/query/POV.java
+++ b/src/main/java/org/caosdb/server/query/POV.java
@@ -52,7 +52,7 @@ import org.slf4j.LoggerFactory;
 
 public class POV implements EntityFilterInterface {
   public static final Pattern NUMBER_PATTERN =
-      Pattern.compile("^((?:-\\s*)?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)\\s*([^-]*)$");
+      Pattern.compile("^((?:-\\s*)?[0-9]+(?:\\.[0-9]+)?(?:\\s*[eE]\\s*[+-]?[0-9]+)?)\\s*([^-]*)$");
   private SubProperty subp = null;
   public static int retry = 10;
   private int retry_count = 0;
@@ -123,7 +123,7 @@ public class POV implements EntityFilterInterface {
           throw new NumberFormatException();
         }
         final String vIntStr = m.group(1);
-        this.vInt = Integer.parseInt(vIntStr);
+        this.vInt = Integer.parseInt(vIntStr.replaceAll("\\s", ""));
         this.unitStr = m.group(2);
       } catch (final NumberFormatException e) {
         this.vInt = null;
@@ -139,7 +139,7 @@ public class POV implements EntityFilterInterface {
           }
           final String vDoubleStr = m.group(1);
 
-          this.vDouble = Double.parseDouble(vDoubleStr);
+          this.vDouble = Double.parseDouble(vDoubleStr.replaceAll("\\s", ""));
           this.unitStr = m.group(2);
         } catch (final NumberFormatException e) {
           this.vDouble = null;
diff --git a/src/test/java/org/caosdb/server/query/POVTest.java b/src/test/java/org/caosdb/server/query/POVTest.java
index 9f2b9576..bf438a84 100644
--- a/src/test/java/org/caosdb/server/query/POVTest.java
+++ b/src/test/java/org/caosdb/server/query/POVTest.java
@@ -37,7 +37,7 @@ class POVTest {
   @ValueSource(
       strings = {
         "1e+3", "1E+3", "5e9", "5E9", "16", MAX_INT, MIN_INT, "0", "-0", "1", "- 1", "-1", "2e-323",
-        "2E-323"
+        "2E-323", "2 e -23"
       })
   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 053a4827..0c6307a5 100644
--- a/src/test/java/org/caosdb/server/query/TestCQL.java
+++ b/src/test/java/org/caosdb/server/query/TestCQL.java
@@ -7018,7 +7018,22 @@ public class TestCQL {
   }
 
   @ParameterizedTest
-  @ValueSource(strings = {"1e+23", "1E+23", "5e22", "5E22", "2e-323", "2E-323"})
+  @ValueSource(
+      strings = {
+        "1e+23",
+        "1E+23",
+        "5e22",
+        "5E22",
+        "2e-323",
+        "2E-323",
+        "-123",
+        "-1e23",
+        "2 e -23",
+        "3E15m^2",
+        "-3e15m",
+        "-3e15 1/s",
+        "3e15 m^2"
+      })
   public void testIssue144(String scientific_notation) {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.issue144 + scientific_notation));
@@ -7027,8 +7042,15 @@ public class TestCQL {
     final CQLParser parser = new CQLParser(tokens);
     final CqContext sfq = parser.cq();
 
+    for (final Token t : tokens.getTokens()) {
+      System.out.println(t.toString());
+    }
+
+    System.out.println(sfq.toStringTree(parser));
+
     assertTrue(sfq.filter instanceof POV);
     POV pov = (POV) sfq.filter;
     assertEquals("POV(pname,=," + scientific_notation + ")", pov.toString());
+    assertTrue(pov.getVDouble() != null || pov.getVInt() != null);
   }
 }
-- 
GitLab