diff --git a/doc/devel/Development.md b/doc/devel/Development.md
index d0887fcfd98cc4dcc7cb8df5f34257ccf8045fc6..246f80db14eeadfd1b95e062f0b43636d5f6960c 100644
--- a/doc/devel/Development.md
+++ b/doc/devel/Development.md
@@ -20,4 +20,5 @@ writing tests.
 ### Running tests with Maven ###
 - Automatic testing can be done with `make test` or, after compilation, `mvn
   test`.
-- Tests of single modules can be started with `mvn test -Dtest=TextClass`
+- Tests of single modules can be started with `mvn test -Dtest=TestClass`
+- Test of a single method `footest`: `mvn test -Dtest=TestClass#footest`
diff --git a/src/main/java/caosdb/server/query/CQLLexer.g4 b/src/main/java/caosdb/server/query/CQLLexer.g4
index ecf00fada057c7aff99b76642c065709423943e4..62cb12c09c00a2f0005a8b9e2b7d5cc8f6b753e5 100644
--- a/src/main/java/caosdb/server/query/CQLLexer.g4
+++ b/src/main/java/caosdb/server/query/CQLLexer.g4
@@ -349,8 +349,9 @@ ID:
 	[Ii][Dd]
 ;
 
-SLASH:
-	'/'
+// Multiple slashes should be allowed in paths instead of a single slash.
+SLASHES:
+	'/'+
 ;
 
 STAR:
diff --git a/src/main/java/caosdb/server/query/CQLParser.g4 b/src/main/java/caosdb/server/query/CQLParser.g4
index 48205d1fece3309570f40e566078f51c96cab1bd..531b61951c508e7cb4e068a4ee061e05ffa5b847 100644
--- a/src/main/java/caosdb/server/query/CQLParser.g4
+++ b/src/main/java/caosdb/server/query/CQLParser.g4
@@ -456,8 +456,8 @@ location returns [String str]
 :
     atom {$str = $atom.str;}
     |
-	SLASH ?
-	((WHICH | WITH)+ SLASH |( TXT | COLON | HYPHEN | NUM | DOT | ESC_STAR | ESC_BS | ESC_REGEXP_END | STAR )+ SLASH ?)* {$str = $text; }
+	SLASHES ?
+	((WHICH | WITH)+ SLASHES |( TXT | COLON | HYPHEN | NUM | DOT | ESC_STAR | ESC_BS | ESC_REGEXP_END | STAR )+ SLASHES ?)* {$str = $text; }
 ;
 
 atom returns [String str]
diff --git a/src/main/java/caosdb/server/query/StoredAt.java b/src/main/java/caosdb/server/query/StoredAt.java
index cfd2be97fe19906f52986f0b124756cd02952649..543968c76f6df525d5460b88d288a9d4054a9f5e 100644
--- a/src/main/java/caosdb/server/query/StoredAt.java
+++ b/src/main/java/caosdb/server/query/StoredAt.java
@@ -25,6 +25,8 @@ package caosdb.server.query;
 import static java.sql.Types.VARCHAR;
 
 import caosdb.server.query.Query.QueryException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.sql.CallableStatement;
 import java.sql.SQLException;
 import java.util.regex.Matcher;
