ContainerBase *LookupIndexFunction::getContainerArg(DynamicContext *context, bool lookup) const { if(container_ != 0) return container_; if(!_args[0]->isConstant() && !lookup) return 0; DbXmlConfiguration *conf = GET_CONFIGURATION(context); Item::Ptr containerName = getParamNumber(1, context)->next(context); try { XmlContainer container = DbXmlUri::openContainer(XMLChToUTF8(containerName->asString(context)).str(), conf->getManager(), conf->getTransaction()); Container *tcont = (Container*)container; conf->getMinder()->addContainer(tcont); return tcont; } catch(XmlException &e) { e.setLocationInfo(this); throw; } // Never reached return 0; }
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); } }
// 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); }
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 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); } }
DecisionPointQP::ListItem *DecisionPointQP::justInTimeOptimize(int contID, DynamicContext *context) { // **** IMPORTANT - This algorithm is very carefully arranged to avoid // **** deadlocks and race-conditions. Don't rearrange things unless you // **** know what you are doing! // Get the runtime configuration DbXmlConfiguration *conf = GET_CONFIGURATION(context); // Lookup the container ScopedContainer scont((Manager&)conf->getManager(), contID, /*mustExist*/true); // Just-in-time optimise the QueryPlan, using a temporary memory manager for thread safety XPath2MemoryManagerImpl tmpMM; QueryPlan *qp; { AutoMemoryManagerReset resetMM(context, &tmpMM); qp = arg_->copy(&tmpMM); try { AutoDecisionPointReset reset(conf, this); justInTimeOptimize(qp, scont.get(), context); } catch(XmlException &e) { if(e.getQueryLine() == 0) e.setLocationInfo(this); throw; } } // Hold the compile time mutex whilst altering the query plan. // This protects the compile time XPath2MemoryManager as well // as the query plan itself. // // (The mutex in the runtime configuration is the same as the // one from the compile time configuration.) MutexLock lock(conf->getMutex()); // Now we hold the lock, re-search qpList_ for the container, // in case someone beat us to creating it. DecisionPointQP::ListItem **li = &qpList_; while(*li != 0 && (*li)->container->getContainerID() < contID) { li = &(*li)->next; } if(*li == 0 || (*li)->container->getContainerID() != contID) { // Add the container to the compile time ReferenceMinder, in case it has been auto-opened if (contID > 0) compileTimeMinder_->addContainer(scont.getContainer()); // Create a new ListItem and copy the optimised QueryPlan using the // compile time memory manager - so that they can both become a // permanent part of the query's AST XPath2MemoryManager *compile_mm = compileTimeContext_->getMemoryManager(); DecisionPointQP::ListItem *newListItem = new (compile_mm) DecisionPointQP::ListItem(scont.get(), *li); newListItem->qp = qp->copy(compile_mm); newListItem->qp->staticTypingLite(compileTimeContext_); // Only add the new ListItem to the linked list once it is fully optimised // and ready to execute - otherwise another thread could come along and try // to use it. *li = newListItem; } else { // All our work was in vain! Someone beat us to creating a QueryPlan // for this container. Oh well, we'll just use the existing one then... } qp->release(); return *li; }