Skip to content

Commit cb86407

Browse files
Orderedness of types. qtspecs#2216, qtspecs#2218
1 parent 5b3dc01 commit cb86407

File tree

23 files changed

+112
-244
lines changed

23 files changed

+112
-244
lines changed

basex-core/src/main/java/org/basex/query/expr/CmpG.java

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -210,15 +210,20 @@ public final Expr optimize(final CompileContext cc) throws QueryException {
210210
if(expr == this) expr = CmpIR.get(cc, this, false);
211211
if(expr == this) expr = CmpR.get(cc, this);
212212
if(expr == this) expr = CmpSR.get(cc, this);
213-
214213
if(expr == this) {
215-
// determine types, choose best implementation
214+
// skip runtime type check if items are known to be comparable (covers most common types)
216215
final SeqType st1 = expr1.seqType(), st2 = expr2.seqType();
217216
final Type type1 = st1.type, type2 = st2.type;
218-
// skip type check if types are identical, have a specific atomic type and are comparable
219-
check = !(type1 == type2 && !type1.oneOf(AtomType.ANY_ATOMIC_TYPE, AtomType.ITEM) &&
220-
comparable(type1, type2, true));
217+
if(type1 == type2 && !type1.oneOf(AtomType.ANY_ATOMIC_TYPE, AtomType.ITEM)
218+
|| type1.isUntyped() || type2.isUntyped()
219+
|| type1.isNumber() && type2.isNumber()
220+
|| type1.isStringOrUntyped() && type2.isStringOrUntyped()
221+
|| type1.instanceOf(AtomType.BINARY) && type2.instanceOf(AtomType.BINARY)
222+
|| type1.instanceOf(AtomType.DURATION) && type2.instanceOf(AtomType.DURATION)) {
223+
check = false;
224+
}
221225

226+
// choose best implementation
222227
if(st1.zeroOrOne() && !st1.mayBeArray() && st2.zeroOrOne() && !st2.mayBeArray()) {
223228
// simple comparisons
224229
if(!(this instanceof CmpSimpleG)) expr = new CmpSimpleG(expr1, expr2, op, info, check);
@@ -233,6 +238,7 @@ public final Expr optimize(final CompileContext cc) throws QueryException {
233238
// range comparisons
234239
if(!(this instanceof CmpRangeG)) expr = new CmpRangeG(expr1, expr2, op, info);
235240
}
241+
236242
// pre-evaluate expression; discard hashed results
237243
if(values(false, cc)) {
238244
final Expr ex = cc.preEval(expr);
@@ -345,15 +351,14 @@ boolean compare(final Iter iter1, final Iter iter2, final long size1, final long
345351
* @throws QueryException query exception
346352
*/
347353
final boolean eval(final Item item1, final Item item2) throws QueryException {
348-
if(check) {
349-
final Type type1 = item1.type, type2 = item2.type;
350-
if(!comparable(type1, type2, true)) throw compareError(item1, item2, info);
351-
}
354+
if(check && !(item1.comparable(item2) || item1.type.isUntyped() || item2.type.isUntyped()))
355+
throw compareError(item1, item2, info);
352356
return op.value().eval(item1, item2, info);
353357
}
354358

355359
/**
356-
* Checks if an expression with the specified types can be rewritten to a general comparison.
360+
* Compile-time check: Checks if an expression with the specified types can be rewritten
361+
* to a general comparison.
357362
* @param st1 first sequence type
358363
* @param st2 second sequence type
359364
* @param eqne eq/ne comparison
@@ -369,23 +374,6 @@ public static boolean compatible(final SeqType st1, final SeqType st2, final boo
369374
type1.instanceOf(AtomType.DURATION) && type2.instanceOf(AtomType.DURATION);
370375
}
371376

372-
/**
373-
* Checks if types can be compared.
374-
* @param type1 first type to compare
375-
* @param type2 second type to compare
376-
* @param untyped allow untyped atomics
377-
* @return result of check
378-
*/
379-
public static boolean comparable(final Type type1, final Type type2, final boolean untyped) {
380-
return type1 == type2 ||
381-
type1.isNumber() && type2.isNumber() ||
382-
type1.isStringOrUntyped() && type2.isStringOrUntyped() ||
383-
untyped && (type1.isUntyped() || type2.isUntyped()) ||
384-
type1.instanceOf(AtomType.DATE_TIME) && type2.instanceOf(AtomType.DATE_TIME) ||
385-
type1.instanceOf(AtomType.DURATION) && type2.instanceOf(AtomType.DURATION) ||
386-
type1.instanceOf(AtomType.BINARY) && type2.instanceOf(AtomType.BINARY);
387-
}
388-
389377
@Override
390378
public final CmpG invert() {
391379
final Expr expr1 = exprs[0], expr2 = exprs[1];

basex-core/src/main/java/org/basex/query/func/fn/FnCompare.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ public Item item(final QueryContext qc, final InputInfo ii) throws QueryExceptio
2525
final Collation collation = toCollation(arg(2), qc);
2626

2727
if(value1 == null || value2 == null) return Empty.VALUE;
28-
final Type type1 = value1.type, type2 = value2.type;
29-
if(!CmpG.comparable(type1, type2, false)) throw compareError(value1, value2, info);
28+
if(!value1.comparable(value2)) throw compareError(value1, value2, info);
3029

3130
final long diff = value1.compare(value2, collation, true, info);
3231
return Itr.get(diff < 0 ? -1 : diff > 0 ? 1 : 0);

basex-core/src/main/java/org/basex/query/value/item/ADate.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,6 @@ static void prefix(final TokenBuilder tb, final long number, final int zero) {
387387
tb.add(t);
388388
}
389389

390-
@Override
391-
public final boolean equal(final Item item, final Collation coll, final InputInfo ii)
392-
throws QueryException {
393-
return compare(item, ii) == 0;
394-
}
395-
396390
@Override
397391
public final boolean deepEqual(final Item item, final DeepEqual deep) throws QueryException {
398392
return (type.instanceOf(item.type) || item.type.instanceOf(type))
@@ -411,12 +405,13 @@ public final int hashCode() {
411405
return toSeconds().intValue();
412406
}
413407

414-
/**
415-
* {@inheritDoc}
416-
* Overwritten by {@link GDt}.
417-
*/
418408
@Override
419-
public int compare(final Item item, final Collation coll, final boolean transitive,
409+
public boolean comparable(final Item item) {
410+
return item instanceof ADate;
411+
}
412+
413+
@Override
414+
public final int compare(final Item item, final Collation coll, final boolean transitive,
420415
final InputInfo ii) throws QueryException {
421416
return compare(item, ii);
422417
}

basex-core/src/main/java/org/basex/query/value/item/ANum.java

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -83,38 +83,6 @@ public final boolean atomicEqual(final Item item) throws QueryException {
8383
*/
8484
protected abstract float flt();
8585

86-
/**
87-
* Converts an item to decimal, if it is untyped, or to double if decimal conversion cannot
88-
* succeed.
89-
* @param item item
90-
* @param ii input info
91-
* @return converted item (unchanged if not untyped, otherwise decimal or double)
92-
* @throws QueryException query exception
93-
*/
94-
protected static Item untypedToDec(final Item item, final InputInfo ii) throws QueryException {
95-
if(!item.type.isUntyped()) return item;
96-
final byte[] token = item.string(ii);
97-
for(final byte b : token) if(b == 'e' || b == 'E' || b == 'N') return Dbl.get(item.dbl(ii));
98-
return Dec.get(item.dec(ii));
99-
}
100-
101-
/**
102-
* Converts an item to float, if it is untyped, or to double if float conversion fails.
103-
* @param item item
104-
* @param ii input info
105-
* @return converted item (unchanged if not untyped, otherwise float or double)
106-
* @throws QueryException query exception
107-
*/
108-
protected static Item untypedToFlt(final Item item, final InputInfo ii) throws QueryException {
109-
if(!item.type.isUntyped()) return item;
110-
try {
111-
return Flt.get(item.flt(ii));
112-
} catch(QueryException ex) {
113-
Util.debug(ex);
114-
return Dbl.get(item.dbl(ii));
115-
}
116-
}
117-
11886
/**
11987
* Returns an absolute value.
12088
* @return absolute value

basex-core/src/main/java/org/basex/query/value/item/AStr.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,6 @@ public final boolean comparable(final Item item) {
118118
return item.type.isStringOrUntyped();
119119
}
120120

121-
@Override
122-
public final boolean equal(final Item item, final Collation coll, final InputInfo ii)
123-
throws QueryException {
124-
return Token.eq(string(ii), item.string(ii), Collation.get(coll, ii));
125-
}
126-
127121
@Override
128122
public final boolean deepEqual(final Item item, final DeepEqual deep) throws QueryException {
129123
return comparable(item) && Token.eq(string(deep.info), item.string(deep.info), deep);

basex-core/src/main/java/org/basex/query/value/item/Atm.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,6 @@ public boolean comparable(final Item item) {
6868
return item.type.isStringOrUntyped();
6969
}
7070

71-
@Override
72-
public boolean equal(final Item item, final Collation coll, final InputInfo ii)
73-
throws QueryException {
74-
return comparable(item) ? Token.eq(value, item.string(ii), Collation.get(coll, ii)) :
75-
item.equal(this, coll, ii);
76-
}
77-
7871
@Override
7972
public boolean deepEqual(final Item item, final DeepEqual deep) throws QueryException {
8073
return comparable(item) && Token.eq(string(deep.info), item.string(deep.info), deep);

basex-core/src/main/java/org/basex/query/value/item/Bin.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ public final boolean comparable(final Item item) {
4242
return item instanceof Bin;
4343
}
4444

45-
@Override
46-
public final boolean equal(final Item item, final Collation coll, final InputInfo ii)
47-
throws QueryException {
48-
final byte[] binary = item instanceof final Bin bin ? bin.binary(ii) : parse(item, ii);
49-
return Token.eq(binary(ii), binary);
50-
}
51-
5245
@Override
5346
public final boolean atomicEqual(final Item item) throws QueryException {
5447
return this == item || item instanceof final Bin bin &&

basex-core/src/main/java/org/basex/query/value/item/Bln.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,6 @@ public BigDecimal dec(final InputInfo ii) {
101101
return value ? BigDecimal.ONE : BigDecimal.ZERO;
102102
}
103103

104-
@Override
105-
public boolean equal(final Item item, final Collation coll, final InputInfo ii)
106-
throws QueryException {
107-
return value == (item.type == AtomType.BOOLEAN ? item.bool(ii) : parse(item, ii));
108-
}
109-
110104
@Override
111105
public int compare(final Item item, final Collation coll, final boolean transitive,
112106
final InputInfo ii) throws QueryException {

basex-core/src/main/java/org/basex/query/value/item/Dbl.java

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -103,32 +103,24 @@ public Dbl round(final int prec, final RoundMode mode) {
103103
d == value ? this : Dbl.get(d);
104104
}
105105

106-
@Override
107-
public boolean equal(final Item item, final Collation coll, final InputInfo ii)
108-
throws QueryException {
109-
return !item.type.instanceOf(AtomType.DECIMAL) ? value == item.dbl(ii) :
110-
Double.isFinite(value) ? dec(ii).compareTo(item.dec(ii)) == 0 : false;
111-
}
112-
113106
@Override
114107
public int compare(final Item item, final Collation coll, final boolean transitive,
115108
final InputInfo ii) throws QueryException {
116-
return !item.type.instanceOf(AtomType.DECIMAL) ? compare(value, item.dbl(ii), transitive) :
117-
Double.isFinite(value) ? dec(ii).compareTo(item.dec(ii)) :
118-
value == Double.NEGATIVE_INFINITY ? -1 : value == Double.POSITIVE_INFINITY ? 1 :
119-
transitive ? -1 : NAN_DUMMY;
109+
return item.type.instanceOf(AtomType.DECIMAL) ?
110+
-item.compare(this, coll, transitive, ii) :
111+
compare(value, item.dbl(ii), transitive);
120112
}
121113

122114
/**
123-
* Compares two doubles.
124-
* @param d1 first double
125-
* @param d2 second double
115+
* Compares two double values (identical for floats).
116+
* @param d1 first double value
117+
* @param d2 second double value
126118
* @param transitive transitive comparison
127-
* @return result of comparison (-1, 0, 1)
119+
* @return difference
128120
*/
129121
static int compare(final double d1, final double d2, final boolean transitive) {
130-
final boolean nan = Double.isNaN(d1), dNan = Double.isNaN(d2);
131-
return nan || dNan ? transitive ? nan == dNan ? 0 : nan ? -1 : 1 : NAN_DUMMY :
122+
final boolean n1 = Double.isNaN(d1), n2 = Double.isNaN(d2);
123+
return n1 || n2 ? transitive ? n1 == n2 ? 0 : n1 ? -1 : 1 : NAN_DUMMY :
132124
d1 < d2 ? -1 : d1 > d2 ? 1 : 0;
133125
}
134126

basex-core/src/main/java/org/basex/query/value/item/Dec.java

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -161,26 +161,38 @@ static BigDecimal round(final BigDecimal value, final int prec, final RoundMode
161161
}
162162

163163
@Override
164-
public boolean equal(final Item item, final Collation coll, final InputInfo ii)
165-
throws QueryException {
166-
final Item it = untypedToDec(item, ii);
167-
return !(it instanceof Dbl || it instanceof Flt) || Double.isFinite(it.dbl(ii)) ?
168-
value.compareTo(it.dec(ii)) == 0 :
169-
false;
164+
public int compare(final Item item, final Collation coll, final boolean transitive,
165+
final InputInfo ii) throws QueryException {
166+
return compare(this, item, transitive, ii);
170167
}
171168

172-
@Override
173-
public int compare(final Item item, final Collation coll, final boolean transitive,
169+
/**
170+
* Compares the numeric values of two items.
171+
* @param item1 first value
172+
* @param item2 second value
173+
* @param transitive transitive comparison
174+
* @param ii input info
175+
* @return difference difference
176+
* @throws QueryException query exception
177+
*/
178+
static int compare(final Item item1, final Item item2, final boolean transitive,
174179
final InputInfo ii) throws QueryException {
175-
final Item it = untypedToDec(item, ii);
176-
if(it instanceof Dbl || it instanceof Flt) {
177-
final double n = it.dbl(ii);
178-
if(!Double.isFinite(n)) {
179-
return n == Double.NEGATIVE_INFINITY ? 1 : n == Double.POSITIVE_INFINITY ? -1 :
180+
final Item it2;
181+
if(item2.type.isUntyped()) {
182+
final byte[] string = item2.string(ii);
183+
final BigDecimal bd = Dec.parse(string, ii, false);
184+
it2 = bd != null ? Dec.get(bd) : Dbl.get(Dbl.parse(string, ii));
185+
} else {
186+
it2 = item2;
187+
}
188+
if(it2 instanceof Dbl || it2 instanceof Flt) {
189+
final double d = it2.dbl(ii);
190+
if(!Double.isFinite(d)) {
191+
return d == Double.NEGATIVE_INFINITY ? 1 : d == Double.POSITIVE_INFINITY ? -1 :
180192
transitive ? 1 : NAN_DUMMY;
181193
}
182194
}
183-
return value.compareTo(it.dec(ii));
195+
return item1.dec(ii).compareTo(it2.dec(ii));
184196
}
185197

186198
@Override
@@ -208,14 +220,19 @@ public boolean equals(final Object obj) {
208220
* Converts the given token into a decimal value.
209221
* @param value value to be converted
210222
* @param info input info (can be {@code null})
211-
* @return double value
223+
* @param error raise error for an invalid input
224+
* @return decimal or {@code null}
212225
* @throws QueryException query exception
213226
*/
214-
public static BigDecimal parse(final byte[] value, final InputInfo info) throws QueryException {
227+
public static BigDecimal parse(final byte[] value, final InputInfo info,
228+
final boolean error) throws QueryException {
215229
try {
216230
if(!contains(value, 'e') && !contains(value, 'E'))
217231
return new BigDecimal(Token.string(value).trim());
218-
} catch(final NumberFormatException ex) { Util.debug(ex); }
219-
throw AtomType.DECIMAL.castError(value, info);
232+
} catch(final NumberFormatException ex) {
233+
Util.debug(ex);
234+
}
235+
if(error) throw AtomType.DECIMAL.castError(value, info);
236+
return null;
220237
}
221238
}

0 commit comments

Comments
 (0)