From e11bc030987b33faadf42f0b2fb21d521077f361 Mon Sep 17 00:00:00 2001 From: Steve Rowe Date: Sun, 14 May 2017 11:31:22 -0400 Subject: [PATCH] LUCENE-7821: The classic and flexible query parsers, as well as Solr's 'lucene'/standard query parser, should require ' TO ' in range queries, and accept 'TO' as endpoints in range queries. --- lucene/CHANGES.txt | 4 ++ .../queryparser/classic/QueryParser.java | 47 +++++++++-------- .../lucene/queryparser/classic/QueryParser.jj | 6 +-- .../standard/parser/StandardSyntaxParser.java | 43 ++++++++-------- .../standard/parser/StandardSyntaxParser.jj | 6 +-- .../queryparser/util/QueryParserTestBase.java | 51 +++++++++++++++++++ solr/CHANGES.txt | 3 ++ .../org/apache/solr/parser/QueryParser.java | 47 +++++++++-------- .../org/apache/solr/parser/QueryParser.jj | 6 +-- .../apache/solr/search/TestRangeQuery.java | 42 +++++++++++++++ 10 files changed, 176 insertions(+), 79 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index a57d67bd40f..10c46cf7694 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -126,6 +126,10 @@ Bug Fixes * LUCENE-5365, LUCENE-7818: Fix incorrect condition in queryparser's QueryNodeOperation#logicalAnd(). (Olivier Binda, Amrit Sarkar, AppChecker via Uwe Schindler) + +* LUCENE-7821: The classic and flexible query parsers, as well as Solr's + "lucene"/standard query parser, should require " TO " in range queries, + and accept "TO" as endpoints in range queries. (hossman, Steve Rowe) Improvements diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.java index 5e5d57bf294..134ddfa9775 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.java @@ -490,19 +490,15 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants case RANGE_QUOTED: goop1 = jj_consume_token(RANGE_QUOTED); break; + case RANGE_TO: + goop1 = jj_consume_token(RANGE_TO); + break; default: jj_la1[16] = jj_gen; jj_consume_token(-1); throw new ParseException(); } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case RANGE_TO: - jj_consume_token(RANGE_TO); - break; - default: - jj_la1[17] = jj_gen; - ; - } + jj_consume_token(RANGE_TO); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case RANGE_GOOP: goop2 = jj_consume_token(RANGE_GOOP); @@ -510,8 +506,11 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants case RANGE_QUOTED: goop2 = jj_consume_token(RANGE_QUOTED); break; + case RANGE_TO: + goop2 = jj_consume_token(RANGE_TO); + break; default: - jj_la1[18] = jj_gen; + jj_la1[17] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -524,7 +523,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants jj_consume_token(RANGEEX_END); break; default: - jj_la1[19] = jj_gen; + jj_la1[18] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -534,7 +533,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants boost = jj_consume_token(NUMBER); break; default: - jj_la1[20] = jj_gen; + jj_la1[19] = jj_gen; ; } boolean startOpen=false; @@ -566,7 +565,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants fuzzy=true; break; default: - jj_la1[21] = jj_gen; + jj_la1[20] = jj_gen; ; } break; @@ -579,24 +578,24 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants boost = jj_consume_token(NUMBER); break; default: - jj_la1[22] = jj_gen; + jj_la1[21] = jj_gen; ; } break; default: - jj_la1[23] = jj_gen; + jj_la1[22] = jj_gen; jj_consume_token(-1); throw new ParseException(); } break; default: - jj_la1[24] = jj_gen; + jj_la1[23] = jj_gen; ; } q = handleQuotedTerm(field, term, fuzzySlop); break; default: - jj_la1[25] = jj_gen; + jj_la1[24] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -732,7 +731,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants private boolean jj_lookingAhead = false; private boolean jj_semLA; private int jj_gen; - final private int[] jj_la1 = new int[26]; + final private int[] jj_la1 = new int[25]; static private int[] jj_la1_0; static private int[] jj_la1_1; static { @@ -740,10 +739,10 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants jj_la1_init_1(); } private static void jj_la1_init_0() { - jj_la1_0 = new int[] {0x300,0x300,0x1c00,0x1c00,0xfda7c00,0xfda7f00,0xfda7f00,0x120000,0x40000,0xfda6000,0x9d22000,0x200000,0x40000,0x240000,0x240000,0x6000000,0x80000000,0x10000000,0x80000000,0x60000000,0x40000,0x200000,0x40000,0x240000,0x240000,0xfda2000,}; + jj_la1_0 = new int[] {0x300,0x300,0x1c00,0x1c00,0xfda7c00,0xfda7f00,0xfda7f00,0x120000,0x40000,0xfda6000,0x9d22000,0x200000,0x40000,0x240000,0x240000,0x6000000,0x90000000,0x90000000,0x60000000,0x40000,0x200000,0x40000,0x240000,0x240000,0xfda2000,}; } private static void jj_la1_init_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; + jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; } final private JJCalls[] jj_2_rtns = new JJCalls[3]; private boolean jj_rescan = false; @@ -755,7 +754,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -766,7 +765,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants jj_ntk = -1; jj_lookingAhead = false; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -776,7 +775,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -786,7 +785,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -903,7 +902,7 @@ public class QueryParser extends QueryParserBase implements QueryParserConstants la1tokens[jj_kind] = true; jj_kind = -1; } - for (int i = 0; i < 26; i++) { + for (int i = 0; i < 25; i++) { if (jj_la1[i] == jj_gen) { for (int j = 0; j < 32; j++) { if ((jj_la1_0[i] & (1< { startInc = true; } | ) - ( goop1= | goop1= ) - [ ] - ( goop2= | goop2= ) + ( goop1= | goop1= | goop1= ) + ( ) + ( goop2= | goop2= | goop2= ) ( { endInc = true; } | ) [ boost= ] { diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/flexible/standard/parser/StandardSyntaxParser.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/flexible/standard/parser/StandardSyntaxParser.java index 8ba34a6ff4e..6008bcc3dc0 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/flexible/standard/parser/StandardSyntaxParser.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/flexible/standard/parser/StandardSyntaxParser.java @@ -577,19 +577,15 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC case RANGE_QUOTED: goop1 = jj_consume_token(RANGE_QUOTED); break; + case RANGE_TO: + goop1 = jj_consume_token(RANGE_TO); + break; default: jj_la1[18] = jj_gen; jj_consume_token(-1); throw new ParseException(); } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case RANGE_TO: - jj_consume_token(RANGE_TO); - break; - default: - jj_la1[19] = jj_gen; - ; - } + jj_consume_token(RANGE_TO); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case RANGE_GOOP: goop2 = jj_consume_token(RANGE_GOOP); @@ -597,8 +593,11 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC case RANGE_QUOTED: goop2 = jj_consume_token(RANGE_QUOTED); break; + case RANGE_TO: + goop2 = jj_consume_token(RANGE_TO); + break; default: - jj_la1[20] = jj_gen; + jj_la1[19] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -611,7 +610,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC jj_consume_token(RANGEEX_END); break; default: - jj_la1[21] = jj_gen; + jj_la1[20] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -621,7 +620,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC boost = jj_consume_token(NUMBER); break; default: - jj_la1[22] = jj_gen; + jj_la1[21] = jj_gen; ; } if (goop1.kind == RANGE_QUOTED) { @@ -645,7 +644,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC fuzzySlop = jj_consume_token(FUZZY_SLOP); break; default: - jj_la1[23] = jj_gen; + jj_la1[22] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { @@ -654,7 +653,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC boost = jj_consume_token(NUMBER); break; default: - jj_la1[24] = jj_gen; + jj_la1[23] = jj_gen; ; } int phraseSlop = 0; @@ -672,7 +671,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC } break; default: - jj_la1[25] = jj_gen; + jj_la1[24] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -831,7 +830,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC private Token jj_scanpos, jj_lastpos; private int jj_la; private int jj_gen; - final private int[] jj_la1 = new int[26]; + final private int[] jj_la1 = new int[25]; static private int[] jj_la1_0; static private int[] jj_la1_1; static { @@ -839,10 +838,10 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC jj_la1_init_1(); } private static void jj_la1_init_0() { - jj_la1_0 = new int[] {0x1c00,0x1c00,0x1ec03c00,0x200,0x100,0x18000,0x1e0000,0x10c00000,0x1f8000,0x18000,0x200000,0x1ec02000,0x1ec02000,0x12800000,0x1000000,0x1000000,0x200000,0xc000000,0x0,0x20000000,0x0,0xc0000000,0x200000,0x1000000,0x200000,0x1ec00000,}; + jj_la1_0 = new int[] {0x1c00,0x1c00,0x1ec03c00,0x200,0x100,0x18000,0x1e0000,0x10c00000,0x1f8000,0x18000,0x200000,0x1ec02000,0x1ec02000,0x12800000,0x1000000,0x1000000,0x200000,0xc000000,0x20000000,0x20000000,0xc0000000,0x200000,0x1000000,0x200000,0x1ec00000,}; } private static void jj_la1_init_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x3,0x0,0x0,0x0,0x0,0x0,}; + jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x3,0x0,0x0,0x0,0x0,0x0,}; } final private JJCalls[] jj_2_rtns = new JJCalls[2]; private boolean jj_rescan = false; @@ -854,7 +853,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -864,7 +863,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -874,7 +873,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -884,7 +883,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 26; i++) jj_la1[i] = -1; + for (int i = 0; i < 25; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -1001,7 +1000,7 @@ public class StandardSyntaxParser implements SyntaxParser, StandardSyntaxParserC la1tokens[jj_kind] = true; jj_kind = -1; } - for (int i = 0; i < 26; i++) { + for (int i = 0; i < 25; i++) { if (jj_la1[i] == jj_gen) { for (int j = 0; j < 32; j++) { if ((jj_la1_0[i] & (1< {startInc=true;} | ) - ( goop1=|goop1= ) - [ ] - ( goop2=|goop2= ) + ( goop1=|goop1=|goop1= ) + ( ) + ( goop2=|goop2=|goop2= ) ( {endInc=true;} | )) [ boost= ] { diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/util/QueryParserTestBase.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/util/QueryParserTestBase.java index 1b8ee96bc40..b49f5765dd2 100644 --- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/util/QueryParserTestBase.java +++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/util/QueryParserTestBase.java @@ -41,6 +41,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.queryparser.classic.QueryParserBase; //import org.apache.lucene.queryparser.classic.QueryParserTokenManager; +import org.apache.lucene.queryparser.classic.TestQueryParser; import org.apache.lucene.queryparser.flexible.standard.CommonQueryParserConfiguration; import org.apache.lucene.search.*; import org.apache.lucene.search.BooleanClause.Occur; @@ -594,6 +595,56 @@ public abstract class QueryParserTestBase extends LuceneTestCase { assertQueryEquals("[\"*\" TO *]",null,"[\\* TO *]"); } + public void testRangeQueryEndpointTO() throws Exception { + Analyzer a = new MockAnalyzer(random()); + assertQueryEquals("[to TO to]", a, "[to TO to]"); + assertQueryEquals("[to TO TO]", a, "[to TO to]"); + assertQueryEquals("[TO TO to]", a, "[to TO to]"); + assertQueryEquals("[TO TO TO]", a, "[to TO to]"); + + assertQueryEquals("[\"TO\" TO \"TO\"]", a, "[to TO to]"); + assertQueryEquals("[\"TO\" TO TO]", a, "[to TO to]"); + assertQueryEquals("[TO TO \"TO\"]", a, "[to TO to]"); + + assertQueryEquals("[to TO xx]", a, "[to TO xx]"); + assertQueryEquals("[\"TO\" TO xx]", a, "[to TO xx]"); + assertQueryEquals("[TO TO xx]", a, "[to TO xx]"); + + assertQueryEquals("[xx TO to]", a, "[xx TO to]"); + assertQueryEquals("[xx TO \"TO\"]", a, "[xx TO to]"); + assertQueryEquals("[xx TO TO]", a, "[xx TO to]"); + } + + public void testRangeQueryRequiresTO() throws Exception { + Analyzer a = new MockAnalyzer(random()); + + assertQueryEquals("{A TO B}", a, "{a TO b}"); + assertQueryEquals("[A TO B}", a, "[a TO b}"); + assertQueryEquals("{A TO B]", a, "{a TO b]"); + assertQueryEquals("[A TO B]", a, "[a TO b]"); + + // " TO " is required between range endpoints + + Class exceptionClass = this instanceof TestQueryParser + ? org.apache.lucene.queryparser.classic.ParseException.class + : org.apache.lucene.queryparser.flexible.standard.parser.ParseException.class; + + expectThrows(exceptionClass, () -> getQuery("{A B}")); + expectThrows(exceptionClass, () -> getQuery("[A B}")); + expectThrows(exceptionClass, () -> getQuery("{A B]")); + expectThrows(exceptionClass, () -> getQuery("[A B]")); + + expectThrows(exceptionClass, () -> getQuery("{TO B}")); + expectThrows(exceptionClass, () -> getQuery("[TO B}")); + expectThrows(exceptionClass, () -> getQuery("{TO B]")); + expectThrows(exceptionClass, () -> getQuery("[TO B]")); + + expectThrows(exceptionClass, () -> getQuery("{A TO}")); + expectThrows(exceptionClass, () -> getQuery("[A TO}")); + expectThrows(exceptionClass, () -> getQuery("{A TO]")); + expectThrows(exceptionClass, () -> getQuery("[A TO]")); + } + private String escapeDateString(String s) { if (s.indexOf(" ") > -1) { return "\"" + s + "\""; diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index c5c41c2d475..a3b551519de 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -370,6 +370,9 @@ Bug Fixes * SOLR-9527: Improve distribution of replicas when restoring a collection (Hrishikesh Gadre, Stephen Lewis, Rohit, Varun Thacker) +* LUCENE-7821: The classic and flexible query parsers, as well as Solr's + "lucene"/standard query parser, should require " TO " in range queries, + and accept "TO" as endpoints in range queries. (hossman, Steve Rowe) Other Changes ---------------------- diff --git a/solr/core/src/java/org/apache/solr/parser/QueryParser.java b/solr/core/src/java/org/apache/solr/parser/QueryParser.java index 39ec673824e..42e982fa26d 100644 --- a/solr/core/src/java/org/apache/solr/parser/QueryParser.java +++ b/solr/core/src/java/org/apache/solr/parser/QueryParser.java @@ -441,19 +441,15 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst case RANGE_QUOTED: goop1 = jj_consume_token(RANGE_QUOTED); break; + case RANGE_TO: + goop1 = jj_consume_token(RANGE_TO); + break; default: jj_la1[18] = jj_gen; jj_consume_token(-1); throw new ParseException(); } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case RANGE_TO: - jj_consume_token(RANGE_TO); - break; - default: - jj_la1[19] = jj_gen; - ; - } + jj_consume_token(RANGE_TO); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case RANGE_GOOP: goop2 = jj_consume_token(RANGE_GOOP); @@ -461,8 +457,11 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst case RANGE_QUOTED: goop2 = jj_consume_token(RANGE_QUOTED); break; + case RANGE_TO: + goop2 = jj_consume_token(RANGE_TO); + break; default: - jj_la1[20] = jj_gen; + jj_la1[19] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -475,7 +474,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst jj_consume_token(RANGEEX_END); break; default: - jj_la1[21] = jj_gen; + jj_la1[20] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -485,7 +484,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst boost = jj_consume_token(NUMBER); break; default: - jj_la1[22] = jj_gen; + jj_la1[21] = jj_gen; ; } boolean startOpen=false; @@ -519,7 +518,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst fuzzy=true; break; default: - jj_la1[23] = jj_gen; + jj_la1[22] = jj_gen; ; } break; @@ -532,24 +531,24 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst boost = jj_consume_token(NUMBER); break; default: - jj_la1[24] = jj_gen; + jj_la1[23] = jj_gen; ; } break; default: - jj_la1[25] = jj_gen; + jj_la1[24] = jj_gen; jj_consume_token(-1); throw new ParseException(); } break; default: - jj_la1[26] = jj_gen; + jj_la1[25] = jj_gen; ; } q = handleQuotedTerm(getField(field), term, fuzzySlop); break; default: - jj_la1[27] = jj_gen; + jj_la1[26] = jj_gen; jj_consume_token(-1); throw new ParseException(); } @@ -685,7 +684,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst private boolean jj_lookingAhead = false; private boolean jj_semLA; private int jj_gen; - final private int[] jj_la1 = new int[28]; + final private int[] jj_la1 = new int[27]; static private int[] jj_la1_0; static private int[] jj_la1_1; static { @@ -693,10 +692,10 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst jj_la1_init_1(); } private static void jj_la1_init_0() { - jj_la1_0 = new int[] {0x6000,0x6000,0x38000,0x38000,0xfb4f8000,0xfb4fe000,0xfb4fe000,0x2400000,0x800000,0x800000,0x800000,0xfb4c0000,0x3a440000,0x4000000,0x800000,0x4800000,0x4800000,0xc0000000,0x0,0x0,0x0,0x0,0x800000,0x4000000,0x800000,0x4800000,0x4800000,0xfb440000,}; + jj_la1_0 = new int[] {0x6000,0x6000,0x38000,0x38000,0xfb4f8000,0xfb4fe000,0xfb4fe000,0x2400000,0x800000,0x800000,0x800000,0xfb4c0000,0x3a440000,0x4000000,0x800000,0x4800000,0x4800000,0xc0000000,0x0,0x0,0x0,0x800000,0x4000000,0x800000,0x4800000,0x4800000,0xfb440000,}; } private static void jj_la1_init_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x7,0x7,0x7,0x0,0x0,0x0,0x0,0x7,0x4,0x0,0x0,0x0,0x0,0x0,0xc0,0x8,0xc0,0x30,0x0,0x0,0x0,0x0,0x0,0x4,}; + jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x7,0x7,0x7,0x0,0x0,0x0,0x0,0x7,0x4,0x0,0x0,0x0,0x0,0x0,0xc8,0xc8,0x30,0x0,0x0,0x0,0x0,0x0,0x4,}; } final private JJCalls[] jj_2_rtns = new JJCalls[3]; private boolean jj_rescan = false; @@ -708,7 +707,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 28; i++) jj_la1[i] = -1; + for (int i = 0; i < 27; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -719,7 +718,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst jj_ntk = -1; jj_lookingAhead = false; jj_gen = 0; - for (int i = 0; i < 28; i++) jj_la1[i] = -1; + for (int i = 0; i < 27; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -729,7 +728,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 28; i++) jj_la1[i] = -1; + for (int i = 0; i < 27; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -739,7 +738,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst token = new Token(); jj_ntk = -1; jj_gen = 0; - for (int i = 0; i < 28; i++) jj_la1[i] = -1; + for (int i = 0; i < 27; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } @@ -856,7 +855,7 @@ public class QueryParser extends SolrQueryParserBase implements QueryParserConst la1tokens[jj_kind] = true; jj_kind = -1; } - for (int i = 0; i < 28; i++) { + for (int i = 0; i < 27; i++) { if (jj_la1[i] == jj_gen) { for (int j = 0; j < 32; j++) { if ((jj_la1_0[i] & (1< { startInc = true; } | ) - ( goop1= | goop1= ) - [ ] - ( goop2= | goop2= ) + ( goop1= | goop1= | goop1= ) + ( ) + ( goop2= | goop2= | goop2= ) ( { endInc = true; } | ) [ boost= ] { diff --git a/solr/core/src/test/org/apache/solr/search/TestRangeQuery.java b/solr/core/src/test/org/apache/solr/search/TestRangeQuery.java index d2244b1272c..0ba716d87dd 100644 --- a/solr/core/src/test/org/apache/solr/search/TestRangeQuery.java +++ b/solr/core/src/test/org/apache/solr/search/TestRangeQuery.java @@ -342,6 +342,48 @@ public class TestRangeQuery extends SolrTestCaseJ4 { } } } + + public void testRangeQueryEndpointTO() throws Exception { + assertEquals("[to TO to]", QParser.getParser("[to TO to]", req("df", "text")).getQuery().toString("text")); + assertEquals("[to TO to]", QParser.getParser("[to TO TO]", req("df", "text")).getQuery().toString("text")); + assertEquals("[to TO to]", QParser.getParser("[TO TO to]", req("df", "text")).getQuery().toString("text")); + assertEquals("[to TO to]", QParser.getParser("[TO TO TO]", req("df", "text")).getQuery().toString("text")); + + assertEquals("[to TO to]", QParser.getParser("[\"TO\" TO \"TO\"]", req("df", "text")).getQuery().toString("text")); + assertEquals("[to TO to]", QParser.getParser("[\"TO\" TO TO]", req("df", "text")).getQuery().toString("text")); + assertEquals("[to TO to]", QParser.getParser("[TO TO \"TO\"]", req("df", "text")).getQuery().toString("text")); + + assertEquals("[to TO xx]", QParser.getParser("[to TO xx]", req("df", "text")).getQuery().toString("text")); + assertEquals("[to TO xx]", QParser.getParser("[\"TO\" TO xx]", req("df", "text")).getQuery().toString("text")); + assertEquals("[to TO xx]", QParser.getParser("[TO TO xx]", req("df", "text")).getQuery().toString("text")); + + assertEquals("[xx TO to]", QParser.getParser("[xx TO to]", req("df", "text")).getQuery().toString("text")); + assertEquals("[xx TO to]", QParser.getParser("[xx TO \"TO\"]", req("df", "text")).getQuery().toString("text")); + assertEquals("[xx TO to]", QParser.getParser("[xx TO TO]", req("df", "text")).getQuery().toString("text")); + } + + public void testRangeQueryRequiresTO() throws Exception { + assertEquals("{a TO b}", QParser.getParser("{A TO B}", req("df", "text")).getQuery().toString("text")); + assertEquals("[a TO b}", QParser.getParser("[A TO B}", req("df", "text")).getQuery().toString("text")); + assertEquals("{a TO b]", QParser.getParser("{A TO B]", req("df", "text")).getQuery().toString("text")); + assertEquals("[a TO b]", QParser.getParser("[A TO B]", req("df", "text")).getQuery().toString("text")); + + // " TO " is required between range endpoints + expectThrows(SyntaxError.class, () -> QParser.getParser("{A B}", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("[A B}", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("{A B]", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("[A B]", req("df", "text")).getQuery()); + + expectThrows(SyntaxError.class, () -> QParser.getParser("{TO B}", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("[TO B}", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("{TO B]", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("[TO B]", req("df", "text")).getQuery()); + + expectThrows(SyntaxError.class, () -> QParser.getParser("{A TO}", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("[A TO}", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("{A TO]", req("df", "text")).getQuery()); + expectThrows(SyntaxError.class, () -> QParser.getParser("[A TO]", req("df", "text")).getQuery()); + } static boolean sameDocs(String msg, DocSet a, DocSet b) { DocIterator i = a.iterator();