#include "../config/pathan_config.h" /* * Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DataItemFor::VB::VB(const XMLCh* variable, DataItem* value) : _variable(variable), _uri(0), _name(0), _allValues(value), _valuesExprDependsOnPreviousBindings(false), _needsNewScope(false) { } DataItemFor::VB::VB(const VB &o) : _variable(o._variable), _uri(o._uri), _name(o._name), _allValues(o._allValues), _valuesExprDependsOnPreviousBindings(o._valuesExprDependsOnPreviousBindings), _needsNewScope(o._needsNewScope) { } DataItemFor::DataItemFor(VectorOfBindings* bindings, DataItem* returnExpr, XPath2MemoryManager* memMgr) : DataItemImpl(memMgr), _bindings(PathanAllocator(memMgr)), _returnExpr(returnExpr) { setType(DataItem::FOR); for(VectorOfBindings::iterator i = bindings->begin(); i != bindings->end(); ++i) { _bindings.push_back(new (memMgr) VB((*i)->getVariable(), (*i)->getValue())); } } DataItemFor::VBExecution::VBExecution(const DataItemFor::VB *vb, DynamicContext *context) : _vb(vb), _currentValues(context->getMemoryManager()), _refVar(0), _valuesComputed(false) { } bool DataItemFor::VBExecution::initialise(DynamicContext *context) { if(_vb->_valuesExprDependsOnPreviousBindings || !_valuesComputed) { _currentValues = _vb->_allValues->collapseTree(context); _valuesComputed = true; } _valueIt = _currentValues.begin(); if(_valueIt == _currentValues.end()) { return false; } VariableStore* varStore = context->getVariableStore(); if(_vb->_needsNewScope) { varStore->addLogicalBlockScope(); } if(_vb->_variable) { varStore->declareVar(_vb->_uri, _vb->_name, Sequence(*_valueIt, context->getMemoryManager()), context); _refVar = varStore->getReferenceVar(_vb->_uri, _vb->_name, context); } return true; } bool DataItemFor::VBExecution::next(DynamicContext *context) { if(++_valueIt == _currentValues.end()) { if(_vb->_needsNewScope) { context->getVariableStore()->removeScope(); } return false; } if(_vb->_variable) { _refVar->setValue(Sequence(*_valueIt, context->getMemoryManager())); } return true; } bool DataItemFor::next(ExecutionBindings &ebs, DynamicContext *context, bool initialisationState) const { ExecutionBindings::reverse_iterator rend = ebs.rend(); ExecutionBindings::reverse_iterator rbegin = ebs.rbegin(); ExecutionBindings::reverse_iterator it; if(initialisationState) { it = rend; } else { it = rbegin; } while(true) { if(initialisationState) { if(it == rbegin) { return true; } else { --it; if(!it->initialise(context)) { initialisationState = false; ++it; } } } else { if(it == rend) { return false; } else { if(it->next(context)) { initialisationState = true; } else { ++it; } } } } } Sequence DataItemFor::collapseTreeInternal(DynamicContext* context, int flags) const { return collapseTreeInternal(_bindings.begin(), _bindings.end(), context, flags); } Sequence DataItemFor::collapseTreeInternal(Bindings::const_iterator it, Bindings::const_iterator end, DynamicContext* context, int flags) const { VariableStore* varStore = context->getVariableStore(); Sequence result(context->getMemoryManager()); // Make the execution bindings ExecutionBindings ebs; for(; it != end; ++it) { ebs.push_back(VBExecution(*it, context)); } // Initialise and run the execution bindings varStore->addLogicalBlockScope(); if(next(ebs, context, true)) { do { result.joinSequence(_returnExpr->collapseTree(context, flags)); if((flags & DataItem::RETURN_ONE) && !result.isEmpty()) break; if((flags & DataItem::RETURN_TWO) && result.getLength()>1) break; } while(next(ebs, context, false)); } varStore->removeScope(); return result; } DataItem* DataItemFor::staticResolution(StaticContext *context, StaticResolutionContext *src) { StaticResolutionContext newSrc(context->getMemoryManager()); staticResolutionImpl(context, &newSrc); if(newSrc.isUsed()) { src->add(&newSrc); return resolvePredicates(context, src); } else { _returnExpr->addPredicates(getPredicates()); return _returnExpr->staticResolution(context, src); } } void DataItemFor::staticResolutionImpl(StaticContext* context, StaticResolutionContext *src) { StaticResolutionContext valueSrc(context->getMemoryManager()); Bindings newBindings(PathanAllocator(context->getMemoryManager())); VariableTypeStore* varStore = context->getVariableTypeStore(); SequenceType s(new SequenceType::ItemType(SequenceType::ItemType::TEST_ANYTHING), SequenceType::STAR); // Add all the binding variables to the new scope Bindings::iterator end = _bindings.end(); for(Bindings::iterator it0 = _bindings.begin(); it0 != end; ++it0) { // Work out the uri and localname of the variable binding (*it0)->_uri = context->getUriBoundToPrefix(XPath2NSUtils::getPrefix((*it0)->_variable, context->getMemoryManager())); (*it0)->_name = XPath2NSUtils::getLocalName((*it0)->_variable); varStore->addLogicalBlockScope(); varStore->declareVar((*it0)->_uri, (*it0)->_name, &s, context); } // Call staticResolution on the return expression _returnExpr = _returnExpr->staticResolution(context, src); Bindings::reverse_iterator rend = _bindings.rend(); for(Bindings::reverse_iterator it = _bindings.rbegin(); it != rend; ++it) { VB *newVB = new (context->getMemoryManager()) VB(**it); // Remove our variable binding and the scope we added varStore->removeScope(); // Remove our binding variable from the StaticResolutionContext data (removing it if it's not used) if(!src->removeVariable(newVB->_uri, newVB->_name)) { newVB->_variable = 0; } // call static resolution on the value valueSrc.clear(); newVB->_allValues = newVB->_allValues->staticResolution(context, &valueSrc); src->add(&valueSrc); Bindings::reverse_iterator it2; // Check if previous variable bindings have been used by this value, for(it2 = it + 1; it2 != rend; ++it2) { if((*it2)->_variable && valueSrc.isVariableUsed((*it2)->_uri, (*it2)->_name)) { newVB->_valuesExprDependsOnPreviousBindings = true; break; } } // Check to see if this binding has the same name as any before it for(it2 = it + 1; it2 != rend; ++it2) { if(newVB->_variable && (*it2)->_variable && XPath2Utils::equals(newVB->_name, (*it2)->_name) && XPath2Utils::equals(newVB->_uri, (*it2)->_uri)) { newVB->_needsNewScope = true; break; } } // Add the new VB at the front of the new Bindings newBindings.insert(newBindings.begin(), newVB); if(!src->isUsed()) { DynamicContext *dContext = context->createDynamicContext(); _returnExpr = new (getMemoryManager()) DataItemSequence(collapseTreeInternal(newBindings.begin(), newBindings.end(), dContext), getMemoryManager()); newBindings.clear(); } } // Overwrite our bindings with the new ones _bindings = newBindings; } const DataItemFor::Bindings &DataItemFor::getBindings() const { return _bindings; } const DataItem *DataItemFor::getReturnExpr() const { return _returnExpr; } void DataItemFor::setReturnExpr(DataItem *item) { _returnExpr = item; }