bool operator==(const ParseTree& t1, const ParseTree& t2) { if (t1.data() != NULL && t2.data() != NULL) { if (*t1.data() != t2.data()) return false; } else if (t1.data() != NULL || t2.data() != NULL) return false; if (t1.left() != NULL && t2.left() != NULL) { if (*t1.left() != *t2.left()) return false; } else if (t1.left() != NULL || t2.left() != NULL) return false; if (t1.right() != NULL && t2.right() != NULL) { if (*t1.right() != *t2.right()) return false; } else if (t1.right() != NULL || t2.right() != NULL) return false; return true; }
/** * This is invoked when a NOT function is got. It's usually the case NOT<IN optimizer> * This function will simple turn the semi join to anti join * */ void InSub::handleNot() { ParseTree *pt = fGwip.ptWorkStack.top(); ExistsFilter *subFilter = dynamic_cast<ExistsFilter*>(pt->data()); idbassert(subFilter); subFilter->notExists(true); SCSEP csep = subFilter->sub(); const ParseTree* ptsub = csep->filters(); if (ptsub) ptsub->walk(makeAntiJoin); ptsub = csep->having(); if (ptsub) ptsub->walk(makeAntiJoin); }
ParseTree* ObjectReader::createParseTree(messageqcpp::ByteStream& b) { CLASSID id = ZERO; ParseTree* ret; b >> (id_t&) id; if (id == NULL_CLASS) return NULL; if (id != PARSETREE) throw UnserializeException("Not a ParseTree"); ret = new ParseTree(); ret->left(createParseTree(b)); ret->right(createParseTree(b)); ret->data(createTreeNode(b)); return ret; }
/** * Handle MySQL's plugin functions * This is mostly for handling the null related functions that MySQL adds to the execution plan */ void InSub::handleFunc(gp_walk_info* gwip, Item_func* func) { if (func->functype() == Item_func::TRIG_COND_FUNC || func->functype() == Item_func::COND_OR_FUNC) { // purpose: remove the isnull() function from the parsetree in ptWorkStack. // IDB handles the null semantics in the join operation // trigcond(or_cond) is the only form we recognize for now if (func->argument_count() > 2) { fGwip.fatalParseError = true; fGwip.parseErrorText = "Unsupported item in IN subquery"; return; } Item_cond* cond; if (func->functype() == Item_func::TRIG_COND_FUNC) { Item* item; if (func->arguments()[0]->type() == Item::REF_ITEM) item = (Item_ref*)(func->arguments()[0])->real_item(); else item = func->arguments()[0]; cond = (Item_cond*)(item); } else { cond = (Item_cond*)(func); } if (cond->functype() == Item_func::COND_OR_FUNC) { // (cache=item) case. do nothing. ignore trigcond()? if (cond->argument_list()->elements == 1) return; // (cache=item or isnull(item)) case. remove "or isnull()" if (cond->argument_list()->elements == 2) { // don't know how to deal with this. don't think it's a fatal error either. if (gwip->ptWorkStack.empty()) return; ParseTree* pt = gwip->ptWorkStack.top(); if (!pt->left() || !pt->right()) return; SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->left()->data()); //assert (sf && sf->op()->op() == execplan::OP_ISNULL); if (!sf || sf->op()->op() != execplan::OP_ISNULL) return; delete sf; sf = dynamic_cast<SimpleFilter*>(pt->right()->data()); //idbassert(sf && sf->op()->op() == execplan::OP_EQ); if (!sf || sf->op()->op() != execplan::OP_EQ) return; // set NULLMATCH for both operand. It's really a setting for the join. // should only set NULLMATCH when the subtype is NOT_IN. for some IN subquery // with aggregation column, MySQL inefficiently convert to: // (cache=item or item is null) and item is not null, which is equivalent to // cache = item. Do not set NULLMATCH for this case. // Because we don't know IN or NOTIN yet, set candidate bit and switch to NULLMATCH // later in handleNot function. if (sf->lhs()->joinInfo() & JOIN_CORRELATED) sf->lhs()->joinInfo(sf->lhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); if (sf->rhs()->joinInfo() & JOIN_CORRELATED) sf->rhs()->joinInfo(sf->rhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); pt = pt->right(); gwip->ptWorkStack.pop(); gwip->ptWorkStack.push(pt); } } else if (cond->functype() == Item_func::EQ_FUNC) { // not in (select const ...) if (gwip->ptWorkStack.empty()) return; ParseTree* pt = gwip->ptWorkStack.top(); SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->data()); if (!sf || sf->op()->op() != execplan::OP_EQ) return; if (sf->lhs()->joinInfo() & JOIN_CORRELATED) sf->lhs()->joinInfo(sf->lhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); if (sf->rhs()->joinInfo() & JOIN_CORRELATED) sf->rhs()->joinInfo(sf->rhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); } } }