Returns an equivalent expression which accesses an index. If the expression cannot be rewritten, the original expression is returned. The following types of queries can be rewritten (in the examples, the equality comparison is used, which will be rewritten to ValueAccess instances):
(final CompileContext cc, final Expr rt)
| 732 | * @throws QueryException query exception |
| 733 | */ |
| 734 | private Expr index(final CompileContext cc, final Expr rt) throws QueryException { |
| 735 | // skip optimization if path does not start with document nodes |
| 736 | if(rt == null || !rt.seqType().type.instanceOf(NodeType.DOCUMENT)) return this; |
| 737 | |
| 738 | // cache index access costs |
| 739 | IndexInfo index = null; |
| 740 | // cheapest predicate and step |
| 741 | int predIndex = 0, stepIndex = 0; |
| 742 | |
| 743 | // check if path can be converted to an index access |
| 744 | final Data data = data(); |
| 745 | final int sl = steps.length; |
| 746 | for(int s = 0; s < sl; s++) { |
| 747 | // only accept descendant steps without positional predicates |
| 748 | // Example for position predicate: child:x[1] != parent::x[1] |
| 749 | final Step step = axisStep(s); |
| 750 | if(step == null || !step.axis.down || step.mayBePositional()) break; |
| 751 | |
| 752 | final int el = step.exprs.length; |
| 753 | if(el > 0) { |
| 754 | // static vs dynamic access |
| 755 | final IndexDb db = data != null ? |
| 756 | new IndexStaticDb(data, info) : |
| 757 | new IndexDynDb(root == null ? new ContextValue(info) : root, info); |
| 758 | |
| 759 | // choose the cheapest index access |
| 760 | for(int e = 0; e < el; e++) { |
| 761 | final IndexInfo ii = new IndexInfo(db, cc, step); |
| 762 | if(!step.exprs[e].indexAccessible(ii)) continue; |
| 763 | |
| 764 | if(ii.costs.results() == 0) { |
| 765 | // no results... |
| 766 | cc.info(QueryText.OPTNORESULTS_X, step); |
| 767 | return Empty.VALUE; |
| 768 | } |
| 769 | |
| 770 | if(index == null || index.costs.compareTo(ii.costs) > 0) { |
| 771 | index = ii; |
| 772 | predIndex = e; |
| 773 | stepIndex = s; |
| 774 | } |
| 775 | } |
| 776 | } |
| 777 | } |
| 778 | |
| 779 | // skip rewriting if no index access is possible or if it is too expensive |
| 780 | if(index == null || data != null && index.costs.tooExpensive(data)) return this; |
| 781 | // skip optimization if root is no value and if index access is not enforced |
| 782 | Test rootTest = null; |
| 783 | if(rt instanceof final Value value && !(value instanceof Dummy)) { |
| 784 | rootTest = InvDocTest.get(value); |
| 785 | } else { |
| 786 | // continue if index use is enforced (skip context-dependent roots) |
| 787 | if(!index.enforce() || rt.has(Flag.CTX)) return this; |
| 788 | } |
| 789 | |
| 790 | // rewrite for index access |
| 791 | cc.info(index.optInfo); |
no test coverage detected