From cd6c702b79fc3e145453ad557c9800c8c3356d07 Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Thu, 7 Jul 2022 22:20:58 +0200 Subject: [PATCH] TST: unit test for caosdb-server#130 --- .../java/org/caosdb/server/query/CQLLexer.g4 | 45 +++++++++++++++++++ .../java/org/caosdb/server/query/CQLParser.g4 | 19 ++++++-- .../java/org/caosdb/server/query/Query.java | 8 +--- .../java/org/caosdb/server/query/TestCQL.java | 38 ++++++++++++++++ 4 files changed, 100 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/caosdb/server/query/CQLLexer.g4 b/src/main/java/org/caosdb/server/query/CQLLexer.g4 index a091027c..8f58cb2c 100644 --- a/src/main/java/org/caosdb/server/query/CQLLexer.g4 +++ b/src/main/java/org/caosdb/server/query/CQLLexer.g4 @@ -498,18 +498,63 @@ mode DOUBLE_QUOTE_MODE; ; +mode SELECT_DOUBLE_QUOTED; + + SELECT_DOUBLE_QUOTE_ESCAPED: + ESC_MARKER + '"' + ; + + SELECT_DOUBLE_QUOTE_END: + '"' {setText("");} -> mode(SELECT_MODE) + ; + + SELECT_DOUBLE_QUOTE_TXT: + . + ; + +mode SELECT_SINGLE_QUOTED; + + SELECT_SINGLE_QUOTE_ESCAPED: + ESC_MARKER + '\'' + ; + + SELECT_SINGLE_QUOTE_END: + '\'' {setText("");} -> mode(SELECT_MODE) + ; + + SELECT_SINGLE_QUOTE_TXT: + . + ; + mode SELECT_MODE; FROM: [Ff][Rr][Oo][Mm]([ \t\n\r])* -> mode(DEFAULT_MODE) ; + SELECT_ESCAPED: + ESC_MARKER + ( '"' | '\\' | '\'' | ',' | '.' ) {setText(getText().substring(1));} + ; + SELECT_DOT: '.' + WHITE_SPACE_f? + ; + + SELECT_DOUBLE_QUOTE: + '"' {setText("");} -> mode(SELECT_DOUBLE_QUOTED) + ; + + SELECT_SINGLE_QUOTE: + '\'' {setText("");} -> mode(SELECT_SINGLE_QUOTED) ; SELECT_COMMA: ',' + WHITE_SPACE_f? ; SELECTOR_TXT: diff --git a/src/main/java/org/caosdb/server/query/CQLParser.g4 b/src/main/java/org/caosdb/server/query/CQLParser.g4 index f8c2a3b5..c4a68e5f 100644 --- a/src/main/java/org/caosdb/server/query/CQLParser.g4 +++ b/src/main/java/org/caosdb/server/query/CQLParser.g4 @@ -74,11 +74,24 @@ prop_sel returns [List<Query.Selection> s] ; prop_subsel returns [Query.Selection sub]: - selector_txt {$sub = new Query.Selection($selector_txt.text);}(SELECT_DOT s=prop_subsel {$sub.setSubSelection($s.sub);})? + selector_txt {$sub = new Query.Selection($selector_txt.text);} + ( + SELECT_DOT s=prop_subsel {$sub.setSubSelection($s.sub);} + )? ; selector_txt: - SELECTOR_TXT+ + ( + SELECT_DOUBLE_QUOTE + ( SELECT_DOUBLE_QUOTE_TXT | SELECT_DOUBLE_QUOTE_ESCAPED )* + SELECT_DOUBLE_QUOTE_END + ) | ( + SELECT_SINGLE_QUOTE + ( SELECT_SINGLE_QUOTE_TXT | SELECT_SINGLE_QUOTE_ESCAPED )* + SELECT_SINGLE_QUOTE_END + ) + | + ( SELECTOR_TXT | SELECT_ESCAPED )+ ; role returns [Query.Role r]: @@ -292,7 +305,7 @@ subproperty returns [SubProperty subp] $subp = null; } : - subproperty_filter {$subp = new SubProperty($subproperty_filter.filter);} + subproperty_filter {$subp = new SubProperty($subproperty_filter.filter);} ; subproperty_filter returns [EntityFilterInterface filter] diff --git a/src/main/java/org/caosdb/server/query/Query.java b/src/main/java/org/caosdb/server/query/Query.java index 39152435..07a165a3 100644 --- a/src/main/java/org/caosdb/server/query/Query.java +++ b/src/main/java/org/caosdb/server/query/Query.java @@ -100,13 +100,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac /** No parsing, just sets the selector string. */ public Selection(final String selector) { - if (selector.trim().startsWith("'") && selector.trim().endsWith("'")) { - this.selector = selector.replaceFirst("^\\s*'", "").replaceFirst("'\\s*$", "").trim(); - } else if (selector.trim().startsWith("\"") && selector.trim().endsWith("\"")) { - this.selector = selector.replaceFirst("^\\s*\"", "").replaceFirst("\"\\s*$", "").trim(); - } else { - this.selector = selector.trim(); - } + this.selector = selector.trim(); } public String getSelector() { diff --git a/src/test/java/org/caosdb/server/query/TestCQL.java b/src/test/java/org/caosdb/server/query/TestCQL.java index 3a151fc3..58de2f31 100644 --- a/src/test/java/org/caosdb/server/query/TestCQL.java +++ b/src/test/java/org/caosdb/server/query/TestCQL.java @@ -273,6 +273,10 @@ public class TestCQL { String issue131e = "FIND ename WITH (pname1.pname2 > 30) AND (pname1.pname2 < 40)"; String issue131f = "FIND ename WITH (pname1.pname2 > 30) AND pname1.pname2 < 40"; + // https://gitlab.com/caosdb/caosdb-server/-/issues/130 + String issue130 = + "SELECT 'name with spaces.and dot', 'name with spaces'.name, name with spaces.name, name with\\,comma and\\.dot and \\'single_quote.sub FROM ENTITY"; + @Test public void testQuery1() throws InterruptedException, SQLException, ConnectionException, QueryException { @@ -6935,4 +6939,38 @@ public class TestCQL { assertNull(pov.getVInt()); assertEquals(1e10, pov.getVDouble().doubleValue(), 0.0); } + + /** + * Spaces and escaped dots in selects + * + * <p>String issue130 = "SELECT 'name with spaces.and dot', 'name with spaces'.name, name with + * spaces.name FROM ENTITY"; + */ + @Test + public void testIssue130() { + CQLLexer lexer; + lexer = new CQLLexer(CharStreams.fromString(this.issue130)); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + + final CQLParser parser = new CQLParser(tokens); + final CqContext sfq = parser.cq(); + + System.out.println(sfq.toStringTree(parser)); + + assertNotNull(sfq.s); + assertFalse(sfq.s.isEmpty()); + assertEquals(4, sfq.s.size()); + assertEquals("name with spaces.and dot", sfq.s.get(0).toString()); + assertEquals("name with spaces.and dot", sfq.s.get(0).getSelector()); + assertNull(sfq.s.get(0).getSubselection()); + assertEquals("name with spaces.name", sfq.s.get(1).toString()); + assertEquals("name with spaces", sfq.s.get(1).getSelector()); + assertEquals("name", sfq.s.get(1).getSubselection().toString()); + assertEquals("name with spaces.name", sfq.s.get(2).toString()); + assertEquals("name with spaces", sfq.s.get(2).getSelector()); + assertEquals("name", sfq.s.get(2).getSubselection().toString()); + assertEquals("name with,comma and.dot and 'single_quote.sub", sfq.s.get(3).toString()); + assertEquals("name with,comma and.dot and 'single_quote", sfq.s.get(3).getSelector()); + assertEquals("sub", sfq.s.get(3).getSubselection().toString()); + } } -- GitLab