Tries to rewrite fn:position() CMP number(s) to a positional expression. @param positions positions to be matched @param op comparison operator @param info input info (can be null) @param cc compilation context @param ref calling expression @return optimized expression or {@code null
(final Expr positions, final CmpOp op, final InputInfo info,
final CompileContext cc, final Expr ref)
| 43 | * @throws QueryException query exception |
| 44 | */ |
| 45 | public static Expr get(final Expr positions, final CmpOp op, final InputInfo info, |
| 46 | final CompileContext cc, final Expr ref) throws QueryException { |
| 47 | |
| 48 | // static result. example: position() > 0 → true |
| 49 | Expr pos = positions.optimizePos(op, cc); |
| 50 | if(pos instanceof Bln) return pos; |
| 51 | |
| 52 | if(op == CmpOp.EQ) { |
| 53 | // normalize positions (sort, remove duplicates and illegal positions) |
| 54 | if(cc.values(true, pos)) pos = ddo((Value) pos); |
| 55 | if(pos == Empty.VALUE) return Bln.FALSE; |
| 56 | |
| 57 | // range sequence. example: position() = 5 to 10 |
| 58 | if(pos instanceof final RangeSeq rs) { |
| 59 | return IntPos.get(rs.min(), rs.max(), info); |
| 60 | } |
| 61 | // range. example: position() = 3 to $max |
| 62 | if(pos instanceof final Range rng && rng.integers()) { |
| 63 | if(pos.isSimple()) return new SimplePos(info, pos.args()); |
| 64 | return ref instanceof Pos ? null : new Pos(info, pos); |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | // integer tests. example: position() > 5 |
| 69 | if(pos instanceof final ANum num) { |
| 70 | final long p = num.itr(); |
| 71 | final boolean exact = p == num.dbl(); |
| 72 | switch(op) { |
| 73 | case EQ: return exact ? IntPos.get(p, p, info) : Bln.FALSE; |
| 74 | case GE: return IntPos.get(exact ? p : p + 1, MAX_VALUE, info); |
| 75 | case GT: return IntPos.get(p + 1, MAX_VALUE, info); |
| 76 | case LE: return IntPos.get(1, p, info); |
| 77 | case LT: return IntPos.get(1, exact ? p - 1 : p, info); |
| 78 | case NE: return exact ? p < 2 ? IntPos.get(p + 1, MAX_VALUE, info) : null : Bln.TRUE; |
| 79 | default: |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | // numeric tests |
| 84 | final SeqType st = pos.seqType(); |
| 85 | final Type type = st.type; |
| 86 | final boolean integer = type.instanceOf(BasicType.INTEGER); |
| 87 | if(st.zeroOrOne() && type.isNumberOrUntyped()) { |
| 88 | Expr min = null, max = null; |
| 89 | switch(op) { |
| 90 | case EQ: |
| 91 | min = pos; |
| 92 | break; |
| 93 | case GE: |
| 94 | min = pos; |
| 95 | max = Itr.MAX; |
| 96 | break; |
| 97 | case GT: |
| 98 | min = new Arith(info, integer ? pos : |
| 99 | cc.function(Function.FLOOR, info, pos), Itr.ONE, Calc.ADD).optimize(cc); |
| 100 | max = Itr.MAX; |
| 101 | break; |
| 102 | case LE: |
no test coverage detected