Skip to content

Commit c5c9575

Browse files
committed
[bugfix] Single positional predicate should return an atomic value
1 parent 2aa68ed commit c5c9575

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

exist-core/src/main/java/org/exist/xquery/Predicate.java

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -565,25 +565,57 @@ private Sequence selectByPosition(final Sequence outerSequence,
565565
Type.NODE) && (mode == Constants.ANCESTOR_AXIS ||
566566
mode == Constants.ANCESTOR_SELF_AXIS || mode == Constants.PARENT_AXIS ||
567567
mode == Constants.PRECEDING_AXIS || mode == Constants.PRECEDING_SIBLING_AXIS);
568-
final Set<NumericValue> set = new TreeSet<>();
569-
final ValueSequence result = new ValueSequence();
570-
for (final SequenceIterator i = innerSeq.iterate(); i.hasNext(); ) {
571-
final NumericValue v = (NumericValue) i.nextItem();
568+
569+
Sequence result = Sequence.EMPTY_SEQUENCE;
570+
if (innerSeq.hasOne()) {
571+
// optimise for single position lookup
572+
final NumericValue v = (NumericValue) innerSeq.itemAt(0);
572573
// Non integers return... nothing, not even an error !
573-
if (!v.hasFractionalPart() && !v.isZero()) {
574-
final int pos = (reverseAxis ? contextSequence.getItemCount()
575-
- v.getInt() : v.getInt() - 1);
574+
if (isNonZeroInteger(v)) {
575+
final int pos = calculatePos(reverseAxis, contextSequence, v);
576576
// Other positions are ignored
577-
if (pos >= 0 && pos < contextSequence.getItemCount() && !set.contains(v)) {
578-
result.add(contextSequence.itemAt(pos));
579-
set.add(v);
577+
if (withinBounds(contextSequence, pos)) {
578+
result = (Sequence) contextSequence.itemAt(pos);
579+
}
580+
}
581+
} else {
582+
// multi-position lookup
583+
Set<NumericValue> set = null;
584+
for (final SequenceIterator i = innerSeq.iterate(); i.hasNext(); ) {
585+
final NumericValue v = (NumericValue) i.nextItem();
586+
// Non integers return... nothing, not even an error !
587+
if (isNonZeroInteger(v)) {
588+
final int pos = calculatePos(reverseAxis, contextSequence, v);
589+
// Other positions are ignored
590+
if (withinBounds(contextSequence, pos) && (set == null || !set.contains(v))) {
591+
if (result == Sequence.EMPTY_SEQUENCE) {
592+
result = new ValueSequence();
593+
}
594+
result.add(contextSequence.itemAt(pos));
595+
if (set == null) {
596+
set = new TreeSet<>();
597+
}
598+
set.add(v);
599+
}
580600
}
581601
}
582602
}
583603
return result;
584604
}
585605
}
586606

607+
private static boolean isNonZeroInteger(final NumericValue v) {
608+
return !v.hasFractionalPart() && !v.isZero();
609+
}
610+
611+
private static int calculatePos(final boolean reverseAxis, final Sequence contextSequence, final NumericValue v) throws XPathException {
612+
return (reverseAxis ? contextSequence.getItemCount() - v.getInt() : v.getInt() - 1);
613+
}
614+
615+
private static boolean withinBounds(final Sequence contextSequence, final int pos) {
616+
return pos >= 0 && pos < contextSequence.getItemCount();
617+
}
618+
587619
@Override
588620
public void setContextDocSet(final DocumentSet contextSet) {
589621
super.setContextDocSet(contextSet);

0 commit comments

Comments
 (0)