Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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);
	}
}
Exemplo n.º 3
0
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);
	}
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
// 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);
}
Exemplo n.º 6
0
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);
	}
}
Exemplo n.º 7
0
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);
}
Exemplo n.º 8
0
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;
	}
}
Exemplo n.º 9
0
// 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);
}
Exemplo n.º 10
0
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());
}
Exemplo n.º 11
0
//
// "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");
		}
	}
}
Exemplo n.º 12
0
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);
}
Exemplo n.º 13
0
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);
	}
}
Exemplo n.º 14
0
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;
}