Exemple #1
0
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");
		}
	}
}