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. CalpontSelectExecutionPlan::SelectList derivedTbList = csep->derivedTableList(); // @bug6156. Skip horizontal optimization for no table union. bool horizontalOptimization = true; for (uint i = 0; i < derivedTbList.size(); i++) { CalpontSelectExecutionPlan* plan = dynamic_cast<CalpontSelectExecutionPlan*>(derivedTbList[i].get()); CalpontSelectExecutionPlan::ReturnedColumnList cols = plan->returnedCols(); vector<CalpontSelectExecutionPlan::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<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols()); } } if (plan->tableList().empty()) horizontalOptimization = false; for (uint j = 0; j < plan->unionVec().size(); j++) { if (dynamic_cast<CalpontSelectExecutionPlan*>(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<CalpontSelectExecutionPlan*>(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++) { CalpontSelectExecutionPlan* plan = dynamic_cast<CalpontSelectExecutionPlan*>(derivedTbList[i].get()); CalpontSelectExecutionPlan::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++) { CalpontSelectExecutionPlan* unionPlan = dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get()); CalpontSelectExecutionPlan::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<CalpontSelectExecutionPlan>(csep->subSelectList()[i])); derivedTableOptimization(subselect); } }
ostream &operator<< (ostream &output, const CalpontSelectExecutionPlan &cep) { output << ">SELECT " ; if (cep.distinct()) output << "DISTINCT "; output << "limit: " << cep.limitStart() << " - " << cep.limitNum() << endl; switch (cep.location()) { case CalpontSelectExecutionPlan::MAIN: output << "MAIN" << endl; break; case CalpontSelectExecutionPlan::FROM: output << "FROM" << endl; break; case CalpontSelectExecutionPlan::WHERE: output << "WHERE" << endl; break; case CalpontSelectExecutionPlan::HAVING: output << "HAVING" << endl; break; } // Returned Column CalpontSelectExecutionPlan::ReturnedColumnList retCols = cep.returnedCols(); output << ">>Returned Columns" << endl; uint seq = 0; for (unsigned int i = 0; i < retCols.size(); i++) { output << *retCols[i] << endl; if (retCols[i]->colSource() & SELECT_SUB) { output << "select sub -- " << endl; CalpontSelectExecutionPlan *plan = dynamic_cast<CalpontSelectExecutionPlan*>(cep.fSelectSubList[seq++].get()); if (plan) output << "{" << *plan << "}" << endl; } } // From Clause CalpontSelectExecutionPlan::TableList tables = cep.tableList(); output << ">>From Tables" << endl; seq = 0; for (unsigned int i = 0; i < tables.size(); i++) { // derived table if (tables[i].schema.length() == 0 && tables[i].table.length() == 0) { output << "derived table - " << tables[i].alias << endl; CalpontSelectExecutionPlan *plan = dynamic_cast<CalpontSelectExecutionPlan*>(cep.fDerivedTableList[seq++].get()); if (plan) output << "{" << *plan << "}" << endl; } else { output << tables[i] << endl; } } // Filters output << ">>Filters" << endl; if (cep.filters() != 0) cep.filters()->walk (ParseTree::print, output); else output << "empty filter tree" << endl; // Group by columns CalpontSelectExecutionPlan::GroupByColumnList groupByCols = cep.groupByCols(); if (groupByCols.size() > 0) { output << ">>Group By Columns" << endl; for (unsigned int i = 0; i < groupByCols.size(); i++) output << *groupByCols[i] << endl; } // Having if (cep.having() != 0) { output << ">>Having" << endl; cep.having()->walk (ParseTree::print, output); } // Order by columns CalpontSelectExecutionPlan::OrderByColumnList orderByCols = cep.orderByCols(); if (orderByCols.size() > 0) { output << ">>Order By Columns" << endl; for (unsigned int i = 0; i < orderByCols.size(); i++) output << *orderByCols[i] << endl; } output << "SessionID: " << cep.fSessionID << endl; output << "TxnID: " << cep.fTxnID << endl; output << "VerID: " << cep.fVerID << endl; output << "TraceFlags: " << cep.fTraceFlags << endl; output << "StatementID: " << cep.fStatementID << endl; output << "DistUnionNum: " << (int)cep.fDistinctUnionNum << endl; output << "Limit: " << cep.fLimitStart << " - " << cep.fLimitNum << endl; output << "String table threshold: " << cep.fStringTableThreshold << endl; output << "--- Column Map ---" << endl; CalpontSelectExecutionPlan::ColumnMap::const_iterator iter; for (iter = cep.columnMap().begin(); iter != cep.columnMap().end(); iter++) output << (*iter).first << " : " << (*iter).second << endl; return output; }