@@ -34,47 +36,73 @@ import org.jdom2.Element;
 public class StoredAt implements EntityFilterInterface {
 
   public static final java.util.regex.Pattern PATTERN =
-      Pattern.compile("((?:(?:\\\\[\\*\\\\])|[^\\*\\\\])+)?(\\*{2,})?(\\*)?");
-  private final String location;
+    // heading and escaped * and \ removed, then
+    // (part of directory name: no \, no *)?(**)?(*)?
+    Pattern.compile("((?:(?:\\\\[\\*\\\\])|[^\\*\\\\])+)?(\\*{2,})?(\\*)?");
+  private String location;
+  private final String likeLocation;
   private boolean pattern_matching = false;
 
   public StoredAt(final String loc) {
-    final String[] dirs = loc.split("/");
-    final StringBuffer sb = new StringBuffer();
-
-    // if (dirs[0].length() == 0) {
-    // sb.append("/");
-    // }
-    for (final String dir : dirs) {
-      final Matcher m = PATTERN.matcher(dir);
-
-      sb.append("/");
-      while (m.find()) {
-        // part of a directory name
-        if (m.group(1) != null) {
-          sb.append(m.group(1).replace("%", "\\%").replace("_", "\\_").replaceAll("\\\\\\*", "*"));
-        }
-
-        // **
-        if (m.group(2) != null) {
-          this.pattern_matching = true;
-          sb.append("%");
-        }
+    Path locPath = Paths.get(loc);
+    this.location =
+        locPath.normalize().toString().replaceFirst("^/", "") + (loc.endsWith("/") ? "/" : "");
+    this.pattern_matching = requiresPatternMatching();
 
-        // *
-        if (m.group(3) != null) {
-          this.pattern_matching = true;
-          sb.append("%%");
-        }
-      }
+    if (this.pattern_matching) {
+      this.likeLocation = convertLikeLocation();
+    } else {
+      this.likeLocation = null;
     }
+  }
 
-    if (loc.endsWith("/")) {
-      sb.append("/");
+  /**
+   * Does some special character escaping for LIKE query
+   *
+   * <p>The following rules should take place in the future (for now, only a subset is implemented
+   * correctly):
+   *
+   * <ul>
+   *   <li>\* -> * (No special meaning in SQL, even numbers of \ are ignored.)
+   *   <li>* -> %% (Wildcard, to be converted to a more complicated regex without / later.
+   *       Exception: at the beginning of a search expression, convert to %.)
+   *   <li>** -> % (Wildcard, also ***, ****, ... -> %)
+   *   <li>_ -> \_ (Prevent special meaning in SQL)
+   *   <li>% -> \% (Prevent special meaning in SQL)
+   *   <li>Heading `/` is removed
+   * </ul>
+   *
+   * @return The converted String.
+   */
+  String convertLikeLocation() {
+    final String evenB = "(^|[^b*])(bb)*";
+    final String oddB = evenB + "b";
+    final String singleEscapedAst = "b\\*";
+    final String findSingleAst =
+        (evenB + "(" + singleEscapedAst + ")?" + "\\*([^*]|$)").replace("b", "\\\\");
+    final String findMultipleAst =
+        (evenB + "(" + singleEscapedAst + ")?" + "\\*{2,}").replace("b", "\\\\");
+    java.util.regex.Pattern singlePat = Pattern.compile(findSingleAst);
+    java.util.regex.Pattern multiplePat = Pattern.compile(findMultipleAst);
+
+    // Simple SQL escape replacements
+    String converted = this.location.replace("%", "\\%").replace("_", "\\_");
+    // * -> %%, has to run mutliple times, because otherwise the separation between patterns would
+    // need to be larger than one character
+    while (singlePat.matcher(converted).find()) {
+      converted = converted.replaceAll(findSingleAst, "$1$2$3%%$4");
     }
+    // ** -> %
+    converted = converted.replaceAll(findMultipleAst, "$1$2$3%");
+    // All remaining asterisks are now guaranteed to have an odd number of backslashes in front
 
-    this.location =
-        sb.toString().replaceFirst("^/", "").replaceFirst("^%{2,}", "%").replaceFirst("^/", "");
+    // So we can now do \* -> *
+    converted = converted.replaceAll(singleEscapedAst.replace("b", "\\\\"), "*");
+
+    // Final exceptions
+    converted = converted.replaceFirst("^%{2,}", "%"); // .replaceFirst("^/", "");
+
+    return converted;
   }
 
   @Override
@@ -99,14 +127,14 @@ public class StoredAt implements EntityFilterInterface {
       if (this.location == null) { // location
         callSAT.setNull(3, VARCHAR);
       } else {
-        callSAT.setString(3, this.location);
+        callSAT.setString(3, (this.pattern_matching ? this.likeLocation : this.location));
       }
 
       callSAT.setString(4, (this.pattern_matching ? "LIKE" : "="));
       callSAT.execute();
 
-      // ... and then cancel out the wrong guys via regexp
-      if (this.pattern_matching && this.location.contains("%%")) {
+      // ... and then cancel out the wrong guys ('*' matching '/') via regexp
+      if (this.pattern_matching && this.likeLocation.contains("%%")) {
 
         // make a MySQL-conform regexp for this.location:
         // 1) escape literal dots (. = \.)
@@ -116,7 +144,7 @@ public class StoredAt implements EntityFilterInterface {
         // 5) replace non-escaped %% with [^/]*
         // 6) replace non-escaped % with .*
         final String nloc =
-            Pattern.quote(this.location.replace(".", "\\."))
+            Pattern.quote(this.likeLocation.replace(".", "\\."))
                 .replaceFirst("..$", "\\$")
                 .replaceFirst("^..", "^")
                 .replaceAll("(?<!\\\\)%%", "[^/]*")
@@ -139,6 +167,20 @@ public class StoredAt implements EntityFilterInterface {
     query.addBenchmark(this.getClass().getSimpleName(), System.currentTimeMillis() - t1);
   }
 
+  /**
+   * Tests if the location String is intended for pattern matching.
+   *
+   * @return True if the location requires pattern matching for a LIKE query, false otherwise.
+   */
+  boolean requiresPatternMatching() {
+    // Looking for *, preceded by no or an even number of backslashes
+    String requiredPatternStr = "(^|[^b])(bb)*\\*";
+    requiredPatternStr = requiredPatternStr.replace("b", "\\\\");
+    java.util.regex.Pattern REQPATTERN = Pattern.compile(requiredPatternStr);
+    final Matcher m = REQPATTERN.matcher(this.location);
+    return m.find();
+  }
+
   @Override
   public Element toElement() {
     final Element ret = new Element("StoredAt");
@@ -146,8 +188,13 @@ public class StoredAt implements EntityFilterInterface {
     return ret;
   }
 
+  /**
+   * For testing purposes, create a string representing the corresponding query.
+   *
+   * @return The String "SAT(<location>)", where "<location>" is the query string.
+   */
   @Override
   public String toString() {
-    return "SAT(" + this.location + ")";
+    return "SAT(" + (this.pattern_matching ? this.likeLocation : this.location) + ")";
   }
 }
diff --git a/src/test/java/caosdb/server/query/TestCQL.java b/src/test/java/caosdb/server/query/TestCQL.java
index e44110104cbd827bc7f39e126822afd25973a76e..d902d9001e7d07809d3821577d41f0b68deff4cd 100644
--- a/src/test/java/caosdb/server/query/TestCQL.java
+++ b/src/test/java/caosdb/server/query/TestCQL.java
@@ -86,6 +86,9 @@ public class TestCQL {
   String query16a = "FIND FILE WHICH IS STORED AT /bla/bla/bla";
   String query16b = "FIND FILE WHICH IS STORED AT /bla/bla/bla/";
   String query16c = "FIND FILE WHICH IS STORED AT /bla/bla/bla.html";
+  String query16d = "FIND FILE WHICH IS STORED AT //bla///bla.html";
+  String query16e = "FIND FILE WHICH IS STORED AT /bla/bla_bla.html";
+  String query16f = "FIND FILE WHICH IS STORED AT /bla/blubb/../bla.html";
   String query17 = "FIND FILE WHICH IS STORED AT \"/bla/bla/bla\" OR HAS A pname2=val2";
   String query18 = "FIND FILE WHICH HAS A pname2=val2 OR IS STORED AT \"/bla/bla/bla\"";
   String query19 =
@@ -215,7 +218,7 @@ public class TestCQL {
   String query56d = "FIND RECORD WHICH REFERENCES A tom";
 
   @Test
-  public void TestQuery1()
+  public void testQuery1()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query1));
@@ -267,7 +270,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery1a() {
+  public void testQuery1a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query1a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -314,7 +317,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery1b() {
+  public void testQuery1b() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query1b));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -362,7 +365,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery1c() {
+  public void testQuery1c() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query1c));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -410,7 +413,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery1d() {
+  public void testQuery1d() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query1d));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -468,7 +471,7 @@ public class TestCQL {
    * String query1e = "FIND ename . pname1";
    */
   @Test
-  public void TestQuery1e() {
+  public void testQuery1e() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query1e));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -520,7 +523,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery2() {
+  public void testQuery2() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query2));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -587,7 +590,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery3() {
+  public void testQuery3() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query3));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -662,7 +665,7 @@ public class TestCQL {
   }
 
   // @Test
-  // public void TestQuery4() {
+  // public void testQuery4() {
   // CQLLexer lexer;
   // lexer = new CQLLexer(CharStreams.fromString(query4));
   // final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -781,7 +784,7 @@ public class TestCQL {
   // }
 
   @Test
-  public void TestQuery5() {
+  public void testQuery5() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query5));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -885,7 +888,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery6() {
+  public void testQuery6() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query6));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -931,7 +934,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery6a() {
+  public void testQuery6a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query6a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -983,7 +986,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery7() {
+  public void testQuery7() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query7));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1029,7 +1032,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery11() {
+  public void testQuery11() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query11));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1075,7 +1078,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery12() {
+  public void testQuery12() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query12));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1125,7 +1128,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery12a() {
+  public void testQuery12a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query12a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1172,7 +1175,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery13() {
+  public void testQuery13() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query13));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1224,7 +1227,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery13a() {
+  public void testQuery13a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query13a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1276,7 +1279,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery13b() {
+  public void testQuery13b() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query13b));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1328,7 +1331,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery14() {
+  public void testQuery14() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query14));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1387,7 +1390,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery14a() {
+  public void testQuery14a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query14a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1479,7 +1482,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery15() {
+  public void testQuery15() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query15));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1534,7 +1537,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery16() {
+  public void testQuery16() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query16));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1582,7 +1585,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery16a() {
+  public void testQuery16a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query16a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1628,7 +1631,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery16b() {
+  public void testQuery16b() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query16b));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1672,8 +1675,13 @@ public class TestCQL {
     assertEquals("SAT(bla/bla/bla/)", ((StoredAt) sfq.filter).toString());
   }
 
