Esempio n. 1
0
QueryPlan *AttributeOrChildJoinQP::copy(XPath2MemoryManager *mm) const
{
	if(!mm) mm = memMgr_;
	QueryPlan *result = new (mm) AttributeOrChildJoinQP(left_->copy(mm), right_->copy(mm), flags_, mm);
	result->setLocationInfo(this);
	return result;
}
Esempio n. 2
0
QueryPlan *DescendantOrSelfJoinQP::copy(XPath2MemoryManager *mm) const
{
	if(!mm) mm = memMgr_;

	QueryPlan *result = new (mm) DescendantOrSelfJoinQP(left_->copy(mm), right_->copy(mm), flags_, mm);
	result->setLocationInfo(this);
	return result;
}
Esempio n. 3
0
QueryPlan *EmptyQP::copy(XPath2MemoryManager *mm) const
{
	if(!mm) {
		mm = memMgr_;
	}

	QueryPlan *result = new (mm) EmptyQP(flags_, mm);
	result->setLocationInfo(this);
	return result;
}
Esempio n. 4
0
QueryPlan *IntersectQP::staticTyping(StaticContext *context, StaticTyper *styper)
{
	_src.clear();

	// Remove duplicate arguments
	vector<QueryPlan*> newArgs;
	Vector::iterator it = args_.begin();
	if(it != args_.end()) {
		QueryPlan *arg = (*it)->staticTyping(context, styper);
		_src.copy(arg->getStaticAnalysis());
		newArgs.push_back(arg);

		for(++it; it != args_.end(); ++it) {
			QueryPlan *arg = (*it)->staticTyping(context, styper);
			_src.add(arg->getStaticAnalysis());
			_src.getStaticType().typeNodeIntersect(arg->getStaticAnalysis().getStaticType());
			_src.setProperties(_src.getProperties() | arg->getStaticAnalysis().getProperties());
			newArgs.push_back(arg);
		}

		args_.clear();
		std::copy(newArgs.begin(), newArgs.end(), back_inserter(args_));
	}

	_src.getStaticType().multiply(0, 1);
	return dissolve();
}
Esempio n. 5
0
QueryPlan *AttributeOrChildJoinQP::staticTyping(StaticContext *context, StaticTyper *styper)
{
	StructuralJoinQP::staticTyping(context, styper);

	XPath2MemoryManager *mm = context->getMemoryManager();

	if(right_->getStaticAnalysis().getStaticType().isType(StaticType::ATTRIBUTE_TYPE)) {
		// Convert to a AttributeJoinQP
		QueryPlan *result = new (mm) AttributeJoinQP(left_, right_, flags_, mm);
		result->setLocationInfo(this);

		logTransformation((Manager&)GET_CONFIGURATION(context)->getManager(),
			"More specific join", this, result);
		return result->staticTyping(context, styper);
	}

	if(!right_->getStaticAnalysis().getStaticType().containsType(StaticType::ATTRIBUTE_TYPE)) {
		// Convert to a ChildJoinQP
		QueryPlan *result = new (mm) ChildJoinQP(left_, right_, flags_, mm);
		result->setLocationInfo(this);

		logTransformation((Manager&)GET_CONFIGURATION(context)->getManager(),
			"More specific join", this, result);
		return result->staticTyping(context, styper);
	}

	return this;
}
Esempio n. 6
0
QueryPlan *AttributeOrChildJoinQP::optimize(OptimizationContext &opt)
{
	QueryPlan *result = StructuralJoinQP::optimize(opt);
	if(result != this) return result;

	XPath2MemoryManager *mm = opt.getMemoryManager();

	ImpliedSchemaNode::Type type = findType(right_);
	if(type == ImpliedSchemaNode::ATTRIBUTE) {
		// Convert to a AttributeJoinQP
		QueryPlan *result = new (mm) AttributeJoinQP(left_, right_, flags_, mm);
		result->setLocationInfo(this);

		logTransformation(opt.getLog(), "More specific join", this, result);
		return result->optimize(opt);
	}

	if(type != -1) {
		// Convert to a ChildJoinQP
		QueryPlan *result = new (mm) ChildJoinQP(left_, right_, flags_, mm);
		result->setLocationInfo(this);

		logTransformation(opt.getLog(), "More specific join", this, result);
		return result->optimize(opt);
	}

	return this;
}
Esempio n. 7
0
QueryPlan *IntersectQP::optimize(OptimizationContext &opt)
{
	// Optimize the arguments
	vector<QueryPlan*> newArgs;
	Vector::iterator it;
	for(it = args_.begin(); it != args_.end(); ++it) {
		QueryPlan *arg = (*it)->optimize(opt);
		if(arg->getType() == type_) {
			// Merge IntersectQP arguments into this object
			const Vector &args  = ((OperationQP*)arg)->getArgs();
			Vector::const_iterator aend = args.end();
			for(Vector::const_iterator ai = args.begin();
			    ai != aend; ++ai) newArgs.push_back(*ai);
		} else {
			newArgs.push_back(arg);
		}
	}
	args_.clear();
	std::copy(newArgs.begin(), newArgs.end(), back_inserter(args_));

	removeSupersets(opt);

	// Return if we only have one argument
	if(args_.size() == 1) return args_[0];

	// Pull forward filters
	for(it = args_.begin(); it != args_.end(); ++it) {
		switch((*it)->getType()) {
		case VALUE_FILTER:
		case PREDICATE_FILTER:
		case NODE_PREDICATE_FILTER:
		case NEGATIVE_NODE_PREDICATE_FILTER:
		// We can't skip NUMERIC_PREDICATE_FILTER, because changing it's input will change
		// the cardinality of it's input, and cause it to return the wrong results.
// 		case NUMERIC_PREDICATE_FILTER:
// 		case DOC_EXISTS:
		case LEVEL_FILTER: {
			string before = logBefore(this);

			FilterQP *filter = (FilterQP*)*it;

			*it = filter->getArg();
			filter->setArg(this);

			logTransformation(opt.getLog(), "Filter pulled forward", before, filter);
			return filter->optimize(opt);
		}
		default: break;
		}
	}

	// Identify potential pairs of ValueQP for a RangeQP
	newArgs.clear();
	for(it = args_.begin(); it != args_.end(); ++it) {
		if(isLessThanOrGreaterThan(*it)) {
			for(Vector::iterator it2 = it + 1;
			    it2 != args_.end(); ++it2) {
				if(isLessThanOrGreaterThan(*it2)) {
					QueryPlan *range = createRange((ValueQP*)*it, (ValueQP*)*it2);
					if(range != 0) {
						logTransformation(opt.getLog(), "Merged into range",
							logIntersectBefore(*it, *it2), range);
						newArgs.push_back(range);
					}
				}
			}
		}

		newArgs.push_back((*it)->optimize(opt));
	}
	args_.clear();
	std::copy(newArgs.begin(), newArgs.end(), back_inserter(args_));

	// Return if we only have one argument
	if(args_.size() == 1) return args_[0];

	// Try to pull forward document indexes, so they will combine
	if(opt.getPhase() < OptimizationContext::ALTERNATIVES) {
		string before = logBefore(this);
		QueryPlan *result = PullForwardDocumentJoin().run(this);
		if(result != 0) {
			logTransformation(opt.getLog(), "Pull forward document join", before, result);
			return result->optimize(opt);
		}
	}

	if(opt.getPhase() < OptimizationContext::REMOVE_REDUNDENTS)
		return this;

	// TBD remove the need for QueryExecutionContext here - jpcs
	QueryExecutionContext qec(GET_CONFIGURATION(opt.getContext())->getQueryContext(),
				  /*debugging*/false);
	qec.setContainerBase(opt.getContainerBase());
	qec.setDynamicContext(opt.getContext());

	// Sort the arguments based on how many keys we think they'll return
	sort(args_.begin(), args_.end(), keys_compare_less(opt.getOperationContext(), qec));

	// Remove document index joins if they are unlikely to be useful.
	it = args_.begin();
	QueryPlan *leftMost = *it;
	Cost lCost = leftMost->cost(opt.getOperationContext(), qec);
	newArgs.clear();
	newArgs.push_back(*it);
	for(++it; it != args_.end(); ++it) {
		if(StructuralJoinQP::isDocumentIndex(*it, /*toBeRemoved*/true) &&
			StructuralJoinQP::isSuitableForDocumentIndexComparison(leftMost)) {
			Cost itCost = (*it)->cost(opt.getOperationContext(), qec);

			// TBD Calculate these constants? - jpcs
			static const double KEY_RATIO_THRESHOLD = 2.0;
			static const double PAGES_PER_KEY_FACTOR = 2.0;

			if((itCost.keys / lCost.keys) > KEY_RATIO_THRESHOLD ||
				(itCost.totalPages() / itCost.keys) > (lCost.totalPages() * PAGES_PER_KEY_FACTOR / lCost.keys)) {
				string before = logIntersectBefore(leftMost, *it);
				logTransformation(opt.getLog(), "Remove document join", before, leftMost);
				leftMost->logCost(qec, lCost, 0);
				(*it)->logCost(qec, itCost, 0);
				continue;
			}
		}

		newArgs.push_back(*it);
	}
	args_.clear();
	std::copy(newArgs.begin(), newArgs.end(), back_inserter(args_));

	// Return if we only have one argument
	if(args_.size() == 1) return args_[0];

	return this;
}
Esempio n. 8
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;
}
Esempio n. 9
0
QueryPlan *DescendantOrSelfJoinQP::optimize(OptimizationContext &opt)
{
	XPath2MemoryManager *mm = opt.getMemoryManager();

	QueryPlan *qp = StructuralJoinQP::optimize(opt);
	if(qp != this) return qp;

	if(findType(left_) == ImpliedSchemaNode::METADATA) {
		switch(right_->getType()) {
		case DESCENDANT_OR_SELF: {
			DescendantOrSelfJoinQP *rsj = (DescendantOrSelfJoinQP*)right_;
			if(findType(rsj->left_) == ImpliedSchemaNode::METADATA) {
				string before = logBefore(this);

				left_ = new (mm) IntersectQP(left_, rsj->left_, 0, mm);
				left_->setLocationInfo(rsj);
				right_ = rsj->right_;
				flags_ |= rsj->flags_;

				logTransformation(opt.getLog(), "Combine document join", before, this);
				return optimize(opt);
			}
			break;
		}
		default: {
			if(findType(right_) == ImpliedSchemaNode::METADATA) {
				string before = logBefore(this);

				QueryPlan *result = new (mm) IntersectQP(left_, right_, flags_, mm);
				result->setLocationInfo(this);

				logTransformation(opt.getLog(), "Combine document join", this, result);
				return result->optimize(opt);
			}
			break;
		}
		}
	}

	if(opt.getPhase() < OptimizationContext::REMOVE_REDUNDENTS)
		return this;

	if(findType(left_) == ImpliedSchemaNode::METADATA) {
		switch(right_->getType()) {
		case STEP: {
			string before = logBefore(this);

			StepQP *step = (StepQP*)right_;
			right_ = step->getArg();
			step->setArg(this);

			logTransformation(opt.getLog(), "Push back document join", before, step);
			return step->optimize(opt);
		}
		case DESCENDANT:
		case DESCENDANT_OR_SELF:
		case ATTRIBUTE:
		case CHILD:
		case ATTRIBUTE_OR_CHILD: {
			string before = logBefore(this);

			StructuralJoinQP *sj = (StructuralJoinQP*)right_;
			right_ = sj->getLeftArg();
			sj->setLeftArg(this);

			logTransformation(opt.getLog(), "Push back document join", before, sj);
			return sj->optimize(opt);
		}
		case ANCESTOR:
		case ANCESTOR_OR_SELF:
		case PARENT:
		case PARENT_OF_ATTRIBUTE:
		case PARENT_OF_CHILD: {
			string before = logBefore(this);

			StructuralJoinQP *sj = (StructuralJoinQP*)right_;
			right_ = sj->getRightArg();
			sj->setRightArg(this);

			logTransformation(opt.getLog(), "Push back document join", before, sj);
			return sj->optimize(opt);
		}
		case EXCEPT: {
			string before = logBefore(this);

			// Add to both arguments of ExceptQP

			ExceptQP *ex = (ExceptQP*)right_;
			right_ = ex->getLeftArg();
			ex->setLeftArg(this);

			QueryPlan *copy = new (mm) DescendantOrSelfJoinQP(left_->copy(mm), ex->getRightArg(), flags_, mm);
			copy->setLocationInfo(this);
			ex->setRightArg(copy);

			logTransformation(opt.getLog(), "Push back document join", before, ex);
			return ex->optimize(opt);
		}
		default: break;
		}
	}

	// TBD remove the need for QueryExecutionContext here - jpcs
	QueryExecutionContext qec(GET_CONFIGURATION(opt.getContext())->getQueryContext(),
		/*debugging*/false);
	qec.setContainerBase(opt.getContainerBase());
	qec.setDynamicContext(opt.getContext());

	// Remove this document index join if it's unlikely to be useful
	if(isDocumentIndex(left_, /*toBeRemoved*/true) && isSuitableForDocumentIndexComparison(right_)) {
		Cost rCost = right_->cost(opt.getOperationContext(), qec);
		Cost lCost = left_->cost(opt.getOperationContext(), qec);

		// TBD Calculate these constants? - jpcs
		static const double KEY_RATIO_THRESHOLD = 2.0;
		static const double KEYS_PER_PAGE_THRESHOLD = 2.0;

		if((lCost.keys / rCost.keys) > KEY_RATIO_THRESHOLD ||
			(lCost.keys / lCost.totalPages()) > KEYS_PER_PAGE_THRESHOLD) {

			logTransformation(opt.getLog(), "Remove document join", this, right_);
			right_->logCost(qec, rCost, 0);
			left_->logCost(qec, lCost, 0);
			return right_;
		}
	}

	return this;
}