bool UpdateExecutor::p_init(AbstractPlanNode* abstract_node, TempTableLimits* limits) { VOLT_TRACE("init Update Executor"); m_node = dynamic_cast<UpdatePlanNode*>(abstract_node); assert(m_node); assert(m_node->getInputTableCount() == 1); // input table should be temptable m_inputTable = dynamic_cast<TempTable*>(m_node->getInputTable()); assert(m_inputTable); // target table should be persistenttable PersistentTable*targetTable = dynamic_cast<PersistentTable*>(m_node->getTargetTable()); assert(targetTable); setDMLCountOutputTable(limits); AbstractPlanNode *child = m_node->getChildren()[0]; ProjectionPlanNode *proj_node = NULL; if (NULL == child) { VOLT_ERROR("Attempted to initialize update executor with NULL child"); return false; } PlanNodeType pnt = child->getPlanNodeType(); if (pnt == PLAN_NODE_TYPE_PROJECTION) { proj_node = dynamic_cast<ProjectionPlanNode*>(child); } else if (pnt == PLAN_NODE_TYPE_SEQSCAN || pnt == PLAN_NODE_TYPE_INDEXSCAN) { proj_node = dynamic_cast<ProjectionPlanNode*>(child->getInlinePlanNode(PLAN_NODE_TYPE_PROJECTION)); assert(NULL != proj_node); } vector<string> output_column_names = proj_node->getOutputColumnNames(); const vector<string> &targettable_column_names = targetTable->getColumnNames(); /* * The first output column is the tuple address expression and it isn't part of our output so we skip * it when generating the map from input columns to the target table columns. */ for (int ii = 1; ii < output_column_names.size(); ii++) { for (int jj=0; jj < targettable_column_names.size(); ++jj) { if (targettable_column_names[jj].compare(output_column_names[ii]) == 0) { m_inputTargetMap.push_back(pair<int,int>(ii, jj)); break; } } } assert(m_inputTargetMap.size() == (output_column_names.size() - 1)); m_inputTargetMapSize = (int)m_inputTargetMap.size(); m_inputTuple = TableTuple(m_inputTable->schema()); // for target table related info. m_partitionColumn = targetTable->partitionColumn(); return true; }
bool UpdateExecutor::p_init(AbstractPlanNode *abstract_node, const catalog::Database* catalog_db, int* tempTableMemoryInBytes) { VOLT_TRACE("init Update Executor"); UpdatePlanNode* node = dynamic_cast<UpdatePlanNode*>(abstract_node); assert(node); assert(node->getTargetTable()); assert(node->getInputTables().size() == 1); m_inputTable = dynamic_cast<TempTable*>(node->getInputTables()[0]); //input table should be temptable assert(m_inputTable); m_targetTable = dynamic_cast<PersistentTable*>(node->getTargetTable()); //target table should be persistenttable assert(m_targetTable); assert(node->getTargetTable()); // Our output is just our input table (regardless if plan is single-sited or not) node->setOutputTable(node->getInputTables()[0]); // record if a full index update is needed, or if these checks can be skipped m_updatesIndexes = node->doesUpdateIndexes(); AbstractPlanNode *child = node->getChildren()[0]; ProjectionPlanNode *proj_node = NULL; if (NULL == child) { VOLT_ERROR("Attempted to initialize update executor with NULL child"); return false; } PlanNodeType pnt = child->getPlanNodeType(); if (pnt == PLAN_NODE_TYPE_PROJECTION) { proj_node = dynamic_cast<ProjectionPlanNode*>(child); } else if (pnt == PLAN_NODE_TYPE_SEQSCAN || pnt == PLAN_NODE_TYPE_INDEXSCAN) { proj_node = dynamic_cast<ProjectionPlanNode*>(child->getInlinePlanNode(PLAN_NODE_TYPE_PROJECTION)); assert(NULL != proj_node); } std::vector<std::string> output_column_names = proj_node->getOutputColumnNames(); std::string targetTableName = node->getTargetTableName(); catalog::Table *targetTable = NULL; catalog::CatalogMap<catalog::Table> tables = catalog_db->tables(); for ( catalog::CatalogMap<catalog::Table>::field_map_iter i = tables.begin(); i != tables.end(); i++) { catalog::Table *table = (*i).second; if (table->name().compare(targetTableName) == 0) { targetTable = table; break; } } assert(targetTable != NULL); catalog::CatalogMap<catalog::Column> columns = targetTable->columns(); /* * The first output column is the tuple address expression and it isn't part of our output so we skip * it when generating the map from input columns to the target table columns. */ for (int ii = 1; ii < output_column_names.size(); ii++) { std::string outputColumnName = output_column_names[ii]; catalog::Column *column = columns.get(outputColumnName); assert (column != NULL); m_inputTargetMap.push_back(std::pair<int, int>( ii, column->index())); } m_inputTargetMapSize = (int)m_inputTargetMap.size(); m_inputTuple = TableTuple(m_inputTable->schema()); m_targetTuple = TableTuple(m_targetTable->schema()); m_partitionColumn = m_targetTable->partitionColumn(); m_partitionColumnIsString = false; if (m_partitionColumn != -1) { if (m_targetTable->schema()->columnType(m_partitionColumn) == voltdb::VALUE_TYPE_VARCHAR) { m_partitionColumnIsString = true; } } return true; }
bool UpdateExecutor::p_init(AbstractPlanNode* abstract_node, TempTableLimits* limits) { VOLT_TRACE("init Update Executor"); m_node = dynamic_cast<UpdatePlanNode*>(abstract_node); assert(m_node); assert(m_node->getTargetTable()); assert(m_node->getInputTables().size() == 1); m_inputTable = dynamic_cast<TempTable*>(m_node->getInputTables()[0]); //input table should be temptable assert(m_inputTable); m_targetTable = dynamic_cast<PersistentTable*>(m_node->getTargetTable()); //target table should be persistenttable assert(m_targetTable); assert(m_node->getTargetTable()); setDMLCountOutputTable(limits); AbstractPlanNode *child = m_node->getChildren()[0]; ProjectionPlanNode *proj_node = NULL; if (NULL == child) { VOLT_ERROR("Attempted to initialize update executor with NULL child"); return false; } PlanNodeType pnt = child->getPlanNodeType(); if (pnt == PLAN_NODE_TYPE_PROJECTION) { proj_node = dynamic_cast<ProjectionPlanNode*>(child); } else if (pnt == PLAN_NODE_TYPE_SEQSCAN || pnt == PLAN_NODE_TYPE_INDEXSCAN) { proj_node = dynamic_cast<ProjectionPlanNode*>(child->getInlinePlanNode(PLAN_NODE_TYPE_PROJECTION)); assert(NULL != proj_node); } vector<string> output_column_names = proj_node->getOutputColumnNames(); const vector<string> &targettable_column_names = m_targetTable->getColumnNames(); /* * The first output column is the tuple address expression and it isn't part of our output so we skip * it when generating the map from input columns to the target table columns. */ for (int ii = 1; ii < output_column_names.size(); ii++) { for (int jj=0; jj < targettable_column_names.size(); ++jj) { if (targettable_column_names[jj].compare(output_column_names[ii]) == 0) { m_inputTargetMap.push_back(pair<int,int>(ii, jj)); break; } } } assert(m_inputTargetMap.size() == (output_column_names.size() - 1)); m_inputTargetMapSize = (int)m_inputTargetMap.size(); m_inputTuple = TableTuple(m_inputTable->schema()); m_targetTuple = TableTuple(m_targetTable->schema()); m_partitionColumn = m_targetTable->partitionColumn(); m_partitionColumnIsString = false; if (m_partitionColumn != -1) { if (m_targetTable->schema()->columnType(m_partitionColumn) == VALUE_TYPE_VARCHAR) { m_partitionColumnIsString = true; } } // determine which indices are updated by this executor // iterate through all target table indices and see if they contain // tables mutated by this executor std::vector<TableIndex*> allIndexes = m_targetTable->allIndexes(); BOOST_FOREACH(TableIndex *index, allIndexes) { bool indexKeyUpdated = false; BOOST_FOREACH(int colIndex, index->getColumnIndices()) { std::pair<int, int> updateColInfo; // needs to be here because of macro failure BOOST_FOREACH(updateColInfo, m_inputTargetMap) { if (updateColInfo.second == colIndex) { indexKeyUpdated = true; break; } } if (indexKeyUpdated) break; } if (indexKeyUpdated) { m_indexesToUpdate.push_back(index); } }