Esempio n. 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;
}
Esempio n. 2
0
PendingUpdateList UInsertAsLast::createUpdateList(DynamicContext *context) const
{
  Node::Ptr node = (Node*)target_->createResult(context)->next(context).get();

  if(node->dmNodeKind() != Node::element_string &&
     node->dmNodeKind() != Node::document_string)
    XQThrow(XPath2TypeMatchException,X("UInsertAsLast::createUpdateList"),
            X("It is a type error for the target expression of an insert as last expression not to be a single element "
              "or document [err:XUTY0005]"));

  Sequence alist(context->getMemoryManager());
  Sequence clist(context->getMemoryManager());

  Result value = source_->createResult(context);
  Item::Ptr item;
  while((item = value->next(context)).notNull()) {
    if(((Node*)item.get())->dmNodeKind() == Node::attribute_string) {
      if(!clist.isEmpty())
        XQThrow(ASTException,X("UInsertAsLast::createUpdateList"),
                X("Attribute nodes must occur before other nodes in the source expression for an insert as last expression [err:XUTY0004]"));

      //    b. No attribute node in $alist may have a QName whose implied namespace binding conflicts with a namespace
      //       binding in the "namespaces" property of $target [err:XUDY0023].  
      ATQNameOrDerived::Ptr qname = ((Node*)item.get())->dmNodeName(context);
      if(qname->getURI() != 0 && *(qname->getURI()) != 0) {
        ATAnyURIOrDerived::Ptr uri = FunctionNamespaceURIForPrefix::uriForPrefix(qname->getPrefix(), node, context, this);
        if(uri.notNull() && !XPath2Utils::equals(uri->asString(context), qname->getURI())) {
          XMLBuffer buf;
          buf.append(X("Implied namespace binding for the insert as last expression (\""));
          buf.append(qname->getPrefix());
          buf.append(X("\" -> \""));
          buf.append(qname->getURI());
          buf.append(X("\") conflicts with those already existing on the parent element of the target attribute [err:XUDY0023]"));
          XQThrow3(DynamicErrorException, X("UInsertInto::createUpdateList"), buf.getRawBuffer(), this);
        }
      }

      alist.addItem(item);
    }
    else
      clist.addItem(item);
  }

  PendingUpdateList result;

  if(!alist.isEmpty()) {
    // 3. If $alist is not empty and into is specified, the following checks are performed:
    //    a. $target must be an element node [err:XUTY0022].
    if(node->dmNodeKind() == Node::document_string)
      XQThrow(XPath2TypeMatchException,X("UInsertInto::createUpdateList"),
              X("It is a type error if an insert expression specifies the insertion of an attribute node into a document node [err:XUTY0022]"));
    result.addUpdate(PendingUpdate(PendingUpdate::INSERT_ATTRIBUTES, node, alist, this));
  }
  if(!clist.isEmpty()) {
    result.addUpdate(PendingUpdate(PendingUpdate::INSERT_INTO_AS_LAST, node, clist, this));
  }

  return result;
}
Esempio n. 3
0
PendingUpdateList XQSequence::createUpdateList(DynamicContext *context) const
{
  PendingUpdateList result;
  for(VectorOfASTNodes::const_iterator i = _astNodes.begin(); i != _astNodes.end(); ++i) {
    result.mergeUpdates((*i)->createUpdateList(context));
  }
  return result;
}
Esempio n. 4
0
PendingUpdateList UDelete::createUpdateList(DynamicContext *context) const
{
  PendingUpdateList pul;

  Result targets = expr_->createResult(context);
  Item::Ptr item;
  while((item = targets->next(context)).notNull()) {
    pul.addUpdate(PendingUpdate(PendingUpdate::PUDELETE, (Node*)item.get(), this));
  }

  return pul;
}
Esempio n. 5
0
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");
		}
	}
}
Esempio n. 6
0
void PendingUpdateList::mergeUpdates(const PendingUpdateList &pul)
{
  for(const_iterator i = pul.begin(); i != pul.end(); ++i) {
    updates_.push_back(*i);
  }
}