From 2f9fec8057935c046f15aa03a9cf7556e76b50de Mon Sep 17 00:00:00 2001 From: drrtuy Date: Wed, 23 Jul 2025 17:55:19 +0000 Subject: [PATCH] feat(rbo,rule,QA): fixed JOIN example works with QA for one leg of the JOIN. --- dbcon/execplan/calpontselectexecutionplan.cpp | 153 +++++++++++++-- dbcon/execplan/calpontselectexecutionplan.h | 3 + dbcon/execplan/calpontsystemcatalog.h | 8 +- dbcon/mysql/ha_mcs_impl.cpp | 15 +- dbcon/mysql/rbo_apply_parallel_ces.cpp | 185 ++++++++++-------- dbcon/mysql/rbo_apply_parallel_ces.h | 4 +- dbcon/mysql/rulebased_optimizer.cpp | 2 +- dbcon/mysql/rulebased_optimizer.h | 2 +- 8 files changed, 259 insertions(+), 113 deletions(-) diff --git a/dbcon/execplan/calpontselectexecutionplan.cpp b/dbcon/execplan/calpontselectexecutionplan.cpp index fd48ebb3c..2eb1459f0 100644 --- a/dbcon/execplan/calpontselectexecutionplan.cpp +++ b/dbcon/execplan/calpontselectexecutionplan.cpp @@ -202,7 +202,7 @@ std::string endlWithIndent(const size_t ident) } void CalpontSelectExecutionPlan::printSubCSEP(const size_t& ident, ostringstream& output, - CalpontSelectExecutionPlan*& plan) const + CalpontSelectExecutionPlan*& plan) const { if (plan) { @@ -243,7 +243,7 @@ string CalpontSelectExecutionPlan::toString(const size_t ident) const for (unsigned int i = 0; i < retCols.size(); i++) { - output << endlWithIndent(ident+2) << *retCols[i]; // WIP replace with constant + output << endlWithIndent(ident + 2) << *retCols[i]; // WIP replace with constant if (retCols[i]->colSource() & SELECT_SUB) { @@ -257,7 +257,7 @@ string CalpontSelectExecutionPlan::toString(const size_t ident) const // From Clause CalpontSelectExecutionPlan::TableList tables = tableList(); - output << endlWithIndent(ident) <<">>From Tables"; + output << endlWithIndent(ident) << ">>From Tables"; seq = 0; for (unsigned int i = 0; i < tables.size(); i++) @@ -265,7 +265,7 @@ string CalpontSelectExecutionPlan::toString(const size_t ident) const // derived table if (tables[i].schema.length() == 0 && tables[i].table.length() == 0) { - output << endlWithIndent(ident+2) << "derived table - " << tables[i].alias; + output << endlWithIndent(ident + 2) << "derived table - " << tables[i].alias; CalpontSelectExecutionPlan* plan = dynamic_cast(fDerivedTableList[seq++].get()); @@ -273,7 +273,7 @@ string CalpontSelectExecutionPlan::toString(const size_t ident) const } else { - output << endlWithIndent(ident+2) << tables[i]; + output << endlWithIndent(ident + 2) << tables[i]; } } @@ -863,11 +863,12 @@ void CalpontSelectExecutionPlan::pron(std::string&& pron) fPron = pron; } -// This routine doesn't copy derived table list, union vector, select subqueries, subquery list, and subselects. +// This routine doesn't copy derived table list, union vector, select subqueries, subquery list, and +// subselects. execplan::SCSEP CalpontSelectExecutionPlan::cloneWORecursiveSelects() { execplan::SCSEP newPlan(new CalpontSelectExecutionPlan(fLocation)); - + // Copy simple members newPlan->fLocalQuery = fLocalQuery; newPlan->fTableAlias = fTableAlias; @@ -908,7 +909,7 @@ execplan::SCSEP CalpontSelectExecutionPlan::cloneWORecursiveSelects() newPlan->fTimeZone = fTimeZone; newPlan->fPron = fPron; newPlan->fWithRollup = fWithRollup; - + // Deep copy of ReturnedColumnList ReturnedColumnList newReturnedCols; for (const auto& col : fReturnedCols) @@ -917,15 +918,15 @@ execplan::SCSEP CalpontSelectExecutionPlan::cloneWORecursiveSelects() newReturnedCols.push_back(SRCP(col->clone())); } newPlan->returnedCols(newReturnedCols); - + // Deep copy of filters if (fFilters) newPlan->filters(new ParseTree(*fFilters)); - + // Deep copy of filter token list newPlan->filterTokenList(fFilterTokenList); newPlan->havingTokenList(fHavingTokenList); - + // Deep copy of group by columns GroupByColumnList newGroupByCols; for (const auto& col : fGroupByCols) @@ -934,11 +935,11 @@ execplan::SCSEP CalpontSelectExecutionPlan::cloneWORecursiveSelects() newGroupByCols.push_back(SRCP(col->clone())); } newPlan->groupByCols(newGroupByCols); - + // Deep copy of having clause if (fHaving) newPlan->having(new ParseTree(*fHaving)); - + // Deep copy of order by columns OrderByColumnList newOrderByCols; for (const auto& col : fOrderByCols) @@ -947,7 +948,7 @@ execplan::SCSEP CalpontSelectExecutionPlan::cloneWORecursiveSelects() newOrderByCols.push_back(SRCP(col->clone())); } newPlan->orderByCols(newOrderByCols); - + // Deep copy of column map ColumnMap newColumnMap; for (const auto& entry : fColumnMap) @@ -956,13 +957,131 @@ execplan::SCSEP CalpontSelectExecutionPlan::cloneWORecursiveSelects() newColumnMap.insert(ColumnMap::value_type(entry.first, SRCP(entry.second->clone()))); } newPlan->columnMap(newColumnMap); - + // Copy RM parameters newPlan->rmParms(frmParms); - + // Deep copy of table list newPlan->tableList(fTableList); - + + return newPlan; +} + +execplan::SCSEP CalpontSelectExecutionPlan::cloneForTableWORecursiveSelects( + const execplan::CalpontSystemCatalog::TableAliasName& targetTableAlias) +{ + execplan::SCSEP newPlan(new CalpontSelectExecutionPlan(fLocation)); + + // Copy simple members + newPlan->fLocalQuery = fLocalQuery; + newPlan->fTableAlias = fTableAlias; + newPlan->fLocation = fLocation; + newPlan->fDependent = fDependent; + newPlan->fData = fData; + newPlan->fSessionID = fSessionID; + newPlan->fTxnID = fTxnID; + newPlan->fVerID = fVerID; + newPlan->fSchemaName = fSchemaName; + newPlan->fTableName = fTableName; + newPlan->fTraceFlags = fTraceFlags; + newPlan->fStatementID = fStatementID; + newPlan->fDistinct = fDistinct; + newPlan->fOverrideLargeSideEstimate = fOverrideLargeSideEstimate; + newPlan->fDistinctUnionNum = fDistinctUnionNum; + newPlan->fSubType = fSubType; + newPlan->fDerivedTbAlias = fDerivedTbAlias; + newPlan->fDerivedTbView = fDerivedTbView; + newPlan->fLimitStart = fLimitStart; + newPlan->fLimitNum = fLimitNum; + newPlan->fHasOrderBy = fHasOrderBy; + newPlan->fStringScanThreshold = fStringScanThreshold; + newPlan->fQueryType = fQueryType; + newPlan->fPriority = fPriority; + newPlan->fStringTableThreshold = fStringTableThreshold; + newPlan->fSpecHandlerProcessed = fSpecHandlerProcessed; + newPlan->fOrderByThreads = fOrderByThreads; + newPlan->fUuid = fUuid; + newPlan->fDJSSmallSideLimit = fDJSSmallSideLimit; + newPlan->fDJSLargeSideLimit = fDJSLargeSideLimit; + newPlan->fDJSPartitionSize = fDJSPartitionSize; + newPlan->fDJSMaxPartitionTreeDepth = fDJSMaxPartitionTreeDepth; + newPlan->fDJSForceRun = fDJSForceRun; + newPlan->fMaxPmJoinResultCount = fMaxPmJoinResultCount; + newPlan->fUMMemLimit = fUMMemLimit; + newPlan->fIsDML = fIsDML; + newPlan->fTimeZone = fTimeZone; + newPlan->fPron = fPron; + newPlan->fWithRollup = fWithRollup; + + // Deep copy of ReturnedColumnList + ReturnedColumnList newReturnedCols; + for (const auto& rc : fReturnedCols) + { + auto* simpleColumn = dynamic_cast(rc.get()); + if (simpleColumn) + { + execplan::CalpontSystemCatalog::TableAliasName rcTable( + simpleColumn->schemaName(), simpleColumn->tableName(), simpleColumn->tableAlias(), "", false); + if (!targetTableAlias.weakerEq(rcTable)) + { + continue; + } + newReturnedCols.push_back(SRCP(rc->clone())); + } + } + newPlan->returnedCols(newReturnedCols); + + // Deep copy of filters + // WIP only filters that apply to the target table must be left intact + // replace all irrelevant branches with true + if (fFilters) + { + newPlan->filters(new ParseTree(*fFilters)); + } + + // Deep copy of filter token list + newPlan->filterTokenList(fFilterTokenList); + newPlan->havingTokenList(fHavingTokenList); + + // Deep copy of group by columns + GroupByColumnList newGroupByCols; + for (const auto& col : fGroupByCols) + { + newGroupByCols.push_back(SRCP(col->clone())); + } + newPlan->groupByCols(newGroupByCols); + + // Deep copy of having clause + if (fHaving) + newPlan->having(new ParseTree(*fHaving)); + + // Deep copy of order by columns + OrderByColumnList newOrderByCols; + for (const auto& col : fOrderByCols) + { + newOrderByCols.push_back(SRCP(col->clone())); + } + newPlan->orderByCols(newOrderByCols); + + // Deep copy of column map + ColumnMap newColumnMap; + for (const auto& entry : fColumnMap) + { + // WIP only relevant RCs must be copied + if (entry.second) + newColumnMap.insert({entry.first, SRCP(entry.second->clone())}); + } + newPlan->columnMap(newColumnMap); + + // Copy RM parameters + newPlan->rmParms(frmParms); + + // Deep copy of table list + // INV the target table must be contained in the original TableList in this CSEP + TableList newTableList{targetTableAlias}; + + newPlan->tableList(newTableList); + return newPlan; } diff --git a/dbcon/execplan/calpontselectexecutionplan.h b/dbcon/execplan/calpontselectexecutionplan.h index 9e540b9ba..e01bab5f2 100644 --- a/dbcon/execplan/calpontselectexecutionplan.h +++ b/dbcon/execplan/calpontselectexecutionplan.h @@ -163,6 +163,9 @@ class CalpontSelectExecutionPlan : public CalpontExecutionPlan * Clones this CSEP without recursive selects for optimizer purposes */ execplan::SCSEP cloneWORecursiveSelects(); + + execplan::SCSEP cloneForTableWORecursiveSelects(const execplan::CalpontSystemCatalog::TableAliasName& targetTableAlias); + /** * Access and mutator methods */ diff --git a/dbcon/execplan/calpontsystemcatalog.h b/dbcon/execplan/calpontsystemcatalog.h index 3cfaceae1..027878345 100644 --- a/dbcon/execplan/calpontsystemcatalog.h +++ b/dbcon/execplan/calpontsystemcatalog.h @@ -437,7 +437,8 @@ class CalpontSystemCatalog : public datatypes::SystemCatalog : schema(sch), table(tb), alias(al), view(v), fisColumnStore(true) { } - TableAliasName(const std::string& sch, const std::string& tb, const std::string& al, const std::string& v, const bool isColumnStore) + TableAliasName(const std::string& sch, const std::string& tb, const std::string& al, const std::string& v, + const bool isColumnStore) : schema(sch), table(tb), alias(al), view(v), fisColumnStore(isColumnStore) { } @@ -458,6 +459,11 @@ class CalpontSystemCatalog : public datatypes::SystemCatalog return (schema == rhs.schema && table == rhs.table && alias == rhs.alias && view == rhs.view && partitions == rhs.partitions && fisColumnStore == rhs.fisColumnStore); } + bool weakerEq(const TableAliasName& rhs) const + { + return (schema == rhs.schema && table == rhs.table && alias == rhs.alias && view == rhs.view && + fisColumnStore == rhs.fisColumnStore); + } bool operator!=(const TableAliasName& rhs) const { return !(*this == rhs); diff --git a/dbcon/mysql/ha_mcs_impl.cpp b/dbcon/mysql/ha_mcs_impl.cpp index 193ad38ea..88500a216 100644 --- a/dbcon/mysql/ha_mcs_impl.cpp +++ b/dbcon/mysql/ha_mcs_impl.cpp @@ -139,7 +139,7 @@ extern bool nonConstFunc(Item_func* ifp); void gp_walk_info::mergeTableStatistics(const TableStatisticsMap& aTableStatisticsMap) { - for (auto& [schemaAndTableName, aColumnStatisticsMap]: aTableStatisticsMap) + for (auto& [schemaAndTableName, aColumnStatisticsMap] : aTableStatisticsMap) { auto tableStatisticsMapIt = tableStatisticsMap.find(schemaAndTableName); if (tableStatisticsMapIt == tableStatisticsMap.end()) @@ -148,7 +148,7 @@ void gp_walk_info::mergeTableStatistics(const TableStatisticsMap& aTableStatisti } else { - for (auto& [columnName, histogram]: aColumnStatisticsMap) + for (auto& [columnName, histogram] : aColumnStatisticsMap) { tableStatisticsMapIt->second[columnName] = histogram; } @@ -156,9 +156,16 @@ void gp_walk_info::mergeTableStatistics(const TableStatisticsMap& aTableStatisti } } -std::optional gp_walk_info::findStatisticsForATable(SchemaAndTableName& schemaAndTableName) +std::optional gp_walk_info::findStatisticsForATable( + SchemaAndTableName& schemaAndTableName) { auto tableStatisticsMapIt = tableStatisticsMap.find(schemaAndTableName); + for (auto& [schemaAndTableName, columnStatisticsMap] : tableStatisticsMap) + { + std::cout << "Table " << schemaAndTableName.schema << "." << schemaAndTableName.table + << " has statistics " << columnStatisticsMap.size() << std::endl; + } + if (tableStatisticsMapIt == tableStatisticsMap.end()) { return std::nullopt; @@ -167,7 +174,7 @@ std::optional gp_walk_info::findStatisticsForATable(SchemaA return {tableStatisticsMapIt->second}; } -} +} // namespace cal_impl_if namespace { diff --git a/dbcon/mysql/rbo_apply_parallel_ces.cpp b/dbcon/mysql/rbo_apply_parallel_ces.cpp index 363ef263b..e3252db08 100644 --- a/dbcon/mysql/rbo_apply_parallel_ces.cpp +++ b/dbcon/mysql/rbo_apply_parallel_ces.cpp @@ -38,13 +38,6 @@ void applyParallelCES_exists(execplan::CalpontSelectExecutionPlan& csep, const s static const std::string RewrittenSubTableAliasPrefix = "$added_sub_"; static const size_t MaxParallelFactor = 16; -bool tableAliasEqual(const execplan::CalpontSystemCatalog::TableAliasName& lhs, - const execplan::CalpontSystemCatalog::TableAliasName& rhs) -{ -return (lhs.schema == rhs.schema && lhs.table == rhs.table && lhs.alias == rhs.alias && -lhs.fisColumnStore == rhs.fisColumnStore); -} - bool tableIsInUnion(const execplan::CalpontSystemCatalog::TableAliasName& table, execplan::CalpontSelectExecutionPlan& csep) { @@ -66,14 +59,26 @@ bool someAreForeignTables(execplan::CalpontSelectExecutionPlan& csep) [](const auto& table) { return !table.isColumnstore(); }); } -bool parallelCESFilter(execplan::CalpontSelectExecutionPlan& csep) +bool someForeignTablesHasIndex(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx) +{ + return std::any_of( + csep.tableList().begin(), csep.tableList().end(), + [&ctx](const auto& table) + { + cal_impl_if::SchemaAndTableName schemaAndTableName = {table.schema, table.table}; + return (!table.isColumnstore() && + ctx.gwi.tableStatisticsMap.find(schemaAndTableName) != ctx.gwi.tableStatisticsMap.end()); + }); +} + +bool parallelCESFilter(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx) { auto tables = csep.tableList(); // This is leaf and there are no other tables at this level in neither UNION, nor derived table. // TODO filter out CSEPs with orderBy, groupBy, having // Filter out tables that were re-written. // return tables.size() == 1 && !tables[0].isColumnstore() && !tableIsInUnion(tables[0], csep); - return someAreForeignTables(csep); + return someAreForeignTables(csep) && someForeignTablesHasIndex(csep, ctx); } // This routine produces a new ParseTree that is AND(lowerBand <= column, column <= upperBand) @@ -135,7 +140,7 @@ execplan::SimpleColumn* findSuitableKeyColumn(execplan::CalpontSelectExecutionPl { execplan::CalpontSystemCatalog::TableAliasName rcTable( simpleColumn->schemaName(), simpleColumn->tableName(), simpleColumn->tableAlias(), "", false); - if (!tableAliasEqual(targetTable, rcTable)) + if (!targetTable.weakerEq(rcTable)) { continue; } @@ -217,7 +222,7 @@ execplan::CalpontSelectExecutionPlan::SelectList makeUnionFromTable( for (auto& bound : bounds) { - auto clonedCSEP = csep.cloneWORecursiveSelects(); + auto clonedCSEP = csep.cloneForTableWORecursiveSelects(table); // Add BETWEEN based on key column range clonedCSEP->filters(filtersWithNewRangeAddedIfNeeded(clonedCSEP, *keyColumn, bound)); unionVec.push_back(clonedCSEP); @@ -239,10 +244,22 @@ bool applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerCon std::cout << "Processing table schema " << schemaAndTableName.schema << " table " << schemaAndTableName.table << " alias " << table.alias << std::endl; auto columnStatistics = ctx.gwi.findStatisticsForATable(schemaAndTableName); + std::cout << "Column statistics: " << columnStatistics.has_value() << std::endl; // TODO add column statistics check to the corresponding match if (!table.isColumnstore() && columnStatistics) { - auto derivedSCEP = csep.cloneWORecursiveSelects(); + auto derivedSCEP = csep.cloneForTableWORecursiveSelects(table); + // Remove the filters as they were pushed down to union units + // This is inappropriate for EXISTS filter and join conditions + // WIP replace with filters applied to filters, so that only relevant filters are left + derivedSCEP->filters(nullptr); + auto* derivedCSEP = dynamic_cast(derivedSCEP.get()); + if (!derivedCSEP) + { + continue; + } + auto additionalUnionVec = makeUnionFromTable(*derivedCSEP, table, ctx); + // need to add a level here std::string tableAlias = RewrittenSubTableAliasPrefix + table.schema + "_" + table.table + "_" + std::to_string(ctx.uniqueId); @@ -252,101 +269,95 @@ bool applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerCon derivedSCEP->subType(execplan::CalpontSelectExecutionPlan::FROM_SUBS); derivedSCEP->derivedTbAlias(tableAlias); - // Create a copy of the current leaf CSEP with additional filters to partition the key column - auto additionalUnionVec = makeUnionFromTable(csep, table, ctx); derivedSCEP->unionVec().insert(derivedSCEP->unionVec().end(), additionalUnionVec.begin(), additionalUnionVec.end()); newDerivedTableList.push_back(derivedSCEP); execplan::CalpontSystemCatalog::TableAliasName tn = execplan::make_aliasview("", "", tableAlias, ""); newTableList.push_back(tn); - // Remove the filters as they were pushed down to union units - // This is inappropriate for EXISTS filter and join conditions - derivedSCEP->filters(nullptr); ruleHasBeenApplied = true; } + else + { + newTableList.push_back(table); + } } execplan::CalpontSelectExecutionPlan::ReturnedColumnList newReturnedColumns; // [[maybe_unused]] size_t colPosition = 0; // replace parent CSEP RCs with derived table RCs using ScheamAndTableName -> tableAlias map - for (auto& rc : csep.returnedCols()) + if (!newDerivedTableList.empty()) { - // TODO support expressions - // Find SC for the RC - auto rcCloned = boost::make_shared(*rc); - // TODO timezone and result type are not copied - // TODO add specific ctor for this functionality - // If there is an alias in the map then it is a new derived table - auto sc = dynamic_cast(rc.get()); - std::vector scs; - // execplan::ParseTree pt(rc.get()); - // pt.walk(execplan::getSimpleCols, &scs); - - // auto sc = scs[0]; - std::cout << "Processing RC schema " << sc->schemaName() << " table " << sc->tableName() << " alias " - << sc->tableAlias() << std::endl; - auto newTableAliasAndColPositionCounter = - tableAliasMap.find({sc->schemaName(), sc->tableName(), sc->tableAlias(), "", false}); - if (newTableAliasAndColPositionCounter == tableAliasMap.end()) + for (auto& rc : csep.returnedCols()) { - std::cout << "The RC doesn't belong to any of the derived tables, so leave it intact" << std::endl; - continue; + // TODO support expressions + // Find SC for the RC + auto rcCloned = boost::make_shared(*rc); + // TODO timezone and result type are not copied + // TODO add specific ctor for this functionality + // If there is an alias in the map then it is a new derived table + auto sc = dynamic_cast(rc.get()); + std::vector scs; + // execplan::ParseTree pt(rc.get()); + // pt.walk(execplan::getSimpleCols, &scs); + + std::cout << "Processing RC schema " << sc->schemaName() << " table " << sc->tableName() << " alias " + << sc->tableAlias() << std::endl; + for (auto& [tableAlias, aliasAndCounter] : tableAliasMap) + { + std::cout << "Processing table alias " << tableAlias << " new alias " << aliasAndCounter.first + << " col position " << aliasAndCounter.second << std::endl; + } + auto newTableAliasAndColPositionCounter = + tableAliasMap.find({sc->schemaName(), sc->tableName(), sc->tableAlias(), "", false}); + if (newTableAliasAndColPositionCounter == tableAliasMap.end()) + { + std::cout << "The RC doesn't belong to any of the derived tables, so leave it intact" << std::endl; + continue; + } + sc->tableName(""); + sc->schemaName(""); + auto& [newTableAlias, colPosition] = newTableAliasAndColPositionCounter->second; + sc->tableAlias(newTableAlias); + // WIP Not needed according with CSEP output + // sc->isColumnStore(true); + sc->colPosition(colPosition++); + // rcCloned->colPosition(colPosition++); + // rcCloned->resultType(rc->resultType()); + // newReturnedColumns.push_back(rcCloned); } - sc->tableName(""); - sc->schemaName(""); - auto& [newTableAlias, colPosition] = newTableAliasAndColPositionCounter->second; - sc->tableAlias(newTableAlias); - // WIP Not needed according with CSEP output - // sc->isColumnStore(true); - sc->colPosition(colPosition++); - // rcCloned->colPosition(colPosition++); - // rcCloned->resultType(rc->resultType()); - // newReturnedColumns.push_back(rcCloned); - } + // Remove the filters if necessary using csep.filters(nullptr) as they were pushed down to union units + // But this is inappropriate for EXISTS filter and join conditions + // There must be no derived at this point, so we can replace it with the new derived table list - execplan::CalpontSelectExecutionPlan::ReturnedColumnList newReturnedColumns; - [[maybe_unused]] size_t colPosition = 0; - // replace parent CSEP RCs with derived table RCs using ScheamAndTableName -> tableAlias map - for (auto& rc : csep.returnedCols()) - { - // TODO support expressions - // Find SC for the RC - auto rcCloned = boost::make_shared(*rc); - // TODO timezone and result type are not copied - // TODO add specific ctor for this functionality - // If there is an alias in the map then it is a new derived table - auto sc = dynamic_cast(rc.get()); - std::vector scs; - // execplan::ParseTree pt(rc.get()); - // pt.walk(execplan::getSimpleCols, &scs); - - // auto sc = scs[0]; - std::cout << "Processing RC schema " << sc->schemaName() << " table " << sc->tableName() << " alias " - << sc->tableAlias() << std::endl; - auto newTableAlias = tableAliasMap.find( - {sc->schemaName(), sc->tableName(), sc->tableAlias(), "", false}); - if (newTableAlias == tableAliasMap.end()) + auto* left = dynamic_cast(csep.filters()->data()); + if (left) { - std::cout << "The RC doesn't belong to any of the derived tables, so leave it intact" << std::endl; - continue; + auto* lhs = left->lhs()->clone(); + if (lhs) + { + auto* lhsSC = dynamic_cast(lhs); + if (lhsSC) + { + auto newTableAlias = tableAliasMap.find({lhsSC->schemaName(), lhsSC->tableName(), lhsSC->tableAlias(), "", false}); + // WIP Leak loosing previous lhs + if (newTableAlias != tableAliasMap.end()) + { + lhsSC->tableName(""); + lhsSC->schemaName(""); + lhsSC->tableAlias(newTableAlias->second.first); + lhsSC->colPosition(0); + left->lhs(lhs); + } + } + } } - sc->tableName(""); - sc->schemaName(""); - sc->tableAlias(newTableAlias->second); - sc->isColumnStore(true); - sc->colPosition(colPosition++); - // rcCloned->colPosition(colPosition++); - // rcCloned->resultType(rc->resultType()); - // newReturnedColumns.push_back(rcCloned); + + csep.derivedTableList(newDerivedTableList); + // Replace table list with new table list populated with union units + csep.tableList(newTableList); + // csep.returnedCols(newReturnedColumns); } - // Remove the filters if necessary using csep.filters(nullptr) as they were pushed down to union units - // But this is inappropriate for EXISTS filter and join conditions - // There must be no derived at this point, so we can replace it with the new derived table list - csep.derivedTableList(newDerivedTableList); - // Replace table list with new table list populated with union units - csep.tableList(newTableList); - csep.returnedCols(newReturnedColumns); return ruleHasBeenApplied; } diff --git a/dbcon/mysql/rbo_apply_parallel_ces.h b/dbcon/mysql/rbo_apply_parallel_ces.h index cf08b84c0..60e546953 100644 --- a/dbcon/mysql/rbo_apply_parallel_ces.h +++ b/dbcon/mysql/rbo_apply_parallel_ces.h @@ -58,6 +58,6 @@ using NewTableAliasAndColumnPosCounter = std::pair; using TableAliasMap = std::map; -bool parallelCESFilter(execplan::CalpontSelectExecutionPlan& csep); +bool parallelCESFilter(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx); bool applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx); -} \ No newline at end of file +} // namespace optimizer \ No newline at end of file diff --git a/dbcon/mysql/rulebased_optimizer.cpp b/dbcon/mysql/rulebased_optimizer.cpp index 3559ad9c6..cb05afb05 100644 --- a/dbcon/mysql/rulebased_optimizer.cpp +++ b/dbcon/mysql/rulebased_optimizer.cpp @@ -130,7 +130,7 @@ bool Rule::walk(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimiz // TODO add walking nested subselect in projection. See CSEP::fSelectSubList - if (mayApply(*current)) + if (mayApply(*current, ctx)) { rewrite |= applyRule(*current, ctx); ++ctx.uniqueId; diff --git a/dbcon/mysql/rulebased_optimizer.h b/dbcon/mysql/rulebased_optimizer.h index a7761c61a..ff83b388a 100644 --- a/dbcon/mysql/rulebased_optimizer.h +++ b/dbcon/mysql/rulebased_optimizer.h @@ -44,7 +44,7 @@ public: struct Rule { // returns true if rule may be applied - using RuleApplierFilter = bool (*)(execplan::CalpontSelectExecutionPlan&); + using RuleApplierFilter = bool (*)(execplan::CalpontSelectExecutionPlan&, RBOptimizerContext&); // returns true if rule was applied using RuleApplier = bool (*)(execplan::CalpontSelectExecutionPlan&, RBOptimizerContext&);