Item::Ptr UTransform::TransformResult::next(DynamicContext *context) { context->testInterrupt(); AutoVariableStoreReset reset(context, &scope_); if(toDo_) { toDo_ = false; NodeSet copiedNodes = NodeSet(nodecompare(context)); VectorOfCopyBinding::const_iterator end = transform_->getBindings()->end(); for(VectorOfCopyBinding::const_iterator it = transform_->getBindings()->begin(); it != end; ++it) { if((*it)->qname_ == 0) continue; Sequence values = (*it)->expr_->createResult(context)->toSequence(context); // Keep a record of the nodes that have been copied Result valIt = values; Item::Ptr val; while((val = valIt->next(context)).notNull()) { copiedNodes.insert((Node*)val.get()); } scope_.setVar((*it)->uri_, (*it)->name_, values); } // Get the pending update list PendingUpdateList pul = transform_->getModifyExpr()->createUpdateList(context); // Check that the targets of the pending updates are copied nodes for(PendingUpdateList::const_iterator i = pul.begin(); i != pul.end(); ++i) { Node::Ptr target = i->getTarget(); while(copiedNodes.find(target) == copiedNodes.end()) { target = target->dmParent(context); if(target.isNull()) { XQThrow3(StaticErrorException,X("UTransform::staticTyping"), X("The target node of an update expression in the transform expression is not a node from the copy clauses [err:XUDY0014]"), &(*i)); } } } // Apply the updates AutoDelete<UpdateFactory> ufactory(context->createUpdateFactory()); ufactory->applyUpdates(pul, context, transform_->getRevalidationMode()); // Execute the return expression result_ = transform_->getReturnExpr()->createResult(context); } Item::Ptr result = result_->next(context); if(result.isNull()) { result_ = 0; return 0; } return result; }
void DbXmlUpdateFactory::checkUpdates(const PendingUpdateList &pul, DynamicContext *context, DocumentCache::ValidationMode valMode) { DocSet docMap; PendingUpdateList::const_iterator i; for (i = pul.begin(); i != pul.end(); ++i) { switch (i->getType()) { case PendingUpdate::PUDELETE: { const DbXmlNodeImpl *nodeImpl = (const DbXmlNodeImpl*)i->getTarget().get(); u_int32_t level = nodeImpl->getNodeLevel(); // level 1 is children of the document node if (level == 1 && (nodeImpl->getType() == NodeInfo::ELEMENT) && nodeImpl->isUpdateAble()) { Document *document = const_cast<Document*>(nodeImpl->getDocument()); DBXML_ASSERT(document); DocSet::iterator it = docMap.find(DocClass(document)); if (it == docMap.end()) { DocClass dc(document); dc.setRootElementDeleted(); docMap.insert(dc); } else { const_cast<DocClass&>(*it).setRootElementDeleted(); } } break; } case PendingUpdate::INSERT_INTO: case PendingUpdate::INSERT_INTO_AS_FIRST: case PendingUpdate::INSERT_INTO_AS_LAST: { const DbXmlNodeImpl *nodeImpl = (const DbXmlNodeImpl*)i->getTarget().get(); u_int32_t level = nodeImpl->getNodeLevel(); // level 0 is document node -- inserting a potential // document/root element if (level == 0 && nodeImpl->isUpdateAble()) { int nElems = numElements(*i, context); if (nElems != 0) { Document *document = const_cast<Document*>(nodeImpl->getDocument()); DBXML_ASSERT(document); DocSet::iterator it = docMap.find(DocClass(document)); if (it == docMap.end()) { docMap.insert(DocClass(document, nElems, isEmptyDoc(nodeImpl))); } else { const_cast<DocClass&>(*it).incrCount(nElems); } } } break; } case PendingUpdate::INSERT_BEFORE: case PendingUpdate::INSERT_AFTER: { const DbXmlNodeImpl *nodeImpl = (const DbXmlNodeImpl*)i->getTarget().get(); u_int32_t level = nodeImpl->getNodeLevel(); // level 1 is a child of the document node if (level == 1 && nodeImpl->isUpdateAble()) { int nElems = numElements(*i, context); if (nElems != 0) { Document *document = const_cast<Document*>(nodeImpl->getDocument()); DBXML_ASSERT(document); DocSet::iterator it = docMap.find(DocClass(document)); if (it == docMap.end()) { docMap.insert(DocClass(document, nElems)); } else { const_cast<DocClass&>(*it).incrCount(nElems); } } } break; } case PendingUpdate::REPLACE_NODE: { const DbXmlNodeImpl *nodeImpl = (const DbXmlNodeImpl*)i->getTarget().get(); u_int32_t level = nodeImpl->getNodeLevel(); // level 1 is children of the document node if (level == 1 && (nodeImpl->getType() == NodeInfo::ELEMENT) && nodeImpl->isUpdateAble()) { // replacing document element. If replacing 1 for 1, no-op // if replacing with more or 0 elements, count int nElems = numElements(*i, context); if (nElems != 1) { Document *document = const_cast<Document*>(nodeImpl->getDocument()); DBXML_ASSERT(document); DocSet::iterator it = docMap.find(DocClass(document)); if (it == docMap.end()) { DocClass dc(document); if (nElems == 0) dc.setRootElementDeleted(); else dc.incrCount(nElems); docMap.insert(dc); } else { if (nElems == 0) const_cast<DocClass&>(*it).setRootElementDeleted(); else const_cast<DocClass&>(*it).incrCount(nElems); } } } break; } default: break; } } // perform sanity checks. for (DocSet::const_iterator it = docMap.begin(); it != docMap.end(); it++) { const DocClass &dc = *it; int count = dc.getNumRootElements(); if (count > 1) { throw XmlException(XmlException::QUERY_EVALUATION_ERROR, "Cannot perform an update that creates a persistent document with more than one document element"); } else if (count < 1) { throw XmlException(XmlException::QUERY_EVALUATION_ERROR, "Cannot perform an update that creates a persistent document with no document element"); } } }