void DbXmlUpdateFactory::applyPut(const PendingUpdate &update, DynamicContext *context) { DbXmlUri uri(update.getValue().first()-> asString(context), true); if (uri.isDbXmlScheme()) { const DbXmlNodeImpl *content = (const DbXmlNodeImpl*)update.getTarget().get(); string cname = uri.getContainerName(); string docname = uri.getDocumentName(); DbXmlConfiguration *conf = GET_CONFIGURATION(context); XmlManager &mgr = conf->getManager(); XmlContainer cont = ((Manager&)mgr).getOpenContainer(cname); if (cont.isNull()) { string msg = "Target container for fn:put -- "; msg += cname; msg += " -- must be open"; throw XmlException(XmlException::INVALID_VALUE, msg); } OperationContext &oc = conf->getOperationContext(); XmlDocument doc = mgr.createDocument(); doc.setName(docname); XmlEventReader *reader = (XmlEventReader*)content->getEventReader(context); DBXML_ASSERT(reader); doc.setContentAsEventReader(*reader); XmlUpdateContext uc = mgr.createUpdateContext(); // use internal interface to avoid additional transaction int err = ((Container &)cont).addDocumentInternal(oc.txn(), doc, uc, 0); if (err != 0) throw XmlException(err); } }
void DbXmlUpdateFactory::applyReplaceElementContent(const PendingUpdate &update, DynamicContext *context) { const DbXmlNodeImpl *target = (const DbXmlNodeImpl*)update.getTarget().get(); // TBD: this check is commented out... need to re-check why. // if (!target->isUpdateAble()) // return; // use child axis to create nodes to mark for delete DbXmlChildAxis children(0, target, 0); Item::Ptr item; while((item = children.next(context)).notNull()) { const DbXmlNodeImpl *child = (const DbXmlNodeImpl*)item-> getInterface(DbXmlNodeImpl::gDbXml); forDeletion_.insert(child); } // insert new content const XMLCh *value = update.getValue().first()->asString(context); if(value != 0 && *value != 0) { // create text node DbXmlConfiguration *conf = GET_CONFIGURATION(context); OperationContext &oc = conf->getOperationContext(); Document *document = const_cast<Document*>(target->getDocument()); Node::Ptr content = ((DbXmlFactoryImpl*)context->getItemFactory())-> createTextNode(nsNodeText, value, context); update_.insertText(*(const DbXmlNodeImpl*)content-> getInterface(DbXmlNodeImpl::gDbXml), *target, 0, *document, oc, context); } }
// NOTE: Because removal of elements can cause text content to // change node ownership, thereby making it impossible to locate // the proper nodes, it's necessary to either: // 1. always remove nodes in document order (will remove leading // text first) or // 2. perform deletions in 2 passes -- first non-element nodes, then // element nodes // As of release 2.4, (1) is true because of the way the list is created // void DbXmlUpdateFactory::completeUpdate(DynamicContext *context) { DbXmlConfiguration *conf = GET_CONFIGURATION(context); XmlManager &mgr = conf->getManager(); OperationContext &oc = conf->getOperationContext(); for(NodeSet::iterator i = forDeletion_.begin(); i != forDeletion_.end(); ++i) { const DbXmlNodeImpl *node = i->get(); try { // see if the node is update-able (i.e. persistent) if (!node->isUpdateAble()) continue; Document *document = const_cast<Document*>(node->getDocument()); DBXML_ASSERT(document); switch(node->getType()) { case NodeInfo::DOCUMENT: { #ifdef DBXML_DONT_DELETE_DOCUMENTS throw XmlException(XmlException::QUERY_EVALUATION_ERROR, "Cannot delete a document node [err:XUDY0020]"); #else update_.removeDocument(*node, *(node->getContainer()->getContainer()), mgr, oc); #endif break; } case NodeInfo::ELEMENT: { update_.removeElement(*node, *document, oc, context); break; } case NodeInfo::ATTRIBUTE: { update_.removeAttribute(*node, *document, oc, context); break; } case NodeInfo::TEXT: case NodeInfo::COMMENT: case NodeInfo::PI: { update_.removeText(*node, *document, oc, context); break; } } } catch (XmlException &xe) { // ignore DB_NOTFOUND in this path -- nodes may // have already been deleted via a parent tree if ((xe.getExceptionCode() == XmlException::DATABASE_ERROR) && (xe.getDbErrno() == DB_NOTFOUND)) continue; throw; } } update_.completeUpdate(mgr, oc, context); }
void DbXmlUpdateFactory::applyInsertAsFirst(const PendingUpdate &update, DynamicContext *context) { const DbXmlNodeImpl *parent = (const DbXmlNodeImpl*)update.getTarget().get(); if (!parent->isUpdateAble()) return; NsDomNodeRef parentRef = parent->getNsDomNode(); NsDomNodeRef nextRef = parentRef->getNsFirstChild(); if (!nextRef.get()) { DbXmlConfiguration *conf = GET_CONFIGURATION(context); parentRef->refreshNode(conf->getOperationContext(), true); nextRef = parentRef->getNsFirstChild(); } applyInserts(update, parent, nextRef.get(), context, true); }
void DbXmlUpdateFactory::applyRename(const PendingUpdate &update, DynamicContext *context) { const DbXmlNodeImpl *node = (const DbXmlNodeImpl*)update.getTarget().get(); if (!node->isUpdateAble()) return; ATQNameOrDerived *qname = (ATQNameOrDerived*)update.getValue().first().get(); // Retrieve fresh node from database using RMW switch(node->getType()) { case NodeInfo::ELEMENT: { DbXmlConfiguration *conf = GET_CONFIGURATION(context); OperationContext &oc = conf->getOperationContext(); Document *document = const_cast<Document*>(node->getDocument()); DBXML_ASSERT(document); update_.renameElement(*node, qname, *document, oc, context); // Remove index entries under old name // Put prefix and URI in the dictionary // Update the prefix, URI, and name // Update NS_NAMEPREFIX, NS_HASURI flags // Add index entries for new name break; } case NodeInfo::ATTRIBUTE: { renameAttribute(update, qname, context); // Remove index entries under old name // Put prefix and URI in the dictionary // Update the prefix, URI, and name // Update NS_ATTR_PREFIX, NS_ATTR_URI flags // Add index entries for new name break; } case NodeInfo::PI: { // no indexes on PI renamePI(update, qname->getName(), context); break; } default: DBXML_ASSERT(false); break; } }
// do the work of attribute insertion -- shared by applyInsertAttributes // and applyReplaceAttributes void DbXmlUpdateFactory::insertAttributes(const PendingUpdate &update, const DbXmlNodeImpl *parent, DynamicContext *context) { DbXmlConfiguration *conf = GET_CONFIGURATION(context); OperationContext &oc = conf->getOperationContext(); Document *document = const_cast<Document*>(parent->getDocument()); vector<const DbXmlNodeImpl *> nodeVec; Result children = update.getValue(); Item::Ptr item; while((item = children->next(context)).notNull()) { const DbXmlNodeImpl *attr = (const DbXmlNodeImpl*)item-> getInterface(DbXmlNodeImpl::gDbXml); nodeVec.push_back(attr); } update_.insertAttributes(nodeVec, *parent, *document, oc, context); }
Sequence DbXmlDocAvailable::createSequence(DynamicContext* context, int flags) const { const XMLCh* currentUri = getUriArg(context); DbXmlUri uri(context->getBaseURI(), currentUri, /*documentUri*/true); if(uri.isDbXmlScheme()) { if(uri.getDocumentName() != "") { try { DbXmlConfiguration *conf = GET_CONFIGURATION(context); OperationContext &oc = conf->getOperationContext(); XmlContainer containerWrapper = uri.openContainer(conf->getManager(), oc.txn()); // Perform a presence lookup on the built-in node-metadata-equality-string // index for the document name AutoDelete<NodeIterator> result(((Container*)containerWrapper)-> createDocumentIterator(context, this, uri.getDocumentName().c_str(), uri.getDocumentName().length())); return Sequence(context->getItemFactory()-> createBoolean(result->next(context), context), context->getMemoryManager()); } catch(XmlException &) {} } return Sequence(context->getItemFactory()->createBoolean(false, context), context->getMemoryManager()); } // Revert to the default behaviour try { Sequence seq = context->resolveDocument(currentUri, this); if(!seq.isEmpty()) { // Force the lazy DbXmlNodeImpl to parse the document, // to check that it actually exists and is valid. const Item *item = seq.first(); const DbXmlNodeImpl *impl = (const DbXmlNodeImpl*)item->getInterface(DbXmlNodeImpl::gDbXml); DBXML_ASSERT(impl); impl->getNsDomNode(); return Sequence(context->getItemFactory()->createBoolean(true, context), context->getMemoryManager()); } } catch(...) {} return Sequence(context->getItemFactory()->createBoolean(false, context), context->getMemoryManager()); }
// // "next" is NsDomNode * because the navigational methods used // to calculate it in callers are available via NsDom and not via // DbXmlNodeImpl, which uses axis iterators. They could be added // if ever deemed necessary and/or cleaner // void DbXmlUpdateFactory::applyInserts( const PendingUpdate &update, const DbXmlNodeImpl *parent, const NsDomNode *next, DynamicContext *context, bool firstOrAfter) { DbXmlConfiguration *conf = GET_CONFIGURATION(context); XmlManager &mgr = conf->getManager(); OperationContext &oc = conf->getOperationContext(); Document *document = const_cast<Document*>(parent->getDocument()); Result children = update.getValue(); Item::Ptr item; while((item = children->next(context)).notNull()) { const DbXmlNodeImpl *child = (const DbXmlNodeImpl*)item-> getInterface(DbXmlNodeImpl::gDbXml); switch(child->getNodeType()) { case nsNodeElement: { update_.insertElement(*child, *parent, next /* next */, mgr, *document, oc, context, firstOrAfter); break; } case nsNodeText: case nsNodeCDATA: case nsNodePinst: case nsNodeComment: { update_.insertText(*child, *parent, next, *document, oc, context); break; } default: throw XmlException(XmlException::INVALID_VALUE, "Cannot insert a node that is not element or text"); } } }
void DbXmlUpdateFactory::applyInsertAfter(const PendingUpdate &update, DynamicContext *context) { const DbXmlNodeImpl *prev = (const DbXmlNodeImpl*)update.getTarget().get(); if (!prev->isUpdateAble()) return; Node::Ptr parent = prev->dmParent(context); // in order to preserve order for multiple inserts, insertAfter must turn // into insertBefore NsDomNodeRef prevRef = prev->getNsDomNode(); NsDomNodeRef nextRef = prevRef->getNsNextSibling(); if (!nextRef.get()) { DbXmlConfiguration *conf = GET_CONFIGURATION(context); prevRef->refreshNode(conf->getOperationContext(), true); nextRef = prevRef->getNsNextSibling(); } applyInserts(update, (const DbXmlNodeImpl *)parent->getInterface(DbXmlNodeImpl::gDbXml), nextRef.get(), context, true); }
void DocID::fetchDocument(const ContainerBase *container, DbXmlConfiguration &conf, XmlDocument &doc, ReferenceMinder *minder) const { fetchDocument(container, conf.getOperationContext(), conf.getFlags(), doc, minder); if(container->getContainerID() == 0 && doc.isNull()) { // Just make a new XmlDocument XmlManager &mgr = conf.getManager(); doc = mgr.createDocument(); // get the temp DB for construction (container id 0) CacheDatabase *cdb = conf.getDbMinder().findOrAllocate((Manager&)mgr, 0); // Tell the document to use this database, and that it's // content is "NsDom" // TBD GMF: at some point, Document and NsDocument objects will not // be required by DbXmlNodeImpl, so creation/init of Document // objects is not required. Document &tdoc = (Document&)doc; tdoc.setDbMinder(conf.getDbMinder()); tdoc.setContentAsNsDom(*this, cdb); if(minder != 0) minder->addDocument(doc); } // tell the document to use the shared databases in // the DbXmlConfiguration's CacheDatabaseMinder // If necessary, initialize the configuration's minder // TBD GMF -- figure out how to avoid using Container * here Container *cont = const_cast<ContainerBase*>(container)->getContainer(); if (cont != 0 && !cont->isNodeContainer()) { Manager &mgr = (Manager&)cont->getManager(); CacheDatabaseMinder &dbminder = conf.getDbMinder(); dbminder.init(mgr); ((Document&)doc).setDbMinder(dbminder); } }