+  /**
+   * 16c: Query String with double slash in path.
+   *
+   * <p>Query string is: "FIND FILE WHICH IS STORED AT /bla/bla/bla.html"
+   */
   @Test
-  public void TestQuery16c() {
+  public void testQuery16c() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query16c));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1718,8 +1726,166 @@ public class TestCQL {
     assertEquals("SAT(bla/bla/bla.html)", ((StoredAt) sfq.filter).toString());
   }
 
+  /**
+   * 16d: Query String with double slash in path.
+   *
+   * <p>Query string is: "FIND FILE WHICH IS STORED AT //bla///bla.html"
+   */
+  @Test
+  public void testQuery16d() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.query16d));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    assertEquals(null, sfq.e);
+    assertEquals(Query.Role.FILE, sfq.r);
+    assertNotNull(sfq.filter);
+    assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName());
+
+    // 4 children: FIND, role, entity_filter, EOF
+    assertEquals(4, sfq.getChildCount());
+    assertEquals("FIND", sfq.getChild(0).getText());
+    assertEquals("FILE", sfq.getChild(1).getText());
+    assertEquals("WHICHIS STORED AT//bla///bla.html", sfq.getChild(2).getText());
+    // entity_filter
+    final ParseTree entity_filter = sfq.getChild(2);
+
+    // 2 children: WHICH_EXP, conjunction
+    assertEquals(2, entity_filter.getChildCount());
+    assertEquals("WHICH", entity_filter.getChild(0).getText());
+    assertEquals("IS STORED AT//bla///bla.html", entity_filter.getChild(1).getText());
+    final ParseTree conjunction = entity_filter.getChild(1);
+
+    // 1 child: storedAt
+    assertEquals(1, conjunction.getChildCount());
+    assertEquals("IS STORED AT//bla///bla.html", conjunction.getChild(0).getText());
+    final ParseTree storedat = conjunction.getChild(0);
+
+    // 2 children: IS_STORED_AT, loc
+    assertEquals(2, storedat.getChildCount());
+    assertEquals("IS STORED AT", storedat.getChild(0).getText());
+    assertEquals("//bla///bla.html", storedat.getChild(1).getText());
+
+    assertEquals(null, sfq.e);
+    assertEquals(Query.Role.FILE, sfq.r);
+    assertNotNull(sfq.filter);
+    assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName());
+
+    assertEquals("SAT(bla/bla.html)", ((StoredAt) sfq.filter).toString());
+  }
+
+  /**
+   * 16e: Query String with underscore in path.
+   *
+   * <p>Query string is "FIND FILE WHICH IS STORED AT /bla/bla_bla.html"
+   */
   @Test
