mirror of https://github.com/apache/lucene.git
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:
parent
9fa04ecc95
commit
e11bc03098
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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> ]
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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> ]
|
||||
{
|
||||
|
|
|
@ -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 + "\"";
|
||||
|
|
|
@ -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
|
||||
----------------------
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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> ]
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue