Exemple #1
0
void
PlanNodeFragment::nodeListFromJSONObject(PlanNodeFragment *pnf, PlannerDomValue planNodesList, PlannerDomValue executeList, int stmtId)
{
    assert(pnf->m_stmtExecutionListMap.find(stmtId) == pnf->m_stmtExecutionListMap.end());
    // NODE_LIST
    std::vector<AbstractPlanNode*> planNodes;
    for (int i = 0; i < planNodesList.arrayLen(); i++) {
        AbstractPlanNode *node = AbstractPlanNode::fromJSONObject(planNodesList.valueAtIndex(i));
        assert(node);
        assert(pnf->m_idToNodeMap.find(node->getPlanNodeId()) == pnf->m_idToNodeMap.end());
        pnf->m_idToNodeMap[node->getPlanNodeId()] = node;
        planNodes.push_back(node);
    }

    // walk the plannodes and complete each plannode's id-to-node maps
    for (std::vector< AbstractPlanNode* >::const_iterator node = planNodes.begin();
         node != planNodes.end(); ++node) {
        const std::vector<CatalogId>& childIds = (*node)->getChildIds();

        for (int zz = 0; zz < childIds.size(); zz++) {
            (*node)->addChild(pnf->m_idToNodeMap[childIds[zz]]);
        }
    }

    // EXECUTE_LIST
    std::auto_ptr<std::vector<AbstractPlanNode*> > executeNodeList(new std::vector<AbstractPlanNode*>());
    for (int i = 0; i < executeList.arrayLen(); i++) {
        executeNodeList->push_back(pnf->m_idToNodeMap[executeList.valueAtIndex(i).asInt()]);
    }
    pnf->m_stmtExecutionListMap.insert(std::make_pair(stmtId, executeNodeList.get()));
    executeNodeList.release();

}
Exemple #2
0
int
AbstractScanPlanNode::getColumnIndexFromGuid(int guid,
                                             const catalog::Database* db) const
{
    // if the scan node has an inlined projection, then we
    // want to look up the column index in the projection
    AbstractPlanNode* projection =
        getInlinePlanNode(PLAN_NODE_TYPE_PROJECTION);
    if (projection != NULL)
    {
        return projection->getColumnIndexFromGuid(guid, db);
    }
    else
    {
        string name = "";
        for (int i = 0; i < m_outputColumnGuids.size(); i++)
        {
            if (guid == m_outputColumnGuids[i])
            {
                return getColumnIndexFromName(m_outputColumnNames[i], db);
            }
        }
    }
    return -1;
}
Exemple #3
0
PlanNodeFragment *
PlanNodeFragment::fromJSONObject(PlannerDomValue obj)
{
    auto_ptr<PlanNodeFragment> pnf(new PlanNodeFragment());

    // read and construct plannodes from json object
    PlannerDomValue planNodesArray = obj.valueForKey("PLAN_NODES");

    for (int i = 0; i < planNodesArray.arrayLen(); i++) {
        AbstractPlanNode *node = NULL;
        node = AbstractPlanNode::fromJSONObject(planNodesArray.valueAtIndex(i));
        assert(node);

        pnf->m_planNodes.push_back(node);
        pnf->m_idToNodeMap[node->getPlanNodeId()] = node;
    }

    // walk the plannodes and complete each plannode's id-to-node maps
    for (std::vector< AbstractPlanNode* >::const_iterator node = pnf->m_planNodes.begin();
         node != pnf->m_planNodes.end(); ++node) {
        const std::vector<CatalogId> childIds = (*node)->getChildIds();
        for (int zz = 0; zz < childIds.size(); zz++) {
            (*node)->addChild(pnf->m_idToNodeMap[childIds[zz]]);
        }
    }
    pnf->loadFromJSONObject(obj);

    PlanNodeFragment *retval = pnf.get();
    pnf.release();
    assert(retval);
    return retval;
}
Exemple #4
0
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;
}
Table* ExecutorContext::executeExecutors(const std::vector<AbstractExecutor*>& executorList,
                                         int subqueryId)
{
    // Walk through the list and execute each plannode.
    // The query planner guarantees that for a given plannode,
    // all of its children are positioned before it in this list,
    // therefore dependency tracking is not needed here.
    size_t ttl = executorList.size();
    int ctr = 0;

    try {
        BOOST_FOREACH (AbstractExecutor *executor, executorList) {
            assert(executor);
            // Call the execute method to actually perform whatever action
            // it is that the node is supposed to do...
            if (!executor->execute(*m_staticParams)) {
                throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                    "Unspecified execution error detected");
            }
            ++ctr;
        }
    } catch (const SerializableEEException &e) {
        // Clean up any tempTables when the plan finishes abnormally.
        // This needs to be the caller's responsibility for normal returns because
        // the caller may want to first examine the final output table.
        cleanupAllExecutors();
        // Normally, each executor cleans its memory pool as it finishes execution,
        // but in the case of a throw, it may not have had the chance.
        // So, clean up all the memory pools now.
        //TODO: This code singles out inline nodes for cleanup.
        // Is that because the currently active (memory pooling) non-inline
        // executor always cleans itself up before throwing???
        // But if an active executor can be that smart, an active executor with
        // (potential) inline children could also be smart enough to clean up
        // after its inline children, and this post-processing would not be needed.
        BOOST_FOREACH (AbstractExecutor *executor, executorList) {
            assert (executor);
            AbstractPlanNode * node = executor->getPlanNode();
            std::map<PlanNodeType, AbstractPlanNode*>::iterator it;
            std::map<PlanNodeType, AbstractPlanNode*> inlineNodes = node->getInlinePlanNodes();
            for (it = inlineNodes.begin(); it != inlineNodes.end(); it++ ) {
                AbstractPlanNode *inlineNode = it->second;
                inlineNode->getExecutor()->cleanupMemoryPool();
            }
        }

        if (subqueryId == 0) {
            VOLT_TRACE("The Executor's execution at position '%d' failed", ctr);
        } else {
            VOLT_TRACE("The Executor's execution at position '%d' in subquery %d failed", ctr, subqueryId);
        }
        throw;
    }
