private bool HandleDodPatterns(QilUnary ndDod) {
OptimizerPatterns pattDod = OptimizerPatterns.Read(ndDod);
XmlNodeKindFlags kinds;
QilName name;
QilNode input, step;
bool isJoinAndDod;
// Handle JoinAndDod and DodReverse patterns
isJoinAndDod = pattDod.MatchesPattern(OptimizerPatternName.JoinAndDod);
if (isJoinAndDod || pattDod.MatchesPattern(OptimizerPatternName.DodReverse)) {
OptimizerPatterns pattStep = OptimizerPatterns.Read((QilNode) pattDod.GetArgument(OptimizerPatternArgument.DodStep));
if (pattStep.MatchesPattern(OptimizerPatternName.FilterElements)) {
// FilterElements pattern, so Kind = Element and Name = Argument
kinds = XmlNodeKindFlags.Element;
name = (QilName) pattStep.GetArgument(OptimizerPatternArgument.ElementQName);
}
else if (pattStep.MatchesPattern(OptimizerPatternName.FilterContentKind)) {
// FilterKindTest pattern, so Kind = Argument and Name = null
kinds = ((XmlQueryType) pattStep.GetArgument(OptimizerPatternArgument.KindTestType)).NodeKinds;
name = null;
}
else {
Debug.Assert(pattStep.MatchesPattern(OptimizerPatternName.Axis), "Dod patterns should only match if step is FilterElements or FilterKindTest or Axis");
kinds = ((ndDod.XmlType.NodeKinds & XmlNodeKindFlags.Attribute) != 0) ? XmlNodeKindFlags.Any : XmlNodeKindFlags.Content;
name = null;
}
step = (QilNode) pattStep.GetArgument(OptimizerPatternArgument.StepNode);
if (isJoinAndDod) {
switch (step.NodeType) {
case QilNodeType.Content:
CreateContainerIterator(ndDod, "$$$iterContent", typeof(ContentMergeIterator), XmlILMethods.ContentMergeCreate, XmlILMethods.ContentMergeNext,
kinds, name, TriState.Unknown);
return true;
case QilNodeType.Descendant:
case QilNodeType.DescendantOrSelf:
CreateContainerIterator(ndDod, "$$$iterDesc", typeof(DescendantMergeIterator), XmlILMethods.DescMergeCreate, XmlILMethods.DescMergeNext,
kinds, name, (step.NodeType == QilNodeType.Descendant) ? TriState.False : TriState.True);
return true;
case QilNodeType.XPathFollowing:
CreateContainerIterator(ndDod, "$$$iterFoll", typeof(XPathFollowingMergeIterator), XmlILMethods.XPFollMergeCreate, XmlILMethods.XPFollMergeNext,
kinds, name, TriState.Unknown);
return true;
case QilNodeType.FollowingSibling:
CreateContainerIterator(ndDod, "$$$iterFollSib", typeof(FollowingSiblingMergeIterator), XmlILMethods.FollSibMergeCreate, XmlILMethods.FollSibMergeNext,
kinds, name, TriState.Unknown);
return true;
case QilNodeType.XPathPreceding:
CreateContainerIterator(ndDod, "$$$iterPrec", typeof(XPathPrecedingMergeIterator), XmlILMethods.XPPrecMergeCreate, XmlILMethods.XPPrecMergeNext,
kinds, name, TriState.Unknown);
return true;
default:
Debug.Assert(false, "Pattern " + step.NodeType + " should have been handled.");
break;
}
}
else {
input = (QilNode) pattStep.GetArgument(OptimizerPatternArgument.StepInput);
switch (step.NodeType) {
case QilNodeType.Ancestor:
case QilNodeType.AncestorOrSelf:
CreateFilteredIterator(input, "$$$iterAnc", typeof(AncestorDocOrderIterator), XmlILMethods.AncDOCreate, XmlILMethods.AncDONext,
kinds, name, (step.NodeType == QilNodeType.Ancestor) ? TriState.False : TriState.True, null);
return true;
case QilNodeType.PrecedingSibling:
CreateFilteredIterator(input, "$$$iterPreSib", typeof(PrecedingSiblingDocOrderIterator), XmlILMethods.PreSibDOCreate, XmlILMethods.PreSibDONext,
kinds, name, TriState.Unknown, null);
return true;
case QilNodeType.XPathPreceding:
CreateFilteredIterator(input, "$$$iterPrec", typeof(XPathPrecedingDocOrderIterator), XmlILMethods.XPPrecDOCreate, XmlILMethods.XPPrecDONext,
kinds, name, TriState.Unknown, null);
return true;
default:
Debug.Assert(false, "Pattern " + step.NodeType + " should have been handled.");
break;
}
}
}
else if (pattDod.MatchesPattern(OptimizerPatternName.DodMerge)) {
// DodSequenceMerge dodMerge;
LocalBuilder locMerge = this.helper.DeclareLocal("$$$dodMerge", typeof(DodSequenceMerge));
Label lblOnEnd = this.helper.DefineLabel();
// dodMerge.Create(runtime);
this.helper.Emit(OpCodes.Ldloca, locMerge);
this.helper.LoadQueryRuntime();
this.helper.Call(XmlILMethods.DodMergeCreate);
this.helper.Emit(OpCodes.Ldloca, locMerge);
StartNestedIterator(ndDod.Child, lblOnEnd);
// foreach (seq in expr) {
Visit(ndDod.Child);
// dodMerge.AddSequence(seq);
Debug.Assert(this.iterCurr.Storage.IsCached, "DodMerge pattern should only be matched when cached sequences are returned from loop");
this.iterCurr.EnsureStack();
this.helper.Call(XmlILMethods.DodMergeAdd);
this.helper.Emit(OpCodes.Ldloca, locMerge);
// }
this.iterCurr.LoopToEnd(lblOnEnd);
EndNestedIterator(ndDod.Child);
// mergedSequence = dodMerge.MergeSequences();
this.helper.Call(XmlILMethods.DodMergeSeq);
this.iterCurr.Storage = StorageDescriptor.Stack(typeof(XPathNavigator), true);
return true;
}
return false;
}