-  public void TestQuery17() {
+  public void testQuery16e() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.query16e));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    assertEquals(null, sfq.e);
+    assertEquals(Query.Role.FILE, sfq.r);
+    assertNotNull(sfq.filter);
+    assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName());
+
+    // 4 children: FIND, role, entity_filter, EOF
+    assertEquals(4, sfq.getChildCount());
+    assertEquals("FIND", sfq.getChild(0).getText());
+    assertEquals("FILE", sfq.getChild(1).getText());
+    assertEquals("WHICHIS STORED AT/bla/bla_bla.html", sfq.getChild(2).getText());
+    // entity_filter
+    final ParseTree entity_filter = sfq.getChild(2);
+
+    // 2 children: WHICH_EXP, conjunction
+    assertEquals(2, entity_filter.getChildCount());
+    assertEquals("WHICH", entity_filter.getChild(0).getText());
+    assertEquals("IS STORED AT/bla/bla_bla.html", entity_filter.getChild(1).getText());
+    final ParseTree conjunction = entity_filter.getChild(1);
+
+    // 1 child: storedAt
+    assertEquals(1, conjunction.getChildCount());
+    assertEquals("IS STORED AT/bla/bla_bla.html", conjunction.getChild(0).getText());
+    final ParseTree storedat = conjunction.getChild(0);
+
+    // 2 children: IS_STORED_AT, loc
+    assertEquals(2, storedat.getChildCount());
+    assertEquals("IS STORED AT", storedat.getChild(0).getText());
+    assertEquals("/bla/bla_bla.html", storedat.getChild(1).getText());
+
+    assertEquals(null, sfq.e);
+    assertEquals(Query.Role.FILE, sfq.r);
+    assertNotNull(sfq.filter);
+    assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName());
+
+    assertEquals("SAT(bla/bla_bla.html)", ((StoredAt) sfq.filter).toString());
+  }
+
+  /**
+   * 16f: Query String with `..` in path.
+   *
+   * <p>Query string is "FIND FILE WHICH IS STORED AT /bla/blubb/../bla.html"
+   */
+  @Test
+  public void testQuery16f() {
+    CQLLexer lexer;
+    lexer = new CQLLexer(CharStreams.fromString(this.query16f));
+    final String origPath = "/bla/blubb/../bla.html";
+    final String absPath = "/bla/bla.html";
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    assertEquals(null, sfq.e);
+    assertEquals(Query.Role.FILE, sfq.r);
+    assertNotNull(sfq.filter);
+    assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName());
+
+    // 4 children: FIND, role, entity_filter, EOF
+    assertEquals(4, sfq.getChildCount());
+    assertEquals("FIND", sfq.getChild(0).getText());
+    assertEquals("FILE", sfq.getChild(1).getText());
+    assertEquals("WHICHIS STORED AT" + origPath, sfq.getChild(2).getText());
+    // entity_filter
+    final ParseTree entity_filter = sfq.getChild(2);
+
+    // 2 children: WHICH_EXP, conjunction
+    assertEquals(2, entity_filter.getChildCount());
+    assertEquals("WHICH", entity_filter.getChild(0).getText());
+    assertEquals("IS STORED AT" + origPath, entity_filter.getChild(1).getText());
+    final ParseTree conjunction = entity_filter.getChild(1);
+
+    // 1 child: storedAt
+    assertEquals(1, conjunction.getChildCount());
+    assertEquals("IS STORED AT" + origPath, conjunction.getChild(0).getText());
+    final ParseTree storedat = conjunction.getChild(0);
+
+    // 2 children: IS_STORED_AT, loc
+    assertEquals(2, storedat.getChildCount());
+    assertEquals("IS STORED AT", storedat.getChild(0).getText());
+    assertEquals(origPath, storedat.getChild(1).getText());
+
+    assertEquals(null, sfq.e);
+    assertEquals(Query.Role.FILE, sfq.r);
+    assertNotNull(sfq.filter);
+    assertEquals(StoredAt.class.getName(), sfq.filter.getClass().getName());
+
+    assertFalse(((StoredAt) sfq.filter).requiresPatternMatching());
+    assertEquals(
+        "SAT(" + absPath.toString().replaceFirst("^/", "") + ")",
+        ((StoredAt) sfq.filter).toString());
+  }
+
+  @Test
+  public void testQuery17() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query17));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1780,7 +1946,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery18() {
+  public void testQuery18() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query18));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1847,7 +2013,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery19() {
+  public void testQuery19() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query19));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1921,7 +2087,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery19a() {
+  public void testQuery19a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query19a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -1990,7 +2156,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery19b() {
+  public void testQuery19b() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query19b));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2059,7 +2225,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery19c() {
+  public void testQuery19c() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query19c));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2132,7 +2298,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery19d() {
+  public void testQuery19d() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query19d));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2201,7 +2367,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery20() {
+  public void testQuery20() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query20));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2280,7 +2446,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery21() {
+  public void testQuery21() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query21));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2349,7 +2515,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery22() {
+  public void testQuery22() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query22));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2409,7 +2575,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery22a() {
+  public void testQuery22a() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query22a));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2474,7 +2640,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery24() {
+  public void testQuery24() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query24));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -2732,7 +2898,7 @@ public class TestCQL {
    * String query25 = "FIND ename . THE GREATEST pname";
    */
   @Test
-  public void TestQuery25()
+  public void testQuery25()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query25));
@@ -2755,7 +2921,7 @@ public class TestCQL {
    * String query26 = "FIND ename . THE SMALLEST pname";
    */
   @Test
-  public void TestQuery26()
+  public void testQuery26()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query26));
@@ -2779,7 +2945,7 @@ public class TestCQL {
    * "FIND SimpleRecordType WITH THE GREATEST SimpleDoubleProperty>0";
    */
   @Test
-  public void TestQuery26a()
+  public void testQuery26a()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query26a));
@@ -3396,7 +3562,7 @@ public class TestCQL {
    * String query27 = "FIND 'Some name with spaces and 1234 numbers'";
    */
   @Test
-  public void TestQuery27()
+  public void testQuery27()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query27));
@@ -3421,7 +3587,7 @@ public class TestCQL {
    * String query27a = "FIND \"Some name with spaces and 1234 numbers\"";
    */
   @Test
-  public void TestQuery27a()
+  public void testQuery27a()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query27a));
@@ -3446,7 +3612,7 @@ public class TestCQL {
    * String query27b = "FIND 'Some name with spaces and 1234 numbers and \"'";
    */
   @Test
-  public void TestQuery27b()
+  public void testQuery27b()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query27b));
@@ -3472,7 +3638,7 @@ public class TestCQL {
    * "FIND 'Some name with spaces and 1234 numbers and \\*'";
    */
   @Test
-  public void TestQuery27c()
+  public void testQuery27c()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query27c));
@@ -3497,7 +3663,7 @@ public class TestCQL {
    * String query27d = "FIND 'Some name with spaces and 1234 numbers and *'";
    */
   @Test
-  public void TestQuery27d()
+  public void testQuery27d()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query27d));
@@ -3522,7 +3688,7 @@ public class TestCQL {
    * String query28 = "FIND ename . pname=2.0";
    */
   @Test
-  public void TestQuery28()
+  public void testQuery28()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query28));
@@ -3552,7 +3718,7 @@ public class TestCQL {
    * String query28a ="FIND ename . pname=2.0prop=test";
    */
   @Test
-  public void TestQuery28a()
+  public void testQuery28a()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query28a));
@@ -3828,7 +3994,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery29()
+  public void testQuery29()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query29));
@@ -3863,7 +4029,7 @@ public class TestCQL {
   }
 
   @Test
