/** * 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); }
/** MySQL transform (NOT) IN subquery to (NOT) EXIST * */ execplan::ParseTree* InSub::transform() { if (!fFunc) return NULL; // @todo need to handle scalar IN and BETWEEN specially // this blocks handles only one subselect scalar // arg[0]: column | arg[1]: subselect //assert (fFunc->argument_count() == 2 && fGwip.rcWorkStack.size() >= 2); if (fFunc->argument_count() != 2 || fGwip.rcWorkStack.size() < 2) { fGwip.fatalParseError = true; fGwip.parseErrorText = "Unsupported item in IN subquery"; return NULL; } ReturnedColumn* rhs = fGwip.rcWorkStack.top(); fGwip.rcWorkStack.pop(); delete rhs; ReturnedColumn* lhs = fGwip.rcWorkStack.top(); fGwip.rcWorkStack.pop(); delete lhs; fSub = (Item_subselect*)(fFunc->arguments()[1]); idbassert(fSub && fFunc); SCSEP csep (new CalpontSelectExecutionPlan()); csep->sessionID(fGwip.sessionid); csep->location(CalpontSelectExecutionPlan::WHERE); csep->subType (CalpontSelectExecutionPlan::IN_SUBS); // gwi for the sub query gp_walk_info gwi; gwi.thd = fGwip.thd; gwi.subQuery = this; // @4827 merge table list to gwi in case there is FROM sub to be referenced // in the FROM sub gwi.derivedTbCnt = fGwip.derivedTbList.size(); uint32_t tbCnt = fGwip.tbList.size(); gwi.tbList.insert(gwi.tbList.begin(), fGwip.tbList.begin(), fGwip.tbList.end()); gwi.derivedTbList.insert(gwi.derivedTbList.begin(), fGwip.derivedTbList.begin(), fGwip.derivedTbList.end()); if (getSelectPlan(gwi, *(fSub->get_select_lex()), csep) != 0) { fGwip.fatalParseError = true; if (gwi.fatalParseError && !gwi.parseErrorText.empty()) fGwip.parseErrorText = gwi.parseErrorText; else fGwip.parseErrorText = "Error occured in InSub::transform()"; return NULL; } // remove outer query tables CalpontSelectExecutionPlan::TableList tblist; if (csep->tableList().size() >= tbCnt) tblist.insert(tblist.begin(), csep->tableList().begin() + tbCnt, csep->tableList().end()); CalpontSelectExecutionPlan::SelectList derivedTbList; if (csep->derivedTableList().size() >= gwi.derivedTbCnt) derivedTbList.insert(derivedTbList.begin(), csep->derivedTableList().begin() + gwi.derivedTbCnt, csep->derivedTableList().end()); csep->tableList(tblist); csep->derivedTableList(derivedTbList); ExistsFilter* subFilter = new ExistsFilter(); subFilter->sub(csep); if (gwi.subQuery->correlated()) subFilter->correlated(true); else subFilter->correlated(false); if (fGwip.clauseType == HAVING && subFilter->correlated()) { fGwip.fatalParseError = true; fGwip.parseErrorText = logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_NON_SUPPORT_HAVING); } fGwip.subselectList.push_back(csep); return new ParseTree(subFilter); }
void derivedTableOptimization(SCSEP& csep) { // @bug5634. replace the unused column with ConstantColumn from derived table column list, // ExeMgr will not project ConstantColumn. Only count for local derived column. // subquery may carry main query derived table list for column reference, those // derived tables are not checked for optimization in this scope. erydbSelectExecutionPlan::SelectList derivedTbList = csep->derivedTableList(); // @bug6156. Skip horizontal optimization for no table union. bool horizontalOptimization = true; for (uint i = 0; i < derivedTbList.size(); i++) { erydbSelectExecutionPlan *plan = dynamic_cast<erydbSelectExecutionPlan*>(derivedTbList[i].get()); erydbSelectExecutionPlan::ReturnedColumnList cols = plan->returnedCols(); vector<erydbSelectExecutionPlan::ReturnedColumnList> unionColVec; // only do vertical optimization for union all // @bug6134. Also skip the vertical optimization for select distinct // because all columns need to be projected to check the distinctness. bool verticalOptimization = false; if (plan->distinctUnionNum() == 0 && !plan->distinct()) { verticalOptimization = true; for (uint j = 0; j < plan->unionVec().size(); j++) { unionColVec.push_back( dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols()); } } if (plan->tableList().empty()) horizontalOptimization = false; for (uint j = 0; j < plan->unionVec().size(); j++) { if (dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get())->tableList().empty()) { horizontalOptimization = false; break; } } if (verticalOptimization) { int64_t val = 1; for (uint i = 0; i < cols.size(); i++) { //if (cols[i]->derivedTable().empty()) if (cols[i]->refCount() == 0) { if (cols[i]->derivedRefCol()) cols[i]->derivedRefCol()->decRefCount(); cols[i].reset(new ConstantColumn(val)); for (uint j = 0; j < unionColVec.size(); j++) unionColVec[j][i].reset(new ConstantColumn(val)); } } // set back plan->returnedCols(cols); for (uint j = 0; j < unionColVec.size(); j++) dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols(unionColVec[j]); } } /* * @bug5635. Move filters that only belongs to a derived table to inside the derived table. * 1. parse tree walk to populate derivedTableFilterMap and set null candidate on the tree. * 2. remove the null filters * 3. and the filters of derivedTableFilterMap and append to the WHERE filter of the derived table * * Note: * 1. Subquery filters is ignored because derived table can not be in subquery * 2. While walking tree, whenever a single derive simplefilter is encountered, * this filter is pushed to the corresponding stack * 2. Whenever an OR operator is encountered, all the filter stack of * that OR involving derived table are emptied and null candidate of each * stacked filter needs to be reset (not null) */ ParseTree* pt = csep->filters(); map<string, ParseTree*> derivedTbFilterMap; if (horizontalOptimization && pt) { pt->walk(setDerivedTable); setDerivedFilter(pt, derivedTbFilterMap, derivedTbList); csep->filters(pt); } // AND the filters of individual stack to the derived table filter tree // @todo union filters. // @todo outer join complication map<string, ParseTree*>::iterator mapIt; for (uint i = 0; i < derivedTbList.size(); i++) { erydbSelectExecutionPlan *plan = dynamic_cast<erydbSelectExecutionPlan*>(derivedTbList[i].get()); erydbSelectExecutionPlan::ReturnedColumnList derivedColList = plan->returnedCols(); mapIt = derivedTbFilterMap.find(plan->derivedTbAlias()); if (mapIt != derivedTbFilterMap.end()) { // replace all derived column of this filter with real column from // derived table projection list. ParseTree *mainFilter = new ParseTree(); mainFilter->copyTree(*(mapIt->second)); replaceRefCol(mainFilter, derivedColList); ParseTree* derivedFilter = plan->filters(); if (derivedFilter) { LogicOperator *op = new LogicOperator("and"); ParseTree *filter = new ParseTree(op); filter->left(derivedFilter); filter->right(mainFilter); plan->filters(filter); } else { plan->filters(mainFilter); } // union filter handling for (uint j = 0; j < plan->unionVec().size(); j++) { erydbSelectExecutionPlan *unionPlan = dynamic_cast<erydbSelectExecutionPlan*>(plan->unionVec()[j].get()); erydbSelectExecutionPlan::ReturnedColumnList unionColList = unionPlan->returnedCols(); ParseTree* mainFilterForUnion = new ParseTree(); mainFilterForUnion->copyTree(*(mapIt->second)); replaceRefCol(mainFilterForUnion, unionColList); ParseTree *unionFilter = unionPlan->filters(); if (unionFilter) { LogicOperator *op = new LogicOperator("and"); ParseTree *filter = new ParseTree(op); filter->left(unionFilter); filter->right(mainFilterForUnion); unionPlan->filters(filter); } else { unionPlan->filters(mainFilterForUnion); } } } } // clean derivedTbFilterMap because all the filters are copied for( mapIt = derivedTbFilterMap.begin(); mapIt != derivedTbFilterMap.end(); ++mapIt ) delete (*mapIt).second; // recursively process the nested derived table for (uint i = 0; i < csep->subSelectList().size(); i++) { SCSEP subselect(boost::dynamic_pointer_cast<erydbSelectExecutionPlan>(csep->subSelectList()[i])); derivedTableOptimization(subselect); } }