Exemple #6
0
PlanNodeFragment *
PlanNodeFragment::fromJSONObject(json_spirit::Object &obj)
{
    json_spirit::Value planNodesValue = json_spirit::find_value( obj, "PLAN_NODES");
    if (planNodesValue == json_spirit::Value::null) {
        throwFatalException("Failure attempting to load plan a plan node fragment from a "
                                 "json_spirit::Object. There was no value \"PLAN_NODES\"");
    }

    PlanNodeFragment * pnf = new PlanNodeFragment();
    // read and construct plannodes from json object
    json_spirit::Array planNodesArray = planNodesValue.get_array();
    for (int ii = 0; ii < planNodesArray.size(); ii++) {
        AbstractPlanNode *node = NULL;
        try {
            node = AbstractPlanNode::fromJSONObject(planNodesArray[ii].get_obj());
        }
        catch (SerializableEEException &ex) {
            delete pnf;
            throw;
        }
        pnf->m_planNodes.push_back(node);
        pnf->m_idToNodeMap[node->getPlanNodeId()] = node;
    }

    // walk the plannodes and complete each plannode's id-to-node maps
    for (std::vector< AbstractPlanNode* >::const_iterator node = pnf->m_planNodes.begin();
         node != pnf->m_planNodes.end(); ++node) {
        const std::vector<CatalogId> childIds = (*node)->getChildIds();
        std::vector<AbstractPlanNode*> &children = (*node)->getChildren();
        for (int zz = 0; zz < childIds.size(); zz++) {
            children.push_back(pnf->m_idToNodeMap[childIds[zz]]);
        }

        const std::vector<CatalogId> parentIds = (*node)->getParentIds();
        std::vector<AbstractPlanNode*> &parents = (*node)->getParents();
        for (int zz = 0; zz < parentIds.size(); zz++) {
            parents.push_back(pnf->m_idToNodeMap[parentIds[zz]]);
        }
    }
    try {
        pnf->loadFromJSONObject(obj);
    }
    catch (SerializableEEException &eeEx) {
        delete pnf;
        throw;
    }
    return pnf;
}
Exemple #7
0
int
AbstractPlanNode::getColumnIndexFromGuid(int guid,
                                         const catalog::Database* db) const
{
    if (m_children.size() != 1)
    {
        return -1;
    }
    AbstractPlanNode* child = m_children[0];
    if (child == NULL)
    {
        return -1;
    }
    return child->getColumnIndexFromGuid(guid, db);
}
Exemple #8
0
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;
}
Exemple #9
0
// ----------------------------------------------------
//  Serialization Functions
// ----------------------------------------------------
AbstractPlanNode*
AbstractPlanNode::fromJSONObject(Object &obj, const catalog::Database *catalog_db) {

    Value typeValue = find_value(obj, "PLAN_NODE_TYPE");
    if (typeValue == Value::null)
    {
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                      "AbstractPlanNode::fromJSONObject:"
                                      " PLAN_NODE_TYPE value is null");
    }
    string typeString = typeValue.get_str();
    AbstractPlanNode* node =
        plannodeutil::getEmptyPlanNode(stringToPlanNode(typeString));

    Value idValue = find_value(obj, "ID");
    if (idValue == Value::null)
    {
        delete node;
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                      "AbstractPlanNode::fromJSONObject:"
                                      " ID value is null");
    }
    node->m_planNodeId = (int32_t) idValue.get_int();
    VOLT_TRACE("Initializing PlanNode %s", node->debug().c_str());

    Value inlineNodesValue = find_value(obj,"INLINE_NODES");
    if (inlineNodesValue == Value::null)
    {
        delete node;
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                      "AbstractPlanNode::fromJSONObject:"
                                      " INLINE_NODES value is null");
    }

    Array inlineNodes = inlineNodesValue.get_array();
    for (int ii = 0; ii < inlineNodes.size(); ii++)
    {
        AbstractPlanNode* newNode = NULL;
        try {
            Object obj = inlineNodes[ii].get_obj();
            newNode = AbstractPlanNode::fromJSONObject(obj, catalog_db);
        }
        catch (SerializableEEException &ex) {
            delete newNode;
            delete node;
            throw;
        }

        // todo: if this throws, new Node can be leaked.
        // As long as newNode is not NULL, this will not throw.
        node->addInlinePlanNode(newNode);
        VOLT_TRACE("Adding inline PlanNode %s for %s", newNode->debug().c_str(), node->debug().c_str());
    }

    Value parentNodeIdsValue = find_value(obj, "PARENT_IDS");
    if (parentNodeIdsValue == Value::null)
    {
        delete node;
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                      "AbstractPlanNode::fromJSONObject:"
                                      " PARENT_IDS value is null");
    }

    Array parentNodeIdsArray = parentNodeIdsValue.get_array();
    for (int ii = 0; ii < parentNodeIdsArray.size(); ii++)
    {
        int32_t parentNodeId = (int32_t) parentNodeIdsArray[ii].get_int();
        node->m_parentIds.push_back(parentNodeId);
    }

    Value childNodeIdsValue = find_value(obj, "CHILDREN_IDS");
    if (childNodeIdsValue == Value::null)
    {
        delete node;
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                      "AbstractPlanNode::fromJSONObject:"
                                      " CHILDREN_IDS value is null");
    }

    Array childNodeIdsArray = childNodeIdsValue.get_array();
    for (int ii = 0; ii < childNodeIdsArray.size(); ii++)
    {
        int32_t childNodeId = (int32_t) childNodeIdsArray[ii].get_int();
        node->m_childIds.push_back(childNodeId);
    }

    Value outputColumnsValue = find_value(obj, "OUTPUT_COLUMNS");
    if (outputColumnsValue == Value::null)
    {
        delete node;
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                      "AbstractPlanNode::loadFromJSONObject:"
                                      " Can't find OUTPUT_COLUMNS value");
    }
    Array outputColumnsArray = outputColumnsValue.get_array();

    for (int ii = 0; ii < outputColumnsArray.size(); ii++)
    {
        Value outputColumnValue = outputColumnsArray[ii];
        PlanColumn outputColumn = PlanColumn(outputColumnValue.get_obj());
        node->m_outputColumnGuids.push_back(outputColumn.getGuid());
    }

    try {
        node->loadFromJSONObject(obj, catalog_db);
    }
    catch (SerializableEEException &ex) {
        delete node;
        throw;
    }
    return node;
}
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);
        }
    }