-  public void TestQuery29a()
+  public void testQuery29a()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query29a));
@@ -4088,7 +4254,7 @@ public class TestCQL {
    * "FIND RECORD.CREATED BY 'henrik.tomwoerden' AND THE GREATEST ID";
    */
   @Test
-  public void TestQuery30()
+  public void testQuery30()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query30));
@@ -4127,7 +4293,7 @@ public class TestCQL {
 
   /** String query31 = "FIND PROPERTIES WHICH ARE INSERTED TODAY"; */
   @Test
-  public void TestQuery31() {
+  public void testQuery31() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query31));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -4445,7 +4611,7 @@ public class TestCQL {
 
   /** String query33 = "FIND ename WITH a date IN 2015"; */
   @Test
-  public void TestQuery33() {
+  public void testQuery33() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query33));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -4484,7 +4650,7 @@ public class TestCQL {
 
   /** String query34 = "FIND ename WITH a date NOT IN 2015"; */
   @Test
-  public void TestQuery34() {
+  public void testQuery34() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query34));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -4524,7 +4690,7 @@ public class TestCQL {
 
   /** String query35 = "FIND ename WITH a date IN 2015-01-01"; */
   @Test
-  public void TestQuery35() {
+  public void testQuery35() {
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query35));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -4827,10 +4993,11 @@ public class TestCQL {
 
     assertTrue(sfq.filter instanceof StoredAt);
     final StoredAt storedAt = (StoredAt) sfq.filter;
-    assertEquals("SAT(%%)", storedAt.toString());
+    assertTrue(storedAt.requiresPatternMatching());
+    assertEquals("SAT(%)", storedAt.toString());
   }
 
-  /** String query43 = "FIND FILE WHICH IS STORED AT /* /"; */
+  /** String query43 = "FIND FILE WHICH IS STORED AT /* /" (without the space); */
   @Test
   public void testQuery43() {
     CQLLexer lexer;
@@ -4864,7 +5031,8 @@ public class TestCQL {
 
     assertTrue(sfq.filter instanceof StoredAt);
     final StoredAt storedAt = (StoredAt) sfq.filter;
-    assertEquals("SAT(%%/)", storedAt.toString());
+    assertTrue(storedAt.requiresPatternMatching());
+    assertEquals("SAT(%/)", storedAt.toString());
   }
 
   /** String query44 = "FIND FILE WHICH IS STORED AT /** /"; */
@@ -4975,7 +5143,7 @@ public class TestCQL {
 
     assertTrue(sfq.filter instanceof StoredAt);
     final StoredAt storedAt = (StoredAt) sfq.filter;
-    assertEquals("SAT(%%/%%)", storedAt.toString());
+    assertEquals("SAT(%/%%)", storedAt.toString());
   }
 
   /** String query47 = "FIND FILE WHICH IS STORED AT /* /*.acq"; */
@@ -5012,7 +5180,7 @@ public class TestCQL {
 
     assertTrue(sfq.filter instanceof StoredAt);
     final StoredAt storedAt = (StoredAt) sfq.filter;
-    assertEquals("SAT(%%/%%.acq)", storedAt.toString());
+    assertEquals("SAT(%/%%.acq)", storedAt.toString());
   }
 
   /** String query48 = "FIND FILE WHICH IS STORED AT /** /*.acq"; */
@@ -5086,7 +5254,7 @@ public class TestCQL {
 
     assertTrue(sfq.filter instanceof StoredAt);
     final StoredAt storedAt = (StoredAt) sfq.filter;
-    assertEquals("SAT(%%.acq)", storedAt.toString());
+    assertEquals("SAT(%.acq)", storedAt.toString());
   }
 
   /** String query50 = "FIND FILE WHICH IS STORED AT *.acq"; */