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); } }
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); } }
bool DecisionPointIterator::nextContainer(int contID, DynamicContext *context) { DbXmlConfiguration *conf = GET_CONFIGURATION(context); { // Find the correct QueryPlan for the container // // Hold the compile time mutex whilst searching the linked list. // This stops the list from being modified by just-in-time // optimisation while we traverse it. // // (The mutex in the runtime configuration is the same as the // one from the compile time configuration.) MutexLock lock(conf->getMutex()); while(list_ != 0 && list_->container->getContainerID() < contID) { list_ = list_->next; } } if(list_ == 0 || list_->container->getContainerID() != contID) { list_ = const_cast<DecisionPointQP*>(dp_)->justInTimeOptimize(contID, context); } AutoDecisionPointIteratorReset reset(conf, this); result_ = list_->qp->createNodeIterator(context); return true; }
// 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 ProjectionSchemaAdjuster::addSchemaForIndex(PresenceQP *item) { XPath2MemoryManager *mm = context_->getMemoryManager(); DbXmlConfiguration *conf = GET_CONFIGURATION(context_); ContainerBase *container = item->getContainerBase(); // We need to add a document projection schema for and DLS+ index lookups, // to make sure that the node it points to is still in the projected tree if(container != 0 && container->getContainer() != 0 && container->getContainer()->isWholedocContainer() && container->nodesIndexed() && !item->isDocumentIndex() && item->getNodeType() != ImpliedSchemaNode::METADATA) { DbXmlNodeTest *nt = new (mm) DbXmlNodeTest(Node::document_string); ImpliedSchemaNode *root = new (mm) ImpliedSchemaNode(nt, ImpliedSchemaNode::ROOT, mm); roots_.push_back(root); Name cname(item->getChildName()); const char *curi = cname.hasURI() ? cname.getURI() : 0; switch(item->getNodeType()) { case ImpliedSchemaNode::ATTRIBUTE: { ImpliedSchemaNode::Type type = ImpliedSchemaNode::DESCENDANT_ATTR; ImpliedSchemaNode *pisn = root; if(item->isParentSet()) { Name pname(item->getParentName()); const char *puri = pname.hasURI() ? pname.getURI() : 0; DbXmlNodeTest *nt2 = new (mm) DbXmlNodeTest(Node::element_string, mm->getPooledString(puri), mm->getPooledString(pname.getName()), mm); pisn = new (mm) ImpliedSchemaNode(nt2, ImpliedSchemaNode::DESCENDANT, mm); pisn = (ImpliedSchemaNode*)root->appendChild(pisn); type = ImpliedSchemaNode::ATTRIBUTE; } DbXmlNodeTest *nt = new (mm) DbXmlNodeTest(Node::attribute_string, mm->getPooledString(curi), mm->getPooledString(cname.getName()), mm); pisn->appendChild(new (mm) ImpliedSchemaNode(nt, type, mm)); break; } case ImpliedSchemaNode::CHILD: case ImpliedSchemaNode::DESCENDANT: { DbXmlNodeTest *nt = new (mm) DbXmlNodeTest(Node::element_string, mm->getPooledString(curi), mm->getPooledString(cname.getName()), mm); root->appendChild(new (mm) ImpliedSchemaNode(nt, ImpliedSchemaNode::DESCENDANT, mm)); break; } default: break; } conf->addImpliedSchemaNode(container->getContainerID(), root); } }
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); } }
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; }