protected ForwardPositionQuery(ForwardPositionQuery other) : base((CacheOutputQuery)other) { }
private Query ProcessFilter(Filter root, Flags flags, out Props props) { bool first = ((flags & Flags.Filter) == 0); Props propsCond; Query cond = ProcessNode(root.Condition, Flags.None, out propsCond); if ( CanBeNumber(cond) || (propsCond & (Props.HasPosition | Props.HasLast)) != 0 ) { propsCond |= Props.HasPosition; flags |= Flags.PosFilter; } // We don't want DescendantOverDescendant pattern to be recognized here (in case descendent::foo[expr]/descendant::bar) // So we clean this flag here: flags &= ~Flags.SmartDesc; // ToDo: Instead it would be nice to wrap descendent::foo[expr] into special query that will flatten it -- i.e. // remove all nodes that are descendant of other nodes. This is very easy becuase for sorted nodesets all children // follow its parent. One step caching. This can be easyly done by rightmost DescendantQuery itsef. // Interesting note! Can we garatee that DescendantOverDescendant returns flat nodeset? This defenetely true if it's input is flat. Query qyInput = ProcessNode(root.Input, flags | Flags.Filter, out props); if (root.Input.Type != AstNode.AstType.Filter) { // Props.PosFilter is for nested filters only. // We clean it here to avoid cleaning it in all other ast nodes. props &= ~Props.PosFilter; } if ((propsCond & Props.HasPosition) != 0) { // this condition is positional rightmost filter should be avare of this. props |= Props.PosFilter; } /*merging predicates*/ { FilterQuery qyFilter = qyInput as FilterQuery; if (qyFilter != null && (propsCond & Props.HasPosition) == 0 && qyFilter.Condition.StaticType != XPathResultType.Any) { Query prevCond = qyFilter.Condition; if (prevCond.StaticType == XPathResultType.Number) { prevCond = new LogicalExpr(Operator.Op.EQ, new NodeFunctions(FT.FuncPosition, null), prevCond); } cond = new BooleanExpr(Operator.Op.AND, prevCond, cond); qyInput = qyFilter.qyInput; } } if ((props & Props.PosFilter) != 0 && qyInput is DocumentOrderQuery) { qyInput = ((DocumentOrderQuery)qyInput).input; } if (firstInput == null) { firstInput = qyInput as BaseAxisQuery; } bool merge = (qyInput.Properties & QueryProps.Merge) != 0; bool reverse = (qyInput.Properties & QueryProps.Reverse) != 0; if ((propsCond & Props.HasPosition) != 0) { if (reverse) { qyInput = new ReversePositionQuery(qyInput); } else if ((propsCond & Props.HasLast) != 0) { qyInput = new ForwardPositionQuery(qyInput); } } if (first && firstInput != null) { if (merge && (props & Props.PosFilter) != 0) { qyInput = new FilterQuery(qyInput, cond, /*noPosition:*/ false); Query parent = firstInput.qyInput; if (!(parent is ContextQuery)) // we don't need to wrap filter with MergeFilterQuery when cardinality is parent <: ? { firstInput.qyInput = new ContextQuery(); firstInput = null; return(new MergeFilterQuery(parent, qyInput)); } firstInput = null; return(qyInput); } firstInput = null; } return(new FilterQuery(qyInput, cond, /*noPosition:*/ (propsCond & Props.HasPosition) == 0)); }
protected ForwardPositionQuery(ForwardPositionQuery other) : base(other) { }