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.

This commit is contained in:
Steve Rowe 2017-05-14 11:31:22 -04:00
parent 9fa04ecc95
commit e11bc03098
10 changed files with 176 additions and 79 deletions

View File

@ -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

View File

@ -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<<j)) != 0) {

View File

@ -341,9 +341,9 @@ Query Term(String field) : {
{ q = handleBareTokenQuery(field, term, fuzzySlop, prefix, wildcard, fuzzy, regexp); }
| ( <RANGEIN_START> { startInc = true; } | <RANGEEX_START> )
( goop1=<RANGE_GOOP> | goop1=<RANGE_QUOTED> )
[ <RANGE_TO> ]
( goop2=<RANGE_GOOP> | goop2=<RANGE_QUOTED> )
( goop1=<RANGE_GOOP> | goop1=<RANGE_QUOTED> | goop1=<RANGE_TO> )
( <RANGE_TO> )
( goop2=<RANGE_GOOP> | goop2=<RANGE_QUOTED> | goop2=<RANGE_TO> )
( <RANGEIN_END> { endInc = true; } | <RANGEEX_END> )
[ <CARAT> boost=<NUMBER> ]
{

View File

@ -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<<j)) != 0) {

View File

@ -445,9 +445,9 @@ QueryNode Term(CharSequence field) : {
}
}
| ( ( <RANGEIN_START> {startInc=true;} | <RANGEEX_START> )
( goop1=<RANGE_GOOP>|goop1=<RANGE_QUOTED> )
[ <RANGE_TO> ]
( goop2=<RANGE_GOOP>|goop2=<RANGE_QUOTED> )
( goop1=<RANGE_GOOP>|goop1=<RANGE_QUOTED>|goop1=<RANGE_TO> )
( <RANGE_TO> )
( goop2=<RANGE_GOOP>|goop2=<RANGE_QUOTED>|goop2=<RANGE_TO> )
( <RANGEIN_END> {endInc=true;} | <RANGEEX_END>))
[ <CARAT> boost=<NUMBER> ]
{

View File

@ -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<? extends Throwable> 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 + "\"";

View File

@ -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
----------------------

View File

@ -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<<j)) != 0) {

View File

@ -282,9 +282,9 @@ Query Term(String field) throws SyntaxError : {
{ q = handleBareTokenQuery(getField(field), term, fuzzySlop, prefix, wildcard, fuzzy, regexp); }
| ( <RANGEIN_START> { startInc = true; } | <RANGEEX_START> )
( goop1=<RANGE_GOOP> | goop1=<RANGE_QUOTED> )
[ <RANGE_TO> ]
( goop2=<RANGE_GOOP> | goop2=<RANGE_QUOTED> )
( goop1=<RANGE_GOOP> | goop1=<RANGE_QUOTED> | goop1=<RANGE_TO> )
( <RANGE_TO> )
( goop2=<RANGE_GOOP> | goop2=<RANGE_QUOTED> | goop2=<RANGE_TO> )
( <RANGEIN_END> { endInc = true; } | <RANGEEX_END> )
[ <CARAT> boost=<NUMBER> ]
{

View File

@ -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();