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; }
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; }
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; }
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; }
QueryPlan *EmptyQP::copy(XPath2MemoryManager *mm) const { if(!mm) { mm = memMgr_; } QueryPlan *result = new (mm) EmptyQP(flags_, mm); result->setLocationInfo(this); return result; }
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; }